mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-17 07:50:04 +00:00
LibJS+LibWeb: Calculate count of regs+consts+locals before EC allocation
This is a preparation step before joining arguments vector into vector of registers+constants+locals.
This commit is contained in:
parent
fca1d33fec
commit
80a8040794
Notes:
github-actions[bot]
2025-04-24 08:32:54 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 80a8040794
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4434
Reviewed-by: https://github.com/alimpfard
14 changed files with 144 additions and 107 deletions
|
@ -208,8 +208,41 @@ ThrowCompletionOr<Value> Interpreter::run(Script& script_record, GC::Ptr<Environ
|
|||
// 1. Let globalEnv be scriptRecord.[[Realm]].[[GlobalEnv]].
|
||||
auto& global_environment = script_record.realm().global_environment();
|
||||
|
||||
// NOTE: Spec steps are rearranged in order to compute number of registers+constants+locals before construction of the execution context.
|
||||
|
||||
// 11. Let script be scriptRecord.[[ECMAScriptCode]].
|
||||
auto& script = script_record.parse_node();
|
||||
|
||||
// 12. Let result be Completion(GlobalDeclarationInstantiation(script, globalEnv)).
|
||||
auto instantiation_result = script.global_declaration_instantiation(vm, global_environment);
|
||||
Completion result = instantiation_result.is_throw_completion() ? instantiation_result.throw_completion() : normal_completion(js_undefined());
|
||||
|
||||
GC::Ptr<Executable> executable;
|
||||
if (result.type() == Completion::Type::Normal) {
|
||||
auto executable_result = JS::Bytecode::Generator::generate_from_ast_node(vm, script, {});
|
||||
|
||||
if (executable_result.is_error()) {
|
||||
if (auto error_string = executable_result.error().to_string(); error_string.is_error())
|
||||
result = vm.template throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory));
|
||||
else if (error_string = String::formatted("TODO({})", error_string.value()); error_string.is_error())
|
||||
result = vm.template throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory));
|
||||
else
|
||||
result = vm.template throw_completion<JS::InternalError>(error_string.release_value());
|
||||
} else {
|
||||
executable = executable_result.release_value();
|
||||
|
||||
if (g_dump_bytecode)
|
||||
executable->dump();
|
||||
}
|
||||
}
|
||||
|
||||
u32 registers_and_constants_and_locals_count = 0;
|
||||
if (executable) {
|
||||
registers_and_constants_and_locals_count = executable->number_of_registers + executable->constants.size() + executable->local_variable_names.size();
|
||||
}
|
||||
|
||||
// 2. Let scriptContext be a new ECMAScript code execution context.
|
||||
auto script_context = ExecutionContext::create();
|
||||
auto script_context = ExecutionContext::create(registers_and_constants_and_locals_count);
|
||||
|
||||
// 3. Set the Function of scriptContext to null.
|
||||
// NOTE: This was done during execution context construction.
|
||||
|
@ -239,38 +272,14 @@ ThrowCompletionOr<Value> Interpreter::run(Script& script_record, GC::Ptr<Environ
|
|||
// 10. Push scriptContext onto the execution context stack; scriptContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(*script_context, {}));
|
||||
|
||||
// 11. Let script be scriptRecord.[[ECMAScriptCode]].
|
||||
auto& script = script_record.parse_node();
|
||||
|
||||
// 12. Let result be Completion(GlobalDeclarationInstantiation(script, globalEnv)).
|
||||
auto instantiation_result = script.global_declaration_instantiation(vm, global_environment);
|
||||
Completion result = instantiation_result.is_throw_completion() ? instantiation_result.throw_completion() : normal_completion(js_undefined());
|
||||
|
||||
// 13. If result.[[Type]] is normal, then
|
||||
if (result.type() == Completion::Type::Normal) {
|
||||
if (executable) {
|
||||
// a. Set result to Completion(Evaluation of script).
|
||||
auto executable_result = JS::Bytecode::Generator::generate_from_ast_node(vm, script, {});
|
||||
|
||||
if (executable_result.is_error()) {
|
||||
if (auto error_string = executable_result.error().to_string(); error_string.is_error())
|
||||
result = vm.template throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory));
|
||||
else if (error_string = String::formatted("TODO({})", error_string.value()); error_string.is_error())
|
||||
result = vm.template throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory));
|
||||
else
|
||||
result = vm.template throw_completion<JS::InternalError>(error_string.release_value());
|
||||
} else {
|
||||
auto executable = executable_result.release_value();
|
||||
|
||||
if (g_dump_bytecode)
|
||||
executable->dump();
|
||||
|
||||
// a. Set result to the result of evaluating script.
|
||||
auto result_or_error = run_executable(*executable, {}, {});
|
||||
if (result_or_error.value.is_error())
|
||||
result = result_or_error.value.release_error();
|
||||
else {
|
||||
result = result_or_error.return_register_value.is_special_empty_value() ? normal_completion(js_undefined()) : result_or_error.return_register_value;
|
||||
}
|
||||
auto result_or_error = run_executable(*executable, {}, {});
|
||||
if (result_or_error.value.is_error())
|
||||
result = result_or_error.value.release_error();
|
||||
else {
|
||||
result = result_or_error.return_register_value.is_special_empty_value() ? normal_completion(js_undefined()) : result_or_error.return_register_value;
|
||||
}
|
||||
|
||||
// b. If result is a normal completion and result.[[Value]] is empty, then
|
||||
|
@ -732,8 +741,7 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(Executable& exe
|
|||
|
||||
auto& running_execution_context = vm().running_execution_context();
|
||||
u32 registers_and_constants_and_locals_count = executable.number_of_registers + executable.constants.size() + executable.local_variable_names.size();
|
||||
if (running_execution_context.registers_and_constants_and_locals.size() < registers_and_constants_and_locals_count)
|
||||
running_execution_context.registers_and_constants_and_locals.resize_with_default_value(registers_and_constants_and_locals_count, js_special_empty_value());
|
||||
VERIFY(registers_and_constants_and_locals_count <= running_execution_context.registers_and_constants_and_locals.size());
|
||||
|
||||
TemporaryChange restore_running_execution_context { m_running_execution_context, &running_execution_context };
|
||||
TemporaryChange restore_arguments { m_arguments, running_execution_context.arguments.span() };
|
||||
|
|
|
@ -646,8 +646,23 @@ ThrowCompletionOr<Value> perform_eval(VM& vm, Value x, CallerMode strict_caller,
|
|||
// 19. If runningContext is not already suspended, suspend runningContext.
|
||||
// NOTE: Done by the push on step 27.
|
||||
|
||||
// NOTE: Spec steps are rearranged in order to compute number of registers+constants+locals before construction of the execution context.
|
||||
|
||||
// 28. Let result be Completion(EvalDeclarationInstantiation(body, varEnv, lexEnv, privateEnv, strictEval)).
|
||||
TRY(eval_declaration_instantiation(vm, program, variable_environment, lexical_environment, private_environment, strict_eval));
|
||||
|
||||
// 29. If result.[[Type]] is normal, then
|
||||
// a. Set result to the result of evaluating body.
|
||||
auto executable_result = Bytecode::Generator::generate_from_ast_node(vm, program, {});
|
||||
if (executable_result.is_error())
|
||||
return vm.throw_completion<InternalError>(ErrorType::NotImplemented, TRY_OR_THROW_OOM(vm, executable_result.error().to_string()));
|
||||
auto executable = executable_result.release_value();
|
||||
executable->name = "eval"_fly_string;
|
||||
if (Bytecode::g_dump_bytecode)
|
||||
executable->dump();
|
||||
|
||||
// 20. Let evalContext be a new ECMAScript code execution context.
|
||||
auto eval_context = ExecutionContext::create();
|
||||
auto eval_context = ExecutionContext::create(executable->number_of_registers + executable->constants.size() + executable->local_variable_names.size());
|
||||
|
||||
// 21. Set evalContext's Function to null.
|
||||
// NOTE: This was done in the construction of eval_context.
|
||||
|
@ -680,21 +695,8 @@ ThrowCompletionOr<Value> perform_eval(VM& vm, Value x, CallerMode strict_caller,
|
|||
vm.pop_execution_context();
|
||||
};
|
||||
|
||||
// 28. Let result be Completion(EvalDeclarationInstantiation(body, varEnv, lexEnv, privateEnv, strictEval)).
|
||||
TRY(eval_declaration_instantiation(vm, program, variable_environment, lexical_environment, private_environment, strict_eval));
|
||||
|
||||
Optional<Value> eval_result;
|
||||
|
||||
// 29. If result.[[Type]] is normal, then
|
||||
// a. Set result to the result of evaluating body.
|
||||
auto executable_result = Bytecode::Generator::generate_from_ast_node(vm, program, {});
|
||||
if (executable_result.is_error())
|
||||
return vm.throw_completion<InternalError>(ErrorType::NotImplemented, TRY_OR_THROW_OOM(vm, executable_result.error().to_string()));
|
||||
|
||||
auto executable = executable_result.release_value();
|
||||
executable->name = "eval"_fly_string;
|
||||
if (Bytecode::g_dump_bytecode)
|
||||
executable->dump();
|
||||
auto result_or_error = vm.bytecode_interpreter().run_executable(*executable, {});
|
||||
if (result_or_error.value.is_error())
|
||||
return result_or_error.value.release_error();
|
||||
|
|
|
@ -489,7 +489,18 @@ ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argu
|
|||
// 1. Let callerContext be the running execution context.
|
||||
// NOTE: No-op, kept by the VM in its execution context stack.
|
||||
|
||||
auto callee_context = ExecutionContext::create();
|
||||
if (!m_bytecode_executable) {
|
||||
if (!ecmascript_code().bytecode_executable()) {
|
||||
if (is_module_wrapper()) {
|
||||
const_cast<Statement&>(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, ecmascript_code(), kind(), name())));
|
||||
} else {
|
||||
const_cast<Statement&>(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, *this)));
|
||||
}
|
||||
}
|
||||
m_bytecode_executable = ecmascript_code().bytecode_executable();
|
||||
}
|
||||
|
||||
auto callee_context = ExecutionContext::create(m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size() + m_bytecode_executable->local_variable_names.size());
|
||||
|
||||
// Non-standard
|
||||
callee_context->arguments.ensure_capacity(max(arguments_list.size(), formal_parameters().size()));
|
||||
|
@ -546,7 +557,18 @@ ThrowCompletionOr<GC::Ref<Object>> ECMAScriptFunctionObject::internal_construct(
|
|||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
auto callee_context = ExecutionContext::create();
|
||||
if (!m_bytecode_executable) {
|
||||
if (!ecmascript_code().bytecode_executable()) {
|
||||
if (is_module_wrapper()) {
|
||||
const_cast<Statement&>(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, ecmascript_code(), kind(), name())));
|
||||
} else {
|
||||
const_cast<Statement&>(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, *this)));
|
||||
}
|
||||
}
|
||||
m_bytecode_executable = ecmascript_code().bytecode_executable();
|
||||
}
|
||||
|
||||
auto callee_context = ExecutionContext::create(m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size() + m_bytecode_executable->local_variable_names.size());
|
||||
|
||||
// Non-standard
|
||||
callee_context->arguments.ensure_capacity(max(arguments_list.size(), formal_parameters().size()));
|
||||
|
@ -890,19 +912,6 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
|
|||
auto& vm = this->vm();
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
if (!m_bytecode_executable) {
|
||||
if (!ecmascript_code().bytecode_executable()) {
|
||||
if (is_module_wrapper()) {
|
||||
const_cast<Statement&>(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, ecmascript_code(), kind(), name())));
|
||||
} else {
|
||||
const_cast<Statement&>(ecmascript_code()).set_bytecode_executable(TRY(Bytecode::compile(vm, *this)));
|
||||
}
|
||||
}
|
||||
m_bytecode_executable = ecmascript_code().bytecode_executable();
|
||||
}
|
||||
|
||||
vm.running_execution_context().registers_and_constants_and_locals.resize_with_default_value(local_variables_names().size() + m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size(), js_special_empty_value());
|
||||
|
||||
auto result_and_frame = vm.bytecode_interpreter().run_executable(*m_bytecode_executable, {});
|
||||
|
||||
if (result_and_frame.value.is_error())
|
||||
|
|
|
@ -33,9 +33,11 @@ private:
|
|||
|
||||
static NeverDestroyed<ExecutionContextAllocator> s_execution_context_allocator;
|
||||
|
||||
NonnullOwnPtr<ExecutionContext> ExecutionContext::create()
|
||||
NonnullOwnPtr<ExecutionContext> ExecutionContext::create(u32 count)
|
||||
{
|
||||
return s_execution_context_allocator->allocate();
|
||||
auto execution_context = s_execution_context_allocator->allocate();
|
||||
execution_context->registers_and_constants_and_locals.resize_with_default_value(count, js_special_empty_value());
|
||||
return execution_context;
|
||||
}
|
||||
|
||||
void ExecutionContext::operator delete(void* ptr)
|
||||
|
@ -53,7 +55,7 @@ ExecutionContext::~ExecutionContext()
|
|||
|
||||
NonnullOwnPtr<ExecutionContext> ExecutionContext::copy() const
|
||||
{
|
||||
auto copy = create();
|
||||
auto copy = create(registers_and_constants_and_locals.size());
|
||||
copy->function = function;
|
||||
copy->realm = realm;
|
||||
copy->script_or_module = script_or_module;
|
||||
|
|
|
@ -32,7 +32,7 @@ struct CachedSourceRange : public RefCounted<CachedSourceRange> {
|
|||
|
||||
// 9.4 Execution Contexts, https://tc39.es/ecma262/#sec-execution-contexts
|
||||
struct ExecutionContext {
|
||||
static NonnullOwnPtr<ExecutionContext> create();
|
||||
static NonnullOwnPtr<ExecutionContext> create(u32);
|
||||
[[nodiscard]] NonnullOwnPtr<ExecutionContext> copy() const;
|
||||
|
||||
~ExecutionContext();
|
||||
|
@ -86,7 +86,12 @@ public:
|
|||
bool is_strict_mode { false };
|
||||
|
||||
Vector<Value> arguments;
|
||||
|
||||
private:
|
||||
friend class Bytecode::Interpreter;
|
||||
Vector<Value> registers_and_constants_and_locals;
|
||||
|
||||
public:
|
||||
Vector<Bytecode::UnwindInfo> unwind_contexts;
|
||||
Vector<Optional<size_t>> previously_scheduled_jumps;
|
||||
Vector<GC::Ptr<Environment>> saved_lexical_environments;
|
||||
|
|
|
@ -119,7 +119,7 @@ ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, Read
|
|||
|
||||
// 2. If callerContext is not already suspended, suspend callerContext.
|
||||
// 3. Let calleeContext be a new execution context.
|
||||
auto callee_context = ExecutionContext::create();
|
||||
auto callee_context = ExecutionContext::create(0);
|
||||
|
||||
// 4. Set the Function of calleeContext to F.
|
||||
callee_context->function = this;
|
||||
|
@ -180,7 +180,7 @@ ThrowCompletionOr<GC::Ref<Object>> NativeFunction::internal_construct(ReadonlySp
|
|||
|
||||
// 2. If callerContext is not already suspended, suspend callerContext.
|
||||
// 3. Let calleeContext be a new execution context.
|
||||
auto callee_context = ExecutionContext::create();
|
||||
auto callee_context = ExecutionContext::create(0);
|
||||
|
||||
// 4. Set the Function of calleeContext to F.
|
||||
callee_context->function = this;
|
||||
|
|
|
@ -36,7 +36,7 @@ ThrowCompletionOr<NonnullOwnPtr<ExecutionContext>> Realm::initialize_host_define
|
|||
// FIXME: 6. Set realm.[[TemplateMap]] to a new empty List.
|
||||
|
||||
// 7. Let newContext be a new execution context.
|
||||
auto new_context = ExecutionContext::create();
|
||||
auto new_context = ExecutionContext::create(0);
|
||||
|
||||
// 8. Set the Function of newContext to null.
|
||||
new_context->function = nullptr;
|
||||
|
|
|
@ -127,8 +127,14 @@ ThrowCompletionOr<Value> perform_shadow_realm_eval(VM& vm, StringView source_tex
|
|||
// 5. If runningContext is not already suspended, suspend runningContext.
|
||||
// NOTE: This would be unused due to step 9 and is omitted for that reason.
|
||||
|
||||
auto maybe_executable = Bytecode::compile(vm, program, FunctionKind::Normal, "ShadowRealmEval"_fly_string);
|
||||
if (maybe_executable.is_error())
|
||||
return vm.throw_completion<TypeError>(ErrorType::ShadowRealmEvaluateAbruptCompletion);
|
||||
auto executable = maybe_executable.release_value();
|
||||
|
||||
// 6. Let evalContext be GetShadowRealmContext(evalRealm, strictEval).
|
||||
auto eval_context = get_shadow_realm_context(eval_realm, strict_eval);
|
||||
u32 registers_and_constants_and_locals_count = executable->number_of_registers + executable->constants.size() + executable->local_variable_names.size();
|
||||
auto eval_context = get_shadow_realm_context(eval_realm, strict_eval, registers_and_constants_and_locals_count);
|
||||
|
||||
// 7. Let lexEnv be evalContext's LexicalEnvironment.
|
||||
auto lexical_environment = eval_context->lexical_environment;
|
||||
|
@ -147,19 +153,12 @@ ThrowCompletionOr<Value> perform_shadow_realm_eval(VM& vm, StringView source_tex
|
|||
// 11. If result.[[Type]] is normal, then
|
||||
if (!eval_result.is_throw_completion()) {
|
||||
// a. Set result to the result of evaluating body.
|
||||
auto maybe_executable = Bytecode::compile(vm, program, FunctionKind::Normal, "ShadowRealmEval"_fly_string);
|
||||
if (maybe_executable.is_error()) {
|
||||
result = maybe_executable.release_error();
|
||||
auto result_and_return_register = vm.bytecode_interpreter().run_executable(*executable, {});
|
||||
if (result_and_return_register.value.is_error()) {
|
||||
result = result_and_return_register.value.release_error();
|
||||
} else {
|
||||
auto executable = maybe_executable.release_value();
|
||||
|
||||
auto result_and_return_register = vm.bytecode_interpreter().run_executable(*executable, {});
|
||||
if (result_and_return_register.value.is_error()) {
|
||||
result = result_and_return_register.value.release_error();
|
||||
} else {
|
||||
// Resulting value is in the accumulator.
|
||||
result = result_and_return_register.return_register_value.is_special_empty_value() ? js_undefined() : result_and_return_register.return_register_value;
|
||||
}
|
||||
// Resulting value is in the accumulator.
|
||||
result = result_and_return_register.return_register_value.is_special_empty_value() ? js_undefined() : result_and_return_register.return_register_value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +194,7 @@ ThrowCompletionOr<Value> shadow_realm_import_value(VM& vm, String specifier_stri
|
|||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. Let evalContext be GetShadowRealmContext(evalRealm, true).
|
||||
auto eval_context = get_shadow_realm_context(eval_realm, true);
|
||||
auto eval_context = get_shadow_realm_context(eval_realm, true, 0);
|
||||
|
||||
// 2. Let innerCapability be ! NewPromiseCapability(%Promise%).
|
||||
auto inner_capability = MUST(new_promise_capability(vm, realm.intrinsics().promise_constructor()));
|
||||
|
@ -288,7 +287,7 @@ ThrowCompletionOr<Value> get_wrapped_value(VM& vm, Realm& caller_realm, Value va
|
|||
}
|
||||
|
||||
// 3.1.7 GetShadowRealmContext ( shadowRealmRecord, strictEval ), https://tc39.es/proposal-shadowrealm/#sec-getshadowrealmcontext
|
||||
NonnullOwnPtr<ExecutionContext> get_shadow_realm_context(Realm& shadow_realm, bool strict_eval)
|
||||
NonnullOwnPtr<ExecutionContext> get_shadow_realm_context(Realm& shadow_realm, bool strict_eval, u32 registers_and_constants_and_locals_count)
|
||||
{
|
||||
// 1. Let lexEnv be NewDeclarativeEnvironment(shadowRealmRecord.[[GlobalEnv]]).
|
||||
Environment* lexical_environment = new_declarative_environment(shadow_realm.global_environment()).ptr();
|
||||
|
@ -301,7 +300,7 @@ NonnullOwnPtr<ExecutionContext> get_shadow_realm_context(Realm& shadow_realm, bo
|
|||
variable_environment = lexical_environment;
|
||||
|
||||
// 4. Let context be a new ECMAScript code execution context.
|
||||
auto context = ExecutionContext::create();
|
||||
auto context = ExecutionContext::create(registers_and_constants_and_locals_count);
|
||||
|
||||
// 5. Set context's Function to null.
|
||||
context->function = nullptr;
|
||||
|
|
|
@ -37,6 +37,6 @@ ThrowCompletionOr<void> copy_name_and_length(VM&, FunctionObject& function, Func
|
|||
ThrowCompletionOr<Value> perform_shadow_realm_eval(VM&, StringView source_text, Realm& caller_realm, Realm& eval_realm);
|
||||
ThrowCompletionOr<Value> shadow_realm_import_value(VM&, String specifier_string, String export_name_string, Realm& caller_realm, Realm& eval_realm);
|
||||
ThrowCompletionOr<Value> get_wrapped_value(VM&, Realm& caller_realm, Value);
|
||||
NonnullOwnPtr<ExecutionContext> get_shadow_realm_context(Realm& shadow_realm, bool strict_eval);
|
||||
NonnullOwnPtr<ExecutionContext> get_shadow_realm_context(Realm& shadow_realm, bool strict_eval, u32 registers_and_constants_and_locals_count);
|
||||
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ ThrowCompletionOr<Value> WrappedFunction::internal_call(Value this_argument, Rea
|
|||
// NOTE: No-op, kept by the VM in its execution context stack.
|
||||
|
||||
// 2. Let calleeContext be PrepareForWrappedFunctionCall(F).
|
||||
auto callee_context = ExecutionContext::create();
|
||||
auto callee_context = ExecutionContext::create(0);
|
||||
prepare_for_wrapped_function_call(*this, *callee_context);
|
||||
|
||||
// 3. Assert: calleeContext is now the running execution context.
|
||||
|
|
|
@ -107,7 +107,7 @@ SourceTextModule::SourceTextModule(Realm& realm, StringView filename, Script::Ho
|
|||
RefPtr<ExportStatement const> default_export)
|
||||
: CyclicModule(realm, filename, has_top_level_await, move(requested_modules), host_defined)
|
||||
, m_ecmascript_code(move(body))
|
||||
, m_execution_context(ExecutionContext::create())
|
||||
, m_execution_context(ExecutionContext::create(0))
|
||||
, m_import_entries(move(import_entries))
|
||||
, m_local_export_entries(move(local_export_entries))
|
||||
, m_indirect_export_entries(move(indirect_export_entries))
|
||||
|
@ -680,8 +680,28 @@ ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, GC::Ptr<Promise
|
|||
{
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] SourceTextModule::execute_module({}, PromiseCapability @ {})", filename(), capability.ptr());
|
||||
|
||||
GC::Ptr<Bytecode::Executable> executable;
|
||||
if (!m_has_top_level_await) {
|
||||
Completion result;
|
||||
|
||||
auto maybe_executable = Bytecode::compile(vm, m_ecmascript_code, FunctionKind::Normal, "ShadowRealmEval"_fly_string);
|
||||
if (maybe_executable.is_error()) {
|
||||
result = maybe_executable.release_error();
|
||||
} else {
|
||||
executable = maybe_executable.release_value();
|
||||
}
|
||||
|
||||
if (result.is_error())
|
||||
return result.release_error();
|
||||
}
|
||||
|
||||
u32 registers_and_constants_and_locals_count = 0;
|
||||
if (executable) {
|
||||
registers_and_constants_and_locals_count = executable->number_of_registers + executable->constants.size() + executable->local_variable_names.size();
|
||||
}
|
||||
|
||||
// 1. Let moduleContext be a new ECMAScript code execution context.
|
||||
auto module_context = ExecutionContext::create();
|
||||
auto module_context = ExecutionContext::create(registers_and_constants_and_locals_count);
|
||||
|
||||
// Note: This is not in the spec but we require it.
|
||||
module_context->is_strict_mode = true;
|
||||
|
@ -720,19 +740,11 @@ ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, GC::Ptr<Promise
|
|||
// c. Let result be the result of evaluating module.[[ECMAScriptCode]].
|
||||
Completion result;
|
||||
|
||||
auto maybe_executable = Bytecode::compile(vm, m_ecmascript_code, FunctionKind::Normal, "ShadowRealmEval"_fly_string);
|
||||
if (maybe_executable.is_error())
|
||||
result = maybe_executable.release_error();
|
||||
else {
|
||||
auto executable = maybe_executable.release_value();
|
||||
|
||||
auto result_and_return_register = vm.bytecode_interpreter().run_executable(*executable, {});
|
||||
if (result_and_return_register.value.is_error()) {
|
||||
result = result_and_return_register.value.release_error();
|
||||
} else {
|
||||
// Resulting value is in the accumulator.
|
||||
result = result_and_return_register.return_register_value.is_special_empty_value() ? js_undefined() : result_and_return_register.return_register_value;
|
||||
}
|
||||
auto result_and_return_register = vm.bytecode_interpreter().run_executable(*executable, {});
|
||||
if (result_and_return_register.value.is_error()) {
|
||||
result = result_and_return_register.value.release_error();
|
||||
} else {
|
||||
result = result_and_return_register.return_register_value.is_special_empty_value() ? js_undefined() : result_and_return_register.return_register_value;
|
||||
}
|
||||
|
||||
// d. Let env be moduleContext's LexicalEnvironment.
|
||||
|
|
|
@ -81,7 +81,7 @@ ThrowCompletionOr<Promise*> SyntheticModule::evaluate(VM& vm)
|
|||
// NOTE: Done by the push on step 8.
|
||||
|
||||
// 2. Let moduleContext be a new ECMAScript code execution context.
|
||||
auto module_context = ExecutionContext::create();
|
||||
auto module_context = ExecutionContext::create(0);
|
||||
|
||||
// 3. Set the Function of moduleContext to null.
|
||||
// Note: This is the default value.
|
||||
|
|
|
@ -281,7 +281,7 @@ ErrorOr<void> initialize_main_thread_vm(HTML::EventLoop::Type type)
|
|||
// FIXME: We need to setup a dummy execution context in case a JS::NativeFunction is called when processing the job.
|
||||
// This is because JS::NativeFunction::call excepts something to be on the execution context stack to be able to get the caller context to initialize the environment.
|
||||
// Do note that the JS spec gives _no_ guarantee that the execution context stack has something on it if HostEnqueuePromiseJob was called with a null realm: https://tc39.es/ecma262/#job-preparedtoevaluatecode
|
||||
dummy_execution_context = JS::ExecutionContext::create();
|
||||
dummy_execution_context = JS::ExecutionContext::create(0);
|
||||
dummy_execution_context->script_or_module = script_or_module;
|
||||
vm.push_execution_context(*dummy_execution_context);
|
||||
}
|
||||
|
@ -324,7 +324,7 @@ ErrorOr<void> initialize_main_thread_vm(HTML::EventLoop::Type type)
|
|||
// 4. If active script is not null, set script execution context to a new JavaScript execution context, with its Function field set to null,
|
||||
// its Realm field set to active script's realm, and its ScriptOrModule set to active script's record.
|
||||
if (script) {
|
||||
script_execution_context = JS::ExecutionContext::create();
|
||||
script_execution_context = JS::ExecutionContext::create(0);
|
||||
script_execution_context->function = nullptr;
|
||||
script_execution_context->realm = &script->realm();
|
||||
if (is<HTML::ClassicScript>(script)) {
|
||||
|
@ -585,7 +585,7 @@ ErrorOr<void> initialize_main_thread_vm(HTML::EventLoop::Type type)
|
|||
// 5. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
|
||||
// NON-STANDARD: To ensure that LibJS can find the module on the stack, we push a new execution context.
|
||||
|
||||
auto module_execution_context = JS::ExecutionContext::create();
|
||||
auto module_execution_context = JS::ExecutionContext::create(0);
|
||||
module_execution_context->realm = realm;
|
||||
if (module)
|
||||
module_execution_context->script_or_module = GC::Ref { *module };
|
||||
|
|
|
@ -102,7 +102,7 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting)
|
|||
VERIFY(record);
|
||||
|
||||
// NON-STANDARD: To ensure that LibJS can find the module on the stack, we push a new execution context.
|
||||
auto module_execution_context = JS::ExecutionContext::create();
|
||||
auto module_execution_context = JS::ExecutionContext::create(0);
|
||||
module_execution_context->realm = &realm;
|
||||
module_execution_context->script_or_module = GC::Ref<JS::Module> { *record };
|
||||
vm().push_execution_context(*module_execution_context);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue