arkcompiler_ets_runtime/ecmascript/compiler/slowpath_lowering.cpp
2024-09-27 16:50:24 +08:00

3937 lines
164 KiB
C++

/*
* Copyright (c) 2021-2024 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/slowpath_lowering.h"
#include "ecmascript/compiler/bytecodes.h"
#include "ecmascript/compiler/circuit_builder.h"
#include "ecmascript/compiler/share_gate_meta_data.h"
#include "ecmascript/dfx/vm_thread_control.h"
#include "ecmascript/dfx/vmstat/opt_code_profiler.h"
#include "ecmascript/js_async_generator_object.h"
#include "ecmascript/js_generator_object.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/jit/jit.h"
#include "ecmascript/lexical_env.h"
namespace panda::ecmascript::kungfu {
using UseIterator = GateAccessor::UseIterator;
#define CREATE_DOUBLE_EXIT(SuccessLabel, FailLabel) \
StateDepend successControl; \
StateDepend failControl; \
builder_.Bind(&SuccessLabel); \
{ \
successControl.SetState(builder_.GetState()); \
successControl.SetDepend(builder_.GetDepend()); \
} \
builder_.Bind(&FailLabel); \
{ \
failControl.SetState(builder_.GetState()); \
failControl.SetDepend(builder_.GetDepend()); \
}
void SlowPathLowering::CallRuntimeLowering()
{
std::vector<GateRef> gateList;
circuit_->GetAllGates(gateList);
for (const auto &gate : gateList) {
auto op = acc_.GetOpCode(gate);
[[maybe_unused]] auto scopedGate = circuit_->VisitGateBegin(gate);
switch (op) {
case OpCode::JS_BYTECODE:
Lower(gate);
break;
case OpCode::GET_EXCEPTION: {
// initialize label manager
Environment env(gate, circuit_, &builder_);
LowerExceptionHandler(gate);
break;
}
case OpCode::CONSTRUCT:
LowerConstruct(gate);
break;
case OpCode::CALLINTERNAL:
LowerCallInternal(gate);
break;
case OpCode::CALL_NEW:
LowerCallNew(gate);
break;
case OpCode::TYPEDCALL:
LowerTypedCall(gate);
break;
case OpCode::TYPEDFASTCALL:
LowerTypedFastCall(gate);
break;
case OpCode::CHECK_SAFEPOINT_AND_STACKOVER:
LowerCheckSafePointAndStackOver(gate);
break;
case OpCode::GET_ENV:
LowerGetEnv(gate);
break;
case OpCode::LOOP_EXIT:
DeleteLoopExit(gate);
break;
case OpCode::LOOP_EXIT_VALUE:
DeleteLoopExitValue(gate);
break;
case OpCode::GET_UNSHARED_CONSTPOOL:
unsharedCP_.emplace_back(gate);
break;
default:
break;
}
}
// Make sure all IRs are lowered before lowering the constpool. If constpool is not used in CIR, it will be replaced
// by undefined.
for (const auto &gate : unsharedCP_) {
GateRef sharedConstPool = acc_.GetValueIn(gate, 0);
ASSERT(acc_.GetOpCode(sharedConstPool) == OpCode::GET_SHARED_CONSTPOOL);
LowerGetUnsharedConstPool(gate);
LowerGetSharedConstPool(sharedConstPool);
}
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << " ";
LOG_COMPILER(INFO) << "\033[34m" << "================="
<< " After slowpath Lowering "
<< "[" << GetMethodName() << "] "
<< "=================" << "\033[0m";
circuit_->PrintAllGatesWithBytecode();
LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
}
}
void SlowPathLowering::LowerGetEnv(GateRef gate)
{
GateRef jsFunc = acc_.GetValueIn(gate, 0);
GateRef envOffset = builder_.IntPtr(JSFunction::LEXICAL_ENV_OFFSET);
GateRef env = builder_.Load(VariableType::JS_ANY(), jsFunc, envOffset, acc_.GetDep(gate));
acc_.UpdateAllUses(gate, env);
acc_.DeleteGate(gate);
}
void SlowPathLowering::DeleteLoopExit(GateRef gate)
{
auto state = acc_.GetState(gate);
acc_.ReplaceGate(gate, state, Circuit::NullGate(), Circuit::NullGate());
}
void SlowPathLowering::DeleteLoopExitValue(GateRef gate)
{
auto state = acc_.GetState(gate);
auto value = acc_.GetValueIn(gate, 0);
acc_.ReplaceGate(gate, state, Circuit::NullGate(), value);
}
void SlowPathLowering::LowerToJSCall(GateRef hirGate, const std::vector<GateRef> &args,
const std::vector<GateRef> &argsFastCall)
{
Label exit(&builder_);
DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
GateRef func = args[static_cast<size_t>(CommonArgIdx::FUNC)];
GateRef argc = args[static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC)];
LowerFastCall(hirGate, glue_, func, argc, args, argsFastCall, &res, &exit, false);
builder_.Bind(&exit);
GateRef stateInGate = builder_.GetState();
GateRef depend = builder_.GetDepend();
ReplaceHirWithPendingException(hirGate, stateInGate, depend, *res);
}
void SlowPathLowering::ReplaceHirWithPendingException(GateRef hirGate,
GateRef state, GateRef depend, GateRef value)
{
auto condition = builder_.HasPendingException(glue_);
GateRef ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
GateRef ifTrue = builder_.IfTrue(ifBranch);
GateRef ifFalse = builder_.IfFalse(ifBranch);
GateRef eDepend = builder_.DependRelay(ifTrue, depend);
GateRef sDepend = builder_.DependRelay(ifFalse, depend);
StateDepend success(ifFalse, sDepend);
StateDepend exception(ifTrue, eDepend);
acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
}
/*
* lower to slowpath call like this pattern:
* have throw:
* res = Call(...);
* if (res == VALUE_EXCEPTION) {
* goto exception_handle;
* }
* Set(res);
*
* no throw:
* res = Call(...);
* Set(res);
*/
void SlowPathLowering::ReplaceHirWithValue(GateRef hirGate, GateRef value, bool noThrow)
{
if (!noThrow) {
GateRef state = builder_.GetState();
// copy depend-wire of hirGate to value
GateRef depend = builder_.GetDepend();
// exception value
GateRef exceptionVal = builder_.ExceptionConstant();
// compare with trampolines result
GateRef equal = builder_.Equal(value, exceptionVal);
auto ifBranch = builder_.Branch(state, equal, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
GateRef ifTrue = builder_.IfTrue(ifBranch);
GateRef ifFalse = builder_.IfFalse(ifBranch);
GateRef eDepend = builder_.DependRelay(ifTrue, depend);
GateRef sDepend = builder_.DependRelay(ifFalse, depend);
StateDepend success(ifFalse, sDepend);
StateDepend exception(ifTrue, eDepend);
acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
} else {
acc_.ReplaceHirDirectly(hirGate, builder_.GetStateDepend(), value);
}
}
/*
* lower to throw call like this pattern:
* Call(...);
* goto exception_handle;
*
*/
void SlowPathLowering::ReplaceHirToThrowCall(GateRef hirGate, GateRef value)
{
auto condition = builder_.HasPendingException(glue_);
GateRef state = builder_.GetState();
GateRef depend = builder_.GetDepend();
GateRef ifBranch = builder_.Branch(state, condition, BranchWeight::DEOPT_WEIGHT, 1, "checkException");
GateRef ifTrue = builder_.IfTrue(ifBranch);
GateRef ifFalse = builder_.IfFalse(ifBranch);
GateRef eDepend = builder_.DependRelay(ifTrue, depend);
GateRef sDepend = builder_.DependRelay(ifFalse, depend);
StateDepend success(ifFalse, sDepend);
StateDepend exception(ifTrue, eDepend);
acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
}
void SlowPathLowering::Lower(GateRef gate)
{
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
// initialize label manager
Environment env(gate, circuit_, &builder_);
AddProfiling(gate);
switch (ecmaOpcode) {
case EcmaOpcode::CALLARG0_IMM8:
LowerCallArg0(gate);
break;
case EcmaOpcode::CALLTHIS0_IMM8_V8:
LowerCallthis0Imm8V8(gate);
break;
case EcmaOpcode::CALLARG1_IMM8_V8:
LowerCallArg1Imm8V8(gate);
break;
case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
LowerWideCallrangePrefImm16V8(gate);
break;
case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
LowerCallThisArg1(gate);
break;
case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
LowerCallargs2Imm8V8V8(gate);
break;
case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
LowerCallthis2Imm8V8V8V8(gate);
break;
case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
LowerCallargs3Imm8V8V8(gate);
break;
case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
LowerCallthis3Imm8V8V8V8V8(gate);
break;
case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
LowerCallthisrangeImm8Imm8V8(gate);
break;
case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
LowerWideCallthisrangePrefImm16V8(gate);
break;
case EcmaOpcode::APPLY_IMM8_V8_V8:
LowerCallSpread(gate);
break;
case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
LowerCallrangeImm8Imm8V8(gate);
break;
case EcmaOpcode::GETUNMAPPEDARGS:
LowerGetUnmappedArgs(gate);
break;
case EcmaOpcode::ASYNCFUNCTIONENTER:
LowerAsyncFunctionEnter(gate);
break;
case EcmaOpcode::INC_IMM8:
LowerInc(gate);
break;
case EcmaOpcode::DEC_IMM8:
LowerDec(gate);
break;
case EcmaOpcode::GETPROPITERATOR:
LowerGetPropIterator(gate);
break;
case EcmaOpcode::RESUMEGENERATOR:
LowerResumeGenerator(gate);
break;
case EcmaOpcode::GETRESUMEMODE:
LowerGetResumeMode(gate);
break;
case EcmaOpcode::CLOSEITERATOR_IMM8_V8:
case EcmaOpcode::CLOSEITERATOR_IMM16_V8:
LowerCloseIterator(gate);
break;
case EcmaOpcode::ADD2_IMM8_V8:
LowerAdd2(gate);
break;
case EcmaOpcode::SUB2_IMM8_V8:
LowerSub2(gate);
break;
case EcmaOpcode::MUL2_IMM8_V8:
LowerMul2(gate);
break;
case EcmaOpcode::DIV2_IMM8_V8:
LowerDiv2(gate);
break;
case EcmaOpcode::MOD2_IMM8_V8:
LowerMod2(gate);
break;
case EcmaOpcode::EQ_IMM8_V8:
LowerEq(gate);
break;
case EcmaOpcode::NOTEQ_IMM8_V8:
LowerNotEq(gate);
break;
case EcmaOpcode::LESS_IMM8_V8:
LowerLess(gate);
break;
case EcmaOpcode::LESSEQ_IMM8_V8:
LowerLessEq(gate);
break;
case EcmaOpcode::GREATER_IMM8_V8:
LowerGreater(gate);
break;
case EcmaOpcode::GREATEREQ_IMM8_V8:
LowerGreaterEq(gate);
break;
case EcmaOpcode::CREATEITERRESULTOBJ_V8_V8:
LowerCreateIterResultObj(gate);
break;
case EcmaOpcode::SUSPENDGENERATOR_V8:
LowerSuspendGenerator(gate);
break;
case EcmaOpcode::ASYNCFUNCTIONAWAITUNCAUGHT_V8:
LowerAsyncFunctionAwaitUncaught(gate);
break;
case EcmaOpcode::ASYNCFUNCTIONRESOLVE_V8:
LowerAsyncFunctionResolve(gate);
break;
case EcmaOpcode::ASYNCFUNCTIONREJECT_V8:
LowerAsyncFunctionReject(gate);
break;
case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16:
case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16:
LowerTryLdGlobalByName(gate);
break;
case EcmaOpcode::STGLOBALVAR_IMM16_ID16:
LowerStGlobalVar(gate);
break;
case EcmaOpcode::GETITERATOR_IMM8:
case EcmaOpcode::GETITERATOR_IMM16:
LowerGetIterator(gate);
break;
case EcmaOpcode::GETASYNCITERATOR_IMM8:
LowerGetAsyncIterator(gate);
break;
case EcmaOpcode::NEWOBJAPPLY_IMM8_V8:
case EcmaOpcode::NEWOBJAPPLY_IMM16_V8:
LowerNewObjApply(gate);
break;
case EcmaOpcode::THROW_PREF_NONE:
LowerThrow(gate);
break;
case EcmaOpcode::TYPEOF_IMM8:
case EcmaOpcode::TYPEOF_IMM16:
LowerTypeof(gate);
break;
case EcmaOpcode::THROW_CONSTASSIGNMENT_PREF_V8:
LowerThrowConstAssignment(gate);
break;
case EcmaOpcode::THROW_NOTEXISTS_PREF_NONE:
LowerThrowThrowNotExists(gate);
break;
case EcmaOpcode::THROW_PATTERNNONCOERCIBLE_PREF_NONE:
LowerThrowPatternNonCoercible(gate);
break;
case EcmaOpcode::THROW_IFNOTOBJECT_PREF_V8:
LowerThrowIfNotObject(gate);
break;
case EcmaOpcode::THROW_UNDEFINEDIFHOLE_PREF_V8_V8:
LowerThrowUndefinedIfHole(gate);
break;
case EcmaOpcode::THROW_UNDEFINEDIFHOLEWITHNAME_PREF_ID16:
LowerThrowUndefinedIfHoleWithName(gate);
break;
case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM8:
case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM16:
LowerThrowIfSuperNotCorrectCall(gate);
break;
case EcmaOpcode::THROW_DELETESUPERPROPERTY_PREF_NONE:
LowerThrowDeleteSuperProperty(gate);
break;
case EcmaOpcode::LDSYMBOL:
LowerLdSymbol(gate);
break;
case EcmaOpcode::LDGLOBAL:
LowerLdGlobal(gate);
break;
case EcmaOpcode::TONUMBER_IMM8:
LowerToNumber(gate);
break;
case EcmaOpcode::NEG_IMM8:
LowerNeg(gate);
break;
case EcmaOpcode::NOT_IMM8:
LowerNot(gate);
break;
case EcmaOpcode::SHL2_IMM8_V8:
LowerShl2(gate);
break;
case EcmaOpcode::SHR2_IMM8_V8:
LowerShr2(gate);
break;
case EcmaOpcode::ASHR2_IMM8_V8:
LowerAshr2(gate);
break;
case EcmaOpcode::AND2_IMM8_V8:
LowerAnd2(gate);
break;
case EcmaOpcode::OR2_IMM8_V8:
LowerOr2(gate);
break;
case EcmaOpcode::XOR2_IMM8_V8:
LowerXor2(gate);
break;
case EcmaOpcode::DELOBJPROP_V8:
LowerDelObjProp(gate);
break;
case EcmaOpcode::DEFINEMETHOD_IMM8_ID16_IMM8:
case EcmaOpcode::DEFINEMETHOD_IMM16_ID16_IMM8:
LowerDefineMethod(gate);
break;
case EcmaOpcode::EXP_IMM8_V8:
LowerExp(gate);
break;
case EcmaOpcode::ISIN_IMM8_V8:
LowerIsIn(gate);
break;
case EcmaOpcode::INSTANCEOF_IMM8_V8:
LowerInstanceof(gate);
break;
case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
LowerFastStrictNotEqual(gate);
break;
case EcmaOpcode::STRICTEQ_IMM8_V8:
LowerFastStrictEqual(gate);
break;
case EcmaOpcode::CREATEEMPTYARRAY_IMM8:
case EcmaOpcode::CREATEEMPTYARRAY_IMM16:
LowerCreateEmptyArray(gate);
break;
case EcmaOpcode::CREATEEMPTYOBJECT:
LowerCreateEmptyObject(gate);
break;
case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
LowerCreateObjectWithBuffer(gate);
break;
case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
LowerCreateArrayWithBuffer(gate);
break;
case EcmaOpcode::STMODULEVAR_IMM8:
case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
LowerStModuleVar(gate);
break;
case EcmaOpcode::SETGENERATORSTATE_IMM8:
LowerSetGeneratorState(gate);
break;
case EcmaOpcode::GETTEMPLATEOBJECT_IMM8:
case EcmaOpcode::GETTEMPLATEOBJECT_IMM16:
LowerGetTemplateObject(gate);
break;
case EcmaOpcode::SETOBJECTWITHPROTO_IMM8_V8:
case EcmaOpcode::SETOBJECTWITHPROTO_IMM16_V8:
LowerSetObjectWithProto(gate);
break;
case EcmaOpcode::LDBIGINT_ID16:
LowerLdBigInt(gate);
break;
case EcmaOpcode::TONUMERIC_IMM8:
LowerToNumeric(gate);
break;
case EcmaOpcode::DYNAMICIMPORT:
LowerDynamicImport(gate);
break;
case EcmaOpcode::LDEXTERNALMODULEVAR_IMM8:
case EcmaOpcode::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16:
LowerExternalModule(gate);
break;
case EcmaOpcode::GETMODULENAMESPACE_IMM8:
case EcmaOpcode::WIDE_GETMODULENAMESPACE_PREF_IMM16:
LowerGetModuleNamespace(gate);
break;
case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
LowerNewObjRange(gate);
break;
case EcmaOpcode::JEQZ_IMM8:
case EcmaOpcode::JEQZ_IMM16:
case EcmaOpcode::JEQZ_IMM32:
LowerConditionJump(gate, true);
break;
case EcmaOpcode::JNEZ_IMM8:
case EcmaOpcode::JNEZ_IMM16:
case EcmaOpcode::JNEZ_IMM32:
LowerConditionJump(gate, false);
break;
case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
LowerSuperCall(gate);
break;
case EcmaOpcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
case EcmaOpcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
LowerSuperCallArrow(gate);
break;
case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8:
LowerSuperCallSpread(gate);
break;
case EcmaOpcode::CALLRUNTIME_SUPERCALLFORWARDALLARGS_PREF_V8:
LowerSuperCallForwardAllArgs(gate);
break;
case EcmaOpcode::ISTRUE:
case EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8:
LowerIsTrueOrFalse(gate, true);
break;
case EcmaOpcode::ISFALSE:
case EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8:
LowerIsTrueOrFalse(gate, false);
break;
case EcmaOpcode::GETNEXTPROPNAME_V8:
LowerGetNextPropName(gate);
break;
case EcmaOpcode::COPYDATAPROPERTIES_V8:
LowerCopyDataProperties(gate);
break;
case EcmaOpcode::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8:
case EcmaOpcode::WIDE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8:
LowerCreateObjectWithExcludedKeys(gate);
break;
case EcmaOpcode::CREATEREGEXPWITHLITERAL_IMM8_ID16_IMM8:
case EcmaOpcode::CREATEREGEXPWITHLITERAL_IMM16_ID16_IMM8:
LowerCreateRegExpWithLiteral(gate);
break;
case EcmaOpcode::STOWNBYVALUE_IMM8_V8_V8:
case EcmaOpcode::STOWNBYVALUE_IMM16_V8_V8:
LowerStOwnByValue(gate);
break;
case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
case EcmaOpcode::WIDE_STOWNBYINDEX_PREF_V8_IMM32:
LowerStOwnByIndex(gate);
break;
case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8:
LowerStOwnByName(gate);
break;
case EcmaOpcode::NEWLEXENV_IMM8:
case EcmaOpcode::WIDE_NEWLEXENV_PREF_IMM16:
LowerNewLexicalEnv(gate);
break;
case EcmaOpcode::NEWLEXENVWITHNAME_IMM8_ID16:
case EcmaOpcode::WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16:
LowerNewLexicalEnvWithName(gate);
break;
case EcmaOpcode::POPLEXENV:
LowerPopLexicalEnv(gate);
break;
case EcmaOpcode::LDSUPERBYVALUE_IMM8_V8:
case EcmaOpcode::LDSUPERBYVALUE_IMM16_V8:
LowerLdSuperByValue(gate);
break;
case EcmaOpcode::STSUPERBYVALUE_IMM16_V8_V8:
case EcmaOpcode::STSUPERBYVALUE_IMM8_V8_V8:
LowerStSuperByValue(gate);
break;
case EcmaOpcode::TRYSTGLOBALBYNAME_IMM8_ID16:
case EcmaOpcode::TRYSTGLOBALBYNAME_IMM16_ID16:
LowerTryStGlobalByName(gate);
break;
case EcmaOpcode::STCONSTTOGLOBALRECORD_IMM16_ID16:
LowerStConstToGlobalRecord(gate, true);
break;
case EcmaOpcode::STTOGLOBALRECORD_IMM16_ID16:
LowerStConstToGlobalRecord(gate, false);
break;
case EcmaOpcode::STOWNBYVALUEWITHNAMESET_IMM8_V8_V8:
case EcmaOpcode::STOWNBYVALUEWITHNAMESET_IMM16_V8_V8:
LowerStOwnByValueWithNameSet(gate);
break;
case EcmaOpcode::STOWNBYNAMEWITHNAMESET_IMM8_ID16_V8:
case EcmaOpcode::STOWNBYNAMEWITHNAMESET_IMM16_ID16_V8:
LowerStOwnByNameWithNameSet(gate);
break;
case EcmaOpcode::LDGLOBALVAR_IMM16_ID16:
LowerLdGlobalVar(gate);
break;
case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
LowerLdObjByName(gate);
break;
case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
LowerStObjByName(gate, false);
break;
case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
LowerDefineGetterSetterByValue(gate);
break;
case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
LowerLdObjByIndex(gate);
break;
case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32:
LowerStObjByIndex(gate);
break;
case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
LowerLdObjByValue(gate, false);
break;
case EcmaOpcode::LDTHISBYVALUE_IMM8:
case EcmaOpcode::LDTHISBYVALUE_IMM16:
LowerLdObjByValue(gate, true);
break;
case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
LowerStObjByValue(gate, false);
break;
case EcmaOpcode::STTHISBYVALUE_IMM8_V8:
case EcmaOpcode::STTHISBYVALUE_IMM16_V8:
LowerStObjByValue(gate, true);
break;
case EcmaOpcode::LDSUPERBYNAME_IMM8_ID16:
case EcmaOpcode::LDSUPERBYNAME_IMM16_ID16:
LowerLdSuperByName(gate);
break;
case EcmaOpcode::STSUPERBYNAME_IMM8_ID16_V8:
case EcmaOpcode::STSUPERBYNAME_IMM16_ID16_V8:
LowerStSuperByName(gate);
break;
case EcmaOpcode::CREATEGENERATOROBJ_V8:
LowerCreateGeneratorObj(gate);
break;
case EcmaOpcode::CREATEASYNCGENERATOROBJ_V8:
LowerCreateAsyncGeneratorObj(gate);
break;
case EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8:
LowerAsyncGeneratorResolve(gate);
break;
case EcmaOpcode::ASYNCGENERATORREJECT_V8:
LowerAsyncGeneratorReject(gate);
break;
case EcmaOpcode::STARRAYSPREAD_V8_V8:
LowerStArraySpread(gate);
break;
case EcmaOpcode::LDLEXVAR_IMM4_IMM4:
case EcmaOpcode::LDLEXVAR_IMM8_IMM8:
case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16:
LowerLdLexVar(gate);
break;
case EcmaOpcode::STLEXVAR_IMM4_IMM4:
case EcmaOpcode::STLEXVAR_IMM8_IMM8:
case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
LowerStLexVar(gate);
break;
case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
LowerDefineClassWithBuffer(gate);
break;
case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8:
case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8:
LowerDefineFunc(gate);
break;
case EcmaOpcode::COPYRESTARGS_IMM8:
case EcmaOpcode::WIDE_COPYRESTARGS_PREF_IMM16:
LowerCopyRestArgs(gate);
break;
case EcmaOpcode::WIDE_LDPATCHVAR_PREF_IMM16:
LowerWideLdPatchVar(gate);
break;
case EcmaOpcode::WIDE_STPATCHVAR_PREF_IMM16:
LowerWideStPatchVar(gate);
break;
case EcmaOpcode::LDLOCALMODULEVAR_IMM8:
case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
LowerLdLocalModuleVarByIndex(gate);
break;
case EcmaOpcode::DEBUGGER:
case EcmaOpcode::JSTRICTEQZ_IMM8:
case EcmaOpcode::JSTRICTEQZ_IMM16:
case EcmaOpcode::JNSTRICTEQZ_IMM8:
case EcmaOpcode::JNSTRICTEQZ_IMM16:
case EcmaOpcode::JEQNULL_IMM8:
case EcmaOpcode::JEQNULL_IMM16:
case EcmaOpcode::JNENULL_IMM8:
case EcmaOpcode::JNENULL_IMM16:
case EcmaOpcode::JSTRICTEQNULL_IMM8:
case EcmaOpcode::JSTRICTEQNULL_IMM16:
case EcmaOpcode::JNSTRICTEQNULL_IMM8:
case EcmaOpcode::JNSTRICTEQNULL_IMM16:
case EcmaOpcode::JEQUNDEFINED_IMM8:
case EcmaOpcode::JEQUNDEFINED_IMM16:
case EcmaOpcode::JNEUNDEFINED_IMM8:
case EcmaOpcode::JNEUNDEFINED_IMM16:
case EcmaOpcode::JSTRICTEQUNDEFINED_IMM8:
case EcmaOpcode::JSTRICTEQUNDEFINED_IMM16:
case EcmaOpcode::JNSTRICTEQUNDEFINED_IMM8:
case EcmaOpcode::JNSTRICTEQUNDEFINED_IMM16:
case EcmaOpcode::JEQ_V8_IMM8:
case EcmaOpcode::JEQ_V8_IMM16:
case EcmaOpcode::JNE_V8_IMM8:
case EcmaOpcode::JNE_V8_IMM16:
case EcmaOpcode::JSTRICTEQ_V8_IMM8:
case EcmaOpcode::JSTRICTEQ_V8_IMM16:
case EcmaOpcode::JNSTRICTEQ_V8_IMM8:
case EcmaOpcode::JNSTRICTEQ_V8_IMM16:
break;
case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
LowerLdThisByName(gate);
break;
case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
LowerStObjByName(gate, true);
break;
case EcmaOpcode::LDPRIVATEPROPERTY_IMM8_IMM16_IMM16:
LowerLdPrivateProperty(gate);
break;
case EcmaOpcode::STPRIVATEPROPERTY_IMM8_IMM16_IMM16_V8:
LowerStPrivateProperty(gate);
break;
case EcmaOpcode::TESTIN_IMM8_IMM16_IMM16:
LowerTestIn(gate);
break;
case EcmaOpcode::CALLRUNTIME_NOTIFYCONCURRENTRESULT_PREF_NONE:
LowerNotifyConcurrentResult(gate);
break;
case EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8:
case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8:
LowerDefineFieldByName(gate);
break;
case EcmaOpcode::CALLRUNTIME_DEFINEFIELDBYVALUE_PREF_IMM8_V8_V8:
LowerDefineFieldByValue(gate);
break;
case EcmaOpcode::CALLRUNTIME_DEFINEFIELDBYINDEX_PREF_IMM8_IMM32_V8:
LowerDefineFieldByIndex(gate);
break;
case EcmaOpcode::CALLRUNTIME_TOPROPERTYKEY_PREF_NONE:
LowerToPropertyKey(gate);
break;
case EcmaOpcode::CALLRUNTIME_CREATEPRIVATEPROPERTY_PREF_IMM16_ID16:
LowerCreatePrivateProperty(gate);
break;
case EcmaOpcode::CALLRUNTIME_DEFINEPRIVATEPROPERTY_PREF_IMM8_IMM16_IMM16_V8:
LowerDefinePrivateProperty(gate);
break;
case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8:
LowerCallInit(gate);
break;
case EcmaOpcode::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8:
LowerDefineSendableClass(gate);
break;
case EcmaOpcode::CALLRUNTIME_LDSENDABLECLASS_PREF_IMM16:
LowerLdSendableClass(gate);
break;
case EcmaOpcode::CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8:
case EcmaOpcode::CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16:
LowerSendableExternalModule(gate);
break;
case EcmaOpcode::CALLRUNTIME_NEWSENDABLEENV_PREF_IMM8:
case EcmaOpcode::CALLRUNTIME_WIDENEWSENDABLEENV_PREF_IMM16:
LowerNewSendableEnv(gate);
break;
case EcmaOpcode::CALLRUNTIME_STSENDABLEVAR_PREF_IMM4_IMM4:
case EcmaOpcode::CALLRUNTIME_STSENDABLEVAR_PREF_IMM8_IMM8:
case EcmaOpcode::CALLRUNTIME_WIDESTSENDABLEVAR_PREF_IMM16_IMM16:
LowerStSendableVar(gate);
break;
case EcmaOpcode::CALLRUNTIME_LDSENDABLEVAR_PREF_IMM4_IMM4:
case EcmaOpcode::CALLRUNTIME_LDSENDABLEVAR_PREF_IMM8_IMM8:
case EcmaOpcode::CALLRUNTIME_WIDELDSENDABLEVAR_PREF_IMM16_IMM16:
LowerLdSendableVar(gate);
break;
case EcmaOpcode::CALLRUNTIME_LDLAZYMODULEVAR_PREF_IMM8:
case EcmaOpcode::CALLRUNTIME_WIDELDLAZYMODULEVAR_PREF_IMM16:
LowerLdLazyExternalModuleVar(gate);
break;
case EcmaOpcode::CALLRUNTIME_LDLAZYSENDABLEMODULEVAR_PREF_IMM8:
case EcmaOpcode::CALLRUNTIME_WIDELDLAZYSENDABLEMODULEVAR_PREF_IMM16:
LowerLdLazySendableExternalModuleVar(gate);
break;
case EcmaOpcode::LDA_STR_ID16:
LowerLdStr(gate);
break;
default:
break;
}
}
void SlowPathLowering::LowerCallStubWithIC(GateRef gate, int sign, const std::vector<GateRef> &args)
{
std::vector<GateRef> inputs { glue_ };
inputs.insert(inputs.end(), args.begin(), args.end());
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef slotId = builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 0));
inputs.emplace_back(jsFunc);
inputs.emplace_back(slotId);
GateRef result = builder_.CallStub(glue_, gate, sign, inputs);
ReplaceHirWithValue(gate, result);
}
GateRef SlowPathLowering::LowerCallRuntime(GateRef gate, int index, const std::vector<GateRef> &args, bool useLabel)
{
const std::string name = RuntimeStubCSigns::GetRTName(index);
if (useLabel) {
GateRef result = builder_.CallRuntime(glue_, index, Gate::InvalidGateRef, args, gate, name.c_str());
return result;
} else {
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
GateRef target = builder_.IntPtr(index);
GateRef result = builder_.Call(cs, glue_, target, builder_.GetDepend(), args, gate, name.c_str());
return result;
}
}
GateRef SlowPathLowering::LowerCallNGCRuntime(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 SlowPathLowering::LowerAdd2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Add,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerCreateIterResultObj(GateRef gate)
{
const int id = RTSTUB_ID(CreateIterResultObj);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
ReplaceHirWithValue(gate, newGate);
}
// When executing to SUSPENDGENERATOR instruction, save contextual information to GeneratorContext,
// including registers, acc, etc.
void SlowPathLowering::SaveFrameToContext(GateRef gate)
{
GateRef genObj = acc_.GetValueIn(gate, 1);
GateRef saveRegister = acc_.GetDep(gate);
while (acc_.GetOpCode(saveRegister) != OpCode::SAVE_REGISTER) {
saveRegister = acc_.GetDep(saveRegister);
}
ASSERT(acc_.GetOpCode(saveRegister) == OpCode::SAVE_REGISTER);
acc_.SetDep(gate, acc_.GetDep(saveRegister));
builder_.SetDepend(acc_.GetDep(saveRegister));
GateRef context =
builder_.Load(VariableType::JS_POINTER(), genObj, builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET));
// new tagged array
auto method = methodLiteral_;
const size_t arrLength = method->GetNumberVRegs() + 1; // 1: env vreg
GateRef length = builder_.Int32(arrLength);
GateRef taggedLength = builder_.ToTaggedInt(builder_.ZExtInt32ToInt64(length));
const int arrayId = RTSTUB_ID(NewTaggedArray);
GateRef taggedArray = LowerCallRuntime(gate, arrayId, {taggedLength});
// setRegsArrays
auto hole = builder_.HoleConstant();
size_t numVreg = acc_.GetNumValueIn(saveRegister);
for (size_t idx = 0; idx < numVreg; idx++) {
GateRef tmpGate = acc_.GetValueIn(saveRegister, idx);
if (tmpGate != hole) {
builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue_, taggedArray, builder_.Int32(idx), tmpGate);
}
}
ASSERT(numVreg > 0);
GateRef lexicalEnvGate = acc_.GetValueIn(saveRegister, numVreg - 1);
acc_.DeleteGate(saveRegister);
// setRegsArrays
GateRef regsArrayOffset = builder_.IntPtr(GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET);
builder_.Store(VariableType::JS_POINTER(), glue_, context, regsArrayOffset, taggedArray);
// set this
GateRef thisOffset = builder_.IntPtr(GeneratorContext::GENERATOR_THIS_OFFSET);
GateRef thisObj = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
builder_.Store(VariableType::JS_ANY(), glue_, context, thisOffset, thisObj);
// set method
GateRef methodOffset = builder_.IntPtr(GeneratorContext::GENERATOR_METHOD_OFFSET);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
builder_.Store(VariableType::JS_ANY(), glue_, context, methodOffset, jsFunc);
// set acc
ASSERT(acc_.GetNumValueIn(gate) > 0);
GateRef accOffset = builder_.IntPtr(GeneratorContext::GENERATOR_ACC_OFFSET);
GateRef curAccGate = acc_.GetValueIn(gate, acc_.GetNumValueIn(gate) - 1); // get current acc
builder_.Store(VariableType::JS_ANY(), glue_, context, accOffset, curAccGate);
// set generator object
GateRef generatorObjectOffset = builder_.IntPtr(GeneratorContext::GENERATOR_GENERATOR_OBJECT_OFFSET);
builder_.Store(VariableType::JS_ANY(), glue_, context, generatorObjectOffset, genObj);
// set lexical env
GateRef lexicalEnvOffset = builder_.IntPtr(GeneratorContext::GENERATOR_LEXICALENV_OFFSET);
builder_.Store(VariableType::JS_ANY(), glue_, context, lexicalEnvOffset, lexicalEnvGate);
// set nregs
GateRef nregsOffset = builder_.IntPtr(GeneratorContext::GENERATOR_NREGS_OFFSET);
builder_.Store(VariableType::INT32(), glue_, context, nregsOffset, length);
// set bc size
GateRef bcSizeOffset = builder_.IntPtr(GeneratorContext::GENERATOR_BC_OFFSET_OFFSET);
GateRef bcSizeGate = acc_.GetValueIn(gate, 0); // saved bc_offset
bcSizeGate = builder_.TruncInt64ToInt32(bcSizeGate);
builder_.Store(VariableType::INT32(), glue_, context, bcSizeOffset, bcSizeGate);
// set context to generator object
GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
builder_.Store(VariableType::JS_POINTER(), glue_, genObj, contextOffset, context);
// set generator object to context
builder_.Store(VariableType::JS_POINTER(), glue_, context, generatorObjectOffset, genObj);
}
void SlowPathLowering::LowerSuspendGenerator(GateRef gate)
{
SaveFrameToContext(gate);
acc_.SetDep(gate, builder_.GetDepend());
AddProfiling(gate, false);
const int id = RTSTUB_ID(OptSuspendGenerator);
auto value = acc_.GetValueIn(gate, 2); // 2: acc
auto genObj = acc_.GetValueIn(gate, 1);
GateRef newGate = LowerCallRuntime(gate, id, { genObj, value });
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerAsyncFunctionAwaitUncaught(GateRef gate)
{
const int id = RTSTUB_ID(AsyncFunctionAwaitUncaught);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerAsyncFunctionResolve(GateRef gate)
{
const int id = RTSTUB_ID(AsyncFunctionResolveOrReject);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef taggedTrue = builder_.TaggedTrue();
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), taggedTrue});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerAsyncFunctionReject(GateRef gate)
{
const int id = RTSTUB_ID(AsyncFunctionResolveOrReject);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef taggedFalse = builder_.TaggedFalse();
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), taggedFalse});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerTryLdGlobalByName(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
LowerCallStubWithIC(gate, CommonStubCSigns::TryLdGlobalByName, { stringId });
}
void SlowPathLowering::LowerStGlobalVar(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef id = acc_.GetValueIn(gate, 1); // 1: the second parameter
GateRef value = acc_.GetValueIn(gate, 2); // 2: the 2nd para is value
LowerCallStubWithIC(gate, CommonStubCSigns::StGlobalVar, { id, value });
}
void SlowPathLowering::LowerGetIterator(GateRef gate)
{
auto result = LowerCallRuntime(gate, RTSTUB_ID(GetIterator), {acc_.GetValueIn(gate, 0)}, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerGetAsyncIterator(GateRef gate)
{
auto result = LowerCallRuntime(gate, RTSTUB_ID(GetAsyncIterator), {acc_.GetValueIn(gate, 0)}, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerCallArg0(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLARG0_IMM8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef newTarget = builder_.Undefined();
GateRef thisObj = builder_.Undefined();
GateRef func = acc_.GetValueIn(gate, 0);
LowerToJSCall(gate, {glue_, actualArgc, actualArgv, func, newTarget, thisObj}, {glue_, func, thisObj});
}
void SlowPathLowering::LowerCallthisrangeImm8Imm8V8(GateRef gate)
{
// this
size_t fixedInputsNum = 1;
size_t numIns = acc_.GetNumValueIn(gate);
ASSERT(numIns >= fixedInputsNum);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
GateRef actualArgv = builder_.IntPtr(0);
const size_t callTargetIndex = 1; // 1: acc
GateRef callTarget = acc_.GetValueIn(gate, numIns - callTargetIndex); // acc
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef newTarget = builder_.Undefined();
std::vector<GateRef> vec { glue_, actualArgc, actualArgv, callTarget, newTarget, thisObj };
// add common args
for (size_t i = fixedInputsNum; i < numIns - callTargetIndex; i++) {
vec.emplace_back(acc_.GetValueIn(gate, i));
}
std::vector<GateRef> vec1 { glue_, callTarget, thisObj };
// add common args
for (size_t i = fixedInputsNum; i < numIns - callTargetIndex; i++) {
vec1.emplace_back(acc_.GetValueIn(gate, i));
}
LowerToJSCall(gate, vec, vec1);
}
void SlowPathLowering::LowerWideCallthisrangePrefImm16V8(GateRef gate)
{
// The first register input is thisobj, second is thisObj and other inputs are common args.
size_t fixedInputsNum = 1; // 1: acc
size_t numIns = acc_.GetNumValueIn(gate);
ASSERT(numIns >= fixedInputsNum);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8));
GateRef actualArgv = builder_.IntPtr(0);
const size_t callTargetIndex = 1;
GateRef callTarget = acc_.GetValueIn(gate, numIns - callTargetIndex);
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef newTarget = builder_.Undefined();
std::vector<GateRef> vec {glue_, actualArgc, actualArgv, callTarget, newTarget, thisObj};
// add common args
for (size_t i = fixedInputsNum; i < numIns - callTargetIndex; i++) {
vec.emplace_back(acc_.GetValueIn(gate, i));
}
std::vector<GateRef> vec1 {glue_, callTarget, thisObj};
// add common args
for (size_t i = fixedInputsNum; i < numIns - callTargetIndex; i++) {
vec1.emplace_back(acc_.GetValueIn(gate, i));
}
LowerToJSCall(gate, vec, vec1);
}
void SlowPathLowering::LowerCallSpread(GateRef gate)
{
// need to fixed in later
const int id = RTSTUB_ID(CallSpread);
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef stateInGate = builder_.GetState();
GateRef newGate = LowerCallRuntime(gate, id,
{acc_.GetValueIn(gate, 2), acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
ReplaceHirWithPendingException(gate, stateInGate, newGate, newGate);
}
void SlowPathLowering::LowerCallrangeImm8Imm8V8(GateRef gate)
{
size_t numArgs = acc_.GetNumValueIn(gate);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
GateRef actualArgv = builder_.IntPtr(0);
const size_t callTargetIndex = 1; // acc
ASSERT(numArgs > 0);
GateRef callTarget = acc_.GetValueIn(gate, numArgs - callTargetIndex);
GateRef newTarget = builder_.Undefined();
GateRef thisObj = builder_.Undefined();
std::vector<GateRef> vec {glue_, actualArgc, actualArgv, callTarget, newTarget, thisObj};
for (size_t i = 0; i < numArgs - callTargetIndex; i++) { // 2: skip acc
vec.emplace_back(acc_.GetValueIn(gate, i));
}
std::vector<GateRef> vec1 {glue_, callTarget, thisObj};
for (size_t i = 0; i < numArgs - callTargetIndex; i++) { // 2: skip acc
vec1.emplace_back(acc_.GetValueIn(gate, i));
}
LowerToJSCall(gate, vec, vec1);
}
void SlowPathLowering::LowerNewObjApply(GateRef gate)
{
const int id = RTSTUB_ID(NewObjApply);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef newGate = LowerCallRuntime(gate, id,
{acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerThrow(GateRef gate)
{
GateRef exception = acc_.GetValueIn(gate, 0);
GateRef exceptionOffset = builder_.Int64(JSThread::GlueData::GetExceptionOffset(false));
builder_.Store(VariableType::INT64(), glue_, glue_, exceptionOffset, exception);
// store gate value == depend
GateRef result = builder_.GetDepend();
ReplaceHirToThrowCall(gate, result);
}
void SlowPathLowering::LowerThrowConstAssignment(GateRef gate)
{
const int id = RTSTUB_ID(ThrowConstAssignment);
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)});
ReplaceHirToThrowCall(gate, newGate);
}
void SlowPathLowering::LowerThrowThrowNotExists(GateRef gate)
{
const int id = RTSTUB_ID(ThrowThrowNotExists);
GateRef newGate = LowerCallRuntime(gate, id, {});
ReplaceHirToThrowCall(gate, newGate);
}
void SlowPathLowering::LowerThrowPatternNonCoercible(GateRef gate)
{
const int id = RTSTUB_ID(ThrowPatternNonCoercible);
GateRef newGate = LowerCallRuntime(gate, id, {});
ReplaceHirToThrowCall(gate, newGate);
}
void SlowPathLowering::LowerThrowIfNotObject(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef value = acc_.GetValueIn(gate, 0);
Label successExit(&builder_);
Label exceptionExit(&builder_);
Label isEcmaObject(&builder_);
Label notEcmaObject(&builder_);
Label isHeapObject(&builder_);
BRANCH_CIR(builder_.TaggedIsHeapObject(value), &isHeapObject, &notEcmaObject);
builder_.Bind(&isHeapObject);
BRANCH_CIR(builder_.TaggedObjectIsEcmaObject(value), &isEcmaObject, &notEcmaObject);
builder_.Bind(&isEcmaObject);
{
builder_.Jump(&successExit);
}
builder_.Bind(&notEcmaObject);
{
LowerCallRuntime(gate, RTSTUB_ID(ThrowIfNotObject), {}, true);
builder_.Jump(&exceptionExit);
}
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
}
void SlowPathLowering::LowerThrowUndefinedIfHole(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef hole = acc_.GetValueIn(gate, 0);
GateRef obj = acc_.GetValueIn(gate, 1);
Label successExit(&builder_);
Label exceptionExit(&builder_);
Label isHole(&builder_);
Label notHole(&builder_);
BRANCH_CIR(builder_.TaggedIsHole(hole), &isHole, &notHole);
builder_.Bind(&notHole);
{
builder_.Jump(&successExit);
}
builder_.Bind(&isHole);
{
LowerCallRuntime(gate, RTSTUB_ID(ThrowUndefinedIfHole), {obj}, true);
builder_.Jump(&exceptionExit);
}
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
}
void SlowPathLowering::LowerThrowUndefinedIfHoleWithName(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef hole = acc_.GetValueIn(gate, 1);
Label successExit(&builder_);
Label exceptionExit(&builder_);
Label isHole(&builder_);
Label notHole(&builder_);
BRANCH_CIR(builder_.TaggedIsHole(hole), &isHole, &notHole);
builder_.Bind(&notHole);
{
builder_.Jump(&successExit);
}
builder_.Bind(&isHole);
{
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef obj = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module,
builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 0)),
ConstPoolType::STRING);
LowerCallRuntime(gate, RTSTUB_ID(ThrowUndefinedIfHole), {obj}, true);
builder_.Jump(&exceptionExit);
}
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
}
void SlowPathLowering::LowerThrowIfSuperNotCorrectCall(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(ThrowIfSuperNotCorrectCall),
{builder_.ToTaggedInt(acc_.GetValueIn(gate, 0)), acc_.GetValueIn(gate, 1)}, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerThrowDeleteSuperProperty(GateRef gate)
{
const int id = RTSTUB_ID(ThrowDeleteSuperProperty);
GateRef newGate = LowerCallRuntime(gate, id, {});
ReplaceHirToThrowCall(gate, newGate);
}
void SlowPathLowering::LowerExceptionHandler(GateRef hirGate)
{
GateRef depend = acc_.GetDep(hirGate);
GateRef exceptionOffset = builder_.Int64(JSThread::GlueData::GetExceptionOffset(false));
GateRef val = builder_.Int64Add(glue_, exceptionOffset);
auto bit = LoadStoreAccessor::ToValue(MemoryAttribute::Default());
GateRef loadException = circuit_->NewGate(circuit_->Load(bit), VariableType::JS_ANY().GetMachineType(),
{ depend, val }, VariableType::JS_ANY().GetGateType());
acc_.SetDep(loadException, depend);
GateRef holeCst = builder_.HoleConstant();
GateRef clearException = circuit_->NewGate(circuit_->Store(bit), MachineType::NOVALUE,
{ loadException, glue_, glue_, exceptionOffset, holeCst }, VariableType::INT64().GetGateType());
auto uses = acc_.Uses(hirGate);
for (auto it = uses.begin(); it != uses.end();) {
if (acc_.GetOpCode(*it) != OpCode::VALUE_SELECTOR && acc_.IsDependIn(it)) {
it = acc_.ReplaceIn(it, clearException);
} else {
it = acc_.ReplaceIn(it, loadException);
}
}
acc_.DeleteGate(hirGate);
}
void SlowPathLowering::LowerLdSymbol(GateRef gate)
{
const int id = RTSTUB_ID(GetSymbolFunction);
GateRef newGate = LowerCallRuntime(gate, id, {});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerLdGlobal(GateRef gate)
{
GateRef offset = builder_.Int64(JSThread::GlueData::GetGlobalObjOffset(false));
GateRef val = builder_.Int64Add(glue_, offset);
auto bit = LoadStoreAccessor::ToValue(MemoryAttribute::Default());
GateRef newGate = circuit_->NewGate(circuit_->Load(bit), VariableType::JS_ANY().GetMachineType(),
{ builder_.GetDepend(), val }, VariableType::JS_ANY().GetGateType());
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerSub2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Sub,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerMul2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Mul,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerDiv2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Div,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerMod2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Mod,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerEq(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Equal,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerNotEq(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::NotEqual,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerLess(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Less,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerLessEq(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::LessEq,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerGreater(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Greater,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerGreaterEq(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::GreaterEq,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerGetPropIterator(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef object = {acc_.GetValueIn(gate, 0)};
GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::Getpropiterator, {glue_, object});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerCloseIterator(GateRef gate)
{
const int id = RTSTUB_ID(CloseIterator);
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerInc(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Inc,
{ glue_, acc_.GetValueIn(gate, 0) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerDec(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Dec,
{ glue_, acc_.GetValueIn(gate, 0) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerToNumber(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
Label notNumber(&builder_);
Label checkResult(&builder_);
GateRef value = acc_.GetValueIn(gate, 0);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), value);
BRANCH_CIR(builder_.TaggedIsNumber(value), &checkResult, &notNumber);
builder_.Bind(&notNumber);
{
result = LowerCallRuntime(gate, RTSTUB_ID(ToNumber), { value }, true);
builder_.Jump(&checkResult);
}
builder_.Bind(&checkResult);
ReplaceHirWithValue(gate, *result);
}
void SlowPathLowering::LowerNeg(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Neg,
{ glue_, acc_.GetValueIn(gate, 0) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerNot(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Not,
{ glue_, acc_.GetValueIn(gate, 0) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerShl2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Shl,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerShr2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Shr,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerAshr2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Ashr,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerAnd2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::And,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerOr2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Or,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerXor2(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Xor,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerDelObjProp(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
Label successExit(&builder_);
Label exceptionExit(&builder_);
GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::DeleteObjectProperty,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
BRANCH_CIR(builder_.IsSpecial(newGate, JSTaggedValue::VALUE_EXCEPTION),
&exceptionExit, &successExit);
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, newGate);
}
void SlowPathLowering::LowerExp(GateRef gate)
{
const int id = RTSTUB_ID(Exp);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerIsIn(GateRef gate)
{
const int id = RTSTUB_ID(IsIn);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerInstanceof(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef obj = acc_.GetValueIn(gate, 1); // 1: the second parameter
GateRef target = acc_.GetValueIn(gate, 2); // 2: the third parameter
LowerCallStubWithIC(gate, CommonStubCSigns::Instanceof, { obj, target });
}
void SlowPathLowering::LowerFastStrictNotEqual(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::StrictNotEqual,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerFastStrictEqual(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::StrictEqual,
{ glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerCreateEmptyArray(GateRef gate)
{
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::CreateEmptyArray, { glue_ });
GateRef newRes = LowerUpdateArrayHClassAtDefine(gate, result);
ReplaceHirWithValue(gate, newRes, true);
}
void SlowPathLowering::LowerCreateEmptyObject(GateRef gate)
{
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(CreateEmptyObject), {}, true);
ReplaceHirWithValue(gate, result, true);
}
void SlowPathLowering::LowerCreateArrayWithBuffer(GateRef gate)
{
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::CreateArrayWithBuffer, { glue_, index, jsFunc });
// when elementsKind switch on, we should not update arrayHClass here.
GateRef newRes = LowerUpdateArrayHClassAtDefine(gate, result);
ReplaceHirWithValue(gate, newRes, true);
}
GateRef SlowPathLowering::LowerUpdateArrayHClassAtDefine(GateRef gate, GateRef array)
{
ElementsKind kind = acc_.TryGetElementsKind(gate);
if (!Elements::IsGeneric(kind)) {
size_t hclassIndex = static_cast<size_t>(compilationEnv_->GetArrayHClassIndexMap().at(kind).first);
GateRef gConstAddr = builder_.Load(VariableType::JS_POINTER(), glue_,
builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(false)));
GateRef constantIndex = builder_.IntPtr(JSTaggedValue::TaggedTypeSize() * hclassIndex);
GateRef hclass = builder_.Load(VariableType::JS_POINTER(), gConstAddr, constantIndex);
builder_.Store(VariableType::JS_POINTER(), glue_, array, builder_.IntPtr(0), hclass);
}
return array;
}
void SlowPathLowering::LowerCreateObjectWithBuffer(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef unsharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
GateRef index = acc_.GetValueIn(gate, 0);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef obj = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, unsharedConstPool, module,
builder_.TruncInt64ToInt32(index), ConstPoolType::OBJECT_LITERAL);
GateRef lexEnv = acc_.GetValueIn(gate, 1);
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(CreateObjectHavingMethod), { obj, lexEnv }, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerStModuleVar(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
auto result = LowerCallRuntime(gate, RTSTUB_ID(StModuleVarByIndexOnJSFunc),
{index, acc_.GetValueIn(gate, 1), jsFunc}, true);
ReplaceHirWithValue(gate, result, true);
}
void SlowPathLowering::LowerSetGeneratorState(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
auto result = LowerCallRuntime(gate, RTSTUB_ID(SetGeneratorState),
{acc_.GetValueIn(gate, 1), index, jsFunc}, true);
ReplaceHirWithValue(gate, result, true);
}
void SlowPathLowering::LowerGetTemplateObject(GateRef gate)
{
const int id = RTSTUB_ID(GetTemplateObject);
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef literal = acc_.GetValueIn(gate, 0);
GateRef newGate = LowerCallRuntime(gate, id, { literal });
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerSetObjectWithProto(GateRef gate)
{
const int id = RTSTUB_ID(SetObjectWithProto);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef proto = acc_.GetValueIn(gate, 0);
GateRef obj = acc_.GetValueIn(gate, 1);
GateRef newGate = LowerCallRuntime(gate, id, { proto, obj });
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerLdBigInt(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef numberBigInt = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module,
stringId, ConstPoolType::STRING);
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(LdBigInt), {numberBigInt}, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerToNumeric(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
Label notNumber(&builder_);
Label checkResult(&builder_);
GateRef value = acc_.GetValueIn(gate, 0);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), value);
BRANCH_CIR(builder_.TaggedIsNumeric(value), &checkResult, &notNumber);
builder_.Bind(&notNumber);
{
result = LowerCallRuntime(gate, RTSTUB_ID(ToNumeric), { value }, true);
builder_.Jump(&checkResult);
}
builder_.Bind(&checkResult);
ReplaceHirWithValue(gate, *result);
}
void SlowPathLowering::LowerDynamicImport(GateRef gate)
{
const int id = RTSTUB_ID(DynamicImport);
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), jsFunc});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerLdLocalModuleVarByIndex(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(LdLocalModuleVarByIndexOnJSFunc), {index, jsFunc}, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerExternalModule(GateRef gate)
{
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(LdExternalModuleVarByIndexOnJSFunc), {index, jsFunc}, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerGetModuleNamespace(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(GetModuleNamespaceByIndexOnJSFunc), {index, jsFunc}, true);
ReplaceHirWithValue(gate, result);
}
GateRef SlowPathLowering::GetTaggedArrayFromValueIn(Environment *env, GateRef gate, size_t length)
{
NewObjectStubBuilder objBuilder(env);
GateRef taggedArray = objBuilder.NewTaggedArray(glue_, builder_.Int32(length));
for (size_t i = 0; i < length; i++) {
builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue_, taggedArray,
builder_.Int32(i), acc_.GetValueIn(gate, i));
}
return taggedArray;
}
void SlowPathLowering::LowerSuperCall(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
NewObjectStubBuilder objBuilder(&env);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(newTarget, (&builder_), VariableType::JS_ANY(), argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET));
Label fastPath(&builder_);
Label slowPath(&builder_);
Label callExit(&builder_);
Label replaceGate(&builder_);
size_t length = acc_.GetNumValueIn(gate);
GateRef taggedLength = builder_.ToTaggedInt(builder_.Int64(length));
GateRef taggedArray = GetTaggedArrayFromValueIn(&env, gate, length);
GateRef func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef superFunc = objBuilder.GetPrototype(glue_, func);
CheckSuperAndNewTarget(objBuilder, superFunc, newTarget, thisObj, fastPath, slowPath);
builder_.Bind(&fastPath);
{
LowerFastSuperCallWithArgArray(taggedArray, {gate, superFunc, *newTarget, *thisObj,
builder_.Int64(length)}, false, result, callExit); // false: not spread
builder_.Bind(&callExit);
result = objBuilder.ConstructorCheck(glue_, superFunc, *result, *thisObj);
builder_.Jump(&replaceGate);
}
builder_.Bind(&slowPath);
{
result = LowerCallRuntime(gate, RTSTUB_ID(OptSuperCall), { func, *newTarget, taggedArray, taggedLength });
builder_.Jump(&replaceGate);
}
builder_.Bind(&replaceGate);
ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
void SlowPathLowering::LowerSuperCallArrow(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
NewObjectStubBuilder objBuilder(&env);
const int id = RTSTUB_ID(OptSuperCall);
ASSERT(acc_.GetNumValueIn(gate) > 0);
GateRef newTarget = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
size_t funcIndex = acc_.GetNumValueIn(gate) - 1;
GateRef taggedLength = builder_.ToTaggedInt(builder_.Int64(funcIndex));
GateRef taggedArray = GetTaggedArrayFromValueIn(&env, gate, funcIndex);
GateRef func = acc_.GetValueIn(gate, funcIndex);
std::vector<GateRef> vec { func, newTarget, taggedArray, taggedLength};
GateRef newGate = LowerCallRuntime(gate, id, vec);
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerSuperCallSpread(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
NewObjectStubBuilder objBuilder(&env);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(newTarget, (&builder_), VariableType::JS_ANY(), argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET));
Label fastPath(&builder_);
Label slowPath(&builder_);
Label callExit(&builder_);
Label replaceGate(&builder_);
GateRef array = acc_.GetValueIn(gate, 0);
GateRef func = acc_.GetValueIn(gate, 1);
GateRef superFunc = objBuilder.GetPrototype(glue_, func);
CheckSuperAndNewTarget(objBuilder, superFunc, newTarget, thisObj, fastPath, slowPath);
builder_.Bind(&fastPath);
{
GateRef actualArgc = builder_.ZExtInt32ToInt64(
builder_.Load(VariableType::INT32(), array, builder_.IntPtr(JSArray::LENGTH_OFFSET)));
LowerFastSuperCallWithArgArray(array, {gate, superFunc, *newTarget, *thisObj, actualArgc},
true, result, callExit); // true: is spread
builder_.Bind(&callExit);
result = objBuilder.ConstructorCheck(glue_, superFunc, *result, *thisObj);
builder_.Jump(&replaceGate);
}
builder_.Bind(&slowPath);
{
result = LowerCallRuntime(gate, RTSTUB_ID(OptSuperCallSpread), { func, *newTarget, array });
builder_.Jump(&replaceGate);
}
builder_.Bind(&replaceGate);
ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
GateRef SlowPathLowering::IsAotOrFastCall(GateRef func, CircuitBuilder::JudgeMethodType type)
{
return builder_.JudgeAotAndFastCall(func, type);
}
void SlowPathLowering::LowerFastSuperCallWithArgArray(GateRef array, const std::vector<GateRef> &args,
bool isSpread, Variable &result, Label &exit)
{
ASSERT(args.size() == 5); // 5: size of args
GateRef srcElements;
if (isSpread) {
GateRef gate = args[0]; // 0: index of gate
srcElements = builder_.CallStub(glue_, gate, CommonStubCSigns::GetCallSpreadArgs, {glue_, array});
} else {
srcElements = array;
}
GateRef elementsPtr = builder_.GetDataOfTaggedArray(srcElements);
LowerFastSuperCall(args, elementsPtr, result, exit);
}
void SlowPathLowering::LowerFastSuperCall(const std::vector<GateRef> &args, GateRef elementsPtr,
Variable &result, Label &exit)
{
Label fastCall(&builder_);
Label notFastCall(&builder_);
Label aotCall(&builder_);
Label notAotCall(&builder_);
ASSERT(args.size() == 5); // 5: size of args
GateRef gate = args[0]; // 0: index of gate
GateRef superFunc = args[1]; // 1: index of superFunc
GateRef newTartget = args[2]; // 2: index of newTarget
GateRef thisObj = args[3]; // 3: index of thisObj
GateRef actualArgc = args[4]; // 4: index of actualArgc
GateRef method = builder_.GetMethodFromFunction(superFunc);
GateRef expectedNum = builder_.GetExpectedNumOfArgs(method);
BRANCH_CIR(IsAotOrFastCall(superFunc, CircuitBuilder::JudgeMethodType::HAS_AOT_FASTCALL), &fastCall, &notFastCall);
builder_.Bind(&fastCall);
{
Label notBridge(&builder_);
Label bridge(&builder_);
BRANCH_CIR(builder_.Int64Equal(expectedNum, actualArgc), &notBridge, &bridge);
builder_.Bind(&notBridge);
CallNGCRuntimeWithCallTimer(RTSTUB_ID(JSFastCallWithArgV), gate, superFunc, result,
{glue_, superFunc, thisObj, actualArgc, elementsPtr});
builder_.Jump(&exit);
builder_.Bind(&bridge);
CallNGCRuntimeWithCallTimer(RTSTUB_ID(JSFastCallWithArgVAndPushArgv), gate, superFunc, result,
{glue_, superFunc, thisObj, actualArgc, elementsPtr, expectedNum});
builder_.Jump(&exit);
}
builder_.Bind(&notFastCall);
BRANCH_CIR(IsAotOrFastCall(superFunc, CircuitBuilder::JudgeMethodType::HAS_AOT), &aotCall, &notAotCall);
builder_.Bind(&aotCall);
{
Label notBridge(&builder_);
Label bridge(&builder_);
std::vector<GateRef> callArgs {glue_, actualArgc, superFunc, newTartget, thisObj, elementsPtr};
BRANCH_CIR(builder_.Int64Equal(expectedNum, actualArgc), &notBridge, &bridge);
builder_.Bind(&notBridge);
CallNGCRuntimeWithCallTimer(RTSTUB_ID(JSCallWithArgV), gate, superFunc, result, callArgs);
builder_.Jump(&exit);
builder_.Bind(&bridge);
CallNGCRuntimeWithCallTimer(RTSTUB_ID(JSCallWithArgVAndPushArgv), gate, superFunc, result, callArgs);
builder_.Jump(&exit);
}
builder_.Bind(&notAotCall);
CallNGCRuntimeWithCallTimer(RTSTUB_ID(SuperCallWithArgV), gate, superFunc, result,
{glue_, actualArgc, superFunc, newTartget, thisObj, elementsPtr});
builder_.Jump(&exit);
}
void SlowPathLowering::CallNGCRuntimeWithCallTimer(int index, GateRef gate, GateRef func, Variable &result,
const std::vector<GateRef> &args)
{
builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
result = LowerCallNGCRuntime(gate, index, args, true);
builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
}
void SlowPathLowering::CheckSuperAndNewTarget(NewObjectStubBuilder &objBuilder, GateRef super, Variable &newTarget,
Variable &thisObj, Label &fastPath, Label &slowPath)
{
Label isHeapObj(&builder_);
Label isJsFunc(&builder_);
Label isCtor(&builder_);
Label targetUndefined(&builder_);
Label normalPath(&builder_);
Label needAllocateThis(&builder_);
BRANCH_CIR(builder_.TaggedIsHeapObject(super), &isHeapObj, &slowPath);
builder_.Bind(&isHeapObj);
BRANCH_CIR(builder_.IsJSFunction(super), &isJsFunc, &slowPath);
builder_.Bind(&isJsFunc);
BRANCH_CIR(builder_.IsConstructor(super), &isCtor, &slowPath);
builder_.Bind(&isCtor);
BRANCH_CIR(builder_.TaggedIsUndefined(*newTarget), &targetUndefined, &normalPath);
builder_.Bind(&targetUndefined);
newTarget = super;
builder_.Jump(&normalPath);
builder_.Bind(&normalPath);
BRANCH_CIR(builder_.IsBase(super), &needAllocateThis, &fastPath);
builder_.Bind(&needAllocateThis);
thisObj = objBuilder.FastSuperAllocateThis(glue_, super, *newTarget);
builder_.Jump(&fastPath);
}
void SlowPathLowering::LowerSuperCallForwardAllArgs(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
NewObjectStubBuilder objBuilder(&env);
DEFVALUE(newTarget, (&builder_), VariableType::JS_ANY(), argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET));
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
GateRef func = acc_.GetValueIn(gate, 0);
GateRef actualArgc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGC);
GateRef actualArgv = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGV);
GateRef super = objBuilder.GetPrototype(glue_, func);
Label fastPath(&builder_);
Label fastPathWithArgv(&builder_);
Label callExit(&builder_);
Label slowPath(&builder_);
Label threadCheck(&builder_);
Label argvIsNull(&builder_);
Label getArgsFromArgAcc(&builder_);
CheckSuperAndNewTarget(objBuilder, super, newTarget, thisObj, fastPath, slowPath);
builder_.Bind(&fastPath);
{
BRANCH_CIR(builder_.Equal(actualArgv, builder_.IntPtr(0)), &argvIsNull, &fastPathWithArgv);
builder_.Bind(&argvIsNull);
{
GateRef method = builder_.GetMethodFromFunction(func);
GateRef expectedFuncArgNum = builder_.ZExtInt32ToInt64(builder_.GetExpectedNumOfArgs(method));
GateRef expected = builder_.Int64Add(expectedFuncArgNum, builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS));
BRANCH_CIR(builder_.Int64Equal(expected, actualArgc), &getArgsFromArgAcc, &slowPath);
builder_.Bind(&getArgsFromArgAcc);
std::vector<GateRef> args { gate, super, actualArgc, *newTarget, *thisObj };
GenerateSuperCallForwardAllArgsWithoutArgv(args, result, threadCheck);
}
builder_.Bind(&fastPathWithArgv);
{
GateRef argc = builder_.Int64Sub(actualArgc, builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS));
GateRef argv = builder_.PtrAdd(actualArgv, builder_.IntPtr(NUM_MANDATORY_JSFUNC_ARGS * 8)); // 8: ptr size
LowerFastSuperCall({ gate, super, *newTarget, *thisObj, argc }, argv, result, callExit);
builder_.Bind(&callExit);
result = objBuilder.ConstructorCheck(glue_, super, *result, *thisObj);
builder_.Jump(&threadCheck);
}
}
builder_.Bind(&slowPath);
{
std::vector<GateRef> args { super, *newTarget, builder_.ToTaggedInt(actualArgc) };
result = LowerCallRuntime(gate, RTSTUB_ID(OptSuperCallForwardAllArgs), args, true);
builder_.Jump(&threadCheck);
}
builder_.Bind(&threadCheck);
ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
void SlowPathLowering::GenerateSuperCallForwardAllArgsWithoutArgv(const std::vector<GateRef> &args, Variable &result,
Label &exit)
{
ASSERT(args.size() == 5); // 5: size of args
GateRef gate = args[0]; // 0: gate
GateRef super = args[1]; // 1: super constructor
GateRef actualArgc = args[2]; // 2: num of args
GateRef newTarget = args[3]; // 3: argv
GateRef thisObj = args[4]; // 4: newTarget
Label afterCallSuper(&builder_);
std::vector<GateRef> callArgs { glue_, actualArgc, builder_.IntPtr(0), super, newTarget, thisObj };
std::vector<GateRef> argsFastCall { glue_, super, thisObj };
uint32_t startIdx = static_cast<uint32_t>(CommonArgIdx::NUM_OF_ARGS);
ASSERT(argAcc_.ArgsCount() >= startIdx);
for (uint32_t i = startIdx; i < argAcc_.ArgsCount(); ++i) {
GateRef value = argAcc_.ArgsAt(i);
callArgs.emplace_back(value);
argsFastCall.emplace_back(value);
}
LowerFastCall(gate, glue_, super, actualArgc, callArgs, argsFastCall, &result, &afterCallSuper, true);
builder_.Bind(&afterCallSuper);
result = builder_.CallStub(glue_, gate, CommonStubCSigns::ConstructorCheck, { glue_, super, *result, thisObj });
builder_.Jump(&exit);
}
void SlowPathLowering::LowerIsTrueOrFalse(GateRef gate, bool flag)
{
Label slowpath(&builder_);
Label isTrue(&builder_);
Label isFalse(&builder_);
Label successExit(&builder_);
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
auto value = acc_.GetValueIn(gate, 0);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), value);
if (flag) {
result = builder_.CallStub(glue_, gate, CommonStubCSigns::ToBooleanTrue, { glue_, value });
} else {
result = builder_.CallStub(glue_, gate, CommonStubCSigns::ToBooleanFalse, { glue_, value });
}
ReplaceHirWithValue(gate, *result, true);
}
void SlowPathLowering::LowerNewObjRange(GateRef gate)
{
Label fastPath(&builder_);
Label slowPath(&builder_);
Label threadCheck(&builder_);
Label successExit(&builder_);
Label exit(&builder_);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
GateRef ctor = acc_.GetValueIn(gate, 0);
GateRef thisObj = builder_.CallStub(glue_, gate, CommonStubCSigns::NewThisObjectChecked, { glue_, ctor });
BRANCH_CIR(builder_.TaggedIsHole(thisObj), &slowPath, &fastPath);
builder_.Bind(&fastPath);
{
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
GateRef actualArgv = builder_.IntPtr(0);
size_t range = acc_.GetNumValueIn(gate);
std::vector<GateRef> args{glue_, actualArgc, actualArgv, ctor, ctor, thisObj};
std::vector<GateRef> argsFastCall{glue_, ctor, thisObj};
for (size_t i = 1; i < range; ++i) {
args.emplace_back(acc_.GetValueIn(gate, i));
argsFastCall.emplace_back(acc_.GetValueIn(gate, i));
}
LowerFastCall(gate, glue_, ctor, actualArgc, args, argsFastCall, &result, &exit, true);
builder_.Bind(&exit);
result = builder_.CallStub(glue_, gate, CommonStubCSigns::ConstructorCheck, { glue_, ctor, *result, thisObj });
builder_.Jump(&threadCheck);
}
builder_.Bind(&slowPath);
{
size_t range = acc_.GetNumValueIn(gate);
std::vector<GateRef> args(range);
for (size_t i = 0; i < range; ++i) {
args[i] = acc_.GetValueIn(gate, i);
}
result = LowerCallRuntime(gate, RTSTUB_ID(OptNewObjRange), args, true);
builder_.Jump(&threadCheck);
}
builder_.Bind(&threadCheck);
ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
bool SlowPathLowering::IsDependIfStateMent(GateRef gate, size_t idx)
{
return ((acc_.GetOpCode(gate) == OpCode::DEPEND_SELECTOR) || (acc_.GetOpCode(gate) == OpCode::DEPEND_RELAY)) &&
(idx > 0 && (acc_.GetOpCode(acc_.GetIn(acc_.GetIn(gate, 0), idx - 1)) != OpCode::IF_EXCEPTION));
}
void SlowPathLowering::LowerConditionJump(GateRef gate, bool isEqualJump)
{
GateRef value = acc_.GetValueIn(gate, 0);
Label isZero(&builder_);
Label notZero(&builder_);
// GET_ACC().IsFalse()
Label notFalse(&builder_);
BRANCH_CIR(builder_.IsSpecial(value, JSTaggedValue::VALUE_FALSE), &isZero, &notFalse);
builder_.Bind(&notFalse);
{
// (GET_ACC().IsInt() && GET_ACC().GetInt() == 0)
Label isInt(&builder_);
Label notIntZero(&builder_);
BRANCH_CIR(builder_.TaggedIsInt(value), &isInt, &notIntZero);
builder_.Bind(&isInt);
BRANCH_CIR(builder_.Equal(builder_.TaggedGetInt(value), builder_.Int32(0)), &isZero, &notIntZero);
builder_.Bind(&notIntZero);
{
// (GET_ACC().IsDouble() && GET_ACC().GetDouble() == 0.0)
Label isDouble(&builder_);
BRANCH_CIR(builder_.TaggedIsDouble(value), &isDouble, &notZero);
builder_.Bind(&isDouble);
BRANCH_CIR(builder_.Equal(builder_.GetDoubleOfTDouble(value), builder_.Double(0.0)), &isZero, &notZero);
builder_.Bind(&notZero);
}
}
builder_.Bind(&isZero);
Label &ifTrue = isEqualJump ? isZero : notZero;
Label &ifFalse = isEqualJump ? notZero : isZero;
auto uses = acc_.Uses(gate);
for (auto it = uses.begin(); it != uses.end();) {
if (acc_.GetOpCode(*it) == OpCode::IF_TRUE) {
acc_.SetMetaData(*it, circuit_->OrdinaryBlock());
it = acc_.ReplaceIn(it, ifTrue.GetControl());
} else if (acc_.GetOpCode(*it) == OpCode::IF_FALSE) {
acc_.SetMetaData(*it, circuit_->OrdinaryBlock());
it = acc_.ReplaceIn(it, ifFalse.GetControl());
} else if (IsDependIfStateMent(*it, it.GetIndex())) {
it = acc_.ReplaceIn(it, acc_.GetDep(gate));
} else {
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
// delete old gate
acc_.DeleteGate(gate);
}
void SlowPathLowering::LowerGetNextPropName(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef iter = acc_.GetValueIn(gate, 0);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label notFinish(&builder_);
Label notEnumCacheValid(&builder_);
Label fastGetKey(&builder_);
Label slowpath(&builder_);
Label exit(&builder_);
GateRef index = builder_.GetIndexFromForInIterator(iter);
GateRef length = builder_.GetLengthFromForInIterator(iter);
BRANCH_CIR(builder_.Int32GreaterThanOrEqual(index, length), &exit, &notFinish);
builder_.Bind(&notFinish);
GateRef keys = builder_.GetKeysFromForInIterator(iter);
GateRef receiver = builder_.GetObjectFromForInIterator(iter);
GateRef cachedHclass = builder_.GetCachedHclassFromForInIterator(iter);
GateRef kind = builder_.GetEnumCacheKind(glue_, keys);
BRANCH_CIR(builder_.IsEnumCacheValid(receiver, cachedHclass, kind), &fastGetKey, &notEnumCacheValid);
builder_.Bind(&notEnumCacheValid);
BRANCH_CIR(builder_.NeedCheckProperty(receiver), &slowpath, &fastGetKey);
builder_.Bind(&fastGetKey);
{
result = builder_.GetValueFromTaggedArray(keys, index);
builder_.IncreaseInteratorIndex(glue_, iter, index);
builder_.Jump(&exit);
}
builder_.Bind(&slowpath);
{
result = LowerCallRuntime(gate, RTSTUB_ID(GetNextPropNameSlowpath), { iter }, true);
builder_.Jump(&exit);
}
builder_.Bind(&exit);
ReplaceHirWithValue(gate, *result);
}
void SlowPathLowering::LowerCopyDataProperties(GateRef gate)
{
const int id = RTSTUB_ID(CopyDataProperties);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef dst = acc_.GetValueIn(gate, 0);
GateRef src = acc_.GetValueIn(gate, 1);
GateRef newGate = LowerCallRuntime(gate, id, { dst, src });
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerCreateObjectWithExcludedKeys(GateRef gate)
{
const int id = RTSTUB_ID(OptCreateObjectWithExcludedKeys);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) >= 2);
size_t numIn = acc_.GetNumValueIn(gate);
std::vector<GateRef> args;
for (size_t idx = 0; idx < numIn; idx++) {
GateRef tmpGate = acc_.GetValueIn(gate, idx);
args.emplace_back(tmpGate);
}
GateRef newGate = LowerCallRuntime(gate, id, args);
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerCreateRegExpWithLiteral(GateRef gate)
{
const int id = RTSTUB_ID(CreateRegExpWithLiteral);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef pattern = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module,
stringId, ConstPoolType::STRING);
GateRef flags = acc_.GetValueIn(gate, 1);
GateRef newGate = LowerCallRuntime(gate, id, { pattern, builder_.ToTaggedInt(flags) }, true);
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerStOwnByValue(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propKey = acc_.GetValueIn(gate, 1);
GateRef accValue = acc_.GetValueIn(gate, 2);
// we do not need to merge outValueGate, so using GateRef directly instead of using Variable
GateRef holeConst = builder_.HoleConstant();
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
result = builder_.CallStub(glue_, gate, CommonStubCSigns::StOwnByValue,
{ glue_, receiver, propKey, accValue });
ReplaceHirWithValue(gate, *result);
}
void SlowPathLowering::LowerStOwnByIndex(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef index = acc_.GetValueIn(gate, 1);
GateRef accValue = acc_.GetValueIn(gate, 2);
// we do not need to merge outValueGate, so using GateRef directly instead of using Variable
GateRef holeConst = builder_.HoleConstant();
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
result = builder_.CallStub(glue_, gate, CommonStubCSigns::StOwnByIndex,
{ glue_, receiver, builder_.TruncInt64ToInt32(index), accValue });
ReplaceHirWithValue(gate, *result);
}
void SlowPathLowering::LowerStOwnByName(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef propKey = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module,
stringId, ConstPoolType::STRING);
GateRef receiver = acc_.GetValueIn(gate, 1);
GateRef accValue = acc_.GetValueIn(gate, 2);
// we do not need to merge outValueGate, so using GateRef directly instead of using Variable
GateRef holeConst = builder_.HoleConstant();
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
result = builder_.CallStub(glue_, gate, CommonStubCSigns::StOwnByName,
{ glue_, receiver, propKey, accValue });
ReplaceHirWithValue(gate, *result);
}
void SlowPathLowering::LowerNewLexicalEnv(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef lexEnv = acc_.GetValueIn(gate, 1);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::NewLexicalEnv,
{ glue_, lexEnv, builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0)) });
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerNewLexicalEnvWithName(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef lexEnv = acc_.GetValueIn(gate, 2); // 2: Get current lexEnv
auto args = { builder_.ToTaggedInt(acc_.GetValueIn(gate, 0)),
builder_.ToTaggedInt(acc_.GetValueIn(gate, 1)),
lexEnv, jsFunc };
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(OptNewLexicalEnvWithName), args, true);
ReplaceHirWithValue(gate, result, true);
}
void SlowPathLowering::LowerNewSendableEnv(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
auto args = { builder_.ToTaggedInt(acc_.GetValueIn(gate, 0)) };
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(NewSendableEnv), args, true);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
builder_.SetSendableEnvToModule(glue_, module, result);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerPopLexicalEnv(GateRef gate)
{
GateRef currentEnv = acc_.GetValueIn(gate, 0);
GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
GateRef parentEnv = builder_.GetValueFromTaggedArray(currentEnv, index);
ReplaceHirWithValue(gate, parentEnv, true);
}
void SlowPathLowering::LowerLdSuperByValue(GateRef gate)
{
const int id = RTSTUB_ID(OptLdSuperByValue);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propKey = acc_.GetValueIn(gate, 1);
GateRef newGate = LowerCallRuntime(gate, id, { receiver, propKey, jsFunc });
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerStSuperByValue(GateRef gate)
{
const int id = RTSTUB_ID(OptStSuperByValue);
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propKey = acc_.GetValueIn(gate, 1);
GateRef value = acc_.GetValueIn(gate, 2);
GateRef newGate = LowerCallRuntime(gate, id, { receiver, propKey, value, jsFunc});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerTryStGlobalByName(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
GateRef value = acc_.GetValueIn(gate, 2); // 2: the 2nd para is value
LowerCallStubWithIC(gate, CommonStubCSigns::TryStGlobalByName, { stringId, value });
}
void SlowPathLowering::LowerStConstToGlobalRecord(GateRef gate, bool isConst)
{
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef propKey = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module,
stringId, ConstPoolType::STRING);
acc_.SetDep(gate, propKey);
// 2 : number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
const int id = RTSTUB_ID(StGlobalRecord);
GateRef value = acc_.GetValueIn(gate, 1);
GateRef isConstGate = isConst ? builder_.TaggedTrue() : builder_.TaggedFalse();
GateRef result = LowerCallRuntime(gate, id, { propKey, value, isConstGate }, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerStOwnByValueWithNameSet(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propKey = acc_.GetValueIn(gate, 1);
GateRef accValue = acc_.GetValueIn(gate, 2);
Label successExit(&builder_);
Label exceptionExit(&builder_);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::StOwnByValueWithNameSet,
{ glue_, receiver, propKey, accValue });
BRANCH_CIR(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
&exceptionExit, &successExit);
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
}
void SlowPathLowering::LowerStOwnByNameWithNameSet(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef propKey = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module,
stringId, ConstPoolType::STRING);
GateRef receiver = acc_.GetValueIn(gate, 1);
GateRef accValue = acc_.GetValueIn(gate, 2);
Label successExit(&builder_);
Label exceptionExit(&builder_);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::StOwnByNameWithNameSet,
{ glue_, receiver, propKey, accValue });
BRANCH_CIR(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
&exceptionExit, &successExit);
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
}
void SlowPathLowering::LowerLdGlobalVar(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
LowerCallStubWithIC(gate, CommonStubCSigns::LdGlobalVar, { stringId });
}
void SlowPathLowering::LowerLdObjByName(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
GateRef receiver = acc_.GetValueIn(gate, 2); // 2: the third parameter
LowerCallStubWithIC(gate, CommonStubCSigns::GetPropertyByName, { receiver, stringId });
}
void SlowPathLowering::LowerStObjByName(GateRef gate, bool isThis)
{
GateRef receiver;
GateRef value;
if (isThis) {
ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: number of value inputs
receiver = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
value = acc_.GetValueIn(gate, 2); // 2: the third para is value
} else {
ASSERT(acc_.GetNumValueIn(gate) == 4); // 4: number of value inputs
receiver = acc_.GetValueIn(gate, 2); // 2: the third para is receiver
value = acc_.GetValueIn(gate, 3); // 3: the 4th para is value
}
GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
LowerCallStubWithIC(gate, CommonStubCSigns::SetPropertyByName, { receiver, stringId, value });
}
void SlowPathLowering::LowerDefineGetterSetterByValue(GateRef gate)
{
const int id = RTSTUB_ID(DefineGetterSetterByValue);
// 5: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 5);
GateRef obj = acc_.GetValueIn(gate, 0);
GateRef prop = acc_.GetValueIn(gate, 1);
GateRef getter = acc_.GetValueIn(gate, 2);
GateRef setter = acc_.GetValueIn(gate, 3);
GateRef acc = acc_.GetValueIn(gate, 4);
auto args = { obj, prop, getter, setter, acc,
builder_.UndefineConstant(), builder_.Int32ToTaggedInt(builder_.Int32(1)) };
GateRef result = LowerCallRuntime(gate, id, args);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerLdObjByIndex(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef holeConst = builder_.HoleConstant();
DEFVALUE(varAcc, (&builder_), VariableType::JS_ANY(), holeConst);
GateRef index = acc_.GetValueIn(gate, 0);
GateRef receiver = acc_.GetValueIn(gate, 1);
varAcc = builder_.CallStub(glue_, gate, CommonStubCSigns::LdObjByIndex,
{glue_, receiver, builder_.TruncInt64ToInt32(index)});
ReplaceHirWithValue(gate, *varAcc);
}
void SlowPathLowering::LowerStObjByIndex(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef index = acc_.GetValueIn(gate, 1);
GateRef accValue = acc_.GetValueIn(gate, 2);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
result = builder_.CallStub(glue_, gate, CommonStubCSigns::StObjByIndex,
{glue_, receiver, builder_.TruncInt64ToInt32(index), accValue});
ReplaceHirWithValue(gate, *result);
}
void SlowPathLowering::LowerLdObjByValue(GateRef gate, bool isThis)
{
GateRef receiver;
GateRef propKey;
if (isThis) {
ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: number of value inputs
receiver = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
propKey = acc_.GetValueIn(gate, 1);
} else {
ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: number of value inputs
receiver = acc_.GetValueIn(gate, 1);
propKey = acc_.GetValueIn(gate, 2); // 2: the third parameter
}
LowerCallStubWithIC(gate, CommonStubCSigns::GetPropertyByValue, { receiver, propKey });
}
void SlowPathLowering::LowerStObjByValue(GateRef gate, bool isThis)
{
GateRef receiver;
GateRef propKey;
GateRef value;
if (isThis) {
ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: number of value inputs
receiver = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
propKey = acc_.GetValueIn(gate, 1);
value = acc_.GetValueIn(gate, 2); // 2: the third parameter
} else {
// 4: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 4);
receiver = acc_.GetValueIn(gate, 1);
propKey = acc_.GetValueIn(gate, 2); // 2: the third parameter
value = acc_.GetValueIn(gate, 3); // 3: the 4th parameter
}
LowerCallStubWithIC(gate, CommonStubCSigns::SetPropertyByValue, { receiver, propKey, value });
}
void SlowPathLowering::LowerLdSuperByName(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef prop = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module, stringId,
ConstPoolType::STRING);
GateRef result =
LowerCallRuntime(gate, RTSTUB_ID(OptLdSuperByValue), {acc_.GetValueIn(gate, 1), prop, jsFunc}, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerStSuperByName(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef prop = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module, stringId,
ConstPoolType::STRING);
auto args2 = { acc_.GetValueIn(gate, 1), prop, acc_.GetValueIn(gate, 2), jsFunc };
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(OptStSuperByValue), args2, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerCreateGeneratorObj(GateRef gate)
{
const int id = RTSTUB_ID(CreateGeneratorObj);
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerCreateAsyncGeneratorObj(GateRef gate)
{
int id = RTSTUB_ID(CreateAsyncGeneratorObj);
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerAsyncGeneratorResolve(GateRef gate)
{
SaveFrameToContext(gate);
acc_.SetDep(gate, builder_.GetDepend());
int id = RTSTUB_ID(OptAsyncGeneratorResolve);
GateRef asyncGen = acc_.GetValueIn(gate, 1);
GateRef value = acc_.GetValueIn(gate, 2);
GateRef flag = acc_.GetValueIn(gate, 3);
GateRef newGate = LowerCallRuntime(gate, id, {asyncGen, value, flag});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerAsyncGeneratorReject(GateRef gate)
{
int id = RTSTUB_ID(AsyncGeneratorReject);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerStArraySpread(GateRef gate)
{
const int id = RTSTUB_ID(StArraySpread);
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
auto args = { acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2) };
GateRef newGate = LowerCallRuntime(gate, id, args);
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerLdLexVar(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 2)); // 2: Get current lexEnv
GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
Label exit(&builder_);
uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
if (constLevel == 0) {
builder_.Jump(&exit);
} else if (constLevel == 1) {
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
builder_.Jump(&exit);
} else {
DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
Label loopHead(&builder_);
Label loopEnd(&builder_);
BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopHead, &exit);
builder_.LoopBegin(&loopHead);
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
i = builder_.Int32Add(*i, builder_.Int32(1));
BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopEnd, &exit);
builder_.Bind(&loopEnd);
builder_.LoopEnd(&loopHead);
}
builder_.Bind(&exit);
GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(LexicalEnv::RESERVED_ENV_LENGTH));
GateRef result = builder_.GetValueFromTaggedArray(*currentEnv, valueIndex);
ReplaceHirWithValue(gate, result, true);
}
void SlowPathLowering::LowerLdSendableVar(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), builder_.GetSendableEnvFromModule(module));
GateRef index = builder_.Int32(SendableEnv::SENDABLE_PARENT_ENV_INDEX);
Label exit(&builder_);
uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
if (constLevel == 0) {
builder_.Jump(&exit);
} else if (constLevel == 1) {
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
builder_.Jump(&exit);
} else {
DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
Label loopHead(&builder_);
Label loopEnd(&builder_);
BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopHead, &exit);
builder_.LoopBegin(&loopHead);
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
i = builder_.Int32Add(*i, builder_.Int32(1));
BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopEnd, &exit);
builder_.Bind(&loopEnd);
builder_.LoopEnd(&loopHead);
}
builder_.Bind(&exit);
GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(SendableEnv::SENDABLE_RESERVED_ENV_LENGTH));
GateRef result = builder_.GetValueFromTaggedArray(*currentEnv, valueIndex);
ReplaceHirWithValue(gate, result, true);
}
void SlowPathLowering::LowerStLexVar(GateRef gate)
{
// 4: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 4);
GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
GateRef value = acc_.GetValueIn(gate, 3);
DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 2)); // 2: Get current lexEnv
GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
Label exit(&builder_);
uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
if (constLevel == 0) {
builder_.Jump(&exit);
} else if (constLevel == 1) {
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
builder_.Jump(&exit);
} else {
DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
Label loopHead(&builder_);
Label loopEnd(&builder_);
BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopHead, &exit);
builder_.LoopBegin(&loopHead);
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
i = builder_.Int32Add(*i, builder_.Int32(1));
BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopEnd, &exit);
builder_.Bind(&loopEnd);
builder_.LoopEnd(&loopHead);
}
builder_.Bind(&exit);
GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(LexicalEnv::RESERVED_ENV_LENGTH));
builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue_, *currentEnv, valueIndex, value);
auto result = *currentEnv;
ReplaceHirWithValue(gate, result, true);
}
void SlowPathLowering::LowerStSendableVar(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
GateRef value = acc_.GetValueIn(gate, 2);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), builder_.GetSendableEnvFromModule(module));
GateRef index = builder_.Int32(SendableEnv::SENDABLE_PARENT_ENV_INDEX);
Label exit(&builder_);
uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
if (constLevel == 0) {
builder_.Jump(&exit);
} else if (constLevel == 1) {
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
builder_.Jump(&exit);
} else {
DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
Label loopHead(&builder_);
Label loopEnd(&builder_);
BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopHead, &exit);
builder_.LoopBegin(&loopHead);
currentEnv = builder_.GetValueFromTaggedArray(*currentEnv, index);
i = builder_.Int32Add(*i, builder_.Int32(1));
BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopEnd, &exit);
builder_.Bind(&loopEnd);
builder_.LoopEnd(&loopHead);
}
builder_.Bind(&exit);
GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(SendableEnv::SENDABLE_RESERVED_ENV_LENGTH));
builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue_, *currentEnv, valueIndex, value);
auto result = *currentEnv;
ReplaceHirWithValue(gate, result, true);
}
void SlowPathLowering::LowerDefineClassWithBuffer(GateRef gate)
{
ASSERT(acc_.GetNumValueIn(gate) == 6); // 6: number of value inputs
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef methodId = acc_.GetValueIn(gate, 0);
GateRef proto = acc_.GetValueIn(gate, 3);
GateRef literalId = acc_.GetValueIn(gate, 1);
GateRef length = acc_.GetValueIn(gate, 2); // 2: second arg
GateRef lexicalEnv = acc_.GetValueIn(gate, 4); // 4: Get current env
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
Label isException(&builder_);
Label isNotException(&builder_);
GateRef result;
auto args = { proto, lexicalEnv, sharedConstPool,
builder_.ToTaggedInt(methodId), builder_.ToTaggedInt(literalId), module,
builder_.ToTaggedInt(length),
#if ECMASCRIPT_ENABLE_IC
// 5: slot id
builder_.Int32ToTaggedInt(builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 5))), jsFunc
#endif
};
result = LowerCallRuntime(gate, RTSTUB_ID(CreateClassWithBuffer), args, true);
BRANCH_CIR(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION), &isException, &isNotException);
CREATE_DOUBLE_EXIT(isNotException, isException)
acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, result);
}
void SlowPathLowering::LowerDefineFunc(GateRef gate)
{
Jit::JitLockHolder lock(compilationEnv_, "SlowPathLowering");
Environment env(gate, circuit_, &builder_);
GateRef methodId = acc_.GetValueIn(gate, 1);
FunctionKind kind = FunctionKind::LAST_FUNCTION_KIND;
if (acc_.IsConstantNumber(methodId)) {
// try to speed up the kind checking
JSTaggedValue unsharedCp;
if (compilationEnv_->IsJitCompiler()) {
unsharedCp = compilationEnv_->FindConstpool(compilationEnv_->GetJSPandaFile(), 0);
} else {
auto methodOffset = acc_.TryGetMethodOffset(gate);
unsharedCp = compilationEnv_->FindOrCreateUnsharedConstpool(methodOffset);
}
auto obj = compilationEnv_->GetMethodFromCache(unsharedCp, acc_.GetConstantValue(methodId));
if (obj != JSTaggedValue::Undefined()) {
kind = Method::Cast(obj)->GetFunctionKind();
}
}
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef length = acc_.GetValueIn(gate, 2);
GateRef lexEnv = acc_.GetValueIn(gate, 3); // 3: Get current env
GateRef slotId = acc_.GetValueIn(gate, 0);
Label success(&builder_);
Label failed(&builder_);
GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Definefunc,
{glue_, jsFunc, builder_.TruncInt64ToInt32(methodId), builder_.TruncInt64ToInt32(length), lexEnv, slotId});
BRANCH_CIR(builder_.TaggedIsException(result), &failed, &success);
CREATE_DOUBLE_EXIT(success, failed)
acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, result);
}
void SlowPathLowering::LowerAsyncFunctionEnter(GateRef gate)
{
const int id = RTSTUB_ID(AsyncFunctionEnter);
// 0: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 0);
GateRef newGate = LowerCallRuntime(gate, id, {});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerTypeof(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef obj = acc_.GetValueIn(gate, 0);
Label entry(&builder_);
Label exit(&builder_);
GateRef gConstAddr = builder_.Load(VariableType::JS_POINTER(), glue_,
builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(builder_.GetCompilationConfig()->Is32Bit())));
GateRef undefinedIndex = builder_.GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX);
GateRef gConstUndefinedStr = builder_.Load(VariableType::JS_POINTER(), gConstAddr, undefinedIndex);
DEFVALUE(result, (&builder_), VariableType::JS_POINTER(), gConstUndefinedStr);
Label objIsTrue(&builder_);
Label objNotTrue(&builder_);
Label defaultLabel(&builder_);
GateRef gConstBooleanStr = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
builder_.GetGlobalConstantOffset(ConstantIndex::BOOLEAN_STRING_INDEX));
BRANCH_CIR(builder_.TaggedIsTrue(obj), &objIsTrue, &objNotTrue);
builder_.Bind(&objIsTrue);
{
result = gConstBooleanStr;
builder_.Jump(&exit);
}
builder_.Bind(&objNotTrue);
{
Label objIsFalse(&builder_);
Label objNotFalse(&builder_);
BRANCH_CIR(builder_.TaggedIsFalse(obj), &objIsFalse, &objNotFalse);
builder_.Bind(&objIsFalse);
{
result = gConstBooleanStr;
builder_.Jump(&exit);
}
builder_.Bind(&objNotFalse);
{
Label objIsNull(&builder_);
Label objNotNull(&builder_);
BRANCH_CIR(builder_.TaggedIsNull(obj), &objIsNull, &objNotNull);
builder_.Bind(&objIsNull);
{
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
builder_.GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX));
builder_.Jump(&exit);
}
builder_.Bind(&objNotNull);
{
Label objIsUndefined(&builder_);
Label objNotUndefined(&builder_);
BRANCH_CIR(builder_.TaggedIsUndefined(obj), &objIsUndefined, &objNotUndefined);
builder_.Bind(&objIsUndefined);
{
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
builder_.GetGlobalConstantOffset(ConstantIndex::UNDEFINED_STRING_INDEX));
builder_.Jump(&exit);
}
builder_.Bind(&objNotUndefined);
builder_.Jump(&defaultLabel);
}
}
}
builder_.Bind(&defaultLabel);
{
Label objIsHeapObject(&builder_);
Label objNotHeapObject(&builder_);
BRANCH_CIR(builder_.TaggedIsHeapObject(obj), &objIsHeapObject, &objNotHeapObject);
builder_.Bind(&objIsHeapObject);
{
Label objIsString(&builder_);
Label objNotString(&builder_);
BRANCH_CIR(builder_.TaggedObjectIsString(obj), &objIsString, &objNotString);
builder_.Bind(&objIsString);
{
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
builder_.GetGlobalConstantOffset(ConstantIndex::STRING_STRING_INDEX));
builder_.Jump(&exit);
}
builder_.Bind(&objNotString);
{
Label objIsSymbol(&builder_);
Label objNotSymbol(&builder_);
BRANCH_CIR(builder_.IsJsType(obj, JSType::SYMBOL), &objIsSymbol, &objNotSymbol);
builder_.Bind(&objIsSymbol);
{
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
builder_.GetGlobalConstantOffset(ConstantIndex::SYMBOL_STRING_INDEX));
builder_.Jump(&exit);
}
builder_.Bind(&objNotSymbol);
{
Label objIsCallable(&builder_);
Label objNotCallable(&builder_);
BRANCH_CIR(builder_.IsCallable(obj), &objIsCallable, &objNotCallable);
builder_.Bind(&objIsCallable);
{
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
builder_.GetGlobalConstantOffset(ConstantIndex::FUNCTION_STRING_INDEX));
builder_.Jump(&exit);
}
builder_.Bind(&objNotCallable);
{
Label objIsBigInt(&builder_);
Label objNotBigInt(&builder_);
BRANCH_CIR(builder_.IsJsType(obj, JSType::BIGINT), &objIsBigInt, &objNotBigInt);
builder_.Bind(&objIsBigInt);
{
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
builder_.GetGlobalConstantOffset(ConstantIndex::BIGINT_STRING_INDEX));
builder_.Jump(&exit);
}
builder_.Bind(&objNotBigInt);
{
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
builder_.GetGlobalConstantOffset(ConstantIndex::OBJECT_STRING_INDEX));
builder_.Jump(&exit);
}
}
}
}
}
builder_.Bind(&objNotHeapObject);
{
Label objIsNum(&builder_);
Label objNotNum(&builder_);
BRANCH_CIR(builder_.TaggedIsNumber(obj), &objIsNum, &objNotNum);
builder_.Bind(&objIsNum);
{
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
builder_.GetGlobalConstantOffset(ConstantIndex::NUMBER_STRING_INDEX));
builder_.Jump(&exit);
}
builder_.Bind(&objNotNum);
builder_.Jump(&exit);
}
}
builder_.Bind(&exit);
ReplaceHirWithValue(gate, *result, true);
}
GateRef SlowPathLowering::GetValueFromTaggedArray(GateRef arrayGate, GateRef indexOffset)
{
GateRef offset = builder_.PtrMul(builder_.ZExtInt32ToPtr(indexOffset),
builder_.IntPtr(JSTaggedValue::TaggedTypeSize()));
GateRef dataOffset = builder_.PtrAdd(offset, builder_.IntPtr(TaggedArray::DATA_OFFSET));
GateRef value = builder_.Load(VariableType::JS_ANY(), arrayGate, dataOffset);
return value;
}
void SlowPathLowering::LowerStoreRegister(GateRef gate, GateRef arrayGate)
{
ASSERT((acc_.GetOpCode(gate) == OpCode::RESTORE_REGISTER));
auto index = acc_.GetVirtualRegisterIndex(gate);
auto indexOffset = builder_.Int32(index);
GateRef value = GetValueFromTaggedArray(arrayGate, indexOffset);
acc_.ReplaceGate(gate, Circuit::NullGate(), Circuit::NullGate(), value);
}
void SlowPathLowering::LowerResumeGenerator(GateRef gate)
{
GateRef obj = acc_.GetValueIn(gate, 0);
std::vector<GateRef> registerGates {};
AddProfiling(gate, false);
GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
GateRef contextGate = builder_.Load(VariableType::JS_POINTER(), obj, contextOffset);
GateRef arrayOffset = builder_.IntPtr(GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET);
GateRef arrayGate = builder_.Load(VariableType::JS_POINTER(), contextGate, arrayOffset);
auto uses = acc_.Uses(gate);
for (auto it = uses.begin(); it != uses.end(); it++) {
if (acc_.IsValueIn(it) && acc_.GetOpCode(*it) == OpCode::RESTORE_REGISTER) {
registerGates.emplace_back(*it);
}
}
for (auto item : registerGates) {
LowerStoreRegister(item, arrayGate);
}
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
Label isAsyncGeneratorObj(&builder_);
Label notAsyncGeneratorObj(&builder_);
Label exit(&builder_);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
BRANCH_CIR(builder_.TaggedIsAsyncGeneratorObject(obj), &isAsyncGeneratorObj, &notAsyncGeneratorObj);
builder_.Bind(&isAsyncGeneratorObj);
{
GateRef resumeResultOffset = builder_.IntPtr(JSAsyncGeneratorObject::GENERATOR_RESUME_RESULT_OFFSET);
result = builder_.Load(VariableType::JS_ANY(), obj, resumeResultOffset);
builder_.Jump(&exit);
}
builder_.Bind(&notAsyncGeneratorObj);
{
GateRef resumeResultOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_RESUME_RESULT_OFFSET);
result = builder_.Load(VariableType::JS_ANY(), obj, resumeResultOffset);
GateRef taskInfoOffset = builder_.IntPtr(JSGeneratorObject::TASK_INFO_OFFSET);
GateRef taskInfo = builder_.Load(VariableType::NATIVE_POINTER(), obj, taskInfoOffset);
GateRef glueTaskOffset =
builder_.IntPtr(JSThread::GlueData::GetTaskInfoOffset(builder_.GetCompilationConfig()->Is32Bit()));
builder_.Store(VariableType::NATIVE_POINTER(), glue_, glue_, glueTaskOffset, taskInfo);
builder_.Store(VariableType::NATIVE_POINTER(), glue_, obj, taskInfoOffset, builder_.IntPtr(0));
builder_.Jump(&exit);
}
builder_.Bind(&exit);
ReplaceHirWithValue(gate, *result, true);
}
void SlowPathLowering::LowerGetResumeMode(GateRef gate)
{
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label isAsyncGeneratorObj(&builder_);
Label notAsyncGeneratorObj(&builder_);
Label exit(&builder_);
GateRef obj = acc_.GetValueIn(gate, 0);
BRANCH_CIR(builder_.TaggedIsAsyncGeneratorObject(obj), &isAsyncGeneratorObj, &notAsyncGeneratorObj);
builder_.Bind(&isAsyncGeneratorObj);
{
GateRef bitFieldOffset = builder_.IntPtr(JSAsyncGeneratorObject::BIT_FIELD_OFFSET);
GateRef bitField = builder_.Load(VariableType::INT32(), obj, bitFieldOffset);
auto bitfieldlsr = builder_.Int32LSR(bitField,
builder_.Int32(JSAsyncGeneratorObject::ResumeModeBits::START_BIT));
GateRef modeBits = builder_.Int32And(bitfieldlsr,
builder_.Int32((1LU << JSAsyncGeneratorObject::ResumeModeBits::SIZE) - 1));
auto resumeMode = builder_.SExtInt32ToInt64(modeBits);
result = builder_.ToTaggedIntPtr(resumeMode);
builder_.Jump(&exit);
}
builder_.Bind(&notAsyncGeneratorObj);
{
GateRef bitFieldOffset = builder_.IntPtr(JSGeneratorObject::BIT_FIELD_OFFSET);
GateRef bitField = builder_.Load(VariableType::INT32(), obj, bitFieldOffset);
auto bitfieldlsr = builder_.Int32LSR(bitField, builder_.Int32(JSGeneratorObject::ResumeModeBits::START_BIT));
GateRef modeBits = builder_.Int32And(bitfieldlsr,
builder_.Int32((1LU << JSGeneratorObject::ResumeModeBits::SIZE) - 1));
auto resumeMode = builder_.SExtInt32ToInt64(modeBits);
result = builder_.ToTaggedIntPtr(resumeMode);
builder_.Jump(&exit);
}
builder_.Bind(&exit);
ReplaceHirWithValue(gate, *result, true);
}
void SlowPathLowering::LowerDefineMethod(GateRef gate)
{
// 5: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 5);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef methodId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef module = builder_.GetModuleFromFunction(jsFunc);
auto method = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module, methodId,
ConstPoolType::METHOD);
GateRef length = acc_.GetValueIn(gate, 1);
GateRef env = acc_.GetValueIn(gate, 2); // 2: Get current env
GateRef homeObject = acc_.GetValueIn(gate, 4); // 4: homeObject
Label defaultLabel(&builder_);
Label successExit(&builder_);
Label exceptionExit(&builder_);
auto args = {method, homeObject, builder_.ToTaggedInt(length), env, builder_.GetModuleFromFunction(jsFunc),
#if ECMASCRIPT_ENABLE_IC
builder_.Int32ToTaggedInt(builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 3))), jsFunc // 3: slot id
#endif
};
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(DefineMethod), args, true);
BRANCH_CIR(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
&exceptionExit, &successExit);
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, result);
}
void SlowPathLowering::LowerGetUnmappedArgs(GateRef gate)
{
GateRef actualArgc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGC);
GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::GetUnmappedArgs,
{ glue_, builder_.IntPtr(0), builder_.TruncInt64ToInt32(actualArgc), builder_.Undefined() });
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerCopyRestArgs(GateRef gate)
{
GateRef actualArgc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGC);
GateRef taggedArgc = builder_.ToTaggedInt(actualArgc);
GateRef restIdx = acc_.GetValueIn(gate, 0);
GateRef taggedRestIdx = builder_.ToTaggedInt(restIdx);
const int id = RTSTUB_ID(OptCopyRestArgs);
GateRef newGate = LowerCallRuntime(gate, id, {taggedArgc, taggedRestIdx});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerWideLdPatchVar(GateRef gate)
{
const int id = RTSTUB_ID(LdPatchVar);
GateRef index = acc_.GetValueIn(gate, 0);
GateRef newGate = LowerCallRuntime(gate, id, {builder_.ToTaggedInt(index)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerWideStPatchVar(GateRef gate)
{
const int id = RTSTUB_ID(StPatchVar);
GateRef index = acc_.GetValueIn(gate, 0);
GateRef newGate = LowerCallRuntime(gate, id, {builder_.ToTaggedInt(index)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::AddProfiling(GateRef gate, bool skipGenerator)
{
if (IsTraceBC()) {
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
if ((ecmaOpcode == EcmaOpcode::SUSPENDGENERATOR_V8 || ecmaOpcode == EcmaOpcode::RESUMEGENERATOR) &&
skipGenerator) {
return;
}
auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
GateRef constOpcode = builder_.ToTaggedInt(builder_.ZExtInt32ToInt64(ecmaOpcodeGate));
GateRef slowPath = builder_.Int32ToTaggedInt(builder_.Int32(0));
GateRef debugGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(gate),
{ constOpcode, slowPath }, gate);
acc_.SetDep(gate, debugGate);
}
if (IsProfiling()) {
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
if ((ecmaOpcode == EcmaOpcode::SUSPENDGENERATOR_V8 || ecmaOpcode == EcmaOpcode::RESUMEGENERATOR) &&
skipGenerator) {
return;
}
GateRef func = builder_.Undefined();
if (acc_.HasFrameState(gate)) {
func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
}
GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
GateRef mode =
builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::SLOW_PATH)));
GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(gate),
{ func, bcIndex, constOpcode, mode }, gate);
acc_.SetDep(gate, profiling);
}
}
void SlowPathLowering::LowerCallthis0Imm8V8(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLTHIS0_IMM8_V8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef newTarget = builder_.Undefined();
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef func = acc_.GetValueIn(gate, 1);
LowerToJSCall(gate, {glue_, actualArgc, actualArgv, func, newTarget, thisObj}, {glue_, func, thisObj});
}
void SlowPathLowering::LowerCallArg1Imm8V8(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLARG1_IMM8_V8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef newTarget = builder_.Undefined();
GateRef a0Value = acc_.GetValueIn(gate, 0);
GateRef thisObj = builder_.Undefined();
GateRef func = acc_.GetValueIn(gate, 1); // acc
LowerToJSCall(gate, {glue_, actualArgc, actualArgv, func, newTarget, thisObj, a0Value},
{glue_, func, thisObj, a0Value});
}
void SlowPathLowering::LowerWideCallrangePrefImm16V8(GateRef gate)
{
std::vector<GateRef> vec;
std::vector<GateRef> vec1;
size_t numIns = acc_.GetNumValueIn(gate);
size_t fixedInputsNum = 1; // 1: acc
ASSERT(acc_.GetNumValueIn(gate) >= fixedInputsNum);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef callTarget = acc_.GetValueIn(gate, numIns - fixedInputsNum); // acc
GateRef newTarget = builder_.Undefined();
GateRef thisObj = builder_.Undefined();
vec.emplace_back(glue_);
vec.emplace_back(actualArgc);
vec.emplace_back(actualArgv);
vec.emplace_back(callTarget);
vec.emplace_back(newTarget);
vec.emplace_back(thisObj);
// add args
for (size_t i = 0; i < numIns - fixedInputsNum; i++) { // skip acc
vec.emplace_back(acc_.GetValueIn(gate, i));
}
vec.emplace_back(glue_);
vec.emplace_back(callTarget);
vec.emplace_back(thisObj);
// add args
for (size_t i = 0; i < numIns - fixedInputsNum; i++) { // skip acc
vec.emplace_back(acc_.GetValueIn(gate, i));
}
LowerToJSCall(gate, vec, vec1);
}
void SlowPathLowering::LowerCallThisArg1(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef newTarget = builder_.Undefined();
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef a0 = acc_.GetValueIn(gate, 1); // 1:first parameter
GateRef func = acc_.GetValueIn(gate, 2); // 2:function
LowerToJSCall(gate, {glue_, actualArgc, actualArgv, func, newTarget, thisObj, a0}, {glue_, func, thisObj, a0});
}
void SlowPathLowering::LowerCallargs2Imm8V8V8(GateRef gate)
{
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLARGS2_IMM8_V8_V8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef newTarget = builder_.Undefined();
GateRef thisObj = builder_.Undefined();
GateRef a0 = acc_.GetValueIn(gate, 0);
GateRef a1 = acc_.GetValueIn(gate, 1); // 1:first parameter
GateRef func = acc_.GetValueIn(gate, 2); // 2:function
LowerToJSCall(gate, {glue_, actualArgc, actualArgv, func, newTarget, thisObj, a0, a1},
{glue_, func, thisObj, a0, a1});
}
void SlowPathLowering::LowerCallargs3Imm8V8V8(GateRef gate)
{
// 4: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 4);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef newTarget = builder_.Undefined();
GateRef thisObj = builder_.Undefined();
GateRef a0 = acc_.GetValueIn(gate, 0);
GateRef a1 = acc_.GetValueIn(gate, 1);
GateRef a2 = acc_.GetValueIn(gate, 2);
GateRef func = acc_.GetValueIn(gate, 3);
LowerToJSCall(gate, {glue_, actualArgc, actualArgv, func, newTarget, thisObj, a0, a1, a2},
{glue_, func, thisObj, a0, a1, a2});
}
void SlowPathLowering::LowerCallthis2Imm8V8V8V8(GateRef gate)
{
// 4: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 4);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef newTarget = builder_.Undefined();
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef a0Value = acc_.GetValueIn(gate, 1);
GateRef a1Value = acc_.GetValueIn(gate, 2);
GateRef func = acc_.GetValueIn(gate, 3); //acc
LowerToJSCall(gate, {glue_, actualArgc, actualArgv, func, newTarget, thisObj, a0Value, a1Value},
{glue_, func, thisObj, a0Value, a1Value});
}
void SlowPathLowering::LowerCallthis3Imm8V8V8V8V8(GateRef gate)
{
// 5: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 5);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef newTarget = builder_.Undefined();
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef a0Value = acc_.GetValueIn(gate, 1);
GateRef a1Value = acc_.GetValueIn(gate, 2);
GateRef a2Value = acc_.GetValueIn(gate, 3);
GateRef func = acc_.GetValueIn(gate, 4);
LowerToJSCall(gate, {glue_, actualArgc, actualArgv, func, newTarget, thisObj, a0Value, a1Value, a2Value},
{glue_, func, thisObj, a0Value, a1Value, a2Value});
}
void SlowPathLowering::LowerLdThisByName(GateRef gate)
{
ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: number of parameter
GateRef thisObj = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
GateRef prop = acc_.GetValueIn(gate, 1); // 1: the second parameter
LowerCallStubWithIC(gate, CommonStubCSigns::GetPropertyByName, { thisObj, prop });
}
bool SlowPathLowering::IsFastCallArgs(size_t index)
{
return index != static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC) &&
index != static_cast<size_t>(CommonArgIdx::ACTUAL_ARGV) &&
index != static_cast<size_t>(CommonArgIdx::NEW_TARGET);
}
void SlowPathLowering::LowerConstruct(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
size_t num = acc_.GetNumValueIn(gate);
std::vector<GateRef> args(num);
for (size_t i = 0; i < num; ++i) {
args[i] = acc_.GetValueIn(gate, i);
}
ASSERT(num >= 3); // 3: skip argc argv newtarget
std::vector<GateRef> argsFastCall(num - 3); // 3: skip argc argv newtarget
size_t j = 0;
for (size_t i = 0; i < num; ++i) {
if (IsFastCallArgs(i)) {
argsFastCall[j++] = acc_.GetValueIn(gate, i);
}
}
GateRef ctor = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
GateRef argc = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC));
Label exit(&builder_);
DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
LowerFastCall(gate, glue_, ctor, argc, args, argsFastCall, &res, &exit, true);
builder_.Bind(&exit);
GateRef thisObj = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::THIS_OBJECT));
GateRef result = builder_.CallStub(
glue_, gate, CommonStubCSigns::ConstructorCheck, { glue_, ctor, *res, thisObj });
GateRef state = builder_.GetState();
ReplaceHirWithPendingException(gate, state, result, result);
}
void SlowPathLowering::LowerCallInternal(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
size_t num = acc_.GetNumValueIn(gate);
std::vector<GateRef> args(num);
for (size_t i = 0; i < num; ++i) {
args[i] = acc_.GetValueIn(gate, i);
}
ASSERT(num >= 3); // 3:skip argc argv newtarget
std::vector<GateRef> argsFastCall(num - 3); // 3:skip argc argv newtarget
size_t j = 0;
for (size_t i = 0; i < num; ++i) {
if (IsFastCallArgs(i)) { // 1: argc index 3: newtarget index 2:ActualArgv
argsFastCall[j++] = acc_.GetValueIn(gate, i);
}
}
GateRef func = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
GateRef argc = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC));
Label exit(&builder_);
DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
LowerFastCall(gate, glue_, func, argc, args, argsFastCall, &res, &exit, false);
builder_.Bind(&exit);
GateRef stateInGate = builder_.GetState();
GateRef depend = builder_.GetDepend();
ReplaceHirWithPendingException(gate, stateInGate, depend, *res);
}
void SlowPathLowering::LowerCallNew(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
size_t num = acc_.GetNumValueIn(gate);
bool needPushArgv = acc_.NeedPushArgv(gate);
std::vector<GateRef> args(num);
for (size_t i = 0; i < num; ++i) {
args[i] = acc_.GetValueIn(gate, i);
}
ASSERT(num >= 3); // 3:skip argc argv newtarget
std::vector<GateRef> argsFastCall(num - 3); // 3:skip argc argv newtarget
size_t j = 0;
for (size_t i = 0; i < num; ++i) {
if (IsFastCallArgs(i)) {
argsFastCall[j++] = acc_.GetValueIn(gate, i);
}
}
GateRef ctor = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
Label exit(&builder_);
DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
LowerNewFastCall(gate, glue_, ctor, needPushArgv, args, argsFastCall, &res, &exit);
builder_.Bind(&exit);
GateRef thisObj = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::THIS_OBJECT));
GateRef result = builder_.CallStub(
glue_, gate, CommonStubCSigns::ConstructorCheck, { glue_, ctor, *res, thisObj });
GateRef state = builder_.GetState();
ReplaceHirWithPendingException(gate, state, result, result);
}
void SlowPathLowering::LowerNewFastCall(GateRef gate, GateRef glue, GateRef func,
bool needPushArgv, const std::vector<GateRef> &args,
const std::vector<GateRef> &argsFastCall, Variable *result, Label *exit)
{
Label fastCall(&builder_);
Label notFastCall(&builder_);
Label slowCall(&builder_);
Label slowPath(&builder_);
BRANCH_CIR(builder_.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT_FASTCALL),
&fastCall, &notFastCall);
builder_.Bind(&fastCall);
{
if (!needPushArgv) {
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);
} else {
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(&notFastCall);
BRANCH_CIR(builder_.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT),
&slowCall, &slowPath);
builder_.Bind(&slowCall);
{
if (!needPushArgv) {
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);
} else {
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);
}
}
builder_.Bind(&slowPath);
{
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);
}
}
void SlowPathLowering::LowerFastCall(GateRef gate, GateRef glue, GateRef func, GateRef argc,
const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall,
Variable *result, Label *exit, bool isNew)
{
Label isHeapObject(&builder_);
Label isJsFcuntion(&builder_);
Label fastCall(&builder_);
Label notFastCall(&builder_);
Label call(&builder_);
Label call1(&builder_);
Label slowCall(&builder_);
Label callBridge(&builder_);
Label callBridge1(&builder_);
Label slowPath(&builder_);
Label notCallConstructor(&builder_);
Label isCallConstructor(&builder_);
BRANCH_CIR(builder_.TaggedIsHeapObject(func), &isHeapObject, &slowPath);
builder_.Bind(&isHeapObject);
{
BRANCH_CIR(builder_.IsJSFunction(func), &isJsFcuntion, &slowPath);
builder_.Bind(&isJsFcuntion);
{
if (!isNew) {
BRANCH_CIR(builder_.IsClassConstructor(func), &slowPath, &notCallConstructor);
builder_.Bind(&notCallConstructor);
}
GateRef method = builder_.GetMethodFromFunction(func);
BRANCH_CIR(builder_.JudgeAotAndFastCall(func,
CircuitBuilder::JudgeMethodType::HAS_AOT_FASTCALL), &fastCall, &notFastCall);
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(&notFastCall);
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);
}
}
}
}
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);
}
}
}
void SlowPathLowering::LowerTypedCall(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef func = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
GateRef code = builder_.GetCodeAddr(func);
size_t num = acc_.GetNumValueIn(gate);
std::vector<GateRef> args(num);
for (size_t i = 0; i < num; ++i) {
args[i] = acc_.GetValueIn(gate, i);
}
GateRef state = builder_.GetState();
auto depend = builder_.GetDepend();
const CallSignature *cs = RuntimeStubCSigns::GetOptimizedCallSign();
GateRef result = builder_.Call(cs, glue_, code, depend, args, gate, "callAOT");
ReplaceHirWithPendingException(gate, state, result, result);
}
void SlowPathLowering::LowerTypedFastCall(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef func = acc_.GetValueIn(gate, static_cast<size_t>(FastCallArgIdx::FUNC));
GateRef code = builder_.GetCodeAddr(func);
size_t num = acc_.GetNumValueIn(gate);
std::vector<GateRef> args(num);
for (size_t i = 0; i < num; ++i) {
args[i] = acc_.GetValueIn(gate, i);
}
GateRef state = builder_.GetState();
auto depend = builder_.GetDepend();
const CallSignature *cs = RuntimeStubCSigns::GetOptimizedFastCallSign();
GateRef result = builder_.Call(cs, glue_, code, depend, args, gate, "callFastAOT");
ReplaceHirWithPendingException(gate, state, result, result);
}
void SlowPathLowering::LowerCheckSafePointAndStackOver(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
Label slowPath(&builder_);
Label dispatch(&builder_);
Label checkStackOver(&builder_);
Label stackOverflow(&builder_);
GateRef stackLimit = builder_.Load(VariableType::INT64(), glue_,
builder_.IntPtr(JSThread::GlueData::GetStackLimitOffset(builder_.GetCompilationConfig()->Is32Bit())));
GateRef interruptsFlag = builder_.Load(VariableType::INT8(), glue_,
builder_.IntPtr(JSThread::GlueData::GetInterruptVectorOffset(builder_.GetCompilationConfig()->Is32Bit())));
GateRef spValue = builder_.ReadSp();
builder_.Branch(builder_.Int8Equal(interruptsFlag, builder_.Int8(VmThreadControl::VM_NEED_SUSPENSION)),
&slowPath, &checkStackOver, BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "checkSafePoint");
builder_.Bind(&slowPath);
{
LowerCallRuntime(glue_, RTSTUB_ID(CheckSafePoint), {}, true);
builder_.Jump(&checkStackOver);
}
builder_.Bind(&checkStackOver);
{
builder_.Branch(builder_.Int64LessThanOrEqual(spValue, stackLimit), &stackOverflow, &dispatch,
BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "checkStackOverflow");
builder_.Bind(&stackOverflow);
{
GateRef res = LowerCallRuntime(glue_, RTSTUB_ID(ThrowStackOverflowException), {}, true);
builder_.Return(res);
}
}
builder_.Bind(&dispatch);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void SlowPathLowering::LowerLdPrivateProperty(GateRef gate)
{
const int id = RTSTUB_ID(LdPrivateProperty);
// 5: number of value inputs + env + acc
ASSERT(acc_.GetNumValueIn(gate) == 5);
[[maybe_unused]] GateRef slotId = acc_.GetValueIn(gate, 0);
GateRef levelIndex = acc_.GetValueIn(gate, 1);
GateRef slotIndex = acc_.GetValueIn(gate, 2);
GateRef lexicalEnv = acc_.GetValueIn(gate, 3);
GateRef obj = acc_.GetValueIn(gate, 4); // acc
GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
builder_.ToTaggedInt(levelIndex), builder_.ToTaggedInt(slotIndex), obj});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerStPrivateProperty(GateRef gate)
{
const int id = RTSTUB_ID(StPrivateProperty);
// 6: number of value inputs + env + acc
ASSERT(acc_.GetNumValueIn(gate) == 6);
[[maybe_unused]] GateRef slotId = acc_.GetValueIn(gate, 0);
GateRef levelIndex = acc_.GetValueIn(gate, 1);
GateRef slotIndex = acc_.GetValueIn(gate, 2);
GateRef obj = acc_.GetValueIn(gate, 3);
GateRef lexicalEnv = acc_.GetValueIn(gate, 4);
GateRef value = acc_.GetValueIn(gate, 5); // acc
GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
builder_.ToTaggedInt(levelIndex), builder_.ToTaggedInt(slotIndex), obj, value});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerTestIn(GateRef gate)
{
const int id = RTSTUB_ID(TestIn);
// 5: number of value inputs + acc
ASSERT(acc_.GetNumValueIn(gate) == 5);
[[maybe_unused]] GateRef slotId = acc_.GetValueIn(gate, 0);
GateRef levelIndex = acc_.GetValueIn(gate, 1);
GateRef slotIndex = acc_.GetValueIn(gate, 2);
GateRef lexicalEnv = acc_.GetValueIn(gate, 3);
GateRef obj = acc_.GetValueIn(gate, 4); // acc
GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
builder_.ToTaggedInt(levelIndex), builder_.ToTaggedInt(slotIndex), obj});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerNotifyConcurrentResult(GateRef gate)
{
const int id = RTSTUB_ID(NotifyConcurrentResult);
GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0),
argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC)});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerDefineFieldByName(GateRef gate)
{
// 4: number of value inputs + acc
ASSERT(acc_.GetNumValueIn(gate) == 4);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
GateRef obj = acc_.GetValueIn(gate, 2);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef propKey = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module,
stringId, ConstPoolType::STRING);
GateRef value = acc_.GetValueIn(gate, 3); // acc
GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::DefineField,
{glue_, obj, propKey, value});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerDefineFieldByValue(GateRef gate)
{
// 3: number of value inputs + acc
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef obj = acc_.GetValueIn(gate, 1);
GateRef propKey = acc_.GetValueIn(gate, 0);
GateRef value = acc_.GetValueIn(gate, 2); // acc
GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::DefineField,
{glue_, obj, propKey, value});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerDefineFieldByIndex(GateRef gate)
{
// 3: number of value inputs + acc
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef obj = acc_.GetValueIn(gate, 1);
GateRef propKey = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
GateRef value = acc_.GetValueIn(gate, 2); // acc
GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::DefineField,
{glue_, obj, propKey, value});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerToPropertyKey(GateRef gate)
{
const int id = RTSTUB_ID(ToPropertyKey);
// 1: number of acc
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef value = acc_.GetValueIn(gate, 0); // acc
GateRef newGate = LowerCallRuntime(gate, id, {value});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerCreatePrivateProperty(GateRef gate)
{
const int id = RTSTUB_ID(CreatePrivateProperty);
// 3: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 3);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef count = acc_.GetValueIn(gate, 0);
GateRef literalId = acc_.GetValueIn(gate, 1);
GateRef lexicalEnv = acc_.GetValueIn(gate, 2);
GateRef constpool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
builder_.ToTaggedInt(count), constpool, builder_.ToTaggedInt(literalId), module});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerDefinePrivateProperty(GateRef gate)
{
const int id = RTSTUB_ID(DefinePrivateProperty);
// 5: number of value inputs + acc
ASSERT(acc_.GetNumValueIn(gate) == 5);
GateRef levelIndex = acc_.GetValueIn(gate, 0);
GateRef slotIndex = acc_.GetValueIn(gate, 1);
GateRef obj = acc_.GetValueIn(gate, 2);
GateRef lexicalEnv = acc_.GetValueIn(gate, 3);
GateRef value = acc_.GetValueIn(gate, 4); // acc
GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
builder_.ToTaggedInt(levelIndex), builder_.ToTaggedInt(slotIndex), obj, value});
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerDefineSendableClass(GateRef gate)
{
// 4: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 4);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef methodId = acc_.GetValueIn(gate, 0);
GateRef literalId = acc_.GetValueIn(gate, 1);
GateRef length = acc_.GetValueIn(gate, 2); // 2: second arg
GateRef proto = acc_.GetValueIn(gate, 3);
GateRef constpool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
auto args = { proto, constpool, builder_.ToTaggedInt(methodId), builder_.ToTaggedInt(literalId),
builder_.ToTaggedInt(length), module };
GateRef newGate = LowerCallRuntime(gate, RTSTUB_ID(CreateSharedClass), args);
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerLdSendableClass(GateRef gate)
{
GateRef level = acc_.GetValueIn(gate, 0);
GateRef lexicalEnv = acc_.GetValueIn(gate, 1);
GateRef newGate = LowerCallRuntime(gate, RTSTUB_ID(LdSendableClass), { lexicalEnv, builder_.ToTaggedInt(level) });
ReplaceHirWithValue(gate, newGate);
}
void SlowPathLowering::LowerSendableExternalModule(GateRef gate)
{
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
GateRef result = LowerCallRuntime(gate,
RTSTUB_ID(LdSendableExternalModuleVarByIndex), {index, jsFunc}, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerCallInit(GateRef gate)
{
// same as callthis0
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
EcmaOpcode::CALLTHIS0_IMM8_V8));
GateRef actualArgv = builder_.IntPtr(0);
GateRef newTarget = builder_.Undefined();
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef func = acc_.GetValueIn(gate, 1);
LowerToJSCall(gate, {glue_, actualArgc, actualArgv, func, newTarget, thisObj}, {glue_, func, thisObj});
}
void SlowPathLowering::LowerLdStr(GateRef gate)
{
GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef sharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
GateRef res = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, Circuit::NullGate(), module, stringId,
ConstPoolType::STRING);
ReplaceHirWithValue(gate, res);
}
void SlowPathLowering::LowerGetSharedConstPool(GateRef gate)
{
bool useConstPool = false;
auto uses = acc_.Uses(gate);
for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
if (acc_.GetOpCode(*useIt) != OpCode::FRAME_ARGS) {
useConstPool = true;
break;
}
}
if (!useConstPool) {
acc_.UpdateAllUses(gate, builder_.Undefined());
acc_.DeleteGate(gate);
return;
}
GateRef jsFunc = acc_.GetValueIn(gate, 0);
GateRef methodOffset = builder_.IntPtr(JSFunctionBase::METHOD_OFFSET);
GateRef method = builder_.Load(VariableType::JS_POINTER(), jsFunc, methodOffset, acc_.GetDependRoot());
GateRef sharedConstpool =
builder_.Load(VariableType::JS_ANY(), method, builder_.IntPtr(Method::CONSTANT_POOL_OFFSET), method);
acc_.UpdateAllUses(gate, sharedConstpool);
acc_.DeleteGate(gate);
}
void SlowPathLowering::LowerGetUnsharedConstPool(GateRef gate)
{
bool useConstPool = false;
auto uses = acc_.Uses(gate);
for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
if (acc_.GetOpCode(*useIt) != OpCode::FRAME_ARGS) {
useConstPool = true;
break;
}
}
if (!useConstPool) {
acc_.UpdateAllUses(gate, builder_.Undefined());
acc_.DeleteGate(gate);
return;
}
GateRef sharedConstPool = acc_.GetValueIn(gate, 0);
GateRef constPoolSize = builder_.Load(VariableType::INT32(), sharedConstPool,
builder_.IntPtr(TaggedArray::LENGTH_OFFSET), sharedConstPool);
GateRef unshareIdx = builder_.Int32Sub(constPoolSize, builder_.Int32(ConstantPool::UNSHARED_CONSTPOOL_INDEX));
GateRef offset =
builder_.PtrMul(builder_.ZExtInt32ToPtr(unshareIdx), builder_.IntPtr(JSTaggedValue::TaggedTypeSize()));
GateRef dataOffset = builder_.PtrAdd(offset, builder_.IntPtr(TaggedArray::DATA_OFFSET));
GateRef index = builder_.Load(VariableType::JS_ANY(), sharedConstPool, dataOffset, constPoolSize);
GateRef unshareCpOffset = static_cast<int32_t>(JSThread::GlueData::GetUnSharedConstpoolsOffset(false));
GateRef unshareCpAddr =
builder_.Load(VariableType::NATIVE_POINTER(), glue_, builder_.IntPtr(unshareCpOffset), index);
GateRef unshareCpDataOffset =
builder_.PtrAdd(unshareCpAddr, builder_.PtrMul(builder_.IntPtr(JSTaggedValue::TaggedTypeSize()),
builder_.ZExtInt32ToPtr(builder_.TaggedGetInt(index))));
GateRef unsharedConstPool =
builder_.Load(VariableType::JS_ANY(), unshareCpDataOffset, builder_.IntPtr(0), unshareCpAddr);
acc_.UpdateAllUses(gate, unsharedConstPool);
// delete old gate
acc_.DeleteGate(gate);
}
void SlowPathLowering::LowerLdLazyExternalModuleVar(GateRef gate)
{
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
GateRef result = LowerCallRuntime(gate,
RTSTUB_ID(LdLazyExternalModuleVarByIndex), {index, jsFunc}, true);
ReplaceHirWithValue(gate, result);
}
void SlowPathLowering::LowerLdLazySendableExternalModuleVar(GateRef gate)
{
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
GateRef result = LowerCallRuntime(gate,
RTSTUB_ID(LdLazySendableExternalModuleVarByIndex), {index, jsFunc}, true);
ReplaceHirWithValue(gate, result);
}
} // namespace panda::ecmascript