mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-23 09:48:56 +00:00
LibJS: Allocate context up front in SuperCallWithArgumentArray
Some checks are pending
CI / macOS, arm64, Sanitizer, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
Some checks are pending
CI / macOS, arm64, Sanitizer, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
This also removes the last user of Interpreter's argument buffer allocation API, which we've used to repeatedly shoot ourselves in the foot. Good-bye!
This commit is contained in:
parent
996ea109b3
commit
f89afe8e27
Notes:
github-actions[bot]
2025-08-31 13:25:35 +00:00
Author: https://github.com/awesomekling
Commit: f89afe8e27
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6035
2 changed files with 73 additions and 83 deletions
|
@ -1562,29 +1562,6 @@ inline Value new_regexp(VM& vm, ParsedRegex const& parsed_regex, Utf16String pat
|
||||||
return regexp_object;
|
return regexp_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 13.3.8.1 https://tc39.es/ecma262/#sec-runtime-semantics-argumentlistevaluation
|
|
||||||
inline Span<Value> argument_list_evaluation(Interpreter& interpreter, Value arguments)
|
|
||||||
{
|
|
||||||
// Note: Any spreading and actual evaluation is handled in preceding opcodes
|
|
||||||
// Note: The spec uses the concept of a list, while we create a temporary array
|
|
||||||
// in the preceding opcodes, so we have to convert in a manner that is not
|
|
||||||
// visible to the user
|
|
||||||
|
|
||||||
auto& argument_array = arguments.as_array();
|
|
||||||
auto array_length = argument_array.indexed_properties().array_like_size();
|
|
||||||
|
|
||||||
auto argument_values = interpreter.allocate_argument_values(array_length);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < array_length; ++i) {
|
|
||||||
if (auto maybe_value = argument_array.indexed_properties().get(i); maybe_value.has_value())
|
|
||||||
argument_values[i] = maybe_value.release_value().value;
|
|
||||||
else
|
|
||||||
argument_values[i] = js_undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
return argument_values;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ThrowCompletionOr<void> create_variable(VM& vm, Utf16FlyString const& name, Op::EnvironmentMode mode, bool is_global, bool is_immutable, bool is_strict)
|
inline ThrowCompletionOr<void> create_variable(VM& vm, Utf16FlyString const& name, Op::EnvironmentMode mode, bool is_global, bool is_immutable, bool is_strict)
|
||||||
{
|
{
|
||||||
if (mode == Op::EnvironmentMode::Lexical) {
|
if (mode == Op::EnvironmentMode::Lexical) {
|
||||||
|
@ -1631,59 +1608,6 @@ inline ThrowCompletionOr<ECMAScriptFunctionObject*> new_class(VM& vm, Value supe
|
||||||
return TRY(class_expression.create_class_constructor(vm, class_environment, vm.lexical_environment(), super_class, element_keys, binding_name, class_name));
|
return TRY(class_expression.create_class_constructor(vm, class_environment, vm.lexical_environment(), super_class, element_keys, binding_name, class_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 13.3.7.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
|
|
||||||
inline ThrowCompletionOr<GC::Ref<Object>> super_call_with_argument_array(Interpreter& interpreter, Value argument_array, bool is_synthetic)
|
|
||||||
{
|
|
||||||
auto& vm = interpreter.vm();
|
|
||||||
|
|
||||||
// 1. Let newTarget be GetNewTarget().
|
|
||||||
auto new_target = vm.get_new_target();
|
|
||||||
|
|
||||||
// 2. Assert: Type(newTarget) is Object.
|
|
||||||
VERIFY(new_target.is_object());
|
|
||||||
|
|
||||||
// 3. Let func be GetSuperConstructor().
|
|
||||||
auto* func = get_super_constructor(vm);
|
|
||||||
|
|
||||||
// 4. Let argList be ? ArgumentListEvaluation of Arguments.
|
|
||||||
Span<Value> arg_list;
|
|
||||||
if (is_synthetic) {
|
|
||||||
VERIFY(argument_array.is_object() && is<Array>(argument_array.as_object()));
|
|
||||||
auto const& array_value = static_cast<Array const&>(argument_array.as_object());
|
|
||||||
auto length = MUST(length_of_array_like(vm, array_value));
|
|
||||||
arg_list = interpreter.allocate_argument_values(length);
|
|
||||||
for (size_t i = 0; i < length; ++i)
|
|
||||||
arg_list[i] = array_value.get_without_side_effects(PropertyKey { i });
|
|
||||||
} else {
|
|
||||||
arg_list = argument_list_evaluation(interpreter, argument_array);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. If IsConstructor(func) is false, throw a TypeError exception.
|
|
||||||
if (!Value(func).is_constructor())
|
|
||||||
return vm.throw_completion<TypeError>(ErrorType::NotAConstructor, "Super constructor");
|
|
||||||
|
|
||||||
// 6. Let result be ? Construct(func, argList, newTarget).
|
|
||||||
auto result = TRY(construct(vm, static_cast<FunctionObject&>(*func), arg_list, &new_target.as_function()));
|
|
||||||
|
|
||||||
// 7. Let thisER be GetThisEnvironment().
|
|
||||||
auto& this_environment = as<FunctionEnvironment>(*get_this_environment(vm));
|
|
||||||
|
|
||||||
// 8. Perform ? thisER.BindThisValue(result).
|
|
||||||
TRY(this_environment.bind_this_value(vm, result));
|
|
||||||
|
|
||||||
// 9. Let F be thisER.[[FunctionObject]].
|
|
||||||
auto& f = this_environment.function_object();
|
|
||||||
|
|
||||||
// 10. Assert: F is an ECMAScript function object.
|
|
||||||
// NOTE: This is implied by the strong C++ type.
|
|
||||||
|
|
||||||
// 11. Perform ? InitializeInstanceElements(result, F).
|
|
||||||
TRY(result->initialize_instance_elements(f));
|
|
||||||
|
|
||||||
// 12. Return result.
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ThrowCompletionOr<GC::Ref<Array>> iterator_to_array(VM& vm, Value iterator)
|
inline ThrowCompletionOr<GC::Ref<Array>> iterator_to_array(VM& vm, Value iterator)
|
||||||
{
|
{
|
||||||
auto& iterator_record = static_cast<IteratorRecord&>(iterator.as_cell());
|
auto& iterator_record = static_cast<IteratorRecord&>(iterator.as_cell());
|
||||||
|
@ -2974,7 +2898,79 @@ ThrowCompletionOr<void> CallConstructWithArgumentArray::execute_impl(Bytecode::I
|
||||||
// 13.3.7.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
|
// 13.3.7.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
|
||||||
ThrowCompletionOr<void> SuperCallWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
ThrowCompletionOr<void> SuperCallWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
interpreter.set(dst(), TRY(super_call_with_argument_array(interpreter, interpreter.get(arguments()), m_is_synthetic)));
|
auto& vm = interpreter.vm();
|
||||||
|
|
||||||
|
// 1. Let newTarget be GetNewTarget().
|
||||||
|
auto new_target = vm.get_new_target();
|
||||||
|
|
||||||
|
// 2. Assert: Type(newTarget) is Object.
|
||||||
|
VERIFY(new_target.is_object());
|
||||||
|
|
||||||
|
// 3. Let func be GetSuperConstructor().
|
||||||
|
auto* func = get_super_constructor(vm);
|
||||||
|
|
||||||
|
// NON-STANDARD: We're doing this step earlier to streamline control flow.
|
||||||
|
// 5. If IsConstructor(func) is false, throw a TypeError exception.
|
||||||
|
if (!Value(func).is_constructor())
|
||||||
|
return vm.throw_completion<TypeError>(ErrorType::NotAConstructor, "Super constructor");
|
||||||
|
|
||||||
|
auto& function = static_cast<FunctionObject&>(*func);
|
||||||
|
|
||||||
|
// 4. Let argList be ? ArgumentListEvaluation of Arguments.
|
||||||
|
auto& argument_array = interpreter.get(m_arguments).as_array();
|
||||||
|
size_t argument_array_length = 0;
|
||||||
|
|
||||||
|
if (m_is_synthetic) {
|
||||||
|
argument_array_length = MUST(length_of_array_like(vm, argument_array));
|
||||||
|
} else {
|
||||||
|
argument_array_length = argument_array.indexed_properties().array_like_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutionContext* callee_context = nullptr;
|
||||||
|
size_t argument_count = argument_array_length;
|
||||||
|
size_t registers_and_constants_and_locals_count = 0;
|
||||||
|
TRY(function.get_stack_frame_size(registers_and_constants_and_locals_count, argument_count));
|
||||||
|
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK_WITHOUT_CLEARING_ARGS(callee_context, registers_and_constants_and_locals_count, max(argument_array_length, argument_count));
|
||||||
|
|
||||||
|
auto* callee_context_argument_values = callee_context->arguments.data();
|
||||||
|
auto const callee_context_argument_count = callee_context->arguments.size();
|
||||||
|
auto const insn_argument_count = argument_array_length;
|
||||||
|
|
||||||
|
if (m_is_synthetic) {
|
||||||
|
for (size_t i = 0; i < insn_argument_count; ++i)
|
||||||
|
callee_context_argument_values[i] = argument_array.get_without_side_effects(PropertyKey { i });
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < insn_argument_count; ++i) {
|
||||||
|
if (auto maybe_value = argument_array.indexed_properties().get(i); maybe_value.has_value())
|
||||||
|
callee_context_argument_values[i] = maybe_value.release_value().value;
|
||||||
|
else
|
||||||
|
callee_context_argument_values[i] = js_undefined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = insn_argument_count; i < callee_context_argument_count; ++i)
|
||||||
|
callee_context_argument_values[i] = js_undefined();
|
||||||
|
callee_context->passed_argument_count = insn_argument_count;
|
||||||
|
|
||||||
|
// 6. Let result be ? Construct(func, argList, newTarget).
|
||||||
|
auto result = TRY(function.internal_construct(*callee_context, new_target.as_function()));
|
||||||
|
|
||||||
|
// 7. Let thisER be GetThisEnvironment().
|
||||||
|
auto& this_environment = as<FunctionEnvironment>(*get_this_environment(vm));
|
||||||
|
|
||||||
|
// 8. Perform ? thisER.BindThisValue(result).
|
||||||
|
TRY(this_environment.bind_this_value(vm, result));
|
||||||
|
|
||||||
|
// 9. Let F be thisER.[[FunctionObject]].
|
||||||
|
auto& f = this_environment.function_object();
|
||||||
|
|
||||||
|
// 10. Assert: F is an ECMAScript function object.
|
||||||
|
// NOTE: This is implied by the strong C++ type.
|
||||||
|
|
||||||
|
// 11. Perform ? InitializeInstanceElements(result, F).
|
||||||
|
TRY(result->initialize_instance_elements(f));
|
||||||
|
|
||||||
|
// 12. Return result.
|
||||||
|
interpreter.set(m_dst, result);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,11 +77,6 @@ public:
|
||||||
|
|
||||||
Executable& current_executable() { return *m_current_executable; }
|
Executable& current_executable() { return *m_current_executable; }
|
||||||
Executable const& current_executable() const { return *m_current_executable; }
|
Executable const& current_executable() const { return *m_current_executable; }
|
||||||
Span<Value> allocate_argument_values(size_t argument_count)
|
|
||||||
{
|
|
||||||
m_argument_values_buffer.resize_and_keep_capacity(argument_count);
|
|
||||||
return m_argument_values_buffer.span();
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecutionContext& running_execution_context() { return *m_running_execution_context; }
|
ExecutionContext& running_execution_context() { return *m_running_execution_context; }
|
||||||
|
|
||||||
|
@ -101,7 +96,6 @@ private:
|
||||||
GC::Ptr<Object> m_global_object { nullptr };
|
GC::Ptr<Object> m_global_object { nullptr };
|
||||||
GC::Ptr<DeclarativeEnvironment> m_global_declarative_environment { nullptr };
|
GC::Ptr<DeclarativeEnvironment> m_global_declarative_environment { nullptr };
|
||||||
Span<Value> m_registers_and_constants_and_locals_arguments;
|
Span<Value> m_registers_and_constants_and_locals_arguments;
|
||||||
Vector<Value> m_argument_values_buffer;
|
|
||||||
ExecutionContext* m_running_execution_context { nullptr };
|
ExecutionContext* m_running_execution_context { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue