1/* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/compiler/circuit_builder.h" 17 18#include "ecmascript/compiler/builtins/builtins_call_signature.h" 19#include "ecmascript/compiler/circuit_builder-inl.h" 20#include "ecmascript/compiler/hcr_circuit_builder.h" 21#include "ecmascript/compiler/lcr_circuit_builder.h" 22#include "ecmascript/compiler/mcr_circuit_builder.h" 23#include "ecmascript/compiler/new_object_stub_builder.h" 24#include "ecmascript/compiler/rt_call_signature.h" 25#include "ecmascript/compiler/share_gate_meta_data.h" 26#include "ecmascript/deoptimizer/deoptimizer.h" 27#include "ecmascript/global_env.h" 28#include "ecmascript/ic/proto_change_details.h" 29#include "ecmascript/js_array_iterator.h" 30#include "ecmascript/js_for_in_iterator.h" 31#include "ecmascript/js_function.h" 32#include "ecmascript/js_primitive_ref.h" 33#include "ecmascript/js_thread.h" 34#include "ecmascript/jspandafile/program_object.h" 35#include "ecmascript/lexical_env.h" 36#include "ecmascript/mem/region.h" 37#include "ecmascript/message_string.h" 38#include "ecmascript/method.h" 39#include "ecmascript/sendable_env.h" 40 41namespace panda::ecmascript::kungfu { 42 43GateRef CircuitBuilder::Merge(const std::vector<GateRef> &inList) 44{ 45 return circuit_->NewGate(circuit_->Merge(inList.size()), inList); 46} 47 48GateRef CircuitBuilder::Selector(OpCode opcode, MachineType machineType, GateRef control, 49 const std::vector<GateRef> &values, int valueCounts, VariableType type) 50{ 51 std::vector<GateRef> inList; 52 inList.push_back(control); 53 if (values.size() == 0) { 54 for (int i = 0; i < valueCounts; i++) { 55 inList.push_back(Circuit::NullGate()); 56 } 57 } else { 58 for (int i = 0; i < valueCounts; i++) { 59 inList.push_back(values[i]); 60 } 61 } 62 ASSERT((opcode == OpCode::VALUE_SELECTOR) || (opcode == OpCode::DEPEND_SELECTOR)); 63 const GateMetaData* meta = (opcode == OpCode::DEPEND_SELECTOR) ? 64 circuit_->DependSelector(valueCounts) : circuit_->ValueSelector(valueCounts); 65 return circuit_->NewGate(meta, machineType, inList.size(), inList.data(), type.GetGateType()); 66} 67 68GateRef CircuitBuilder::Selector(OpCode opcode, GateRef control, 69 const std::vector<GateRef> &values, int valueCounts, VariableType type) 70{ 71 MachineType machineType = (opcode == OpCode::DEPEND_SELECTOR) ? 72 MachineType::NOVALUE : MachineType::FLEX; 73 return Selector(opcode, machineType, control, values, valueCounts, type); 74} 75 76GateRef CircuitBuilder::Nop() 77{ 78 return circuit_->NewGate(circuit_->Nop(), {}); 79} 80 81GateRef CircuitBuilder::UndefineConstant() 82{ 83 auto type = GateType::TaggedValue(); 84 return circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, type); 85} 86 87GateRef CircuitBuilder::Branch(GateRef state, GateRef condition, uint32_t trueWeight, uint32_t falseWeight, 88 const char* comment) 89{ 90 auto value = BranchAccessor::ToValue(trueWeight, falseWeight); 91 return circuit_->NewGate(circuit_->IfBranch(value), { state, condition }, comment); 92} 93 94GateRef CircuitBuilder::SwitchBranch(GateRef state, GateRef index, int caseCounts) 95{ 96 return circuit_->NewGate(circuit_->SwitchBranch(caseCounts), { state, index }); 97} 98 99GateRef CircuitBuilder::Return(GateRef state, GateRef depend, GateRef value) 100{ 101 auto returnList = circuit_->GetReturnRoot(); 102 return circuit_->NewGate(circuit_->Return(), { state, depend, value, returnList }); 103} 104 105GateRef CircuitBuilder::ReturnVoid(GateRef state, GateRef depend) 106{ 107 auto returnList = circuit_->GetReturnRoot(); 108 return circuit_->NewGate(circuit_->ReturnVoid(), { state, depend, returnList }); 109} 110 111GateRef CircuitBuilder::Goto(GateRef state) 112{ 113 return circuit_->NewGate(circuit_->OrdinaryBlock(), { state }); 114} 115 116GateRef CircuitBuilder::LoopBegin(GateRef state) 117{ 118 auto nullGate = Circuit::NullGate(); 119 return circuit_->NewGate(circuit_->LoopBegin(2), { state, nullGate }); // 2: entry&back 120} 121 122GateRef CircuitBuilder::LoopEnd(GateRef state) 123{ 124 return circuit_->NewGate(circuit_->LoopBack(), { state }); 125} 126 127GateRef CircuitBuilder::LoopExit(GateRef state) 128{ 129 return circuit_->NewGate(circuit_->LoopExit(), { state }); 130} 131 132GateRef CircuitBuilder::LoopExitDepend(GateRef state, GateRef depend) 133{ 134 return circuit_->NewGate(circuit_->LoopExitDepend(), { state, depend }); 135} 136 137GateRef CircuitBuilder::LoopExitValue(GateRef state, GateRef value) 138{ 139 auto machineType = acc_.GetMachineType(value); 140 auto gateType = acc_.GetGateType(value); 141 return circuit_->NewGate(circuit_->LoopExitValue(), machineType, { state, value }, gateType); 142} 143 144GateRef CircuitBuilder::IfTrue(GateRef ifBranch) 145{ 146 return circuit_->NewGate(circuit_->IfTrue(), { ifBranch }); 147} 148 149GateRef CircuitBuilder::IfFalse(GateRef ifBranch) 150{ 151 return circuit_->NewGate(circuit_->IfFalse(), { ifBranch }); 152} 153 154GateRef CircuitBuilder::SwitchCase(GateRef switchBranch, int64_t value) 155{ 156 return circuit_->NewGate(circuit_->SwitchCase(value), { switchBranch }); 157} 158 159GateRef CircuitBuilder::DefaultCase(GateRef switchBranch) 160{ 161 return circuit_->NewGate(circuit_->DefaultCase(), { switchBranch }); 162} 163 164GateRef CircuitBuilder::DependRelay(GateRef state, GateRef depend) 165{ 166 return circuit_->NewGate(circuit_->DependRelay(), { state, depend }); 167} 168 169GateRef CircuitBuilder::Arguments(size_t index) 170{ 171 auto argListOfCircuit = circuit_->GetArgRoot(); 172 return GetCircuit()->NewArg(MachineType::I64, index, GateType::NJSValue(), argListOfCircuit); 173} 174 175GateRef CircuitBuilder::IsJsCOWArray(GateRef obj) 176{ 177 // Elements of JSArray are shared and properties are not yet. 178 GateRef elements = GetElementsArray(obj); 179 GateRef objectType = GetObjectType(LoadHClass(elements)); 180 return IsCOWArray(objectType); 181} 182 183GateRef CircuitBuilder::IsCOWArray(GateRef objectType) 184{ 185 return BitOr(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::COW_TAGGED_ARRAY))), 186 Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::COW_MUTANT_TAGGED_ARRAY)))); 187} 188 189GateRef CircuitBuilder::IsTaggedArray(GateRef object) 190{ 191 GateRef objectType = GetObjectType(LoadHClass(object)); 192 return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::TAGGED_ARRAY))); 193} 194 195GateRef CircuitBuilder::IsMutantTaggedArray(GateRef objectType) 196{ 197 return BitOr(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::MUTANT_TAGGED_ARRAY))), 198 Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::COW_MUTANT_TAGGED_ARRAY)))); 199} 200 201GateRef CircuitBuilder::GetElementsArray(GateRef object) 202{ 203 GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET); 204 return Load(VariableType::JS_POINTER(), object, elementsOffset); 205} 206 207GateRef CircuitBuilder::GetLengthOfTaggedArray(GateRef array) 208{ 209 return Load(VariableType::INT32(), array, IntPtr(TaggedArray::LENGTH_OFFSET)); 210} 211 212GateRef CircuitBuilder::GetLengthOfJSTypedArray(GateRef array) 213{ 214 return Load(VariableType::INT32(), array, IntPtr(JSTypedArray::ARRAY_LENGTH_OFFSET)); 215} 216 217GateRef CircuitBuilder::GetDataOfTaggedArray(GateRef array) 218{ 219 return PtrAdd(array, Int64(TaggedArray::DATA_OFFSET)); 220} 221 222GateRef CircuitBuilder::GetLengthOfJSArray(GateRef array) 223{ 224 return Load(VariableType::INT32(), array, IntPtr(JSArray::LENGTH_OFFSET)); 225} 226 227GateRef CircuitBuilder::IsTypedArray(GateRef array) 228{ 229 GateRef hclass = LoadHClass(array); 230 GateRef type = GetObjectType(hclass); 231 return BitAnd(Int32GreaterThan(type, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY_FIRST))), 232 Int32GreaterThanOrEqual(Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY_LAST)), type)); 233} 234 235void CircuitBuilder::Jump(Label *label) 236{ 237 ASSERT(label); 238 auto currentLabel = env_->GetCurrentLabel(); 239 auto currentControl = currentLabel->GetControl(); 240 auto jump = Goto(currentControl); 241 currentLabel->SetControl(jump); 242 label->AppendPredecessor(currentLabel); 243 label->MergeControl(currentLabel->GetControl()); 244 env_->SetCurrentLabel(nullptr); 245} 246 247void CircuitBuilder::Branch(GateRef condition, Label *trueLabel, Label *falseLabel, 248 uint32_t trueWeight, uint32_t falseWeight, const char* comment) 249{ 250 auto currentLabel = env_->GetCurrentLabel(); 251 auto currentControl = currentLabel->GetControl(); 252 GateRef ifBranch = Branch(currentControl, condition, trueWeight, falseWeight, comment); 253 currentLabel->SetControl(ifBranch); 254 GateRef ifTrue = IfTrue(ifBranch); 255 trueLabel->AppendPredecessor(GetCurrentLabel()); 256 trueLabel->MergeControl(ifTrue); 257 GateRef ifFalse = IfFalse(ifBranch); 258 falseLabel->AppendPredecessor(GetCurrentLabel()); 259 falseLabel->MergeControl(ifFalse); 260 env_->SetCurrentLabel(nullptr); 261} 262 263void CircuitBuilder::Switch(GateRef index, Label *defaultLabel, int64_t *keysValue, Label *keysLabel, int numberOfKeys) 264{ 265 auto currentLabel = env_->GetCurrentLabel(); 266 auto currentControl = currentLabel->GetControl(); 267 GateRef switchBranch = SwitchBranch(currentControl, index, numberOfKeys); 268 currentLabel->SetControl(switchBranch); 269 for (int i = 0; i < numberOfKeys; i++) { 270 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 271 GateRef switchCase = SwitchCase(switchBranch, keysValue[i]); 272 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 273 keysLabel[i].AppendPredecessor(currentLabel); 274 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 275 keysLabel[i].MergeControl(switchCase); 276 } 277 278 GateRef defaultCase = DefaultCase(switchBranch); 279 defaultLabel->AppendPredecessor(currentLabel); 280 defaultLabel->MergeControl(defaultCase); 281 env_->SetCurrentLabel(nullptr); 282} 283 284void CircuitBuilder::LoopBegin(Label *loopHead) 285{ 286 ASSERT(loopHead); 287 auto loopControl = LoopBegin(loopHead->GetControl()); 288 loopHead->SetControl(loopControl); 289 loopHead->SetPreControl(loopControl); 290 loopHead->Bind(); 291 env_->SetCurrentLabel(loopHead); 292} 293 294void CircuitBuilder::LoopEnd(Label *loopHead) 295{ 296 ASSERT(loopHead); 297 auto currentLabel = GetCurrentLabel(); 298 auto currentControl = currentLabel->GetControl(); 299 auto loopend = LoopEnd(currentControl); 300 currentLabel->SetControl(loopend); 301 loopHead->AppendPredecessor(currentLabel); 302 loopHead->MergeControl(loopend); 303 loopHead->Seal(); 304 loopHead->MergeAllControl(); 305 loopHead->MergeAllDepend(); 306 env_->SetCurrentLabel(nullptr); 307} 308 309// add loop exit info at begin of label (only support not merge label) 310void CircuitBuilder::LoopExit(const std::vector<Variable *> &vars, size_t diff) 311{ 312 auto currentLabel = env_->GetCurrentLabel(); 313 auto loopExit = currentLabel->GetControl(); 314 auto loopExitDepend = currentLabel->GetDepend(); 315 std::vector<GateRef> loopExitValues; 316 for (size_t i = 0; i < diff; ++i) { 317 loopExit = LoopExit(loopExit); 318 loopExitDepend = LoopExitDepend(loopExit, loopExitDepend); 319 for (const auto &var : vars) { 320 auto loopExitValue = LoopExitValue(loopExit, var->ReadVariable()); 321 var->WriteVariable(loopExitValue); 322 } 323 } 324 currentLabel->SetControl(loopExit); 325 currentLabel->SetDepend(loopExitDepend); 326} 327 328void CircuitBuilder::ClearConstantCache(GateRef gate) 329{ 330 ASSERT(acc_.GetOpCode(gate) == OpCode::CONSTANT); 331 auto machineType = acc_.GetMachineType(gate); 332 auto value = acc_.GetConstantValue(gate); 333 auto gateType = acc_.GetGateType(gate); 334 GetCircuit()->ClearConstantCache(machineType, value, gateType); 335} 336 337void CircuitBuilder::DeoptCheck(GateRef condition, GateRef frameState, DeoptType type) 338{ 339 std::string comment = Deoptimizier::DisplayItems(type); 340 auto currentLabel = env_->GetCurrentLabel(); 341 auto currentControl = currentLabel->GetControl(); 342 auto currentDepend = currentLabel->GetDepend(); 343 ASSERT(acc_.GetOpCode(frameState) == OpCode::FRAME_STATE); 344 GateRef deoptCheck = GetCircuit()->NewGate(circuit_->DeoptCheck(), 345 MachineType::I1, { currentControl, currentDepend, condition, 346 frameState, Int64(static_cast<int64_t>(type))}, GateType::NJSValue(), comment.c_str()); 347 // Add a state output to avoid schedule a phi node to deoptCheck's BB by mistake 348 GateRef trueBB = circuit_->NewGate(circuit_->OrdinaryBlock(), { deoptCheck }); 349 auto dependRelay = DependRelay(trueBB, currentDepend); 350 currentLabel->SetControl(trueBB); 351 currentLabel->SetDepend(dependRelay); 352} 353 354GateRef CircuitBuilder::GetSuperConstructor(GateRef ctor) 355{ 356 auto currentLabel = env_->GetCurrentLabel(); 357 auto currentControl = currentLabel->GetControl(); 358 auto currentDepend = currentLabel->GetDepend(); 359 auto ret = GetCircuit()->NewGate(circuit_->GetSuperConstructor(), MachineType::ANYVALUE, 360 { currentControl, currentDepend, ctor }, GateType::TaggedValue()); 361 currentLabel->SetControl(ret); 362 currentLabel->SetDepend(ret); 363 return ret; 364} 365 366GateRef CircuitBuilder::Int8(int8_t val) 367{ 368 return GetCircuit()->GetConstantGate(MachineType::I8, val, GateType::NJSValue()); 369} 370 371GateRef CircuitBuilder::Int16(int16_t val) 372{ 373 return GetCircuit()->GetConstantGate(MachineType::I16, val, GateType::NJSValue()); 374} 375 376GateRef CircuitBuilder::Int32(int32_t val) 377{ 378 return GetCircuit()->GetConstantGate(MachineType::I32, static_cast<BitField>(val), GateType::NJSValue()); 379} 380 381GateRef CircuitBuilder::Int64(int64_t val) 382{ 383 return GetCircuit()->GetConstantGate(MachineType::I64, val, GateType::NJSValue()); 384} 385 386GateRef CircuitBuilder::IntPtr(int64_t val) 387{ 388 return GetCircuit()->GetConstantGate(MachineType::ARCH, val, GateType::NJSValue()); 389} 390 391GateRef CircuitBuilder::StringPtr(std::string_view str) 392{ 393 return GetCircuit()->GetConstantStringGate(MachineType::ARCH, str, GateType::NJSValue()); 394} 395 396GateRef CircuitBuilder::RelocatableData(uint64_t val) 397{ 398 return GetCircuit()->NewGate(circuit_->RelocatableData(val), 399 MachineType::ARCH, GateType::TaggedValue()); 400} 401 402GateRef CircuitBuilder::Boolean(bool val) 403{ 404 return GetCircuit()->GetConstantGate(MachineType::I1, val ? 1 : 0, GateType::NJSValue()); 405} 406 407GateRef CircuitBuilder::Double(double val) 408{ 409 return GetCircuit()->GetConstantGate(MachineType::F64, base::bit_cast<int64_t>(val), GateType::NJSValue()); 410} 411 412GateRef CircuitBuilder::HoleConstant() 413{ 414 auto type = GateType::TaggedValue(); 415 return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_HOLE, type); 416} 417 418GateRef CircuitBuilder::SpecialHoleConstant() 419{ 420 auto type = GateType::NJSValue(); 421 return GetCircuit()->GetConstantGate(MachineType::I64, base::SPECIAL_HOLE, type); 422} 423 424GateRef CircuitBuilder::NullPtrConstant() 425{ 426 auto type = GateType::TaggedValue(); 427 return GetCircuit()->GetConstantGate(MachineType::I64, 0u, type); 428} 429 430GateRef CircuitBuilder::NullConstant() 431{ 432 auto type = GateType::TaggedValue(); 433 return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_NULL, type); 434} 435 436GateRef CircuitBuilder::TaggedValueConstant(JSTaggedValue taggedValue) 437{ 438 auto type = GateType::TaggedValue(); 439 return GetCircuit()->GetConstantGate(MachineType::I64, taggedValue.GetRawData(), type); 440} 441 442GateRef CircuitBuilder::ExceptionConstant() 443{ 444 auto type = GateType::TaggedValue(); 445 return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_EXCEPTION, type); 446} 447 448GateRef CircuitBuilder::NanValue() 449{ 450 return Double(std::numeric_limits<double>::quiet_NaN()); 451} 452 453GateRef CircuitBuilder::LoadObjectFromConstPool(GateRef constPool, GateRef index) 454{ 455 return GetValueFromTaggedArray(constPool, TruncInt64ToInt32(index)); 456} 457 458GateRef CircuitBuilder::IsAccessorInternal(GateRef accessor) 459{ 460 return Int32Equal(GetObjectType(LoadHClass(accessor)), 461 Int32(static_cast<int32_t>(JSType::INTERNAL_ACCESSOR))); 462} 463 464void CircuitBuilder::AppendFrameArgs(std::vector<GateRef> &args, GateRef hirGate) 465{ 466 GateRef frameArgs = acc_.GetFrameArgs(hirGate); 467 if (frameArgs == Circuit::NullGate()) { 468 args.emplace_back(IntPtr(0)); 469 } else { 470 args.emplace_back(frameArgs); 471 } 472} 473 474GateRef CircuitBuilder::GetGlobalEnv() 475{ 476 auto currentLabel = env_->GetCurrentLabel(); 477 auto currentDepend = currentLabel->GetDepend(); 478 auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalEnv(), MachineType::I64, 479 { currentDepend }, 480 GateType::AnyType()); 481 currentLabel->SetDepend(newGate); 482 return newGate; 483} 484 485GateRef CircuitBuilder::GetGlobalEnvObj(GateRef env, size_t index) 486{ 487 auto currentLabel = env_->GetCurrentLabel(); 488 auto currentDepend = currentLabel->GetDepend(); 489 auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalEnvObj(index), MachineType::I64, 490 { currentDepend, env }, 491 GateType::AnyType()); 492 currentLabel->SetDepend(newGate); 493 return newGate; 494} 495 496GateRef CircuitBuilder::GetGlobalEnvObjHClass(GateRef env, size_t index) 497{ 498 auto currentLabel = env_->GetCurrentLabel(); 499 auto currentDepend = currentLabel->GetDepend(); 500 auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalEnvObjHClass(index), MachineType::I64, 501 { currentDepend, env }, 502 GateType::AnyType()); 503 currentLabel->SetDepend(newGate); 504 return newGate; 505} 506 507GateRef CircuitBuilder::GetGlobalConstantValue(ConstantIndex index) 508{ 509 auto currentLabel = env_->GetCurrentLabel(); 510 auto currentDepend = currentLabel->GetDepend(); 511 auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalConstantValue(static_cast<size_t>(index)), 512 MachineType::I64, { currentDepend }, GateType::AnyType()); 513 currentLabel->SetDepend(newGate); 514 return newGate; 515} 516 517GateRef CircuitBuilder::HasPendingException(GateRef glue) 518{ 519 GateRef exceptionOffset = IntPtr(JSThread::GlueData::GetExceptionOffset(env_->IsArch32Bit())); 520 GateRef exception = Load(VariableType::JS_ANY(), glue, exceptionOffset); 521 return TaggedIsNotHole(exception); 522} 523 524GateRef CircuitBuilder::IsUtf8String(GateRef string) 525{ 526 // compressedStringsEnabled fixed to true constant 527 GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET)); 528 return Int32Equal( 529 Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)), 530 Int32(EcmaString::STRING_COMPRESSED)); 531} 532 533GateRef CircuitBuilder::IsUtf16String(GateRef string) 534{ 535 // compressedStringsEnabled fixed to true constant 536 GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET)); 537 return Int32Equal( 538 Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)), 539 Int32(EcmaString::STRING_UNCOMPRESSED)); 540} 541 542GateRef CircuitBuilder::GetGlobalObject(GateRef glue) 543{ 544 GateRef offset = IntPtr(JSThread::GlueData::GetGlobalObjOffset(cmpCfg_->Is32Bit())); 545 return Load(VariableType::JS_ANY(), glue, offset); 546} 547 548GateRef CircuitBuilder::GetMethodFromFunction(GateRef function) 549{ 550 GateRef offset = IntPtr(JSFunctionBase::METHOD_OFFSET); 551 return Load(VariableType::JS_POINTER(), function, offset); 552} 553 554GateRef CircuitBuilder::GetModuleFromFunction(GateRef function) 555{ 556 GateRef offset = IntPtr(JSFunction::ECMA_MODULE_OFFSET); 557 return Load(VariableType::JS_POINTER(), function, offset); 558} 559 560GateRef CircuitBuilder::GetSendableEnvFromModule(GateRef module) 561{ 562 return Load(VariableType::JS_POINTER(), module, IntPtr(SourceTextModule::SENDABLE_ENV_OFFSET)); 563} 564 565void CircuitBuilder::SetSendableEnvToModule(GateRef glue, GateRef module, GateRef value) 566{ 567 GateRef offset = IntPtr(SourceTextModule::SENDABLE_ENV_OFFSET); 568 Store(VariableType::JS_POINTER(), glue, module, offset, value); 569} 570 571GateRef CircuitBuilder::GetHomeObjectFromFunction(GateRef function) 572{ 573 GateRef offset = IntPtr(JSFunction::HOME_OBJECT_OFFSET); 574 return Load(VariableType::JS_POINTER(), function, offset); 575} 576 577GateRef CircuitBuilder::GetConstPoolFromFunction(GateRef jsFunc) 578{ 579 GateRef method = GetMethodFromFunction(jsFunc); 580 return Load(VariableType::JS_ANY(), method, IntPtr(Method::CONSTANT_POOL_OFFSET)); 581} 582 583GateRef CircuitBuilder::GetUnsharedConstpoolFromGlue(GateRef glue, GateRef constpool) 584{ 585 GateRef unshareIdx = GetUnsharedConstpoolIndex(constpool); 586 GateRef unshareCpOffset = static_cast<int32_t>(JSThread::GlueData::GetUnSharedConstpoolsOffset(env_->Is32Bit())); 587 GateRef unshareCpAddr = Load(VariableType::NATIVE_POINTER(), glue, IntPtr(unshareCpOffset)); 588 return GetUnsharedConstpool(unshareCpAddr, unshareIdx); 589} 590 591GateRef CircuitBuilder::GetUnsharedConstpoolIndex(GateRef constpool) 592{ 593 GateRef constPoolSize = GetLengthOfTaggedArray(constpool); 594 GateRef unshareIdx = Int32Sub(constPoolSize, Int32(ConstantPool::UNSHARED_CONSTPOOL_INDEX)); 595 return GetValueFromTaggedArray(constpool, unshareIdx); 596} 597 598GateRef CircuitBuilder::GetUnsharedConstpool(GateRef arrayAddr, GateRef index) 599{ 600 GateRef dataOffset = PtrAdd(arrayAddr, 601 PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), ZExtInt32ToPtr(TaggedGetInt(index)))); 602 return Load(VariableType::JS_ANY(), dataOffset, IntPtr(0)); 603} 604 605GateRef CircuitBuilder::GetEmptyArray(GateRef glue) 606{ 607 GateRef gConstAddr = Load(VariableType::JS_ANY(), glue, 608 IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit()))); 609 GateRef offset = GetGlobalConstantOffset(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX); 610 return Load(VariableType::JS_ANY(), gConstAddr, offset); 611} 612 613GateRef CircuitBuilder::GetPrototypeFromHClass(GateRef hClass) 614{ 615 GateRef protoOffset = IntPtr(JSHClass::PROTOTYPE_OFFSET); 616 return Load(VariableType::JS_ANY(), hClass, protoOffset); 617} 618 619GateRef CircuitBuilder::GetEnumCacheFromHClass(GateRef hClass) 620{ 621 GateRef offset = IntPtr(JSHClass::ENUM_CACHE_OFFSET); 622 return Load(VariableType::JS_ANY(), hClass, offset); 623} 624 625GateRef CircuitBuilder::GetProtoChangeMarkerFromHClass(GateRef hClass) 626{ 627 GateRef offset = IntPtr(JSHClass::PROTO_CHANGE_MARKER_OFFSET); 628 return Load(VariableType::JS_ANY(), hClass, offset); 629} 630 631GateRef CircuitBuilder::GetLengthFromForInIterator(GateRef iter) 632{ 633 GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET); 634 return Load(VariableType::INT32(), iter, offset); 635} 636 637GateRef CircuitBuilder::GetIndexFromForInIterator(GateRef iter) 638{ 639 GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET); 640 return Load(VariableType::INT32(), iter, offset); 641} 642 643GateRef CircuitBuilder::GetKeysFromForInIterator(GateRef iter) 644{ 645 GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET); 646 return Load(VariableType::JS_ANY(), iter, offset); 647} 648 649GateRef CircuitBuilder::GetObjectFromForInIterator(GateRef iter) 650{ 651 GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET); 652 return Load(VariableType::JS_ANY(), iter, offset); 653} 654 655GateRef CircuitBuilder::GetCachedHclassFromForInIterator(GateRef iter) 656{ 657 GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET); 658 return Load(VariableType::JS_ANY(), iter, offset); 659} 660 661void CircuitBuilder::SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length) 662{ 663 GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET); 664 Store(VariableType::INT32(), glue, iter, offset, length); 665} 666 667void CircuitBuilder::SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index) 668{ 669 GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET); 670 Store(VariableType::INT32(), glue, iter, offset, index); 671} 672 673void CircuitBuilder::SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys) 674{ 675 GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET); 676 Store(VariableType::JS_ANY(), glue, iter, offset, keys); 677} 678 679void CircuitBuilder::SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object) 680{ 681 GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET); 682 Store(VariableType::JS_ANY(), glue, iter, offset, object); 683} 684 685void CircuitBuilder::SetCachedHclassOfForInIterator(GateRef glue, GateRef iter, GateRef hclass) 686{ 687 GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET); 688 Store(VariableType::JS_ANY(), glue, iter, offset, hclass); 689} 690 691void CircuitBuilder::SetNextIndexOfArrayIterator(GateRef glue, GateRef iter, GateRef nextIndex) 692{ 693 GateRef offset = IntPtr(JSArrayIterator::NEXT_INDEX_OFFSET); 694 Store(VariableType::INT32(), glue, iter, offset, nextIndex); 695} 696 697void CircuitBuilder::SetIteratedArrayOfArrayIterator(GateRef glue, GateRef iter, GateRef iteratedArray) 698{ 699 GateRef offset = IntPtr(JSArrayIterator::ITERATED_ARRAY_OFFSET); 700 Store(VariableType::JS_ANY(), glue, iter, offset, iteratedArray); 701} 702 703void CircuitBuilder::SetBitFieldOfArrayIterator(GateRef glue, GateRef iter, GateRef kind) 704{ 705 GateRef offset = IntPtr(JSArrayIterator::BIT_FIELD_OFFSET); 706 Store(VariableType::INT32(), glue, iter, offset, kind); 707} 708 709void CircuitBuilder::IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index) 710{ 711 GateRef newIndex = Int32Add(index, Int32(1)); 712 GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET); 713 Store(VariableType::INT32(), glue, iter, offset, newIndex); 714} 715 716GateRef CircuitBuilder::GetHasChanged(GateRef object) 717{ 718 GateRef bitfieldOffset = IntPtr(ProtoChangeMarker::BIT_FIELD_OFFSET); 719 GateRef bitfield = Load(VariableType::INT32(), object, bitfieldOffset); 720 GateRef mask = Int32(1LLU << (ProtoChangeMarker::HAS_CHANGED_BITS - 1)); 721 return Int32NotEqual(Int32And(bitfield, mask), Int32(0)); 722} 723 724GateRef CircuitBuilder::GetAccessorHasChanged(GateRef object) 725{ 726 GateRef bitfieldOffset = IntPtr(ProtoChangeMarker::BIT_FIELD_OFFSET); 727 GateRef bitfield = Load(VariableType::INT32(), object, bitfieldOffset); 728 return Int32NotEqual( 729 Int32And(Int32LSR(bitfield, Int32(ProtoChangeMarker::AccessorHasChangedBits::START_BIT)), 730 Int32((1LLU << ProtoChangeMarker::AccessorHasChangedBits::SIZE) - 1)), 731 Int32(0)); 732} 733 734GateRef CircuitBuilder::HasDeleteProperty(GateRef hClass) 735{ 736 GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET)); 737 return Int32NotEqual( 738 Int32And(Int32LSR(bitfield, Int32(JSHClass::HasDeletePropertyBit::START_BIT)), 739 Int32((1LLU << JSHClass::HasDeletePropertyBit::SIZE) - 1)), 740 Int32(0)); 741} 742 743GateRef CircuitBuilder::IsOnHeap(GateRef hClass) 744{ 745 GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD_OFFSET)); 746 return Int32NotEqual( 747 Int32And(Int32LSR(bitfield, Int32(JSHClass::IsOnHeap::START_BIT)), 748 Int32((1LU << JSHClass::IsOnHeap::SIZE) - 1)), 749 Int32(0)); 750} 751 752GateRef CircuitBuilder::IsEcmaObject(GateRef obj) 753{ 754 return LogicAndBuilder(env_).And(TaggedIsHeapObject(obj)).And(TaggedObjectIsEcmaObject(obj)).Done(); 755} 756 757GateRef CircuitBuilder::CheckJSType(GateRef object, JSType jsType) 758{ 759 Label entryPass(env_); 760 SubCfgEntry(&entryPass); 761 DEFVALUE(result, env_, VariableType::BOOL(), False()); 762 Label heapObj(env_); 763 Label exit(env_); 764 GateRef isHeapObject = TaggedIsHeapObject(object); 765 BRANCH_CIR2(isHeapObject, &heapObj, &exit); 766 Bind(&heapObj); 767 { 768 GateRef objectType = GetObjectType(LoadHClass(object)); 769 result = Int32Equal(objectType, Int32(static_cast<int32_t>(jsType))); 770 Jump(&exit); 771 } 772 Bind(&exit); 773 auto ret = *result; 774 SubCfgExit(); 775 return ret; 776} 777 778GateRef CircuitBuilder::GetObjectByIndexFromConstPool(GateRef glue, GateRef hirGate, GateRef frameState, GateRef index, 779 ConstPoolType type) 780{ 781 ArgumentAccessor argAcc(circuit_); 782 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC); 783 GateRef module = GetModuleFromFunction(jsFunc); 784 GateRef sharedConstpool = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::SHARED_CONST_POOL); 785 GateRef unsharedConstPool = unsharedConstPool = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::UNSHARED_CONST_POOL); 786 GateRef obj = GetObjectFromConstPool(glue, hirGate, sharedConstpool, unsharedConstPool, module, index, type); 787 return obj; 788} 789 790GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef sharedConstPool, 791 GateRef unsharedConstPool, GateRef module, GateRef index, 792 ConstPoolType type) 793{ 794 Label entry(env_); 795 SubCfgEntry(&entry); 796 Label exit(env_); 797 Label cacheMiss(env_); 798 Label cache(env_); 799 Label unshareCpHit(env_); 800 Label unshareCpMiss(env_); 801 802 // HirGate Can not be a nullGate in Aot 803 if (GetCircuit()->IsOptimizedOrFastJit() && hirGate == Circuit::NullGate()) { 804 hirGate = index; 805 } 806 // Call runtime to create unshared constpool when current context's cache is hole in multi-thread. 807 DEFVALUE(cacheValue, env_, VariableType::JS_ANY(), Hole()); 808 if (type == ConstPoolType::ARRAY_LITERAL || type == ConstPoolType::OBJECT_LITERAL) { 809 BRANCH_CIR2(TaggedIsNotHole(unsharedConstPool), &unshareCpHit, &unshareCpMiss); 810 Bind(&unshareCpHit); 811 { 812 cacheValue = GetValueFromTaggedArray(unsharedConstPool, index); 813 Jump(&unshareCpMiss); 814 } 815 } else { 816 cacheValue = GetValueFromTaggedArray(sharedConstPool, index); 817 Jump(&unshareCpMiss); 818 } 819 Bind(&unshareCpMiss); 820 DEFVALUE(result, env_, VariableType::JS_ANY(), *cacheValue); 821 BRANCH_CIR2(BitOr(TaggedIsHole(*result), TaggedIsNullPtr(*result)), &cacheMiss, &cache); 822 Bind(&cacheMiss); 823 { 824 if (type == ConstPoolType::STRING) { 825 result = CallRuntime(glue, RTSTUB_ID(GetStringFromCache), Gate::InvalidGateRef, 826 { sharedConstPool, Int32ToTaggedInt(index) }, hirGate); 827 } else if (type == ConstPoolType::ARRAY_LITERAL) { 828 result = CallRuntime(glue, RTSTUB_ID(GetArrayLiteralFromCache), Gate::InvalidGateRef, 829 { sharedConstPool, Int32ToTaggedInt(index), module }, hirGate); 830 } else if (type == ConstPoolType::OBJECT_LITERAL) { 831 result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef, 832 { sharedConstPool, Int32ToTaggedInt(index), module }, hirGate); 833 } else { 834 result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef, 835 { sharedConstPool, Int32ToTaggedInt(index) }, hirGate); 836 } 837 Jump(&exit); 838 } 839 Bind(&cache); 840 { 841 if (type == ConstPoolType::METHOD) { 842 Label isHeapObj(env_); 843 Label checkInteger(env_); 844 BRANCH_CIR2(TaggedIsHeapObject(*result), &isHeapObj, &checkInteger); 845 Bind(&isHeapObj); 846 { 847 Label isAOTLiteralInfo(env_); 848 BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit); 849 Bind(&isAOTLiteralInfo); 850 { 851 result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef, 852 { sharedConstPool, Int32ToTaggedInt(index) }, hirGate); 853 Jump(&exit); 854 } 855 } 856 Bind(&checkInteger); 857 { 858 Label isInteger(env_); 859 BRANCH_CIR2(TaggedIsInt(*result), &isInteger, &exit); 860 Bind(&isInteger); 861 { 862 result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef, 863 { sharedConstPool, Int32ToTaggedInt(index) }, hirGate); 864 Jump(&exit); 865 } 866 } 867 } else if (type == ConstPoolType::ARRAY_LITERAL) { 868 Label isHeapObj(env_); 869 BRANCH_CIR2(TaggedIsHeapObject(*result), &isHeapObj, &exit); 870 Bind(&isHeapObj); 871 { 872 Label isAOTLiteralInfo(env_); 873 BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit); 874 Bind(&isAOTLiteralInfo); 875 { 876 result = CallRuntime(glue, RTSTUB_ID(GetArrayLiteralFromCache), Gate::InvalidGateRef, 877 { sharedConstPool, Int32ToTaggedInt(index), module }, hirGate); 878 Jump(&exit); 879 } 880 } 881 } else if (type == ConstPoolType::OBJECT_LITERAL) { 882 Label isHeapObj(env_); 883 BRANCH_CIR2(TaggedIsHeapObject(*result), &isHeapObj, &exit); 884 Bind(&isHeapObj); 885 { 886 Label isAOTLiteralInfo(env_); 887 BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit); 888 Bind(&isAOTLiteralInfo); 889 { 890 result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef, 891 { sharedConstPool, Int32ToTaggedInt(index), module }, hirGate); 892 Jump(&exit); 893 } 894 } 895 } else { 896 Jump(&exit); 897 } 898 } 899 Bind(&exit); 900 auto ret = *result; 901 SubCfgExit(); 902 return ret; 903} 904 905GateRef CircuitBuilder::GetFunctionLexicalEnv(GateRef function) 906{ 907 return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::LEXICAL_ENV_OFFSET)); 908} 909 910void CircuitBuilder::SetLengthToFunction(GateRef glue, GateRef function, GateRef value) 911{ 912 GateRef offset = IntPtr(JSFunction::LENGTH_OFFSET); 913 Store(VariableType::INT32(), glue, function, offset, value); 914} 915 916void CircuitBuilder::SetLexicalEnvToFunction(GateRef glue, GateRef function, GateRef value) 917{ 918 GateRef offset = IntPtr(JSFunction::LEXICAL_ENV_OFFSET); 919 Store(VariableType::JS_ANY(), glue, function, offset, value); 920} 921 922void CircuitBuilder::SetHomeObjectToFunction(GateRef glue, GateRef function, GateRef value) 923{ 924 GateRef offset = IntPtr(JSFunction::HOME_OBJECT_OFFSET); 925 Store(VariableType::JS_ANY(), glue, function, offset, value); 926} 927 928void CircuitBuilder::SetModuleToFunction(GateRef glue, GateRef function, GateRef value) 929{ 930 GateRef offset = IntPtr(JSFunction::ECMA_MODULE_OFFSET); 931 Store(VariableType::JS_POINTER(), glue, function, offset, value); 932} 933 934GateRef CircuitBuilder::GetGlobalEnvValue(VariableType type, GateRef env, size_t index) 935{ 936 auto valueIndex = IntPtr(GlobalEnv::HEADER_SIZE + JSTaggedValue::TaggedTypeSize() * index); 937 return Load(type, env, valueIndex); 938} 939 940GateRef CircuitBuilder::GetCodeAddr(GateRef jsFunc) 941{ 942 auto codeAddOffset = IntPtr(JSFunction::CODE_ENTRY_OFFSET); 943 return Load(VariableType::NATIVE_POINTER(), jsFunc, codeAddOffset); 944} 945 946GateRef CircuitBuilder::GetBaselineCodeAddr(GateRef baselineCode) 947{ 948 auto codeAddrOffset = IntPtr(MachineCode::FUNCADDR_OFFSET); 949 return Load(VariableType::NATIVE_POINTER(), baselineCode, codeAddrOffset); 950} 951 952GateRef CircuitBuilder::GetHClassGateFromIndex(GateRef gate, int32_t index) 953{ 954 ArgumentAccessor argAcc(circuit_); 955 GateRef unsharedConstpool = argAcc.GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL); 956 return LoadHClassFromConstpool(unsharedConstpool, index); 957} 958 959GateRef Variable::AddPhiOperand(GateRef val) 960{ 961 ASSERT(GateAccessor(env_->GetCircuit()).IsValueSelector(val)); 962 Label label = env_->GetLabelFromSelector(val); 963 size_t idx = 0; 964 for (auto pred : label.GetPredecessors()) { 965 auto preVal = pred.ReadVariable(this); 966 ASSERT(!GateAccessor(env_->GetCircuit()).IsNop(preVal)); 967 idx++; 968 val = AddOperandToSelector(val, idx, preVal); 969 } 970 return TryRemoveTrivialPhi(val); 971} 972 973GateRef Variable::AddOperandToSelector(GateRef val, size_t idx, GateRef in) 974{ 975 GateAccessor(env_->GetCircuit()).NewIn(val, idx, in); 976 return val; 977} 978 979GateRef Variable::TryRemoveTrivialPhi(GateRef phi) 980{ 981 GateAccessor acc(GetCircuit()); 982 GateRef same = Gate::InvalidGateRef; 983 const size_t inNum = acc.GetNumIns(phi); 984 for (size_t i = 1; i < inNum; ++i) { 985 GateRef phiIn = acc.GetIn(phi, i); 986 if (phiIn == same || phiIn == phi) { 987 continue; // unique value or self-reference 988 } 989 if (same != Gate::InvalidGateRef) { 990 return phi; // the phi merges at least two valusses: not trivial 991 } 992 same = phiIn; 993 } 994 if (same == Gate::InvalidGateRef) { 995 // the phi is unreachable or in the start block 996 GateType type = acc.GetGateType(phi); 997 same = env_->GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, type); 998 } 999 // remove the trivial phi 1000 // get all users of phi except self 1001 std::vector<GateRef> outs; 1002 auto uses = acc.Uses(phi); 1003 for (auto use = uses.begin(); use != uses.end();) { 1004 GateRef u = *use; 1005 if (u != phi) { 1006 outs.push_back(u); 1007 use = acc.ReplaceIn(use, same); 1008 } else { 1009 use++; 1010 } 1011 } 1012 acc.DeleteGate(phi); 1013 1014 // try to recursiveby remove all phi users, which might have vecome trivial 1015 for (auto out : outs) { 1016 if (acc.IsValueSelector(out)) { 1017 auto result = TryRemoveTrivialPhi(out); 1018 if (same == out) { 1019 same = result; 1020 } 1021 } 1022 } 1023 return same; 1024} 1025 1026GateRef CircuitBuilder::ElementsKindIsIntOrHoleInt(GateRef kind) 1027{ 1028 GateRef kindIsInt = Int32Equal(kind, Int32(static_cast<uint32_t>(ElementsKind::INT))); 1029 GateRef kindIsHoleInt = Int32Equal(kind, Int32(static_cast<uint32_t>(ElementsKind::HOLE_INT))); 1030 return BitOr(kindIsInt, kindIsHoleInt); 1031} 1032 1033GateRef CircuitBuilder::ElementsKindIsNumOrHoleNum(GateRef kind) 1034{ 1035 GateRef kindIsNum = Int32Equal(kind, Int32(static_cast<uint32_t>(ElementsKind::NUMBER))); 1036 GateRef kindIsHoleNum = Int32Equal(kind, Int32(static_cast<uint32_t>(ElementsKind::HOLE_NUMBER))); 1037 return BitOr(kindIsNum, kindIsHoleNum); 1038} 1039 1040GateRef CircuitBuilder::ElementsKindIsHeapKind(GateRef kind) 1041{ 1042 GateRef overString = Int32GreaterThanOrEqual(kind, Int32(static_cast<uint32_t>(ElementsKind::STRING))); 1043 GateRef isHoleOrNone = Int32LessThanOrEqual(kind, Int32(static_cast<uint32_t>(ElementsKind::HOLE))); 1044 return BitOr(overString, isHoleOrNone); 1045} 1046 1047GateRef CircuitBuilder::ElementsKindHasHole(GateRef kind) 1048{ 1049 return Int32NotEqual(Int32And(kind, Int32(static_cast<uint32_t>(ElementsKind::HOLE))), Int32(0)); 1050} 1051 1052GateRef CircuitBuilder::LoadBuiltinObject(size_t offset) 1053{ 1054 auto currentLabel = env_->GetCurrentLabel(); 1055 auto currentControl = currentLabel->GetControl(); 1056 auto currentDepend = currentLabel->GetDepend(); 1057 auto frameState = acc_.FindNearestFrameState(currentDepend); 1058 GateRef ret = GetCircuit()->NewGate(circuit_->LoadBuiltinObject(offset), 1059 MachineType::I64, 1060 {currentControl, currentDepend, frameState}, 1061 GateType::AnyType()); 1062 currentLabel->SetControl(ret); 1063 currentLabel->SetDepend(ret); 1064 return ret; 1065} 1066 1067GateRef CircuitBuilder::GetKeyFromLexivalEnv(GateRef lexicalEnv, GateRef levelIndex, GateRef slotIndex) 1068{ 1069 Label entry(env_); 1070 SubCfgEntry(&entry); 1071 Label exit(env_); 1072 Label loopHead(env_); 1073 Label loopEnd(env_); 1074 Label afterLoop(env_); 1075 1076 DEFVALUE(result, env_, VariableType::JS_ANY(), Hole()); 1077 DEFVALUE(currentEnv, env_, VariableType::JS_ANY(), lexicalEnv); 1078 DEFVALUE(i, env_, VariableType::INT32(), Int32(0)); 1079 1080 Branch(Int32LessThan(*i, levelIndex), &loopHead, &afterLoop); 1081 LoopBegin(&loopHead); 1082 { 1083 currentEnv = GetParentEnv(*currentEnv); 1084 i = Int32Add(*i, Int32(1)); 1085 Branch(Int32LessThan(*i, levelIndex), &loopEnd, &afterLoop); 1086 Bind(&loopEnd); 1087 LoopEnd(&loopHead); 1088 } 1089 Bind(&afterLoop); 1090 { 1091 result = GetPropertiesFromLexicalEnv(*currentEnv, slotIndex); 1092 Jump(&exit); 1093 } 1094 Bind(&exit); 1095 auto ret = *result; 1096 SubCfgExit(); 1097 return ret; 1098} 1099 1100GateRef CircuitBuilder::GetParentEnv(GateRef object) 1101{ 1102 GateRef index = Int32(LexicalEnv::PARENT_ENV_INDEX); 1103 return GetValueFromTaggedArray(object, index); 1104} 1105 1106GateRef CircuitBuilder::GetSendableParentEnv(GateRef object) 1107{ 1108 GateRef index = Int32(SendableEnv::SENDABLE_PARENT_ENV_INDEX); 1109 return GetValueFromTaggedArray(object, index); 1110} 1111 1112GateRef CircuitBuilder::GetPropertiesFromLexicalEnv(GateRef object, GateRef index) 1113{ 1114 GateRef valueIndex = Int32Add(index, Int32(LexicalEnv::RESERVED_ENV_LENGTH)); 1115 return GetValueFromTaggedArray(object, valueIndex); 1116} 1117 1118GateRef CircuitBuilder::NewJSPrimitiveRef(GateRef glue, size_t index, GateRef obj) 1119{ 1120 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env_->Is32Bit())); 1121 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); 1122 GateRef func = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, index); 1123 GateRef protoOrHclass = Load(VariableType::JS_ANY(), func, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); 1124 NewObjectStubBuilder newBuilder(env_); 1125 GateRef newObj = newBuilder.NewJSObject(glue, protoOrHclass); 1126 GateRef valueOffset = IntPtr(JSPrimitiveRef::VALUE_OFFSET); 1127 Store(VariableType::JS_ANY(), glue, newObj, valueOffset, obj); 1128 return newObj; 1129} 1130 1131GateRef CircuitBuilder::ToObject(GateRef glue, GateRef obj) 1132{ 1133 Label entry(env_); 1134 env_->SubCfgEntry(&entry); 1135 Label exit(env_); 1136 DEFVALUE(result, env_, VariableType::JS_ANY(), obj); 1137 DEFVALUE(taggedId, env_, VariableType::INT32(), Int32(0)); 1138 Label isNumber(env_); 1139 Label notNumber(env_); 1140 Label isBoolean(env_); 1141 Label notBoolean(env_); 1142 Label isString(env_); 1143 Label notString(env_); 1144 Label isECMAObject(env_); 1145 Label notIsECMAObject(env_); 1146 Label isSymbol(env_); 1147 Label notSymbol(env_); 1148 Label isUndefined(env_); 1149 Label notIsUndefined(env_); 1150 Label isNull(env_); 1151 Label notIsNull(env_); 1152 Label isHole(env_); 1153 Label notIsHole(env_); 1154 Label isBigInt(env_); 1155 Label notIsBigInt(env_); 1156 Label throwError(env_); 1157 BRANCH_CIR2(IsEcmaObject(obj), &isECMAObject, ¬IsECMAObject); 1158 Bind(&isECMAObject); 1159 { 1160 result = obj; 1161 Jump(&exit); 1162 } 1163 Bind(¬IsECMAObject); 1164 BRANCH_CIR2(TaggedIsNumber(obj), &isNumber, ¬Number); 1165 Bind(&isNumber); 1166 { 1167 result = NewJSPrimitiveRef(glue, GlobalEnv::NUMBER_FUNCTION_INDEX, obj); 1168 Jump(&exit); 1169 } 1170 Bind(¬Number); 1171 BRANCH_CIR2(TaggedIsBoolean(obj), &isBoolean, ¬Boolean); 1172 Bind(&isBoolean); 1173 { 1174 result = NewJSPrimitiveRef(glue, GlobalEnv::BOOLEAN_FUNCTION_INDEX, obj); 1175 Jump(&exit); 1176 } 1177 Bind(¬Boolean); 1178 BRANCH_CIR2(TaggedIsString(obj), &isString, ¬String); 1179 Bind(&isString); 1180 { 1181 result = NewJSPrimitiveRef(glue, GlobalEnv::STRING_FUNCTION_INDEX, obj); 1182 Jump(&exit); 1183 } 1184 Bind(¬String); 1185 BRANCH_CIR2(TaggedIsSymbol(obj), &isSymbol, ¬Symbol); 1186 Bind(&isSymbol); 1187 { 1188 result = NewJSPrimitiveRef(glue, GlobalEnv::SYMBOL_FUNCTION_INDEX, obj); 1189 Jump(&exit); 1190 } 1191 Bind(¬Symbol); 1192 BRANCH_CIR2(TaggedIsUndefined(obj), &isUndefined, ¬IsUndefined); 1193 Bind(&isUndefined); 1194 { 1195 taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotUndefinedObject)); 1196 Jump(&throwError); 1197 } 1198 Bind(¬IsUndefined); 1199 BRANCH_CIR2(TaggedIsHole(obj), &isHole, ¬IsHole); 1200 Bind(&isHole); 1201 { 1202 taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotHoleObject)); 1203 Jump(&throwError); 1204 } 1205 Bind(¬IsHole); 1206 BRANCH_CIR2(TaggedIsNull(obj), &isNull, ¬IsNull); 1207 Bind(&isNull); 1208 { 1209 taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotNullObject)); 1210 Jump(&throwError); 1211 } 1212 Bind(¬IsNull); 1213 BRANCH_CIR2(TaggedIsBigInt(obj), &isBigInt, ¬IsBigInt); 1214 Bind(&isBigInt); 1215 { 1216 result = NewJSPrimitiveRef(glue, GlobalEnv::BIGINT_FUNCTION_INDEX, obj); 1217 Jump(&exit); 1218 } 1219 Bind(¬IsBigInt); 1220 { 1221 taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotNullObject)); 1222 Jump(&throwError); 1223 } 1224 Bind(&throwError); 1225 { 1226 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), Gate::InvalidGateRef, { Int32ToTaggedInt(*taggedId) }, glue); 1227 result = ExceptionConstant(); 1228 Jump(&exit); 1229 } 1230 Bind(&exit); 1231 auto ret = *result; 1232 env_->SubCfgExit(); 1233 return ret; 1234} 1235 1236GateRef CircuitBuilder::GetPrototype(GateRef glue, GateRef object) 1237{ 1238 Label entry(env_); 1239 env_->SubCfgEntry(&entry); 1240 DEFVALUE(result, env_, VariableType::JS_ANY(), Hole()); 1241 Label exit(env_); 1242 Label objectIsHeapObject(env_); 1243 Label objectIsEcmaObject(env_); 1244 Label objectNotEcmaObject(env_); 1245 1246 BRANCH_CIR2(TaggedIsHeapObject(object), &objectIsHeapObject, &objectNotEcmaObject); 1247 Bind(&objectIsHeapObject); 1248 BRANCH_CIR2(TaggedObjectIsEcmaObject(object), &objectIsEcmaObject, &objectNotEcmaObject); 1249 Bind(&objectNotEcmaObject); 1250 { 1251 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotGetNotEcmaObject)); 1252 CallRuntime(glue, RTSTUB_ID(ThrowTypeError), Gate::InvalidGateRef, { Int32ToTaggedInt(taggedId) }, glue); 1253 result = ExceptionConstant(); 1254 Jump(&exit); 1255 } 1256 Bind(&objectIsEcmaObject); 1257 { 1258 Label objectIsJsProxy(env_); 1259 Label objectNotIsJsProxy(env_); 1260 BRANCH_CIR2(IsJsProxy(object), &objectIsJsProxy, &objectNotIsJsProxy); 1261 Bind(&objectIsJsProxy); 1262 { 1263 result = CallRuntime(glue, RTSTUB_ID(CallGetPrototype), Gate::InvalidGateRef, { object }, glue); 1264 Jump(&exit); 1265 } 1266 Bind(&objectNotIsJsProxy); 1267 { 1268 result = GetPrototypeFromHClass(LoadHClass(object)); 1269 Jump(&exit); 1270 } 1271 } 1272 Bind(&exit); 1273 auto ret = *result; 1274 env_->SubCfgExit(); 1275 return ret; 1276} 1277 1278GateRef CircuitBuilder::GetGlobalConstantValue(VariableType type, GateRef glue, ConstantIndex index) 1279{ 1280 GateRef gConstAddr = Load(VariableType::JS_ANY(), glue, 1281 IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit()))); 1282 auto constantIndex = IntPtr(JSTaggedValue::TaggedTypeSize() * static_cast<size_t>(index)); 1283 return Load(type, gConstAddr, constantIndex); 1284} 1285 1286GateRef CircuitBuilder::TransProtoWithoutLayout(GateRef glue, GateRef hClass, GateRef proto) 1287{ 1288 Label entry(env_); 1289 env_->SubCfgEntry(&entry); 1290 Label exit(env_); 1291 DEFVALUE(result, env_, VariableType::JS_ANY(), Undefined()); 1292 1293 GateRef key = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, 1294 ConstantIndex::PROTOTYPE_STRING_INDEX); 1295 GateRef newClass = CallNGCRuntime(glue, RTSTUB_ID(JSHClassFindProtoTransitions), Gate::InvalidGateRef, 1296 { hClass, key, proto }, glue); 1297 Label undef(env_); 1298 Label find(env_); 1299 BRANCH_CIR2(IntPtrEqual(TaggedCastToIntPtr(newClass), IntPtr(0)), &undef, &find); 1300 Bind(&find); 1301 { 1302 result = newClass; 1303 Jump(&exit); 1304 } 1305 Bind(&undef); 1306 { 1307 result = CallRuntime(glue, RTSTUB_ID(HClassCloneWithAddProto), Gate::InvalidGateRef, 1308 { hClass, key, proto }, glue); 1309 Jump(&exit); 1310 } 1311 Bind(&exit); 1312 auto ret = *result; 1313 env_->SubCfgExit(); 1314 return ret; 1315} 1316 1317 1318GateRef CircuitBuilder::OrdinaryNewJSObjectCreate(GateRef glue, GateRef proto) 1319{ 1320 Label entry(env_); 1321 env_->SubCfgEntry(&entry); 1322 Label exit(env_); 1323 DEFVALUE(result, env_, VariableType::JS_ANY(), Undefined()); 1324 1325 GateRef hClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, 1326 ConstantIndex::OBJECT_HCLASS_INDEX); 1327 GateRef newClass = TransProtoWithoutLayout(glue, hClass, proto); 1328 Label exception(env_); 1329 Label noexception(env_); 1330 BRANCH_CIR2(TaggedIsException(newClass), &exception, &noexception); 1331 Bind(&exception); 1332 { 1333 result = ExceptionConstant(); 1334 Jump(&exit); 1335 } 1336 Bind(&noexception); 1337 NewObjectStubBuilder newBuilder(env_); 1338 GateRef newObj = newBuilder.NewJSObject(glue, newClass); 1339 Label exceptionNewObj(env_); 1340 Label noexceptionNewObj(env_); 1341 BRANCH_CIR2(TaggedIsException(newObj), &exceptionNewObj, &noexceptionNewObj); 1342 Bind(&exceptionNewObj); 1343 { 1344 result = ExceptionConstant(); 1345 Jump(&exit); 1346 } 1347 Bind(&noexceptionNewObj); 1348 { 1349 SetExtensibleToBitfield(glue, newObj, True()); 1350 result = newObj; 1351 Jump(&exit); 1352 } 1353 Bind(&exit); 1354 auto ret = *result; 1355 env_->SubCfgExit(); 1356 return ret; 1357} 1358 1359GateRef CircuitBuilder::GetPropertiesFromSendableEnv(GateRef object, GateRef index) 1360{ 1361 GateRef valueIndex = Int32Add(index, Int32(SendableEnv::SENDABLE_RESERVED_ENV_LENGTH)); 1362 return GetValueFromTaggedArray(object, valueIndex); 1363} 1364 1365GateRef CircuitBuilder::GetProfileTypeInfo(GateRef function) 1366{ 1367 GateRef raw = Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET)); 1368 return Load(VariableType::JS_POINTER(), raw, IntPtr(ProfileTypeInfoCell::VALUE_OFFSET)); 1369} 1370 1371void CircuitBuilder::SetRawProfileTypeInfoToFunction(GateRef glue, GateRef function, GateRef value) 1372{ 1373 GateRef offset = IntPtr(JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET); 1374 Store(VariableType::JS_ANY(), glue, function, offset, value); 1375} 1376 1377void CircuitBuilder::UpdateProfileTypeInfoCellToFunction(GateRef glue, GateRef function, 1378 GateRef profileTypeInfo, GateRef slotId) 1379{ 1380 Label subEntry(env_); 1381 env_->SubCfgEntry(&subEntry); 1382 1383 Label profileTypeInfoNotUndefined(env_); 1384 Label slotValueUpdate(env_); 1385 Label slotValueNotUndefined(env_); 1386 Label profileTypeInfoEnd(env_); 1387 NewObjectStubBuilder newBuilder(env_); 1388 BRANCH_CIR2(TaggedIsUndefined(profileTypeInfo), &profileTypeInfoEnd, &profileTypeInfoNotUndefined); 1389 Bind(&profileTypeInfoNotUndefined); 1390 { 1391 GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId); 1392 BRANCH_CIR2(TaggedIsUndefined(slotValue), &slotValueUpdate, &slotValueNotUndefined); 1393 Bind(&slotValueUpdate); 1394 { 1395 GateRef newProfileTypeInfoCell = newBuilder.NewProfileTypeInfoCell(glue, Undefined()); 1396 SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, newProfileTypeInfoCell); 1397 SetRawProfileTypeInfoToFunction(glue, function, newProfileTypeInfoCell); 1398 Jump(&profileTypeInfoEnd); 1399 } 1400 Bind(&slotValueNotUndefined); 1401 UpdateProfileTypeInfoCellType(glue, slotValue); 1402 SetRawProfileTypeInfoToFunction(glue, function, slotValue); 1403 Jump(&profileTypeInfoEnd); 1404 } 1405 Bind(&profileTypeInfoEnd); 1406 1407 env_->SubCfgExit(); 1408} 1409 1410void CircuitBuilder::UpdateProfileTypeInfoCellType(GateRef glue, GateRef profileTypeInfoCell) 1411{ 1412 Label subEntry(env_); 1413 env_->SubCfgEntry(&subEntry); 1414 1415 // ProfileTypeInfoCell0 -> Cell1 -> CellN 1416 Label isProfileTypeInfoCell0(env_); 1417 Label notProfileTypeInfoCell0(env_); 1418 Label isProfileTypeInfoCell1(env_); 1419 Label endProfileTypeInfoCellType(env_); 1420 GateRef objectType = GetObjectType(LoadHClass(profileTypeInfoCell)); 1421 BRANCH_CIR2(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::PROFILE_TYPE_INFO_CELL_0))), 1422 &isProfileTypeInfoCell0, ¬ProfileTypeInfoCell0); 1423 Bind(&isProfileTypeInfoCell0); 1424 { 1425 auto profileTypeInfoCell1Class = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, 1426 ConstantIndex::PROFILE_TYPE_INFO_CELL_1_CLASS_INDEX); 1427 StoreHClassWithoutBarrier(glue, profileTypeInfoCell, profileTypeInfoCell1Class); 1428 Jump(&endProfileTypeInfoCellType); 1429 } 1430 Bind(¬ProfileTypeInfoCell0); 1431 BRANCH_CIR2(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::PROFILE_TYPE_INFO_CELL_1))), 1432 &isProfileTypeInfoCell1, &endProfileTypeInfoCellType); 1433 Bind(&isProfileTypeInfoCell1); 1434 { 1435 auto profileTypeInfoCellNClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, 1436 ConstantIndex::PROFILE_TYPE_INFO_CELL_N_CLASS_INDEX); 1437 StoreHClassWithoutBarrier(glue, profileTypeInfoCell, profileTypeInfoCellNClass); 1438 Jump(&endProfileTypeInfoCellType); 1439 } 1440 Bind(&endProfileTypeInfoCellType); 1441 env_->SubCfgExit(); 1442} 1443 1444GateRef CircuitBuilder::FastToBoolean(GateRef value) 1445{ 1446 Label entry(env_); 1447 env_->SubCfgEntry(&entry); 1448 DEFVALUE(result, env_, VariableType::JS_ANY(), HoleConstant()); 1449 Label exit(env_); 1450 1451 Label isSpecial(env_); 1452 Label notSpecial(env_); 1453 Label isNumber(env_); 1454 Label isInt(env_); 1455 Label isDouble(env_); 1456 Label notNumber(env_); 1457 Label notNan(env_); 1458 Label isString(env_); 1459 Label notString(env_); 1460 Label isBigint(env_); 1461 Label lengthIsOne(env_); 1462 Label returnTrue(env_); 1463 Label returnFalse(env_); 1464 1465 BRANCH_CIR2(TaggedIsSpecial(value), &isSpecial, ¬Special); 1466 Bind(&isSpecial); 1467 { 1468 BRANCH_CIR2(TaggedIsTrue(value), &returnTrue, &returnFalse); 1469 } 1470 Bind(¬Special); 1471 { 1472 BRANCH_CIR2(TaggedIsNumber(value), &isNumber, ¬Number); 1473 Bind(¬Number); 1474 { 1475 BRANCH_CIR2(TaggedIsString(value), &isString, ¬String); 1476 Bind(&isString); 1477 { 1478 auto len = GetLengthFromString(value); 1479 BRANCH_CIR2(Int32Equal(len, Int32(0)), &returnFalse, &returnTrue); 1480 } 1481 Bind(¬String); 1482 BRANCH_CIR2(TaggedIsBigInt(value), &isBigint, &returnTrue); 1483 Bind(&isBigint); 1484 { 1485 auto len = Load(VariableType::INT32(), value, IntPtr(BigInt::LENGTH_OFFSET)); 1486 BRANCH_CIR2(Int32Equal(len, Int32(1)), &lengthIsOne, &returnTrue); 1487 Bind(&lengthIsOne); 1488 { 1489 auto data = PtrAdd(value, IntPtr(BigInt::DATA_OFFSET)); 1490 auto data0 = Load(VariableType::INT32(), data, Int32(0)); 1491 BRANCH_CIR2(Int32Equal(data0, Int32(0)), &returnFalse, &returnTrue); 1492 } 1493 } 1494 } 1495 Bind(&isNumber); 1496 { 1497 BRANCH_CIR2(TaggedIsInt(value), &isInt, &isDouble); 1498 Bind(&isInt); 1499 { 1500 auto intValue = GetInt32OfTInt(value); 1501 BRANCH_CIR2(Int32Equal(intValue, Int32(0)), &returnFalse, &returnTrue); 1502 } 1503 Bind(&isDouble); 1504 { 1505 auto doubleValue = GetDoubleOfTDouble(value); 1506 BRANCH_CIR2(DoubleIsNAN(doubleValue), &returnFalse, ¬Nan); 1507 Bind(¬Nan); 1508 BRANCH_CIR2(DoubleEqual(doubleValue, Double(0.0)), &returnFalse, &returnTrue); 1509 } 1510 } 1511 } 1512 Bind(&returnTrue); 1513 { 1514 result = TaggedTrue(); 1515 Jump(&exit); 1516 } 1517 Bind(&returnFalse); 1518 { 1519 result = TaggedFalse(); 1520 Jump(&exit); 1521 } 1522 Bind(&exit); 1523 auto ret = *result; 1524 env_->SubCfgExit(); 1525 return ret; 1526} 1527 1528GateRef CircuitBuilder::IsStableArrayLengthWriteable(GateRef array) 1529{ 1530 Label entry(env_); 1531 env_->SubCfgEntry(&entry); 1532 DEFVALUE(result, env_, VariableType::BOOL(), False()); 1533 GateRef hClass = LoadHClassByConstOffset(array); 1534 GateRef attrOffset = IntPtr(JSHClass::LAYOUT_OFFSET); 1535 GateRef layout = Load(VariableType::JS_POINTER(), hClass, attrOffset); 1536 GateRef entryHandler = Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX); 1537 GateRef index = 1538 Int32Add(Int32LSL(entryHandler, Int32(LayoutInfo::ELEMENTS_INDEX_LOG2)), Int32(LayoutInfo::ATTR_INDEX_OFFSET)); 1539 GateRef attr = GetInt64OfTInt(GetValueFromTaggedArray(layout, index)); 1540 GateRef writeableField = 1541 Int32And(TruncInt64ToInt32(Int64LSR(attr, Int64(PropertyAttributes::WritableField::START_BIT))), 1542 Int32((1LLU << PropertyAttributes::WritableField::SIZE) - 1)); 1543 result = Int32NotEqual(writeableField, Int32(0)); 1544 auto ret = *result; 1545 env_->SubCfgExit(); 1546 return ret; 1547} 1548} // namespace panda::ecmascript::kungfu 1549