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