Skip to content

Commit

Permalink
feat: add support for bhtml and optimize inline scripts performance.
Browse files Browse the repository at this point in the history
  • Loading branch information
andycall committed Jul 11, 2024
1 parent 821cd01 commit 6feb3f0
Show file tree
Hide file tree
Showing 20 changed files with 404 additions and 78 deletions.
35 changes: 34 additions & 1 deletion bridge/core/api/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "api.h"
#include "core/dart_isolate_context.h"
#include "core/html/parser/html_parser.h"
#include "core/html/html_script_element.h"
#include "core/page.h"
#include "foundation/wbc.h"
#include "multiple_threading/dispatcher.h"
Expand Down Expand Up @@ -43,6 +44,24 @@ void evaluateScriptsInternal(void* page_,
persistent_handle, result_callback, is_success);
}

void evaluateScriptsByIdInternal(void* page_,
uint32_t script_id,
int64_t profile_id,
Dart_Handle persistent_handle,
EvaluateScriptsByIdCallback result_callback) {
auto page = reinterpret_cast<webf::WebFPage*>(page_);
assert(std::this_thread::get_id() == page->currentThread());

page->dartIsolateContext()->profiler()->StartTrackEvaluation(profile_id);

bool is_success = page->evaluateScriptById(script_id);

page->dartIsolateContext()->profiler()->FinishTrackEvaluation(profile_id);

page->dartIsolateContext()->dispatcher()->PostToDart(page->isDedicated(), ReturnEvaluateScriptsInternal,
persistent_handle, result_callback, is_success);
}

static void ReturnEvaluateQuickjsByteCodeResultToDart(Dart_PersistentHandle persistent_handle,
EvaluateQuickjsByteCodeCallback result_callback,
bool is_success) {
Expand Down Expand Up @@ -72,7 +91,7 @@ void evaluateQuickjsByteCodeInternal(void* page_,

void evaluateWbcInternal(void* page_,
uint8_t* bytes,
int32_t byte_len,
uint32_t byte_len,
int64_t profile_id,
Dart_PersistentHandle persistent_handle,
EvaluateQuickjsByteCodeCallback result_callback) {
Expand Down Expand Up @@ -119,6 +138,20 @@ void evaluateWbcInternal(void* page_,
persistent_handle, result_callback, is_success);
}

void evaluateWbcByIdInternal(void* page_,
uint32_t script_id,
int64_t profile_id,
Dart_PersistentHandle persistent_handle,
EvaluateQuickjsByteCodeCallback result_callback) {
auto* script_element = HTMLScriptElement::ObtainScriptElementFromId(script_id);
if (script_element == nullptr) return;

auto* bytes = (uint8_t*) script_element->buffer();
uint32_t byte_len = script_element->buffer_len();

evaluateWbcInternal(page_, bytes, byte_len, profile_id, persistent_handle, result_callback);
}

static void ReturnParseHTMLToDart(Dart_PersistentHandle persistent_handle, ParseHTMLCallback result_callback) {
Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle);
result_callback(handle);
Expand Down
15 changes: 14 additions & 1 deletion bridge/core/api/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ void evaluateScriptsInternal(void* page_,
Dart_Handle dart_handle,
EvaluateScriptsCallback result_callback);

void evaluateScriptsByIdInternal(void* page_,
uint32_t script_id,
int64_t profile_id,
Dart_Handle dart_handle,
EvaluateScriptsByIdCallback result_callback);

void evaluateQuickjsByteCodeInternal(void* page_,
uint8_t* bytes,
int32_t byteLen,
Expand All @@ -30,10 +36,17 @@ void evaluateQuickjsByteCodeInternal(void* page_,

void evaluateWbcInternal(void* page_,
uint8_t* bytes,
int32_t byte_len,
uint32_t byte_len,
int64_t profile_id,
Dart_PersistentHandle persistent_handle,
EvaluateQuickjsByteCodeCallback result_callback);

void evaluateWbcByIdInternal(void* page_,
uint32_t script_id,
int64_t profile_id,
Dart_PersistentHandle persistent_handle,
EvaluateQuickjsByteCodeCallback result_callback);

void parseHTMLInternal(void* page_,
char* code,
int32_t length,
Expand Down
3 changes: 2 additions & 1 deletion bridge/core/dom/element_attribute_names.json5
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
},
"data": [
"id",
"className"
"className",
"__script_id__"
]
}
11 changes: 11 additions & 0 deletions bridge/core/executing_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,17 @@ bool ExecutingContext::EvaluateJavaScript(const char* code, size_t codeLength, c
return success;
}

bool ExecutingContext::EvaluateJavaScriptById(uint32_t script_id) {
auto* script_element = HTMLScriptElement::ObtainScriptElementFromId(script_id);
if (script_element == nullptr) return false;

JSValue result = JS_Eval(script_state_.ctx(), (const char*) script_element->buffer(), script_element->buffer_len(), "eval://", JS_EVAL_TYPE_GLOBAL);
DrainMicrotasks();
bool success = HandleException(&result);
JS_FreeValue(script_state_.ctx(), result);
return success;
}

bool ExecutingContext::EvaluateByteCode(uint8_t* bytes, size_t byteLength) {
dart_isolate_context_->profiler()->StartTrackSteps("ExecutingContext::EvaluateByteCode");

Expand Down
1 change: 1 addition & 0 deletions bridge/core/executing_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class ExecutingContext {
int startLine);
bool EvaluateJavaScript(const char16_t* code, size_t length, const char* sourceURL, int startLine);
bool EvaluateJavaScript(const char* code, size_t codeLength, const char* sourceURL, int startLine);
bool EvaluateJavaScriptById(uint32_t script_id);
bool EvaluateByteCode(uint8_t* bytes, size_t byteLength);
bool IsContextValid() const;
void SetContextInValid();
Expand Down
46 changes: 46 additions & 0 deletions bridge/core/html/html_script_element.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@

namespace webf {

static thread_local std::unordered_map<uint32_t, HTMLScriptElement*> code_buffer_;
static std::atomic<uint32_t> script_id_ = 0;

HTMLScriptElement::HTMLScriptElement(Document& document) : HTMLElement(html_names::kscript, &document) {}

HTMLScriptElement::~HTMLScriptElement() {
code_buffer_.erase(id_);
free(script_buffer_);
}

bool HTMLScriptElement::supports(const AtomicString& type, ExceptionState& exception_state) {
// Only class module support now.
if (type == script_type_names::kclassic) {
Expand All @@ -19,4 +27,42 @@ bool HTMLScriptElement::supports(const AtomicString& type, ExceptionState& excep
return false;
}

HTMLScriptElement* HTMLScriptElement::ObtainScriptElementFromId(uint32_t script_id) {
if (code_buffer_.count(script_id) == 0) return nullptr;
return code_buffer_[script_id];
}

uint32_t HTMLScriptElement::StoreWBCByteBuffer(uint8_t* bytes, uint32_t length) {
script_buffer_ = malloc(sizeof(uint8_t) * length);
memcpy(script_buffer_, bytes, sizeof(uint8_t) * length);
buffer_len_ = length;
uint32_t script_id = script_id_++;
code_buffer_[script_id] = this;
is_wbc_ = true;
id_ = script_id;
return script_id;
}

uint32_t HTMLScriptElement::StoreUTF8String(const char* code, uint32_t length) {
script_buffer_ = malloc(sizeof(char) * length);
memcpy(script_buffer_, code, sizeof(uint8_t) * length);
buffer_len_ = length;
uint32_t script_id = script_id_++;
code_buffer_[script_id] = this;
id_ = script_id;
return script_id;
}

void* HTMLScriptElement::buffer() const {
return script_buffer_;
}

uint32_t HTMLScriptElement::buffer_len() const {
return buffer_len_;
}

bool HTMLScriptElement::isWBC() const {
return is_wbc_;
}

} // namespace webf
15 changes: 15 additions & 0 deletions bridge/core/html/html_script_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,23 @@ class HTMLScriptElement : public HTMLElement {

public:
static bool supports(const AtomicString& type, ExceptionState& exception_state);
static HTMLScriptElement* ObtainScriptElementFromId(uint32_t script_id);

explicit HTMLScriptElement(Document& document);
~HTMLScriptElement();

uint32_t StoreWBCByteBuffer(uint8_t* bytes, uint32_t length);
uint32_t StoreUTF8String(const char* code, uint32_t length);

void* buffer() const;
uint32_t buffer_len() const;
bool isWBC() const;

private:
void* script_buffer_;
uint32_t buffer_len_;
uint32_t id_;
bool is_wbc_ = false;
};

} // namespace webf
Expand Down
62 changes: 56 additions & 6 deletions bridge/core/html/parser/html_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#include "core/dom/document.h"
#include "core/dom/element.h"
#include "core/dom/text.h"
#include "html_element_type_helper.h"
#include "core/html/html_script_element.h"
#include "element_attribute_names.h"
#include "element_namespace_uris.h"
#include "foundation/logging.h"
#include "html_names.h"
Expand Down Expand Up @@ -99,7 +102,8 @@ void HTMLParser::traverseHTML(Node* root_node, GumboNode* node) {

auto* html_element = DynamicTo<Element>(root_node);
if (html_element != nullptr && html_element->localName() == html_names::khtml) {
parseProperty(html_element, &node->v.element);
bool _ = false;
parseProperty(html_element, &node->v.element, &_);
}

const GumboVector* children = &node->v.element.children;
Expand Down Expand Up @@ -131,11 +135,52 @@ void HTMLParser::traverseHTML(Node* root_node, GumboNode* node) {
}
}

traverseHTML(element, child);
root_container->AppendChild(element);
parseProperty(element, &child->v.element);
bool is_script_element = child->v.element.tag == GumboTag::GUMBO_TAG_SCRIPT;
bool is_wbc_script_element;
parseProperty(element, &child->v.element, &is_wbc_script_element);
if (is_script_element) {
auto& gumbo_script_element = child->v.element;
assert(gumbo_script_element.children.length == 1);
auto* script_text_node = (GumboNode*)gumbo_script_element.children.data[0];
auto* script_element = DynamicTo<HTMLScriptElement>(element);

if (is_wbc_script_element) {
auto* bytes = (uint8_t*)script_text_node->v.text.original_text.data;
size_t total_length = script_text_node->v.text.original_text.length;
if (script_text_node->v.text.original_text.length < 20) {
return;
}
uint32_t start = -1;
// Search first 10 bytes to find start
for (size_t index = 0; index < 11; index++) {
// Verify the WBC file signature.
// https://github.com/openwebf/rfc/pull/5/files#diff-b26b0f961278d1abed24f2f4874e802e99d5f92b13cbd5f0652b47597647ed26R34
if (bytes[index] == 0x89 && bytes[index + 1] == 0x57 && bytes[index + 2] == 0x42 &&
bytes[index + 3] == 0x43 && bytes[index + 4] == 0x31 && bytes[index + 5] == 0x0D &&
bytes[index + 6] == 0x0A && bytes[index + 7] == 0x1A && bytes[index + 8] == 0x0A) {
start = index;
break;
}
}
if (start == -1) continue;

uint32_t script_id = script_element->StoreWBCByteBuffer(bytes + start, total_length - start);
script_element->setAttribute(element_attribute_names::k__script_id__,
AtomicString(ctx, std::to_string(script_id)));
} else {
uint32_t script_id = script_element->StoreUTF8String(script_text_node->v.text.original_text.data,
script_text_node->v.text.original_text.length);
script_element->setAttribute(element_attribute_names::k__script_id__,
AtomicString(ctx, std::to_string(script_id)));
}
root_container->AppendChild(element);
} else {
traverseHTML(element, child);
root_container->AppendChild(element);
}
} else if (child->type == GUMBO_NODE_TEXT) {
auto* text = context->document()->createTextNode(AtomicString(ctx, child->v.text.text), ASSERT_NO_EXCEPTION());
auto* text =
context->document()->createTextNode(AtomicString(ctx, child->v.text.text), ASSERT_NO_EXCEPTION());
root_container->AppendChild(text);
}
}
Expand Down Expand Up @@ -201,7 +246,7 @@ void HTMLParser::freeSVGResult(GumboOutput* svgTree) {
gumbo_destroy_output(&kGumboDefaultOptions, svgTree);
}

void HTMLParser::parseProperty(Element* element, GumboElement* gumboElement) {
void HTMLParser::parseProperty(Element* element, GumboElement* gumboElement, bool* is_wbc_scripts_element) {
auto* context = element->GetExecutingContext();
JSContext* ctx = context->ctx();

Expand All @@ -211,6 +256,11 @@ void HTMLParser::parseProperty(Element* element, GumboElement* gumboElement) {

std::string strName = attribute->name;
std::string strValue = attribute->value;

if (strName == "type" && strValue == "application/vnd.webf.bc1") {
*is_wbc_scripts_element = true;
}

element->setAttribute(AtomicString(ctx, strName), AtomicString(ctx, strValue), ASSERT_NO_EXCEPTION());
}
}
Expand Down
2 changes: 1 addition & 1 deletion bridge/core/html/parser/html_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class HTMLParser {
private:
ExecutingContext* context_;
static void traverseHTML(Node* root, GumboNode* node);
static void parseProperty(Element* element, GumboElement* gumboElement);
static void parseProperty(Element* element, GumboElement* gumboElement, bool* is_wbc_scripts_element);

static bool parseHTML(const std::string& html, Node* rootNode, bool isHTMLFragment);
};
Expand Down
6 changes: 6 additions & 0 deletions bridge/core/page.cc
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ bool WebFPage::evaluateScript(const char* script,
return context_->EvaluateJavaScript(script, script_len, parsed_bytecodes, bytecode_len, url, startLine);
}

bool WebFPage::evaluateScriptById(uint32_t script_id) {
if (!context_->IsContextValid())
return false;
return context_->EvaluateJavaScriptById(script_id);
}

void WebFPage::evaluateScript(const char* script, size_t length, const char* url, int startLine) {
if (!context_->IsContextValid())
return;
Expand Down
1 change: 1 addition & 0 deletions bridge/core/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class WebFPage final {
uint64_t* bytecode_len,
const char* url,
int startLine);
bool evaluateScriptById(uint32_t script_id);
bool parseHTML(const char* code, size_t length);
void evaluateScript(const char* script, size_t length, const char* url, int startLine);
uint8_t* dumpByteCode(const char* script, size_t length, const char* url, uint64_t* byteLength);
Expand Down
18 changes: 17 additions & 1 deletion bridge/include/webf_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ typedef void (*EvaluateQuickjsByteCodeCallback)(Dart_Handle dart_handle, int8_t)
typedef void (*DumpQuickjsByteCodeCallback)(Dart_Handle);
typedef void (*ParseHTMLCallback)(Dart_Handle);
typedef void (*EvaluateScriptsCallback)(Dart_Handle dart_handle, int8_t);
typedef void (*EvaluateScriptsByIdCallback)(Dart_Handle dart_handle, int8_t);

WEBF_EXPORT_C
void* initDartIsolateContextSync(int64_t dart_port,
Expand Down Expand Up @@ -80,6 +81,14 @@ void evaluateScripts(void* page,
int64_t profile_id,
Dart_Handle dart_handle,
EvaluateQuickjsByteCodeCallback result_callback);

WEBF_EXPORT_C
void evaluateScriptsById(void* page,
uint32_t script_id,
int64_t profile_id,
Dart_Handle dart_handle,
EvaluateScriptsByIdCallback result_callback);

WEBF_EXPORT_C
void evaluateQuickjsByteCode(void* page,
uint8_t* bytes,
Expand Down Expand Up @@ -107,7 +116,14 @@ void evaluateWbc(void* page_,
Dart_Handle dart_handle,
EvaluateQuickjsByteCodeCallback result_callback);

WEBF_EXPORT_C
WEBF_EXPORT_C
void evaluateWbcById(void* page_,
uint32_t script_id,
int64_t profile_id,
Dart_Handle dart_handle,
EvaluateQuickjsByteCodeCallback result_callback);

WEBF_EXPORT_C
void parseHTML(void* page,
char* code,
int32_t length,
Expand Down
Loading

0 comments on commit 6feb3f0

Please sign in to comment.