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