LibJS+LibWeb: Port remaining callers to Rust pipeline
Port all remaining users of the C++ Parser/Lexer/Generator to use the Rust pipeline instead: - Intrinsics: Remove C++ fallback in parse_builtin_file() - ECMAScriptFunctionObject: Remove C++ compile() fallback - NativeJavaScriptBackedFunction: Remove C++ compile() fallback - EventTarget: Port to compile_dynamic_function - WebDriver/ExecuteScript: Port to compile_dynamic_function - LibTest/JavaScriptTestRunner.h: Remove Parser/Lexer includes - FuzzilliJs: Remove unused Parser/Lexer includes Also remove the dead Statement-based template instantiation of async_block_start/async_function_start.
This commit is contained in:
parent
0c7d50b33d
commit
3518efd71c
9 changed files with 47 additions and 113 deletions
|
|
@ -221,16 +221,11 @@ void ECMAScriptFunctionObject::get_stack_frame_size(size_t& registers_and_locals
|
|||
auto& executable = shared_data().m_executable;
|
||||
if (!executable) {
|
||||
auto rust_executable = RustIntegration::compile_function(vm(), *m_shared_data, false);
|
||||
if (rust_executable) {
|
||||
executable = rust_executable;
|
||||
executable->name = m_shared_data->m_name;
|
||||
if (Bytecode::g_dump_bytecode)
|
||||
executable->dump();
|
||||
} else if (is_module_wrapper()) {
|
||||
executable = Bytecode::compile(vm(), ecmascript_code(), kind(), name());
|
||||
} else {
|
||||
executable = Bytecode::compile(vm(), shared_data(), Bytecode::BuiltinAbstractOperationsEnabled::No);
|
||||
}
|
||||
VERIFY(rust_executable);
|
||||
executable = rust_executable;
|
||||
executable->name = m_shared_data->m_name;
|
||||
if (Bytecode::g_dump_bytecode)
|
||||
executable->dump();
|
||||
m_shared_data->clear_compile_inputs();
|
||||
}
|
||||
registers_and_locals_count = executable->registers_and_locals_count;
|
||||
|
|
@ -599,9 +594,6 @@ void async_block_start(VM& vm, T const& async_body, PromiseCapability const& pro
|
|||
// 8. Return unused.
|
||||
}
|
||||
|
||||
template void async_block_start(VM&, NonnullRefPtr<Statement const> const& async_body, PromiseCapability const&, ExecutionContext&);
|
||||
template void async_function_start(VM&, PromiseCapability const&, NonnullRefPtr<Statement const> const& async_function_body);
|
||||
|
||||
template void async_block_start(VM&, GC::Function<Completion()> const& async_body, PromiseCapability const&, ExecutionContext&);
|
||||
template void async_function_start(VM&, PromiseCapability const&, GC::Function<Completion()> const& async_function_body);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
*/
|
||||
|
||||
#include <LibGC/Root.h>
|
||||
#include <LibJS/Lexer.h>
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/Runtime/Accessor.h>
|
||||
#include <LibJS/Runtime/AggregateErrorConstructor.h>
|
||||
#include <LibJS/Runtime/AggregateErrorPrototype.h>
|
||||
|
|
@ -210,24 +208,8 @@ GC::Ref<Intrinsics> Intrinsics::create(Realm& realm)
|
|||
static Vector<GC::Root<SharedFunctionInstanceData>> parse_builtin_file(unsigned char const* script_text, VM& vm)
|
||||
{
|
||||
auto rust_compilation = RustIntegration::compile_builtin_file(script_text, vm);
|
||||
if (rust_compilation.has_value())
|
||||
return move(rust_compilation.value());
|
||||
|
||||
auto script_text_as_utf16 = Utf16String::from_utf8_without_validation({ script_text, strlen(reinterpret_cast<char const*>(script_text)) });
|
||||
auto code = SourceCode::create("BuiltinFile"_string, move(script_text_as_utf16));
|
||||
|
||||
auto lexer = Lexer { move(code) };
|
||||
auto parser = Parser { move(lexer) };
|
||||
VERIFY(!parser.has_errors());
|
||||
auto program = parser.parse_program(true);
|
||||
|
||||
Vector<GC::Root<SharedFunctionInstanceData>> shared_data_list;
|
||||
for (auto const& child : program->children()) {
|
||||
if (auto const* function_declaration = as_if<FunctionDeclaration>(*child))
|
||||
shared_data_list.append(SharedFunctionInstanceData::create_for_function_node(vm, *function_declaration));
|
||||
}
|
||||
|
||||
return shared_data_list;
|
||||
VERIFY(rust_compilation.has_value());
|
||||
return move(rust_compilation.value());
|
||||
}
|
||||
|
||||
void Intrinsics::initialize_intrinsics(Realm& realm)
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
*/
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibJS/Bytecode/BuiltinAbstractOperationsEnabled.h>
|
||||
#include <LibJS/Bytecode/Generator.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Runtime/AsyncFunctionDriverWrapper.h>
|
||||
#include <LibJS/Runtime/AsyncGenerator.h>
|
||||
|
|
@ -100,14 +98,11 @@ Bytecode::Executable& NativeJavaScriptBackedFunction::bytecode_executable()
|
|||
auto& executable = m_shared_function_instance_data->m_executable;
|
||||
if (!executable) {
|
||||
auto rust_executable = RustIntegration::compile_function(vm(), *m_shared_function_instance_data, true);
|
||||
if (rust_executable) {
|
||||
executable = rust_executable;
|
||||
executable->name = m_shared_function_instance_data->m_name;
|
||||
if (Bytecode::g_dump_bytecode)
|
||||
executable->dump();
|
||||
} else {
|
||||
executable = Bytecode::compile(vm(), m_shared_function_instance_data, Bytecode::BuiltinAbstractOperationsEnabled::Yes);
|
||||
}
|
||||
VERIFY(rust_executable);
|
||||
executable = rust_executable;
|
||||
executable->name = m_shared_function_instance_data->m_name;
|
||||
if (Bytecode::g_dump_bytecode)
|
||||
executable->dump();
|
||||
m_shared_function_instance_data->clear_compile_inputs();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,9 +118,9 @@ Optional<Result<ModuleResult, Vector<ParserError>>> compile_parsed_module(FFI::P
|
|||
// Compile a module. Returns nullopt if Rust is not available.
|
||||
Optional<Result<ModuleResult, Vector<ParserError>>> compile_module(StringView source_text, Realm& realm, StringView filename);
|
||||
|
||||
// Compile a dynamic function (new Function()). Returns nullopt if Rust is not available.
|
||||
// Compile a dynamic function (new Function()).
|
||||
// On success, returns a SharedFunctionInstanceData with source_text set.
|
||||
Optional<Result<GC::Ref<SharedFunctionInstanceData>, String>> compile_dynamic_function(
|
||||
JS_API Optional<Result<GC::Ref<SharedFunctionInstanceData>, String>> compile_dynamic_function(
|
||||
VM& vm, StringView source_text, StringView parameters_string, StringView body_parse_string,
|
||||
FunctionKind kind);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,12 +20,13 @@
|
|||
#include <LibCore/DirIterator.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Lexer.h>
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/ParserError.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/JSONObject.h>
|
||||
#include <LibJS/Runtime/Reference.h>
|
||||
#include <LibJS/Runtime/TypedArray.h>
|
||||
#include <LibJS/Runtime/ValueInlines.h>
|
||||
#include <LibJS/Runtime/WeakMap.h>
|
||||
#include <LibJS/Runtime/WeakSet.h>
|
||||
#include <LibJS/Script.h>
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
|
||||
#include <LibJS/Runtime/GlobalEnvironment.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/ObjectEnvironment.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibJS/RustIntegration.h>
|
||||
#include <LibWeb/Bindings/EventTargetPrototype.h>
|
||||
#include <LibWeb/Bindings/MainThreadVM.h>
|
||||
#include <LibWeb/Bindings/PrincipalHostDefined.h>
|
||||
|
|
@ -428,66 +428,44 @@ WebIDL::CallbackType* EventTarget::get_current_value_of_event_handler(FlyString
|
|||
// 6. Let settings object be the relevant settings object of document.
|
||||
auto& settings_object = document->relevant_settings_object();
|
||||
|
||||
// NOTE: ECMAScriptFunctionObject::create expects a parsed body as input, so we must do the spec's sourceText steps here.
|
||||
StringBuilder builder(StringBuilder::Mode::UTF16);
|
||||
// Build source text and parameter strings for the event handler function.
|
||||
StringBuilder source_builder;
|
||||
StringView parameters_string;
|
||||
|
||||
// sourceText
|
||||
// sourceText / ParameterList
|
||||
if (name == HTML::EventNames::error && is<HTML::Window>(this)) {
|
||||
// -> If name is onerror and eventTarget is a Window object
|
||||
// The string formed by concatenating "function ", name, "(event, source, lineno, colno, error) {", U+000A LF, body, U+000A LF, and "}".
|
||||
builder.appendff("function {}(event, source, lineno, colno, error) {{\n{}\n}}", name, body);
|
||||
// Let the function have five arguments, named event, source, lineno, colno, and error.
|
||||
source_builder.appendff("function {}(event, source, lineno, colno, error) {{\n{}\n}}", name, body);
|
||||
parameters_string = "event, source, lineno, colno, error"sv;
|
||||
} else {
|
||||
// -> Otherwise
|
||||
// The string formed by concatenating "function ", name, "(event) {", U+000A LF, body, U+000A LF, and "}".
|
||||
builder.appendff("function {}(event) {{\n{}\n}}", name, body);
|
||||
// Let the function have a single argument called event.
|
||||
source_builder.appendff("function {}(event) {{\n{}\n}}", name, body);
|
||||
parameters_string = "event"sv;
|
||||
}
|
||||
|
||||
auto source_text = builder.to_utf16_string();
|
||||
auto source_text = source_builder.to_byte_string();
|
||||
|
||||
auto parser = JS::Parser(JS::Lexer(JS::SourceCode::create({}, source_text)));
|
||||
auto& vm = Bindings::main_thread_vm();
|
||||
|
||||
// FIXME: This should only be parsing the `body` instead of `source_text` and therefore use `JS::FunctionBody` instead of `JS::FunctionExpression`.
|
||||
// However, JS::ECMAScriptFunctionObject::create wants parameters and length and JS::FunctionBody does not inherit JS::FunctionNode.
|
||||
auto program = parser.parse_function_node<JS::FunctionExpression>();
|
||||
auto rust_compilation = JS::RustIntegration::compile_dynamic_function(
|
||||
vm, source_text, parameters_string, body, JS::FunctionKind::Normal);
|
||||
|
||||
// 7. If body is not parsable as FunctionBody or if parsing detects an early error, then follow these substeps:
|
||||
if (parser.has_errors()) {
|
||||
if (!rust_compilation.has_value() || rust_compilation->is_error()) {
|
||||
// 1. Set eventHandler's value to null.
|
||||
// Note: This does not deactivate the event handler, which additionally removes the event handler's listener (if present).
|
||||
handler_map.remove(event_handler_iterator);
|
||||
|
||||
// FIXME: 2. Report the error for the appropriate script and with the appropriate position (line number and column number) given by location, using settings object's global object.
|
||||
// If the error is still not handled after this, then the error may be reported to a developer console.
|
||||
|
||||
// 3. Return null.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto& vm = Bindings::main_thread_vm();
|
||||
|
||||
// 8. Push settings object's realm execution context onto the JavaScript execution context stack; it is now the running JavaScript execution context.
|
||||
vm.push_execution_context(settings_object.realm_execution_context());
|
||||
|
||||
// 9. Let function be the result of calling OrdinaryFunctionCreate, with arguments:
|
||||
// functionPrototype
|
||||
// %Function.prototype% (This is enforced by using JS::ECMAScriptFunctionObject)
|
||||
|
||||
// sourceText was handled above.
|
||||
|
||||
// ParameterList
|
||||
// If name is onerror and eventTarget is a Window object
|
||||
// Let the function have five arguments, named event, source, lineno, colno, and error.
|
||||
// Otherwise
|
||||
// Let the function have a single argument called event.
|
||||
// (This was handled above for us by the parser using sourceText)
|
||||
|
||||
// body
|
||||
// The result of parsing body above. (This is given by program->body())
|
||||
|
||||
// thisMode
|
||||
// non-lexical-this (For JS::ECMAScriptFunctionObject, this means passing is_arrow_function as false)
|
||||
constexpr bool is_arrow_function = false;
|
||||
|
||||
// scope
|
||||
// 1. Let realm be settings object's Realm.
|
||||
auto& realm = settings_object.realm();
|
||||
|
|
@ -508,10 +486,12 @@ WebIDL::CallbackType* EventTarget::get_current_value_of_event_handler(FlyString
|
|||
if (element)
|
||||
scope = JS::new_object_environment(*element, true, scope);
|
||||
|
||||
// 6. Return scope. (NOTE: Not necessary)
|
||||
|
||||
auto function = JS::ECMAScriptFunctionObject::create(realm, Utf16FlyString::from_utf8(name), move(source_text), program->body(), program->parameters(), program->function_length(), program->local_variables_names(), scope, nullptr, JS::FunctionKind::Normal, program->is_strict_mode(),
|
||||
program->parsing_insights(), is_arrow_function);
|
||||
// 9. Let function be the result of calling OrdinaryFunctionCreate.
|
||||
auto function = JS::ECMAScriptFunctionObject::create_from_function_data(
|
||||
realm,
|
||||
rust_compilation->value(),
|
||||
scope,
|
||||
nullptr);
|
||||
|
||||
// 10. Remove settings object's realm execution context from the JavaScript execution context stack.
|
||||
VERIFY(vm.execution_context_stack().last() == &settings_object.realm_execution_context());
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
|
||||
#include <LibJS/Runtime/GlobalEnvironment.h>
|
||||
#include <LibJS/Runtime/ObjectEnvironment.h>
|
||||
#include <LibJS/Runtime/PromiseConstructor.h>
|
||||
#include <LibJS/Runtime/SharedFunctionInstanceData.h>
|
||||
#include <LibJS/RustIntegration.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/HTML/BrowsingContext.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
|
|
@ -56,37 +56,23 @@ static JS::ThrowCompletionOr<JS::Value> execute_a_function_body(HTML::BrowsingCo
|
|||
}})~~~",
|
||||
body);
|
||||
|
||||
auto parser = JS::Parser(JS::Lexer(JS::SourceCode::create({}, Utf16String::from_utf8(source_text))));
|
||||
;
|
||||
auto function_expression = parser.parse_function_node<JS::FunctionExpression>();
|
||||
auto rust_compilation = JS::RustIntegration::compile_dynamic_function(
|
||||
realm.vm(), source_text, ""sv, body, JS::FunctionKind::Normal);
|
||||
|
||||
// 4. If body is not parsable as a FunctionBody or if parsing detects an early error, return Completion { [[Type]]: normal, [[Value]]: null, [[Target]]: empty }.
|
||||
if (parser.has_errors())
|
||||
if (!rust_compilation.has_value() || rust_compilation->is_error())
|
||||
return JS::js_null();
|
||||
|
||||
// 5. If body begins with a directive prologue that contains a use strict directive then let strict be true, otherwise let strict be false.
|
||||
// NOTE: Handled in step 8 below.
|
||||
|
||||
// 6. Prepare to run a script with realm.
|
||||
HTML::prepare_to_run_script(realm);
|
||||
|
||||
// 7. Prepare to run a callback with environment settings.
|
||||
HTML::prepare_to_run_callback(realm);
|
||||
|
||||
// 8. Let function be the result of calling FunctionCreate, with arguments:
|
||||
// kind
|
||||
// Normal.
|
||||
// list
|
||||
// An empty List.
|
||||
// body
|
||||
// The result of parsing body above.
|
||||
// global scope
|
||||
// The result of parsing global scope above.
|
||||
// strict
|
||||
// The result of parsing strict above.
|
||||
// 8. Let function be the result of calling FunctionCreate.
|
||||
auto function = JS::ECMAScriptFunctionObject::create_from_function_data(
|
||||
realm,
|
||||
JS::SharedFunctionInstanceData::create_for_function_node(realm.vm(), *function_expression),
|
||||
rust_compilation->value(),
|
||||
&global_scope,
|
||||
nullptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@
|
|||
#include <AK/StringView.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Lexer.h>
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -154,9 +154,9 @@ TESTJS_RUN_FILE_FUNCTION(ByteString const& test_file, JS::Realm& realm, JS::Exec
|
|||
else
|
||||
return Test::JS::RunFileHookResult::SkipFile;
|
||||
|
||||
auto program_type = path.basename().ends_with(".module.js"sv) ? JS::Program::Type::Module : JS::Program::Type::Script;
|
||||
bool const is_module = path.basename().ends_with(".module.js"sv);
|
||||
bool parse_succeeded = false;
|
||||
if (program_type == JS::Program::Type::Module)
|
||||
if (is_module)
|
||||
parse_succeeded = !Test::JS::parse_module(test_file, realm).is_error();
|
||||
else
|
||||
parse_succeeded = !Test::JS::parse_script(test_file, realm).is_error();
|
||||
|
|
|
|||
Loading…
Reference in a new issue