From c23ed104e54a852befc8e13b9cdddda8670f369a Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 15 Oct 2025 11:26:58 +0200 Subject: [PATCH] LibJS: Micro-optimize ECMAScriptFunctionObject::internal_construct() - Add FLATTEN (same as we do for internal_call()). - Demote nice-to-have VERIFYs to ASSERTs. - Pass already-known Realm to ordinary_create_from_constructor 1.03x speedup on Octane/earley-boyer.js --- Libraries/LibJS/Runtime/AbstractOperations.h | 10 ++++++++-- Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp | 12 ++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Libraries/LibJS/Runtime/AbstractOperations.h b/Libraries/LibJS/Runtime/AbstractOperations.h index 1b3e0daeac..889834d4e5 100644 --- a/Libraries/LibJS/Runtime/AbstractOperations.h +++ b/Libraries/LibJS/Runtime/AbstractOperations.h @@ -157,13 +157,19 @@ ALWAYS_INLINE ThrowCompletionOr> construct(VM& vm, FunctionObjec // 10.1.13 OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ), https://tc39.es/ecma262/#sec-ordinarycreatefromconstructor template -ThrowCompletionOr> ordinary_create_from_constructor(VM& vm, FunctionObject const& constructor, GC::Ref (Intrinsics::*intrinsic_default_prototype)(), Args&&... args) +ALWAYS_INLINE ThrowCompletionOr> ordinary_create_from_constructor(VM& vm, Realm& realm, FunctionObject const& constructor, GC::Ref (Intrinsics::*intrinsic_default_prototype)(), Args&&... args) { - auto& realm = *vm.current_realm(); auto* prototype = TRY(get_prototype_from_constructor(vm, constructor, intrinsic_default_prototype)); return realm.create(forward(args)..., *prototype); } +// 10.1.13 OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ), https://tc39.es/ecma262/#sec-ordinarycreatefromconstructor +template +ALWAYS_INLINE ThrowCompletionOr> ordinary_create_from_constructor(VM& vm, FunctionObject const& constructor, GC::Ref (Intrinsics::*intrinsic_default_prototype)(), Args&&... args) +{ + return ordinary_create_from_constructor(vm, *vm.current_realm(), constructor, intrinsic_default_prototype, forward(args)...); +} + // 7.3.35 AddValueToKeyedGroup ( groups, key, value ), https://tc39.es/ecma262/#sec-add-value-to-keyed-group template void add_value_to_keyed_group(VM& vm, GroupsType& groups, KeyType key, Value value) diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 52cb283e6c..6789ae3c9d 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -549,7 +549,7 @@ FLATTEN ThrowCompletionOr ECMAScriptFunctionObject::internal_call(Executi } // 10.2.2 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget -ThrowCompletionOr> ECMAScriptFunctionObject::internal_construct(ExecutionContext& callee_context, FunctionObject& new_target) +FLATTEN ThrowCompletionOr> ECMAScriptFunctionObject::internal_construct(ExecutionContext& callee_context, FunctionObject& new_target) { auto& vm = this->vm(); @@ -566,14 +566,14 @@ ThrowCompletionOr> ECMAScriptFunctionObject::internal_construct( // 3. If kind is base, then if (kind == ConstructorKind::Base) { // a. Let thisArgument be ? OrdinaryCreateFromConstructor(newTarget, "%Object.prototype%"). - this_argument = TRY(ordinary_create_from_constructor(vm, new_target, &Intrinsics::object_prototype, ConstructWithPrototypeTag::Tag)); + this_argument = TRY(ordinary_create_from_constructor(vm, *realm(), new_target, &Intrinsics::object_prototype, ConstructWithPrototypeTag::Tag)); } // 4. Let calleeContext be PrepareForOrdinaryCall(F, newTarget). prepare_for_ordinary_call(vm, callee_context, &new_target); // 5. Assert: calleeContext is now the running execution context. - VERIFY(&vm.running_execution_context() == &callee_context); + ASSERT(&vm.running_execution_context() == &callee_context); // 6. If kind is base, then if (kind == ConstructorKind::Base) { @@ -628,7 +628,7 @@ ThrowCompletionOr> ECMAScriptFunctionObject::internal_construct( auto this_binding = TRY(constructor_env->get_this_binding(vm)); // 16. Assert: Type(thisBinding) is Object. - VERIFY(this_binding.is_object()); + ASSERT(this_binding.is_object()); // 17. Return thisBinding. return this_binding.as_object(); @@ -765,7 +765,7 @@ void ECMAScriptFunctionObject::ordinary_call_bind_this(VM& vm, ExecutionContext& this_value = MUST(this_argument.to_object(vm)); // ii. NOTE: ToObject produces wrapper objects using calleeRealm. - VERIFY(vm.current_realm() == callee_realm); + ASSERT(vm.current_realm() == callee_realm); } } @@ -908,7 +908,7 @@ ThrowCompletionOr ECMAScriptFunctionObject::ordinary_call_evaluate_body(V if (kind() == FunctionKind::Async) return AsyncFunctionDriverWrapper::create(realm, generator_object); - VERIFY(kind() == FunctionKind::Generator); + ASSERT(kind() == FunctionKind::Generator); return generator_object; }