1 /*
2 * Copyright (c) 2023-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/hcr_circuit_builder.h"
17 #include "ecmascript/compiler/common_stub_csigns.h"
18 #include "ecmascript/js_thread.h"
19 #include "ecmascript/compiler/circuit_builder-inl.h"
20
21 namespace panda::ecmascript::kungfu {
22
NoLabelCallRuntime(GateRef glue, GateRef depend, size_t index, std::vector<GateRef> &args, GateRef hirGate)23 GateRef CircuitBuilder::NoLabelCallRuntime(GateRef glue, GateRef depend, size_t index, std::vector<GateRef> &args,
24 GateRef hirGate)
25 {
26 const std::string name = RuntimeStubCSigns::GetRTName(RTSTUB_ID(CallRuntime));
27 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
28 GateRef target = IntPtr(index);
29 std::vector<GateRef> inputs { depend, target, glue };
30 inputs.insert(inputs.end(), args.begin(), args.end());
31 auto numValuesIn = args.size() + 2; // 2: target & glue
32 inputs.emplace_back(IntPtr(0)); // framestate slot
33 numValuesIn += 1;
34 GateRef pcOffset = Int64(acc_.TryGetPcOffset(hirGate));
35 inputs.emplace_back(pcOffset);
36 numValuesIn += 1;
37
38 const GateMetaData* meta = circuit_->RuntimeCall(numValuesIn);
39 MachineType machineType = cs->GetReturnType().GetMachineType();
40 GateType type = cs->GetReturnType().GetGateType();
41 GateRef result = circuit_->NewGate(meta, machineType, inputs.size(), inputs.data(), type, name.c_str());
42 return result;
43 }
44
ToLength(GateRef receiver)45 GateRef CircuitBuilder::ToLength(GateRef receiver)
46 {
47 auto currentLabel = env_->GetCurrentLabel();
48 auto currentControl = currentLabel->GetControl();
49 auto currentDepend = currentLabel->GetDepend();
50 auto ret = GetCircuit()->NewGate(circuit_->ToLength(), MachineType::I64,
51 { currentControl, currentDepend, receiver }, GateType::NumberType());
52 currentLabel->SetControl(ret);
53 currentLabel->SetDepend(ret);
54 return ret;
55 }
56
CallStub(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args, const char* comment)57 GateRef CircuitBuilder::CallStub(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
58 const char* comment)
59 {
60 const CallSignature *cs = env_->IsBaselineBuiltin() ? BaselineStubCSigns::Get(index) :
61 CommonStubCSigns::Get(index);
62 ASSERT(cs->IsCommonStub() || cs->IsBaselineStub());
63 GateRef target = IntPtr(index);
64 auto label = GetCurrentLabel();
65 auto depend = label->GetDepend();
66 GateRef result;
67 if (GetCircuit()->IsOptimizedOrFastJit()) {
68 ASSERT(hirGate != Circuit::NullGate());
69 result = Call(cs, glue, target, depend, args, hirGate, comment);
70 } else {
71 result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
72 }
73 return result;
74 }
75
CallBuiltinRuntime(GateRef glue, GateRef depend, const std::vector<GateRef> &args, bool isNew)76 GateRef CircuitBuilder::CallBuiltinRuntime(GateRef glue, GateRef depend, const std::vector<GateRef> &args, bool isNew)
77 {
78 ASSERT(!GetCircuit()->IsOptimizedOrFastJit());
79 int index = 0;
80 if (!isNew) {
81 index = static_cast<int>(RTSTUB_ID(PushCallArgsAndDispatchNative));
82 } else {
83 index = static_cast<int>(RTSTUB_ID(PushCallNewAndDispatchNative));
84 }
85 const std::string name = RuntimeStubCSigns::GetRTName(index);
86
87 const CallSignature *cs = RuntimeStubCSigns::Get(index);
88 GateRef target = IntPtr(index);
89 auto label = GetCurrentLabel();
90 if (depend == Gate::InvalidGateRef) {
91 depend = label->GetDepend();
92 }
93 GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), name.c_str());
94 return result;
95 }
96
CallBuiltinRuntimeWithNewTarget(GateRef glue, GateRef depend, const std::vector<GateRef> &args)97 GateRef CircuitBuilder::CallBuiltinRuntimeWithNewTarget(GateRef glue, GateRef depend, const std::vector<GateRef> &args)
98 {
99 ASSERT(!GetCircuit()->IsOptimizedOrFastJit());
100 int index = 0;
101
102 index = static_cast<int>(RTSTUB_ID(PushNewTargetAndDispatchNative));
103 const std::string name = RuntimeStubCSigns::GetRTName(index);
104
105 const CallSignature *cs = RuntimeStubCSigns::Get(index);
106 GateRef target = IntPtr(index);
107 auto label = GetCurrentLabel();
108 if (depend == Gate::InvalidGateRef) {
109 depend = label->GetDepend();
110 }
111 GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), name.c_str());
112 return result;
113 }
114
Call(const CallSignature* cs, GateRef glue, GateRef target, GateRef depend, const std::vector<GateRef> &args, GateRef hirGate, const char* comment)115 GateRef CircuitBuilder::Call(const CallSignature* cs, GateRef glue, GateRef target, GateRef depend,
116 const std::vector<GateRef> &args, GateRef hirGate, const char* comment)
117 {
118 std::vector<GateRef> inputs { depend, target, glue };
119 inputs.insert(inputs.end(), args.begin(), args.end());
120 auto numValuesIn = args.size() + 2; // 2: target & glue
121 if (GetCircuit()->IsOptimizedOrFastJit() && hirGate != Circuit::NullGate()) {
122 AppendFrameArgs(inputs, hirGate);
123 numValuesIn += 1;
124
125 GateRef pcOffset = Int64(acc_.TryGetPcOffset(hirGate));
126 inputs.emplace_back(pcOffset);
127 numValuesIn += 1;
128 }
129
130 const GateMetaData* meta = nullptr;
131 if (cs->IsCommonStub()) {
132 meta = circuit_->Call(numValuesIn);
133 } else if (cs->IsRuntimeVAStub()) {
134 meta = circuit_->RuntimeCallWithArgv(numValuesIn);
135 } else if (cs->IsRuntimeStub()) {
136 meta = circuit_->RuntimeCall(numValuesIn);
137 } else if (cs->IsBCDebuggerStub()) {
138 meta = circuit_->DebuggerBytecodeCall(numValuesIn);
139 } else if (cs->IsBCHandlerStub()) {
140 meta = circuit_->BytecodeCall(numValuesIn);
141 } else if (cs->IsBuiltinsStub()) {
142 meta = circuit_->BuiltinsCall(numValuesIn);
143 } else if (cs->IsBuiltinsWithArgvStub()) {
144 meta = circuit_->BuiltinsCallWithArgv(numValuesIn);
145 } else if (cs->IsRuntimeNGCStub()) {
146 meta = circuit_->NoGcRuntimeCall(numValuesIn);
147 } else if (cs->IsOptimizedStub()) {
148 bool isNoGC = acc_.GetNoGCFlag(hirGate);
149 meta = circuit_->CallOptimized(numValuesIn, isNoGC);
150 } else if (cs->IsOptimizedFastCallStub()) {
151 bool isNoGC = acc_.GetNoGCFlag(hirGate);
152 meta = circuit_->FastCallOptimized(numValuesIn, isNoGC);
153 } else if (cs->IsBaselineStub()) {
154 meta = circuit_->BaselineCall(numValuesIn);
155 } else if (cs->IsASMCallBarrierStub()) {
156 meta = circuit_->ASMCallBarrier(numValuesIn);
157 } else {
158 LOG_ECMA(FATAL) << "unknown call operator";
159 UNREACHABLE();
160 }
161 MachineType machineType = cs->GetReturnType().GetMachineType();
162 GateType type = cs->GetReturnType().GetGateType();
163 GateRef result = GetCircuit()->NewGate(meta, machineType, inputs.size(), inputs.data(), type, comment);
164 auto label = GetCurrentLabel();
165 label->SetDepend(result);
166 return result;
167 }
168
CallBCHandler(GateRef glue, GateRef target, const std::vector<GateRef> &args, const char* comment)169 GateRef CircuitBuilder::CallBCHandler(GateRef glue, GateRef target, const std::vector<GateRef> &args,
170 const char* comment)
171 {
172 ASSERT(!GetCircuit()->IsOptimizedOrFastJit());
173 const CallSignature *cs = BytecodeStubCSigns::BCHandler();
174 ASSERT(cs->IsBCStub());
175 auto label = GetCurrentLabel();
176 auto depend = label->GetDepend();
177 GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
178 return result;
179 }
180
CallBuiltin(GateRef glue, GateRef target, const std::vector<GateRef> &args, const char* comment)181 GateRef CircuitBuilder::CallBuiltin(GateRef glue, GateRef target, const std::vector<GateRef> &args,
182 const char* comment)
183 {
184 ASSERT(!GetCircuit()->IsOptimizedOrFastJit());
185 const CallSignature *cs = BuiltinsStubCSigns::BuiltinsCSign();
186 ASSERT(cs->IsBuiltinsStub());
187 auto label = GetCurrentLabel();
188 auto depend = label->GetDepend();
189 GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
190 return result;
191 }
192
CallBuiltinWithArgv(GateRef glue, GateRef target, const std::vector<GateRef> &args, const char* comment)193 GateRef CircuitBuilder::CallBuiltinWithArgv(GateRef glue, GateRef target, const std::vector<GateRef> &args,
194 const char* comment)
195 {
196 ASSERT(!GetCircuit()->IsOptimizedOrFastJit());
197 const CallSignature *cs = BuiltinsStubCSigns::BuiltinsWithArgvCSign();
198 ASSERT(cs->IsBuiltinsWithArgvStub());
199 auto label = GetCurrentLabel();
200 auto depend = label->GetDepend();
201 GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
202 return result;
203 }
204
CallBCDebugger(GateRef glue, GateRef target, const std::vector<GateRef> &args, const char* comment)205 GateRef CircuitBuilder::CallBCDebugger(GateRef glue, GateRef target, const std::vector<GateRef> &args,
206 const char* comment)
207 {
208 ASSERT(!GetCircuit()->IsOptimizedOrFastJit());
209 const CallSignature *cs = BytecodeStubCSigns::BCDebuggerHandler();
210 ASSERT(cs->IsBCDebuggerStub());
211 auto label = GetCurrentLabel();
212 auto depend = label->GetDepend();
213 GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
214 return result;
215 }
216
CallRuntime(GateRef glue, int index, GateRef depend, const std::vector<GateRef> &args, GateRef hirGate, const char* comment)217 GateRef CircuitBuilder::CallRuntime(GateRef glue, int index, GateRef depend, const std::vector<GateRef> &args,
218 GateRef hirGate, const char* comment)
219 {
220 GateRef target = IntPtr(index);
221 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
222 ASSERT(cs->IsRuntimeStub());
223 auto label = GetCurrentLabel();
224 if (depend == Gate::InvalidGateRef) {
225 depend = label->GetDepend();
226 }
227 GateRef filteredHirGate = Circuit::NullGate();
228 if (GetCircuit()->IsOptimizedOrFastJit()) {
229 ASSERT(hirGate != Circuit::NullGate());
230 filteredHirGate = hirGate;
231 }
232 GateRef result = Call(cs, glue, target, depend, args, filteredHirGate, comment);
233 return result;
234 }
235
CallRuntimeVarargs(GateRef glue, int index, GateRef argc, GateRef argv, const char* comment)236 GateRef CircuitBuilder::CallRuntimeVarargs(GateRef glue, int index, GateRef argc, GateRef argv, const char* comment)
237 {
238 ASSERT(!GetCircuit()->IsOptimizedOrFastJit());
239 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntimeWithArgv));
240 GateRef target = IntPtr(index);
241 auto label = GetCurrentLabel();
242 auto depend = label->GetDepend();
243 ASSERT(cs->IsRuntimeVAStub());
244 GateRef result = Call(cs, glue, target, depend, {argc, argv}, Circuit::NullGate(), comment);
245 return result;
246 }
247
CallNGCRuntime(GateRef glue, int index, GateRef depend, const std::vector<GateRef> &args, GateRef hirGate, const char* comment)248 GateRef CircuitBuilder::CallNGCRuntime(GateRef glue, int index, GateRef depend, const std::vector<GateRef> &args,
249 GateRef hirGate, const char* comment)
250 {
251 const CallSignature *cs = RuntimeStubCSigns::Get(index);
252 ASSERT(cs->IsRuntimeNGCStub());
253 GateRef target = IntPtr(index);
254 auto label = GetCurrentLabel();
255 if (depend == Gate::InvalidGateRef) {
256 depend = label->GetDepend();
257 }
258 GateRef filteredHirGate = Circuit::NullGate();
259 if (GetCircuit()->IsOptimizedOrFastJit() && RuntimeStubCSigns::IsAsmStub(index)) {
260 ASSERT(hirGate != Circuit::NullGate());
261 filteredHirGate = hirGate;
262 }
263 GateRef result = Call(cs, glue, target, depend, args, filteredHirGate, comment);
264 return result;
265 }
266
CallNGCRuntime(GateRef glue, GateRef gate, int index, const std::vector<GateRef> &args, bool useLabel)267 GateRef CircuitBuilder::CallNGCRuntime(GateRef glue, GateRef gate, int index, const std::vector<GateRef> &args,
268 bool useLabel)
269 {
270 const std::string name = RuntimeStubCSigns::GetRTName(index);
271 if (useLabel) {
272 GateRef result = CallNGCRuntime(glue, index, Gate::InvalidGateRef, args, gate, name.c_str());
273 return result;
274 } else {
275 const CallSignature *cs = RuntimeStubCSigns::Get(index);
276 GateRef target = IntPtr(index);
277 GateRef result = Call(cs, glue, target, GetDepend(), args, gate, name.c_str());
278 return result;
279 }
280 }
281
StartCallTimer(GateRef glue, GateRef gate, const std::vector<GateRef> &args, bool useLabel)282 void CircuitBuilder::StartCallTimer(GateRef glue, GateRef gate, const std::vector<GateRef> &args, bool useLabel)
283 {
284 (void)glue;
285 (void)gate;
286 (void)args;
287 (void)useLabel;
288 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
289 CallNGCRuntime(glue, gate, RTSTUB_ID(StartCallTimer), args, useLabel);
290 #endif
291 }
292
EndCallTimer(GateRef glue, GateRef gate, const std::vector<GateRef> &args, bool useLabel)293 void CircuitBuilder::EndCallTimer(GateRef glue, GateRef gate, const std::vector<GateRef> &args, bool useLabel)
294 {
295 (void)glue;
296 (void)gate;
297 (void)args;
298 (void)useLabel;
299 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
300 CallNGCRuntime(glue, gate, RTSTUB_ID(EndCallTimer), args, useLabel);
301 #endif
302 }
303
FastCallOptimized(GateRef glue, GateRef code, GateRef depend, const std::vector<GateRef> &args, GateRef hirGate)304 GateRef CircuitBuilder::FastCallOptimized(GateRef glue, GateRef code, GateRef depend, const std::vector<GateRef> &args,
305 GateRef hirGate)
306 {
307 const CallSignature *cs = RuntimeStubCSigns::GetOptimizedFastCallSign();
308 ASSERT(cs->IsOptimizedFastCallStub());
309 auto label = GetCurrentLabel();
310 if (depend == Gate::InvalidGateRef) {
311 depend = label->GetDepend();
312 }
313 GateRef filteredHirGate = Circuit::NullGate();
314 if (GetCircuit()->IsOptimizedOrFastJit()) {
315 ASSERT(hirGate != Circuit::NullGate());
316 filteredHirGate = hirGate;
317 }
318 GateRef result = Call(cs, glue, code, depend, args, filteredHirGate, "fastCallOptimized");
319 return result;
320 }
321
CallOptimized(GateRef glue, GateRef code, GateRef depend, const std::vector<GateRef> &args, GateRef hirGate)322 GateRef CircuitBuilder::CallOptimized(GateRef glue, GateRef code, GateRef depend, const std::vector<GateRef> &args,
323 GateRef hirGate)
324 {
325 const CallSignature *cs = RuntimeStubCSigns::GetOptimizedCallSign();
326 ASSERT(cs->IsOptimizedStub());
327 auto label = GetCurrentLabel();
328 if (depend == Gate::InvalidGateRef) {
329 depend = label->GetDepend();
330 }
331 GateRef filteredHirGate = Circuit::NullGate();
332 if (GetCircuit()->IsOptimizedOrFastJit()) {
333 ASSERT(hirGate != Circuit::NullGate());
334 filteredHirGate = hirGate;
335 }
336 GateRef result = Call(cs, glue, code, depend, args, filteredHirGate, "callOptimized");
337 return result;
338 }
339
GetCallBuiltinId(GateRef method)340 GateRef CircuitBuilder::GetCallBuiltinId(GateRef method)
341 {
342 GateRef extraLiteralInfoOffset = IntPtr(Method::EXTRA_LITERAL_INFO_OFFSET);
343 GateRef extraLiteralInfo = Load(VariableType::INT64(), method, extraLiteralInfoOffset);
344 return Int64And(
345 Int64LSR(extraLiteralInfo, Int64(MethodLiteral::BuiltinIdBits::START_BIT)),
346 Int64((1LU << MethodLiteral::BuiltinIdBits::SIZE) - 1));
347 }
348
CallPrivateGetter(GateRef hirGate, GateRef receiver, GateRef accessor, const char* comment)349 GateRef CircuitBuilder::CallPrivateGetter(GateRef hirGate, GateRef receiver, GateRef accessor, const char* comment)
350 {
351 ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
352 uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
353 ASSERT(pcOffset != 0);
354
355 auto currentLabel = env_->GetCurrentLabel();
356 auto currentControl = currentLabel->GetControl();
357 auto currentDepend = currentLabel->GetDepend();
358 std::vector<GateRef> args = {currentControl, currentDepend, receiver, accessor};
359 AppendFrameArgs(args, hirGate);
360 auto callGate = GetCircuit()->NewGate(circuit_->CallPrivateGetter(pcOffset),
361 MachineType::I64,
362 args.size(),
363 args.data(),
364 GateType::AnyType(),
365 comment);
366 currentLabel->SetControl(callGate);
367 currentLabel->SetDepend(callGate);
368 return callGate;
369 }
370
CallPrivateSetter( GateRef hirGate, GateRef receiver, GateRef accessor, GateRef value, const char* comment)371 GateRef CircuitBuilder::CallPrivateSetter(
372 GateRef hirGate, GateRef receiver, GateRef accessor, GateRef value, const char* comment)
373 {
374 ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
375 uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
376 ASSERT(pcOffset != 0);
377
378 auto currentLabel = env_->GetCurrentLabel();
379 auto currentControl = currentLabel->GetControl();
380 auto currentDepend = currentLabel->GetDepend();
381 std::vector<GateRef> args = {currentControl, currentDepend, receiver, accessor, value};
382 AppendFrameArgs(args, hirGate);
383 auto callGate = GetCircuit()->NewGate(circuit_->CallPrivateSetter(pcOffset),
384 MachineType::I64,
385 args.size(),
386 args.data(),
387 GateType::AnyType(),
388 comment);
389 currentLabel->SetControl(callGate);
390 currentLabel->SetDepend(callGate);
391 return callGate;
392 }
393
CallGetter(GateRef hirGate, GateRef receiver, GateRef holder, GateRef propertyLookupResult, const char* comment)394 GateRef CircuitBuilder::CallGetter(GateRef hirGate, GateRef receiver, GateRef holder, GateRef propertyLookupResult,
395 const char* comment)
396 {
397 ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
398 uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
399 ASSERT(pcOffset != 0);
400
401 auto currentLabel = env_->GetCurrentLabel();
402 auto currentControl = currentLabel->GetControl();
403 auto currentDepend = currentLabel->GetDepend();
404 std::vector<GateRef> args = { currentControl, currentDepend, receiver, propertyLookupResult, holder };
405 AppendFrameArgs(args, hirGate);
406 auto callGate = GetCircuit()->NewGate(circuit_->CallGetter(pcOffset),
407 MachineType::I64,
408 args.size(),
409 args.data(),
410 GateType::AnyType(),
411 comment);
412 currentLabel->SetControl(callGate);
413 currentLabel->SetDepend(callGate);
414 return callGate;
415 }
416
CallSetter(GateRef hirGate, GateRef receiver, GateRef holder, GateRef propertyLookupResult, GateRef value, const char* comment)417 GateRef CircuitBuilder::CallSetter(GateRef hirGate, GateRef receiver, GateRef holder, GateRef propertyLookupResult,
418 GateRef value, const char* comment)
419 {
420 ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
421 uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
422 ASSERT(pcOffset != 0);
423
424 auto currentLabel = env_->GetCurrentLabel();
425 auto currentControl = currentLabel->GetControl();
426 auto currentDepend = currentLabel->GetDepend();
427 std::vector<GateRef> args = { currentControl, currentDepend, receiver, propertyLookupResult, holder, value };
428 AppendFrameArgs(args, hirGate);
429 auto callGate = GetCircuit()->NewGate(circuit_->CallSetter(pcOffset),
430 MachineType::I64,
431 args.size(),
432 args.data(),
433 GateType::AnyType(),
434 comment);
435 currentLabel->SetControl(callGate);
436 currentLabel->SetDepend(callGate);
437 return callGate;
438 }
439
Float32ArrayConstructor(GateRef hirGate, std::vector<GateRef> args)440 GateRef CircuitBuilder::Float32ArrayConstructor(GateRef hirGate, std::vector<GateRef> args)
441 {
442 ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
443 auto currentLabel = env_->GetCurrentLabel();
444 auto currentControl = currentLabel->GetControl();
445 auto currentDepend = currentLabel->GetDepend();
446 uint64_t bitfield = args.size();
447 uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
448 ASSERT(pcOffset != 0);
449 args.insert(args.begin(), currentDepend);
450 args.insert(args.begin(), currentControl);
451 AppendFrameArgs(args, hirGate);
452 auto callGate = GetCircuit()->NewGate(circuit_->Float32ArrayConstructor(bitfield, pcOffset),
453 MachineType::I64, args.size(), args.data(), GateType::AnyType());
454 currentLabel->SetControl(callGate);
455 currentLabel->SetDepend(callGate);
456 return callGate;
457 }
458
Construct(GateRef hirGate, std::vector<GateRef> args)459 GateRef CircuitBuilder::Construct(GateRef hirGate, std::vector<GateRef> args)
460 {
461 ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE || acc_.GetOpCode(hirGate) == OpCode::REFLECT_CONSTRUCT);
462 auto currentLabel = env_->GetCurrentLabel();
463 auto currentControl = currentLabel->GetControl();
464 auto currentDepend = currentLabel->GetDepend();
465 uint64_t bitfield = args.size();
466 uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
467 args.insert(args.begin(), currentDepend);
468 args.insert(args.begin(), currentControl);
469 AppendFrameArgs(args, hirGate);
470 auto callGate = GetCircuit()->NewGate(circuit_->Construct(bitfield, pcOffset), MachineType::I64,
471 args.size(), args.data(), GateType::AnyType());
472 currentLabel->SetControl(callGate);
473 currentLabel->SetDepend(callGate);
474 return callGate;
475 }
476
CallInternal(GateRef hirGate, std::vector<GateRef> args, uint64_t pcOffset)477 GateRef CircuitBuilder::CallInternal(GateRef hirGate, std::vector<GateRef> args, uint64_t pcOffset)
478 {
479 auto currentLabel = env_->GetCurrentLabel();
480 auto currentControl = currentLabel->GetControl();
481 auto currentDepend = currentLabel->GetDepend();
482 uint64_t bitfield = args.size();
483 ASSERT(pcOffset != 0);
484 args.insert(args.begin(), currentDepend);
485 args.insert(args.begin(), currentControl);
486 AppendFrameArgs(args, hirGate);
487 auto callGate = GetCircuit()->NewGate(
488 circuit_->CallInternal(bitfield, pcOffset), MachineType::I64, args.size(), args.data(), GateType::AnyType());
489 currentLabel->SetControl(callGate);
490 currentLabel->SetDepend(callGate);
491 return callGate;
492 }
493
CallNew(GateRef hirGate, std::vector<GateRef> args, bool needPushArgv)494 GateRef CircuitBuilder::CallNew(GateRef hirGate, std::vector<GateRef> args,
495 bool needPushArgv)
496 {
497 ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE ||
498 acc_.GetOpCode(hirGate) == OpCode::FLOAT32_ARRAY_CONSTRUCTOR);
499 auto currentLabel = env_->GetCurrentLabel();
500 auto currentControl = currentLabel->GetControl();
501 auto currentDepend = currentLabel->GetDepend();
502 uint64_t bitfield = args.size();
503 uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
504 ASSERT(pcOffset != 0);
505 args.insert(args.begin(), currentDepend);
506 args.insert(args.begin(), currentControl);
507 AppendFrameArgs(args, hirGate);
508 auto callGate = GetCircuit()->NewGate(circuit_->CallNew(bitfield, pcOffset, needPushArgv),
509 MachineType::I64, args.size(), args.data(), GateType::AnyType());
510 currentLabel->SetControl(callGate);
511 currentLabel->SetDepend(callGate);
512 return callGate;
513 }
514
CreateArray(ElementsKind kind, uint32_t arraySize, GateRef elementsLength, RegionSpaceFlag flag)515 GateRef CircuitBuilder::CreateArray(ElementsKind kind, uint32_t arraySize,
516 GateRef elementsLength, RegionSpaceFlag flag)
517 {
518 auto currentLabel = env_->GetCurrentLabel();
519 auto currentControl = currentLabel->GetControl();
520 auto currentDepend = currentLabel->GetDepend();
521 ArrayMetaDataAccessor accessor(kind, ArrayMetaDataAccessor::Mode::CREATE, arraySize, flag);
522 GateRef newGate = GetCircuit()->NewGate(circuit_->CreateArray(accessor.ToValue()), MachineType::I64,
523 { currentControl, currentDepend, elementsLength },
524 GateType::TaggedValue());
525 currentLabel->SetControl(newGate);
526 currentLabel->SetDepend(newGate);
527 return newGate;
528 }
529
CreateArrayWithBuffer(ElementsKind kind, ArrayMetaDataAccessor::Mode mode, GateRef cpId, GateRef constPoolIndex, RegionSpaceFlag flag)530 GateRef CircuitBuilder::CreateArrayWithBuffer(ElementsKind kind, ArrayMetaDataAccessor::Mode mode, GateRef cpId,
531 GateRef constPoolIndex, RegionSpaceFlag flag)
532 {
533 auto currentLabel = env_->GetCurrentLabel();
534 auto currentControl = currentLabel->GetControl();
535 auto currentDepend = currentLabel->GetDepend();
536 auto frameState = acc_.FindNearestFrameState(currentDepend);
537 ArrayMetaDataAccessor accessor(kind, mode, 0, flag);
538 GateRef newGate = GetCircuit()->NewGate(circuit_->CreateArrayWithBuffer(accessor.ToValue()),
539 MachineType::I64,
540 { currentControl, currentDepend, cpId, constPoolIndex, frameState },
541 GateType::NJSValue());
542 currentLabel->SetControl(newGate);
543 currentLabel->SetDepend(newGate);
544 return newGate;
545 }
546
CreateArguments(ElementsKind kind, CreateArgumentsAccessor::Mode mode, GateRef restIdx)547 GateRef CircuitBuilder::CreateArguments(ElementsKind kind, CreateArgumentsAccessor::Mode mode, GateRef restIdx)
548 {
549 auto currentLabel = env_->GetCurrentLabel();
550 auto currentControl = currentLabel->GetControl();
551 auto currentDepend = currentLabel->GetDepend();
552 auto frameState = acc_.FindNearestFrameState(currentDepend);
553 CreateArgumentsAccessor accessor(kind, mode);
554 GateRef newGate = GetCircuit()->NewGate(circuit_->CreateArguments(accessor.ToValue()),
555 MachineType::I64,
556 { currentControl, currentDepend, restIdx, frameState },
557 GateType::NJSValue());
558 currentLabel->SetControl(newGate);
559 currentLabel->SetDepend(newGate);
560 return newGate;
561 }
562
SetPropertyInlinedProps(GateRef glue, GateRef obj, GateRef hClass, GateRef value, GateRef attrOffset, VariableType type)563 void CircuitBuilder::SetPropertyInlinedProps(GateRef glue, GateRef obj, GateRef hClass,
564 GateRef value, GateRef attrOffset, VariableType type)
565 {
566 GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET));
567 GateRef inlinedPropsStart = Int32And(Int32LSR(bitfield,
568 Int32(JSHClass::InlinedPropsStartBits::START_BIT)),
569 Int32((1LU << JSHClass::InlinedPropsStartBits::SIZE) - 1));
570 GateRef propOffset = Int32Mul(Int32Add(inlinedPropsStart, attrOffset),
571 Int32(JSTaggedValue::TaggedTypeSize()));
572 Store(type, glue, obj, ZExtInt32ToPtr(propOffset), value);
573 }
574
IsStabelArray(GateRef glue, GateRef obj)575 GateRef CircuitBuilder::IsStabelArray(GateRef glue, GateRef obj)
576 {
577 Label subentry(env_);
578 env_->SubCfgEntry(&subentry);
579 DEFVALUE(result, env_, VariableType::BOOL(), False());
580 Label exit(env_);
581 Label targetIsHeapObject(env_);
582 Label targetIsStableArray(env_);
583
584 BRANCH_CIR2(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
585 Bind(&targetIsHeapObject);
586 {
587 GateRef jsHclass = LoadHClass(obj);
588 BRANCH_CIR2(IsStableArray(jsHclass), &targetIsStableArray, &exit);
589 Bind(&targetIsStableArray);
590 {
591 GateRef guardiansOffset =
592 IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(false));
593 result = Load(VariableType::BOOL(), glue, guardiansOffset);
594 Jump(&exit);
595 }
596 }
597 Bind(&exit);
598 auto res = *result;
599 env_->SubCfgExit();
600 return res;
601 }
602
StoreModuleVar(GateRef jsFunc, GateRef index, GateRef value)603 GateRef CircuitBuilder::StoreModuleVar(GateRef jsFunc, GateRef index, GateRef value)
604 {
605 auto currentLabel = env_->GetCurrentLabel();
606 auto currentControl = currentLabel->GetControl();
607 auto currentDepend = currentLabel->GetDepend();
608 GateRef newGate = GetCircuit()->NewGate(circuit_->StoreModuleVar(), MachineType::I64,
609 { currentControl, currentDepend, jsFunc, index, value }, GateType::TaggedValue());
610 currentLabel->SetControl(newGate);
611 currentLabel->SetDepend(newGate);
612 return newGate;
613 }
614
LdLocalModuleVar(GateRef jsFunc, GateRef index)615 GateRef CircuitBuilder::LdLocalModuleVar(GateRef jsFunc, GateRef index)
616 {
617 auto currentLabel = env_->GetCurrentLabel();
618 auto currentControl = currentLabel->GetControl();
619 auto currentDepend = currentLabel->GetDepend();
620 GateRef newGate = GetCircuit()->NewGate(circuit_->LdLocalModuleVar(), MachineType::I64,
621 { currentControl, currentDepend, jsFunc, index}, GateType::TaggedValue());
622 currentLabel->SetControl(newGate);
623 currentLabel->SetDepend(newGate);
624 return newGate;
625 }
626
BuiltinConstructor(BuiltinsStubCSigns::ID id, GateRef gate)627 GateRef CircuitBuilder::BuiltinConstructor(BuiltinsStubCSigns::ID id, GateRef gate)
628 {
629 auto currentLabel = env_->GetCurrentLabel();
630 auto currentControl = currentLabel->GetControl();
631 auto currentDepend = currentLabel->GetDepend();
632 GateRef newGate = Circuit::NullGate();
633 switch (id) {
634 case BuiltinsStubCSigns::ID::ArrayConstructor: {
635 if (acc_.GetNumValueIn(gate) == 1) {
636 newGate = GetCircuit()->NewGate(circuit_->ArrayConstructor(1), MachineType::I64,
637 { currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
638 GateType::TaggedValue());
639 } else {
640 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: num value in
641 newGate = GetCircuit()->NewGate(circuit_->ArrayConstructor(2), MachineType::I64,
642 { currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
643 GateType::TaggedValue());
644 }
645 break;
646 }
647 case BuiltinsStubCSigns::ID::ObjectConstructor: {
648 if (acc_.GetNumValueIn(gate) == 1) {
649 newGate = GetCircuit()->NewGate(circuit_->ObjectConstructor(1), MachineType::I64,
650 { currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
651 GateType::TaggedValue());
652 } else {
653 ASSERT(acc_.GetNumValueIn(gate) >= 2); // 2: num value in
654 newGate = GetCircuit()->NewGate(circuit_->ObjectConstructor(2), MachineType::I64,
655 { currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
656 GateType::TaggedValue());
657 }
658 break;
659 }
660 case BuiltinsStubCSigns::ID::BooleanConstructor: {
661 if (acc_.GetNumValueIn(gate) == 1) {
662 newGate = GetCircuit()->NewGate(circuit_->BooleanConstructor(1), MachineType::I64,
663 { currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
664 GateType::TaggedValue());
665 } else {
666 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: num value in
667 newGate = GetCircuit()->NewGate(circuit_->BooleanConstructor(2), MachineType::I64,
668 { currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
669 GateType::TaggedValue());
670 }
671 break;
672 }
673 case BuiltinsStubCSigns::ID::Float32ArrayConstructor: {
674 if (acc_.GetNumValueIn(gate) == 1) {
675 newGate = Float32ArrayConstructor(gate, { acc_.GetValueIn(gate, 0)});
676 } else {
677 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: num value in
678 newGate = Float32ArrayConstructor(gate, { acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
679 }
680 break;
681 }
682 default:
683 LOG_ECMA(FATAL) << "this branch is unreachable";
684 UNREACHABLE();
685 break;
686 }
687 currentLabel->SetControl(newGate);
688 currentLabel->SetDepend(newGate);
689 return newGate;
690 }
691
SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible)692 void CircuitBuilder::SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible)
693 {
694 GateRef jsHclass = LoadHClass(obj);
695 GateRef bitfield = Load(VariableType::INT32(), jsHclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
696 GateRef boolVal = Boolean(isExtensible);
697 GateRef boolToInt32 = ZExtInt1ToInt32(boolVal);
698 GateRef encodeValue = Int32LSL(boolToInt32, Int32(JSHClass::ExtensibleBit::START_BIT));
699 GateRef mask = Int32(((1LU << JSHClass::ExtensibleBit::SIZE) - 1) << JSHClass::ExtensibleBit::START_BIT);
700 bitfield = Int32Or(Int32And(bitfield, Int32Not(mask)), encodeValue);
701 Store(VariableType::INT32(), glue, jsHclass, IntPtr(JSHClass::BIT_FIELD_OFFSET), bitfield);
702 }
703
OrdinaryHasInstance(GateRef obj, GateRef target)704 GateRef CircuitBuilder::OrdinaryHasInstance(GateRef obj, GateRef target)
705 {
706 auto currentLabel = env_->GetCurrentLabel();
707 auto currentControl = currentLabel->GetControl();
708 auto currentDepend = currentLabel->GetDepend();
709 GateRef frameState = acc_.FindNearestFrameState(currentDepend);
710 auto ret = GetCircuit()->NewGate(circuit_->OrdinaryHasInstance(),
711 MachineType::I64,
712 {currentControl, currentDepend, obj, target, frameState},
713 GateType::TaggedNPointer());
714 acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret);
715 currentLabel->SetControl(ret);
716 currentLabel->SetDepend(ret);
717 return ret;
718 }
719
MigrateArrayWithKind(GateRef receiver, GateRef oldElementsKind, GateRef newElementsKind)720 GateRef CircuitBuilder::MigrateArrayWithKind(GateRef receiver, GateRef oldElementsKind,
721 GateRef newElementsKind)
722 {
723 auto currentLabel = env_->GetCurrentLabel();
724 auto currentControl = currentLabel->GetControl();
725 auto currentDepend = currentLabel->GetDepend();
726 GateRef newGate = GetCircuit()->NewGate(circuit_->MigrateArrayWithKind(), MachineType::I64,
727 { currentControl, currentDepend, receiver, oldElementsKind,
728 newElementsKind },
729 GateType::TaggedValue());
730 currentLabel->SetControl(newGate);
731 currentLabel->SetDepend(newGate);
732 return newGate;
733 }
734
IsLiteralString(GateRef string)735 GateRef CircuitBuilder::IsLiteralString(GateRef string)
736 {
737 GateRef objectType = GetObjectType(LoadHClass(string));
738 return BitOr(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::LINE_STRING))),
739 Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::CONSTANT_STRING))));
740 }
741
742 // left and right both utf-8 or utf-16 and both linestring or constantstring can be concat.
CanBeConcat(GateRef leftString, GateRef rightString, GateRef isValidOpt)743 GateRef CircuitBuilder::CanBeConcat(GateRef leftString, GateRef rightString, GateRef isValidOpt)
744 {
745 return LogicAndBuilder(env_).And(isValidOpt).And(IsLiteralString(leftString))
746 .And(IsLiteralString(rightString)).Done();
747 }
748
749 // left and right both utf-8 or utf-16 and right is linestring or constantstring can back store.
CanBackStore(GateRef rightString, GateRef isValidOpt)750 GateRef CircuitBuilder::CanBackStore(GateRef rightString, GateRef isValidOpt)
751 {
752 return LogicAndBuilder(env_).And(isValidOpt).And(IsLiteralString(rightString)).Done();
753 }
754
NumberToString(GateRef number)755 GateRef CircuitBuilder::NumberToString(GateRef number)
756 {
757 auto currentLabel = env_->GetCurrentLabel();
758 auto currentControl = currentLabel->GetControl();
759 auto currentDepend = currentLabel->GetDepend();
760 GateRef newGate = GetCircuit()->NewGate(circuit_->NumberToString(), MachineType::I64,
761 { currentControl, currentDepend, number }, GateType::StringType());
762 currentLabel->SetControl(newGate);
763 currentLabel->SetDepend(newGate);
764 return newGate;
765 }
766 }
767