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, &notIsECMAObject);
1158    Bind(&isECMAObject);
1159    {
1160        result = obj;
1161        Jump(&exit);
1162    }
1163    Bind(&notIsECMAObject);
1164    BRANCH_CIR2(TaggedIsNumber(obj), &isNumber, &notNumber);
1165    Bind(&isNumber);
1166    {
1167        result = NewJSPrimitiveRef(glue, GlobalEnv::NUMBER_FUNCTION_INDEX, obj);
1168        Jump(&exit);
1169    }
1170    Bind(&notNumber);
1171    BRANCH_CIR2(TaggedIsBoolean(obj), &isBoolean, &notBoolean);
1172    Bind(&isBoolean);
1173    {
1174        result = NewJSPrimitiveRef(glue, GlobalEnv::BOOLEAN_FUNCTION_INDEX, obj);
1175        Jump(&exit);
1176    }
1177    Bind(&notBoolean);
1178    BRANCH_CIR2(TaggedIsString(obj), &isString, &notString);
1179    Bind(&isString);
1180    {
1181        result = NewJSPrimitiveRef(glue, GlobalEnv::STRING_FUNCTION_INDEX, obj);
1182        Jump(&exit);
1183    }
1184    Bind(&notString);
1185    BRANCH_CIR2(TaggedIsSymbol(obj), &isSymbol, &notSymbol);
1186    Bind(&isSymbol);
1187    {
1188        result = NewJSPrimitiveRef(glue, GlobalEnv::SYMBOL_FUNCTION_INDEX, obj);
1189        Jump(&exit);
1190    }
1191    Bind(&notSymbol);
1192    BRANCH_CIR2(TaggedIsUndefined(obj), &isUndefined, &notIsUndefined);
1193    Bind(&isUndefined);
1194    {
1195        taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotUndefinedObject));
1196        Jump(&throwError);
1197    }
1198    Bind(&notIsUndefined);
1199    BRANCH_CIR2(TaggedIsHole(obj), &isHole, &notIsHole);
1200    Bind(&isHole);
1201    {
1202        taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotHoleObject));
1203        Jump(&throwError);
1204    }
1205    Bind(&notIsHole);
1206    BRANCH_CIR2(TaggedIsNull(obj), &isNull, &notIsNull);
1207    Bind(&isNull);
1208    {
1209        taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotNullObject));
1210        Jump(&throwError);
1211    }
1212    Bind(&notIsNull);
1213    BRANCH_CIR2(TaggedIsBigInt(obj), &isBigInt, &notIsBigInt);
1214    Bind(&isBigInt);
1215    {
1216        result = NewJSPrimitiveRef(glue, GlobalEnv::BIGINT_FUNCTION_INDEX, obj);
1217        Jump(&exit);
1218    }
1219    Bind(&notIsBigInt);
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, &notProfileTypeInfoCell0);
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(&notProfileTypeInfoCell0);
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, &notSpecial);
1466    Bind(&isSpecial);
1467    {
1468        BRANCH_CIR2(TaggedIsTrue(value), &returnTrue, &returnFalse);
1469    }
1470    Bind(&notSpecial);
1471    {
1472        BRANCH_CIR2(TaggedIsNumber(value), &isNumber, &notNumber);
1473        Bind(&notNumber);
1474        {
1475            BRANCH_CIR2(TaggedIsString(value), &isString, &notString);
1476            Bind(&isString);
1477            {
1478                auto len = GetLengthFromString(value);
1479                BRANCH_CIR2(Int32Equal(len, Int32(0)), &returnFalse, &returnTrue);
1480            }
1481            Bind(&notString);
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, &notNan);
1507                Bind(&notNan);
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