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