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