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, ¬IsECMAObject);
1357 Bind(&isECMAObject);
1358 {
1359 result = obj;
1360 Jump(&exit);
1361 }
1362 Bind(¬IsECMAObject);
1363 BRANCH(TaggedIsNumber(obj), &isNumber, ¬Number);
1364 Bind(&isNumber);
1365 {
1366 result = NewJSPrimitiveRef(glue, globalEnv, GlobalEnv::NUMBER_FUNCTION_INDEX, obj);
1367 Jump(&exit);
1368 }
1369 Bind(¬Number);
1370 BRANCH(TaggedIsBoolean(obj), &isBoolean, ¬Boolean);
1371 Bind(&isBoolean);
1372 {
1373 result = NewJSPrimitiveRef(glue, globalEnv, GlobalEnv::BOOLEAN_FUNCTION_INDEX, obj);
1374 Jump(&exit);
1375 }
1376 Bind(¬Boolean);
1377 BRANCH(TaggedIsString(glue, obj), &isString, ¬String);
1378 Bind(&isString);
1379 {
1380 result = NewJSPrimitiveRef(glue, globalEnv, GlobalEnv::STRING_FUNCTION_INDEX, obj);
1381 Jump(&exit);
1382 }
1383 Bind(¬String);
1384 BRANCH(TaggedIsSymbol(glue, obj), &isSymbol, ¬Symbol);
1385 Bind(&isSymbol);
1386 {
1387 result = NewJSPrimitiveRef(glue, globalEnv, GlobalEnv::SYMBOL_FUNCTION_INDEX, obj);
1388 Jump(&exit);
1389 }
1390 Bind(¬Symbol);
1391 BRANCH(TaggedIsUndefined(obj), &isUndefined, ¬IsUndefined);
1392 Bind(&isUndefined);
1393 {
1394 taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotUndefinedObject));
1395 Jump(&throwError);
1396 }
1397 Bind(¬IsUndefined);
1398 BRANCH(TaggedIsHole(obj), &isHole, ¬IsHole);
1399 Bind(&isHole);
1400 {
1401 taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotHoleObject));
1402 Jump(&throwError);
1403 }
1404 Bind(¬IsHole);
1405 BRANCH(TaggedIsNull(obj), &isNull, ¬IsNull);
1406 Bind(&isNull);
1407 {
1408 taggedId = Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotNullObject));
1409 Jump(&throwError);
1410 }
1411 Bind(¬IsNull);
1412 BRANCH(TaggedIsBigInt(glue, obj), &isBigInt, ¬IsBigInt);
1413 Bind(&isBigInt);
1414 {
1415 result = NewJSPrimitiveRef(glue, globalEnv, GlobalEnv::BIGINT_FUNCTION_INDEX, obj);
1416 Jump(&exit);
1417 }
1418 Bind(¬IsBigInt);
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, ¬ProfileTypeInfoCell0);
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(¬ProfileTypeInfoCell0);
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, ¬Special);
1665 Bind(&isSpecial);
1666 {
1667 BRANCH(TaggedIsTrue(value), &returnTrue, &returnFalse);
1668 }
1669 Bind(¬Special);
1670 {
1671 BRANCH(TaggedIsNumber(value), &isNumber, ¬Number);
1672 Bind(¬Number);
1673 {
1674 BRANCH(TaggedIsString(glue, value), &isString, ¬String);
1675 Bind(&isString);
1676 {
1677 auto len = GetLengthFromString(value);
1678 BRANCH(Int32Equal(len, Int32(0)), &returnFalse, &returnTrue);
1679 }
1680 Bind(¬String);
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, ¬Nan);
1706 Bind(¬Nan);
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