mirror of
https://github.com/openharmony/ark_js_runtime.git
synced 2026-07-25 22:15:32 -04:00
6430e8f31e
1. Throw JS exception in tsaot 2. Print bcoffset when occur JS exception issue: https://gitee.com/openharmony/ark_js_runtime/issues/I5AMHL Signed-off-by: xujie <xujie101@huawei.com> Change-Id: I046d76c092a399354ddcdedd859f0c1e622387c2
3003 lines
122 KiB
C++
3003 lines
122 KiB
C++
/*
|
|
* Copyright (c) 2021 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 "slowpath_lowering.h"
|
|
|
|
namespace panda::ecmascript::kungfu {
|
|
#define CREATE_DOUBLE_EXIT(SuccessLabel, FailLabel) \
|
|
std::vector<GateRef> successControl; \
|
|
std::vector<GateRef> failControl; \
|
|
builder_.Bind(&SuccessLabel); \
|
|
{ \
|
|
successControl.emplace_back(builder_.GetState()); \
|
|
successControl.emplace_back(builder_.GetDepend()); \
|
|
} \
|
|
builder_.Bind(&FailLabel); \
|
|
{ \
|
|
failControl.emplace_back(builder_.GetState()); \
|
|
failControl.emplace_back(builder_.GetDepend()); \
|
|
}
|
|
|
|
void SlowPathLowering::CallRuntimeLowering()
|
|
{
|
|
const auto &gateList = circuit_->GetAllGates();
|
|
for (const auto &gate : gateList) {
|
|
auto op = circuit_->GetOpCode(gate);
|
|
if (op == OpCode::JS_BYTECODE) {
|
|
Lower(gate);
|
|
} else if (op == OpCode::GET_EXCEPTION) {
|
|
LowerExceptionHandler(gate);
|
|
}
|
|
}
|
|
|
|
if (IsLogEnabled()) {
|
|
COMPILER_LOG(INFO) << "=========================================================";
|
|
circuit_->PrintAllGates(*bcBuilder_);
|
|
}
|
|
}
|
|
|
|
int32_t SlowPathLowering::ComputeCallArgc(GateRef gate, EcmaOpcode op)
|
|
{
|
|
if (op == EcmaOpcode::CALLITHISRANGEDYN_PREF_IMM16_V8) {
|
|
return acc_.GetNumValueIn(gate) + NUM_MANDATORY_JSFUNC_ARGS - 3; // 3: calltarget, this and bcoffset
|
|
}
|
|
return acc_.GetNumValueIn(gate) + NUM_MANDATORY_JSFUNC_ARGS - 2; // 2: calltarget and bcoffset
|
|
}
|
|
|
|
void SlowPathLowering::ReplaceHirControlGate(GateAccessor::UsesIterator &useIt, GateRef newGate, bool noThrow)
|
|
{
|
|
GateAccessor acc(circuit_);
|
|
ASSERT(acc.GetOpCode(*useIt) == OpCode::IF_SUCCESS || acc.GetOpCode(*useIt) == OpCode::IF_EXCEPTION);
|
|
if (!noThrow) {
|
|
auto firstUse = acc.Uses(*useIt).begin();
|
|
circuit_->ModifyIn(*firstUse, firstUse.GetIndex(), newGate);
|
|
}
|
|
acc.DeleteGate(useIt);
|
|
}
|
|
|
|
// depends on the construction of JSgates in BytecodeCircuitBuilder
|
|
void SlowPathLowering::ReplaceHirToSubCfg(GateRef hir, GateRef outir,
|
|
const std::vector<GateRef> &successControl,
|
|
const std::vector<GateRef> &exceptionControl,
|
|
bool noThrow)
|
|
{
|
|
GateAccessor acc(circuit_);
|
|
if (outir != Circuit::NullGate()) {
|
|
acc.SetGateType(outir, acc.GetGateType(hir));
|
|
}
|
|
auto uses = acc.Uses(hir);
|
|
for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
|
|
// replace HIR:IF_SUCCESS/IF_EXCEPTION with control flow in Label successExit/failExit of MIR Circuit
|
|
if (acc.GetOpCode(*useIt) == OpCode::IF_SUCCESS) {
|
|
ReplaceHirControlGate(useIt, successControl[0]);
|
|
} else if (acc.GetOpCode(*useIt) == OpCode::IF_EXCEPTION) {
|
|
ReplaceHirControlGate(useIt, exceptionControl[0], noThrow);
|
|
// change depend flow in catch block from HIR:JS_BYTECODE to depend flow in MIR Circuit
|
|
} else if (acc.GetOpCode(*useIt) == OpCode::DEPEND_SELECTOR) {
|
|
if (acc.GetOpCode(acc.GetIn(acc.GetIn(*useIt, 0), useIt.GetIndex() - 1)) == OpCode::IF_EXCEPTION) {
|
|
noThrow ? acc.DeleteExceptionDep(useIt) : acc.ReplaceIn(useIt, exceptionControl[1]);
|
|
} else {
|
|
acc.ReplaceIn(useIt, successControl[1]);
|
|
}
|
|
} else if (acc.GetOpCode(*useIt) == OpCode::DEPEND_RELAY) {
|
|
if (acc.GetOpCode(acc.GetIn(*useIt, 0)) == OpCode::IF_EXCEPTION) {
|
|
acc.ReplaceIn(useIt, exceptionControl[1]);
|
|
} else {
|
|
acc.ReplaceIn(useIt, successControl[1]);
|
|
}
|
|
// replace normal depend
|
|
} else if ((acc.GetOpCode(*useIt) == OpCode::JS_BYTECODE) && useIt.GetIndex() == 1) {
|
|
acc.ReplaceIn(useIt, successControl[1]);
|
|
// if no catch block, just throw exception(RETURN)
|
|
} else if ((acc.GetOpCode(*useIt) == OpCode::RETURN) &&
|
|
acc.GetOpCode(acc.GetIn(*useIt, 0)) == OpCode::IF_EXCEPTION) {
|
|
noThrow ? acc.DeleteExceptionDep(useIt) : acc.ReplaceIn(useIt, exceptionControl[1]);
|
|
// if hir isThrow
|
|
} else if (acc.GetOpCode(*useIt) != OpCode::VALUE_SELECTOR && useIt.GetIndex() == 1) {
|
|
acc.ReplaceIn(useIt, successControl[1]);
|
|
// replace data flow with data output in label successExit(incluing JSgates and phigates)
|
|
} else {
|
|
acc.ReplaceIn(useIt, outir);
|
|
}
|
|
}
|
|
|
|
circuit_->DeleteGate(hir);
|
|
}
|
|
|
|
|
|
/*
|
|
* 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::ReplaceHirToCall(GateRef hirGate, GateRef callGate, bool noThrow)
|
|
{
|
|
GateRef stateInGate = acc_.GetState(hirGate);
|
|
// copy depend-wire of hirGate to callGate
|
|
GateRef dependInGate = acc_.GetDep(hirGate);
|
|
acc_.SetDep(callGate, dependInGate);
|
|
|
|
GateRef ifBranch;
|
|
if (!noThrow) {
|
|
// exception value
|
|
GateRef exceptionVal = builder_.ExceptionConstant(GateType::TaggedNPointer());
|
|
// compare with trampolines result
|
|
GateRef equal = builder_.BinaryLogic(OpCode(OpCode::EQ), callGate, exceptionVal);
|
|
ifBranch = builder_.Branch(stateInGate, equal);
|
|
} else {
|
|
ifBranch = builder_.Branch(stateInGate, builder_.Boolean(false));
|
|
}
|
|
|
|
auto uses = acc_.Uses(hirGate);
|
|
for (auto it = uses.begin(); it != uses.end(); it++) {
|
|
if (acc_.GetOpCode(*it) == OpCode::IF_SUCCESS) {
|
|
acc_.SetOpCode(*it, OpCode::IF_FALSE);
|
|
acc_.ReplaceIn(it, ifBranch);
|
|
} else {
|
|
if (acc_.GetOpCode(*it) == OpCode::IF_EXCEPTION) {
|
|
acc_.SetOpCode(*it, OpCode::IF_TRUE);
|
|
acc_.ReplaceIn(it, ifBranch);
|
|
} else {
|
|
acc_.ReplaceIn(it, callGate);
|
|
}
|
|
}
|
|
}
|
|
|
|
// delete old gate
|
|
circuit_->DeleteGate(hirGate);
|
|
}
|
|
|
|
/*
|
|
* lower to throw call like this pattern:
|
|
* Call(...);
|
|
* goto exception_handle;
|
|
*
|
|
*/
|
|
void SlowPathLowering::ReplaceHirToThrowCall(GateRef hirGate, GateRef callGate)
|
|
{
|
|
GateRef stateInGate = acc_.GetState(hirGate);
|
|
GateRef dependInGate = acc_.GetDep(hirGate);
|
|
acc_.SetDep(callGate, dependInGate);
|
|
|
|
GateRef ifBranch = builder_.Branch(stateInGate, builder_.Boolean(true));
|
|
auto uses = acc_.Uses(hirGate);
|
|
for (auto it = uses.begin(); it != uses.end(); it++) {
|
|
if (acc_.GetOpCode(*it) == OpCode::IF_SUCCESS) {
|
|
acc_.SetOpCode(*it, OpCode::IF_FALSE);
|
|
acc_.ReplaceIn(it, ifBranch);
|
|
} else {
|
|
if (acc_.GetOpCode(*it) == OpCode::IF_EXCEPTION) {
|
|
acc_.SetOpCode(*it, OpCode::IF_TRUE);
|
|
acc_.ReplaceIn(it, ifBranch);
|
|
} else {
|
|
acc_.ReplaceIn(it, callGate);
|
|
}
|
|
}
|
|
}
|
|
|
|
circuit_->DeleteGate(hirGate);
|
|
}
|
|
|
|
// labelmanager must be initialized
|
|
GateRef SlowPathLowering::GetConstPool(GateRef jsFunc)
|
|
{
|
|
return builder_.Load(VariableType::JS_ANY(), jsFunc, builder_.IntPtr(JSFunction::CONSTANT_POOL_OFFSET));
|
|
}
|
|
|
|
// labelmanager must be initialized
|
|
GateRef SlowPathLowering::GetCurrentEnv(GateRef jsFunc)
|
|
{
|
|
return builder_.Load(VariableType::JS_ANY(), jsFunc, builder_.IntPtr(JSFunction::LEXICAL_ENV_OFFSET));
|
|
}
|
|
|
|
// labelmanager must be initialized
|
|
GateRef SlowPathLowering::GetObjectFromConstPool(GateRef jsFunc, GateRef index)
|
|
{
|
|
GateRef constPool = GetConstPool(jsFunc);
|
|
return builder_.GetValueFromTaggedArray(VariableType::JS_ANY(), constPool, index);
|
|
}
|
|
|
|
// labelmanager must be initialized
|
|
GateRef SlowPathLowering::GetHomeObjectFromJSFunction(GateRef jsFunc)
|
|
{
|
|
GateRef offset = builder_.IntPtr(JSFunction::HOME_OBJECT_OFFSET);
|
|
return builder_.Load(VariableType::JS_ANY(), jsFunc, offset);
|
|
}
|
|
|
|
GateRef SlowPathLowering::GetValueFromConstStringTable(GateRef glue, GateRef gate, uint32_t inIndex)
|
|
{
|
|
GateRef target = builder_.IntPtr(RTSTUB_ID(LoadValueFromConstantStringTable));
|
|
auto idGate = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, inIndex)));
|
|
GateRef dependGate = acc_.GetDep(gate);
|
|
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
|
|
return builder_.Call(cs, glue, target, dependGate, {idGate});
|
|
}
|
|
|
|
void SlowPathLowering::Lower(GateRef gate)
|
|
{
|
|
GateRef glue = bcBuilder_->GetCommonArgByIndex(CommonArgIdx::GLUE);
|
|
GateRef newTarget = bcBuilder_->GetCommonArgByIndex(CommonArgIdx::NEW_TARGET);
|
|
GateRef jsFunc = bcBuilder_->GetCommonArgByIndex(CommonArgIdx::FUNC);
|
|
|
|
auto pc = bcBuilder_->GetJSBytecode(gate);
|
|
EcmaOpcode op = static_cast<EcmaOpcode>(*pc);
|
|
// initialize label manager
|
|
Environment env(gate, circuit_, &builder_);
|
|
switch (op) {
|
|
case LDA_STR_ID32:
|
|
LowerLoadStr(gate, glue);
|
|
break;
|
|
case CALLARG0DYN_PREF_V8:
|
|
LowerCallArg0Dyn(gate, glue);
|
|
break;
|
|
case CALLARG1DYN_PREF_V8_V8:
|
|
LowerCallArg1Dyn(gate, glue);
|
|
break;
|
|
case CALLARGS2DYN_PREF_V8_V8_V8:
|
|
LowerCallArgs2Dyn(gate, glue);
|
|
break;
|
|
case CALLARGS3DYN_PREF_V8_V8_V8_V8:
|
|
LowerCallArgs3Dyn(gate, glue);
|
|
break;
|
|
case CALLITHISRANGEDYN_PREF_IMM16_V8:
|
|
LowerCallIThisRangeDyn(gate, glue);
|
|
break;
|
|
case CALLSPREADDYN_PREF_V8_V8_V8:
|
|
LowerCallSpreadDyn(gate, glue);
|
|
break;
|
|
case CALLIRANGEDYN_PREF_IMM16_V8:
|
|
LowerCallIRangeDyn(gate, glue);
|
|
break;
|
|
case LDLEXENVDYN_PREF:
|
|
LowerLexicalEnv(gate, glue, jsFunc);
|
|
break;
|
|
case GETUNMAPPEDARGS_PREF:
|
|
LowerGetUnmappedArgs(gate, glue);
|
|
break;
|
|
case ASYNCFUNCTIONENTER_PREF:
|
|
LowerAsyncFunctionEnter(gate, glue);
|
|
break;
|
|
case INCDYN_PREF_V8:
|
|
LowerIncDyn(gate, glue);
|
|
break;
|
|
case DECDYN_PREF_V8:
|
|
LowerDecDyn(gate, glue);
|
|
break;
|
|
case GETPROPITERATOR_PREF:
|
|
LowerGetPropIterator(gate, glue);
|
|
break;
|
|
case RESUMEGENERATOR_PREF_V8:
|
|
LowerResumeGenerator(gate);
|
|
break;
|
|
case GETRESUMEMODE_PREF_V8:
|
|
LowerGetResumeMode(gate);
|
|
break;
|
|
case ITERNEXT_PREF_V8:
|
|
LowerIterNext(gate, glue);
|
|
break;
|
|
case CLOSEITERATOR_PREF_V8:
|
|
LowerCloseIterator(gate, glue);
|
|
break;
|
|
case ADD2DYN_PREF_V8:
|
|
LowerAdd2Dyn(gate, glue);
|
|
break;
|
|
case SUB2DYN_PREF_V8:
|
|
LowerSub2Dyn(gate, glue);
|
|
break;
|
|
case MUL2DYN_PREF_V8:
|
|
LowerMul2Dyn(gate, glue);
|
|
break;
|
|
case DIV2DYN_PREF_V8:
|
|
LowerDiv2Dyn(gate, glue);
|
|
break;
|
|
case MOD2DYN_PREF_V8:
|
|
LowerMod2Dyn(gate, glue);
|
|
break;
|
|
case EQDYN_PREF_V8:
|
|
LowerEqDyn(gate, glue);
|
|
break;
|
|
case NOTEQDYN_PREF_V8:
|
|
LowerNotEqDyn(gate, glue);
|
|
break;
|
|
case LESSDYN_PREF_V8:
|
|
LowerLessDyn(gate, glue);
|
|
break;
|
|
case LESSEQDYN_PREF_V8:
|
|
LowerLessEqDyn(gate, glue);
|
|
break;
|
|
case GREATERDYN_PREF_V8:
|
|
LowerGreaterDyn(gate, glue);
|
|
break;
|
|
case GREATEREQDYN_PREF_V8:
|
|
LowerGreaterEqDyn(gate, glue);
|
|
break;
|
|
case CREATEITERRESULTOBJ_PREF_V8_V8:
|
|
LowerCreateIterResultObj(gate, glue);
|
|
break;
|
|
case SUSPENDGENERATOR_PREF_V8_V8:
|
|
LowerSuspendGenerator(gate, glue);
|
|
break;
|
|
case ASYNCFUNCTIONAWAITUNCAUGHT_PREF_V8_V8:
|
|
LowerAsyncFunctionAwaitUncaught(gate, glue);
|
|
break;
|
|
case ASYNCFUNCTIONRESOLVE_PREF_V8_V8_V8:
|
|
LowerAsyncFunctionResolve(gate, glue);
|
|
break;
|
|
case ASYNCFUNCTIONREJECT_PREF_V8_V8_V8:
|
|
LowerAsyncFunctionReject(gate, glue);
|
|
break;
|
|
case TRYLDGLOBALBYNAME_PREF_ID32:
|
|
LowerTryLdGlobalByName(gate, glue);
|
|
break;
|
|
case STGLOBALVAR_PREF_ID32:
|
|
LowerStGlobalVar(gate, glue);
|
|
break;
|
|
case GETITERATOR_PREF:
|
|
LowerGetIterator(gate, glue);
|
|
break;
|
|
case NEWOBJSPREADDYN_PREF_V8_V8:
|
|
LowerNewObjSpreadDyn(gate, glue);
|
|
break;
|
|
case THROWDYN_PREF:
|
|
LowerThrowDyn(gate, glue);
|
|
break;
|
|
case TYPEOFDYN_PREF:
|
|
LowerTypeOfDyn(gate, glue);
|
|
break;
|
|
case THROWCONSTASSIGNMENT_PREF_V8:
|
|
LowerThrowConstAssignment(gate, glue);
|
|
break;
|
|
case THROWTHROWNOTEXISTS_PREF:
|
|
LowerThrowThrowNotExists(gate, glue);
|
|
break;
|
|
case THROWPATTERNNONCOERCIBLE_PREF:
|
|
LowerThrowPatternNonCoercible(gate, glue);
|
|
break;
|
|
case THROWIFNOTOBJECT_PREF_V8:
|
|
LowerThrowIfNotObject(gate, glue);
|
|
break;
|
|
case THROWUNDEFINEDIFHOLE_PREF_V8_V8:
|
|
LowerThrowUndefinedIfHole(gate, glue);
|
|
break;
|
|
case THROWIFSUPERNOTCORRECTCALL_PREF_IMM16:
|
|
LowerThrowIfSuperNotCorrectCall(gate, glue);
|
|
break;
|
|
case THROWDELETESUPERPROPERTY_PREF:
|
|
LowerThrowDeleteSuperProperty(gate, glue);
|
|
break;
|
|
case LDGLOBALTHIS_PREF:
|
|
LowerLdGlobal(gate, glue);
|
|
break;
|
|
case LDSYMBOL_PREF:
|
|
LowerLdSymbol(gate, glue);
|
|
break;
|
|
case LDGLOBAL_PREF:
|
|
LowerLdGlobal(gate, glue);
|
|
break;
|
|
case TONUMBER_PREF_V8:
|
|
LowerToNumber(gate, glue);
|
|
break;
|
|
case NEGDYN_PREF_V8:
|
|
LowerNegDyn(gate, glue);
|
|
break;
|
|
case NOTDYN_PREF_V8:
|
|
LowerNotDyn(gate, glue);
|
|
break;
|
|
case SHL2DYN_PREF_V8:
|
|
LowerShl2Dyn(gate, glue);
|
|
break;
|
|
case SHR2DYN_PREF_V8:
|
|
LowerShr2Dyn(gate, glue);
|
|
break;
|
|
case ASHR2DYN_PREF_V8:
|
|
LowerAshr2Dyn(gate, glue);
|
|
break;
|
|
case AND2DYN_PREF_V8:
|
|
LowerAnd2Dyn(gate, glue);
|
|
break;
|
|
case OR2DYN_PREF_V8:
|
|
LowerOr2Dyn(gate, glue);
|
|
break;
|
|
case XOR2DYN_PREF_V8:
|
|
LowerXor2Dyn(gate, glue);
|
|
break;
|
|
case DELOBJPROP_PREF_V8_V8:
|
|
LowerDelObjProp(gate, glue);
|
|
break;
|
|
case DEFINENCFUNCDYN_PREF_ID16_IMM16_V8:
|
|
LowerDefineNCFuncDyn(gate, glue, jsFunc);
|
|
break;
|
|
case DEFINEMETHOD_PREF_ID16_IMM16_V8:
|
|
LowerDefineMethod(gate, glue, jsFunc);
|
|
break;
|
|
case EXPDYN_PREF_V8:
|
|
LowerExpDyn(gate, glue);
|
|
break;
|
|
case ISINDYN_PREF_V8:
|
|
LowerIsInDyn(gate, glue);
|
|
break;
|
|
case INSTANCEOFDYN_PREF_V8:
|
|
LowerInstanceofDyn(gate, glue);
|
|
break;
|
|
case STRICTNOTEQDYN_PREF_V8:
|
|
LowerFastStrictNotEqual(gate, glue);
|
|
break;
|
|
case STRICTEQDYN_PREF_V8:
|
|
LowerFastStrictEqual(gate, glue);
|
|
break;
|
|
case CREATEEMPTYARRAY_PREF:
|
|
LowerCreateEmptyArray(gate, glue);
|
|
break;
|
|
case CREATEEMPTYOBJECT_PREF:
|
|
LowerCreateEmptyObject(gate, glue);
|
|
break;
|
|
case CREATEOBJECTWITHBUFFER_PREF_IMM16:
|
|
LowerCreateObjectWithBuffer(gate, glue, jsFunc);
|
|
break;
|
|
case CREATEARRAYWITHBUFFER_PREF_IMM16:
|
|
LowerCreateArrayWithBuffer(gate, glue, jsFunc);
|
|
break;
|
|
case STMODULEVAR_PREF_ID32:
|
|
LowerStModuleVar(gate, glue);
|
|
break;
|
|
case GETTEMPLATEOBJECT_PREF_V8:
|
|
LowerGetTemplateObject(gate, glue);
|
|
break;
|
|
case SETOBJECTWITHPROTO_PREF_V8_V8:
|
|
LowerSetObjectWithProto(gate, glue);
|
|
break;
|
|
case LDBIGINT_PREF_ID32:
|
|
LowerLdBigInt(gate, glue, jsFunc);
|
|
break;
|
|
case LDMODULEVAR_PREF_ID32_IMM8:
|
|
LowerLdModuleVar(gate, glue);
|
|
break;
|
|
case GETMODULENAMESPACE_PREF_ID32:
|
|
LowerGetModuleNamespace(gate, glue);
|
|
break;
|
|
case NEWOBJDYNRANGE_PREF_IMM16_V8:
|
|
LowerNewObjDynRange(gate, glue);
|
|
break;
|
|
case JEQZ_IMM8:
|
|
case JEQZ_IMM16:
|
|
LowerConditionJump(gate, true);
|
|
break;
|
|
case JNEZ_IMM8:
|
|
case JNEZ_IMM16:
|
|
LowerConditionJump(gate, false);
|
|
break;
|
|
case GETITERATORNEXT_PREF_V8_V8:
|
|
LowerGetIteratorNext(gate, glue);
|
|
break;
|
|
case SUPERCALL_PREF_IMM16_V8:
|
|
LowerSuperCall(gate, glue, newTarget);
|
|
break;
|
|
case SUPERCALLSPREAD_PREF_V8:
|
|
LowerSuperCallSpread(gate, glue, newTarget);
|
|
break;
|
|
case ISTRUE_PREF:
|
|
LowerIsTrueOrFalse(gate, glue, true);
|
|
break;
|
|
case ISFALSE_PREF:
|
|
LowerIsTrueOrFalse(gate, glue, false);
|
|
break;
|
|
case GETNEXTPROPNAME_PREF_V8:
|
|
LowerGetNextPropName(gate, glue);
|
|
break;
|
|
case COPYDATAPROPERTIES_PREF_V8_V8:
|
|
LowerCopyDataProperties(gate, glue);
|
|
break;
|
|
case CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8:
|
|
LowerCreateObjectWithExcludedKeys(gate, glue);
|
|
break;
|
|
case CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8:
|
|
LowerCreateRegExpWithLiteral(gate, glue);
|
|
break;
|
|
case STOWNBYVALUE_PREF_V8_V8:
|
|
LowerStOwnByValue(gate, glue);
|
|
break;
|
|
case STOWNBYINDEX_PREF_V8_IMM32:
|
|
LowerStOwnByIndex(gate, glue);
|
|
break;
|
|
case STOWNBYNAME_PREF_ID32_V8:
|
|
LowerStOwnByName(gate, glue);
|
|
break;
|
|
case DEFINEGENERATORFUNC_PREF_ID16_IMM16_V8:
|
|
LowerDefineGeneratorFunc(gate, glue, jsFunc);
|
|
break;
|
|
case DEFINEASYNCFUNC_PREF_ID16_IMM16_V8:
|
|
LowerDefineAsyncFunc(gate, glue, jsFunc);
|
|
break;
|
|
case NEWLEXENVDYN_PREF_IMM16:
|
|
LowerNewLexicalEnvDyn(gate, glue, jsFunc);
|
|
break;
|
|
case NEWLEXENVWITHNAMEDYN_PREF_IMM16_IMM16:
|
|
LowerNewLexicalEnvWithNameDyn(gate, glue, jsFunc);
|
|
break;
|
|
case POPLEXENVDYN_PREF:
|
|
LowerPopLexicalEnv(gate, glue, jsFunc);
|
|
break;
|
|
case LDSUPERBYVALUE_PREF_V8_V8:
|
|
LowerLdSuperByValue(gate, glue, jsFunc);
|
|
break;
|
|
case STSUPERBYVALUE_PREF_V8_V8:
|
|
LowerStSuperByValue(gate, glue, jsFunc);
|
|
break;
|
|
case TRYSTGLOBALBYNAME_PREF_ID32:
|
|
LowerTryStGlobalByName(gate, glue);
|
|
break;
|
|
case STCONSTTOGLOBALRECORD_PREF_ID32:
|
|
LowerStConstToGlobalRecord(gate, glue);
|
|
break;
|
|
case STLETTOGLOBALRECORD_PREF_ID32:
|
|
LowerStLetToGlobalRecord(gate, glue);
|
|
break;
|
|
case STCLASSTOGLOBALRECORD_PREF_ID32:
|
|
LowerStClassToGlobalRecord(gate, glue);
|
|
break;
|
|
case STOWNBYVALUEWITHNAMESET_PREF_V8_V8:
|
|
LowerStOwnByValueWithNameSet(gate, glue);
|
|
break;
|
|
case STOWNBYNAMEWITHNAMESET_PREF_ID32_V8:
|
|
LowerStOwnByNameWithNameSet(gate, glue);
|
|
break;
|
|
case LDGLOBALVAR_PREF_ID32:
|
|
LowerLdGlobalVar(gate, glue);
|
|
break;
|
|
case LDOBJBYNAME_PREF_ID32_V8:
|
|
LowerLdObjByName(gate, glue);
|
|
break;
|
|
case STOBJBYNAME_PREF_ID32_V8:
|
|
LowerStObjByName(gate, glue);
|
|
break;
|
|
case DEFINEGETTERSETTERBYVALUE_PREF_V8_V8_V8_V8:
|
|
LowerDefineGetterSetterByValue(gate, glue);
|
|
break;
|
|
case LDOBJBYINDEX_PREF_V8_IMM32:
|
|
LowerLdObjByIndex(gate, glue);
|
|
break;
|
|
case STOBJBYINDEX_PREF_V8_IMM32:
|
|
LowerStObjByIndex(gate, glue);
|
|
break;
|
|
case LDOBJBYVALUE_PREF_V8_V8:
|
|
LowerLdObjByValue(gate, glue);
|
|
break;
|
|
case STOBJBYVALUE_PREF_V8_V8:
|
|
LowerStObjByValue(gate, glue);
|
|
break;
|
|
case LDSUPERBYNAME_PREF_ID32_V8:
|
|
LowerLdSuperByName(gate, glue);
|
|
break;
|
|
case STSUPERBYNAME_PREF_ID32_V8:
|
|
LowerStSuperByName(gate, glue);
|
|
break;
|
|
case CREATEGENERATOROBJ_PREF_V8:
|
|
LowerCreateGeneratorObj(gate, glue);
|
|
break;
|
|
case STARRAYSPREAD_PREF_V8_V8:
|
|
LowerStArraySpread(gate, glue);
|
|
break;
|
|
case LDLEXVARDYN_PREF_IMM4_IMM4:
|
|
case LDLEXVARDYN_PREF_IMM8_IMM8:
|
|
case LDLEXVARDYN_PREF_IMM16_IMM16:
|
|
LowerLdLexVarDyn(gate, jsFunc);
|
|
break;
|
|
case STLEXVARDYN_PREF_IMM4_IMM4_V8:
|
|
case STLEXVARDYN_PREF_IMM8_IMM8_V8:
|
|
case STLEXVARDYN_PREF_IMM16_IMM16_V8:
|
|
LowerStLexVarDyn(gate, glue, jsFunc);
|
|
break;
|
|
case CREATEOBJECTHAVINGMETHOD_PREF_IMM16:
|
|
LowerCreateObjectHavingMethod(gate, glue, jsFunc);
|
|
break;
|
|
case LDHOMEOBJECT_PREF:
|
|
LowerLdHomeObject(gate, jsFunc);
|
|
break;
|
|
case DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8:
|
|
LowerDefineClassWithBuffer(gate, glue, jsFunc);
|
|
break;
|
|
case DEFINEFUNCDYN_PREF_ID16_IMM16_V8:
|
|
LowerDefineFuncDyn(gate, glue, jsFunc);
|
|
break;
|
|
case COPYRESTARGS_PREF_IMM16:
|
|
LowerCopyRestArgs(gate, glue);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
GateRef SlowPathLowering::LowerCallRuntime(GateRef glue, int index, const std::vector<GateRef> &args, bool useLabel)
|
|
{
|
|
if (useLabel) {
|
|
GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args);
|
|
return result;
|
|
} else {
|
|
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
|
|
GateRef target = builder_.IntPtr(index);
|
|
GateRef result = builder_.Call(cs, glue, target, dependEntry_, args);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
void SlowPathLowering::LowerAdd2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Add2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
auto args = {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)};
|
|
GateRef newGate = LowerCallRuntime(glue, id, args);
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCreateIterResultObj(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(CreateIterResultObj);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerSuspendGenerator(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(SuspendAotGenerator);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerAsyncFunctionAwaitUncaught(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(AsyncFunctionAwaitUncaught);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerAsyncFunctionResolve(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(AsyncFunctionResolveOrReject);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef taggedTrue = builder_.TaggedTrue();
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), taggedTrue});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerAsyncFunctionReject(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(AsyncFunctionResolveOrReject);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef taggedFalse = builder_.TaggedFalse();
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), taggedFalse});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLoadStr(GateRef gate, GateRef glue)
|
|
{
|
|
GateRef newGate = GetValueFromConstStringTable(glue, gate, 0);
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLexicalEnv(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
const int id = RTSTUB_ID(GetAotLexicalEnv);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {jsFunc});
|
|
ReplaceHirToCall(gate, newGate, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerTryLdGlobalByName(GateRef gate, GateRef glue)
|
|
{
|
|
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 0));
|
|
GateRef stringId = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0)));
|
|
GateRef prop = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), { stringId }, true);
|
|
GateRef recordResult = LowerCallRuntime(glue, RTSTUB_ID(LdGlobalRecord), {prop}, true);
|
|
Label isFound(&builder_);
|
|
Label isNotFound(&builder_);
|
|
Label success(&builder_);
|
|
Label exception(&builder_);
|
|
Label defaultLabel(&builder_);
|
|
GateRef value = 0;
|
|
builder_.Branch(builder_.TaggedIsUndefined(recordResult), &isNotFound, &isFound);
|
|
builder_.Bind(&isNotFound);
|
|
{
|
|
Label notException(&builder_);
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(TryLdGlobalByName), {prop}, true);
|
|
builder_.Branch(builder_.IsSpecial(*result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exception, ¬Exception);
|
|
builder_.Bind(¬Exception);
|
|
{
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
}
|
|
builder_.Bind(&isFound);
|
|
{
|
|
result = builder_.Load(VariableType::JS_ANY(), recordResult, builder_.IntPtr(PropertyBox::VALUE_OFFSET));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
builder_.Bind(&defaultLabel);
|
|
{
|
|
value = *result;
|
|
builder_.Jump(&success);
|
|
}
|
|
CREATE_DOUBLE_EXIT(success, exception);
|
|
ReplaceHirToSubCfg(gate, value, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStGlobalVar(GateRef gate, GateRef glue)
|
|
{
|
|
GateRef prop = GetValueFromConstStringTable(glue, gate, 0);
|
|
acc_.SetDep(gate, prop);
|
|
const int id = RTSTUB_ID(StGlobalVar);
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: number of value inputs
|
|
GateRef newGate = LowerCallRuntime(glue, id, {prop, acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGetIterator(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> successControl(2);
|
|
std::vector<GateRef> failControl(2);
|
|
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 0));
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
Label isTrue(&builder_);
|
|
Label isNot(&builder_);
|
|
GateRef value = 0;
|
|
builder_.Branch(builder_.TaggedIsGeneratorObject(acc_.GetValueIn(gate, 0)), &isTrue, &isNot);
|
|
builder_.Bind(&isTrue);
|
|
{
|
|
builder_.Jump(&successExit);
|
|
}
|
|
builder_.Bind(&isNot);
|
|
{
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(GetIterator), {acc_.GetValueIn(gate, 0)}, true);
|
|
builder_.Branch(builder_.IsSpecial(*result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&successExit);
|
|
{
|
|
value = *result;
|
|
successControl[0] = builder_.GetState();
|
|
successControl[1] = builder_.GetDepend();
|
|
}
|
|
builder_.Bind(&exceptionExit);
|
|
{
|
|
failControl[0] = builder_.GetState();
|
|
failControl[1] = builder_.GetDepend();
|
|
}
|
|
ReplaceHirToSubCfg(gate, value, successControl, failControl);
|
|
}
|
|
|
|
|
|
void SlowPathLowering::LowerToJSCall(GateRef gate, GateRef glue, const std::vector<GateRef> &args)
|
|
{
|
|
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCall));
|
|
GateRef target = builder_.IntPtr(RTSTUB_ID(JSCall));
|
|
GateRef newGate = builder_.Call(cs, glue, target, dependEntry_, args);
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCallArg0Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
|
|
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLARG0DYN_PREF_V8));
|
|
GateRef newTarget = builder_.Undefined();
|
|
GateRef thisObj = builder_.Undefined();
|
|
LowerToJSCall(gate, glue, {glue, actualArgc, acc_.GetValueIn(gate, 0), newTarget, thisObj,
|
|
acc_.GetValueIn(gate, 1)});
|
|
}
|
|
|
|
void SlowPathLowering::LowerCallArg1Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
// 2: func and bcoffset
|
|
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLARG1DYN_PREF_V8_V8));
|
|
GateRef newTarget = builder_.Undefined();
|
|
GateRef thisObj = builder_.Undefined();
|
|
LowerToJSCall(gate, glue, {glue, actualArgc,
|
|
acc_.GetValueIn(gate, 0), newTarget, thisObj, acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2)});
|
|
}
|
|
|
|
void SlowPathLowering::LowerCallArgs2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
// 4: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 4);
|
|
// 2: func and bcoffset
|
|
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLARGS2DYN_PREF_V8_V8_V8));
|
|
GateRef newTarget = builder_.Undefined();
|
|
GateRef thisObj = builder_.Undefined();
|
|
LowerToJSCall(gate, glue, {glue, actualArgc,
|
|
acc_.GetValueIn(gate, 0), newTarget, thisObj, acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2),
|
|
acc_.GetValueIn(gate, 3)});
|
|
}
|
|
|
|
void SlowPathLowering::LowerCallArgs3Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
// 5: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 5);
|
|
// 2: func and bcoffset
|
|
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLARGS3DYN_PREF_V8_V8_V8_V8));
|
|
GateRef newTarget = builder_.Undefined();
|
|
GateRef thisObj = builder_.Undefined();
|
|
LowerToJSCall(gate, glue, {glue, actualArgc,
|
|
acc_.GetValueIn(gate, 0), newTarget, thisObj, acc_.GetValueIn(gate, 1),
|
|
acc_.GetValueIn(gate, 2), acc_.GetValueIn(gate, 3)});
|
|
}
|
|
|
|
void SlowPathLowering::LowerCallIThisRangeDyn(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> vec;
|
|
// The first register input is callTarget, second is thisObj and other inputs are common args.
|
|
size_t fixedInputsNum = 2;
|
|
ASSERT(acc_.GetNumValueIn(gate) - fixedInputsNum >= 0);
|
|
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLITHISRANGEDYN_PREF_IMM16_V8));
|
|
GateRef callTarget = acc_.GetValueIn(gate, 0);
|
|
GateRef thisObj = acc_.GetValueIn(gate, 1);
|
|
GateRef newTarget = builder_.Undefined();
|
|
vec.emplace_back(glue);
|
|
vec.emplace_back(actualArgc);
|
|
vec.emplace_back(callTarget);
|
|
vec.emplace_back(newTarget);
|
|
vec.emplace_back(thisObj);
|
|
// add common args
|
|
for (size_t i = fixedInputsNum; i < acc_.GetNumValueIn(gate); i++) {
|
|
vec.emplace_back(acc_.GetValueIn(gate, i));
|
|
}
|
|
LowerToJSCall(gate, glue, vec);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCallSpreadDyn(GateRef gate, GateRef glue)
|
|
{
|
|
// need to fixed in later
|
|
const int id = RTSTUB_ID(CallSpreadDyn);
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
GateRef newGate = LowerCallRuntime(glue, id,
|
|
{acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCallIRangeDyn(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> vec;
|
|
size_t numArgs = acc_.GetNumValueIn(gate) - 1;
|
|
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLIRANGEDYN_PREF_IMM16_V8));
|
|
GateRef callTarget = acc_.GetValueIn(gate, 0);
|
|
GateRef newTarget = builder_.Undefined();
|
|
GateRef thisObj = builder_.Undefined();
|
|
vec.emplace_back(glue);
|
|
vec.emplace_back(actualArgc);
|
|
vec.emplace_back(callTarget);
|
|
vec.emplace_back(newTarget);
|
|
vec.emplace_back(thisObj);
|
|
|
|
for (size_t i = 1; i < numArgs; i++) { // skip imm
|
|
vec.emplace_back(acc_.GetValueIn(gate, i));
|
|
}
|
|
LowerToJSCall(gate, glue, vec);
|
|
}
|
|
|
|
void SlowPathLowering::LowerNewObjSpreadDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(NewObjSpreadDyn);
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
GateRef newGate = LowerCallRuntime(glue, id,
|
|
{acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerThrowDyn(GateRef gate, GateRef glue)
|
|
{
|
|
GateRef exception = acc_.GetValueIn(gate, 0);
|
|
GateRef setException = circuit_->NewGate(OpCode(OpCode::STORE), 0,
|
|
{dependEntry_, exception, glue}, VariableType::INT64().GetGateType());
|
|
ReplaceHirToThrowCall(gate, setException);
|
|
}
|
|
|
|
void SlowPathLowering::LowerThrowConstAssignment(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(ThrowConstAssignment);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToThrowCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerThrowThrowNotExists(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(ThrowThrowNotExists);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToThrowCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerThrowPatternNonCoercible(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(ThrowPatternNonCoercible);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {});
|
|
ReplaceHirToThrowCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerThrowIfNotObject(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(ThrowIfNotObject);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {});
|
|
ReplaceHirToThrowCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerThrowUndefinedIfHole(GateRef gate, GateRef glue)
|
|
{
|
|
// 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_);
|
|
builder_.Branch(builder_.TaggedIsHole(hole), &isHole, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
{
|
|
builder_.Jump(&successExit);
|
|
}
|
|
builder_.Bind(&isHole);
|
|
{
|
|
LowerCallRuntime(glue, RTSTUB_ID(ThrowUndefinedIfHole), {obj}, true);
|
|
builder_.Jump(&exceptionExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerThrowIfSuperNotCorrectCall(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(ThrowIfSuperNotCorrectCall);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
auto args = { builder_.TaggedTypeNGC(acc_.GetValueIn(gate, 0)), acc_.GetValueIn(gate, 1) };
|
|
GateRef newGate = LowerCallRuntime(glue, id, args);
|
|
ReplaceHirToThrowCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerThrowDeleteSuperProperty(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(ThrowDeleteSuperProperty);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {});
|
|
ReplaceHirToThrowCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerExceptionHandler(GateRef hirGate)
|
|
{
|
|
GateRef glue = bcBuilder_->GetCommonArgByIndex(CommonArgIdx::GLUE);
|
|
GateRef depend = acc_.GetDep(hirGate);
|
|
GateRef loadException = circuit_->NewGate(OpCode(OpCode::LOAD), VariableType::JS_ANY().GetMachineType(),
|
|
0, { depend, glue }, VariableType::JS_ANY().GetGateType());
|
|
acc_.SetDep(loadException, depend);
|
|
GateRef holeCst = builder_.HoleConstant(VariableType::JS_ANY().GetGateType());
|
|
GateRef clearException = circuit_->NewGate(OpCode(OpCode::STORE), 0,
|
|
{ loadException, holeCst, glue }, VariableType::INT64().GetGateType());
|
|
auto uses = acc_.Uses(hirGate);
|
|
for (auto it = uses.begin(); it != uses.end(); it++) {
|
|
if (acc_.GetDep(*it) == hirGate && acc_.IsDependIn(it)) {
|
|
acc_.ReplaceIn(it, clearException);
|
|
} else {
|
|
acc_.ReplaceIn(it, loadException);
|
|
}
|
|
}
|
|
circuit_->DeleteGate(hirGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdSymbol(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(GetSymbolFunction);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdGlobal(GateRef gate, GateRef glue)
|
|
{
|
|
GateRef offset = builder_.Int64(JSThread::GlueData::GetGlobalObjOffset(false));
|
|
GateRef val = builder_.Int64Add(glue, offset);
|
|
GateRef newGate = circuit_->NewGate(OpCode(OpCode::LOAD), VariableType::JS_ANY().GetMachineType(),
|
|
0, { dependEntry_, val }, VariableType::JS_ANY().GetGateType());
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerSub2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Sub2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerMul2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Mul2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDiv2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Div2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerMod2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Mod2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerEqDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(EqDyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerNotEqDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(NotEqDyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLessDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(LessDyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLessEqDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(LessEqDyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGreaterDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(GreaterDyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGreaterEqDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(GreaterEqDyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGetPropIterator(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(GetPropIterator);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerIterNext(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(IterNext);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCloseIterator(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(CloseIterator);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerIncDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(IncDyn);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDecDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(DecDyn);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerToNumber(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(ToNumber);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerNegDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(NegDyn);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerNotDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(NotDyn);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerShl2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Shl2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerShr2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Shr2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerAshr2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Ashr2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerAnd2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(And2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerOr2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Or2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerXor2Dyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(Xor2Dyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDelObjProp(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(DelObjProp);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerExpDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(ExpDyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerIsInDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(IsInDyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerInstanceofDyn(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(InstanceOfDyn);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerFastStrictNotEqual(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(FastStrictNotEqual);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerFastStrictEqual(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(FastStrictEqual);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
|
|
ReplaceHirToCall(gate, newGate, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCreateEmptyArray(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(CreateEmptyArray), {}, true);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCreateEmptyObject(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(CreateEmptyObject), {}, true);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCreateArrayWithBuffer(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef index = acc_.GetValueIn(gate, 0);
|
|
GateRef obj = GetObjectFromConstPool(jsFunc, builder_.TruncInt64ToInt32(index));
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(CreateArrayWithBuffer), { obj }, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCreateObjectWithBuffer(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef index = acc_.GetValueIn(gate, 0);
|
|
GateRef obj = GetObjectFromConstPool(jsFunc, builder_.TruncInt64ToInt32(index));
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(CreateObjectWithBuffer), { obj }, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStModuleVar(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef prop = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable),
|
|
{ builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0))) }, true);
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(StModuleVar), { prop, acc_.GetValueIn(gate, 1) }, true);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
// StModuleVar will not be inValue to other hir gates, result will not be used to replace hirgate
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGetTemplateObject(GateRef gate, GateRef glue)
|
|
{
|
|
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(glue, id, { literal });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerSetObjectWithProto(GateRef gate, GateRef glue)
|
|
{
|
|
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(glue, id, { proto, obj });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdBigInt(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef numberBigInt = GetObjectFromConstPool(jsFunc, acc_.GetValueIn(gate, 0));
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(LdBigInt), {numberBigInt}, true);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
// StModuleVar will not be inValue to other hir gates, result will not be used to replace hirgate
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdModuleVar(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef key = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable),
|
|
{ builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0))) }, true);
|
|
GateRef inner = builder_.TaggedTypeNGC(acc_.GetValueIn(gate, 1));
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(LdModuleVar), {key, inner}, true);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
// StModuleVar will not be inValue to other hir gates, result will not be used to replace hirgate
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGetModuleNamespace(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
auto args = { builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0))) };
|
|
GateRef localName = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), args, true);
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(GetModuleNamespace), {localName}, true);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
// StModuleVar will not be inValue to other hir gates, result will not be used to replace hirgate
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGetIteratorNext(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(GetIteratorNext);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef obj = acc_.GetValueIn(gate, 0);
|
|
GateRef method = acc_.GetValueIn(gate, 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, { obj, method });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerSuperCall(GateRef gate, GateRef glue, GateRef newTarget)
|
|
{
|
|
const int id = RTSTUB_ID(SuperCall);
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
GateRef func = acc_.GetValueIn(gate, 2);
|
|
GateRef firstVRegIdx = acc_.GetValueIn(gate, 1);
|
|
GateRef length = acc_.GetValueIn(gate, 0);
|
|
GateRef newGate = LowerCallRuntime(glue, id, { func, newTarget, builder_.TaggedTypeNGC(firstVRegIdx),
|
|
builder_.TaggedTypeNGC(length) });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerSuperCallSpread(GateRef gate, GateRef glue, GateRef newTarget)
|
|
{
|
|
const int id = RTSTUB_ID(SuperCallSpread);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef func = acc_.GetValueIn(gate, 1);
|
|
GateRef array = acc_.GetValueIn(gate, 0);
|
|
GateRef newGate = LowerCallRuntime(glue, id, { func, newTarget, array });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerIsTrueOrFalse(GateRef gate, GateRef glue, bool flag)
|
|
{
|
|
Label isTrue(&builder_);
|
|
Label isFalse(&builder_);
|
|
Label successExit(&builder_);
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> exceptionControl;
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 0));
|
|
GateRef callResult = LowerCallRuntime(glue, RTSTUB_ID(ToBoolean), { *result }, true);
|
|
builder_.Branch(builder_.IsSpecial(callResult, JSTaggedValue::VALUE_TRUE),
|
|
&isTrue, &isFalse);
|
|
builder_.Bind(&isTrue);
|
|
{
|
|
auto trueResult = flag ? builder_.TaggedTrue() : builder_.TaggedFalse();
|
|
result = builder_.ChangeInt64ToTagged(trueResult);
|
|
builder_.Jump(&successExit);
|
|
}
|
|
builder_.Bind(&isFalse);
|
|
{
|
|
auto falseResult = flag ? builder_.TaggedFalse() : builder_.TaggedTrue();
|
|
result = builder_.ChangeInt64ToTagged(falseResult);
|
|
builder_.Jump(&successExit);
|
|
}
|
|
builder_.Bind(&successExit);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
exceptionControl.emplace_back(Circuit::NullGate());
|
|
exceptionControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, *result, successControl, exceptionControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerNewObjDynRange(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(NewAotObjDynRange);
|
|
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);
|
|
}
|
|
GateRef newGate = LowerCallRuntime(glue, id, args);
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerConditionJump(GateRef gate, bool isEqualJump)
|
|
{
|
|
std::vector<GateRef> trueState;
|
|
GateRef value = acc_.GetValueIn(gate, 0);
|
|
// GET_ACC() == JSTaggedValue::False()
|
|
GateRef condition = builder_.IsSpecial(value, JSTaggedValue::VALUE_FALSE);
|
|
GateRef ifBranch = builder_.Branch(acc_.GetState(gate), condition);
|
|
GateRef ifTrue = builder_.IfTrue(ifBranch);
|
|
trueState.emplace_back(ifTrue);
|
|
GateRef ifFalse = builder_.IfFalse(ifBranch);
|
|
|
|
// (GET_ACC().IsInt() && GET_ACC().GetInt())
|
|
std::vector<GateRef> intFalseState;
|
|
ifBranch = builder_.Branch(ifFalse, builder_.TaggedIsInt(value));
|
|
GateRef isInt = builder_.IfTrue(ifBranch);
|
|
GateRef notInt = builder_.IfFalse(ifBranch);
|
|
intFalseState.emplace_back(notInt);
|
|
condition = builder_.Equal(builder_.TaggedGetInt(value), builder_.Int32(0));
|
|
ifBranch = builder_.Branch(isInt, condition);
|
|
GateRef isZero = builder_.IfTrue(ifBranch);
|
|
trueState.emplace_back(isZero);
|
|
GateRef notZero = builder_.IfFalse(ifBranch);
|
|
if (isEqualJump) {
|
|
intFalseState.emplace_back(notZero);
|
|
} else {
|
|
intFalseState.emplace_back(isZero);
|
|
}
|
|
auto mergeIntState = builder_.Merge(intFalseState.data(), intFalseState.size());
|
|
|
|
// (GET_ACC().IsDouble() && GET_ACC().GetDouble() == 0)
|
|
std::vector<GateRef> doubleFalseState;
|
|
ifBranch = builder_.Branch(mergeIntState, builder_.TaggedIsDouble(value));
|
|
GateRef isDouble = builder_.IfTrue(ifBranch);
|
|
GateRef notDouble = builder_.IfFalse(ifBranch);
|
|
doubleFalseState.emplace_back(notDouble);
|
|
condition = builder_.Equal(builder_.TaggedCastToDouble(value), builder_.Double(0));
|
|
ifBranch = builder_.Branch(isDouble, condition);
|
|
GateRef isDoubleZero = builder_.IfTrue(ifBranch);
|
|
trueState.emplace_back(isDoubleZero);
|
|
GateRef notDoubleZero = builder_.IfFalse(ifBranch);
|
|
if (isEqualJump) {
|
|
doubleFalseState.emplace_back(notDoubleZero);
|
|
} else {
|
|
doubleFalseState.emplace_back(isDoubleZero);
|
|
}
|
|
auto mergeFalseState = builder_.Merge(doubleFalseState.data(), doubleFalseState.size());
|
|
|
|
GateRef mergeTrueState = builder_.Merge(trueState.data(), trueState.size());
|
|
auto uses = acc_.Uses(gate);
|
|
for (auto it = uses.begin(); it != uses.end(); it++) {
|
|
if (acc_.GetOpCode(*it) == OpCode::IF_TRUE) {
|
|
acc_.SetOpCode(*it, OpCode::ORDINARY_BLOCK);
|
|
acc_.ReplaceIn(it, mergeTrueState);
|
|
} else if (acc_.GetOpCode(*it) == OpCode::IF_FALSE) {
|
|
acc_.SetOpCode(*it, OpCode::ORDINARY_BLOCK);
|
|
acc_.ReplaceIn(it, mergeFalseState);
|
|
} else if (((acc_.GetOpCode(*it) == OpCode::DEPEND_SELECTOR) ||
|
|
(acc_.GetOpCode(*it) == OpCode::DEPEND_RELAY)) &&
|
|
(acc_.GetOpCode(acc_.GetIn(acc_.GetIn(*it, 0), it.GetIndex() - 1)) != OpCode::IF_EXCEPTION)) {
|
|
acc_.ReplaceIn(it, acc_.GetDep(gate));
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
// delete old gate
|
|
circuit_->DeleteGate(gate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGetNextPropName(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(GetNextPropName);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef iter = acc_.GetValueIn(gate, 0);
|
|
GateRef newGate = LowerCallRuntime(glue, id, { iter });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCopyDataProperties(GateRef gate, GateRef glue)
|
|
{
|
|
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(glue, id, { dst, src });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCreateObjectWithExcludedKeys(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(CreateObjectWithExcludedKeys);
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
GateRef numKeys = acc_.GetValueIn(gate, 0);
|
|
GateRef obj = acc_.GetValueIn(gate, 1);
|
|
GateRef firstArgRegIdx = acc_.GetValueIn(gate, 2);
|
|
auto args = { builder_.TaggedTypeNGC(numKeys), obj, builder_.TaggedTypeNGC(firstArgRegIdx) };
|
|
GateRef newGate = LowerCallRuntime(glue, id, args);
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCreateRegExpWithLiteral(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(CreateRegExpWithLiteral);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef pattern = GetValueFromConstStringTable(glue, gate, 0);
|
|
GateRef flags = acc_.GetValueIn(gate, 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, { pattern, builder_.TaggedTypeNGC(flags) });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStOwnByValue(GateRef gate, GateRef glue)
|
|
{
|
|
// 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 result;
|
|
Label isHeapObject(&builder_);
|
|
Label slowPath(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
|
|
builder_.Bind(&isHeapObject);
|
|
Label notClassConstructor(&builder_);
|
|
builder_.Branch(builder_.IsClassConstructor(receiver), &slowPath, ¬ClassConstructor);
|
|
builder_.Bind(¬ClassConstructor);
|
|
Label notClassPrototype(&builder_);
|
|
builder_.Branch(builder_.IsClassPrototype(receiver), &slowPath, ¬ClassPrototype);
|
|
builder_.Bind(¬ClassPrototype);
|
|
{
|
|
result = builder_.CallStub(glue, CommonStubCSigns::SetPropertyByValueWithOwn,
|
|
{ glue, receiver, propKey, accValue });
|
|
Label notHole(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_HOLE), &slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(StOwnByValue), { receiver, propKey, accValue }, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
// stOwnByValue will not be inValue to other hir gates, result gate will be ignored
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStOwnByIndex(GateRef gate, GateRef glue)
|
|
{
|
|
// 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 result;
|
|
Label isHeapObject(&builder_);
|
|
Label slowPath(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
|
|
builder_.Bind(&isHeapObject);
|
|
Label notClassConstructor(&builder_);
|
|
builder_.Branch(builder_.IsClassConstructor(receiver), &slowPath, ¬ClassConstructor);
|
|
builder_.Bind(¬ClassConstructor);
|
|
Label notClassPrototype(&builder_);
|
|
builder_.Branch(builder_.IsClassPrototype(receiver), &slowPath, ¬ClassPrototype);
|
|
builder_.Bind(¬ClassPrototype);
|
|
{
|
|
result = builder_.CallStub(glue, CommonStubCSigns::SetPropertyByIndexWithOwn,
|
|
{ glue, receiver, builder_.TruncInt64ToInt32(index), accValue });
|
|
Label notHole(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_HOLE), &slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
auto args = {receiver, builder_.TaggedTypeNGC(index), accValue };
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(StOwnByIndex), args, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
// StOwnByIndex will not be inValue to other hir gates, result gate will be ignored
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStOwnByName(GateRef gate, GateRef glue)
|
|
{
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
auto args = { builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0))) };
|
|
GateRef propKey = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), args, true);
|
|
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 result;
|
|
Label isJsObject(&builder_);
|
|
Label slowPath(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.IsJsObject(receiver), &isJsObject, &slowPath);
|
|
builder_.Bind(&isJsObject);
|
|
Label notClassConstructor(&builder_);
|
|
builder_.Branch(builder_.IsClassConstructor(receiver), &slowPath, ¬ClassConstructor);
|
|
builder_.Bind(¬ClassConstructor);
|
|
Label notClassPrototype(&builder_);
|
|
builder_.Branch(builder_.IsClassPrototype(receiver), &slowPath, ¬ClassPrototype);
|
|
builder_.Bind(¬ClassPrototype);
|
|
{
|
|
result = builder_.CallStub(glue, CommonStubCSigns::SetPropertyByNameWithOwn,
|
|
{ glue, receiver, propKey, accValue });
|
|
Label notHole(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_HOLE), &slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(StOwnByName), {receiver, propKey, accValue }, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
// StOwnByName will not be inValue to other hir gates, result gate will be ignored
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDefineGeneratorFunc(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
GateRef methodId = builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 0));
|
|
GateRef firstMethod = GetObjectFromConstPool(jsFunc, methodId);
|
|
DEFVAlUE(method, (&builder_), VariableType::JS_POINTER(), firstMethod);
|
|
GateRef length = acc_.GetValueIn(gate, 1);
|
|
GateRef lexEnv = acc_.GetValueIn(gate, 2);
|
|
GateRef result;
|
|
Label isResolved(&builder_);
|
|
Label notResolved(&builder_);
|
|
Label defaultLabel(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.FunctionIsResolved(*method), &isResolved, ¬Resolved);
|
|
builder_.Bind(&isResolved);
|
|
{
|
|
method = LowerCallRuntime(glue, RTSTUB_ID(DefineGeneratorFunc), { *method });
|
|
Label notException(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(*method, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, ¬Exception);
|
|
builder_.Bind(¬Exception);
|
|
{
|
|
builder_.SetConstPoolToFunction(glue, *method, GetConstPool(jsFunc));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
}
|
|
builder_.Bind(¬Resolved);
|
|
{
|
|
builder_.SetResolvedToFunction(glue, *method, builder_.Boolean(true));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
builder_.Bind(&defaultLabel);
|
|
{
|
|
GateRef hclass = builder_.LoadHClass(*method);
|
|
builder_.SetPropertyInlinedProps(glue, *method, hclass, builder_.TaggedNGC(length),
|
|
builder_.Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::INT64());
|
|
builder_.SetLexicalEnvToFunction(glue, *method, lexEnv);
|
|
builder_.SetModuleToFunction(glue, *method, builder_.GetModuleFromFunction(jsFunc));
|
|
result = *method;
|
|
builder_.Jump(&successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDefineAsyncFunc(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
GateRef methodId = builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 0));
|
|
GateRef firstMethod = GetObjectFromConstPool(jsFunc, methodId);
|
|
DEFVAlUE(method, (&builder_), VariableType::JS_POINTER(), firstMethod);
|
|
GateRef length = acc_.GetValueIn(gate, 1);
|
|
GateRef lexEnv = acc_.GetValueIn(gate, 2);
|
|
GateRef result;
|
|
Label isResolved(&builder_);
|
|
Label notResolved(&builder_);
|
|
Label defaultLabel(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.FunctionIsResolved(*method), &isResolved, ¬Resolved);
|
|
builder_.Bind(&isResolved);
|
|
{
|
|
method = LowerCallRuntime(glue, RTSTUB_ID(DefineAsyncFunc), { *method }, true);
|
|
Label notException(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(*method, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, ¬Exception);
|
|
builder_.Bind(¬Exception);
|
|
{
|
|
builder_.SetConstPoolToFunction(glue, *method, GetConstPool(jsFunc));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
}
|
|
builder_.Bind(¬Resolved);
|
|
{
|
|
builder_.SetResolvedToFunction(glue, *method, builder_.Boolean(true));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
builder_.Bind(&defaultLabel);
|
|
{
|
|
GateRef hclass = builder_.LoadHClass(*method);
|
|
builder_.SetPropertyInlinedProps(glue, *method, hclass, builder_.TaggedNGC(length),
|
|
builder_.Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::INT64());
|
|
builder_.SetLexicalEnvToFunction(glue, *method, lexEnv);
|
|
builder_.SetModuleToFunction(glue, *method, builder_.GetModuleFromFunction(jsFunc));
|
|
result = *method;
|
|
builder_.Jump(&successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerNewLexicalEnvDyn(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef lexEnv = LowerCallRuntime(glue, RTSTUB_ID(GetAotLexicalEnv), {jsFunc}, true);
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(NewAotLexicalEnvDyn),
|
|
{builder_.TaggedTypeNGC(acc_.GetValueIn(gate, 0)), lexEnv}, true);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerNewLexicalEnvWithNameDyn(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef lexEnv = LowerCallRuntime(glue, RTSTUB_ID(GetAotLexicalEnv), {jsFunc}, true);
|
|
auto args = { builder_.TaggedTypeNGC(acc_.GetValueIn(gate, 0)),
|
|
builder_.TaggedTypeNGC(acc_.GetValueIn(gate, 1)),
|
|
lexEnv};
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(NewAotLexicalEnvWithNameDyn), args, true);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerPopLexicalEnv(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(GetAotLexicalEnv), {jsFunc}, true);
|
|
GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
|
|
GateRef parentLexEnv = builder_.GetValueFromTaggedArray(VariableType::JS_ANY(), result, index);
|
|
builder_.SetLexicalEnvToFunction(glue, jsFunc, parentLexEnv);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdSuperByValue(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
const int id = RTSTUB_ID(LdSuperByValue);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef receiver = acc_.GetValueIn(gate, 0);
|
|
GateRef propKey = acc_.GetValueIn(gate, 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, { receiver, propKey, jsFunc });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStSuperByValue(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
const int id = RTSTUB_ID(StSuperByValue);
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
GateRef receiver = acc_.GetValueIn(gate, 0);
|
|
GateRef propKey = acc_.GetValueIn(gate, 1);
|
|
GateRef value = acc_.GetValueIn(gate, 2);
|
|
GateRef newGate = LowerCallRuntime(glue, id, { receiver, propKey, value, jsFunc});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerTryStGlobalByName(GateRef gate, GateRef glue)
|
|
{
|
|
// order: 1. global record 2. global object
|
|
DEFVAlUE(res, (&builder_), VariableType::JS_ANY(), builder_.Int64(JSTaggedValue::VALUE_HOLE));
|
|
// 2 : number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef stringId = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0)));
|
|
GateRef propKey = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), { stringId }, true);
|
|
Label isUndefined(&builder_);
|
|
Label notUndefined(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
|
|
// order: 1. global record 2. global object
|
|
GateRef value = acc_.GetValueIn(gate, 1);
|
|
GateRef recordInfo = LowerCallRuntime(glue, RTSTUB_ID(LdGlobalRecord), { propKey }, true);
|
|
builder_.Branch(builder_.IsSpecial(recordInfo, JSTaggedValue::VALUE_UNDEFINED),
|
|
&isUndefined, ¬Undefined);
|
|
builder_.Bind(¬Undefined);
|
|
{
|
|
res = LowerCallRuntime(glue, RTSTUB_ID(TryUpdateGlobalRecord), { propKey, value }, true);
|
|
builder_.Branch(builder_.IsSpecial(*res, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&isUndefined);
|
|
{
|
|
Label isHole(&builder_);
|
|
Label notHole(&builder_);
|
|
GateRef globalResult = LowerCallRuntime(glue, RTSTUB_ID(GetGlobalOwnProperty), { propKey }, true);
|
|
builder_.Branch(builder_.IsSpecial(globalResult, JSTaggedValue::VALUE_HOLE), &isHole, ¬Hole);
|
|
builder_.Bind(&isHole);
|
|
{
|
|
res = LowerCallRuntime(glue, RTSTUB_ID(ThrowReferenceError), { propKey }, true);
|
|
builder_.Branch(builder_.IsSpecial(*res, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(¬Hole);
|
|
{
|
|
res = LowerCallRuntime(glue, RTSTUB_ID(StGlobalVar), { propKey, value }, true);
|
|
builder_.Branch(builder_.IsSpecial(*res, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit);
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStConstToGlobalRecord(GateRef gate, GateRef glue)
|
|
{
|
|
GateRef propKey = GetValueFromConstStringTable(glue, gate, 0);
|
|
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 isConst = builder_.TaggedTrue();
|
|
GateRef newGate = LowerCallRuntime(glue, id, { propKey, value, isConst });
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStLetToGlobalRecord(GateRef gate, GateRef glue)
|
|
{
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef stringId = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0)));
|
|
GateRef prop = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), { stringId }, true);
|
|
GateRef taggedFalse = builder_.TaggedFalse();
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(StGlobalRecord),
|
|
{prop, acc_.GetValueIn(gate, 1), taggedFalse}, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStClassToGlobalRecord(GateRef gate, GateRef glue)
|
|
{
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef stringId = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0)));
|
|
GateRef prop = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), { stringId }, true);
|
|
GateRef taggedFalse = builder_.TaggedFalse();
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(StGlobalRecord),
|
|
{prop, acc_.GetValueIn(gate, 1), taggedFalse}, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStOwnByValueWithNameSet(GateRef gate, GateRef glue)
|
|
{
|
|
// 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 isHeapObject(&builder_);
|
|
Label slowPath(&builder_);
|
|
Label notClassConstructor(&builder_);
|
|
Label notClassPrototype(&builder_);
|
|
Label notHole(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
GateRef res;
|
|
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
|
|
builder_.Bind(&isHeapObject);
|
|
{
|
|
builder_.Branch(builder_.IsClassConstructor(receiver), &slowPath, ¬ClassConstructor);
|
|
builder_.Bind(¬ClassConstructor);
|
|
{
|
|
builder_.Branch(builder_.IsClassPrototype(receiver), &slowPath, ¬ClassPrototype);
|
|
builder_.Bind(¬ClassPrototype);
|
|
{
|
|
res = builder_.CallStub(glue, CommonStubCSigns::SetPropertyByValue,
|
|
{ glue, receiver, propKey, accValue });
|
|
builder_.Branch(builder_.IsSpecial(res, JSTaggedValue::VALUE_HOLE),
|
|
&slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
{
|
|
Label notexception(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(res, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, ¬exception);
|
|
builder_.Bind(¬exception);
|
|
LowerCallRuntime(glue, RTSTUB_ID(SetFunctionNameNoPrefix), { accValue, propKey }, true);
|
|
builder_.Jump(&successExit);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
res = LowerCallRuntime(glue, RTSTUB_ID(StOwnByValueWithNameSet), { receiver, propKey, accValue }, true);
|
|
builder_.Branch(builder_.IsSpecial(res, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStOwnByNameWithNameSet(GateRef gate, GateRef glue)
|
|
{
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
GateRef stringId = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0)));
|
|
GateRef propKey = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), { stringId }, true);
|
|
GateRef receiver = acc_.GetValueIn(gate, 1);
|
|
GateRef accValue = acc_.GetValueIn(gate, 2);
|
|
GateRef result;
|
|
Label isJsObject(&builder_);
|
|
Label notJSObject(&builder_);
|
|
Label notClassConstructor(&builder_);
|
|
Label notClassPrototype(&builder_);
|
|
Label notHole(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.IsJsObject(receiver), &isJsObject, ¬JSObject);
|
|
builder_.Bind(&isJsObject);
|
|
{
|
|
builder_.Branch(builder_.IsClassConstructor(receiver), ¬JSObject, ¬ClassConstructor);
|
|
builder_.Bind(¬ClassConstructor);
|
|
{
|
|
builder_.Branch(builder_.IsClassPrototype(receiver), ¬JSObject, ¬ClassPrototype);
|
|
builder_.Bind(¬ClassPrototype);
|
|
{
|
|
result = builder_.CallStub(glue, CommonStubCSigns::SetPropertyByNameWithOwn,
|
|
{ glue, receiver, propKey, accValue });
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_HOLE),
|
|
¬JSObject, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
{
|
|
Label notException(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, ¬Exception);
|
|
builder_.Bind(¬Exception);
|
|
LowerCallRuntime(glue, RTSTUB_ID(SetFunctionNameNoPrefix), {accValue, propKey}, true);
|
|
builder_.Jump(&successExit);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
builder_.Bind(¬JSObject);
|
|
{
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(StOwnByNameWithNameSet), { receiver, propKey, accValue }, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit);
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdGlobalVar(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
Label slowPath(&builder_);
|
|
GateRef ret;
|
|
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef stringId = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0)));
|
|
GateRef propKey = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), { stringId }, true);
|
|
GateRef globalObject = builder_.GetGlobalObject(glue);
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(GetGlobalOwnProperty), { propKey }, true);
|
|
builder_.Branch(builder_.IsSpecial(*result, JSTaggedValue::VALUE_HOLE),
|
|
&slowPath, &successExit);
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(LdGlobalVar), { globalObject, propKey }, true);
|
|
builder_.Branch(builder_.IsSpecial(*result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&successExit);
|
|
{
|
|
ret = *result;
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
builder_.Bind(&exceptionExit);
|
|
{
|
|
failControl.emplace_back(builder_.GetState());
|
|
failControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
ReplaceHirToSubCfg(gate, ret, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdObjByName(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
GateRef holeConst = builder_.HoleConstant();
|
|
DEFVAlUE(varAcc, (&builder_), VariableType::JS_ANY(), holeConst);
|
|
GateRef result;
|
|
Label receiverIsHeapObject(&builder_);
|
|
Label slowPath(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef receiver = acc_.GetValueIn(gate, 1);
|
|
GateRef stringId = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0)));
|
|
GateRef prop = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), {stringId}, true);
|
|
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &receiverIsHeapObject, &slowPath);
|
|
builder_.Bind(&receiverIsHeapObject);
|
|
{
|
|
varAcc = builder_.CallStub(glue, CommonStubCSigns::GetPropertyByName,
|
|
{glue, receiver, prop});
|
|
Label notHole(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(*varAcc, JSTaggedValue::VALUE_HOLE), &slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
builder_.Branch(builder_.IsSpecial(*varAcc, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
GateRef undefined = builder_.UndefineConstant();
|
|
varAcc = LowerCallRuntime(glue, RTSTUB_ID(LoadICByName), {undefined,
|
|
receiver, prop, undefined}, true);
|
|
builder_.Branch(builder_.IsSpecial(*varAcc, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&successExit);
|
|
{
|
|
result = *varAcc;
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
builder_.Bind(&exceptionExit);
|
|
{
|
|
failControl.emplace_back(builder_.GetState());
|
|
failControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStObjByName(GateRef gate, GateRef glue)
|
|
{
|
|
Label receiverIsHeapObject(&builder_);
|
|
Label slowPath(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
GateRef stringId = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0)));
|
|
GateRef prop = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), {stringId}, true);
|
|
GateRef receiver = acc_.GetValueIn(gate, 1);
|
|
GateRef result;
|
|
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &receiverIsHeapObject, &slowPath);
|
|
builder_.Bind(&receiverIsHeapObject);
|
|
{
|
|
result = builder_.CallStub(glue, CommonStubCSigns::SetPropertyByName,
|
|
{glue, receiver, prop, acc_.GetValueIn(gate, 2)});
|
|
Label notHole(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_HOLE), &slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
GateRef undefined = builder_.UndefineConstant();
|
|
auto args = { undefined, receiver, prop, acc_.GetValueIn(gate, 2), undefined };
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(StoreICByName), args, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDefineGetterSetterByValue(GateRef gate, GateRef glue)
|
|
{
|
|
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 };
|
|
GateRef newGate = LowerCallRuntime(glue, id, args);
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdObjByIndex(GateRef gate, GateRef glue)
|
|
{
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
GateRef holeConst = builder_.HoleConstant();
|
|
DEFVAlUE(varAcc, (&builder_), VariableType::JS_ANY(), holeConst);
|
|
GateRef result;
|
|
GateRef receiver = acc_.GetValueIn(gate, 0);
|
|
GateRef index = acc_.GetValueIn(gate, 1);
|
|
Label fastPath(&builder_);
|
|
Label slowPath(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &fastPath, &slowPath);
|
|
builder_.Bind(&fastPath);
|
|
{
|
|
varAcc = builder_.CallStub(glue, CommonStubCSigns::GetPropertyByIndex,
|
|
{glue, receiver, builder_.TruncInt64ToInt32(index)});
|
|
Label notHole(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(*varAcc, JSTaggedValue::VALUE_HOLE), &slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
builder_.Branch(builder_.IsSpecial(*varAcc, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
GateRef undefined = builder_.UndefineConstant();
|
|
auto args = { receiver, builder_.TaggedTypeNGC(index),
|
|
builder_.TaggedFalse(), builder_.TaggedTypeNGC(undefined) };
|
|
varAcc = LowerCallRuntime(glue, RTSTUB_ID(LdObjByIndex), args);
|
|
builder_.Branch(builder_.IsSpecial(*varAcc, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&successExit);
|
|
{
|
|
result = *varAcc;
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
builder_.Bind(&exceptionExit);
|
|
{
|
|
failControl.emplace_back(builder_.GetState());
|
|
failControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStObjByIndex(GateRef gate, GateRef glue)
|
|
{
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
Label fastPath(&builder_);
|
|
Label slowPath(&builder_);
|
|
GateRef receiver = acc_.GetValueIn(gate, 0);
|
|
GateRef index = acc_.GetValueIn(gate, 1);
|
|
GateRef accValue = acc_.GetValueIn(gate, 2);
|
|
GateRef result;
|
|
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &fastPath, &slowPath);
|
|
builder_.Bind(&fastPath);
|
|
{
|
|
result = builder_.CallStub(glue, CommonStubCSigns::SetPropertyByIndex,
|
|
{glue, receiver, builder_.TruncInt64ToInt32(index), accValue});
|
|
Label notHole(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_HOLE), &slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(StObjByIndex),
|
|
{receiver, builder_.TaggedTypeNGC(index), accValue}, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdObjByValue(GateRef gate, GateRef glue)
|
|
{
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef receiver = acc_.GetValueIn(gate, 0);
|
|
GateRef propKey = acc_.GetValueIn(gate, 1);
|
|
GateRef holeConst = builder_.HoleConstant();
|
|
DEFVAlUE(varAcc, (&builder_), VariableType::JS_ANY(), holeConst);
|
|
GateRef result;
|
|
Label isHeapObject(&builder_);
|
|
Label slowPath(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
|
|
builder_.Bind(&isHeapObject);
|
|
{
|
|
varAcc = builder_.CallStub(glue, CommonStubCSigns::GetPropertyByValue,
|
|
{glue, receiver, propKey});
|
|
Label notHole(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(*varAcc, JSTaggedValue::VALUE_HOLE), &slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
builder_.Branch(builder_.IsSpecial(*varAcc, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
GateRef undefined = builder_.UndefineConstant();
|
|
varAcc = LowerCallRuntime(glue, RTSTUB_ID(LoadICByValue), {undefined, receiver, propKey,
|
|
builder_.TaggedTypeNGC(undefined)});
|
|
builder_.Branch(builder_.IsSpecial(*varAcc, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&successExit);
|
|
{
|
|
result = *varAcc;
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
builder_.Bind(&exceptionExit);
|
|
{
|
|
failControl.emplace_back(builder_.GetState());
|
|
failControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStObjByValue(GateRef gate, GateRef glue)
|
|
{
|
|
// 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 result;
|
|
Label isHeapObject(&builder_);
|
|
Label slowPath(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
|
|
builder_.Bind(&isHeapObject);
|
|
{
|
|
result = builder_.CallStub(glue, CommonStubCSigns::SetPropertyByValue, {glue, receiver, propKey, accValue});
|
|
Label notHole(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_HOLE), &slowPath, ¬Hole);
|
|
builder_.Bind(¬Hole);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
builder_.Bind(&slowPath);
|
|
{
|
|
GateRef undefined = builder_.UndefineConstant();
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(StoreICByValue), {undefined, receiver, propKey, accValue,
|
|
builder_.TaggedTypeNGC(undefined)});
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
// stObjByValue will not be inValue to other hir gates, result gate will be ignored
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdSuperByName(GateRef gate, GateRef glue)
|
|
{
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
auto args1 = { builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0))) };
|
|
GateRef prop = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), args1, true);
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(LdSuperByValue), {prop, acc_.GetValueIn(gate, 1)}, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStSuperByName(GateRef gate, GateRef glue)
|
|
{
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
// 3: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
|
auto args1 = { builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(acc_.GetValueIn(gate, 0))) };
|
|
GateRef prop = LowerCallRuntime(glue, RTSTUB_ID(LoadValueFromConstantStringTable), args1, true);
|
|
auto args2 = { prop, acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2) };
|
|
GateRef result = LowerCallRuntime(glue, RTSTUB_ID(StSuperByValue), args2, true);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCreateGeneratorObj(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(CreateGeneratorObj);
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0)});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStArraySpread(GateRef gate, GateRef glue)
|
|
{
|
|
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(glue, id, args);
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdLexVarDyn(GateRef gate, GateRef jsFunc)
|
|
{
|
|
// 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));
|
|
DEFVAlUE(currentEnv, (&builder_), VariableType::JS_ANY(), GetCurrentEnv(jsFunc));
|
|
DEFVAlUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> exceptionControl;
|
|
|
|
Label loopHead(&builder_);
|
|
Label loopEnd(&builder_);
|
|
Label afterLoop(&builder_);
|
|
builder_.Branch(builder_.Int32LessThan(*i, level), &loopHead, &afterLoop);
|
|
builder_.LoopBegin(&loopHead);
|
|
GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
|
|
currentEnv = builder_.GetValueFromTaggedArray(VariableType::JS_ANY(), *currentEnv, index);
|
|
i = builder_.Int32Add(*i, builder_.Int32(1));
|
|
builder_.Branch(builder_.Int32LessThan(*i, level), &loopEnd, &afterLoop);
|
|
builder_.Bind(&loopEnd);
|
|
builder_.LoopEnd(&loopHead);
|
|
builder_.Bind(&afterLoop);
|
|
GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(LexicalEnv::RESERVED_ENV_LENGTH));
|
|
GateRef result = builder_.GetValueFromTaggedArray(VariableType::JS_ANY(), *currentEnv, valueIndex);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
exceptionControl.emplace_back(Circuit::NullGate());
|
|
exceptionControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, result, successControl, exceptionControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerStLexVarDyn(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
// 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);
|
|
DEFVAlUE(currentEnv, (&builder_), VariableType::JS_ANY(), GetCurrentEnv(jsFunc));
|
|
DEFVAlUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> exceptionControl;
|
|
Label loopHead(&builder_);
|
|
Label loopEnd(&builder_);
|
|
Label afterLoop(&builder_);
|
|
builder_.Branch(builder_.Int32LessThan(*i, level), &loopHead, &afterLoop);
|
|
builder_.LoopBegin(&loopHead);
|
|
GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
|
|
currentEnv = builder_.GetValueFromTaggedArray(VariableType::JS_ANY(), *currentEnv, index);
|
|
i = builder_.Int32Add(*i, builder_.Int32(1));
|
|
builder_.Branch(builder_.Int32LessThan(*i, level), &loopEnd, &afterLoop);
|
|
builder_.Bind(&loopEnd);
|
|
builder_.LoopEnd(&loopHead);
|
|
builder_.Bind(&afterLoop);
|
|
GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(LexicalEnv::RESERVED_ENV_LENGTH));
|
|
builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue, *currentEnv, valueIndex, value);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
exceptionControl.emplace_back(Circuit::NullGate());
|
|
exceptionControl.emplace_back(Circuit::NullGate());
|
|
// StLexVarDyn will not be inValue to other hir gates, result gate will be ignored
|
|
ReplaceHirToSubCfg(gate, Circuit::NullGate(), successControl, exceptionControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCreateObjectHavingMethod(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
const int id = RTSTUB_ID(CreateObjectHavingMethod);
|
|
// 2: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
|
GateRef imm = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
|
|
GateRef literal = GetObjectFromConstPool(jsFunc, imm);
|
|
GateRef env = acc_.GetValueIn(gate, 1);
|
|
GateRef constpool = GetConstPool(jsFunc);
|
|
GateRef result = LowerCallRuntime(glue, id, { literal, env, constpool });
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, &successExit);
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerLdHomeObject(GateRef gate, GateRef jsFunc)
|
|
{
|
|
GateRef homeObj = GetHomeObjectFromJSFunction(jsFunc);
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> exceptionControl;
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
exceptionControl.emplace_back(Circuit::NullGate());
|
|
exceptionControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, homeObj, successControl, exceptionControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDefineClassWithBuffer(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
// 5: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 5);
|
|
GateRef methodId = builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 0));
|
|
GateRef length = acc_.GetValueIn(gate, 2);
|
|
|
|
GateRef classTemplate = GetObjectFromConstPool(jsFunc, methodId);
|
|
GateRef lexicalEnv = acc_.GetValueIn(gate, 3);
|
|
GateRef proto = acc_.GetValueIn(gate, 4);
|
|
GateRef constpool = GetConstPool(jsFunc);
|
|
|
|
DEFVAlUE(res, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
|
|
|
|
Label isResolved(&builder_);
|
|
Label isNotResolved(&builder_);
|
|
auto argsCloneClass = { classTemplate, proto, lexicalEnv, constpool };
|
|
res = LowerCallRuntime(glue, RTSTUB_ID(CloneClassFromTemplate), argsCloneClass, true);
|
|
Label isException(&builder_);
|
|
Label isNotException(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(*res, JSTaggedValue::VALUE_EXCEPTION),
|
|
&isException, &isNotException);
|
|
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> exceptionControl;
|
|
builder_.Bind(&isException);
|
|
{
|
|
exceptionControl.emplace_back(builder_.GetState());
|
|
exceptionControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
builder_.Bind(&isNotException);
|
|
GateRef newLexicalEnv = acc_.GetValueIn(gate, 3);
|
|
builder_.SetLexicalEnvToFunction(glue, *res, newLexicalEnv);
|
|
auto args = { *res, builder_.TaggedTypeNGC(length) };
|
|
LowerCallRuntime(glue, RTSTUB_ID(SetClassConstructorLength), args, true);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
ReplaceHirToSubCfg(gate, *res, successControl, exceptionControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDefineFuncDyn(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
GateRef methodId = acc_.GetValueIn(gate, 0);
|
|
GateRef length = acc_.GetValueIn(gate, 1);
|
|
GateRef v0 = acc_.GetValueIn(gate, 2);
|
|
DEFVAlUE(result, (&builder_),
|
|
VariableType::JS_POINTER(), GetObjectFromConstPool(jsFunc, builder_.ZExtInt16ToInt32(methodId)));
|
|
Label isResolved(&builder_);
|
|
Label notResolved(&builder_);
|
|
Label defaultLabel(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
GateRef ret;
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
builder_.Branch(builder_.FunctionIsResolved(*result), &isResolved, ¬Resolved);
|
|
builder_.Bind(&isResolved);
|
|
{
|
|
result = LowerCallRuntime(glue, RTSTUB_ID(DefinefuncDyn), { *result });
|
|
Label isException(&builder_);
|
|
Label notException(&builder_);
|
|
builder_.Branch(builder_.TaggedIsException(*result), &isException, ¬Exception);
|
|
builder_.Bind(&isException);
|
|
{
|
|
builder_.Jump(&exceptionExit);
|
|
}
|
|
builder_.Bind(¬Exception);
|
|
{
|
|
builder_.SetConstPoolToFunction(glue, *result, GetConstPool(jsFunc));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
}
|
|
builder_.Bind(¬Resolved);
|
|
{
|
|
builder_.SetResolvedToFunction(glue, *result, builder_.Boolean(true));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
builder_.Bind(&defaultLabel);
|
|
{
|
|
GateRef hClass = builder_.LoadHClass(*result);
|
|
builder_.SetPropertyInlinedProps(glue, *result, hClass, builder_.TaggedNGC(length),
|
|
builder_.Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::INT64());
|
|
builder_.SetLexicalEnvToFunction(glue, *result, v0);
|
|
builder_.SetModuleToFunction(glue, *result, builder_.GetModuleFromFunction(jsFunc));
|
|
builder_.Jump(&successExit);
|
|
}
|
|
builder_.Bind(&successExit);
|
|
{
|
|
ret = *result;
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
builder_.Bind(&exceptionExit);
|
|
{
|
|
failControl.emplace_back(builder_.GetState());
|
|
failControl.emplace_back(builder_.GetDepend());
|
|
}
|
|
ReplaceHirToSubCfg(gate, ret, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerAsyncFunctionEnter(GateRef gate, GateRef glue)
|
|
{
|
|
const int id = RTSTUB_ID(AsyncFunctionEnter);
|
|
// 0: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 0);
|
|
GateRef newGate = LowerCallRuntime(glue, id, {});
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerTypeOfDyn(GateRef gate, GateRef glue)
|
|
{
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
GateRef obj = acc_.GetValueIn(gate, 0);
|
|
Label entry(&builder_);
|
|
Label exit(&builder_);
|
|
|
|
GateRef gConstAddr = builder_.PtrAdd(glue,
|
|
builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(builder_.GetCompilationConfig()->Is32Bit())));
|
|
GateRef undefinedIndex = builder_.GetGlobalConstantString(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_.GetGlobalConstantString(ConstantIndex::BOOLEAN_STRING_INDEX));
|
|
builder_.Branch(builder_.TaggedIsTrue(obj), &objIsTrue, &objNotTrue);
|
|
builder_.Bind(&objIsTrue);
|
|
{
|
|
result = gConstBooleanStr;
|
|
builder_.Jump(&exit);
|
|
}
|
|
builder_.Bind(&objNotTrue);
|
|
{
|
|
Label objIsFalse(&builder_);
|
|
Label objNotFalse(&builder_);
|
|
builder_.Branch(builder_.TaggedIsFalse(obj), &objIsFalse, &objNotFalse);
|
|
builder_.Bind(&objIsFalse);
|
|
{
|
|
result = gConstBooleanStr;
|
|
builder_.Jump(&exit);
|
|
}
|
|
builder_.Bind(&objNotFalse);
|
|
{
|
|
Label objIsNull(&builder_);
|
|
Label objNotNull(&builder_);
|
|
builder_.Branch(builder_.TaggedIsNull(obj), &objIsNull, &objNotNull);
|
|
builder_.Bind(&objIsNull);
|
|
{
|
|
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
|
builder_.GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
|
|
builder_.Jump(&exit);
|
|
}
|
|
builder_.Bind(&objNotNull);
|
|
{
|
|
Label objIsUndefined(&builder_);
|
|
Label objNotUndefined(&builder_);
|
|
builder_.Branch(builder_.TaggedIsUndefined(obj), &objIsUndefined, &objNotUndefined);
|
|
builder_.Bind(&objIsUndefined);
|
|
{
|
|
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
|
builder_.GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX));
|
|
builder_.Jump(&exit);
|
|
}
|
|
builder_.Bind(&objNotUndefined);
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
}
|
|
}
|
|
builder_.Bind(&defaultLabel);
|
|
{
|
|
Label objIsHeapObject(&builder_);
|
|
Label objNotHeapObject(&builder_);
|
|
builder_.Branch(builder_.TaggedIsHeapObject(obj), &objIsHeapObject, &objNotHeapObject);
|
|
builder_.Bind(&objIsHeapObject);
|
|
{
|
|
Label objIsString(&builder_);
|
|
Label objNotString(&builder_);
|
|
builder_.Branch(builder_.IsJsType(obj, JSType::STRING), &objIsString, &objNotString);
|
|
builder_.Bind(&objIsString);
|
|
{
|
|
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
|
builder_.GetGlobalConstantString(ConstantIndex::STRING_STRING_INDEX));
|
|
builder_.Jump(&exit);
|
|
}
|
|
builder_.Bind(&objNotString);
|
|
{
|
|
Label objIsSymbol(&builder_);
|
|
Label objNotSymbol(&builder_);
|
|
builder_.Branch(builder_.IsJsType(obj, JSType::SYMBOL), &objIsSymbol, &objNotSymbol);
|
|
builder_.Bind(&objIsSymbol);
|
|
{
|
|
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
|
builder_.GetGlobalConstantString(ConstantIndex::SYMBOL_STRING_INDEX));
|
|
builder_.Jump(&exit);
|
|
}
|
|
builder_.Bind(&objNotSymbol);
|
|
{
|
|
Label objIsCallable(&builder_);
|
|
Label objNotCallable(&builder_);
|
|
builder_.Branch(builder_.IsCallable(obj), &objIsCallable, &objNotCallable);
|
|
builder_.Bind(&objIsCallable);
|
|
{
|
|
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
|
builder_.GetGlobalConstantString(ConstantIndex::FUNCTION_STRING_INDEX));
|
|
builder_.Jump(&exit);
|
|
}
|
|
builder_.Bind(&objNotCallable);
|
|
{
|
|
Label objIsBigInt(&builder_);
|
|
Label objNotBigInt(&builder_);
|
|
builder_.Branch(builder_.IsJsType(obj, JSType::BIGINT), &objIsBigInt, &objNotBigInt);
|
|
builder_.Bind(&objIsBigInt);
|
|
{
|
|
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
|
builder_.GetGlobalConstantString(ConstantIndex::BIGINT_STRING_INDEX));
|
|
builder_.Jump(&exit);
|
|
}
|
|
builder_.Bind(&objNotBigInt);
|
|
{
|
|
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
|
builder_.GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX));
|
|
builder_.Jump(&exit);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
builder_.Bind(&objNotHeapObject);
|
|
{
|
|
Label objIsNum(&builder_);
|
|
Label objNotNum(&builder_);
|
|
builder_.Branch(builder_.TaggedIsNumber(obj), &objIsNum, &objNotNum);
|
|
builder_.Bind(&objIsNum);
|
|
{
|
|
result = builder_.Load(VariableType::JS_POINTER(), gConstAddr,
|
|
builder_.GetGlobalConstantString(ConstantIndex::NUMBER_STRING_INDEX));
|
|
builder_.Jump(&exit);
|
|
}
|
|
builder_.Bind(&objNotNum);
|
|
builder_.Jump(&exit);
|
|
}
|
|
}
|
|
builder_.Bind(&exit);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, *result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerResumeGenerator(GateRef gate)
|
|
{
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
GateRef obj = acc_.GetValueIn(gate, 0);
|
|
GateRef resumeResultOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_RESUME_RESULT_OFFSET);
|
|
GateRef result = builder_.Load(VariableType::JS_ANY(), obj, resumeResultOffset);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGetResumeMode(GateRef gate)
|
|
{
|
|
// 1: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
|
std::vector<GateRef> successControl;
|
|
std::vector<GateRef> failControl;
|
|
GateRef obj = acc_.GetValueIn(gate, 0);
|
|
GateRef bitFieldOffset = builder_.IntPtr(JSGeneratorObject::BIT_FIELD_OFFSET);
|
|
GateRef bitField = builder_.Load(VariableType::INT64(), obj, bitFieldOffset);
|
|
auto bitfieldlsr = builder_.Int32LSR(builder_.TruncInt64ToInt32(bitField),
|
|
builder_.Int32(JSGeneratorObject::ResumeModeBits::START_BIT));
|
|
GateRef resumeModeBits = builder_.Int32And(
|
|
bitfieldlsr,
|
|
builder_.Int32((1LU << JSGeneratorObject::ResumeModeBits::SIZE) - 1));
|
|
auto resumeMode = builder_.ZExtInt32ToInt64(resumeModeBits);
|
|
GateRef result = builder_.TaggedTypeNGC(resumeMode);
|
|
successControl.emplace_back(builder_.GetState());
|
|
successControl.emplace_back(builder_.GetDepend());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
failControl.emplace_back(Circuit::NullGate());
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl, true);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDefineNCFuncDyn(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
// 4: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 4);
|
|
GateRef methodId = acc_.GetValueIn(gate, 0);
|
|
GateRef length = acc_.GetValueIn(gate, 1);
|
|
GateRef env = acc_.GetValueIn(gate, 2);
|
|
GateRef result;
|
|
DEFVAlUE(method, (&builder_), VariableType::JS_POINTER(),
|
|
GetObjectFromConstPool(jsFunc, builder_.ZExtInt16ToInt32(methodId)));
|
|
Label isResolved(&builder_);
|
|
Label notResolved(&builder_);
|
|
Label defaultLabel(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.FunctionIsResolved(*method), &isResolved, ¬Resolved);
|
|
builder_.Bind(&isResolved);
|
|
{
|
|
method = LowerCallRuntime(glue, RTSTUB_ID(DefineNCFuncDyn), {*method});
|
|
Label notException(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(*method, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, ¬Exception);
|
|
builder_.Bind(¬Exception);
|
|
{
|
|
builder_.SetConstPoolToFunction(glue, *method, GetConstPool(jsFunc));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
}
|
|
builder_.Bind(¬Resolved);
|
|
{
|
|
builder_.SetResolvedToFunction(glue, *method, builder_.Boolean(true));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
builder_.Bind(&defaultLabel);
|
|
{
|
|
GateRef hclass = builder_.LoadHClass(*method);
|
|
builder_.SetPropertyInlinedProps(glue, *method, hclass, builder_.TaggedNGC(length),
|
|
builder_.Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::INT64());
|
|
builder_.SetLexicalEnvToFunction(glue, *method, env);
|
|
GateRef homeObject = acc_.GetValueIn(gate, 3);
|
|
builder_.SetHomeObjectToFunction(glue, *method, homeObject);
|
|
builder_.SetModuleToFunction(glue, *method, builder_.GetModuleFromFunction(jsFunc));
|
|
result = *method;
|
|
builder_.Jump(&successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerDefineMethod(GateRef gate, GateRef glue, GateRef jsFunc)
|
|
{
|
|
// 4: number of value inputs
|
|
ASSERT(acc_.GetNumValueIn(gate) == 4);
|
|
GateRef methodId = acc_.GetValueIn(gate, 0);
|
|
GateRef length = acc_.GetValueIn(gate, 1);
|
|
GateRef env = acc_.GetValueIn(gate, 2);
|
|
GateRef result;
|
|
DEFVAlUE(method, (&builder_), VariableType::JS_POINTER(),
|
|
GetObjectFromConstPool(jsFunc, builder_.ZExtInt16ToInt32(methodId)));
|
|
Label isResolved(&builder_);
|
|
Label notResolved(&builder_);
|
|
Label defaultLabel(&builder_);
|
|
Label successExit(&builder_);
|
|
Label exceptionExit(&builder_);
|
|
builder_.Branch(builder_.FunctionIsResolved(*method), &isResolved, ¬Resolved);
|
|
builder_.Bind(&isResolved);
|
|
{
|
|
method = LowerCallRuntime(glue, RTSTUB_ID(DefineMethod), {*method});
|
|
Label notException(&builder_);
|
|
builder_.Branch(builder_.IsSpecial(*method, JSTaggedValue::VALUE_EXCEPTION),
|
|
&exceptionExit, ¬Exception);
|
|
builder_.Bind(¬Exception);
|
|
{
|
|
builder_.SetConstPoolToFunction(glue, *method, GetConstPool(jsFunc));
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
}
|
|
builder_.Bind(¬Resolved);
|
|
{
|
|
builder_.SetResolvedToFunction(glue, *method, builder_.Boolean(true));
|
|
GateRef homeObject = acc_.GetValueIn(gate, 3);
|
|
builder_.SetHomeObjectToFunction(glue, *method, homeObject);
|
|
builder_.Jump(&defaultLabel);
|
|
}
|
|
builder_.Bind(&defaultLabel);
|
|
{
|
|
GateRef hclass = builder_.LoadHClass(*method);
|
|
builder_.SetPropertyInlinedProps(glue, *method, hclass, builder_.TaggedNGC(length),
|
|
builder_.Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX), VariableType::INT64());
|
|
builder_.SetLexicalEnvToFunction(glue, *method, env);
|
|
builder_.SetModuleToFunction(glue, *method, builder_.GetModuleFromFunction(jsFunc));
|
|
result = *method;
|
|
builder_.Jump(&successExit);
|
|
}
|
|
CREATE_DOUBLE_EXIT(successExit, exceptionExit)
|
|
ReplaceHirToSubCfg(gate, result, successControl, failControl);
|
|
}
|
|
|
|
void SlowPathLowering::LowerGetUnmappedArgs(GateRef gate, GateRef glue)
|
|
{
|
|
GateRef actualArgc = bcBuilder_->GetCommonArgByIndex(CommonArgIdx::ACTUAL_ARGC);
|
|
GateRef taggedArgc = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(actualArgc));
|
|
std::vector<GateRef> vec;
|
|
GateRef argList = Circuit::GetCircuitRoot(OpCode(OpCode::ARG_LIST));
|
|
auto uses = acc_.ConstUses(argList);
|
|
for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
|
|
vec.emplace_back(*useIt);
|
|
}
|
|
std::vector<GateRef> args({vec.rbegin() + CommonArgIdx::NUM_OF_ARGS, vec.rend()});
|
|
args.insert(args.begin(), taggedArgc);
|
|
const int id = RTSTUB_ID(GetAotUnmapedArgs);
|
|
GateRef newGate = LowerCallRuntime(glue, id, args);
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
|
|
void SlowPathLowering::LowerCopyRestArgs(GateRef gate, GateRef glue)
|
|
{
|
|
GateRef actualArgc = bcBuilder_->GetCommonArgByIndex(CommonArgIdx::ACTUAL_ARGC);
|
|
GateRef restIdx = acc_.GetValueIn(gate, 0);
|
|
size_t restId = acc_.GetImmediateId(restIdx);
|
|
GateRef restNum = builder_.Int64Sub(builder_.ZExtInt32ToInt64(actualArgc), restIdx);
|
|
GateRef taggedRestNum = builder_.TaggedTypeNGC(restNum);
|
|
std::vector<GateRef> vec;
|
|
GateRef argList = Circuit::GetCircuitRoot(OpCode(OpCode::ARG_LIST));
|
|
auto uses = acc_.ConstUses(argList);
|
|
for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
|
|
vec.emplace_back(*useIt);
|
|
}
|
|
std::vector<GateRef> args({vec.rbegin() + CommonArgIdx::NUM_OF_ARGS + restId, vec.rend()});
|
|
args.insert(args.begin(), taggedRestNum);
|
|
const int id = RTSTUB_ID(CopyAotRestArgs);
|
|
GateRef newGate = LowerCallRuntime(glue, id, args);
|
|
ReplaceHirToCall(gate, newGate);
|
|
}
|
|
} // namespace panda::ecmascript
|