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