/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/compiler/mcr_lowering.h" #include "ecmascript/compiler/bytecodes.h" #include "ecmascript/compiler/share_gate_meta_data.h" #include "ecmascript/global_env.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_function.h" #include "ecmascript/message_string.h" #include "ecmascript/compiler/argument_accessor.h" namespace panda::ecmascript::kungfu { GateRef MCRLowering::VisitGate(GateRef gate) { auto op = acc_.GetOpCode(gate); switch (op) { case OpCode::GET_CONSTPOOL: LowerGetConstPool(gate); break; case OpCode::STATE_SPLIT: DeleteStateSplit(gate); break; case OpCode::ARRAY_GUARDIAN_CHECK: LowerArrayGuardianCheck(gate); break; case OpCode::HCLASS_STABLE_ARRAY_CHECK: LowerHClassStableArrayCheck(gate); break; case OpCode::HEAP_OBJECT_CHECK: LowerHeapObjectCheck(gate); break; case OpCode::LOAD_CONST_OFFSET: LowerLoadConstOffset(gate); break; case OpCode::LOAD_HCLASS_FROM_CONSTPOOL: LowerLoadHClassFromConstpool(gate); break; case OpCode::STORE_CONST_OFFSET: LowerStoreConstOffset(gate); break; case OpCode::CONVERT_HOLE_AS_UNDEFINED: LowerConvertHoleAsUndefined(gate); break; case OpCode::GET_GLOBAL_ENV: LowerGetGlobalEnv(gate); break; case OpCode::GET_GLOBAL_ENV_OBJ: LowerGetGlobalEnvObj(gate); break; case OpCode::GET_GLOBAL_ENV_OBJ_HCLASS: LowerGetGlobalEnvObjHClass(gate); break; case OpCode::GET_GLOBAL_CONSTANT_VALUE: LowerGetGlobalConstantValue(gate); break; case OpCode::HEAP_ALLOC: LowerHeapAllocate(gate); break; case OpCode::INT32_CHECK_RIGHT_IS_ZERO: LowerInt32CheckRightIsZero(gate); break; case OpCode::REMAINDER_IS_NEGATIVE_ZERO: LowerRemainderIsNegativeZero(gate); break; case OpCode::FLOAT64_CHECK_RIGHT_IS_ZERO: LowerFloat64CheckRightIsZero(gate); break; case OpCode::VALUE_CHECK_NEG_OVERFLOW: LowerValueCheckNegOverflow(gate); break; case OpCode::OVERFLOW_CHECK: LowerOverflowCheck(gate); break; case OpCode::INT32_UNSIGNED_UPPER_BOUND_CHECK: LowerInt32UnsignedUpperBoundCheck(gate); break; case OpCode::INT32_DIV_WITH_CHECK: LowerInt32DivWithCheck(gate); break; case OpCode::LEX_VAR_IS_HOLE_CHECK: LowerLexVarIsHoleCheck(gate); break; case OpCode::STORE_MEMORY: LowerStoreMemory(gate); break; case OpCode::CHECK_AND_CONVERT: LowerCheckAndConvert(gate); break; case OpCode::TAGGED_IS_HEAP_OBJECT: LowerTaggedIsHeapObject(gate); break; case OpCode::IS_MARKER_CELL_VALID: LowerIsMarkerCellValid(gate); break; case OpCode::IS_SPECIFIC_OBJECT_TYPE: LowerIsSpecificObjectType(gate); break; default: break; } return Circuit::NullGate(); } void MCRLowering::LowerConvertHoleAsUndefined(GateRef gate) { Environment env(gate, circuit_, &builder_); Label returnUndefined(&builder_); Label exit(&builder_); GateRef receiver = acc_.GetValueIn(gate, 0); DEFVALUE(result, (&builder_), VariableType::JS_ANY(), receiver); builder_.Branch(builder_.TaggedIsHole(*result), &returnUndefined, &exit, 1, BranchWeight::DEOPT_WEIGHT); builder_.Bind(&returnUndefined); { result = builder_.UndefineConstant(); builder_.Jump(&exit); } builder_.Bind(&exit); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); } void MCRLowering::LowerLoadConstOffset(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef receiver = acc_.GetValueIn(gate, 0); GateRef offset = builder_.IntPtr(acc_.GetOffset(gate)); VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate)); GateRef result = builder_.Load(type, receiver, offset, acc_.GetMemoryOrder(gate)); acc_.ReplaceGate(gate, Circuit::NullGate(), builder_.GetDepend(), result); } void MCRLowering::LowerLoadHClassFromConstpool(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef constpool = acc_.GetValueIn(gate, 0); uint32_t index = acc_.GetIndex(gate); GateRef constPoolSize = builder_.GetLengthOfTaggedArray(constpool); GateRef valVecIndex = builder_.Int32Sub(constPoolSize, builder_.Int32(ConstantPool::AOT_HCLASS_INFO_INDEX)); GateRef valVec = builder_.GetValueFromTaggedArray(constpool, valVecIndex); GateRef hclass = builder_.GetValueFromTaggedArray(valVec, builder_.Int32(index)); acc_.ReplaceGate(gate, Circuit::NullGate(), builder_.GetDepend(), hclass); } void MCRLowering::LowerStoreConstOffset(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef receiver = acc_.GetValueIn(gate, 0); GateRef value = acc_.GetValueIn(gate, 1); GateRef offset = builder_.IntPtr(acc_.GetOffset(gate)); VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate)); builder_.Store(type, glue_, receiver, offset, value, acc_.GetMemoryOrder(gate)); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerHeapObjectCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef receiver = acc_.GetValueIn(gate, 0); GateRef heapObjectCheck = builder_.TaggedIsHeapObject(receiver); builder_.DeoptCheck(heapObjectCheck, frameState, DeoptType::NOTHEAPOBJECT1); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerTaggedIsHeapObject(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef receiver = acc_.GetValueIn(gate, 0); GateRef result = builder_.TaggedIsHeapObject(receiver); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerIsMarkerCellValid(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef cell = acc_.GetValueIn(gate, 0); GateRef result = builder_.IsMarkerCellValid(cell); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerIsSpecificObjectType(GateRef gate) { Environment env(gate, circuit_, &builder_); JSType expectType = static_cast<JSType>(acc_.GetJSType(gate)); GateRef obj = acc_.GetValueIn(gate, 0); GateRef result; switch (expectType) { case JSType::JS_MAP: { result = builder_.TaggedObjectIsJSMap(obj); break; } case JSType::JS_SET: { result = builder_.TaggedObjectIsJSSet(obj); break; } case JSType::JS_ARRAY: { result = builder_.TaggedObjectIsJSArray(obj); break; } case JSType::STRING_FIRST: { result = builder_.TaggedObjectIsString(obj); break; } case JSType::JS_TYPED_ARRAY_FIRST: { result = builder_.TaggedObjectIsTypedArray(obj); break; } default: { LOG_COMPILER(FATAL) << "this branch is unreachable"; UNREACHABLE(); } } acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerGetConstPool(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef jsFunc = acc_.GetValueIn(gate, 0); // 0: this object GateRef newGate = builder_.GetConstPoolFromFunction(jsFunc); acc_.UpdateAllUses(gate, newGate); // delete old gate acc_.DeleteGate(gate); } void MCRLowering::DeleteStateSplit(GateRef gate) { auto depend = acc_.GetDep(gate); auto frameState = acc_.GetFrameState(gate); acc_.DeleteGateIfNoUse(frameState); acc_.ReplaceGate(gate, Circuit::NullGate(), depend, Circuit::NullGate()); } void MCRLowering::LowerArrayGuardianCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef guardiansOffset = builder_.IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(false)); GateRef check = builder_.Load(VariableType::BOOL(), glue_, guardiansOffset); builder_.DeoptCheck(check, frameState, DeoptType::NOTSARRAY1); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerHClassStableArrayCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef hclass = acc_.GetValueIn(gate, 0); GateRef check = Circuit::NullGate(); GateRef stableCheck = builder_.IsStableElements(hclass); ArrayMetaDataAccessor accessor = acc_.GetArrayMetaDataAccessor(gate); ElementsKind kind = accessor.GetElementsKind(); if (accessor.IsLoadElement() && !Elements::IsHole(kind)) { if (Elements::IsComplex(kind)) { GateRef elementsKindCheck = builder_.Int32GreaterThanOrEqual(builder_.Int32(static_cast<int32_t>(kind)), builder_.GetElementsKindByHClass(hclass)); check = builder_.BoolAnd(stableCheck, elementsKindCheck); } else { GateRef elementsKindCheck = builder_.Equal(builder_.Int32(static_cast<int32_t>(kind)), builder_.GetElementsKindByHClass(hclass)); check = builder_.BoolAnd(stableCheck, elementsKindCheck); } } else { check = stableCheck; } builder_.DeoptCheck(check, frameState, DeoptType::NOTSARRAY2); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } StateDepend MCRLowering::LowerConvert(StateDepend stateDepend, GateRef gate) { Environment env(stateDepend.State(), stateDepend.Depend(), {}, circuit_, &builder_); GateRef value = acc_.GetValueIn(gate); ValueType dstType = acc_.GetDstType(gate); GateRef result = Circuit::NullGate(); Label exit(&builder_); switch (acc_.GetSrcType(gate)) { case ValueType::BOOL: ASSERT(dstType == ValueType::TAGGED_BOOLEAN); result = ConvertBoolToTaggedBoolean(value); break; case ValueType::INT32: if (dstType == ValueType::TAGGED_INT) { result = ConvertInt32ToTaggedInt(value); } else if (dstType == ValueType::FLOAT64) { result = ConvertInt32ToFloat64(value); } else { ASSERT(dstType == ValueType::BOOL); result = builder_.NotEqual(value, builder_.Int32(0)); } break; case ValueType::UINT32: if (dstType == ValueType::TAGGED_NUMBER) { result = ConvertUInt32ToTaggedNumber(value, &exit); } else if (dstType == ValueType::FLOAT64) { result = ConvertUInt32ToFloat64(value); } else { ASSERT(dstType == ValueType::BOOL); result = builder_.NotEqual(value, builder_.Int32(0)); } break; case ValueType::FLOAT64: if (dstType == ValueType::TAGGED_DOUBLE) { result = ConvertFloat64ToTaggedDouble(value); } else if (dstType == ValueType::INT32) { result = ConvertFloat64ToInt32(value, &exit); } else { ASSERT(dstType == ValueType::BOOL); result = ConvertFloat64ToBool(value); } break; case ValueType::TAGGED_BOOLEAN: ASSERT((dstType == ValueType::BOOL)); result = ConvertTaggedBooleanToBool(value); break; case ValueType::TAGGED_INT: ASSERT((dstType == ValueType::INT32)); result = ConvertTaggedIntToInt32(value); break; case ValueType::TAGGED_DOUBLE: ASSERT((dstType == ValueType::FLOAT64)); result = ConvertTaggedDoubleToFloat64(value); break; case ValueType::CHAR: { ASSERT((dstType == ValueType::ECMA_STRING)); GateRef glue = acc_.GetGlueFromArgList(); result = builder_.CallStub(glue, gate, CommonStubCSigns::CreateStringBySingleCharCode, { glue, value }); break; } default: LOG_COMPILER(FATAL) << "this branch is unreachable"; break; } acc_.ReplaceGate(gate, Circuit::NullGate(), Circuit::NullGate(), result); return builder_.GetStateDepend(); } GateRef MCRLowering::ConvertTaggedNumberToBool(GateRef gate, Label *exit) { DEFVALUE(result, (&builder_), VariableType::BOOL(), builder_.Boolean(false)); Label isInt(&builder_); Label isDouble(&builder_); Label toInt32(&builder_); builder_.Branch(builder_.TaggedIsInt(gate), &isInt, &isDouble); builder_.Bind(&isInt); { GateRef intVal = builder_.GetInt64OfTInt(gate); result = builder_.NotEqual(intVal, builder_.Int64(0)); } builder_.Jump(exit); builder_.Bind(&isDouble); { GateRef doubleVal = builder_.GetDoubleOfTDouble(gate); result = ConvertFloat64ToBool(doubleVal); } builder_.Jump(exit); builder_.Bind(exit); return *result; } GateRef MCRLowering::ConvertTaggedNumberToInt32(GateRef gate, Label *exit) { DEFVALUE(result, (&builder_), VariableType::INT32(), builder_.Int32(0)); Label isInt(&builder_); Label isDouble(&builder_); Label toInt32(&builder_); builder_.Branch(builder_.TaggedIsInt(gate), &isInt, &isDouble); builder_.Bind(&isInt); result = ConvertTaggedIntToInt32(gate); builder_.Jump(exit); builder_.Bind(&isDouble); result = ConvertFloat64ToInt32(ConvertTaggedDoubleToFloat64(gate), &toInt32); builder_.Jump(exit); builder_.Bind(exit); return *result; } GateRef MCRLowering::ConvertTaggedNumberToFloat64(GateRef gate, Label *exit) { DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.Double(0)); Label isInt(&builder_); Label isDouble(&builder_); builder_.Branch(builder_.TaggedIsInt(gate), &isInt, &isDouble); builder_.Bind(&isInt); result = ConvertInt32ToFloat64(ConvertTaggedIntToInt32(gate)); builder_.Jump(exit); builder_.Bind(&isDouble); result = ConvertTaggedDoubleToFloat64(gate); builder_.Jump(exit); builder_.Bind(exit); return *result; } void MCRLowering::LowerCheckAndConvert(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); ValueType srcType = acc_.GetSrcType(gate); Label exit(&builder_); switch (srcType) { case ValueType::UINT32: LowerCheckUInt32AndConvert(gate, frameState); break; case ValueType::TAGGED_INT: LowerCheckTaggedIntAndConvert(gate, frameState); break; case ValueType::TAGGED_DOUBLE: LowerCheckTaggedDoubleAndConvert(gate, frameState, &exit); break; case ValueType::TAGGED_BOOLEAN: LowerCheckTaggedBoolAndConvert(gate, frameState); break; case ValueType::TAGGED_NUMBER: LowerCheckTaggedNumberAndConvert(gate, frameState, &exit); break; case ValueType::BOOL: LowerCheckSupportAndConvert(gate, frameState); break; case ValueType::TAGGED_NULL: LowerCheckNullAndConvert(gate, frameState); break; case ValueType::UNDEFINED: LowerUndefinedAndConvert(gate, frameState); break; default: UNREACHABLE(); } } void MCRLowering::LowerCheckUInt32AndConvert(GateRef gate, GateRef frameState) { GateRef value = acc_.GetValueIn(gate, 0); GateRef upperBound = builder_.Int32(INT32_MAX); GateRef check = builder_.Int32UnsignedLessThanOrEqual(value, upperBound); builder_.DeoptCheck(check, frameState, DeoptType::INT32OVERFLOW1); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), value); } void MCRLowering::LowerCheckTaggedIntAndConvert(GateRef gate, GateRef frameState) { GateRef value = acc_.GetValueIn(gate, 0); GateRef typeCheck = builder_.TaggedIsInt(value); builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTINT1); GateRef result = Circuit::NullGate(); ValueType dst = acc_.GetDstType(gate); ASSERT(dst == ValueType::INT32 || dst == ValueType::FLOAT64); if (dst == ValueType::INT32) { result = ConvertTaggedIntToInt32(value); } else { result = ConvertTaggedIntToFloat64(value); } acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerCheckTaggedDoubleAndConvert(GateRef gate, GateRef frameState, Label *exit) { GateRef value = acc_.GetValueIn(gate, 0); GateRef typeCheck = builder_.TaggedIsDouble(value); builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTDOUBLE1); GateRef result = Circuit::NullGate(); ValueType dst = acc_.GetDstType(gate); ASSERT(dst == ValueType::INT32 || dst == ValueType::FLOAT64); if (dst == ValueType::INT32) { result = ConvertTaggedDoubleToInt32(value, exit); } else { result = ConvertTaggedDoubleToFloat64(value); } acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerCheckTaggedNumberAndConvert(GateRef gate, GateRef frameState, Label *exit) { GateRef value = acc_.GetValueIn(gate, 0); GateRef typeCheck = builder_.TaggedIsNumber(value); builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTNUMBER1); GateRef result = Circuit::NullGate(); ValueType dst = acc_.GetDstType(gate); if (dst == ValueType::INT32) { result = ConvertTaggedNumberToInt32(value, exit); } else if (dst == ValueType::FLOAT64) { result = ConvertTaggedNumberToFloat64(value, exit); } else { ASSERT(dst == ValueType::BOOL); result = ConvertTaggedNumberToBool(value, exit); } acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerCheckSupportAndConvert(GateRef gate, GateRef frameState) { ValueType dstType = acc_.GetDstType(gate); ASSERT(dstType == ValueType::INT32 || dstType == ValueType::FLOAT64); bool support = acc_.IsConvertSupport(gate); GateRef value = acc_.GetValueIn(gate, 0); GateRef result = Circuit::NullGate(); if (dstType == ValueType::INT32) { builder_.DeoptCheck(builder_.Boolean(support), frameState, DeoptType::NOTINT2); result = builder_.BooleanToInt32(value); } else { builder_.DeoptCheck(builder_.Boolean(support), frameState, DeoptType::NOTDOUBLE2); result = builder_.BooleanToFloat64(value); } acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerCheckTaggedBoolAndConvert(GateRef gate, GateRef frameState) { GateRef value = acc_.GetValueIn(gate, 0); GateRef typeCheck = builder_.TaggedIsBoolean(value); builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTBOOL1); GateRef result = Circuit::NullGate(); GateRef boolValue = ConvertTaggedBooleanToBool(value); if (acc_.GetDstType(gate) == ValueType::BOOL) { result = boolValue; } else if (acc_.GetDstType(gate) == ValueType::INT32) { result = builder_.ZExtInt1ToInt32(boolValue); } else if (acc_.GetDstType(gate) == ValueType::FLOAT64) { result = builder_.BooleanToFloat64(boolValue); } else { UNREACHABLE(); } acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerCheckNullAndConvert(GateRef gate, GateRef frameState) { GateRef value = acc_.GetValueIn(gate, 0); GateRef typeCheck = builder_.TaggedIsNull(value); builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTNULL1); GateRef result = Circuit::NullGate(); if (acc_.GetDstType(gate) == ValueType::INT32) { result = builder_.Int32(0); } else if (acc_.GetDstType(gate) == ValueType::FLOAT64) { result = builder_.Double(0); } else if (acc_.GetDstType(gate) == ValueType::BOOL) { result = builder_.False(); } else { UNREACHABLE(); } acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerUndefinedAndConvert(GateRef gate, GateRef frameState) { GateRef value = acc_.GetValueIn(gate, 0); GateRef typeCheck = builder_.TaggedIsUndefined(value); builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTNULL2); GateRef result = Circuit::NullGate(); if (acc_.GetDstType(gate) == ValueType::FLOAT64) { result = builder_.NanValue(); } else if (acc_.GetDstType(gate) == ValueType::BOOL) { result = builder_.False(); } else if (acc_.GetDstType(gate) == ValueType::INT32) { result = builder_.Int32(0); } else { UNREACHABLE(); } acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } GateRef MCRLowering::ConvertTaggedBooleanToBool(GateRef value) { return builder_.TaggedIsTrue(value); } GateRef MCRLowering::ConvertBoolToTaggedBoolean(GateRef gate) { return builder_.BooleanToTaggedBooleanPtr(gate); } GateRef MCRLowering::ConvertInt32ToFloat64(GateRef gate) { return builder_.ChangeInt32ToFloat64(gate); } GateRef MCRLowering::ConvertUInt32ToFloat64(GateRef gate) { return builder_.ChangeUInt32ToFloat64(gate); } GateRef MCRLowering::ConvertInt32ToTaggedInt(GateRef gate) { return builder_.Int32ToTaggedPtr(gate); } GateRef MCRLowering::ConvertUInt32ToTaggedNumber(GateRef gate, Label *exit) { Label isOverFlow(&builder_); Label notOverFlow(&builder_); GateRef upperBound = builder_.Int32(INT32_MAX); DEFVALUE(taggedVal, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant()); builder_.Branch(builder_.Int32UnsignedLessThanOrEqual(gate, upperBound), ¬OverFlow, &isOverFlow); builder_.Bind(¬OverFlow); taggedVal = builder_.Int32ToTaggedPtr(gate); builder_.Jump(exit); builder_.Bind(&isOverFlow); taggedVal = builder_.DoubleToTaggedDoublePtr(builder_.ChangeUInt32ToFloat64(gate)); builder_.Jump(exit); builder_.Bind(exit); return *taggedVal; } GateRef MCRLowering::ConvertFloat64ToInt32(GateRef gate, Label *exit) { return builder_.DoubleToInt(gate, exit); } GateRef MCRLowering::ConvertFloat64ToBool(GateRef gate) { GateRef doubleNotZero = builder_.DoubleNotEqual(gate, builder_.Double(0.0)); GateRef doubleNotNAN = builder_.BoolNot(builder_.DoubleIsNAN(gate)); return builder_.BoolAnd(doubleNotZero, doubleNotNAN); } GateRef MCRLowering::ConvertFloat64ToTaggedDouble(GateRef gate) { return builder_.DoubleToTaggedDoublePtr(gate); } GateRef MCRLowering::ConvertTaggedIntToInt32(GateRef gate) { return builder_.GetInt32OfTInt(gate); } GateRef MCRLowering::ConvertTaggedIntToFloat64(GateRef gate) { return builder_.ChangeInt32ToFloat64(builder_.GetInt32OfTInt(gate)); } GateRef MCRLowering::ConvertTaggedDoubleToInt32(GateRef gate, Label *exit) { return builder_.DoubleToInt(builder_.GetDoubleOfTDouble(gate), exit); } GateRef MCRLowering::ConvertTaggedDoubleToFloat64(GateRef gate) { return builder_.GetDoubleOfTDouble(gate); } void MCRLowering::LowerGetGlobalEnv(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef glueGlobalEnvOffset = builder_.IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(false)); GateRef glueGlobalEnv = builder_.Load(VariableType::JS_POINTER(), glue_, glueGlobalEnvOffset); acc_.ReplaceGate(gate, Circuit::NullGate(), builder_.GetDepend(), glueGlobalEnv); } void MCRLowering::LowerGetGlobalEnvObj(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef globalEnv = acc_.GetValueIn(gate, 0); size_t index = acc_.GetIndex(gate); GateRef offset = builder_.IntPtr(GlobalEnv::HEADER_SIZE + JSTaggedValue::TaggedTypeSize() * index); GateRef object = builder_.Load(VariableType::JS_ANY(), globalEnv, offset); acc_.ReplaceGate(gate, Circuit::NullGate(), builder_.GetDepend(), object); } void MCRLowering::LowerGetGlobalEnvObjHClass(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef globalEnv = acc_.GetValueIn(gate, 0); size_t index = acc_.GetIndex(gate); GateRef offset = builder_.IntPtr(GlobalEnv::HEADER_SIZE + JSTaggedValue::TaggedTypeSize() * index); GateRef object = builder_.Load(VariableType::JS_ANY(), globalEnv, offset); auto hclass = builder_.Load(VariableType::JS_POINTER(), object, builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); acc_.ReplaceGate(gate, Circuit::NullGate(), builder_.GetDepend(), hclass); } void MCRLowering::LowerGetGlobalConstantValue(GateRef gate) { Environment env(gate, circuit_, &builder_); size_t index = acc_.GetIndex(gate); GateRef gConstAddr = builder_.Load(VariableType::JS_POINTER(), glue_, builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(false))); GateRef constantIndex = builder_.IntPtr(JSTaggedValue::TaggedTypeSize() * index); GateRef result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, constantIndex); acc_.ReplaceGate(gate, Circuit::NullGate(), builder_.GetDepend(), result); } void MCRLowering::LowerHeapAllocate(GateRef gate) { Environment env(gate, circuit_, &builder_); auto flag = acc_.TryGetValue(gate); switch (flag) { case RegionSpaceFlag::IN_YOUNG_SPACE: HeapAllocateInYoung(gate); break; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); } } void MCRLowering::HeapAllocateInYoung(GateRef gate) { Label exit(&builder_); GateRef size = acc_.GetValueIn(gate, 0); DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant()); #ifndef ARK_ASAN_ON Label success(&builder_); Label callRuntime(&builder_); size_t topOffset = JSThread::GlueData::GetNewSpaceAllocationTopAddressOffset(false); size_t endOffset = JSThread::GlueData::GetNewSpaceAllocationEndAddressOffset(false); GateRef topAddress = builder_.Load(VariableType::NATIVE_POINTER(), glue_, builder_.IntPtr(topOffset)); GateRef endAddress = builder_.Load(VariableType::NATIVE_POINTER(), glue_, builder_.IntPtr(endOffset)); GateRef top = builder_.Load(VariableType::JS_POINTER(), topAddress, builder_.IntPtr(0)); GateRef end = builder_.Load(VariableType::JS_POINTER(), endAddress, builder_.IntPtr(0)); GateRef newTop = builder_.PtrAdd(top, size); builder_.Branch(builder_.IntPtrGreaterThan(newTop, end), &callRuntime, &success); builder_.Bind(&success); { builder_.Store(VariableType::NATIVE_POINTER(), glue_, topAddress, builder_.IntPtr(0), newTop); result = top; builder_.Jump(&exit); } builder_.Bind(&callRuntime); #endif { result = builder_.CallRuntime(glue_, RTSTUB_ID(AllocateInYoung), Gate::InvalidGateRef, {builder_.ToTaggedInt(size)}, gate); builder_.Jump(&exit); } builder_.Bind(&exit); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); } void MCRLowering::LowerInt32CheckRightIsZero(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef right = acc_.GetValueIn(gate, 0); GateRef rightNotZero = builder_.Int32NotEqual(right, builder_.Int32(0)); builder_.DeoptCheck(rightNotZero, frameState, DeoptType::MODZERO1); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerRemainderIsNegativeZero(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); GateRef leftIsNegative = builder_.Int32LessThan(left, builder_.Int32(0)); GateRef remainder = builder_.BinaryArithmetic(circuit_->Smod(), MachineType::I32, left, right, GateType::NJSValue()); GateRef remainderEqualZero = builder_.Int32Equal(remainder, builder_.Int32(0)); GateRef remainderIsNotNegative = builder_.BoolNot(builder_.BoolAnd(leftIsNegative, remainderEqualZero)); builder_.DeoptCheck(remainderIsNotNegative, frameState, DeoptType::REMAINDERISNEGATIVEZERO); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerFloat64CheckRightIsZero(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef right = acc_.GetValueIn(gate, 0); GateRef rightNotZero = builder_.DoubleNotEqual(right, builder_.Double(0.0)); builder_.DeoptCheck(rightNotZero, frameState, DeoptType::DIVZERO1); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerLexVarIsHoleCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef value = acc_.GetValueIn(gate, 0); GateRef valueIsNotHole = builder_.TaggedIsNotHole(value); builder_.DeoptCheck(valueIsNotHole, frameState, DeoptType::LEXVARISHOLE1); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerValueCheckNegOverflow(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef value = acc_.GetValueIn(gate, 0); GateRef valueNotZero = builder_.NotEqual(value, builder_.Int32(0)); builder_.DeoptCheck(valueNotZero, frameState, DeoptType::NOTNEGOV1); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerOverflowCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef result = acc_.GetValueIn(gate, 0); GateRef condition = builder_.BoolNot(builder_.ExtractValue(MachineType::I1, result, builder_.Int32(1))); builder_.DeoptCheck(condition, frameState, DeoptType::NOTINT3); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerInt32UnsignedUpperBoundCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef value = acc_.GetValueIn(gate, 0); GateRef upperBound = acc_.GetValueIn(gate, 1); GateRef condition = builder_.Int32UnsignedLessThanOrEqual(value, upperBound); builder_.DeoptCheck(condition, frameState, DeoptType::NOTINT4); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::LowerInt32DivWithCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef frameState = acc_.GetFrameState(gate); GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); GateRef result = Circuit::NullGate(); GateRef rightGreaterZero = builder_.Int32GreaterThan(right, builder_.Int32(0)); GateRef rightLessZero = builder_.Int32LessThan(right, builder_.Int32(0)); GateRef leftNotZero = builder_.Int32NotEqual(left, builder_.Int32(0)); GateRef condition = builder_.BoolOr(rightGreaterZero, builder_.BoolAnd(rightLessZero, leftNotZero)); builder_.DeoptCheck(condition, frameState, DeoptType::DIVZERO2); result = builder_.BinaryArithmetic(circuit_->Sdiv(), MachineType::I32, left, right, GateType::NJSValue()); GateRef truncated = builder_.BinaryArithmetic(circuit_->Mul(), MachineType::I32, result, right, GateType::NJSValue()); GateRef overCheck = builder_.Int32Equal(truncated, left); builder_.DeoptCheck(overCheck, frameState, DeoptType::NOTINT5); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void MCRLowering::LowerStoreMemory(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef receiver = acc_.GetValueIn(gate, 0); GateRef index = acc_.GetValueIn(gate, 1); GateRef value = acc_.GetValueIn(gate, 2); builder_.Store(VariableType::VOID(), glue_, receiver, index, value); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void MCRLowering::InitializeWithSpeicalValue(Label *exit, GateRef object, GateRef glue, GateRef value, GateRef start, GateRef end) { Label begin(&builder_); Label storeValue(&builder_); Label endLoop(&builder_); DEFVALUE(startOffset, (&builder_), VariableType::INT32(), start); builder_.Jump(&begin); builder_.LoopBegin(&begin); { builder_.Branch(builder_.Int32UnsignedLessThan(*startOffset, end), &storeValue, exit); builder_.Bind(&storeValue); { builder_.Store(VariableType::INT64(), glue, object, builder_.ZExtInt32ToPtr(*startOffset), value); startOffset = builder_.Int32Add(*startOffset, builder_.Int32(JSTaggedValue::TaggedTypeSize())); builder_.Jump(&endLoop); } builder_.Bind(&endLoop); builder_.LoopEnd(&begin); } } } // namespace panda::ecmascript