• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)515 GateRef CircuitBuilder::CreateArray(ElementsKind kind, uint32_t arraySize, GateRef elementsLength)
516 {
517     auto currentLabel = env_->GetCurrentLabel();
518     auto currentControl = currentLabel->GetControl();
519     auto currentDepend = currentLabel->GetDepend();
520     ArrayMetaDataAccessor accessor(kind, ArrayMetaDataAccessor::Mode::CREATE, arraySize);
521     GateRef newGate = GetCircuit()->NewGate(circuit_->CreateArray(accessor.ToValue()), MachineType::I64,
522                                             { currentControl, currentDepend, elementsLength },
523                                             GateType::TaggedValue());
524     currentLabel->SetControl(newGate);
525     currentLabel->SetDepend(newGate);
526     return newGate;
527 }
528 
CreateArrayWithBuffer(ElementsKind kind,ArrayMetaDataAccessor::Mode mode,GateRef cpId,GateRef constPoolIndex)529 GateRef CircuitBuilder::CreateArrayWithBuffer(ElementsKind kind, ArrayMetaDataAccessor::Mode mode, GateRef cpId,
530                                               GateRef constPoolIndex)
531 {
532     auto currentLabel = env_->GetCurrentLabel();
533     auto currentControl = currentLabel->GetControl();
534     auto currentDepend = currentLabel->GetDepend();
535     auto frameState = acc_.FindNearestFrameState(currentDepend);
536     ArrayMetaDataAccessor accessor(kind, mode);
537     GateRef newGate = GetCircuit()->NewGate(circuit_->CreateArrayWithBuffer(accessor.ToValue()),
538                                             MachineType::I64,
539                                             { currentControl, currentDepend, cpId, constPoolIndex, frameState },
540                                             GateType::NJSValue());
541     currentLabel->SetControl(newGate);
542     currentLabel->SetDepend(newGate);
543     return newGate;
544 }
545 
CreateArguments(ElementsKind kind,CreateArgumentsAccessor::Mode mode,GateRef restIdx)546 GateRef CircuitBuilder::CreateArguments(ElementsKind kind, CreateArgumentsAccessor::Mode mode, GateRef restIdx)
547 {
548     auto currentLabel = env_->GetCurrentLabel();
549     auto currentControl = currentLabel->GetControl();
550     auto currentDepend = currentLabel->GetDepend();
551     auto frameState = acc_.FindNearestFrameState(currentDepend);
552     CreateArgumentsAccessor accessor(kind, mode);
553     GateRef newGate = GetCircuit()->NewGate(circuit_->CreateArguments(accessor.ToValue()),
554                                             MachineType::I64,
555                                             { currentControl, currentDepend, restIdx, frameState },
556                                             GateType::NJSValue());
557     currentLabel->SetControl(newGate);
558     currentLabel->SetDepend(newGate);
559     return newGate;
560 }
561 
SetPropertyInlinedProps(GateRef glue,GateRef obj,GateRef hClass,GateRef value,GateRef attrOffset,VariableType type)562 void CircuitBuilder::SetPropertyInlinedProps(GateRef glue, GateRef obj, GateRef hClass,
563     GateRef value, GateRef attrOffset, VariableType type)
564 {
565     GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET));
566     GateRef inlinedPropsStart = Int32And(Int32LSR(bitfield,
567         Int32(JSHClass::InlinedPropsStartBits::START_BIT)),
568         Int32((1LU << JSHClass::InlinedPropsStartBits::SIZE) - 1));
569     GateRef propOffset = Int32Mul(Int32Add(inlinedPropsStart, attrOffset),
570         Int32(JSTaggedValue::TaggedTypeSize()));
571     Store(type, glue, obj, ZExtInt32ToPtr(propOffset), value);
572 }
573 
IsStabelArray(GateRef glue,GateRef obj)574 GateRef CircuitBuilder::IsStabelArray(GateRef glue, GateRef obj)
575 {
576     Label subentry(env_);
577     env_->SubCfgEntry(&subentry);
578     DEFVALUE(result, env_, VariableType::BOOL(), False());
579     Label exit(env_);
580     Label targetIsHeapObject(env_);
581     Label targetIsStableArray(env_);
582 
583     BRANCH_CIR2(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
584     Bind(&targetIsHeapObject);
585     {
586         GateRef jsHclass = LoadHClass(obj);
587         BRANCH_CIR2(IsStableArray(jsHclass), &targetIsStableArray, &exit);
588         Bind(&targetIsStableArray);
589         {
590             GateRef guardiansOffset =
591                 IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(false));
592             result = Load(VariableType::BOOL(), glue, guardiansOffset);
593             Jump(&exit);
594         }
595     }
596     Bind(&exit);
597     auto res = *result;
598     env_->SubCfgExit();
599     return res;
600 }
601 
StoreModuleVar(GateRef jsFunc,GateRef index,GateRef value)602 GateRef CircuitBuilder::StoreModuleVar(GateRef jsFunc, GateRef index, GateRef value)
603 {
604     auto currentLabel = env_->GetCurrentLabel();
605     auto currentControl = currentLabel->GetControl();
606     auto currentDepend = currentLabel->GetDepend();
607     GateRef newGate = GetCircuit()->NewGate(circuit_->StoreModuleVar(), MachineType::I64,
608         { currentControl, currentDepend, jsFunc, index, value }, GateType::TaggedValue());
609     currentLabel->SetControl(newGate);
610     currentLabel->SetDepend(newGate);
611     return newGate;
612 }
613 
LdLocalModuleVar(GateRef jsFunc,GateRef index)614 GateRef CircuitBuilder::LdLocalModuleVar(GateRef jsFunc, GateRef index)
615 {
616     auto currentLabel = env_->GetCurrentLabel();
617     auto currentControl = currentLabel->GetControl();
618     auto currentDepend = currentLabel->GetDepend();
619     GateRef newGate = GetCircuit()->NewGate(circuit_->LdLocalModuleVar(), MachineType::I64,
620                                             { currentControl, currentDepend, jsFunc, index}, GateType::TaggedValue());
621     currentLabel->SetControl(newGate);
622     currentLabel->SetDepend(newGate);
623     return newGate;
624 }
625 
BuiltinConstructor(BuiltinsStubCSigns::ID id,GateRef gate)626 GateRef CircuitBuilder::BuiltinConstructor(BuiltinsStubCSigns::ID id, GateRef gate)
627 {
628     auto currentLabel = env_->GetCurrentLabel();
629     auto currentControl = currentLabel->GetControl();
630     auto currentDepend = currentLabel->GetDepend();
631     GateRef newGate = Circuit::NullGate();
632     switch (id) {
633         case BuiltinsStubCSigns::ID::ArrayConstructor: {
634             if (acc_.GetNumValueIn(gate) == 1) {
635                 newGate = GetCircuit()->NewGate(circuit_->ArrayConstructor(1), MachineType::I64,
636                                                 { currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
637                                                 GateType::TaggedValue());
638             } else {
639                 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: num value in
640                 newGate = GetCircuit()->NewGate(circuit_->ArrayConstructor(2), MachineType::I64,
641                     { currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
642                     GateType::TaggedValue());
643             }
644             break;
645         }
646         case BuiltinsStubCSigns::ID::ObjectConstructor: {
647             if (acc_.GetNumValueIn(gate) == 1) {
648                 newGate = GetCircuit()->NewGate(circuit_->ObjectConstructor(1), MachineType::I64,
649                                                 { currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
650                                                 GateType::TaggedValue());
651             } else {
652                 ASSERT(acc_.GetNumValueIn(gate) >= 2); // 2: num value in
653                 newGate = GetCircuit()->NewGate(circuit_->ObjectConstructor(2), MachineType::I64,
654                     { currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
655                     GateType::TaggedValue());
656             }
657             break;
658         }
659         case BuiltinsStubCSigns::ID::BooleanConstructor: {
660             if (acc_.GetNumValueIn(gate) == 1) {
661                 newGate = GetCircuit()->NewGate(circuit_->BooleanConstructor(1), MachineType::I64,
662                                                 { currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
663                                                 GateType::TaggedValue());
664             } else {
665                 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: num value in
666                 newGate = GetCircuit()->NewGate(circuit_->BooleanConstructor(2), MachineType::I64,
667                     { currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
668                     GateType::TaggedValue());
669             }
670             break;
671         }
672         case BuiltinsStubCSigns::ID::Float32ArrayConstructor: {
673             if (acc_.GetNumValueIn(gate) == 1) {
674                 newGate = Float32ArrayConstructor(gate, { acc_.GetValueIn(gate, 0)});
675             } else {
676                 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: num value in
677                 newGate = Float32ArrayConstructor(gate, { acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
678             }
679             break;
680         }
681         default:
682             LOG_ECMA(FATAL) << "this branch is unreachable";
683             UNREACHABLE();
684             break;
685     }
686     currentLabel->SetControl(newGate);
687     currentLabel->SetDepend(newGate);
688     return newGate;
689 }
690 
SetExtensibleToBitfield(GateRef glue,GateRef obj,bool isExtensible)691 void CircuitBuilder::SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible)
692 {
693     GateRef jsHclass = LoadHClass(obj);
694     GateRef bitfield = Load(VariableType::INT32(), jsHclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
695     GateRef boolVal = Boolean(isExtensible);
696     GateRef boolToInt32 = ZExtInt1ToInt32(boolVal);
697     GateRef encodeValue = Int32LSL(boolToInt32, Int32(JSHClass::ExtensibleBit::START_BIT));
698     GateRef mask = Int32(((1LU << JSHClass::ExtensibleBit::SIZE) - 1) << JSHClass::ExtensibleBit::START_BIT);
699     bitfield = Int32Or(Int32And(bitfield, Int32Not(mask)), encodeValue);
700     Store(VariableType::INT32(), glue, jsHclass, IntPtr(JSHClass::BIT_FIELD_OFFSET), bitfield);
701 }
702 
OrdinaryHasInstance(GateRef obj,GateRef target)703 GateRef CircuitBuilder::OrdinaryHasInstance(GateRef obj, GateRef target)
704 {
705     auto currentLabel = env_->GetCurrentLabel();
706     auto currentControl = currentLabel->GetControl();
707     auto currentDepend = currentLabel->GetDepend();
708     GateRef frameState = acc_.FindNearestFrameState(currentDepend);
709     auto ret = GetCircuit()->NewGate(circuit_->OrdinaryHasInstance(),
710                                      MachineType::I64,
711                                      {currentControl, currentDepend, obj, target, frameState},
712                                      GateType::TaggedNPointer());
713     acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret);
714     currentLabel->SetControl(ret);
715     currentLabel->SetDepend(ret);
716     return ret;
717 }
718 
MigrateArrayWithKind(GateRef receiver,GateRef oldElementsKind,GateRef newElementsKind)719 GateRef CircuitBuilder::MigrateArrayWithKind(GateRef receiver, GateRef oldElementsKind,
720                                              GateRef newElementsKind)
721 {
722     auto currentLabel = env_->GetCurrentLabel();
723     auto currentControl = currentLabel->GetControl();
724     auto currentDepend = currentLabel->GetDepend();
725     GateRef newGate = GetCircuit()->NewGate(circuit_->MigrateArrayWithKind(), MachineType::I64,
726                                             { currentControl, currentDepend, receiver, oldElementsKind,
727                                               newElementsKind },
728                                             GateType::TaggedValue());
729     currentLabel->SetControl(newGate);
730     currentLabel->SetDepend(newGate);
731     return newGate;
732 }
733 
IsLiteralString(GateRef string)734 GateRef CircuitBuilder::IsLiteralString(GateRef string)
735 {
736     GateRef objectType = GetObjectType(LoadHClass(string));
737     return BitOr(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::LINE_STRING))),
738                  Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::CONSTANT_STRING))));
739 }
740 
741 // left and right both utf-8 or utf-16 and both linestring or constantstring can be concat.
CanBeConcat(GateRef leftString,GateRef rightString,GateRef isValidOpt)742 GateRef CircuitBuilder::CanBeConcat(GateRef leftString, GateRef rightString, GateRef isValidOpt)
743 {
744     return LogicAndBuilder(env_).And(isValidOpt).And(IsLiteralString(leftString))
745         .And(IsLiteralString(rightString)).Done();
746 }
747 
748 // left and right both utf-8 or utf-16 and right is linestring or constantstring can back store.
CanBackStore(GateRef rightString,GateRef isValidOpt)749 GateRef CircuitBuilder::CanBackStore(GateRef rightString, GateRef isValidOpt)
750 {
751     return LogicAndBuilder(env_).And(isValidOpt).And(IsLiteralString(rightString)).Done();
752 }
753 
NumberToString(GateRef number)754 GateRef CircuitBuilder::NumberToString(GateRef number)
755 {
756     auto currentLabel = env_->GetCurrentLabel();
757     auto currentControl = currentLabel->GetControl();
758     auto currentDepend = currentLabel->GetDepend();
759     GateRef newGate = GetCircuit()->NewGate(circuit_->NumberToString(), MachineType::I64,
760                                             { currentControl, currentDepend, number }, GateType::StringType());
761     currentLabel->SetControl(newGate);
762     currentLabel->SetDepend(newGate);
763     return newGate;
764 }
765 }
766