From f0bfba1ee9afc6c01baca4e6e42439526e848204 Mon Sep 17 00:00:00 2001 From: Aakash Patel Date: Thu, 14 Nov 2024 15:03:41 -0800 Subject: [PATCH] Add HermesBuiltin applyArguments Summary: We'll use this new builtin for a fast path when applying with `arguments`. Reviewed By: tmikov Differential Revision: D65348304 fbshipit-source-id: ac45d2b4de048ea0ed22224f6b8ca8d1cfe7a71b --- include/hermes/FrontEndDefs/Builtins.def | 1 + include/hermes/VM/NativeFunctions.def | 1 + include/hermes/VM/PredefinedStrings.def | 1 + lib/VM/JSLib/HermesBuiltin.cpp | 42 ++++++++++++++++++++++++ 4 files changed, 45 insertions(+) diff --git a/include/hermes/FrontEndDefs/Builtins.def b/include/hermes/FrontEndDefs/Builtins.def index ccb5c0304fb..eda7bf1b4f7 100644 --- a/include/hermes/FrontEndDefs/Builtins.def +++ b/include/hermes/FrontEndDefs/Builtins.def @@ -145,6 +145,7 @@ PRIVATE_BUILTIN(copyDataProperties) PRIVATE_BUILTIN(copyRestArgs) PRIVATE_BUILTIN(arraySpread) PRIVATE_BUILTIN(apply) +PRIVATE_BUILTIN(applyArguments) PRIVATE_BUILTIN(exportAll) PRIVATE_BUILTIN(exponentiationOperator) PRIVATE_BUILTIN(initRegexNamedGroups) diff --git a/include/hermes/VM/NativeFunctions.def b/include/hermes/VM/NativeFunctions.def index 795148982f0..a90d6b4ee44 100644 --- a/include/hermes/VM/NativeFunctions.def +++ b/include/hermes/VM/NativeFunctions.def @@ -142,6 +142,7 @@ NATIVE_FUNCTION(hermesBuiltinCopyDataProperties) NATIVE_FUNCTION(hermesBuiltinCopyRestArgs) NATIVE_FUNCTION(hermesBuiltinArraySpread) NATIVE_FUNCTION(hermesBuiltinApply) +NATIVE_FUNCTION(hermesBuiltinApplyArguments) NATIVE_FUNCTION(hermesBuiltinEnsureObject) NATIVE_FUNCTION(hermesBuiltinGetMethod) NATIVE_FUNCTION(hermesBuiltinExponentiate) diff --git a/include/hermes/VM/PredefinedStrings.def b/include/hermes/VM/PredefinedStrings.def index a1490019a26..b91ece6745f 100644 --- a/include/hermes/VM/PredefinedStrings.def +++ b/include/hermes/VM/PredefinedStrings.def @@ -449,6 +449,7 @@ STR(throwReferenceError, "throwReferenceError") STR(copyDataProperties, "copyDataProperties") STR(copyRestArgs, "copyRestArgs") STR(arraySpread, "arraySpread") +STR(applyArguments, "applyArguments") STR(exportAll, "exportAll") STR(exponentiationOperator, "exponentiationOperator") STR(initRegexNamedGroups, "initRegexNamedGroups") diff --git a/lib/VM/JSLib/HermesBuiltin.cpp b/lib/VM/JSLib/HermesBuiltin.cpp index a100804355b..53515f66fc3 100644 --- a/lib/VM/JSLib/HermesBuiltin.cpp +++ b/lib/VM/JSLib/HermesBuiltin.cpp @@ -671,6 +671,43 @@ hermesBuiltinApply(void *, Runtime &runtime, NativeArgs args) { return res->getHermesValue(); } +/// \code +/// HermesBuiltin.applyArguments = function(fn, thisVal) {} +/// /endcode +/// Faster version of Function.prototype.apply which copies the arguments +/// from the caller to the callee. +CallResult +hermesBuiltinApplyArguments(void *, Runtime &runtime, NativeArgs args) { + // Copy 'arguments' from the caller's stack, then call the callee. + + Handle fn = args.dyncastArg(0); + if (LLVM_UNLIKELY(!fn)) { + return runtime.raiseTypeErrorForValue( + args.getArgHandle(0), " is not a function"); + } + + // Obtain the caller's stack frame. + auto frames = runtime.getStackFrames(); + auto it = frames.begin(); + ++it; + // Check for the extremely unlikely case where there is no caller frame. + if (LLVM_UNLIKELY(it == frames.end())) + return HermesValue::encodeUndefinedValue(); + + uint32_t argCount = it->getArgCount(); + + ScopedNativeCallFrame newFrame{runtime, argCount, *fn, false, args.getArg(1)}; + if (LLVM_UNLIKELY(newFrame.overflowed())) { + return runtime.raiseStackOverflow(Runtime::StackOverflowKind::NativeStack); + } + + for (uint32_t i = 0; i < argCount; ++i) { + newFrame->getArgRef(i) = it->getArgRef(i); + } + + return Callable::call(fn, runtime).toCallResultHermesValue(); +} + /// HermesBuiltin.exportAll(exports, source) will copy exported named /// properties from `source` to `exports`, defining them on `exports` as /// non-configurable. @@ -836,6 +873,11 @@ void createHermesBuiltins( hermesBuiltinArraySpread, 2); defineInternMethod(B::HermesBuiltin_apply, P::apply, hermesBuiltinApply, 2); + defineInternMethod( + B::HermesBuiltin_applyArguments, + P::apply, + hermesBuiltinApplyArguments, + 2); defineInternMethod( B::HermesBuiltin_exportAll, P::exportAll, hermesBuiltinExportAll); defineInternMethod(