• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/common_stubs.h"
21 #include "ecmascript/compiler/hcr_circuit_builder.h"
22 #include "ecmascript/compiler/lcr_circuit_builder.h"
23 #include "ecmascript/compiler/mcr_circuit_builder.h"
24 #include "ecmascript/compiler/rt_call_signature.h"
25 #include "ecmascript/deoptimizer/deoptimizer.h"
26 #include "ecmascript/global_env.h"
27 #include "ecmascript/ic/proto_change_details.h"
28 #include "ecmascript/js_for_in_iterator.h"
29 #include "ecmascript/js_function.h"
30 #include "ecmascript/js_thread.h"
31 #include "ecmascript/jspandafile/program_object.h"
32 #include "ecmascript/mem/region.h"
33 #include "ecmascript/method.h"
34 #include "ecmascript/js_array_iterator.h"
35 
36 namespace panda::ecmascript::kungfu {
37 
Merge(const std::vector<GateRef> & inList)38 GateRef CircuitBuilder::Merge(const std::vector<GateRef> &inList)
39 {
40     return circuit_->NewGate(circuit_->Merge(inList.size()), inList);
41 }
42 
Selector(OpCode opcode,MachineType machineType,GateRef control,const std::vector<GateRef> & values,int valueCounts,VariableType type)43 GateRef CircuitBuilder::Selector(OpCode opcode, MachineType machineType, GateRef control,
44     const std::vector<GateRef> &values, int valueCounts, VariableType type)
45 {
46     std::vector<GateRef> inList;
47     inList.push_back(control);
48     if (values.size() == 0) {
49         for (int i = 0; i < valueCounts; i++) {
50             inList.push_back(Circuit::NullGate());
51         }
52     } else {
53         for (int i = 0; i < valueCounts; i++) {
54             inList.push_back(values[i]);
55         }
56     }
57     ASSERT((opcode == OpCode::VALUE_SELECTOR) || (opcode == OpCode::DEPEND_SELECTOR));
58     const GateMetaData* meta = (opcode == OpCode::DEPEND_SELECTOR) ?
59         circuit_->DependSelector(valueCounts) : circuit_->ValueSelector(valueCounts);
60     return circuit_->NewGate(meta, machineType, inList.size(), inList.data(), type.GetGateType());
61 }
62 
Selector(OpCode opcode,GateRef control,const std::vector<GateRef> & values,int valueCounts,VariableType type)63 GateRef CircuitBuilder::Selector(OpCode opcode, GateRef control,
64     const std::vector<GateRef> &values, int valueCounts, VariableType type)
65 {
66     MachineType machineType = (opcode == OpCode::DEPEND_SELECTOR) ?
67         MachineType::NOVALUE : MachineType::FLEX;
68     return Selector(opcode, machineType, control, values, valueCounts, type);
69 }
70 
UndefineConstant()71 GateRef CircuitBuilder::UndefineConstant()
72 {
73     auto type = GateType::TaggedValue();
74     return circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, type);
75 }
76 
Branch(GateRef state,GateRef condition,uint32_t trueWeight,uint32_t falseWeight,const char * comment)77 GateRef CircuitBuilder::Branch(GateRef state, GateRef condition, uint32_t trueWeight, uint32_t falseWeight,
78                                const char* comment)
79 {
80     auto value = BranchAccessor::ToValue(trueWeight, falseWeight);
81     return circuit_->NewGate(circuit_->IfBranch(value), { state, condition }, comment);
82 }
83 
SwitchBranch(GateRef state,GateRef index,int caseCounts)84 GateRef CircuitBuilder::SwitchBranch(GateRef state, GateRef index, int caseCounts)
85 {
86     return circuit_->NewGate(circuit_->SwitchBranch(caseCounts), { state, index });
87 }
88 
Return(GateRef state,GateRef depend,GateRef value)89 GateRef CircuitBuilder::Return(GateRef state, GateRef depend, GateRef value)
90 {
91     auto returnList = circuit_->GetReturnRoot();
92     return circuit_->NewGate(circuit_->Return(), { state, depend, value, returnList });
93 }
94 
ReturnVoid(GateRef state,GateRef depend)95 GateRef CircuitBuilder::ReturnVoid(GateRef state, GateRef depend)
96 {
97     auto returnList = circuit_->GetReturnRoot();
98     return circuit_->NewGate(circuit_->ReturnVoid(), { state, depend, returnList });
99 }
100 
Goto(GateRef state)101 GateRef CircuitBuilder::Goto(GateRef state)
102 {
103     return circuit_->NewGate(circuit_->OrdinaryBlock(), { state });
104 }
105 
LoopBegin(GateRef state)106 GateRef CircuitBuilder::LoopBegin(GateRef state)
107 {
108     auto nullGate = Circuit::NullGate();
109     return circuit_->NewGate(circuit_->LoopBegin(2), { state, nullGate }); // 2: entry&back
110 }
111 
LoopEnd(GateRef state)112 GateRef CircuitBuilder::LoopEnd(GateRef state)
113 {
114     return circuit_->NewGate(circuit_->LoopBack(), { state });
115 }
116 
LoopExit(GateRef state)117 GateRef CircuitBuilder::LoopExit(GateRef state)
118 {
119     return circuit_->NewGate(circuit_->LoopExit(), { state });
120 }
121 
LoopExitDepend(GateRef state,GateRef depend)122 GateRef CircuitBuilder::LoopExitDepend(GateRef state, GateRef depend)
123 {
124     return circuit_->NewGate(circuit_->LoopExitDepend(), { state, depend });
125 }
126 
LoopExitValue(GateRef state,GateRef value)127 GateRef CircuitBuilder::LoopExitValue(GateRef state, GateRef value)
128 {
129     auto machineType = acc_.GetMachineType(value);
130     auto gateType = acc_.GetGateType(value);
131     return circuit_->NewGate(circuit_->LoopExitValue(), machineType, { state, value }, gateType);
132 }
133 
IfTrue(GateRef ifBranch)134 GateRef CircuitBuilder::IfTrue(GateRef ifBranch)
135 {
136     return circuit_->NewGate(circuit_->IfTrue(), { ifBranch });
137 }
138 
IfFalse(GateRef ifBranch)139 GateRef CircuitBuilder::IfFalse(GateRef ifBranch)
140 {
141     return circuit_->NewGate(circuit_->IfFalse(), { ifBranch });
142 }
143 
SwitchCase(GateRef switchBranch,int64_t value)144 GateRef CircuitBuilder::SwitchCase(GateRef switchBranch, int64_t value)
145 {
146     return circuit_->NewGate(circuit_->SwitchCase(value), { switchBranch });
147 }
148 
DefaultCase(GateRef switchBranch)149 GateRef CircuitBuilder::DefaultCase(GateRef switchBranch)
150 {
151     return circuit_->NewGate(circuit_->DefaultCase(), { switchBranch });
152 }
153 
DependRelay(GateRef state,GateRef depend)154 GateRef CircuitBuilder::DependRelay(GateRef state, GateRef depend)
155 {
156     return circuit_->NewGate(circuit_->DependRelay(), { state, depend });
157 }
158 
Arguments(size_t index)159 GateRef CircuitBuilder::Arguments(size_t index)
160 {
161     auto argListOfCircuit = circuit_->GetArgRoot();
162     return GetCircuit()->NewArg(MachineType::I64, index, GateType::NJSValue(), argListOfCircuit);
163 }
164 
IsJsCOWArray(GateRef obj)165 GateRef CircuitBuilder::IsJsCOWArray(GateRef obj)
166 {
167     // Elements of JSArray are shared and properties are not yet.
168     GateRef elements = GetElementsArray(obj);
169     GateRef objectType = GetObjectType(LoadHClass(elements));
170     return IsCOWArray(objectType);
171 }
172 
IsCOWArray(GateRef objectType)173 GateRef CircuitBuilder::IsCOWArray(GateRef objectType)
174 {
175     return BoolOr(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::COW_TAGGED_ARRAY))),
176                   Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::COW_MUTANT_TAGGED_ARRAY))));
177 }
178 
IsTaggedArray(GateRef object)179 GateRef CircuitBuilder::IsTaggedArray(GateRef object)
180 {
181     GateRef objectType = GetObjectType(LoadHClass(object));
182     return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::TAGGED_ARRAY)));
183 }
184 
IsMutantTaggedArray(GateRef objectType)185 GateRef CircuitBuilder::IsMutantTaggedArray(GateRef objectType)
186 {
187     return BoolOr(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::MUTANT_TAGGED_ARRAY))),
188                   Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::COW_MUTANT_TAGGED_ARRAY))));
189 }
190 
GetElementsArray(GateRef object)191 GateRef CircuitBuilder::GetElementsArray(GateRef object)
192 {
193     GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET);
194     return Load(VariableType::JS_POINTER(), object, elementsOffset);
195 }
196 
GetLengthOfTaggedArray(GateRef array)197 GateRef CircuitBuilder::GetLengthOfTaggedArray(GateRef array)
198 {
199     return Load(VariableType::INT32(), array, IntPtr(TaggedArray::LENGTH_OFFSET));
200 }
201 
Jump(Label * label)202 void CircuitBuilder::Jump(Label *label)
203 {
204     ASSERT(label);
205     auto currentLabel = env_->GetCurrentLabel();
206     auto currentControl = currentLabel->GetControl();
207     auto jump = Goto(currentControl);
208     currentLabel->SetControl(jump);
209     label->AppendPredecessor(currentLabel);
210     label->MergeControl(currentLabel->GetControl());
211     env_->SetCurrentLabel(nullptr);
212 }
213 
Branch(GateRef condition,Label * trueLabel,Label * falseLabel,uint32_t trueWeight,uint32_t falseWeight)214 void CircuitBuilder::Branch(GateRef condition, Label *trueLabel, Label *falseLabel,
215                             uint32_t trueWeight, uint32_t falseWeight)
216 {
217     auto currentLabel = env_->GetCurrentLabel();
218     auto currentControl = currentLabel->GetControl();
219     GateRef ifBranch = Branch(currentControl, condition, trueWeight, falseWeight);
220     currentLabel->SetControl(ifBranch);
221     GateRef ifTrue = IfTrue(ifBranch);
222     trueLabel->AppendPredecessor(GetCurrentLabel());
223     trueLabel->MergeControl(ifTrue);
224     GateRef ifFalse = IfFalse(ifBranch);
225     falseLabel->AppendPredecessor(GetCurrentLabel());
226     falseLabel->MergeControl(ifFalse);
227     env_->SetCurrentLabel(nullptr);
228 }
229 
Switch(GateRef index,Label * defaultLabel,int64_t * keysValue,Label * keysLabel,int numberOfKeys)230 void CircuitBuilder::Switch(GateRef index, Label *defaultLabel, int64_t *keysValue, Label *keysLabel, int numberOfKeys)
231 {
232     auto currentLabel = env_->GetCurrentLabel();
233     auto currentControl = currentLabel->GetControl();
234     GateRef switchBranch = SwitchBranch(currentControl, index, numberOfKeys);
235     currentLabel->SetControl(switchBranch);
236     for (int i = 0; i < numberOfKeys; i++) {
237         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
238         GateRef switchCase = SwitchCase(switchBranch, keysValue[i]);
239         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
240         keysLabel[i].AppendPredecessor(currentLabel);
241         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
242         keysLabel[i].MergeControl(switchCase);
243     }
244 
245     GateRef defaultCase = DefaultCase(switchBranch);
246     defaultLabel->AppendPredecessor(currentLabel);
247     defaultLabel->MergeControl(defaultCase);
248     env_->SetCurrentLabel(nullptr);
249 }
250 
LoopBegin(Label * loopHead)251 void CircuitBuilder::LoopBegin(Label *loopHead)
252 {
253     ASSERT(loopHead);
254     auto loopControl = LoopBegin(loopHead->GetControl());
255     loopHead->SetControl(loopControl);
256     loopHead->SetPreControl(loopControl);
257     loopHead->Bind();
258     env_->SetCurrentLabel(loopHead);
259 }
260 
LoopEnd(Label * loopHead)261 void CircuitBuilder::LoopEnd(Label *loopHead)
262 {
263     ASSERT(loopHead);
264     auto currentLabel = GetCurrentLabel();
265     auto currentControl = currentLabel->GetControl();
266     auto loopend = LoopEnd(currentControl);
267     currentLabel->SetControl(loopend);
268     loopHead->AppendPredecessor(currentLabel);
269     loopHead->MergeControl(loopend);
270     loopHead->Seal();
271     loopHead->MergeAllControl();
272     loopHead->MergeAllDepend();
273     env_->SetCurrentLabel(nullptr);
274 }
275 
276 // add loop exit info at begin of label (only support not merge label)
LoopExit(const std::vector<Variable * > & vars,size_t diff)277 void CircuitBuilder::LoopExit(const std::vector<Variable *> &vars, size_t diff)
278 {
279     auto currentLabel = env_->GetCurrentLabel();
280     auto loopExit = currentLabel->GetControl();
281     auto loopExitDepend = currentLabel->GetDepend();
282     std::vector<GateRef> loopExitValues;
283     for (size_t i = 0; i < diff; ++i) {
284         loopExit = LoopExit(loopExit);
285         loopExitDepend = LoopExitDepend(loopExit, loopExitDepend);
286         for (const auto &var : vars) {
287             auto loopExitValue = LoopExitValue(loopExit, var->ReadVariable());
288             var->WriteVariable(loopExitValue);
289         }
290     }
291     currentLabel->SetControl(loopExit);
292     currentLabel->SetDepend(loopExitDepend);
293 }
294 
ClearConstantCache(GateRef gate)295 void CircuitBuilder::ClearConstantCache(GateRef gate)
296 {
297     ASSERT(acc_.GetOpCode(gate) == OpCode::CONSTANT);
298     auto machineType = acc_.GetMachineType(gate);
299     auto value = acc_.GetConstantValue(gate);
300     auto gateType = acc_.GetGateType(gate);
301     GetCircuit()->ClearConstantCache(machineType, value, gateType);
302 }
303 
DeoptCheck(GateRef condition,GateRef frameState,DeoptType type)304 GateRef CircuitBuilder::DeoptCheck(GateRef condition, GateRef frameState, DeoptType type)
305 {
306     std::string comment = Deoptimizier::DisplayItems(type);
307     auto currentLabel = env_->GetCurrentLabel();
308     auto currentControl = currentLabel->GetControl();
309     auto currentDepend = currentLabel->GetDepend();
310     ASSERT(acc_.GetOpCode(frameState) == OpCode::FRAME_STATE);
311     GateRef ret = GetCircuit()->NewGate(circuit_->DeoptCheck(),
312         MachineType::I1, { currentControl, condition,
313         frameState, Int64(static_cast<int64_t>(type))}, GateType::NJSValue(), comment.c_str());
314     auto dependRelay = DependRelay(ret, currentDepend);
315     currentLabel->SetControl(ret);
316     currentLabel->SetDepend(dependRelay);
317     return ret;
318 }
319 
GetSuperConstructor(GateRef ctor)320 GateRef CircuitBuilder::GetSuperConstructor(GateRef ctor)
321 {
322     auto currentLabel = env_->GetCurrentLabel();
323     auto currentControl = currentLabel->GetControl();
324     auto currentDepend = currentLabel->GetDepend();
325     auto ret = GetCircuit()->NewGate(circuit_->GetSuperConstructor(), MachineType::ANYVALUE,
326                                      { currentControl, currentDepend, ctor }, GateType::TaggedValue());
327     currentLabel->SetControl(ret);
328     currentLabel->SetDepend(ret);
329     return ret;
330 }
331 
Int8(int8_t val)332 GateRef CircuitBuilder::Int8(int8_t val)
333 {
334     return GetCircuit()->GetConstantGate(MachineType::I8, val, GateType::NJSValue());
335 }
336 
Int16(int16_t val)337 GateRef CircuitBuilder::Int16(int16_t val)
338 {
339     return GetCircuit()->GetConstantGate(MachineType::I16, val, GateType::NJSValue());
340 }
341 
Int32(int32_t val)342 GateRef CircuitBuilder::Int32(int32_t val)
343 {
344     return GetCircuit()->GetConstantGate(MachineType::I32, static_cast<BitField>(val), GateType::NJSValue());
345 }
346 
Int64(int64_t val)347 GateRef CircuitBuilder::Int64(int64_t val)
348 {
349     return GetCircuit()->GetConstantGate(MachineType::I64, val, GateType::NJSValue());
350 }
351 
IntPtr(int64_t val)352 GateRef CircuitBuilder::IntPtr(int64_t val)
353 {
354     return GetCircuit()->GetConstantGate(MachineType::ARCH, val, GateType::NJSValue());
355 }
356 
StringPtr(std::string_view str)357 GateRef CircuitBuilder::StringPtr(std::string_view str)
358 {
359     return GetCircuit()->GetConstantStringGate(MachineType::ARCH, str, GateType::NJSValue());
360 }
361 
RelocatableData(uint64_t val)362 GateRef CircuitBuilder::RelocatableData(uint64_t val)
363 {
364     return GetCircuit()->NewGate(circuit_->RelocatableData(val),
365         MachineType::ARCH, GateType::TaggedValue());
366 }
367 
Boolean(bool val)368 GateRef CircuitBuilder::Boolean(bool val)
369 {
370     return GetCircuit()->GetConstantGate(MachineType::I1, val ? 1 : 0, GateType::NJSValue());
371 }
372 
Double(double val)373 GateRef CircuitBuilder::Double(double val)
374 {
375     return GetCircuit()->GetConstantGate(MachineType::F64, base::bit_cast<int64_t>(val), GateType::NJSValue());
376 }
377 
HoleConstant()378 GateRef CircuitBuilder::HoleConstant()
379 {
380     auto type = GateType::TaggedValue();
381     return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_HOLE, type);
382 }
383 
SpecialHoleConstant()384 GateRef CircuitBuilder::SpecialHoleConstant()
385 {
386     auto type = GateType::NJSValue();
387     return GetCircuit()->GetConstantGate(MachineType::I64, base::SPECIAL_HOLE, type);
388 }
389 
NullPtrConstant()390 GateRef CircuitBuilder::NullPtrConstant()
391 {
392     auto type = GateType::TaggedValue();
393     return GetCircuit()->GetConstantGate(MachineType::I64, 0u, type);
394 }
395 
NullConstant()396 GateRef CircuitBuilder::NullConstant()
397 {
398     auto type = GateType::TaggedValue();
399     return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_NULL, type);
400 }
401 
ExceptionConstant()402 GateRef CircuitBuilder::ExceptionConstant()
403 {
404     auto type = GateType::TaggedValue();
405     return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_EXCEPTION, type);
406 }
407 
NanValue()408 GateRef CircuitBuilder::NanValue()
409 {
410     return Double(std::numeric_limits<double>::quiet_NaN());
411 }
412 
LoadObjectFromConstPool(GateRef jsFunc,GateRef index)413 GateRef CircuitBuilder::LoadObjectFromConstPool(GateRef jsFunc, GateRef index)
414 {
415     GateRef constPool = GetConstPoolFromFunction(jsFunc);
416     return GetValueFromTaggedArray(constPool, TruncInt64ToInt32(index));
417 }
418 
IsAccessorInternal(GateRef accessor)419 GateRef CircuitBuilder::IsAccessorInternal(GateRef accessor)
420 {
421     return Int32Equal(GetObjectType(LoadHClass(accessor)),
422                       Int32(static_cast<int32_t>(JSType::INTERNAL_ACCESSOR)));
423 }
424 
AppendFrameArgs(std::vector<GateRef> & args,GateRef hirGate)425 void CircuitBuilder::AppendFrameArgs(std::vector<GateRef> &args, GateRef hirGate)
426 {
427     GateRef frameArgs = acc_.GetFrameArgs(hirGate);
428     if (frameArgs == Circuit::NullGate()) {
429         args.emplace_back(IntPtr(0));
430     } else {
431         args.emplace_back(frameArgs);
432     }
433 }
434 
GetConstPool(GateRef jsFunc)435 GateRef CircuitBuilder::GetConstPool(GateRef jsFunc)
436 {
437     auto currentLabel = env_->GetCurrentLabel();
438     auto currentDepend = currentLabel->GetDepend();
439     // In an inline accessor scenario, if the accessor function and the caller function have the same constpool, then
440     // the caller function is used to load accessor, which avoids the dependency on the accessor.
441     if (acc_.GetOpCode(jsFunc) == OpCode::LOAD_GETTER || acc_.GetOpCode(jsFunc) == OpCode::LOAD_SETTER) {
442         GateRef frameState = acc_.GetFrameState(jsFunc);
443         if (acc_.GetOpCode(frameState) != OpCode::FRAME_STATE) {
444             jsFunc = frameState;
445         }
446     }
447     auto newGate = GetCircuit()->NewGate(circuit_->GetConstPool(), MachineType::I64,
448                                          { currentDepend, jsFunc },
449                                          GateType::AnyType());
450     currentLabel->SetDepend(newGate);
451     return newGate;
452 }
453 
GetGlobalEnv()454 GateRef CircuitBuilder::GetGlobalEnv()
455 {
456     auto currentLabel = env_->GetCurrentLabel();
457     auto currentDepend = currentLabel->GetDepend();
458     auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalEnv(), MachineType::I64,
459                                          { currentDepend },
460                                          GateType::AnyType());
461     currentLabel->SetDepend(newGate);
462     return newGate;
463 }
464 
GetGlobalEnvObj(GateRef env,size_t index)465 GateRef CircuitBuilder::GetGlobalEnvObj(GateRef env, size_t index)
466 {
467     auto currentLabel = env_->GetCurrentLabel();
468     auto currentDepend = currentLabel->GetDepend();
469     auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalEnvObj(index), MachineType::I64,
470                                          { currentDepend, env },
471                                          GateType::AnyType());
472     currentLabel->SetDepend(newGate);
473     return newGate;
474 }
475 
GetGlobalEnvObjHClass(GateRef env,size_t index)476 GateRef CircuitBuilder::GetGlobalEnvObjHClass(GateRef env, size_t index)
477 {
478     auto currentLabel = env_->GetCurrentLabel();
479     auto currentDepend = currentLabel->GetDepend();
480     auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalEnvObjHClass(index), MachineType::I64,
481                                          { currentDepend, env },
482                                          GateType::AnyType());
483     currentLabel->SetDepend(newGate);
484     return newGate;
485 }
486 
GetGlobalConstantValue(ConstantIndex index)487 GateRef CircuitBuilder::GetGlobalConstantValue(ConstantIndex index)
488 {
489     auto currentLabel = env_->GetCurrentLabel();
490     auto currentDepend = currentLabel->GetDepend();
491     auto newGate = GetCircuit()->NewGate(circuit_->GetGlobalConstantValue(static_cast<size_t>(index)),
492                                          MachineType::I64, { currentDepend }, GateType::AnyType());
493     currentLabel->SetDepend(newGate);
494     return newGate;
495 }
496 
HasPendingException(GateRef glue)497 GateRef CircuitBuilder::HasPendingException(GateRef glue)
498 {
499     GateRef exceptionOffset = IntPtr(JSThread::GlueData::GetExceptionOffset(env_->IsArch32Bit()));
500     GateRef exception = Load(VariableType::JS_ANY(), glue, exceptionOffset);
501     return TaggedIsNotHole(exception);
502 }
503 
IsUtf8String(GateRef string)504 GateRef CircuitBuilder::IsUtf8String(GateRef string)
505 {
506     // compressedStringsEnabled fixed to true constant
507     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
508     return Int32Equal(
509         Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)),
510         Int32(EcmaString::STRING_COMPRESSED));
511 }
512 
IsUtf16String(GateRef string)513 GateRef CircuitBuilder::IsUtf16String(GateRef string)
514 {
515     // compressedStringsEnabled fixed to true constant
516     GateRef len = Load(VariableType::INT32(), string, IntPtr(EcmaString::MIX_LENGTH_OFFSET));
517     return Int32Equal(
518         Int32And(len, Int32(EcmaString::STRING_COMPRESSED_BIT)),
519         Int32(EcmaString::STRING_UNCOMPRESSED));
520 }
521 
GetGlobalObject(GateRef glue)522 GateRef CircuitBuilder::GetGlobalObject(GateRef glue)
523 {
524     GateRef offset = IntPtr(JSThread::GlueData::GetGlobalObjOffset(cmpCfg_->Is32Bit()));
525     return Load(VariableType::JS_ANY(), glue, offset);
526 }
527 
GetMethodFromFunction(GateRef function)528 GateRef CircuitBuilder::GetMethodFromFunction(GateRef function)
529 {
530     GateRef offset = IntPtr(JSFunctionBase::METHOD_OFFSET);
531     return Load(VariableType::JS_POINTER(), function, offset);
532 }
533 
GetModuleFromFunction(GateRef function)534 GateRef CircuitBuilder::GetModuleFromFunction(GateRef function)
535 {
536     GateRef method = GetMethodFromFunction(function);
537     GateRef offset = IntPtr(Method::ECMA_MODULE_OFFSET);
538     return Load(VariableType::JS_POINTER(), method, offset);
539 }
540 
GetHomeObjectFromFunction(GateRef function)541 GateRef CircuitBuilder::GetHomeObjectFromFunction(GateRef function)
542 {
543     GateRef offset = IntPtr(JSFunction::HOME_OBJECT_OFFSET);
544     return Load(VariableType::JS_POINTER(), function, offset);
545 }
546 
GetConstPoolFromFunction(GateRef jsFunc)547 GateRef CircuitBuilder::GetConstPoolFromFunction(GateRef jsFunc)
548 {
549     GateRef method = GetMethodFromFunction(jsFunc);
550     return Load(VariableType::JS_ANY(), method, IntPtr(Method::CONSTANT_POOL_OFFSET));
551 }
552 
GetObjectFromConstPool(GateRef glue,GateRef hirGate,GateRef jsFunc,GateRef index,ConstPoolType type)553 GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef jsFunc, GateRef index,
554                                                ConstPoolType type)
555 {
556     GateRef constPool = GetConstPoolFromFunction(jsFunc);
557     GateRef module = GetModuleFromFunction(jsFunc);
558     return GetObjectFromConstPool(glue, hirGate, constPool, module, index, type);
559 }
560 
GetEmptyArray(GateRef glue)561 GateRef CircuitBuilder::GetEmptyArray(GateRef glue)
562 {
563     GateRef gConstAddr = Load(VariableType::JS_ANY(), glue,
564         IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
565     GateRef offset = GetGlobalConstantOffset(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
566     return Load(VariableType::JS_ANY(), gConstAddr, offset);
567 }
568 
GetPrototypeFromHClass(GateRef hClass)569 GateRef CircuitBuilder::GetPrototypeFromHClass(GateRef hClass)
570 {
571     GateRef protoOffset = IntPtr(JSHClass::PROTOTYPE_OFFSET);
572     return Load(VariableType::JS_ANY(), hClass, protoOffset);
573 }
574 
GetEnumCacheFromHClass(GateRef hClass)575 GateRef CircuitBuilder::GetEnumCacheFromHClass(GateRef hClass)
576 {
577     GateRef offset = IntPtr(JSHClass::ENUM_CACHE_OFFSET);
578     return Load(VariableType::JS_ANY(), hClass, offset);
579 }
580 
GetProtoChangeMarkerFromHClass(GateRef hClass)581 GateRef CircuitBuilder::GetProtoChangeMarkerFromHClass(GateRef hClass)
582 {
583     GateRef offset = IntPtr(JSHClass::PROTO_CHANGE_MARKER_OFFSET);
584     return Load(VariableType::JS_ANY(), hClass, offset);
585 }
586 
GetLengthFromForInIterator(GateRef iter)587 GateRef CircuitBuilder::GetLengthFromForInIterator(GateRef iter)
588 {
589     GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET);
590     return Load(VariableType::INT32(), iter, offset);
591 }
592 
GetIndexFromForInIterator(GateRef iter)593 GateRef CircuitBuilder::GetIndexFromForInIterator(GateRef iter)
594 {
595     GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
596     return Load(VariableType::INT32(), iter, offset);
597 }
598 
GetKeysFromForInIterator(GateRef iter)599 GateRef CircuitBuilder::GetKeysFromForInIterator(GateRef iter)
600 {
601     GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET);
602     return Load(VariableType::JS_ANY(), iter, offset);
603 }
604 
GetObjectFromForInIterator(GateRef iter)605 GateRef CircuitBuilder::GetObjectFromForInIterator(GateRef iter)
606 {
607     GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET);
608     return Load(VariableType::JS_ANY(), iter, offset);
609 }
610 
GetCachedHclassFromForInIterator(GateRef iter)611 GateRef CircuitBuilder::GetCachedHclassFromForInIterator(GateRef iter)
612 {
613     GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET);
614     return Load(VariableType::JS_ANY(), iter, offset);
615 }
616 
SetLengthOfForInIterator(GateRef glue,GateRef iter,GateRef length)617 void CircuitBuilder::SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length)
618 {
619     GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET);
620     Store(VariableType::INT32(), glue, iter, offset, length);
621 }
622 
SetIndexOfForInIterator(GateRef glue,GateRef iter,GateRef index)623 void CircuitBuilder::SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index)
624 {
625     GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
626     Store(VariableType::INT32(), glue, iter, offset, index);
627 }
628 
SetKeysOfForInIterator(GateRef glue,GateRef iter,GateRef keys)629 void CircuitBuilder::SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys)
630 {
631     GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET);
632     Store(VariableType::JS_ANY(), glue, iter, offset, keys);
633 }
634 
SetObjectOfForInIterator(GateRef glue,GateRef iter,GateRef object)635 void CircuitBuilder::SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object)
636 {
637     GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET);
638     Store(VariableType::JS_ANY(), glue, iter, offset, object);
639 }
640 
SetCachedHclassOfForInIterator(GateRef glue,GateRef iter,GateRef hclass)641 void CircuitBuilder::SetCachedHclassOfForInIterator(GateRef glue, GateRef iter, GateRef hclass)
642 {
643     GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET);
644     Store(VariableType::JS_ANY(), glue, iter, offset, hclass);
645 }
646 
SetNextIndexOfArrayIterator(GateRef glue,GateRef iter,GateRef nextIndex)647 void CircuitBuilder::SetNextIndexOfArrayIterator(GateRef glue, GateRef iter, GateRef nextIndex)
648 {
649     GateRef offset = IntPtr(JSArrayIterator::NEXT_INDEX_OFFSET);
650     Store(VariableType::INT32(), glue, iter, offset, nextIndex);
651 }
652 
SetIteratedArrayOfArrayIterator(GateRef glue,GateRef iter,GateRef iteratedArray)653 void CircuitBuilder::SetIteratedArrayOfArrayIterator(GateRef glue, GateRef iter, GateRef iteratedArray)
654 {
655     GateRef offset = IntPtr(JSArrayIterator::ITERATED_ARRAY_OFFSET);
656     Store(VariableType::JS_ANY(), glue, iter, offset, iteratedArray);
657 }
658 
SetBitFieldOfArrayIterator(GateRef glue,GateRef iter,GateRef kind)659 void CircuitBuilder::SetBitFieldOfArrayIterator(GateRef glue, GateRef iter, GateRef kind)
660 {
661     GateRef offset = IntPtr(JSArrayIterator::BIT_FIELD_OFFSET);
662     Store(VariableType::INT32(), glue, iter, offset, kind);
663 }
664 
IncreaseInteratorIndex(GateRef glue,GateRef iter,GateRef index)665 void CircuitBuilder::IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index)
666 {
667     GateRef newIndex = Int32Add(index, Int32(1));
668     GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
669     Store(VariableType::INT32(), glue, iter, offset, newIndex);
670 }
671 
GetHasChanged(GateRef object)672 GateRef CircuitBuilder::GetHasChanged(GateRef object)
673 {
674     GateRef bitfieldOffset = IntPtr(ProtoChangeMarker::BIT_FIELD_OFFSET);
675     GateRef bitfield = Load(VariableType::INT32(), object, bitfieldOffset);
676     GateRef mask = Int32(1LLU << (ProtoChangeMarker::HAS_CHANGED_BITS - 1));
677     return Int32NotEqual(Int32And(bitfield, mask), Int32(0));
678 }
679 
GetAccessorHasChanged(GateRef object)680 GateRef CircuitBuilder::GetAccessorHasChanged(GateRef object)
681 {
682     GateRef bitfieldOffset = IntPtr(ProtoChangeMarker::BIT_FIELD_OFFSET);
683     GateRef bitfield = Load(VariableType::INT32(), object, bitfieldOffset);
684     return Int32NotEqual(
685         Int32And(Int32LSR(bitfield, Int32(ProtoChangeMarker::AccessorHasChangedBits::START_BIT)),
686                  Int32((1LLU << ProtoChangeMarker::AccessorHasChangedBits::SIZE) - 1)),
687         Int32(0));
688 }
689 
HasDeleteProperty(GateRef hClass)690 GateRef CircuitBuilder::HasDeleteProperty(GateRef hClass)
691 {
692     GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET));
693     return Int32NotEqual(
694         Int32And(Int32LSR(bitfield, Int32(JSHClass::HasDeletePropertyBit::START_BIT)),
695                  Int32((1LLU << JSHClass::HasDeletePropertyBit::SIZE) - 1)),
696         Int32(0));
697 }
698 
IsOnHeap(GateRef hClass)699 GateRef CircuitBuilder::IsOnHeap(GateRef hClass)
700 {
701     GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
702     return Int32NotEqual(
703         Int32And(Int32LSR(bitfield, Int32(JSHClass::IsOnHeap::START_BIT)),
704                  Int32((1LU << JSHClass::IsOnHeap::SIZE) - 1)),
705         Int32(0));
706 }
707 
IsEcmaObject(GateRef obj)708 GateRef CircuitBuilder::IsEcmaObject(GateRef obj)
709 {
710     Label entryPass(env_);
711     SubCfgEntry(&entryPass);
712     DEFVALUE(result, env_, VariableType::BOOL(), False());
713     Label heapObj(env_);
714     Label exit(env_);
715     GateRef isHeapObject = TaggedIsHeapObject(obj);
716     Branch(isHeapObject, &heapObj, &exit);
717     Bind(&heapObj);
718     result = LogicAnd(isHeapObject, TaggedObjectIsEcmaObject(obj));
719     Jump(&exit);
720     Bind(&exit);
721     auto ret = *result;
722     SubCfgExit();
723     return ret;
724 }
725 
GetObjectFromConstPool(GateRef glue,GateRef hirGate,GateRef constPool,GateRef module,GateRef index,ConstPoolType type)726 GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module,
727                                                GateRef index, ConstPoolType type)
728 {
729     Label entry(env_);
730     SubCfgEntry(&entry);
731     Label exit(env_);
732     Label cacheMiss(env_);
733     Label cache(env_);
734 
735     // HirGate Can not be a nullGate in Aot
736     if (GetCircuit()->IsOptimizedJSFunctionFrame() && hirGate == Circuit::NullGate()) {
737         hirGate = index;
738     }
739     auto cacheValue = GetValueFromTaggedArray(constPool, index);
740     DEFVALUE(result, env_, VariableType::JS_ANY(), cacheValue);
741     Branch(BoolOr(TaggedIsHole(*result), TaggedIsNullPtr(*result)), &cacheMiss, &cache);
742     Bind(&cacheMiss);
743     {
744         if (type == ConstPoolType::STRING) {
745             result = CallRuntime(glue, RTSTUB_ID(GetStringFromCache), Gate::InvalidGateRef,
746                 { constPool, Int32ToTaggedInt(index) }, hirGate);
747         } else if (type == ConstPoolType::ARRAY_LITERAL) {
748             result = CallRuntime(glue, RTSTUB_ID(GetArrayLiteralFromCache), Gate::InvalidGateRef,
749                 { constPool, Int32ToTaggedInt(index), module }, hirGate);
750         } else if (type == ConstPoolType::OBJECT_LITERAL) {
751             result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef,
752                 { constPool, Int32ToTaggedInt(index), module }, hirGate);
753         } else {
754             result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef,
755                 { constPool, Int32ToTaggedInt(index), module }, hirGate);
756         }
757         Jump(&exit);
758     }
759     Bind(&cache);
760     {
761         if (type == ConstPoolType::METHOD) {
762             Label isAOTLiteralInfo(env_);
763             Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
764             Bind(&isAOTLiteralInfo);
765             {
766                 result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef,
767                     { constPool, Int32ToTaggedInt(index), module }, hirGate);
768                 Jump(&exit);
769             }
770         } else if (type == ConstPoolType::ARRAY_LITERAL) {
771             Label isAOTLiteralInfo(env_);
772             Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
773             Bind(&isAOTLiteralInfo);
774             {
775                 result = CallRuntime(glue, RTSTUB_ID(GetArrayLiteralFromCache), Gate::InvalidGateRef,
776                     { constPool, Int32ToTaggedInt(index), module }, hirGate);
777                 Jump(&exit);
778             }
779         } else if (type == ConstPoolType::OBJECT_LITERAL) {
780             Label isAOTLiteralInfo(env_);
781             Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
782             Bind(&isAOTLiteralInfo);
783             {
784                 result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef,
785                     { constPool, Int32ToTaggedInt(index), module }, hirGate);
786                 Jump(&exit);
787             }
788         } else {
789             Jump(&exit);
790         }
791     }
792     Bind(&exit);
793     auto ret = *result;
794     SubCfgExit();
795     return ret;
796 }
797 
GetFunctionLexicalEnv(GateRef function)798 GateRef CircuitBuilder::GetFunctionLexicalEnv(GateRef function)
799 {
800     return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::LEXICAL_ENV_OFFSET));
801 }
802 
SetLengthToFunction(GateRef glue,GateRef function,GateRef value)803 void CircuitBuilder::SetLengthToFunction(GateRef glue, GateRef function, GateRef value)
804 {
805     GateRef offset = IntPtr(JSFunction::LENGTH_OFFSET);
806     Store(VariableType::INT32(), glue, function, offset, value);
807 }
808 
SetLexicalEnvToFunction(GateRef glue,GateRef function,GateRef value)809 void CircuitBuilder::SetLexicalEnvToFunction(GateRef glue, GateRef function, GateRef value)
810 {
811     GateRef offset = IntPtr(JSFunction::LEXICAL_ENV_OFFSET);
812     Store(VariableType::JS_ANY(), glue, function, offset, value);
813 }
814 
SetHomeObjectToFunction(GateRef glue,GateRef function,GateRef value)815 void CircuitBuilder::SetHomeObjectToFunction(GateRef glue, GateRef function, GateRef value)
816 {
817     GateRef offset = IntPtr(JSFunction::HOME_OBJECT_OFFSET);
818     Store(VariableType::JS_ANY(), glue, function, offset, value);
819 }
820 
GetGlobalEnvValue(VariableType type,GateRef env,size_t index)821 GateRef CircuitBuilder::GetGlobalEnvValue(VariableType type, GateRef env, size_t index)
822 {
823     auto valueIndex = IntPtr(GlobalEnv::HEADER_SIZE + JSTaggedValue::TaggedTypeSize() * index);
824     return Load(type, env, valueIndex);
825 }
826 
GetCodeAddr(GateRef method)827 GateRef CircuitBuilder::GetCodeAddr(GateRef method)
828 {
829     auto codeAddOffset = IntPtr(Method::CODE_ENTRY_OFFSET);
830     return Load(VariableType::NATIVE_POINTER(), method, codeAddOffset);
831 }
832 
GetHClassGateFromIndex(GateRef gate,int32_t index)833 GateRef CircuitBuilder::GetHClassGateFromIndex(GateRef gate, int32_t index)
834 {
835     ArgumentAccessor argAcc(circuit_);
836     GateRef jsFunc = argAcc.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
837     GateRef constPool = GetConstPool(jsFunc);
838     return LoadHClassFromConstpool(constPool, index);
839 }
840 
AddPhiOperand(GateRef val)841 GateRef Variable::AddPhiOperand(GateRef val)
842 {
843     ASSERT(GateAccessor(env_->GetCircuit()).IsValueSelector(val));
844     Label label = env_->GetLabelFromSelector(val);
845     size_t idx = 0;
846     for (auto pred : label.GetPredecessors()) {
847         auto preVal = pred.ReadVariable(this);
848         ASSERT(!GateAccessor(env_->GetCircuit()).IsNop(preVal));
849         idx++;
850         val = AddOperandToSelector(val, idx, preVal);
851     }
852     return TryRemoveTrivialPhi(val);
853 }
854 
AddOperandToSelector(GateRef val,size_t idx,GateRef in)855 GateRef Variable::AddOperandToSelector(GateRef val, size_t idx, GateRef in)
856 {
857     GateAccessor(env_->GetCircuit()).NewIn(val, idx, in);
858     return val;
859 }
860 
TryRemoveTrivialPhi(GateRef phi)861 GateRef Variable::TryRemoveTrivialPhi(GateRef phi)
862 {
863     GateAccessor acc(GetCircuit());
864     GateRef same = Gate::InvalidGateRef;
865     const size_t inNum = acc.GetNumIns(phi);
866     for (size_t i = 1; i < inNum; ++i) {
867         GateRef phiIn = acc.GetIn(phi, i);
868         if (phiIn == same || phiIn == phi) {
869             continue;  // unique value or self-reference
870         }
871         if (same != Gate::InvalidGateRef) {
872             return phi;  // the phi merges at least two valusses: not trivial
873         }
874         same = phiIn;
875     }
876     if (same == Gate::InvalidGateRef) {
877         // the phi is unreachable or in the start block
878         GateType type = acc.GetGateType(phi);
879         same = env_->GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, type);
880     }
881     // remove the trivial phi
882     // get all users of phi except self
883     std::vector<GateRef> outs;
884     auto uses = acc.Uses(phi);
885     for (auto use = uses.begin(); use != uses.end();) {
886         GateRef u = *use;
887         if (u != phi) {
888             outs.push_back(u);
889             use = acc.ReplaceIn(use, same);
890         } else {
891             use++;
892         }
893     }
894     acc.DeleteGate(phi);
895 
896     // try to recursiveby remove all phi users, which might have vecome trivial
897     for (auto out : outs) {
898         if (acc.IsValueSelector(out)) {
899             auto result = TryRemoveTrivialPhi(out);
900             if (same == out) {
901                 same = result;
902             }
903         }
904     }
905     return same;
906 }
907 
LoadBuiltinObject(size_t offset)908 GateRef CircuitBuilder::LoadBuiltinObject(size_t offset)
909 {
910     auto currentLabel = env_->GetCurrentLabel();
911     auto currentControl = currentLabel->GetControl();
912     auto currentDepend = currentLabel->GetDepend();
913     auto frameState = acc_.FindNearestFrameState(currentDepend);
914     GateRef ret = GetCircuit()->NewGate(circuit_->LoadBuiltinObject(offset),
915                                         MachineType::I64,
916                                         {currentControl, currentDepend, frameState},
917                                         GateType::AnyType());
918     currentLabel->SetControl(ret);
919     currentLabel->SetDepend(ret);
920     return ret;
921 }
922 
923 }  // namespace panda::ecmascript::kungfu
924