mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibJS: Allocate ExecutionContext memory using alloca() when possible
This should be faster than heap allocation. However, heap allocation is still necessary in some cases, such as with generators and async functions.
This commit is contained in:
parent
5a92929282
commit
a329868c1b
Notes:
github-actions[bot]
2025-04-24 08:32:11 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: a329868c1b
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4434
Reviewed-by: https://github.com/alimpfard
10 changed files with 42 additions and 12 deletions
|
@ -242,7 +242,8 @@ ThrowCompletionOr<Value> Interpreter::run(Script& script_record, GC::Ptr<Environ
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Let scriptContext be a new ECMAScript code execution context.
|
// 2. Let scriptContext be a new ECMAScript code execution context.
|
||||||
auto script_context = ExecutionContext::create(registers_and_constants_and_locals_count, 0);
|
ExecutionContext* script_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(script_context, registers_and_constants_and_locals_count, 0);
|
||||||
|
|
||||||
// 3. Set the Function of scriptContext to null.
|
// 3. Set the Function of scriptContext to null.
|
||||||
// NOTE: This was done during execution context construction.
|
// NOTE: This was done during execution context construction.
|
||||||
|
|
|
@ -662,7 +662,8 @@ ThrowCompletionOr<Value> perform_eval(VM& vm, Value x, CallerMode strict_caller,
|
||||||
executable->dump();
|
executable->dump();
|
||||||
|
|
||||||
// 20. Let evalContext be a new ECMAScript code execution context.
|
// 20. Let evalContext be a new ECMAScript code execution context.
|
||||||
auto eval_context = ExecutionContext::create(executable->number_of_registers + executable->constants.size() + executable->local_variable_names.size(), 0);
|
ExecutionContext* eval_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(eval_context, executable->number_of_registers + executable->constants.size() + executable->local_variable_names.size(), 0);
|
||||||
|
|
||||||
// 21. Set evalContext's Function to null.
|
// 21. Set evalContext's Function to null.
|
||||||
// NOTE: This was done in the construction of eval_context.
|
// NOTE: This was done in the construction of eval_context.
|
||||||
|
|
|
@ -501,7 +501,9 @@ ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argu
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 arguments_count = max(arguments_list.size(), formal_parameters().size());
|
u32 arguments_count = max(arguments_list.size(), formal_parameters().size());
|
||||||
auto callee_context = ExecutionContext::create(m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size() + m_bytecode_executable->local_variable_names.size(), arguments_count);
|
auto registers_and_constants_and_locals_count = m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size() + m_bytecode_executable->local_variable_names.size();
|
||||||
|
ExecutionContext* callee_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, registers_and_constants_and_locals_count, arguments_count);
|
||||||
|
|
||||||
// Non-standard
|
// Non-standard
|
||||||
auto arguments = callee_context->arguments();
|
auto arguments = callee_context->arguments();
|
||||||
|
@ -571,7 +573,9 @@ ThrowCompletionOr<GC::Ref<Object>> ECMAScriptFunctionObject::internal_construct(
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 arguments_count = max(arguments_list.size(), formal_parameters().size());
|
u32 arguments_count = max(arguments_list.size(), formal_parameters().size());
|
||||||
auto callee_context = ExecutionContext::create(m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size() + m_bytecode_executable->local_variable_names.size(), arguments_count);
|
auto registers_and_constants_and_locals_count = m_bytecode_executable->number_of_registers + m_bytecode_executable->constants.size() + m_bytecode_executable->local_variable_names.size();
|
||||||
|
ExecutionContext* callee_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, registers_and_constants_and_locals_count, arguments_count);
|
||||||
|
|
||||||
// Non-standard
|
// Non-standard
|
||||||
auto arguments = callee_context->arguments();
|
auto arguments = callee_context->arguments();
|
||||||
|
|
|
@ -43,9 +43,9 @@ struct ExecutionContext {
|
||||||
private:
|
private:
|
||||||
friend class ExecutionContextAllocator;
|
friend class ExecutionContextAllocator;
|
||||||
|
|
||||||
|
public:
|
||||||
ExecutionContext(u32 registers_and_constants_and_locals_count, u32 arguments_count);
|
ExecutionContext(u32 registers_and_constants_and_locals_count, u32 arguments_count);
|
||||||
|
|
||||||
public:
|
|
||||||
void operator delete(void* ptr);
|
void operator delete(void* ptr);
|
||||||
|
|
||||||
GC::Ptr<FunctionObject> function; // [[Function]]
|
GC::Ptr<FunctionObject> function; // [[Function]]
|
||||||
|
@ -123,6 +123,22 @@ private:
|
||||||
u32 registers_and_constants_and_locals_and_arguments_count { 0 };
|
u32 registers_and_constants_and_locals_and_arguments_count { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(execution_context, \
|
||||||
|
registers_and_constants_and_locals_count, \
|
||||||
|
arguments_count) \
|
||||||
|
auto execution_context_size = sizeof(JS::ExecutionContext) \
|
||||||
|
+ ((registers_and_constants_and_locals_count) + (arguments_count)) \
|
||||||
|
* sizeof(JS::Value); \
|
||||||
|
\
|
||||||
|
void* execution_context_memory = alloca(execution_context_size); \
|
||||||
|
\
|
||||||
|
execution_context = new (execution_context_memory) \
|
||||||
|
JS::ExecutionContext((registers_and_constants_and_locals_count), (arguments_count)); \
|
||||||
|
\
|
||||||
|
ScopeGuard run_execution_context_destructor([execution_context] { \
|
||||||
|
execution_context->~ExecutionContext(); \
|
||||||
|
})
|
||||||
|
|
||||||
struct StackTraceElement {
|
struct StackTraceElement {
|
||||||
ExecutionContext* execution_context;
|
ExecutionContext* execution_context;
|
||||||
RefPtr<CachedSourceRange> source_range;
|
RefPtr<CachedSourceRange> source_range;
|
||||||
|
|
|
@ -119,7 +119,8 @@ ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, Read
|
||||||
|
|
||||||
// 2. If callerContext is not already suspended, suspend callerContext.
|
// 2. If callerContext is not already suspended, suspend callerContext.
|
||||||
// 3. Let calleeContext be a new execution context.
|
// 3. Let calleeContext be a new execution context.
|
||||||
auto callee_context = ExecutionContext::create(0, arguments_list.size());
|
ExecutionContext* callee_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, 0, arguments_list.size());
|
||||||
|
|
||||||
// 4. Set the Function of calleeContext to F.
|
// 4. Set the Function of calleeContext to F.
|
||||||
callee_context->function = this;
|
callee_context->function = this;
|
||||||
|
@ -181,7 +182,8 @@ ThrowCompletionOr<GC::Ref<Object>> NativeFunction::internal_construct(ReadonlySp
|
||||||
|
|
||||||
// 2. If callerContext is not already suspended, suspend callerContext.
|
// 2. If callerContext is not already suspended, suspend callerContext.
|
||||||
// 3. Let calleeContext be a new execution context.
|
// 3. Let calleeContext be a new execution context.
|
||||||
auto callee_context = ExecutionContext::create(0, arguments_list.size());
|
ExecutionContext* callee_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, 0, arguments_list.size());
|
||||||
|
|
||||||
// 4. Set the Function of calleeContext to F.
|
// 4. Set the Function of calleeContext to F.
|
||||||
callee_context->function = this;
|
callee_context->function = this;
|
||||||
|
|
|
@ -62,7 +62,9 @@ ThrowCompletionOr<Value> WrappedFunction::internal_call(Value this_argument, Rea
|
||||||
// NOTE: No-op, kept by the VM in its execution context stack.
|
// NOTE: No-op, kept by the VM in its execution context stack.
|
||||||
|
|
||||||
// 2. Let calleeContext be PrepareForWrappedFunctionCall(F).
|
// 2. Let calleeContext be PrepareForWrappedFunctionCall(F).
|
||||||
auto callee_context = ExecutionContext::create(0, 0);
|
ExecutionContext* callee_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(callee_context, 0, 0);
|
||||||
|
|
||||||
prepare_for_wrapped_function_call(*this, *callee_context);
|
prepare_for_wrapped_function_call(*this, *callee_context);
|
||||||
|
|
||||||
// 3. Assert: calleeContext is now the running execution context.
|
// 3. Assert: calleeContext is now the running execution context.
|
||||||
|
|
|
@ -701,7 +701,8 @@ ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, GC::Ptr<Promise
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Let moduleContext be a new ECMAScript code execution context.
|
// 1. Let moduleContext be a new ECMAScript code execution context.
|
||||||
auto module_context = ExecutionContext::create(registers_and_constants_and_locals_count, 0);
|
ExecutionContext* module_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(module_context, registers_and_constants_and_locals_count, 0);
|
||||||
|
|
||||||
// Note: This is not in the spec but we require it.
|
// Note: This is not in the spec but we require it.
|
||||||
module_context->is_strict_mode = true;
|
module_context->is_strict_mode = true;
|
||||||
|
|
|
@ -81,7 +81,8 @@ ThrowCompletionOr<Promise*> SyntheticModule::evaluate(VM& vm)
|
||||||
// NOTE: Done by the push on step 8.
|
// NOTE: Done by the push on step 8.
|
||||||
|
|
||||||
// 2. Let moduleContext be a new ECMAScript code execution context.
|
// 2. Let moduleContext be a new ECMAScript code execution context.
|
||||||
auto module_context = ExecutionContext::create(0, 0);
|
ExecutionContext* module_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(module_context, 0, 0);
|
||||||
|
|
||||||
// 3. Set the Function of moduleContext to null.
|
// 3. Set the Function of moduleContext to null.
|
||||||
// Note: This is the default value.
|
// Note: This is the default value.
|
||||||
|
|
|
@ -585,7 +585,8 @@ ErrorOr<void> initialize_main_thread_vm(HTML::EventLoop::Type type)
|
||||||
// 5. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
|
// 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.
|
// 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(0, 0);
|
JS::ExecutionContext* module_execution_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(module_execution_context, 0, 0);
|
||||||
module_execution_context->realm = realm;
|
module_execution_context->realm = realm;
|
||||||
if (module)
|
if (module)
|
||||||
module_execution_context->script_or_module = GC::Ref { *module };
|
module_execution_context->script_or_module = GC::Ref { *module };
|
||||||
|
|
|
@ -102,7 +102,8 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting)
|
||||||
VERIFY(record);
|
VERIFY(record);
|
||||||
|
|
||||||
// NON-STANDARD: To ensure that LibJS can find the module on the stack, we push a new execution context.
|
// 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(0, 0);
|
JS::ExecutionContext* module_execution_context = nullptr;
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(module_execution_context, 0, 0);
|
||||||
module_execution_context->realm = &realm;
|
module_execution_context->realm = &realm;
|
||||||
module_execution_context->script_or_module = GC::Ref<JS::Module> { *record };
|
module_execution_context->script_or_module = GC::Ref<JS::Module> { *record };
|
||||||
vm().push_execution_context(*module_execution_context);
|
vm().push_execution_context(*module_execution_context);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue