* Copyright (c) 2024-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/compiler/call_stub_builder.h"
#include <cstddef>
#include <tuple>
#include "ecmascript/compiler/bytecodes.h"
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/circuit_builder.h"
#include "ecmascript/compiler/slowpath_lowering.h"
#include "ecmascript/compiler/stub_builder-inl.h"
namespace panda::ecmascript::kungfu {
void CallStubBuilder::JSCallDispatchForBaseline(Label *exit, Label *noNeedCheckException)
{
this->isForBaseline_ = true;
auto env = GetEnvironment();
baselineBuiltinFp_ = CallNGCRuntime(glue_, RTSTUB_ID(GetBaselineBuiltinFp), {glue_});
Label needSkipReadBarrier(env);
Label needReadBarrier(env);
BRANCH_LIKELY(NeedSkipReadBarrier(glue_), &needSkipReadBarrier, &needReadBarrier);
Bind(&needReadBarrier);
{
CallNGCRuntime(glue_, RTSTUB_ID(CopyCallTarget), { glue_, func_ });
if (callArgs_.mode == JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV) {
CallNGCRuntime(glue_, RTSTUB_ID(CopyArgvArray),
{ glue_, callArgs_.superCallArgs.argv, callArgs_.superCallArgs.argc });
}
Jump(&needSkipReadBarrier);
}
Bind(&needSkipReadBarrier);
Label funcIsHeapObject(env);
Label funcIsCallable(env);
Label funcNotCallable(env);
JSCallInit(exit, &funcIsHeapObject, &funcIsCallable, &funcNotCallable);
Label methodIsNative(env);
Label methodNotNative(env);
BRANCH(Int64NotEqual(Int64And(callField_, isNativeMask_), Int64(0)), &methodIsNative, &methodNotNative);
Bind(&methodIsNative);
{
JSCallNative(exit);
}
Bind(&methodNotNative);
{
JSCallJSFunction(exit, noNeedCheckException);
}
}
std::tuple<bool, size_t, size_t> CallCoStubBuilder::GetOpInfo()
{
switch (op_) {
case EcmaOpcode::CALLTHIS0_IMM8_V8:
return std::make_tuple(true, 2, 0);
case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
return std::make_tuple(true, 3, 1);
case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
return std::make_tuple(true, 4, 2);
case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
return std::make_tuple(true, 5, 3);
case EcmaOpcode::CALLARG0_IMM8:
return std::make_tuple(false, 1, 0);
case EcmaOpcode::CALLARG1_IMM8_V8:
return std::make_tuple(false, 2, 1);
case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
return std::make_tuple(false, 3, 2);
case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
return std::make_tuple(false, 4, 3);
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
void CallCoStubBuilder::PrepareArgs(std::vector<GateRef> &args, std::vector<GateRef> &argsFastCall)
{
auto env = GetEnvironment();
auto &builder = *env->GetBuilder();
auto [needThis, numberValueIn, numberArg] = GetOpInfo();
actualArgc_ = builder.Int64(BytecodeCallArgc::ComputeCallArgc(numberValueIn, op_));
actualArgv_ = builder.IntPtr(0);
newTarget_ = builder.Undefined();
thisObj_ = builder.Undefined();
hirGate_ = Circuit::NullGate();
size_t argIndex = 0;
glue_ = PtrArgument(argIndex++);
func_ = TaggedArgument(argIndex++);
args.push_back(glue_);
args.push_back(actualArgc_);
args.push_back(actualArgv_);
args.push_back(func_);
args.push_back(newTarget_);
argsFastCall.push_back(glue_);
argsFastCall.push_back(func_);
if (needThis) {
thisObj_ = TaggedArgument(argIndex++);
}
args.push_back(thisObj_);
argsFastCall.push_back(thisObj_);
for (size_t i = 0; i < numberArg; i++) {
args.push_back(TaggedArgument(argIndex));
argsFastCall.push_back(TaggedArgument(argIndex));
argIndex++;
}
}
void CallCoStubBuilder::FastCallSelector(CircuitBuilder &builder, GateRef glue, GateRef func, GateRef argc,
Variable *result, Label *exit)
{
Label isHeapJSFunction(&builder);
Label fastCall(&builder);
Label notFastCall(&builder);
Label call(&builder);
Label call1(&builder);
Label slowCall(&builder);
Label callBridge(&builder);
Label callBridge1(&builder);
auto &builder_ = builder;
BRANCH_CIR(builder.TaggedIsJSFunction(glue, func), &isHeapJSFunction, exit);
builder.Bind(&isHeapJSFunction);
{
GateRef method = builder.GetMethodFromFunction(glue, func);
GateRef expectedArgc =
builder.Int64Add(builder.GetExpectedNumOfArgs(method), builder.Int64(NUM_MANDATORY_JSFUNC_ARGS));
BRANCH_CIR(builder.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT_FASTCALL), &fastCall,
¬FastCall);
builder.Bind(&fastCall);
{
BRANCH_CIR(builder.Equal(expectedArgc, argc), &call, &callBridge);
builder.Bind(&call);
result->WriteVariable(builder.Int32(static_cast<int32_t>(FastCallType::FAST_AOT_CALL)));
builder.Jump(exit);
builder.Bind(&callBridge);
result->WriteVariable(builder.Int32(static_cast<int32_t>(FastCallType::FAST_AOT_CALL_BRIDGE)));
builder.Jump(exit);
}
builder.Bind(¬FastCall);
BRANCH_CIR(builder.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT), &slowCall, exit);
builder.Bind(&slowCall);
{
BRANCH_CIR(builder.Equal(expectedArgc, argc), &call1, &callBridge1);
builder.Bind(&call1);
result->WriteVariable(builder.Int32(static_cast<int32_t>(FastCallType::AOT_CALL)));
builder.Jump(exit);
builder.Bind(&callBridge1);
result->WriteVariable(builder.Int32(static_cast<int32_t>(FastCallType::AOT_CALL_BRIDGE)));
builder.Jump(exit);
}
}
}
GateRef CallCoStubBuilder::LowerCallNGCRuntime(GateRef glue, CircuitBuilder &builder, GateRef gate, int index,
const std::vector<GateRef> &args, bool useLabel)
{
const std::string name = RuntimeStubCSigns::GetRTName(index);
if (useLabel) {
GateRef result = builder.CallNGCRuntime(glue, index, Gate::InvalidGateRef, args, gate, name.c_str());
return result;
} else {
const CallSignature *cs = RuntimeStubCSigns::Get(index);
GateRef target = builder.IntPtr(index);
GateRef result = builder.Call(cs, glue, target, builder.GetDepend(), args, gate, name.c_str());
return result;
}
}
void CallCoStubBuilder::CallNGCRuntimeWithCallTimer(GateRef glue, CircuitBuilder &builder, int index, GateRef gate,
GateRef func, Variable &result, const std::vector<GateRef> &args)
{
builder.StartCallTimer(glue, gate, {glue, func, builder.True()}, true);
result = LowerCallNGCRuntime(glue, builder, gate, index, args, true);
builder.EndCallTimer(glue, gate, {glue, func}, true);
}
static GateRef IsAotFastCall(CircuitBuilder &builder, GateRef func)
{
return builder.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT_FASTCALL);
}
static GateRef IsAotCall(CircuitBuilder &builder, GateRef func)
{
return builder.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT);
}
void CallCoStubBuilder::LowerFastSuperCall(GateRef glue, CircuitBuilder &builder, const std::vector<GateRef> &args,
GateRef elementsPtr, Variable &result, Label &exit)
{
auto env = builder.GetCurrentEnvironment();
auto &builder_ = builder;
Label fastCall(&builder);
Label notFastCall(&builder);
Label aotCall(&builder);
Label notAotCall(&builder);
ASSERT(args.size() == 5);
GateRef gate = args[0];
GateRef superFunc = args[1];
GateRef newTarget = args[2];
GateRef thisObj = args[3];
GateRef actualArgc = args[4];
GateRef method = builder.GetMethodFromFunction(glue, superFunc);
GateRef expectedNum = builder.GetExpectedNumOfArgs(method);
Label isEnableCMCGC(&builder);
Label skipReadBarrier(&builder);
BRANCH_CIR(builder.LoadWithoutBarrier(VariableType::BOOL(), glue,
builder.IntPtr(JSThread::GlueData::GetIsEnableCMCGCOffset(env->Is32Bit()))),
&isEnableCMCGC, &skipReadBarrier);
builder.Bind(&isEnableCMCGC);
{
Label readBarrier(&builder);
BRANCH_CIR_LIKELY(
builder.NeedSkipReadBarrier(glue),
&skipReadBarrier, &readBarrier);
builder_.Bind(&readBarrier);
builder_.CallNGCRuntime(glue, RTSTUB_ID(CopyCallTarget),
Gate::InvalidGateRef, {glue, superFunc}, glue);
builder_.CallNGCRuntime(glue, RTSTUB_ID(CopyArgvArray),
Gate::InvalidGateRef,
{glue, elementsPtr, actualArgc}, glue);
builder_.Jump(&skipReadBarrier);
}
builder_.Bind(&skipReadBarrier);
BRANCH_CIR(IsAotFastCall(builder, superFunc), &fastCall, ¬FastCall);
builder.Bind(&fastCall);
{
Label notBridge(&builder);
Label bridge(&builder);
BRANCH_CIR(builder.Int64Equal(expectedNum, actualArgc), ¬Bridge, &bridge);
builder.Bind(¬Bridge);
CallNGCRuntimeWithCallTimer(glue, builder, RTSTUB_ID(JSFastCallWithArgV), gate, superFunc, result,
{glue, superFunc, thisObj, actualArgc, elementsPtr});
builder.Jump(&exit);
builder.Bind(&bridge);
CallNGCRuntimeWithCallTimer(glue, builder, RTSTUB_ID(JSFastCallWithArgVAndPushArgv), gate, superFunc, result,
{glue, superFunc, thisObj, actualArgc, elementsPtr, expectedNum});
builder.Jump(&exit);
}
builder.Bind(¬FastCall);
BRANCH_CIR(IsAotCall(builder, superFunc), &aotCall, ¬AotCall);
builder_.Bind(&aotCall);
{
Label notBridge(&builder);
Label bridge(&builder);
std::vector<GateRef> callArgs {glue, actualArgc, superFunc, newTarget, thisObj, elementsPtr};
BRANCH_CIR(builder.Int64Equal(expectedNum, actualArgc), ¬Bridge, &bridge);
builder.Bind(¬Bridge);
CallNGCRuntimeWithCallTimer(glue, builder, RTSTUB_ID(JSCallWithArgV), gate, superFunc, result, callArgs);
builder.Jump(&exit);
builder.Bind(&bridge);
CallNGCRuntimeWithCallTimer(glue, builder, RTSTUB_ID(JSCallWithArgVAndPushArgv), gate, superFunc, result,
callArgs);
builder.Jump(&exit);
}
builder.Bind(¬AotCall);
CallNGCRuntimeWithCallTimer(glue, builder, RTSTUB_ID(SuperCallWithArgV), gate, superFunc, result,
{glue, actualArgc, superFunc, newTarget, thisObj, elementsPtr});
builder.Jump(&exit);
}
void CallCoStubBuilder::LowerFastCall(GateRef gate, GateRef glue, CircuitBuilder &builder, GateRef func, GateRef argc,
const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall,
Variable *result, Label *exit, bool isNew, bool useCmc)
{
auto env = builder.GetCurrentEnvironment();
Label isHeapObject(&builder);
Label isJsFcuntion(&builder);
Label fastCall(&builder);
#if !ECMASCRIPT_ENABLE_ARK_STEED
Label notFastCall(&builder);
Label slowCall(&builder);
Label call(&builder);
Label call1(&builder);
Label callBridge(&builder);
Label callBridge1(&builder);
#endif
Label slowPath(&builder);
Label notCallConstructor(&builder);
Label isCallConstructor(&builder);
#if ECMASCRIPT_ENABLE_ARK_STEED
(void)argc;
(void)argsFastCall;
#endif
auto &builder_ = builder;
Label skipReadBarrier(&builder);
Label readBarrier(&builder);
if (useCmc) {
BRANCH_CIR_LIKELY(builder.NeedSkipReadBarrier(glue), &skipReadBarrier, &readBarrier);
builder.Bind(&readBarrier);
{
builder_.CallNGCRuntime(glue, RTSTUB_ID(CopyCallTarget), Gate::InvalidGateRef, {glue, func}, glue);
builder.Jump(&skipReadBarrier);
}
builder.Bind(&skipReadBarrier);
}
BRANCH_CIR(builder.TaggedIsHeapObject(func), &isHeapObject, &slowPath);
builder.Bind(&isHeapObject);
{
BRANCH_CIR(builder.IsJSFunction(glue, func), &isJsFcuntion, &slowPath);
builder.Bind(&isJsFcuntion);
{
if (!isNew) {
BRANCH_CIR(builder.IsClassConstructor(glue, func), &slowPath, ¬CallConstructor);
builder.Bind(¬CallConstructor);
}
#if ECMASCRIPT_ENABLE_ARK_STEED
BRANCH_CIR(builder.JudgeAotAndFastCall(func,
CircuitBuilder::JudgeMethodType::HAS_AOT), &fastCall, &slowPath);
builder.Bind(&fastCall);
{
builder.StartCallTimer(glue, gate, {glue, func, builder.True()}, true);
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(SteedCallAndPushArgv));
GateRef target = builder.IntPtr(RTSTUB_ID(SteedCallAndPushArgv));
auto depend = builder.GetDepend();
result->WriteVariable(builder.Call(cs, glue, target, depend, args, gate, "callArkSteed"));
builder.EndCallTimer(glue, gate, {glue, func}, true);
builder.Jump(exit);
}
#else
GateRef method = builder.GetMethodFromFunction(glue, func);
BRANCH_CIR(builder.JudgeAotAndFastCall(func,
CircuitBuilder::JudgeMethodType::HAS_AOT_FASTCALL), &fastCall, ¬FastCall);
builder.Bind(&fastCall);
{
GateRef expectedArgc = builder.Int64Add(builder.GetExpectedNumOfArgs(method),
builder.Int64(NUM_MANDATORY_JSFUNC_ARGS));
BRANCH_CIR(builder.Equal(expectedArgc, argc), &call, &callBridge);
builder.Bind(&call);
{
builder.StartCallTimer(glue, gate, {glue, func, builder.True()}, true);
GateRef code = builder.GetCodeAddr(func);
auto depend = builder.GetDepend();
const CallSignature *cs = RuntimeStubCSigns::GetOptimizedFastCallSign();
result->WriteVariable(builder.Call(cs, glue, code, depend, argsFastCall, gate, "callFastAOT"));
builder.EndCallTimer(glue, gate, {glue, func}, true);
builder.Jump(exit);
}
builder.Bind(&callBridge);
{
builder.StartCallTimer(glue, gate, {glue, func, builder.True()}, true);
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(OptimizedFastCallAndPushArgv));
GateRef target = builder.IntPtr(RTSTUB_ID(OptimizedFastCallAndPushArgv));
auto depend = builder.GetDepend();
result->WriteVariable(builder.Call(cs, glue, target, depend, args, gate, "callFastBridge"));
builder.EndCallTimer(glue, gate, {glue, func}, true);
builder.Jump(exit);
}
}
builder.Bind(¬FastCall);
BRANCH_CIR(builder.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT),
&slowCall, &slowPath);
builder.Bind(&slowCall);
{
GateRef expectedArgc = builder.Int64Add(builder.GetExpectedNumOfArgs(method),
builder.Int64(NUM_MANDATORY_JSFUNC_ARGS));
BRANCH_CIR(builder.Equal(expectedArgc, argc), &call1, &callBridge1);
builder.Bind(&call1);
{
builder.StartCallTimer(glue, gate, {glue, func, builder.True()}, true);
GateRef code = builder.GetCodeAddr(func);
auto depend = builder.GetDepend();
const CallSignature *cs = RuntimeStubCSigns::GetOptimizedCallSign();
result->WriteVariable(builder.Call(cs, glue, code, depend, args, gate, "callAOT"));
builder.EndCallTimer(glue, gate, {glue, func}, true);
builder.Jump(exit);
}
builder.Bind(&callBridge1);
{
builder.StartCallTimer(glue, gate, {glue, func, builder.True()}, true);
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(OptimizedCallAndPushArgv));
GateRef target = builder.IntPtr(RTSTUB_ID(OptimizedCallAndPushArgv));
auto depend = builder.GetDepend();
result->WriteVariable(builder.Call(cs, glue, target, depend, args, gate, "callBridge"));
builder.EndCallTimer(glue, gate, {glue, func}, true);
builder.Jump(exit);
}
}
#endif
}
}
builder.Bind(&slowPath);
{
if (isNew) {
builder.StartCallTimer(glue, gate, {glue, func, builder.True()}, true);
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCallNew));
GateRef target = builder.IntPtr(RTSTUB_ID(JSCallNew));
auto depend = builder.GetDepend();
result->WriteVariable(builder.Call(cs, glue, target, depend, args, gate, "slowNew"));
builder.EndCallTimer(glue, gate, {glue, func}, true);
builder.Jump(exit);
} else {
builder.StartCallTimer(glue, gate, {glue, func, builder.True()}, true);
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCall));
GateRef target = builder.IntPtr(RTSTUB_ID(JSCall));
auto depend = builder.GetDepend();
result->WriteVariable(builder.Call(cs, glue, target, depend, args, gate, "jscall"));
builder.EndCallTimer(glue, gate, {glue, func}, true);
builder.Jump(exit);
}
}
}
GateRef CallCoStubBuilder::CallStubDispatch(bool useCmc)
{
std::vector<GateRef> args = {};
std::vector<GateRef> argsFastCall = {};
PrepareArgs(args, argsFastCall);
auto env = GetEnvironment();
auto &builder = *env->GetBuilder();
Label entry(env);
Label exit(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), builder.Undefined());
LowerFastCall(hirGate_, glue_, builder, func_, actualArgc_, args, argsFastCall, &result, &exit, false, useCmc);
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef CallStubBuilder::JSCallDispatch()
{
this->isForBaseline_ = false;
auto env = GetEnvironment();
Label entryPass(env);
Label exit(env);
env->SubCfgEntry(&entryPass);
DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
this->result_ = &result;
Label prepareForAsmBridgeEntry(env);
Label finishPrepare(env);
BRANCH_LIKELY(NeedSkipReadBarrier(glue_), &finishPrepare, &prepareForAsmBridgeEntry);
Bind(&prepareForAsmBridgeEntry);
{
CallNGCRuntime(glue_, RTSTUB_ID(CopyCallTarget), { glue_, func_ });
if (callArgs_.mode == JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV) {
CallNGCRuntime(glue_, RTSTUB_ID(CopyArgvArray),
{ glue_, callArgs_.superCallArgs.argv, callArgs_.superCallArgs.argc });
} else if (callArgs_.mode == JSCallMode::CALL_THIS_ARGV_WITH_RETURN) {
CallNGCRuntime(glue_, RTSTUB_ID(CopyArgvArray),
{ glue_, callArgs_.callThisArgvWithReturnArgs.argv,
ZExtInt32ToInt64(callArgs_.callThisArgvWithReturnArgs.argc) });
}
Jump(&finishPrepare);
}
Bind(&finishPrepare);
Label funcIsHeapObject(env);
Label funcIsCallable(env);
Label funcNotCallable(env);
JSCallInit(&exit, &funcIsHeapObject, &funcIsCallable, &funcNotCallable);
Label methodIsNative(env);
Label methodNotNative(env);
BRANCH(Int64NotEqual(Int64And(callField_, isNativeMask_), Int64(0)), &methodIsNative, &methodNotNative);
Bind(&methodIsNative);
{
JSCallNative(&exit);
}
Bind(&methodNotNative);
{
JSCallJSFunction(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
void CallStubBuilder::JSCallInit(Label *exit, Label *funcIsHeapObject, Label *funcIsCallable, Label *funcNotCallable)
{
if (!isForBaseline_) {
SavePcIfNeeded(glue_);
}
#if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
CallNGCRuntime(glue_, RTSTUB_ID(StartCallTimer, { glue_, func_, False()}));
#endif
if (checkIsCallable_) {
BRANCH_LIKELY(TaggedIsHeapObject(func_), funcIsHeapObject, funcNotCallable);
Bind(funcIsHeapObject);
GateRef hclass = LoadHClass(glue_, func_);
bitfield_ = LoadPrimitive(VariableType::INT32(), hclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
BRANCH_LIKELY(IsCallableFromBitField(bitfield_), funcIsCallable, funcNotCallable);
Bind(funcNotCallable);
{
if (constPool_ != Circuit::NullGate()) {
GateRef funcName = GetStringFromConstPool(glue_, constPool_, stringId_);
CallRuntime(glue_, RTSTUB_ID(ThrowNotCallableException), {funcName});
} else {
CallRuntime(glue_, RTSTUB_ID(ThrowNotCallableException), {func_});
}
Jump(exit);
}
Bind(funcIsCallable);
} else {
GateRef hclass = LoadHClass(glue_, func_);
bitfield_ = LoadPrimitive(VariableType::INT32(), hclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
}
method_ = GetMethodFromJSFunctionOrProxy(glue_, func_);
callField_ = GetCallFieldFromMethod(method_);
isNativeMask_ = Int64(static_cast<uint64_t>(1) << Method::IsNativeBit::START_BIT);
}
void CallStubBuilder::JSCallNative(Label *exit)
{
HandleProfileNativeCall();
newTarget_ = Undefined();
thisValue_ = Undefined();
numArgs_ = Int32Add(actualNumArgs_, Int32(NUM_MANDATORY_JSFUNC_ARGS));
auto env = GetEnvironment();
Label isJSFunction(env);
Label notJSFunction(env);
BRANCH(IsJSFunction(glue_, func_), &isJSFunction, ¬JSFunction);
Bind(&isJSFunction);
{
JSCallNativeInner(exit, true);
}
Bind(¬JSFunction);
{
JSCallNativeInner(exit, false);
}
}
void CallStubBuilder::JSCallNativeInner(Label *exit, bool isJSFunction)
{
if (isJSFunction) {
nativeCode_ = LoadPrimitive(VariableType::NATIVE_POINTER(), func_, IntPtr(JSFunctionBase::CODE_ENTRY_OFFSET));
} else {
nativeCode_ = LoadPrimitive(VariableType::NATIVE_POINTER(), method_,
IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
}
GateRef ret;
int idxForNative = PrepareIdxForNative();
std::vector<GateRef> argsForNative = PrepareArgsForNative();
auto env0 = GetEnvironment();
Label notFastBuiltins(env0);
switch (callArgs_.mode) {
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
if (isJSFunction) {
GateRef numArgsKeeper = numArgs_;
CallFastBuiltin(¬FastBuiltins, exit, hir_);
Bind(¬FastBuiltins);
numArgs_ = numArgsKeeper;
}
[[fallthrough]];
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
if (isJSFunction) {
Label setGlueGlobalEnv(env0);
Label next(env0);
GateRef lexicalEnv = GetFunctionLexicalEnv(glue_, func_);
{
ASM_ASSERT(GET_MESSAGE_STRING_ID(LexicalEnvIsInvalid),
BitOr(TaggedIsUndefined(lexicalEnv),
LogicAndBuilder(env0).And(TaggedIsHeapObject(lexicalEnv))
.And(IsGlobalEnv(glue_, lexicalEnv))
.Done()));
}
BRANCH_UNLIKELY(TaggedIsUndefined(lexicalEnv), &next, &setGlueGlobalEnv);
Bind(&setGlueGlobalEnv);
SetGlueGlobalEnv(glue_, lexicalEnv);
Jump(&next);
Bind(&next);
}
ret = CallNGCRuntime(glue_, idxForNative, argsForNative, hir_);
break;
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
if (isJSFunction) {
Label setGlueGlobalEnv(env0);
Label next(env0);
GateRef lexicalEnv = GetFunctionLexicalEnv(glue_, func_);
{
ASM_ASSERT(GET_MESSAGE_STRING_ID(LexicalEnvIsInvalid),
BitOr(TaggedIsUndefined(lexicalEnv),
LogicAndBuilder(env0).And(TaggedIsHeapObject(lexicalEnv))
.And(IsGlobalEnv(glue_, lexicalEnv))
.Done()));
}
BRANCH_UNLIKELY(TaggedIsUndefined(lexicalEnv), &next, &setGlueGlobalEnv);
Bind(&setGlueGlobalEnv);
SetGlueGlobalEnv(glue_, lexicalEnv);
Jump(&next);
Bind(&next);
}
ret = CallRuntime(glue_, idxForNative, argsForNative);
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
result_->WriteVariable(ret);
Jump(exit);
}
void CallStubBuilder::JSCallJSFunction(Label *exit, Label *noNeedCheckException)
{
auto env = GetEnvironment();
Label funcIsClassConstructor(env);
Label funcNotClassConstructor(env);
Label methodNotAot(env);
if (!AssemblerModule::IsCallNew(callArgs_.mode)) {
BRANCH(IsClassConstructorFromBitField(bitfield_), &funcIsClassConstructor, &funcNotClassConstructor);
Bind(&funcIsClassConstructor);
{
CallRuntime(glue_, RTSTUB_ID(ThrowCallConstructorException), {});
Jump(exit);
}
Bind(&funcNotClassConstructor);
}
HandleProfileCall();
Label skipReadBarrier(env);
Label readBarrier(env);
BRANCH_LIKELY(NeedSkipReadBarrier(glue_), &skipReadBarrier, &readBarrier);
Bind(&readBarrier);
{
CallNGCRuntime(glue_, RTSTUB_ID(CopyCallTarget), {glue_, func_});
if (callArgs_.mode == JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV) {
CallNGCRuntime(glue_, RTSTUB_ID(CopyArgvArray),
{glue_, callArgs_.superCallArgs.argv, callArgs_.superCallArgs.argc});
}
Jump(&skipReadBarrier);
}
Bind(&skipReadBarrier);
if (isForBaseline_ && env->IsBaselineBuiltin()) {
sp_ = Argument(static_cast<size_t>(BaselineCallInputs::SP));
}
if (!isForBaseline_ && env->IsAsmInterp()) {
sp_ = Argument(static_cast<size_t>(InterpreterHandlerInputs::SP));
}
Label methodisAot(env);
Label funcHasBaselineCode(env);
Label funcCheckBaselineCode(env);
Label checkIsBaselineCompiling(env);
Label methodIsFastCall(env);
Label methodNotFastCall(env);
Label methodIsSteed(env);
Label checkSteed(env);
Label checkAot(env);
{
newTarget_ = Undefined();
thisValue_ = Undefined();
realNumArgs_ = Int64Add(ZExtInt32ToInt64(actualNumArgs_), Int64(NUM_MANDATORY_JSFUNC_ARGS));
#if ECMASCRIPT_ENABLE_ARK_STEED
BRANCH(BitOr(NotSwitchToStwStub(glue_), IsJsProxy(glue_, func_)), &methodNotAot, &checkSteed);
#else
BRANCH(BitOr(NotSwitchToStwStub(glue_), IsJsProxy(glue_, func_)), &methodNotAot, &checkAot);
#endif
#if ECMASCRIPT_ENABLE_ARK_STEED
Bind(&checkSteed);
BRANCH(JudgeAotAndFastCall(func_, CircuitBuilder::JudgeMethodType::HAS_AOT), &methodIsSteed, &methodNotAot);
Bind(&methodIsSteed);
{
JSCallArkSteed(exit);
}
#else
Bind(&checkAot);
BRANCH(JudgeAotAndFastCall(func_, CircuitBuilder::JudgeMethodType::HAS_AOT_FASTCALL), &methodIsFastCall,
&methodNotFastCall);
Bind(&methodIsFastCall);
{
JSFastAotCall(exit);
}
Bind(&methodNotFastCall);
BRANCH(JudgeAotAndFastCall(func_, CircuitBuilder::JudgeMethodType::HAS_AOT), &methodisAot,
&funcCheckBaselineCode);
Bind(&methodisAot);
{
JSSlowAotCall(exit);
}
Bind(&funcCheckBaselineCode);
GateRef baselineCodeOffset = IntPtr(JSFunction::BASELINECODE_OFFSET);
GateRef baselineCode = LoadPrimitive(VariableType::JS_POINTER(), func_, baselineCodeOffset);
Branch(NotEqual(baselineCode, Undefined()), &checkIsBaselineCompiling, &methodNotAot);
Bind(&checkIsBaselineCompiling);
Branch(NotEqual(baselineCode, Hole()), &funcHasBaselineCode, &methodNotAot);
Bind(&funcHasBaselineCode);
{
GateRef res = result_->Value();
JSCallAsmInterpreter(true, &methodNotAot, exit, noNeedCheckException);
if (!isForBaseline_) {
ASSERT(CheckResultValueChangedWithReturn(res));
}
(void) res;
}
#endif
Bind(&methodNotAot);
{
JSCallAsmInterpreter(false, &methodNotAot, exit, noNeedCheckException);
}
}
}
void CallStubBuilder::JSFastAotCall(Label *exit)
{
auto env = GetEnvironment();
Label fastCall(env);
Label fastCallBridge(env);
isFast_ = true;
GateRef expectedNum = Int64And(Int64LSR(callField_, Int64(Method::NumArgsBits::START_BIT)),
Int64((1LU << Method::NumArgsBits::SIZE) - 1));
GateRef expectedArgc = Int64Add(expectedNum, Int64(NUM_MANDATORY_JSFUNC_ARGS));
BRANCH(Int64Equal(expectedArgc, realNumArgs_), &fastCall, &fastCallBridge);
GateRef code;
Bind(&fastCall);
{
isBridge_ = false;
code = GetAotCodeAddr(func_);
CallBridge(code, expectedNum, exit);
}
Bind(&fastCallBridge);
{
isBridge_ = true;
CallBridge(code, expectedNum, exit);
}
}
void CallStubBuilder::JSSlowAotCall(Label *exit)
{
auto env = GetEnvironment();
Label slowCall(env);
Label slowCallBridge(env);
isFast_ = false;
GateRef expectedNum = Int64And(Int64LSR(callField_, Int64(Method::NumArgsBits::START_BIT)),
Int64((1LU << Method::NumArgsBits::SIZE) - 1));
GateRef expectedArgc = Int64Add(expectedNum, Int64(NUM_MANDATORY_JSFUNC_ARGS));
BRANCH(Int64Equal(expectedArgc, realNumArgs_), &slowCall, &slowCallBridge);
GateRef code;
Bind(&slowCall);
{
isBridge_ = false;
code = GetAotCodeAddr(func_);
CallBridge(code, expectedNum, exit);
}
Bind(&slowCallBridge);
{
isBridge_ = true;
CallBridge(code, expectedNum, exit);
}
}
GateRef CallStubBuilder::CallConstructorBridge(const int idxForAot, const std::vector<GateRef> &argsForAot)
{
GateRef ret;
switch (callArgs_.mode) {
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
ret = CallNGCRuntime(glue_, idxForAot, argsForAot);
ret = ConstructorCheck(glue_, func_, ret, callArgs_.callConstructorArgs.thisObj);
break;
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
ret = CallNGCRuntime(glue_, idxForAot, argsForAot, hir_);
ret = ConstructorCheck(glue_, func_, ret, callArgs_.superCallArgs.thisObj);
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
return ret;
}
void CallStubBuilder::CallBridge(GateRef code, GateRef expectedNum, Label *exit)
{
int idxForAot = PrepareIdxForAot();
std::vector<GateRef> argsForAot = PrepareArgsForAot(expectedNum);
GateRef ret;
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
if (IsFastAotCall()) {
ret = FastCallOptimized(glue_, code, argsForAot, hir_);
} else if (IsSlowAotCall()) {
ret = CallOptimized(glue_, code, argsForAot, hir_);
} else {
ret = CallNGCRuntime(glue_, idxForAot, argsForAot, hir_);
}
break;
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
ret = CallNGCRuntime(glue_, idxForAot, argsForAot);
break;
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
ret = CallConstructorBridge(idxForAot, argsForAot);
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
result_->WriteVariable(ret);
Jump(exit);
}
void CallStubBuilder::JSCallAsmInterpreter(bool hasBaselineCode, Label *methodNotAot, Label *exit,
Label *noNeedCheckException)
{
if (jumpSize_ != 0) {
SaveJumpSizeIfNeeded(glue_, jumpSize_);
}
SaveHotnessCounterIfNeeded(glue_, sp_, hotnessCounter_, callArgs_.mode);
int idxForAsmInterpreter = isForBaseline_ ?
(hasBaselineCode ?
PrepareIdxForAsmInterpreterForBaselineWithBaselineCode() :
PrepareIdxForAsmInterpreterForBaselineWithoutBaselineCode()) :
(hasBaselineCode ?
PrepareIdxForAsmInterpreterWithBaselineCode() :
PrepareIdxForAsmInterpreterWithoutBaselineCode());
std::vector<GateRef> argsForAsmInterpreter = PrepareArgsForAsmInterpreter();
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
*result_ = CallNGCRuntime(glue_, idxForAsmInterpreter, argsForAsmInterpreter);
if (!isForBaseline_) {
Return();
}
break;
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
if (isForBaseline_) {
*result_ = CallNGCRuntime(glue_, idxForAsmInterpreter, argsForAsmInterpreter);
} else if (hasBaselineCode) {
Jump(methodNotAot);
} else {
*result_ = CallNGCRuntime(glue_, idxForAsmInterpreter, argsForAsmInterpreter, hir_);
Jump(exit);
}
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
if (isForBaseline_) {
if (noNeedCheckException != nullptr) {
Jump(noNeedCheckException);
} else {
Jump(exit);
}
}
}
#if ECMASCRIPT_ENABLE_ARK_STEED
std::vector<GateRef> CallStubBuilder::PrepareArgsForArkSteedPushArgv()
{
std::vector<GateRef> args;
args = { glue_, realNumArgs_, IntPtr(0), func_, newTarget_ };
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG0:
args.push_back(thisValue_);
break;
case JSCallMode::CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG1:
args.push_back(thisValue_);
args.push_back(callArgs_.callArgs.arg0);
break;
case JSCallMode::CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG2:
args.push_back(thisValue_);
args.push_back(callArgs_.callArgs.arg0);
args.push_back(callArgs_.callArgs.arg1);
break;
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG3:
args.push_back(thisValue_);
args.push_back(callArgs_.callArgs.arg0);
args.push_back(callArgs_.callArgs.arg1);
args.push_back(callArgs_.callArgs.arg2);
break;
case JSCallMode::CALL_THIS_ARG0:
args.push_back(callArgs_.callArgsWithThis.thisValue);
break;
case JSCallMode::CALL_THIS_ARG1:
args.push_back(callArgs_.callArgsWithThis.thisValue);
args.push_back(callArgs_.callArgsWithThis.arg0);
break;
case JSCallMode::CALL_THIS_ARG2:
args.push_back(callArgs_.callArgsWithThis.thisValue);
args.push_back(callArgs_.callArgsWithThis.arg0);
args.push_back(callArgs_.callArgsWithThis.arg1);
break;
case JSCallMode::CALL_THIS_ARG3:
args.push_back(callArgs_.callArgsWithThis.thisValue);
args.push_back(callArgs_.callArgsWithThis.arg0);
args.push_back(callArgs_.callArgsWithThis.arg1);
args.push_back(callArgs_.callArgsWithThis.arg2);
break;
case JSCallMode::CALL_GETTER:
args.push_back(callArgs_.callGetterArgs.receiver);
break;
case JSCallMode::CALL_SETTER:
args.push_back(callArgs_.callSetterArgs.receiver);
args.push_back(callArgs_.callSetterArgs.value);
break;
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
args.push_back(callArgs_.callThisArg2WithReturnArgs.thisValue);
args.push_back(callArgs_.callThisArg2WithReturnArgs.arg0);
args.push_back(callArgs_.callThisArg2WithReturnArgs.arg1);
break;
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
args.push_back(callArgs_.callThisArg3WithReturnArgs.argHandle);
args.push_back(callArgs_.callThisArg3WithReturnArgs.value);
args.push_back(callArgs_.callThisArg3WithReturnArgs.key);
args.push_back(callArgs_.callThisArg3WithReturnArgs.thisValue);
break;
default:
UNREACHABLE();
break;
}
return args;
}
std::vector<GateRef> CallStubBuilder::PrepareArgsForArkSteedWithArgV()
{
std::vector<GateRef> args;
GateRef steedNewTarget = newTarget_;
switch (callArgs_.mode) {
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
args = { glue_, ZExtInt32ToInt64(actualNumArgs_), func_, steedNewTarget, thisValue_,
callArgs_.callArgv.argv };
break;
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
args = { glue_, ZExtInt32ToInt64(actualNumArgs_), func_, steedNewTarget,
callArgs_.callArgvWithThis.thisValue,
callArgs_.callArgvWithThis.argv };
break;
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
args = { glue_, ZExtInt32ToInt64(actualNumArgs_), func_, steedNewTarget,
callArgs_.callThisArgvWithReturnArgs.thisValue,
callArgs_.callThisArgvWithReturnArgs.argv };
break;
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
steedNewTarget = func_;
args = { glue_, ZExtInt32ToInt64(actualNumArgs_), func_, steedNewTarget,
callArgs_.callConstructorArgs.thisObj,
callArgs_.callConstructorArgs.argv };
break;
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
steedNewTarget = callArgs_.superCallArgs.newTarget;
args = { glue_, ZExtInt32ToInt64(actualNumArgs_), func_, steedNewTarget,
callArgs_.superCallArgs.thisObj,
callArgs_.superCallArgs.argv };
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
return args;
}
void CallStubBuilder::JSCallArkSteed(Label *exit)
{
GateRef ret;
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN: {
const int idxForSteed = RTSTUB_ID(SteedCallAndPushArgv);
std::vector<GateRef> argsForSteed = PrepareArgsForArkSteedPushArgv();
ret = CallNGCRuntime(glue_, idxForSteed, argsForSteed, hir_);
break;
}
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN: {
const int idxForSteed = RTSTUB_ID(SteedCallWithArgVAndPushArgv);
std::vector<GateRef> argsForSteed = PrepareArgsForArkSteedWithArgV();
ret = CallNGCRuntime(glue_, idxForSteed, argsForSteed, hir_);
break;
}
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV: {
const int idxForSteed = RTSTUB_ID(SteedCallWithArgVAndPushArgv);
std::vector<GateRef> argsForSteed = PrepareArgsForArkSteedWithArgV();
ret = CallArkSteedConstructorBridge(idxForSteed, argsForSteed);
break;
}
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
result_->WriteVariable(ret);
Jump(exit);
}
GateRef CallStubBuilder::CallArkSteedConstructorBridge(const int idxForSteed, const std::vector<GateRef> &argsForSteed)
{
GateRef ret;
switch (callArgs_.mode) {
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
ret = CallNGCRuntime(glue_, idxForSteed, argsForSteed, hir_);
ret = ConstructorCheck(glue_, func_, ret, callArgs_.callConstructorArgs.thisObj);
break;
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
ret = CallNGCRuntime(glue_, idxForSteed, argsForSteed, hir_);
ret = ConstructorCheck(glue_, func_, ret, callArgs_.superCallArgs.thisObj);
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
return ret;
}
#endif
int CallStubBuilder::PrepareIdxForNative()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return RTSTUB_ID(PushCallArgsAndDispatchNative);
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return RTSTUB_ID(PushCallRangeAndDispatchNative);
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return RTSTUB_ID(PushCallNewAndDispatchNative);
case JSCallMode::SUPER_CALL_WITH_ARGV:
return RTSTUB_ID(SuperCall);
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
return RTSTUB_ID(SuperCallSpread);
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
std::vector<GateRef> CallStubBuilder::PrepareArgsForNative()
{
std::vector<GateRef> basicArgs = PrepareBasicArgsForNative();
std::vector<GateRef> appendArgs = PrepareAppendArgsForNative();
basicArgs.insert(basicArgs.end(), appendArgs.begin(), appendArgs.end());
return basicArgs;
}
std::vector<GateRef> CallStubBuilder::PrepareBasicArgsForNative()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
return { nativeCode_, glue_, numArgs_, func_, newTarget_, thisValue_ };
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return { nativeCode_, glue_, numArgs_, func_, newTarget_ };
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
return { glue_, nativeCode_, func_, thisValue_ };
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return { glue_, nativeCode_, func_ };
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
return {};
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
std::vector<GateRef> CallStubBuilder::PrepareAppendArgsForNative()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG0:
return {};
case JSCallMode::CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG1:
return {
callArgs_.callArgs.arg0
};
case JSCallMode::CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG2:
return {
callArgs_.callArgs.arg0,
callArgs_.callArgs.arg1
};
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG3:
return {
callArgs_.callArgs.arg0,
callArgs_.callArgs.arg1,
callArgs_.callArgs.arg2
};
case JSCallMode::CALL_THIS_ARG0:
return {
callArgs_.callArgsWithThis.thisValue
};
case JSCallMode::CALL_THIS_ARG1:
return {
callArgs_.callArgsWithThis.thisValue,
callArgs_.callArgsWithThis.arg0
};
case JSCallMode::CALL_THIS_ARG2:
return {
callArgs_.callArgsWithThis.thisValue,
callArgs_.callArgsWithThis.arg0,
callArgs_.callArgsWithThis.arg1
};
case JSCallMode::CALL_THIS_ARG3:
return {
callArgs_.callArgsWithThis.thisValue,
callArgs_.callArgsWithThis.arg0,
callArgs_.callArgsWithThis.arg1,
callArgs_.callArgsWithThis.arg2
};
case JSCallMode::CALL_GETTER:
return {
callArgs_.callGetterArgs.receiver
};
case JSCallMode::CALL_SETTER:
return {
callArgs_.callSetterArgs.receiver,
callArgs_.callSetterArgs.value
};
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
return {
callArgs_.callThisArg2WithReturnArgs.thisValue,
callArgs_.callThisArg2WithReturnArgs.arg0,
callArgs_.callThisArg2WithReturnArgs.arg1
};
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return {
callArgs_.callThisArg3WithReturnArgs.argHandle,
callArgs_.callThisArg3WithReturnArgs.value,
callArgs_.callThisArg3WithReturnArgs.key,
callArgs_.callThisArg3WithReturnArgs.thisValue
};
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
return {
callArgs_.callArgv.argc,
callArgs_.callArgv.argv
};
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
return {
callArgs_.callArgvWithThis.thisValue,
callArgs_.callArgvWithThis.argc,
callArgs_.callArgvWithThis.argv
};
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return {
callArgs_.callThisArgvWithReturnArgs.thisValue,
callArgs_.callThisArgvWithReturnArgs.argc,
callArgs_.callThisArgvWithReturnArgs.argv
};
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return {
callArgs_.callConstructorArgs.thisObj,
callArgs_.callConstructorArgs.argc,
callArgs_.callConstructorArgs.argv
};
case JSCallMode::SUPER_CALL_WITH_ARGV:
return {
callArgs_.superCallArgs.thisFunc,
callArgs_.superCallArgs.array,
IntToTaggedInt(callArgs_.superCallArgs.argc)
};
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
return {
callArgs_.superCallArgs.thisFunc,
callArgs_.superCallArgs.array
};
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
int CallStubBuilder::PrepareIdxForAot()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
if (isFast_) {
return RTSTUB_ID(OptimizedFastCallAndPushArgv);
} else {
return RTSTUB_ID(OptimizedCallAndPushArgv);
}
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
if (IsFastAotCall()) {
return RTSTUB_ID(JSFastCallWithArgV);
} else if (IsFastAotCallWithBridge()) {
return RTSTUB_ID(JSFastCallWithArgVAndPushArgv);
} else if (IsSlowAotCall()) {
return RTSTUB_ID(JSCallWithArgV);
} else {
return RTSTUB_ID(JSCallWithArgVAndPushArgv);
}
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
std::vector<GateRef> CallStubBuilder::PrepareArgsForAot(GateRef expectedNum)
{
std::vector<GateRef> basicArgs = PrepareBasicArgsForAot();
std::vector<GateRef> appendArgs = PrepareAppendArgsForAotStep1();
basicArgs.insert(basicArgs.end(), appendArgs.begin(), appendArgs.end());
appendArgs = PrepareAppendArgsForAotStep2();
basicArgs.insert(basicArgs.end(), appendArgs.begin(), appendArgs.end());
appendArgs = PrepareAppendArgsForAotStep3(expectedNum);
basicArgs.insert(basicArgs.end(), appendArgs.begin(), appendArgs.end());
return basicArgs;
}
std::vector<GateRef> CallStubBuilder::PrepareBasicArgsForAot()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
if (IsFastAotCall()) {
return { glue_, func_, thisValue_ };
} else {
return { glue_, realNumArgs_, IntPtr(0), func_, newTarget_, thisValue_ };
}
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
if (IsFastAotCall()) {
return { glue_, func_ };
} else {
return { glue_, realNumArgs_, IntPtr(0), func_, newTarget_ };
}
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
if (isFast_) {
return { glue_, func_, thisValue_, ZExtInt32ToInt64(actualNumArgs_) };
} else {
return { glue_, ZExtInt32ToInt64(actualNumArgs_), func_, newTarget_, thisValue_ };
}
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
if (!isFast_) {
return { glue_, ZExtInt32ToInt64(actualNumArgs_), func_, func_ };
}
[[fallthrough]];
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
if (isFast_) {
return { glue_, func_ };
} else {
return { glue_, ZExtInt32ToInt64(actualNumArgs_), func_, newTarget_ };
}
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
if (isFast_) {
return { glue_, func_ };
} else {
return { glue_, ZExtInt32ToInt64(actualNumArgs_), func_};
}
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
std::vector<GateRef> CallStubBuilder::PrepareAppendArgsForAotStep1()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG0:
return {};
case JSCallMode::CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG1:
return { callArgs_.callArgs.arg0 };
case JSCallMode::CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG2:
return {
callArgs_.callArgs.arg0,
callArgs_.callArgs.arg1
};
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG3:
return {
callArgs_.callArgs.arg0,
callArgs_.callArgs.arg1,
callArgs_.callArgs.arg2
};
case JSCallMode::CALL_THIS_ARG0:
return { callArgs_.callArgsWithThis.thisValue };
case JSCallMode::CALL_THIS_ARG1:
return {
callArgs_.callArgsWithThis.thisValue,
callArgs_.callArgsWithThis.arg0
};
case JSCallMode::CALL_THIS_ARG2:
return {
callArgs_.callArgsWithThis.thisValue,
callArgs_.callArgsWithThis.arg0,
callArgs_.callArgsWithThis.arg1
};
case JSCallMode::CALL_THIS_ARG3:
return {
callArgs_.callArgsWithThis.thisValue,
callArgs_.callArgsWithThis.arg0,
callArgs_.callArgsWithThis.arg1,
callArgs_.callArgsWithThis.arg2
};
case JSCallMode::CALL_GETTER:
return { callArgs_.callGetterArgs.receiver };
case JSCallMode::CALL_SETTER:
return {
callArgs_.callSetterArgs.receiver,
callArgs_.callSetterArgs.value
};
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
return {
callArgs_.callThisArg2WithReturnArgs.thisValue,
callArgs_.callThisArg2WithReturnArgs.arg0,
callArgs_.callThisArg2WithReturnArgs.arg1
};
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return {
callArgs_.callThisArg3WithReturnArgs.argHandle,
callArgs_.callThisArg3WithReturnArgs.value,
callArgs_.callThisArg3WithReturnArgs.key,
callArgs_.callThisArg3WithReturnArgs.thisValue
};
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
return { callArgs_.callArgv.argv };
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
return { callArgs_.callArgvWithThis.thisValue };
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return { callArgs_.callConstructorArgs.thisObj };
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return { callArgs_.callThisArgvWithReturnArgs.thisValue };
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
return {};
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
std::vector<GateRef> CallStubBuilder::PrepareAppendArgsForAotStep2()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
if (isFast_) {
return { ZExtInt32ToInt64(actualNumArgs_) };
}
[[fallthrough]];
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return {};
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
if (isFast_) {
return {
callArgs_.superCallArgs.thisObj,
callArgs_.superCallArgs.argc,
callArgs_.superCallArgs.argv
};
} else {
return {
callArgs_.superCallArgs.newTarget,
callArgs_.superCallArgs.thisObj,
callArgs_.superCallArgs.argv
};
}
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
std::vector<GateRef> CallStubBuilder::PrepareAppendArgsForAotStep3(GateRef expectedNum)
{
std::vector<GateRef> retArgs {};
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return {};
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
retArgs.push_back(callArgs_.callArgvWithThis.argv);
break;
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
retArgs.push_back(callArgs_.callConstructorArgs.argv);
break;
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
retArgs.push_back(callArgs_.callThisArgvWithReturnArgs.argv);
break;
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
if (IsFastAotCallWithBridge()) {
retArgs.push_back(expectedNum);
}
return retArgs;
}
int CallStubBuilder::PrepareIdxForAsmInterpreterForBaselineWithBaselineCode()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG0:
return RTSTUB_ID(CallArg0AndCheckToBaselineFromBaseline);
case JSCallMode::CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG1:
return RTSTUB_ID(CallArg1AndCheckToBaselineFromBaseline);
case JSCallMode::CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG2:
return RTSTUB_ID(CallArgs2AndCheckToBaselineFromBaseline);
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG3:
return RTSTUB_ID(CallArgs3AndCheckToBaselineFromBaseline);
case JSCallMode::CALL_THIS_ARG0:
return RTSTUB_ID(CallThisArg0AndCheckToBaselineFromBaseline);
case JSCallMode::CALL_THIS_ARG1:
return RTSTUB_ID(CallThisArg1AndCheckToBaselineFromBaseline);
case JSCallMode::CALL_THIS_ARG2:
return RTSTUB_ID(CallThisArgs2AndCheckToBaselineFromBaseline);
case JSCallMode::CALL_THIS_ARG3:
return RTSTUB_ID(CallThisArgs3AndCheckToBaselineFromBaseline);
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
return RTSTUB_ID(CallRangeAndCheckToBaselineFromBaseline);
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
return RTSTUB_ID(CallThisRangeAndCheckToBaselineFromBaseline);
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return RTSTUB_ID(CallNewAndCheckToBaselineFromBaseline);
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
return RTSTUB_ID(SuperCallAndCheckToBaselineFromBaseline);
case JSCallMode::CALL_GETTER:
return RTSTUB_ID(CallGetter);
case JSCallMode::CALL_SETTER:
return RTSTUB_ID(CallSetter);
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
return RTSTUB_ID(CallContainersArgs2);
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return RTSTUB_ID(CallContainersArgs3);
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return RTSTUB_ID(CallReturnWithArgv);
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
int CallStubBuilder::PrepareIdxForAsmInterpreterForBaselineWithoutBaselineCode()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG0:
return RTSTUB_ID(CallArg0AndDispatchFromBaseline);
case JSCallMode::CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG1:
return RTSTUB_ID(CallArg1AndDispatchFromBaseline);
case JSCallMode::CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG2:
return RTSTUB_ID(CallArgs2AndDispatchFromBaseline);
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG3:
return RTSTUB_ID(CallArgs3AndDispatchFromBaseline);
case JSCallMode::CALL_THIS_ARG0:
return RTSTUB_ID(CallThisArg0AndDispatchFromBaseline);
case JSCallMode::CALL_THIS_ARG1:
return RTSTUB_ID(CallThisArg1AndDispatchFromBaseline);
case JSCallMode::CALL_THIS_ARG2:
return RTSTUB_ID(CallThisArgs2AndDispatchFromBaseline);
case JSCallMode::CALL_THIS_ARG3:
return RTSTUB_ID(CallThisArgs3AndDispatchFromBaseline);
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
return RTSTUB_ID(CallRangeAndDispatchFromBaseline);
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
return RTSTUB_ID(CallThisRangeAndDispatchFromBaseline);
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return RTSTUB_ID(CallNewAndDispatchFromBaseline);
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
return RTSTUB_ID(SuperCallAndDispatchFromBaseline);
case JSCallMode::CALL_GETTER:
return RTSTUB_ID(CallGetter);
case JSCallMode::CALL_SETTER:
return RTSTUB_ID(CallSetter);
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
return RTSTUB_ID(CallContainersArgs2);
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return RTSTUB_ID(CallContainersArgs3);
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return RTSTUB_ID(CallReturnWithArgv);
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
int CallStubBuilder::PrepareIdxForAsmInterpreterWithBaselineCode()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG0:
return RTSTUB_ID(CallArg0AndCheckToBaseline);
case JSCallMode::CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG1:
return RTSTUB_ID(CallArg1AndCheckToBaseline);
case JSCallMode::CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG2:
return RTSTUB_ID(CallArgs2AndCheckToBaseline);
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG3:
return RTSTUB_ID(CallArgs3AndCheckToBaseline);
case JSCallMode::CALL_THIS_ARG0:
return RTSTUB_ID(CallThisArg0AndCheckToBaseline);
case JSCallMode::CALL_THIS_ARG1:
return RTSTUB_ID(CallThisArg1AndCheckToBaseline);
case JSCallMode::CALL_THIS_ARG2:
return RTSTUB_ID(CallThisArgs2AndCheckToBaseline);
case JSCallMode::CALL_THIS_ARG3:
return RTSTUB_ID(CallThisArgs3AndCheckToBaseline);
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
return RTSTUB_ID(CallRangeAndCheckToBaseline);
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
return RTSTUB_ID(CallThisRangeAndCheckToBaseline);
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return RTSTUB_ID(CallNewAndCheckToBaseline);
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
return RTSTUB_ID(SuperCallAndCheckToBaseline);
case JSCallMode::CALL_GETTER:
return RTSTUB_ID(CallGetter);
case JSCallMode::CALL_SETTER:
return RTSTUB_ID(CallSetter);
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
return RTSTUB_ID(CallContainersArgs2);
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return RTSTUB_ID(CallContainersArgs3);
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return RTSTUB_ID(CallReturnWithArgv);
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
int CallStubBuilder::PrepareIdxForAsmInterpreterWithoutBaselineCode()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG0:
return RTSTUB_ID(PushCallArg0AndDispatch);
case JSCallMode::CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG1:
return RTSTUB_ID(PushCallArg1AndDispatch);
case JSCallMode::CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG2:
return RTSTUB_ID(PushCallArgs2AndDispatch);
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG3:
return RTSTUB_ID(PushCallArgs3AndDispatch);
case JSCallMode::CALL_THIS_ARG0:
return RTSTUB_ID(PushCallThisArg0AndDispatch);
case JSCallMode::CALL_THIS_ARG1:
return RTSTUB_ID(PushCallThisArg1AndDispatch);
case JSCallMode::CALL_THIS_ARG2:
return RTSTUB_ID(PushCallThisArgs2AndDispatch);
case JSCallMode::CALL_THIS_ARG3:
return RTSTUB_ID(PushCallThisArgs3AndDispatch);
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
return RTSTUB_ID(PushCallRangeAndDispatch);
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
return RTSTUB_ID(PushCallThisRangeAndDispatch);
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return RTSTUB_ID(PushCallNewAndDispatch);
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
return RTSTUB_ID(PushSuperCallAndDispatch);
case JSCallMode::CALL_GETTER:
return RTSTUB_ID(CallGetter);
case JSCallMode::CALL_SETTER:
return RTSTUB_ID(CallSetter);
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
return RTSTUB_ID(CallContainersArgs2);
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return RTSTUB_ID(CallContainersArgs3);
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return RTSTUB_ID(CallReturnWithArgv);
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
std::vector<GateRef> CallStubBuilder::PrepareArgsForAsmInterpreter()
{
std::vector<GateRef> basicArgs = PrepareBasicArgsForAsmInterpreter();
std::vector<GateRef> appendArgs = PrepareAppendArgsForAsmInterpreter();
basicArgs.insert(basicArgs.end(), appendArgs.begin(), appendArgs.end());
return basicArgs;
}
std::vector<GateRef> CallStubBuilder::PrepareBasicArgsForAsmInterpreter()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
if (isForBaseline_) {
return { glue_, baselineBuiltinFp_, func_, method_, callField_ };
} else {
return { glue_, sp_, func_, method_, callField_ };
}
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return { glue_, func_, method_, callField_ };
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
std::vector<GateRef> CallStubBuilder::PrepareAppendArgsForAsmInterpreter()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG0:
return {};
case JSCallMode::CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG1:
return { callArgs_.callArgs.arg0 };
case JSCallMode::CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG2:
return {
callArgs_.callArgs.arg0,
callArgs_.callArgs.arg1
};
case JSCallMode::CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_ARG3:
return {
callArgs_.callArgs.arg0,
callArgs_.callArgs.arg1,
callArgs_.callArgs.arg2
};
case JSCallMode::CALL_THIS_ARG0:
return { callArgs_.callArgsWithThis.thisValue };
case JSCallMode::CALL_THIS_ARG1:
return {
callArgs_.callArgsWithThis.arg0,
callArgs_.callArgsWithThis.thisValue
};
case JSCallMode::CALL_THIS_ARG2:
return {
callArgs_.callArgsWithThis.arg0,
callArgs_.callArgsWithThis.arg1,
callArgs_.callArgsWithThis.thisValue
};
case JSCallMode::CALL_THIS_ARG3:
return {
callArgs_.callArgsWithThis.arg0,
callArgs_.callArgsWithThis.arg1,
callArgs_.callArgsWithThis.arg2,
callArgs_.callArgsWithThis.thisValue
};
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
return {
callArgs_.callArgv.argc,
callArgs_.callArgv.argv
};
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
return {
callArgs_.callArgvWithThis.argc,
callArgs_.callArgvWithThis.argv,
callArgs_.callArgvWithThis.thisValue
};
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return {
callArgs_.callConstructorArgs.argc,
callArgs_.callConstructorArgs.argv,
callArgs_.callConstructorArgs.thisObj
};
case JSCallMode::CALL_GETTER:
return { callArgs_.callGetterArgs.receiver };
case JSCallMode::CALL_SETTER:
return {
callArgs_.callSetterArgs.value,
callArgs_.callSetterArgs.receiver
};
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
return {
callArgs_.callThisArg2WithReturnArgs.arg0,
callArgs_.callThisArg2WithReturnArgs.arg1,
callArgs_.callThisArg2WithReturnArgs.thisValue
};
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
return {
callArgs_.callThisArg3WithReturnArgs.value,
callArgs_.callThisArg3WithReturnArgs.key,
callArgs_.callThisArg3WithReturnArgs.thisValue,
callArgs_.callThisArg3WithReturnArgs.argHandle
};
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return {
callArgs_.callThisArgvWithReturnArgs.argc,
callArgs_.callThisArgvWithReturnArgs.argv,
callArgs_.callThisArgvWithReturnArgs.thisValue
};
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
return {
callArgs_.superCallArgs.argc,
callArgs_.superCallArgs.argv,
callArgs_.superCallArgs.thisObj,
callArgs_.superCallArgs.newTarget
};
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
void CallStubBuilder::CallFastBuiltin(Label* notFastBuiltins, Label *exit, GateRef hir)
{
auto env = GetEnvironment();
Label isFastBuiltins(env);
Label supportCall(env);
numArgs_ = ZExtInt32ToPtr(actualNumArgs_);
GateRef isFastBuiltinsMask = Int64(static_cast<uint64_t>(1) << Method::IsFastBuiltinBit::START_BIT);
BRANCH(Int64NotEqual(Int64And(callField_, isFastBuiltinsMask), Int64(0)), &isFastBuiltins, notFastBuiltins);
Bind(&isFastBuiltins);
GateRef builtinId = GetBuiltinId(method_);
if (IsCallModeSupportCallBuiltin()) {
BRANCH(Int32GreaterThanOrEqual(builtinId, Int32(BUILTINS_STUB_ID(BUILTINS_CONSTRUCTOR_STUB_FIRST))),
notFastBuiltins, &supportCall);
Bind(&supportCall);
}
{
GateRef ret;
switch (callArgs_.mode) {
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
ret = DispatchBuiltins(glue_, builtinId, PrepareArgsForFastBuiltin(), hir);
break;
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
ret = DispatchBuiltinsWithArgv(glue_, builtinId, PrepareArgsForFastBuiltin());
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
result_->WriteVariable(ret);
Jump(exit);
}
}
std::vector<GateRef> CallStubBuilder::PrepareBasicArgsForFastBuiltin()
{
return { glue_, nativeCode_, func_ };
}
std::vector<GateRef> CallStubBuilder::PrepareAppendArgsForFastBuiltin()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_THIS_ARG0:
return { Undefined(),
callArgs_.callArgsWithThis.thisValue, numArgs_, Undefined(), Undefined(), Undefined()
};
case JSCallMode::CALL_THIS_ARG1:
return { Undefined(),
callArgs_.callArgsWithThis.thisValue, numArgs_,
callArgs_.callArgsWithThis.arg0, Undefined(), Undefined()
};
case JSCallMode::CALL_THIS_ARG2:
return { Undefined(),
callArgs_.callArgsWithThis.thisValue, numArgs_,
callArgs_.callArgsWithThis.arg0,
callArgs_.callArgsWithThis.arg1, Undefined()
};
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
return { Undefined(),
callArgs_.callThisArg2WithReturnArgs.thisValue, numArgs_,
callArgs_.callThisArg2WithReturnArgs.arg0,
callArgs_.callThisArg2WithReturnArgs.arg1, Undefined()
};
case JSCallMode::CALL_THIS_ARG3:
return { Undefined(),
callArgs_.callArgsWithThis.thisValue, numArgs_,
callArgs_.callArgsWithThis.arg0,
callArgs_.callArgsWithThis.arg1,
callArgs_.callArgsWithThis.arg2
};
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
return { func_, thisValue_, numArgs_,
callArgs_.callConstructorArgs.argv
};
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
std::vector<GateRef> CallStubBuilder::PrepareArgsForFastBuiltin()
{
std::vector<GateRef> basicArgs = PrepareBasicArgsForFastBuiltin();
std::vector<GateRef> appendArgs = PrepareAppendArgsForFastBuiltin();
basicArgs.insert(basicArgs.end(), appendArgs.begin(), appendArgs.end());
return basicArgs;
}
bool CallStubBuilder::IsCallModeSupportPGO() const
{
switch (callArgs_.mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::SUPER_CALL_WITH_ARGV:
case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
return true;
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::CALL_ENTRY:
case JSCallMode::CALL_FROM_AOT:
case JSCallMode::CALL_GENERATOR:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return false;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
bool CallStubBuilder::IsCallModeSupportCallBuiltin() const
{
switch (callArgs_.mode) {
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
return true;
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
return false;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
bool CallStubBuilder::CheckResultValueChangedWithReturn(GateRef prevResRef) const
{
switch (callArgs_.mode) {
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return result_->Value() == prevResRef;
default:
return result_->Value() != prevResRef;
}
}
bool CallStubBuilder::IsSlowAotCall() const
{ return !isFast_ && !isBridge_; }
bool CallStubBuilder::IsFastAotCall() const
{ return isFast_ && !isBridge_; }
bool CallStubBuilder::IsSlowAotCallWithBridge() const
{ return !isFast_ && isBridge_; }
bool CallStubBuilder::IsFastAotCallWithBridge() const
{ return isFast_ && isBridge_; }
void CallStubBuilder::HandleProfileCall()
{
if (!callback_.IsEmpty()) {
if (!IsCallModeSupportPGO()) {
return;
}
if (IsCallModeGetterSetter()) {
callback_.ProfileGetterSetterCall(func_);
return;
}
callback_.ProfileCall(func_);
}
}
void CallStubBuilder::HandleProfileNativeCall()
{
if (!callback_.IsEmpty()) {
if (!IsCallModeSupportPGO()) {
return;
}
if (!IsCallModeGetterSetter()) {
callback_.ProfileNativeCall(func_);
}
}
}
bool CallStubBuilder::IsCallModeGetterSetter()
{
switch (callArgs_.mode) {
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
return true;
default:
return false;
}
}
}