/* * 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 "ecmascript/compiler/circuit_builder.h" #include "ecmascript/compiler/builtins/builtins_call_signature.h" #include "ecmascript/compiler/circuit_builder-inl.h" #include "ecmascript/compiler/common_stubs.h" #include "ecmascript/compiler/hcr_circuit_builder.h" #include "ecmascript/compiler/lcr_circuit_builder.h" #include "ecmascript/compiler/mcr_circuit_builder.h" #include "ecmascript/compiler/rt_call_signature.h" #include "ecmascript/compiler/share_gate_meta_data.h" #include "ecmascript/deoptimizer/deoptimizer.h" #include "ecmascript/global_env.h" #include "ecmascript/ic/proto_change_details.h" #include "ecmascript/js_array_iterator.h" #include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_function.h" #include "ecmascript/js_thread.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/mem/region.h" #include "ecmascript/method.h" namespace panda::ecmascript::kungfu { GateRef CircuitBuilder::Merge(const std::vector &inList) { return circuit_->NewGate(circuit_->Merge(inList.size()), inList); } GateRef CircuitBuilder::Selector(OpCode opcode, MachineType machineType, GateRef control, const std::vector &values, int valueCounts, VariableType type) { std::vector inList; inList.push_back(control); if (values.size() == 0) { for (int i = 0; i < valueCounts; i++) { inList.push_back(Circuit::NullGate()); } } else { for (int i = 0; i < valueCounts; i++) { inList.push_back(values[i]); } } ASSERT((opcode == OpCode::VALUE_SELECTOR) || (opcode == OpCode::DEPEND_SELECTOR)); const GateMetaData* meta = (opcode == OpCode::DEPEND_SELECTOR) ? circuit_->DependSelector(valueCounts) : circuit_->ValueSelector(valueCounts); return circuit_->NewGate(meta, machineType, inList.size(), inList.data(), type.GetGateType()); } GateRef CircuitBuilder::Selector(OpCode opcode, GateRef control, const std::vector &values, int valueCounts, VariableType type) { MachineType machineType = (opcode == OpCode::DEPEND_SELECTOR) ? MachineType::NOVALUE : MachineType::FLEX; return Selector(opcode, machineType, control, values, valueCounts, type); } GateRef CircuitBuilder::Nop() { return circuit_->NewGate(circuit_->Nop(), {}); } GateRef CircuitBuilder::UndefineConstant() { auto type = GateType::TaggedValue(); return circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, type); } GateRef CircuitBuilder::Branch(GateRef state, GateRef condition, uint32_t trueWeight, uint32_t falseWeight, const char* comment) { auto value = BranchAccessor::ToValue(trueWeight, falseWeight); return circuit_->NewGate(circuit_->IfBranch(value), { state, condition }, comment); } GateRef CircuitBuilder::SwitchBranch(GateRef state, GateRef index, int caseCounts) { return circuit_->NewGate(circuit_->SwitchBranch(caseCounts), { state, index }); } GateRef CircuitBuilder::Return(GateRef state, GateRef depend, GateRef value) { auto returnList = circuit_->GetReturnRoot(); return circuit_->NewGate(circuit_->Return(), { state, depend, value, returnList }); } GateRef CircuitBuilder::ReturnVoid(GateRef state, GateRef depend) { auto returnList = circuit_->GetReturnRoot(); return circuit_->NewGate(circuit_->ReturnVoid(), { state, depend, returnList }); } GateRef CircuitBuilder::Goto(GateRef state) { return circuit_->NewGate(circuit_->OrdinaryBlock(), { state }); } GateRef CircuitBuilder::LoopBegin(GateRef state) { auto nullGate = Circuit::NullGate(); return circuit_->NewGate(circuit_->LoopBegin(2), { state, nullGate }); // 2: entry&back } GateRef CircuitBuilder::LoopEnd(GateRef state) { return circuit_->NewGate(circuit_->LoopBack(), { state }); } GateRef CircuitBuilder::LoopExit(GateRef state) { return circuit_->NewGate(circuit_->LoopExit(), { state }); } GateRef CircuitBuilder::LoopExitDepend(GateRef state, GateRef depend) { return circuit_->NewGate(circuit_->LoopExitDepend(), { state, depend }); } GateRef CircuitBuilder::LoopExitValue(GateRef state, GateRef value) { auto machineType = acc_.GetMachineType(value); auto gateType = acc_.GetGateType(value); return circuit_->NewGate(circuit_->LoopExitValue(), machineType, { state, value }, gateType); } GateRef CircuitBuilder::IfTrue(GateRef ifBranch) { return circuit_->NewGate(circuit_->IfTrue(), { ifBranch }); } GateRef CircuitBuilder::IfFalse(GateRef ifBranch) { return circuit_->NewGate(circuit_->IfFalse(), { ifBranch }); } GateRef CircuitBuilder::SwitchCase(GateRef switchBranch, int64_t value) { return circuit_->NewGate(circuit_->SwitchCase(value), { switchBranch }); } GateRef CircuitBuilder::DefaultCase(GateRef switchBranch) { return circuit_->NewGate(circuit_->DefaultCase(), { switchBranch }); } GateRef CircuitBuilder::DependRelay(GateRef state, GateRef depend) { return circuit_->NewGate(circuit_->DependRelay(), { state, depend }); } GateRef CircuitBuilder::Arguments(size_t index) { auto argListOfCircuit = circuit_->GetArgRoot(); return GetCircuit()->NewArg(MachineType::I64, index, GateType::NJSValue(), argListOfCircuit); } GateRef CircuitBuilder::IsJsCOWArray(GateRef obj) { // Elements of JSArray are shared and properties are not yet. GateRef elements = GetElementsArray(obj); GateRef objectType = GetObjectType(LoadHClass(elements)); return IsCOWArray(objectType); } GateRef CircuitBuilder::IsCOWArray(GateRef objectType) { return BoolOr(Int32Equal(objectType, Int32(static_cast(JSType::COW_TAGGED_ARRAY))), Int32Equal(objectType, Int32(static_cast(JSType::COW_MUTANT_TAGGED_ARRAY)))); } GateRef CircuitBuilder::IsTaggedArray(GateRef object) { GateRef objectType = GetObjectType(LoadHClass(object)); return Int32Equal(objectType, Int32(static_cast(JSType::TAGGED_ARRAY))); } GateRef CircuitBuilder::IsMutantTaggedArray(GateRef objectType) { return BoolOr(Int32Equal(objectType, Int32(static_cast(JSType::MUTANT_TAGGED_ARRAY))), Int32Equal(objectType, Int32(static_cast(JSType::COW_MUTANT_TAGGED_ARRAY)))); } GateRef CircuitBuilder::GetElementsArray(GateRef object) { GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET); return Load(VariableType::JS_POINTER(), object, elementsOffset); } GateRef CircuitBuilder::GetLengthOfTaggedArray(GateRef array) { return Load(VariableType::INT32(), array, IntPtr(TaggedArray::LENGTH_OFFSET)); } GateRef CircuitBuilder::GetLengthOfJSTypedArray(GateRef array) { return Load(VariableType::INT32(), array, IntPtr(JSTypedArray::ARRAY_LENGTH_OFFSET)); } GateRef CircuitBuilder::IsTypedArray(GateRef array) { GateRef hclass = LoadHClass(array); GateRef type = GetObjectType(hclass); return BoolAnd(Int32GreaterThan(type, Int32(static_cast(JSType::JS_TYPED_ARRAY_FIRST))), Int32GreaterThanOrEqual(Int32(static_cast(JSType::JS_TYPED_ARRAY_LAST)), type)); } void CircuitBuilder::Jump(Label *label) { ASSERT(label); auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto jump = Goto(currentControl); currentLabel->SetControl(jump); label->AppendPredecessor(currentLabel); label->MergeControl(currentLabel->GetControl()); env_->SetCurrentLabel(nullptr); } void CircuitBuilder::Branch(GateRef condition, Label *trueLabel, Label *falseLabel, uint32_t trueWeight, uint32_t falseWeight, const char* comment) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); GateRef ifBranch = Branch(currentControl, condition, trueWeight, falseWeight, comment); currentLabel->SetControl(ifBranch); GateRef ifTrue = IfTrue(ifBranch); trueLabel->AppendPredecessor(GetCurrentLabel()); trueLabel->MergeControl(ifTrue); GateRef ifFalse = IfFalse(ifBranch); falseLabel->AppendPredecessor(GetCurrentLabel()); falseLabel->MergeControl(ifFalse); env_->SetCurrentLabel(nullptr); } void CircuitBuilder::Switch(GateRef index, Label *defaultLabel, int64_t *keysValue, Label *keysLabel, int numberOfKeys) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); GateRef switchBranch = SwitchBranch(currentControl, index, numberOfKeys); currentLabel->SetControl(switchBranch); for (int i = 0; i < numberOfKeys; i++) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) GateRef switchCase = SwitchCase(switchBranch, keysValue[i]); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) keysLabel[i].AppendPredecessor(currentLabel); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) keysLabel[i].MergeControl(switchCase); } GateRef defaultCase = DefaultCase(switchBranch); defaultLabel->AppendPredecessor(currentLabel); defaultLabel->MergeControl(defaultCase); env_->SetCurrentLabel(nullptr); } void CircuitBuilder::LoopBegin(Label *loopHead) { ASSERT(loopHead); auto loopControl = LoopBegin(loopHead->GetControl()); loopHead->SetControl(loopControl); loopHead->SetPreControl(loopControl); loopHead->Bind(); env_->SetCurrentLabel(loopHead); } void CircuitBuilder::LoopEnd(Label *loopHead) { ASSERT(loopHead); auto currentLabel = GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto loopend = LoopEnd(currentControl); currentLabel->SetControl(loopend); loopHead->AppendPredecessor(currentLabel); loopHead->MergeControl(loopend); loopHead->Seal(); loopHead->MergeAllControl(); loopHead->MergeAllDepend(); env_->SetCurrentLabel(nullptr); } // add loop exit info at begin of label (only support not merge label) void CircuitBuilder::LoopExit(const std::vector &vars, size_t diff) { auto currentLabel = env_->GetCurrentLabel(); auto loopExit = currentLabel->GetControl(); auto loopExitDepend = currentLabel->GetDepend(); std::vector loopExitValues; for (size_t i = 0; i < diff; ++i) { loopExit = LoopExit(loopExit); loopExitDepend = LoopExitDepend(loopExit, loopExitDepend); for (const auto &var : vars) { auto loopExitValue = LoopExitValue(loopExit, var->ReadVariable()); var->WriteVariable(loopExitValue); } } currentLabel->SetControl(loopExit); currentLabel->SetDepend(loopExitDepend); } void CircuitBuilder::ClearConstantCache(GateRef gate) { ASSERT(acc_.GetOpCode(gate) == OpCode::CONSTANT); auto machineType = acc_.GetMachineType(gate); auto value = acc_.GetConstantValue(gate); auto gateType = acc_.GetGateType(gate); GetCircuit()->ClearConstantCache(machineType, value, gateType); } void CircuitBuilder::DeoptCheck(GateRef condition, GateRef frameState, DeoptType type) { std::string comment = Deoptimizier::DisplayItems(type); auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); ASSERT(acc_.GetOpCode(frameState) == OpCode::FRAME_STATE); GateRef deoptCheck = GetCircuit()->NewGate(circuit_->DeoptCheck(), MachineType::I1, { currentControl, currentDepend, condition, frameState, Int64(static_cast(type))}, GateType::NJSValue(), comment.c_str()); // Add a state output to avoid schedule a phi node to deoptCheck's BB by mistake GateRef trueBB = circuit_->NewGate(circuit_->OrdinaryBlock(), { deoptCheck }); auto dependRelay = DependRelay(trueBB, currentDepend); currentLabel->SetControl(trueBB); currentLabel->SetDepend(dependRelay); } GateRef CircuitBuilder::GetSuperConstructor(GateRef ctor) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto ret = GetCircuit()->NewGate(circuit_->GetSuperConstructor(), MachineType::ANYVALUE, { currentControl, currentDepend, ctor }, GateType::TaggedValue()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); return ret; } GateRef CircuitBuilder::Int8(int8_t val) { return GetCircuit()->GetConstantGate(MachineType::I8, val, GateType::NJSValue()); } GateRef CircuitBuilder::Int16(int16_t val) { return GetCircuit()->GetConstantGate(MachineType::I16, val, GateType::NJSValue()); } GateRef CircuitBuilder::Int32(int32_t val) { return GetCircuit()->GetConstantGate(MachineType::I32, static_cast(val), GateType::NJSValue()); } GateRef CircuitBuilder::Int64(int64_t val) { return GetCircuit()->GetConstantGate(MachineType::I64, val, GateType::NJSValue()); } GateRef CircuitBuilder::IntPtr(int64_t val) { return GetCircuit()->GetConstantGate(MachineType::ARCH, val, GateType::NJSValue()); } GateRef CircuitBuilder::StringPtr(std::string_view str) { return GetCircuit()->GetConstantStringGate(MachineType::ARCH, str, GateType::NJSValue()); } GateRef CircuitBuilder::RelocatableData(uint64_t val) { return GetCircuit()->NewGate(circuit_->RelocatableData(val), MachineType::ARCH, GateType::TaggedValue()); } GateRef CircuitBuilder::Boolean(bool val) { return GetCircuit()->GetConstantGate(MachineType::I1, val ? 1 : 0, GateType::NJSValue()); } GateRef CircuitBuilder::Double(double val) { return GetCircuit()->GetConstantGate(MachineType::F64, base::bit_cast(val), GateType::NJSValue()); } GateRef CircuitBuilder::HoleConstant() { auto type = GateType::TaggedValue(); return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_HOLE, type); } GateRef CircuitBuilder::SpecialHoleConstant() { auto type = GateType::NJSValue(); return GetCircuit()->GetConstantGate(MachineType::I64, base::SPECIAL_HOLE, type); } GateRef CircuitBuilder::NullPtrConstant() { auto type = GateType::TaggedValue(); return GetCircuit()->GetConstantGate(MachineType::I64, 0u, type); } GateRef CircuitBuilder::NullConstant() { auto type = GateType::TaggedValue(); return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_NULL, type); } GateRef CircuitBuilder::ExceptionConstant() { auto type = GateType::TaggedValue(); return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_EXCEPTION, type); } GateRef CircuitBuilder::NanValue() { return Double(std::numeric_limits::quiet_NaN()); } GateRef CircuitBuilder::LoadObjectFromConstPool(GateRef constPool, GateRef index) { return GetValueFromTaggedArray(constPool, TruncInt64ToInt32(index)); } GateRef CircuitBuilder::IsAccessorInternal(GateRef accessor) { return Int32Equal(GetObjectType(LoadHClass(accessor)), Int32(static_cast(JSType::INTERNAL_ACCESSOR))); } void CircuitBuilder::AppendFrameArgs(std::vector &args, GateRef hirGate) { GateRef frameArgs = acc_.GetFrameArgs(hirGate); if (frameArgs == Circuit::NullGate()) { args.emplace_back(IntPtr(0)); } else { args.emplace_back(frameArgs); } } GateRef CircuitBuilder::GetUnsharedConstpool(GateRef constpool) { auto currentLabel = env_->GetCurrentLabel(); auto currentDepend = currentLabel->GetDepend(); auto newGate = GetCircuit()->NewGate(circuit_->GetUnsharedConstpool(), MachineType::I64, { currentDepend, constpool }, GateType::AnyType()); currentLabel->SetDepend(newGate); return newGate; } GateRef CircuitBuilder::GetGlobalEnv() { auto currentLabel = env_->GetCurrentLabel(); auto currentDepend = currentLabel->GetDepend(); auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalEnv(), MachineType::I64, { currentDepend }, GateType::AnyType()); currentLabel->SetDepend(newGate); return newGate; } GateRef CircuitBuilder::GetGlobalEnvObj(GateRef env, size_t index) { auto currentLabel = env_->GetCurrentLabel(); auto currentDepend = currentLabel->GetDepend(); auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalEnvObj(index), MachineType::I64, { currentDepend, env }, GateType::AnyType()); currentLabel->SetDepend(newGate); return newGate; } GateRef CircuitBuilder::GetGlobalEnvObjHClass(GateRef env, size_t index) { auto currentLabel = env_->GetCurrentLabel(); auto currentDepend = currentLabel->GetDepend(); auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalEnvObjHClass(index), MachineType::I64, { currentDepend, env }, GateType::AnyType()); currentLabel->SetDepend(newGate); return newGate; } GateRef CircuitBuilder::GetGlobalConstantValue(ConstantIndex index) { auto currentLabel = env_->GetCurrentLabel(); auto currentDepend = currentLabel->GetDepend(); auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalConstantValue(static_cast(index)), MachineType::I64, { currentDepend }, GateType::AnyType()); currentLabel->SetDepend(newGate); return newGate; } GateRef CircuitBuilder::HasPendingException(GateRef glue) { GateRef exceptionOffset = IntPtr(JSThread::GlueData::GetExceptionOffset(env_->IsArch32Bit())); GateRef exception = Load(VariableType::JS_ANY(), glue, exceptionOffset); return TaggedIsNotHole(exception); } GateRef CircuitBuilder::IsUtf8String(GateRef string) { // compressedStringsEnabled fixed to true constant GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET)); return Int32Equal( Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)), Int32(EcmaString::STRING_COMPRESSED)); } GateRef CircuitBuilder::IsUtf16String(GateRef string) { // compressedStringsEnabled fixed to true constant GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET)); return Int32Equal( Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)), Int32(EcmaString::STRING_UNCOMPRESSED)); } GateRef CircuitBuilder::GetGlobalObject(GateRef glue) { GateRef offset = IntPtr(JSThread::GlueData::GetGlobalObjOffset(cmpCfg_->Is32Bit())); return Load(VariableType::JS_ANY(), glue, offset); } GateRef CircuitBuilder::GetMethodFromFunction(GateRef function) { GateRef offset = IntPtr(JSFunctionBase::METHOD_OFFSET); return Load(VariableType::JS_POINTER(), function, offset); } GateRef CircuitBuilder::GetModuleFromFunction(GateRef function) { GateRef offset = IntPtr(JSFunction::ECMA_MODULE_OFFSET); return Load(VariableType::JS_POINTER(), function, offset); } GateRef CircuitBuilder::GetHomeObjectFromFunction(GateRef function) { GateRef offset = IntPtr(JSFunction::HOME_OBJECT_OFFSET); return Load(VariableType::JS_POINTER(), function, offset); } GateRef CircuitBuilder::GetConstPoolFromFunction(GateRef jsFunc) { GateRef method = GetMethodFromFunction(jsFunc); return Load(VariableType::JS_ANY(), method, IntPtr(Method::CONSTANT_POOL_OFFSET)); } GateRef CircuitBuilder::GetUnsharedConstpoolFromGlue(GateRef glue, GateRef constpool) { GateRef unshareIdx = GetUnsharedConstpoolIndex(constpool); GateRef unshareCpOffset = JSThread::GlueData::GetUnSharedConstpoolsOffset(env_->Is32Bit()); GateRef unshareCpAddr = Load(VariableType::NATIVE_POINTER(), glue, IntPtr(unshareCpOffset)); return GetUnsharedConstpool(unshareCpAddr, unshareIdx); } GateRef CircuitBuilder::GetUnsharedConstpoolIndex(GateRef constpool) { GateRef constPoolSize = GetLengthOfTaggedArray(constpool); GateRef unshareIdx = Int32Sub(constPoolSize, Int32(ConstantPool::UNSHARED_CONSTPOOL_INDEX)); return GetValueFromTaggedArray(constpool, unshareIdx); } GateRef CircuitBuilder::GetUnsharedConstpool(GateRef arrayAddr, GateRef index) { GateRef dataOffset = PtrAdd(arrayAddr, PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), ZExtInt32ToPtr(TaggedGetInt(index)))); return Load(VariableType::JS_ANY(), dataOffset, IntPtr(0)); } GateRef CircuitBuilder::GetEmptyArray(GateRef glue) { GateRef gConstAddr = Load(VariableType::JS_ANY(), glue, IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit()))); GateRef offset = GetGlobalConstantOffset(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX); return Load(VariableType::JS_ANY(), gConstAddr, offset); } GateRef CircuitBuilder::GetPrototypeFromHClass(GateRef hClass) { GateRef protoOffset = IntPtr(JSHClass::PROTOTYPE_OFFSET); return Load(VariableType::JS_ANY(), hClass, protoOffset); } GateRef CircuitBuilder::GetEnumCacheFromHClass(GateRef hClass) { GateRef offset = IntPtr(JSHClass::ENUM_CACHE_OFFSET); return Load(VariableType::JS_ANY(), hClass, offset); } GateRef CircuitBuilder::GetProtoChangeMarkerFromHClass(GateRef hClass) { GateRef offset = IntPtr(JSHClass::PROTO_CHANGE_MARKER_OFFSET); return Load(VariableType::JS_ANY(), hClass, offset); } GateRef CircuitBuilder::GetLengthFromForInIterator(GateRef iter) { GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET); return Load(VariableType::INT32(), iter, offset); } GateRef CircuitBuilder::GetIndexFromForInIterator(GateRef iter) { GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET); return Load(VariableType::INT32(), iter, offset); } GateRef CircuitBuilder::GetKeysFromForInIterator(GateRef iter) { GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET); return Load(VariableType::JS_ANY(), iter, offset); } GateRef CircuitBuilder::GetObjectFromForInIterator(GateRef iter) { GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET); return Load(VariableType::JS_ANY(), iter, offset); } GateRef CircuitBuilder::GetCachedHclassFromForInIterator(GateRef iter) { GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET); return Load(VariableType::JS_ANY(), iter, offset); } void CircuitBuilder::SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length) { GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET); Store(VariableType::INT32(), glue, iter, offset, length); } void CircuitBuilder::SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index) { GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET); Store(VariableType::INT32(), glue, iter, offset, index); } void CircuitBuilder::SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys) { GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET); Store(VariableType::JS_ANY(), glue, iter, offset, keys); } void CircuitBuilder::SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object) { GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET); Store(VariableType::JS_ANY(), glue, iter, offset, object); } void CircuitBuilder::SetCachedHclassOfForInIterator(GateRef glue, GateRef iter, GateRef hclass) { GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET); Store(VariableType::JS_ANY(), glue, iter, offset, hclass); } void CircuitBuilder::SetNextIndexOfArrayIterator(GateRef glue, GateRef iter, GateRef nextIndex) { GateRef offset = IntPtr(JSArrayIterator::NEXT_INDEX_OFFSET); Store(VariableType::INT32(), glue, iter, offset, nextIndex); } void CircuitBuilder::SetIteratedArrayOfArrayIterator(GateRef glue, GateRef iter, GateRef iteratedArray) { GateRef offset = IntPtr(JSArrayIterator::ITERATED_ARRAY_OFFSET); Store(VariableType::JS_ANY(), glue, iter, offset, iteratedArray); } void CircuitBuilder::SetBitFieldOfArrayIterator(GateRef glue, GateRef iter, GateRef kind) { GateRef offset = IntPtr(JSArrayIterator::BIT_FIELD_OFFSET); Store(VariableType::INT32(), glue, iter, offset, kind); } void CircuitBuilder::IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index) { GateRef newIndex = Int32Add(index, Int32(1)); GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET); Store(VariableType::INT32(), glue, iter, offset, newIndex); } GateRef CircuitBuilder::GetHasChanged(GateRef object) { GateRef bitfieldOffset = IntPtr(ProtoChangeMarker::BIT_FIELD_OFFSET); GateRef bitfield = Load(VariableType::INT32(), object, bitfieldOffset); GateRef mask = Int32(1LLU << (ProtoChangeMarker::HAS_CHANGED_BITS - 1)); return Int32NotEqual(Int32And(bitfield, mask), Int32(0)); } GateRef CircuitBuilder::GetAccessorHasChanged(GateRef object) { GateRef bitfieldOffset = IntPtr(ProtoChangeMarker::BIT_FIELD_OFFSET); GateRef bitfield = Load(VariableType::INT32(), object, bitfieldOffset); return Int32NotEqual( Int32And(Int32LSR(bitfield, Int32(ProtoChangeMarker::AccessorHasChangedBits::START_BIT)), Int32((1LLU << ProtoChangeMarker::AccessorHasChangedBits::SIZE) - 1)), Int32(0)); } GateRef CircuitBuilder::HasDeleteProperty(GateRef hClass) { GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET)); return Int32NotEqual( Int32And(Int32LSR(bitfield, Int32(JSHClass::HasDeletePropertyBit::START_BIT)), Int32((1LLU << JSHClass::HasDeletePropertyBit::SIZE) - 1)), Int32(0)); } GateRef CircuitBuilder::IsOnHeap(GateRef hClass) { GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD_OFFSET)); return Int32NotEqual( Int32And(Int32LSR(bitfield, Int32(JSHClass::IsOnHeap::START_BIT)), Int32((1LU << JSHClass::IsOnHeap::SIZE) - 1)), Int32(0)); } GateRef CircuitBuilder::IsEcmaObject(GateRef obj) { Label entryPass(env_); SubCfgEntry(&entryPass); DEFVALUE(result, env_, VariableType::BOOL(), False()); Label heapObj(env_); Label exit(env_); GateRef isHeapObject = TaggedIsHeapObject(obj); BRANCH_CIR2(isHeapObject, &heapObj, &exit); Bind(&heapObj); result = LogicAnd(isHeapObject, TaggedObjectIsEcmaObject(obj)); Jump(&exit); Bind(&exit); auto ret = *result; SubCfgExit(); return ret; } GateRef CircuitBuilder::CheckJSType(GateRef object, JSType jsType) { Label entryPass(env_); SubCfgEntry(&entryPass); DEFVALUE(result, env_, VariableType::BOOL(), False()); Label heapObj(env_); Label exit(env_); GateRef isHeapObject = TaggedIsHeapObject(object); BRANCH_CIR2(isHeapObject, &heapObj, &exit); Bind(&heapObj); { GateRef objectType = GetObjectType(LoadHClass(object)); GateRef checkType = Int32Equal(objectType, Int32(static_cast(jsType))); result = LogicAnd(isHeapObject, checkType); Jump(&exit); } Bind(&exit); auto ret = *result; SubCfgExit(); return ret; } GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module, GateRef index, ConstPoolType type) { Label entry(env_); SubCfgEntry(&entry); Label exit(env_); Label cacheMiss(env_); Label cache(env_); // HirGate Can not be a nullGate in Aot if (GetCircuit()->IsOptimizedJSFunctionFrame() && hirGate == Circuit::NullGate()) { hirGate = index; } auto cacheValue = GetValueFromTaggedArray(constPool, index); DEFVALUE(result, env_, VariableType::JS_ANY(), cacheValue); BRANCH_CIR2(BoolOr(TaggedIsHole(*result), TaggedIsNullPtr(*result)), &cacheMiss, &cache); Bind(&cacheMiss); { if (type == ConstPoolType::STRING) { result = CallRuntime(glue, RTSTUB_ID(GetStringFromCache), Gate::InvalidGateRef, { constPool, Int32ToTaggedInt(index) }, hirGate); } else if (type == ConstPoolType::ARRAY_LITERAL) { result = CallRuntime(glue, RTSTUB_ID(GetArrayLiteralFromCache), Gate::InvalidGateRef, { constPool, Int32ToTaggedInt(index), module }, hirGate); } else if (type == ConstPoolType::OBJECT_LITERAL) { result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef, { constPool, Int32ToTaggedInt(index), module }, hirGate); } else { result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef, { constPool, Int32ToTaggedInt(index) }, hirGate); } Jump(&exit); } Bind(&cache); { if (type == ConstPoolType::METHOD) { Label isAOTLiteralInfo(env_); BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit); Bind(&isAOTLiteralInfo); { result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef, { constPool, Int32ToTaggedInt(index) }, hirGate); Jump(&exit); } } else if (type == ConstPoolType::ARRAY_LITERAL) { Label isAOTLiteralInfo(env_); BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit); Bind(&isAOTLiteralInfo); { result = CallRuntime(glue, RTSTUB_ID(GetArrayLiteralFromCache), Gate::InvalidGateRef, { constPool, Int32ToTaggedInt(index), module }, hirGate); Jump(&exit); } } else if (type == ConstPoolType::OBJECT_LITERAL) { Label isAOTLiteralInfo(env_); BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit); Bind(&isAOTLiteralInfo); { result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef, { constPool, Int32ToTaggedInt(index), module }, hirGate); Jump(&exit); } } else { Jump(&exit); } } Bind(&exit); auto ret = *result; SubCfgExit(); return ret; } GateRef CircuitBuilder::GetFunctionLexicalEnv(GateRef function) { return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::LEXICAL_ENV_OFFSET)); } void CircuitBuilder::SetLengthToFunction(GateRef glue, GateRef function, GateRef value) { GateRef offset = IntPtr(JSFunction::LENGTH_OFFSET); Store(VariableType::INT32(), glue, function, offset, value); } void CircuitBuilder::SetLexicalEnvToFunction(GateRef glue, GateRef function, GateRef value) { GateRef offset = IntPtr(JSFunction::LEXICAL_ENV_OFFSET); Store(VariableType::JS_ANY(), glue, function, offset, value); } void CircuitBuilder::SetHomeObjectToFunction(GateRef glue, GateRef function, GateRef value) { GateRef offset = IntPtr(JSFunction::HOME_OBJECT_OFFSET); Store(VariableType::JS_ANY(), glue, function, offset, value); } void CircuitBuilder::SetModuleToFunction(GateRef glue, GateRef function, GateRef value) { GateRef offset = IntPtr(JSFunction::ECMA_MODULE_OFFSET); Store(VariableType::JS_POINTER(), glue, function, offset, value); } GateRef CircuitBuilder::GetGlobalEnvValue(VariableType type, GateRef env, size_t index) { auto valueIndex = IntPtr(GlobalEnv::HEADER_SIZE + JSTaggedValue::TaggedTypeSize() * index); return Load(type, env, valueIndex); } GateRef CircuitBuilder::GetCodeAddr(GateRef jsFunc) { auto codeAddOffset = IntPtr(JSFunction::CODE_ENTRY_OFFSET); return Load(VariableType::NATIVE_POINTER(), jsFunc, codeAddOffset); } GateRef CircuitBuilder::GetHClassGateFromIndex(GateRef gate, int32_t index) { ArgumentAccessor argAcc(circuit_); GateRef constPool = argAcc.GetFrameArgsIn(gate, FrameArgIdx::CONST_POOL); GateRef unsharedConstpool = GetUnsharedConstpool(constPool); return LoadHClassFromUnsharedConstpool(unsharedConstpool, index); } GateRef Variable::AddPhiOperand(GateRef val) { ASSERT(GateAccessor(env_->GetCircuit()).IsValueSelector(val)); Label label = env_->GetLabelFromSelector(val); size_t idx = 0; for (auto pred : label.GetPredecessors()) { auto preVal = pred.ReadVariable(this); ASSERT(!GateAccessor(env_->GetCircuit()).IsNop(preVal)); idx++; val = AddOperandToSelector(val, idx, preVal); } return TryRemoveTrivialPhi(val); } GateRef Variable::AddOperandToSelector(GateRef val, size_t idx, GateRef in) { GateAccessor(env_->GetCircuit()).NewIn(val, idx, in); return val; } GateRef Variable::TryRemoveTrivialPhi(GateRef phi) { GateAccessor acc(GetCircuit()); GateRef same = Gate::InvalidGateRef; const size_t inNum = acc.GetNumIns(phi); for (size_t i = 1; i < inNum; ++i) { GateRef phiIn = acc.GetIn(phi, i); if (phiIn == same || phiIn == phi) { continue; // unique value or self-reference } if (same != Gate::InvalidGateRef) { return phi; // the phi merges at least two valusses: not trivial } same = phiIn; } if (same == Gate::InvalidGateRef) { // the phi is unreachable or in the start block GateType type = acc.GetGateType(phi); same = env_->GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, type); } // remove the trivial phi // get all users of phi except self std::vector outs; auto uses = acc.Uses(phi); for (auto use = uses.begin(); use != uses.end();) { GateRef u = *use; if (u != phi) { outs.push_back(u); use = acc.ReplaceIn(use, same); } else { use++; } } acc.DeleteGate(phi); // try to recursiveby remove all phi users, which might have vecome trivial for (auto out : outs) { if (acc.IsValueSelector(out)) { auto result = TryRemoveTrivialPhi(out); if (same == out) { same = result; } } } return same; } GateRef CircuitBuilder::ElementsKindIsIntOrHoleInt(GateRef kind) { GateRef kindIsInt = Int32Equal(kind, Int32(static_cast(ElementsKind::INT))); GateRef kindIsHoleInt = Int32Equal(kind, Int32(static_cast(ElementsKind::HOLE_INT))); return BoolOr(kindIsInt, kindIsHoleInt); } GateRef CircuitBuilder::ElementsKindIsNumOrHoleNum(GateRef kind) { GateRef kindIsNum = Int32Equal(kind, Int32(static_cast(ElementsKind::NUMBER))); GateRef kindIsHoleNum = Int32Equal(kind, Int32(static_cast(ElementsKind::HOLE_NUMBER))); return BoolOr(kindIsNum, kindIsHoleNum); } GateRef CircuitBuilder::ElementsKindIsHeapKind(GateRef kind) { GateRef overString = Int32GreaterThanOrEqual(kind, Int32(static_cast(ElementsKind::STRING))); GateRef isHoleOrNone = Int32LessThanOrEqual(kind, Int32(static_cast(ElementsKind::HOLE))); return BoolOr(overString, isHoleOrNone); } GateRef CircuitBuilder::LoadBuiltinObject(size_t offset) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto frameState = acc_.FindNearestFrameState(currentDepend); GateRef ret = GetCircuit()->NewGate(circuit_->LoadBuiltinObject(offset), MachineType::I64, {currentControl, currentDepend, frameState}, GateType::AnyType()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); return ret; } } // namespace panda::ecmascript::kungfu