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