1 /*
2 * Copyright (c) 2021-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/slowpath_lowering.h"
17
18 #include "ecmascript/compiler/call_stub_builder.h"
19 #include "ecmascript/compiler/circuit_builder.h"
20 #include "ecmascript/compiler/gate.h"
21 #include "ecmascript/compiler/share_gate_meta_data.h"
22 #include "ecmascript/compiler/variable_type.h"
23 #include "ecmascript/dfx/vm_thread_control.h"
24 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
25 #include "ecmascript/js_async_generator_object.h"
26 #include "ecmascript/js_runtime_options.h"
27 #include "ecmascript/jit/jit.h"
28 #include "ecmascript/js_thread.h"
29 #include "ecmascript/lexical_env.h"
30 #include "thread/mutator_base.h"
31 #include <cstdint>
32
33 namespace panda::ecmascript::kungfu {
34 using UseIterator = GateAccessor::UseIterator;
35
36 #define CREATE_DOUBLE_EXIT(SuccessLabel, FailLabel) \
37 StateDepend successControl; \
38 StateDepend failControl; \
39 builder_.Bind(&SuccessLabel); \
40 { \
41 successControl.SetState(builder_.GetState()); \
42 successControl.SetDepend(builder_.GetDepend()); \
43 } \
44 builder_.Bind(&FailLabel); \
45 { \
46 failControl.SetState(builder_.GetState()); \
47 failControl.SetDepend(builder_.GetDepend()); \
48 }
49
CallRuntimeLowering()50 void SlowPathLowering::CallRuntimeLowering()
51 {
52 std::vector<GateRef> gateList;
53 circuit_->GetAllGates(gateList);
54 GateRef globalEnvCache = Circuit::NullGate();
55 for (const auto &gate : gateList) {
56 auto op = acc_.GetOpCode(gate);
57 [[maybe_unused]] auto scopedGate = circuit_->VisitGateBegin(gate);
58 switch (op) {
59 case OpCode::JS_BYTECODE:
60 Lower(gate);
61 break;
62 case OpCode::GET_EXCEPTION: {
63 // initialize label manager
64 Environment env(gate, circuit_, &builder_);
65 LowerExceptionHandler(gate);
66 break;
67 }
68 case OpCode::CONSTRUCT:
69 LowerConstruct(gate);
70 break;
71 case OpCode::CALLINTERNAL:
72 LowerCallInternal(gate);
73 break;
74 case OpCode::CALL_NEW:
75 LowerCallNew(gate);
76 break;
77 case OpCode::CALL_NEW_BUILTIN:
78 LowerCallNewBuiltin(gate);
79 break;
80 case OpCode::TYPEDCALL:
81 LowerTypedCall(gate);
82 break;
83 case OpCode::TYPEDFASTCALL:
84 LowerTypedFastCall(gate);
85 break;
86 case OpCode::CHECK_SAFEPOINT_AND_STACKOVER:
87 LowerCheckSafePointAndStackOver(gate);
88 break;
89 case OpCode::GET_ENV:
90 LowerGetEnv(gate);
91 break;
92 case OpCode::LOOP_EXIT:
93 DeleteLoopExit(gate);
94 break;
95 case OpCode::LOOP_EXIT_VALUE:
96 DeleteLoopExitValue(gate);
97 break;
98 case OpCode::GET_UNSHARED_CONSTPOOL:
99 unsharedCP_.emplace_back(gate);
100 break;
101 case OpCode::GET_GLOBAL_ENV_BY_FUNC:
102 case OpCode::GET_GLOBAL_ENV_BY_LEXICAL_ENV:
103 globalEnvCache = gate;
104 break;
105 default:
106 break;
107 }
108 }
109
110 // Make sure all IRs are lowered before lowering the constpool. If constpool is not used in CIR, it will be replaced
111 // by undefined.
112 for (const auto &gate : unsharedCP_) {
113 GateRef sharedConstPool = acc_.GetValueIn(gate, 0);
114 ASSERT(acc_.GetOpCode(sharedConstPool) == OpCode::GET_SHARED_CONSTPOOL);
115 LowerGetUnsharedConstPool(gate);
116 LowerGetSharedConstPool(sharedConstPool);
117 }
118
119 // Make sure GetGlobalEnvByFunc must be lowered after js bytecode slowpath, because now it's only have one cache in
120 // circuit, but it may be used in js bytecode slowpath.
121 if (!TryLowerGetGlobalEnvCache(globalEnvCache)) {
122 acc_.ReplaceGate(globalEnvCache, Circuit::NullGate());
123 }
124
125 if (IsLogEnabled()) {
126 LOG_COMPILER(INFO) << " ";
127 LOG_COMPILER(INFO) << "\033[34m" << "================="
128 << " After slowpath Lowering "
129 << "[" << GetMethodName() << "] "
130 << "=================" << "\033[0m";
131 circuit_->PrintAllGatesWithBytecode();
132 LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
133 }
134 }
135
LowerGetEnv(GateRef gate)136 void SlowPathLowering::LowerGetEnv(GateRef gate)
137 {
138 GateRef jsFunc = acc_.GetValueIn(gate, 0);
139 GateRef envOffset = builder_.IntPtr(JSFunction::LEXICAL_ENV_OFFSET);
140 GateRef env = builder_.Load(VariableType::JS_ANY(), glue_, jsFunc, envOffset, acc_.GetDep(gate));
141 acc_.UpdateAllUses(gate, env);
142 acc_.DeleteGate(gate);
143 }
144
TryLowerGetGlobalEnvCache(GateRef gate)145 bool SlowPathLowering::TryLowerGetGlobalEnvCache(GateRef gate)
146 {
147 if (gate == Circuit::NullGate()) {
148 LOG_COMPILER(FATAL) << "global env cache gate is null";
149 UNREACHABLE();
150 return false;
151 }
152 bool useGlobalEnv = false;
153 auto uses = acc_.Uses(gate);
154 for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
155 if (acc_.IsValueIn(useIt)) {
156 useGlobalEnv = true;
157 break;
158 }
159 }
160 if (!useGlobalEnv) {
161 return false;
162 }
163 GateRef globalEnv = Circuit::NullGate();
164 if (acc_.GetOpCode(gate) == OpCode::GET_GLOBAL_ENV_BY_LEXICAL_ENV) {
165 GateRef lexicalEnv = acc_.GetValueIn(gate, 0);
166 GateRef globalEnvOffset = builder_.IntPtr(GlobalEnv::HEADER_SIZE);
167 globalEnv = builder_.Load(VariableType::JS_ANY(), glue_, lexicalEnv, globalEnvOffset, lexicalEnv);
168 } else if (acc_.GetOpCode(gate) == OpCode::GET_GLOBAL_ENV_BY_FUNC) {
169 GateRef jsFunc = acc_.GetValueIn(gate, 0);
170 GateRef envOffset = builder_.IntPtr(JSFunction::LEXICAL_ENV_OFFSET);
171 GateRef lexicalEnv = builder_.Load(VariableType::JS_ANY(), glue_, jsFunc, envOffset, acc_.GetDep(gate));
172 GateRef globalEnvOffset = builder_.IntPtr(GlobalEnv::HEADER_SIZE);
173 globalEnv = builder_.Load(VariableType::JS_ANY(), glue_, lexicalEnv, globalEnvOffset, lexicalEnv);
174 } else {
175 LOG_COMPILER(FATAL) << "Unexpected gate opcode for GetGlobalEnvCache: " << acc_.GetOpCode(gate);
176 UNREACHABLE();
177 return false;
178 }
179 acc_.UpdateAllUses(gate, globalEnv);
180 acc_.DeleteGate(gate);
181 return true;
182 }
183
DeleteLoopExit(GateRef gate)184 void SlowPathLowering::DeleteLoopExit(GateRef gate)
185 {
186 auto state = acc_.GetState(gate);
187 acc_.ReplaceGate(gate, state, Circuit::NullGate(), Circuit::NullGate());
188 }
189
DeleteLoopExitValue(GateRef gate)190 void SlowPathLowering::DeleteLoopExitValue(GateRef gate)
191 {
192 auto state = acc_.GetState(gate);
193 auto value = acc_.GetValueIn(gate, 0);
194 acc_.ReplaceGate(gate, state, Circuit::NullGate(), value);
195 }
196
LowerToJSCall(GateRef hirGate,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)197 void SlowPathLowering::LowerToJSCall(GateRef hirGate, const std::vector<GateRef> &args,
198 const std::vector<GateRef> &argsFastCall)
199 {
200 Label exit(&builder_);
201 DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
202 GateRef func = args[static_cast<size_t>(CommonArgIdx::FUNC)];
203 GateRef argc = args[static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC)];
204 CallCoStubBuilder::LowerFastCall(hirGate, glue_, builder_, func, argc, args, argsFastCall, &res, &exit, false,
205 g_isEnableCMCGC);
206 builder_.Bind(&exit);
207 GateRef stateInGate = builder_.GetState();
208 GateRef depend = builder_.GetDepend();
209 ReplaceHirWithPendingException(hirGate, stateInGate, depend, *res);
210 }
211
ReplaceHirWithPendingException(GateRef hirGate,GateRef state,GateRef depend,GateRef value)212 void SlowPathLowering::ReplaceHirWithPendingException(GateRef hirGate,
213 GateRef state, GateRef depend, GateRef value)
214 {
215 auto condition = builder_.HasPendingException(glue_, compilationEnv_);
216 GateRef ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
217 GateRef ifTrue = builder_.IfTrue(ifBranch);
218 GateRef ifFalse = builder_.IfFalse(ifBranch);
219 GateRef eDepend = builder_.DependRelay(ifTrue, depend);
220 GateRef sDepend = builder_.DependRelay(ifFalse, depend);
221
222 StateDepend success(ifFalse, sDepend);
223 StateDepend exception(ifTrue, eDepend);
224 acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
225 }
226
227 /*
228 * lower to slowpath call like this pattern:
229 * have throw:
230 * res = Call(...);
231 * if (res == VALUE_EXCEPTION) {
232 * goto exception_handle;
233 * }
234 * Set(res);
235 *
236 * no throw:
237 * res = Call(...);
238 * Set(res);
239 */
ReplaceHirWithValue(GateRef hirGate,GateRef value)240 void SlowPathLowering::ReplaceHirWithValue(GateRef hirGate, GateRef value)
241 {
242 auto opcode = acc_.GetByteCodeOpcode(hirGate);
243 if (!BytecodeMetaData::IsBytecodeNoThrow(opcode)) {
244 GateRef state = builder_.GetState();
245 // copy depend-wire of hirGate to value
246 GateRef depend = builder_.GetDepend();
247 // exception value
248 GateRef exceptionVal = builder_.ExceptionConstant();
249 // compare with trampolines result
250 GateRef equal = builder_.Equal(value, exceptionVal);
251 auto ifBranch = builder_.Branch(state, equal, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
252
253 GateRef ifTrue = builder_.IfTrue(ifBranch);
254 GateRef ifFalse = builder_.IfFalse(ifBranch);
255 GateRef eDepend = builder_.DependRelay(ifTrue, depend);
256 GateRef sDepend = builder_.DependRelay(ifFalse, depend);
257 StateDepend success(ifFalse, sDepend);
258 StateDepend exception(ifTrue, eDepend);
259 acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
260 } else {
261 acc_.ReplaceHirDirectly(hirGate, builder_.GetStateDepend(), value);
262 }
263 }
264
265 /*
266 * lower to throw call like this pattern:
267 * Call(...);
268 * goto exception_handle;
269 *
270 */
ReplaceHirToThrowCall(GateRef hirGate,GateRef value)271 void SlowPathLowering::ReplaceHirToThrowCall(GateRef hirGate, GateRef value)
272 {
273 auto condition = builder_.HasPendingException(glue_, compilationEnv_);
274 GateRef state = builder_.GetState();
275 GateRef depend = builder_.GetDepend();
276 GateRef ifBranch = builder_.Branch(state, condition, BranchWeight::DEOPT_WEIGHT, 1, "checkException");
277 GateRef ifTrue = builder_.IfTrue(ifBranch);
278 GateRef ifFalse = builder_.IfFalse(ifBranch);
279 GateRef eDepend = builder_.DependRelay(ifTrue, depend);
280 GateRef sDepend = builder_.DependRelay(ifFalse, depend);
281
282 StateDepend success(ifFalse, sDepend);
283 StateDepend exception(ifTrue, eDepend);
284 acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
285 }
286
Lower(GateRef gate)287 void SlowPathLowering::Lower(GateRef gate)
288 {
289 Jit::JitLockHolder lock(compilationEnv_, "SlowPathLowering::Lower");
290 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
291 // initialize label manager
292 Environment env(gate, circuit_, &builder_);
293 AddProfiling(gate);
294 switch (ecmaOpcode) {
295 case EcmaOpcode::CALLARG0_IMM8:
296 LowerCallArg0Stub(gate);
297 break;
298 case EcmaOpcode::CALLARG1_IMM8_V8:
299 LowerCallArg1Stub(gate);
300 break;
301 case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
302 LowerCallArg2Stub(gate);
303 break;
304 case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
305 LowerCallArg3Stub(gate);
306 break;
307 case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8:
308 // same as callthis0
309 LowerCallThis0Stub(gate);
310 break;
311 case EcmaOpcode::CALLTHIS0_IMM8_V8:
312 LowerCallThis0Stub(gate);
313 break;
314 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
315 LowerCallThis1Stub(gate);
316 break;
317 case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
318 LowerCallThis2Stub(gate);
319 break;
320 case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
321 LowerCallThis3Stub(gate);
322 break;
323 case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
324 LowerWideCallrangePrefImm16V8(gate);
325 break;
326 case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
327 LowerCallthisrangeImm8Imm8V8(gate);
328 break;
329 case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
330 LowerWideCallthisrangePrefImm16V8(gate);
331 break;
332 case EcmaOpcode::APPLY_IMM8_V8_V8:
333 LowerCallSpread(gate);
334 break;
335 case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
336 LowerCallrangeImm8Imm8V8(gate);
337 break;
338 case EcmaOpcode::GETUNMAPPEDARGS:
339 LowerGetUnmappedArgs(gate);
340 break;
341 case EcmaOpcode::ASYNCFUNCTIONENTER:
342 LowerAsyncFunctionEnter(gate);
343 break;
344 case EcmaOpcode::INC_IMM8:
345 LowerInc(gate);
346 break;
347 case EcmaOpcode::DEC_IMM8:
348 LowerDec(gate);
349 break;
350 case EcmaOpcode::GETPROPITERATOR:
351 LowerGetPropIterator(gate);
352 break;
353 case EcmaOpcode::RESUMEGENERATOR:
354 LowerResumeGenerator(gate);
355 break;
356 case EcmaOpcode::GETRESUMEMODE:
357 LowerGetResumeMode(gate);
358 break;
359 case EcmaOpcode::CLOSEITERATOR_IMM8_V8:
360 case EcmaOpcode::CLOSEITERATOR_IMM16_V8:
361 LowerCloseIterator(gate);
362 break;
363 case EcmaOpcode::ADD2_IMM8_V8:
364 LowerAdd2(gate);
365 break;
366 case EcmaOpcode::SUB2_IMM8_V8:
367 LowerSub2(gate);
368 break;
369 case EcmaOpcode::MUL2_IMM8_V8:
370 LowerMul2(gate);
371 break;
372 case EcmaOpcode::DIV2_IMM8_V8:
373 LowerDiv2(gate);
374 break;
375 case EcmaOpcode::MOD2_IMM8_V8:
376 LowerMod2(gate);
377 break;
378 case EcmaOpcode::EQ_IMM8_V8:
379 LowerEq(gate);
380 break;
381 case EcmaOpcode::NOTEQ_IMM8_V8:
382 LowerNotEq(gate);
383 break;
384 case EcmaOpcode::LESS_IMM8_V8:
385 LowerLess(gate);
386 break;
387 case EcmaOpcode::LESSEQ_IMM8_V8:
388 LowerLessEq(gate);
389 break;
390 case EcmaOpcode::GREATER_IMM8_V8:
391 LowerGreater(gate);
392 break;
393 case EcmaOpcode::GREATEREQ_IMM8_V8:
394 LowerGreaterEq(gate);
395 break;
396 case EcmaOpcode::CREATEITERRESULTOBJ_V8_V8:
397 LowerCreateIterResultObj(gate);
398 break;
399 case EcmaOpcode::SUSPENDGENERATOR_V8:
400 LowerSuspendGenerator(gate);
401 break;
402 case EcmaOpcode::ASYNCFUNCTIONAWAITUNCAUGHT_V8:
403 LowerAsyncFunctionAwaitUncaught(gate);
404 break;
405 case EcmaOpcode::ASYNCFUNCTIONRESOLVE_V8:
406 LowerAsyncFunctionResolve(gate);
407 break;
408 case EcmaOpcode::ASYNCFUNCTIONREJECT_V8:
409 LowerAsyncFunctionReject(gate);
410 break;
411 case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16:
412 case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16:
413 LowerTryLdGlobalByName(gate);
414 break;
415 case EcmaOpcode::STGLOBALVAR_IMM16_ID16:
416 LowerStGlobalVar(gate);
417 break;
418 case EcmaOpcode::GETITERATOR_IMM8:
419 case EcmaOpcode::GETITERATOR_IMM16:
420 LowerGetIterator(gate);
421 break;
422 case EcmaOpcode::GETASYNCITERATOR_IMM8:
423 LowerGetAsyncIterator(gate);
424 break;
425 case EcmaOpcode::NEWOBJAPPLY_IMM8_V8:
426 case EcmaOpcode::NEWOBJAPPLY_IMM16_V8:
427 LowerNewObjApply(gate);
428 break;
429 case EcmaOpcode::THROW_PREF_NONE:
430 LowerThrow(gate);
431 break;
432 case EcmaOpcode::TYPEOF_IMM8:
433 case EcmaOpcode::TYPEOF_IMM16:
434 LowerTypeof(gate);
435 break;
436 case EcmaOpcode::THROW_CONSTASSIGNMENT_PREF_V8:
437 LowerThrowConstAssignment(gate);
438 break;
439 case EcmaOpcode::THROW_NOTEXISTS_PREF_NONE:
440 LowerThrowThrowNotExists(gate);
441 break;
442 case EcmaOpcode::THROW_PATTERNNONCOERCIBLE_PREF_NONE:
443 LowerThrowPatternNonCoercible(gate);
444 break;
445 case EcmaOpcode::THROW_IFNOTOBJECT_PREF_V8:
446 LowerThrowIfNotObject(gate);
447 break;
448 case EcmaOpcode::THROW_UNDEFINEDIFHOLE_PREF_V8_V8:
449 LowerThrowUndefinedIfHole(gate);
450 break;
451 case EcmaOpcode::THROW_UNDEFINEDIFHOLEWITHNAME_PREF_ID16:
452 LowerThrowUndefinedIfHoleWithName(gate);
453 break;
454 case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM8:
455 case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM16:
456 LowerThrowIfSuperNotCorrectCall(gate);
457 break;
458 case EcmaOpcode::THROW_DELETESUPERPROPERTY_PREF_NONE:
459 LowerThrowDeleteSuperProperty(gate);
460 break;
461 case EcmaOpcode::LDSYMBOL:
462 LowerLdSymbol(gate);
463 break;
464 case EcmaOpcode::LDGLOBAL:
465 LowerLdGlobal(gate);
466 break;
467 case EcmaOpcode::TONUMBER_IMM8:
468 LowerToNumber(gate);
469 break;
470 case EcmaOpcode::NEG_IMM8:
471 LowerNeg(gate);
472 break;
473 case EcmaOpcode::NOT_IMM8:
474 LowerNot(gate);
475 break;
476 case EcmaOpcode::SHL2_IMM8_V8:
477 LowerShl2(gate);
478 break;
479 case EcmaOpcode::SHR2_IMM8_V8:
480 LowerShr2(gate);
481 break;
482 case EcmaOpcode::ASHR2_IMM8_V8:
483 LowerAshr2(gate);
484 break;
485 case EcmaOpcode::AND2_IMM8_V8:
486 LowerAnd2(gate);
487 break;
488 case EcmaOpcode::OR2_IMM8_V8:
489 LowerOr2(gate);
490 break;
491 case EcmaOpcode::XOR2_IMM8_V8:
492 LowerXor2(gate);
493 break;
494 case EcmaOpcode::DELOBJPROP_V8:
495 LowerDelObjProp(gate);
496 break;
497 case EcmaOpcode::DEFINEMETHOD_IMM8_ID16_IMM8:
498 case EcmaOpcode::DEFINEMETHOD_IMM16_ID16_IMM8:
499 LowerDefineMethod(gate);
500 break;
501 case EcmaOpcode::EXP_IMM8_V8:
502 LowerExp(gate);
503 break;
504 case EcmaOpcode::ISIN_IMM8_V8:
505 LowerIsIn(gate);
506 break;
507 case EcmaOpcode::INSTANCEOF_IMM8_V8:
508 LowerInstanceof(gate);
509 break;
510 case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
511 LowerFastStrictNotEqual(gate);
512 break;
513 case EcmaOpcode::STRICTEQ_IMM8_V8:
514 LowerFastStrictEqual(gate);
515 break;
516 case EcmaOpcode::CREATEEMPTYARRAY_IMM8:
517 case EcmaOpcode::CREATEEMPTYARRAY_IMM16:
518 LowerCreateEmptyArray(gate);
519 break;
520 case EcmaOpcode::CREATEEMPTYOBJECT:
521 LowerCreateEmptyObject(gate);
522 break;
523 case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
524 case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
525 LowerCreateObjectWithBuffer(gate);
526 break;
527 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
528 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
529 LowerCreateArrayWithBuffer(gate);
530 break;
531 case EcmaOpcode::STMODULEVAR_IMM8:
532 case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
533 LowerStModuleVar(gate);
534 break;
535 case EcmaOpcode::SETGENERATORSTATE_IMM8:
536 LowerSetGeneratorState(gate);
537 break;
538 case EcmaOpcode::GETTEMPLATEOBJECT_IMM8:
539 case EcmaOpcode::GETTEMPLATEOBJECT_IMM16:
540 LowerGetTemplateObject(gate);
541 break;
542 case EcmaOpcode::SETOBJECTWITHPROTO_IMM8_V8:
543 case EcmaOpcode::SETOBJECTWITHPROTO_IMM16_V8:
544 LowerSetObjectWithProto(gate);
545 break;
546 case EcmaOpcode::LDBIGINT_ID16:
547 LowerLdBigInt(gate);
548 break;
549 case EcmaOpcode::TONUMERIC_IMM8:
550 LowerToNumeric(gate);
551 break;
552 case EcmaOpcode::DYNAMICIMPORT:
553 LowerDynamicImport(gate);
554 break;
555 case EcmaOpcode::LDEXTERNALMODULEVAR_IMM8:
556 case EcmaOpcode::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16:
557 LowerExternalModule(gate);
558 break;
559 case EcmaOpcode::GETMODULENAMESPACE_IMM8:
560 case EcmaOpcode::WIDE_GETMODULENAMESPACE_PREF_IMM16:
561 LowerGetModuleNamespace(gate);
562 break;
563 case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
564 case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
565 case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
566 LowerNewObjRange(gate);
567 break;
568 case EcmaOpcode::JEQZ_IMM8:
569 case EcmaOpcode::JEQZ_IMM16:
570 case EcmaOpcode::JEQZ_IMM32:
571 LowerConditionJump(gate, true);
572 break;
573 case EcmaOpcode::JNEZ_IMM8:
574 case EcmaOpcode::JNEZ_IMM16:
575 case EcmaOpcode::JNEZ_IMM32:
576 LowerConditionJump(gate, false);
577 break;
578 case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
579 case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
580 if (compilationEnv_->IsJitCompiler()) {
581 LowerSuperCallForJIT(gate);
582 } else {
583 LowerSuperCall(gate);
584 }
585 break;
586 case EcmaOpcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
587 case EcmaOpcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
588 LowerSuperCallArrow(gate);
589 break;
590 case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8:
591 LowerSuperCallSpread(gate);
592 break;
593 case EcmaOpcode::CALLRUNTIME_SUPERCALLFORWARDALLARGS_PREF_V8:
594 if (compilationEnv_->IsJitCompiler()) {
595 LowerSuperCallForwardAllArgsForJIT(gate);
596 } else {
597 LowerSuperCallForwardAllArgs(gate);
598 }
599 break;
600 case EcmaOpcode::ISTRUE:
601 case EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8:
602 LowerIsTrueOrFalse(gate, true);
603 break;
604 case EcmaOpcode::ISFALSE:
605 case EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8:
606 LowerIsTrueOrFalse(gate, false);
607 break;
608 case EcmaOpcode::GETNEXTPROPNAME_V8:
609 LowerGetNextPropName(gate);
610 break;
611 case EcmaOpcode::COPYDATAPROPERTIES_V8:
612 LowerCopyDataProperties(gate);
613 break;
614 case EcmaOpcode::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8:
615 case EcmaOpcode::WIDE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8:
616 LowerCreateObjectWithExcludedKeys(gate);
617 break;
618 case EcmaOpcode::CREATEREGEXPWITHLITERAL_IMM8_ID16_IMM8:
619 case EcmaOpcode::CREATEREGEXPWITHLITERAL_IMM16_ID16_IMM8:
620 LowerCreateRegExpWithLiteral(gate);
621 break;
622 case EcmaOpcode::STOWNBYVALUE_IMM8_V8_V8:
623 case EcmaOpcode::STOWNBYVALUE_IMM16_V8_V8:
624 LowerStOwnByValue(gate);
625 break;
626 case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
627 case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
628 case EcmaOpcode::WIDE_STOWNBYINDEX_PREF_V8_IMM32:
629 LowerStOwnByIndex(gate);
630 break;
631 case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
632 case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8:
633 LowerStOwnByName(gate);
634 break;
635 case EcmaOpcode::NEWLEXENV_IMM8:
636 case EcmaOpcode::WIDE_NEWLEXENV_PREF_IMM16:
637 LowerNewLexicalEnv(gate);
638 break;
639 case EcmaOpcode::NEWLEXENVWITHNAME_IMM8_ID16:
640 case EcmaOpcode::WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16:
641 LowerNewLexicalEnvWithName(gate);
642 break;
643 case EcmaOpcode::POPLEXENV:
644 LowerPopLexicalEnv(gate);
645 break;
646 case EcmaOpcode::LDSUPERBYVALUE_IMM8_V8:
647 case EcmaOpcode::LDSUPERBYVALUE_IMM16_V8:
648 LowerLdSuperByValue(gate);
649 break;
650 case EcmaOpcode::STSUPERBYVALUE_IMM16_V8_V8:
651 case EcmaOpcode::STSUPERBYVALUE_IMM8_V8_V8:
652 LowerStSuperByValue(gate);
653 break;
654 case EcmaOpcode::TRYSTGLOBALBYNAME_IMM8_ID16:
655 case EcmaOpcode::TRYSTGLOBALBYNAME_IMM16_ID16:
656 LowerTryStGlobalByName(gate);
657 break;
658 case EcmaOpcode::STCONSTTOGLOBALRECORD_IMM16_ID16:
659 LowerStConstToGlobalRecord(gate, true);
660 break;
661 case EcmaOpcode::STTOGLOBALRECORD_IMM16_ID16:
662 LowerStConstToGlobalRecord(gate, false);
663 break;
664 case EcmaOpcode::STOWNBYVALUEWITHNAMESET_IMM8_V8_V8:
665 case EcmaOpcode::STOWNBYVALUEWITHNAMESET_IMM16_V8_V8:
666 LowerStOwnByValueWithNameSet(gate);
667 break;
668 case EcmaOpcode::STOWNBYNAMEWITHNAMESET_IMM8_ID16_V8:
669 case EcmaOpcode::STOWNBYNAMEWITHNAMESET_IMM16_ID16_V8:
670 LowerStOwnByNameWithNameSet(gate);
671 break;
672 case EcmaOpcode::LDGLOBALVAR_IMM16_ID16:
673 LowerLdGlobalVar(gate);
674 break;
675 case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
676 case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
677 LowerLdObjByName(gate);
678 break;
679 case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
680 case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
681 LowerStObjByName(gate, false);
682 break;
683 case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
684 LowerDefineGetterSetterByValue(gate);
685 break;
686 case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
687 case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
688 case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
689 LowerLdObjByIndex(gate);
690 break;
691 case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
692 case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
693 case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32:
694 LowerStObjByIndex(gate);
695 break;
696 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
697 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
698 LowerLdObjByValue(gate, false);
699 break;
700 case EcmaOpcode::LDTHISBYVALUE_IMM8:
701 case EcmaOpcode::LDTHISBYVALUE_IMM16:
702 LowerLdObjByValue(gate, true);
703 break;
704 case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
705 case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
706 LowerStObjByValue(gate, false);
707 break;
708 case EcmaOpcode::STTHISBYVALUE_IMM8_V8:
709 case EcmaOpcode::STTHISBYVALUE_IMM16_V8:
710 LowerStObjByValue(gate, true);
711 break;
712 case EcmaOpcode::LDSUPERBYNAME_IMM8_ID16:
713 case EcmaOpcode::LDSUPERBYNAME_IMM16_ID16:
714 LowerLdSuperByName(gate);
715 break;
716 case EcmaOpcode::STSUPERBYNAME_IMM8_ID16_V8:
717 case EcmaOpcode::STSUPERBYNAME_IMM16_ID16_V8:
718 LowerStSuperByName(gate);
719 break;
720 case EcmaOpcode::CREATEGENERATOROBJ_V8:
721 LowerCreateGeneratorObj(gate);
722 break;
723 case EcmaOpcode::CREATEASYNCGENERATOROBJ_V8:
724 LowerCreateAsyncGeneratorObj(gate);
725 break;
726 case EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8:
727 LowerAsyncGeneratorResolve(gate);
728 break;
729 case EcmaOpcode::ASYNCGENERATORREJECT_V8:
730 LowerAsyncGeneratorReject(gate);
731 break;
732 case EcmaOpcode::STARRAYSPREAD_V8_V8:
733 LowerStArraySpread(gate);
734 break;
735 case EcmaOpcode::LDLEXVAR_IMM4_IMM4:
736 case EcmaOpcode::LDLEXVAR_IMM8_IMM8:
737 case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16:
738 LowerLdLexVar(gate);
739 break;
740 case EcmaOpcode::STLEXVAR_IMM4_IMM4:
741 case EcmaOpcode::STLEXVAR_IMM8_IMM8:
742 case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
743 LowerStLexVar(gate);
744 break;
745 case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
746 case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
747 LowerDefineClassWithBuffer(gate);
748 break;
749 case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8:
750 case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8:
751 LowerDefineFunc(gate);
752 break;
753 case EcmaOpcode::COPYRESTARGS_IMM8:
754 case EcmaOpcode::WIDE_COPYRESTARGS_PREF_IMM16:
755 LowerCopyRestArgs(gate);
756 break;
757 case EcmaOpcode::WIDE_LDPATCHVAR_PREF_IMM16:
758 LowerWideLdPatchVar(gate);
759 break;
760 case EcmaOpcode::WIDE_STPATCHVAR_PREF_IMM16:
761 LowerWideStPatchVar(gate);
762 break;
763 case EcmaOpcode::LDLOCALMODULEVAR_IMM8:
764 case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
765 LowerLdLocalModuleVarByIndex(gate);
766 break;
767 case EcmaOpcode::DEBUGGER:
768 case EcmaOpcode::JSTRICTEQZ_IMM8:
769 case EcmaOpcode::JSTRICTEQZ_IMM16:
770 case EcmaOpcode::JNSTRICTEQZ_IMM8:
771 case EcmaOpcode::JNSTRICTEQZ_IMM16:
772 case EcmaOpcode::JEQNULL_IMM8:
773 case EcmaOpcode::JEQNULL_IMM16:
774 case EcmaOpcode::JNENULL_IMM8:
775 case EcmaOpcode::JNENULL_IMM16:
776 case EcmaOpcode::JSTRICTEQNULL_IMM8:
777 case EcmaOpcode::JSTRICTEQNULL_IMM16:
778 case EcmaOpcode::JNSTRICTEQNULL_IMM8:
779 case EcmaOpcode::JNSTRICTEQNULL_IMM16:
780 case EcmaOpcode::JEQUNDEFINED_IMM8:
781 case EcmaOpcode::JEQUNDEFINED_IMM16:
782 case EcmaOpcode::JNEUNDEFINED_IMM8:
783 case EcmaOpcode::JNEUNDEFINED_IMM16:
784 case EcmaOpcode::JSTRICTEQUNDEFINED_IMM8:
785 case EcmaOpcode::JSTRICTEQUNDEFINED_IMM16:
786 case EcmaOpcode::JNSTRICTEQUNDEFINED_IMM8:
787 case EcmaOpcode::JNSTRICTEQUNDEFINED_IMM16:
788 case EcmaOpcode::JEQ_V8_IMM8:
789 case EcmaOpcode::JEQ_V8_IMM16:
790 case EcmaOpcode::JNE_V8_IMM8:
791 case EcmaOpcode::JNE_V8_IMM16:
792 case EcmaOpcode::JSTRICTEQ_V8_IMM8:
793 case EcmaOpcode::JSTRICTEQ_V8_IMM16:
794 case EcmaOpcode::JNSTRICTEQ_V8_IMM8:
795 case EcmaOpcode::JNSTRICTEQ_V8_IMM16:
796 break;
797 case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
798 case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
799 LowerLdThisByName(gate);
800 break;
801 case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
802 case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
803 LowerStObjByName(gate, true);
804 break;
805 case EcmaOpcode::LDPRIVATEPROPERTY_IMM8_IMM16_IMM16:
806 LowerLdPrivateProperty(gate);
807 break;
808 case EcmaOpcode::STPRIVATEPROPERTY_IMM8_IMM16_IMM16_V8:
809 LowerStPrivateProperty(gate);
810 break;
811 case EcmaOpcode::TESTIN_IMM8_IMM16_IMM16:
812 LowerTestIn(gate);
813 break;
814 case EcmaOpcode::CALLRUNTIME_NOTIFYCONCURRENTRESULT_PREF_NONE:
815 LowerNotifyConcurrentResult(gate);
816 break;
817 case EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8:
818 case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8:
819 LowerDefineFieldByName(gate);
820 break;
821 case EcmaOpcode::CALLRUNTIME_DEFINEFIELDBYVALUE_PREF_IMM8_V8_V8:
822 LowerDefineFieldByValue(gate);
823 break;
824 case EcmaOpcode::CALLRUNTIME_DEFINEFIELDBYINDEX_PREF_IMM8_IMM32_V8:
825 LowerDefineFieldByIndex(gate);
826 break;
827 case EcmaOpcode::CALLRUNTIME_TOPROPERTYKEY_PREF_NONE:
828 LowerToPropertyKey(gate);
829 break;
830 case EcmaOpcode::CALLRUNTIME_CREATEPRIVATEPROPERTY_PREF_IMM16_ID16:
831 LowerCreatePrivateProperty(gate);
832 break;
833 case EcmaOpcode::CALLRUNTIME_DEFINEPRIVATEPROPERTY_PREF_IMM8_IMM16_IMM16_V8:
834 LowerDefinePrivateProperty(gate);
835 break;
836 case EcmaOpcode::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8:
837 LowerDefineSendableClass(gate);
838 break;
839 case EcmaOpcode::CALLRUNTIME_LDSENDABLECLASS_PREF_IMM16:
840 LowerLdSendableClass(gate);
841 break;
842 case EcmaOpcode::CALLRUNTIME_LDSENDABLEEXTERNALMODULEVAR_PREF_IMM8:
843 case EcmaOpcode::CALLRUNTIME_WIDELDSENDABLEEXTERNALMODULEVAR_PREF_IMM16:
844 LowerSendableExternalModule(gate);
845 break;
846 case EcmaOpcode::CALLRUNTIME_LDSENDABLELOCALMODULEVAR_PREF_IMM8:
847 case EcmaOpcode::CALLRUNTIME_WIDELDSENDABLELOCALMODULEVAR_PREF_IMM16:
848 LowerSendableLocalModule(gate);
849 break;
850 case EcmaOpcode::CALLRUNTIME_NEWSENDABLEENV_PREF_IMM8:
851 case EcmaOpcode::CALLRUNTIME_WIDENEWSENDABLEENV_PREF_IMM16:
852 LowerNewSendableEnv(gate);
853 break;
854 case EcmaOpcode::CALLRUNTIME_STSENDABLEVAR_PREF_IMM4_IMM4:
855 case EcmaOpcode::CALLRUNTIME_STSENDABLEVAR_PREF_IMM8_IMM8:
856 case EcmaOpcode::CALLRUNTIME_WIDESTSENDABLEVAR_PREF_IMM16_IMM16:
857 LowerStSendableVar(gate);
858 break;
859 case EcmaOpcode::CALLRUNTIME_LDSENDABLEVAR_PREF_IMM4_IMM4:
860 case EcmaOpcode::CALLRUNTIME_LDSENDABLEVAR_PREF_IMM8_IMM8:
861 case EcmaOpcode::CALLRUNTIME_WIDELDSENDABLEVAR_PREF_IMM16_IMM16:
862 LowerLdSendableVar(gate);
863 break;
864 case EcmaOpcode::CALLRUNTIME_LDLAZYMODULEVAR_PREF_IMM8:
865 case EcmaOpcode::CALLRUNTIME_WIDELDLAZYMODULEVAR_PREF_IMM16:
866 LowerLdLazyExternalModuleVar(gate);
867 break;
868 case EcmaOpcode::CALLRUNTIME_LDLAZYSENDABLEMODULEVAR_PREF_IMM8:
869 case EcmaOpcode::CALLRUNTIME_WIDELDLAZYSENDABLEMODULEVAR_PREF_IMM16:
870 LowerLdLazySendableExternalModuleVar(gate);
871 break;
872 case EcmaOpcode::LDA_STR_ID16:
873 LowerLdStr(gate);
874 break;
875 default:
876 break;
877 }
878 }
879
LowerCallStubWithIC(GateRef gate,int sign,const std::vector<GateRef> & args)880 void SlowPathLowering::LowerCallStubWithIC(GateRef gate, int sign, const std::vector<GateRef> &args)
881 {
882 std::vector<GateRef> inputs { glue_ };
883 inputs.insert(inputs.end(), args.begin(), args.end());
884 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
885 GateRef slotId = builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 0));
886 inputs.emplace_back(jsFunc);
887 inputs.emplace_back(slotId);
888
889 GateRef result = builder_.CallStub(glue_, gate, sign, inputs);
890 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), result);
891 }
892
LowerCallRuntime(GateRef gate,int index,const std::vector<GateRef> & args,bool useLabel)893 GateRef SlowPathLowering::LowerCallRuntime(GateRef gate, int index, const std::vector<GateRef> &args, bool useLabel)
894 {
895 const std::string name = RuntimeStubCSigns::GetRTName(index);
896 if (useLabel) {
897 GateRef result = builder_.CallRuntime(glue_, index, Gate::InvalidGateRef, args, gate, name.c_str());
898 return result;
899 } else {
900 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
901 GateRef target = builder_.IntPtr(index);
902 GateRef result = builder_.Call(cs, glue_, target, builder_.GetDepend(), args, gate, name.c_str());
903 return result;
904 }
905 }
906
LowerCallNGCRuntime(GateRef gate,int index,const std::vector<GateRef> & args,bool useLabel)907 GateRef SlowPathLowering::LowerCallNGCRuntime(GateRef gate, int index, const std::vector<GateRef> &args, bool useLabel)
908 {
909 const std::string name = RuntimeStubCSigns::GetRTName(index);
910 if (useLabel) {
911 GateRef result = builder_.CallNGCRuntime(glue_, index, Gate::InvalidGateRef, args, gate, name.c_str());
912 return result;
913 } else {
914 const CallSignature *cs = RuntimeStubCSigns::Get(index);
915 GateRef target = builder_.IntPtr(index);
916 GateRef result = builder_.Call(cs, glue_, target, builder_.GetDepend(), args, gate, name.c_str());
917 return result;
918 }
919 }
920
LowerAdd2(GateRef gate)921 void SlowPathLowering::LowerAdd2(GateRef gate)
922 {
923 // 2: number of value inputs
924 ASSERT(acc_.GetNumValueIn(gate) == 2);
925 GateRef result =
926 builder_.CallStub(glue_, gate, CommonStubCSigns::Add,
927 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
928 ReplaceHirWithValue(gate, result);
929 }
930
LowerCreateIterResultObj(GateRef gate)931 void SlowPathLowering::LowerCreateIterResultObj(GateRef gate)
932 {
933 const int id = RTSTUB_ID(CreateIterResultObj);
934 // 2: number of value inputs
935 ASSERT(acc_.GetNumValueIn(gate) == 2);
936 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
937 ReplaceHirWithValue(gate, newGate);
938 }
939
940 // When executing to SUSPENDGENERATOR instruction, save contextual information to GeneratorContext,
941 // including registers, acc, etc.
SaveFrameToContext(GateRef gate)942 void SlowPathLowering::SaveFrameToContext(GateRef gate)
943 {
944 GateRef genObj = acc_.GetValueIn(gate, 1);
945 GateRef saveRegister = acc_.GetDep(gate);
946 while (acc_.GetOpCode(saveRegister) != OpCode::SAVE_REGISTER) {
947 saveRegister = acc_.GetDep(saveRegister);
948 }
949 ASSERT(acc_.GetOpCode(saveRegister) == OpCode::SAVE_REGISTER);
950
951 acc_.SetDep(gate, acc_.GetDep(saveRegister));
952 builder_.SetDepend(acc_.GetDep(saveRegister));
953 GateRef context =
954 builder_.Load(VariableType::JS_POINTER(), glue_, genObj,
955 builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET));
956 // new tagged array
957 auto method = methodLiteral_;
958 const size_t arrLength = method->GetNumberVRegs() + 1; // 1: env vreg
959 GateRef length = builder_.Int32(arrLength);
960 GateRef taggedLength = builder_.ToTaggedInt(builder_.ZExtInt32ToInt64(length));
961 const int arrayId = RTSTUB_ID(NewTaggedArray);
962 GateRef taggedArray = LowerCallRuntime(gate, arrayId, {taggedLength});
963 // setRegsArrays
964 auto hole = builder_.HoleConstant();
965 size_t numVreg = acc_.GetNumValueIn(saveRegister);
966 for (size_t idx = 0; idx < numVreg; idx++) {
967 GateRef tmpGate = acc_.GetValueIn(saveRegister, idx);
968 if (tmpGate != hole) {
969 builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue_, taggedArray, builder_.Int32(idx), tmpGate);
970 }
971 }
972 ASSERT(numVreg > 0);
973 GateRef savedLexicalEnvGate = acc_.GetValueIn(saveRegister, numVreg - 1);
974 // If the lexical env saved in aot is hole, then use the lexical env on the function to avoid using hole as the
975 // lexical env when re-entering the interpreter.
976 GateRef lexicalEnvGate =
977 savedLexicalEnvGate == hole
978 ? builder_.Load(VariableType::JS_ANY(), glue_, argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC),
979 builder_.IntPtr(JSFunction::LEXICAL_ENV_OFFSET))
980 : savedLexicalEnvGate;
981 acc_.DeleteGate(saveRegister);
982
983 // setRegsArrays
984 GateRef regsArrayOffset = builder_.IntPtr(GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET);
985 builder_.Store(VariableType::JS_POINTER(), glue_, context, regsArrayOffset, taggedArray);
986
987 // set this
988 GateRef thisOffset = builder_.IntPtr(GeneratorContext::GENERATOR_THIS_OFFSET);
989 GateRef thisObj = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
990 builder_.Store(VariableType::JS_ANY(), glue_, context, thisOffset, thisObj);
991
992 // set method
993 GateRef methodOffset = builder_.IntPtr(GeneratorContext::GENERATOR_METHOD_OFFSET);
994 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
995 builder_.Store(VariableType::JS_ANY(), glue_, context, methodOffset, jsFunc);
996
997 // set acc
998 ASSERT(acc_.GetNumValueIn(gate) > 0);
999 GateRef accOffset = builder_.IntPtr(GeneratorContext::GENERATOR_ACC_OFFSET);
1000 GateRef curAccGate = acc_.GetValueIn(gate, acc_.GetNumValueIn(gate) - 1); // get current acc
1001 builder_.Store(VariableType::JS_ANY(), glue_, context, accOffset, curAccGate);
1002
1003 // set generator object
1004 GateRef generatorObjectOffset = builder_.IntPtr(GeneratorContext::GENERATOR_GENERATOR_OBJECT_OFFSET);
1005 builder_.Store(VariableType::JS_ANY(), glue_, context, generatorObjectOffset, genObj);
1006
1007 // set lexical env
1008 GateRef lexicalEnvOffset = builder_.IntPtr(GeneratorContext::GENERATOR_LEXICALENV_OFFSET);
1009 builder_.Store(VariableType::JS_ANY(), glue_, context, lexicalEnvOffset, lexicalEnvGate);
1010
1011 // set nregs
1012 GateRef nregsOffset = builder_.IntPtr(GeneratorContext::GENERATOR_NREGS_OFFSET);
1013 builder_.Store(VariableType::INT32(), glue_, context, nregsOffset, length);
1014
1015 // set bc size
1016 GateRef bcSizeOffset = builder_.IntPtr(GeneratorContext::GENERATOR_BC_OFFSET_OFFSET);
1017 GateRef bcSizeGate = acc_.GetValueIn(gate, 0); // saved bc_offset
1018 bcSizeGate = builder_.TruncInt64ToInt32(bcSizeGate);
1019 builder_.Store(VariableType::INT32(), glue_, context, bcSizeOffset, bcSizeGate);
1020
1021 // set context to generator object
1022 GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
1023 builder_.Store(VariableType::JS_POINTER(), glue_, genObj, contextOffset, context);
1024
1025 // set generator object to context
1026 builder_.Store(VariableType::JS_POINTER(), glue_, context, generatorObjectOffset, genObj);
1027 }
1028
LowerSuspendGenerator(GateRef gate)1029 void SlowPathLowering::LowerSuspendGenerator(GateRef gate)
1030 {
1031 SaveFrameToContext(gate);
1032 acc_.SetDep(gate, builder_.GetDepend());
1033 AddProfiling(gate, false);
1034 const int id = RTSTUB_ID(OptSuspendGenerator);
1035 auto value = acc_.GetValueIn(gate, 2); // 2: acc
1036 auto genObj = acc_.GetValueIn(gate, 1);
1037 GateRef newGate = LowerCallRuntime(gate, id, { genObj, value });
1038 ReplaceHirWithValue(gate, newGate);
1039 }
1040
LowerAsyncFunctionAwaitUncaught(GateRef gate)1041 void SlowPathLowering::LowerAsyncFunctionAwaitUncaught(GateRef gate)
1042 {
1043 const int id = RTSTUB_ID(AsyncFunctionAwaitUncaught);
1044 // 2: number of value inputs
1045 ASSERT(acc_.GetNumValueIn(gate) == 2);
1046 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
1047 ReplaceHirWithValue(gate, newGate);
1048 }
1049
LowerAsyncFunctionResolve(GateRef gate)1050 void SlowPathLowering::LowerAsyncFunctionResolve(GateRef gate)
1051 {
1052 const int id = RTSTUB_ID(AsyncFunctionResolveOrReject);
1053 // 2: number of value inputs
1054 ASSERT(acc_.GetNumValueIn(gate) == 2);
1055 GateRef taggedTrue = builder_.TaggedTrue();
1056 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), taggedTrue});
1057 ReplaceHirWithValue(gate, newGate);
1058 }
1059
LowerAsyncFunctionReject(GateRef gate)1060 void SlowPathLowering::LowerAsyncFunctionReject(GateRef gate)
1061 {
1062 const int id = RTSTUB_ID(AsyncFunctionResolveOrReject);
1063 // 2: number of value inputs
1064 ASSERT(acc_.GetNumValueIn(gate) == 2);
1065 GateRef taggedFalse = builder_.TaggedFalse();
1066 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), taggedFalse});
1067 ReplaceHirWithValue(gate, newGate);
1068 }
1069
LowerTryLdGlobalByName(GateRef gate)1070 void SlowPathLowering::LowerTryLdGlobalByName(GateRef gate)
1071 {
1072 // 2: number of value inputs
1073 ASSERT(acc_.GetNumValueIn(gate) == 2);
1074 GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
1075 LowerCallStubWithIC(gate, CommonStubCSigns::TryLdGlobalByName, {stringId, circuit_->GetGlobalEnvCache()});
1076 }
1077
LowerStGlobalVar(GateRef gate)1078 void SlowPathLowering::LowerStGlobalVar(GateRef gate)
1079 {
1080 // 3: number of value inputs
1081 ASSERT(acc_.GetNumValueIn(gate) == 3);
1082 GateRef id = acc_.GetValueIn(gate, 1); // 1: the second parameter
1083 GateRef value = acc_.GetValueIn(gate, 2); // 2: the 2nd para is value
1084 LowerCallStubWithIC(gate, CommonStubCSigns::StGlobalVar, {id, value, circuit_->GetGlobalEnvCache()});
1085 }
1086
LowerGetIterator(GateRef gate)1087 void SlowPathLowering::LowerGetIterator(GateRef gate)
1088 {
1089 auto result = builder_.CallStub(glue_, gate, CommonStubCSigns::GetIterator,
1090 {glue_, acc_.GetValueIn(gate, 0), circuit_->GetGlobalEnvCache()});
1091 ReplaceHirWithValue(gate, result);
1092 }
1093
LowerGetAsyncIterator(GateRef gate)1094 void SlowPathLowering::LowerGetAsyncIterator(GateRef gate)
1095 {
1096 auto result = LowerCallRuntime(gate, RTSTUB_ID(GetAsyncIterator), {acc_.GetValueIn(gate, 0)}, true);
1097 ReplaceHirWithValue(gate, result);
1098 }
1099
LowerCallthisrangeImm8Imm8V8(GateRef gate)1100 void SlowPathLowering::LowerCallthisrangeImm8Imm8V8(GateRef gate)
1101 {
1102 // this
1103 size_t fixedInputsNum = 1;
1104 size_t numIns = acc_.GetNumValueIn(gate);
1105 ASSERT(numIns >= fixedInputsNum);
1106 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1107 EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
1108 GateRef actualArgv = builder_.IntPtr(0);
1109 const size_t callTargetIndex = 1; // 1: acc
1110 GateRef callTarget = acc_.GetValueIn(gate, numIns - callTargetIndex); // acc
1111 GateRef thisObj = acc_.GetValueIn(gate, 0);
1112 GateRef newTarget = builder_.Undefined();
1113 std::vector<GateRef> vec { glue_, actualArgc, actualArgv, callTarget, newTarget, thisObj };
1114 // add common args
1115 for (size_t i = fixedInputsNum; i < numIns - callTargetIndex; i++) {
1116 vec.emplace_back(acc_.GetValueIn(gate, i));
1117 }
1118 std::vector<GateRef> vec1 { glue_, callTarget, thisObj };
1119 // add common args
1120 for (size_t i = fixedInputsNum; i < numIns - callTargetIndex; i++) {
1121 vec1.emplace_back(acc_.GetValueIn(gate, i));
1122 }
1123 LowerToJSCall(gate, vec, vec1);
1124 }
1125
LowerWideCallthisrangePrefImm16V8(GateRef gate)1126 void SlowPathLowering::LowerWideCallthisrangePrefImm16V8(GateRef gate)
1127 {
1128 // The first register input is thisobj, second is thisObj and other inputs are common args.
1129 size_t fixedInputsNum = 1; // 1: acc
1130 size_t numIns = acc_.GetNumValueIn(gate);
1131 ASSERT(numIns >= fixedInputsNum);
1132 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1133 EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8));
1134 GateRef actualArgv = builder_.IntPtr(0);
1135 const size_t callTargetIndex = 1;
1136 GateRef callTarget = acc_.GetValueIn(gate, numIns - callTargetIndex);
1137 GateRef thisObj = acc_.GetValueIn(gate, 0);
1138 GateRef newTarget = builder_.Undefined();
1139 std::vector<GateRef> vec {glue_, actualArgc, actualArgv, callTarget, newTarget, thisObj};
1140 // add common args
1141 for (size_t i = fixedInputsNum; i < numIns - callTargetIndex; i++) {
1142 vec.emplace_back(acc_.GetValueIn(gate, i));
1143 }
1144 std::vector<GateRef> vec1 {glue_, callTarget, thisObj};
1145 // add common args
1146 for (size_t i = fixedInputsNum; i < numIns - callTargetIndex; i++) {
1147 vec1.emplace_back(acc_.GetValueIn(gate, i));
1148 }
1149 LowerToJSCall(gate, vec, vec1);
1150 }
1151
LowerCallSpread(GateRef gate)1152 void SlowPathLowering::LowerCallSpread(GateRef gate)
1153 {
1154 // need to fixed in later
1155 const int id = RTSTUB_ID(CallSpread);
1156 // 3: number of value inputs
1157 ASSERT(acc_.GetNumValueIn(gate) == 3);
1158 GateRef stateInGate = builder_.GetState();
1159 GateRef newGate = LowerCallRuntime(gate, id,
1160 {acc_.GetValueIn(gate, 2), acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
1161 ReplaceHirWithPendingException(gate, stateInGate, newGate, newGate);
1162 }
1163
LowerCallrangeImm8Imm8V8(GateRef gate)1164 void SlowPathLowering::LowerCallrangeImm8Imm8V8(GateRef gate)
1165 {
1166 size_t numArgs = acc_.GetNumValueIn(gate);
1167 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1168 EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
1169 GateRef actualArgv = builder_.IntPtr(0);
1170 const size_t callTargetIndex = 1; // acc
1171 ASSERT(numArgs > 0);
1172 GateRef callTarget = acc_.GetValueIn(gate, numArgs - callTargetIndex);
1173 GateRef newTarget = builder_.Undefined();
1174 GateRef thisObj = builder_.Undefined();
1175 std::vector<GateRef> vec {glue_, actualArgc, actualArgv, callTarget, newTarget, thisObj};
1176 for (size_t i = 0; i < numArgs - callTargetIndex; i++) { // 2: skip acc
1177 vec.emplace_back(acc_.GetValueIn(gate, i));
1178 }
1179 std::vector<GateRef> vec1 {glue_, callTarget, thisObj};
1180 for (size_t i = 0; i < numArgs - callTargetIndex; i++) { // 2: skip acc
1181 vec1.emplace_back(acc_.GetValueIn(gate, i));
1182 }
1183 LowerToJSCall(gate, vec, vec1);
1184 }
1185
LowerNewObjApply(GateRef gate)1186 void SlowPathLowering::LowerNewObjApply(GateRef gate)
1187 {
1188 const int id = RTSTUB_ID(NewObjApply);
1189 // 2: number of value inputs
1190 ASSERT(acc_.GetNumValueIn(gate) == 2);
1191 GateRef newGate = LowerCallRuntime(gate, id,
1192 {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1) });
1193 ReplaceHirWithValue(gate, newGate);
1194 }
1195
LowerThrow(GateRef gate)1196 void SlowPathLowering::LowerThrow(GateRef gate)
1197 {
1198 GateRef exception = acc_.GetValueIn(gate, 0);
1199 GateRef exceptionOffset = builder_.Int64(JSThread::GlueData::GetExceptionOffset(false));
1200 builder_.Store(VariableType::INT64(), glue_, glue_, exceptionOffset, exception);
1201 // store gate value == depend
1202 GateRef result = builder_.GetDepend();
1203 ReplaceHirToThrowCall(gate, result);
1204 }
1205
LowerThrowConstAssignment(GateRef gate)1206 void SlowPathLowering::LowerThrowConstAssignment(GateRef gate)
1207 {
1208 const int id = RTSTUB_ID(ThrowConstAssignment);
1209 // 1: number of value inputs
1210 ASSERT(acc_.GetNumValueIn(gate) == 1);
1211 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)});
1212 ReplaceHirToThrowCall(gate, newGate);
1213 }
1214
LowerThrowThrowNotExists(GateRef gate)1215 void SlowPathLowering::LowerThrowThrowNotExists(GateRef gate)
1216 {
1217 const int id = RTSTUB_ID(ThrowThrowNotExists);
1218 GateRef newGate = LowerCallRuntime(gate, id, {});
1219 ReplaceHirToThrowCall(gate, newGate);
1220 }
1221
LowerThrowPatternNonCoercible(GateRef gate)1222 void SlowPathLowering::LowerThrowPatternNonCoercible(GateRef gate)
1223 {
1224 const int id = RTSTUB_ID(ThrowPatternNonCoercible);
1225 GateRef newGate = LowerCallRuntime(gate, id, {});
1226 ReplaceHirToThrowCall(gate, newGate);
1227 }
1228
LowerThrowIfNotObject(GateRef gate)1229 void SlowPathLowering::LowerThrowIfNotObject(GateRef gate)
1230 {
1231 // 1: number of value inputs
1232 ASSERT(acc_.GetNumValueIn(gate) == 1);
1233 GateRef value = acc_.GetValueIn(gate, 0);
1234 Label successExit(&builder_);
1235 Label exceptionExit(&builder_);
1236 Label isEcmaObject(&builder_);
1237 Label notEcmaObject(&builder_);
1238 Label isHeapObject(&builder_);
1239 BRANCH_CIR(builder_.TaggedIsHeapObject(value, compilationEnv_), &isHeapObject, ¬EcmaObject);
1240 builder_.Bind(&isHeapObject);
1241 BRANCH_CIR(builder_.TaggedObjectIsEcmaObject(glue_, value), &isEcmaObject, ¬EcmaObject);
1242 builder_.Bind(&isEcmaObject);
1243 {
1244 builder_.Jump(&successExit);
1245 }
1246 builder_.Bind(¬EcmaObject);
1247 {
1248 LowerCallRuntime(gate, RTSTUB_ID(ThrowIfNotObject), {}, true);
1249 builder_.Jump(&exceptionExit);
1250 }
1251 CREATE_DOUBLE_EXIT(successExit, exceptionExit)
1252 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
1253 }
1254
LowerThrowUndefinedIfHole(GateRef gate)1255 void SlowPathLowering::LowerThrowUndefinedIfHole(GateRef gate)
1256 {
1257 // 2: number of value inputs
1258 ASSERT(acc_.GetNumValueIn(gate) == 2);
1259 GateRef hole = acc_.GetValueIn(gate, 0);
1260 GateRef obj = acc_.GetValueIn(gate, 1);
1261 Label successExit(&builder_);
1262 Label exceptionExit(&builder_);
1263 Label isHole(&builder_);
1264 Label notHole(&builder_);
1265 BRANCH_CIR(builder_.TaggedIsHole(hole), &isHole, ¬Hole);
1266 builder_.Bind(¬Hole);
1267 {
1268 builder_.Jump(&successExit);
1269 }
1270 builder_.Bind(&isHole);
1271 {
1272 LowerCallRuntime(gate, RTSTUB_ID(ThrowUndefinedIfHole), {obj}, true);
1273 builder_.Jump(&exceptionExit);
1274 }
1275 CREATE_DOUBLE_EXIT(successExit, exceptionExit)
1276 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
1277 }
1278
GetStringFromConstPool(GateRef gate,GateRef stringId,uint32_t stringIdIdx=0)1279 GateRef SlowPathLowering::GetStringFromConstPool(GateRef gate, GateRef stringId, uint32_t stringIdIdx = 0)
1280 {
1281 if (compilationEnv_->SupportHeapConstant()) {
1282 auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
1283 JSTaggedValue strObj = JSTaggedValue::Undefined();
1284 uint32_t stringIndex = acc_.GetConstantValue(acc_.GetValueIn(gate, stringIdIdx));
1285 auto methodOffset = acc_.TryGetMethodOffset(gate);
1286 // the allowAlloc is false, because GetStringFromCacheForJit can't set value to constpool,
1287 // which lead to can't find strObj in runtime
1288 strObj = jitCompilationEnv->GetStringFromConstantPool(methodOffset, stringIndex, false);
1289 if (!strObj.IsUndefined()) {
1290 JSHandle<JSTaggedValue> strObjHandle = jitCompilationEnv->NewJSHandle(strObj);
1291 auto constpool = jitCompilationEnv->GetConstantPoolByMethodOffset(methodOffset);
1292 ASSERT(!constpool.IsUndefined());
1293 auto constpoolId = static_cast<uint32_t>(
1294 ConstantPool::Cast(constpool.GetTaggedObject())->GetSharedConstpoolId().GetInt());
1295 uint32_t indexInConstantTable = jitCompilationEnv->RecordHeapConstant(
1296 { constpoolId, stringIndex, JitCompilationEnv::IN_SHARED_CONSTANTPOOL }, strObjHandle);
1297 GateRef res = builder_.HeapConstant(indexInConstantTable);
1298 return res;
1299 }
1300 }
1301 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1302 GateRef sharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
1303 GateRef module = builder_.GetModuleFromFunction(glue_, jsFunc);
1304 if (compilationEnv_->IsJitCompiler()) {
1305 return builder_.CallStub(glue_, gate, CommonStubCSigns::GetStringFromConstPool,
1306 {glue_, sharedConstPool, stringId}, "GetStringFromConstPool stub");
1307 }
1308 GateRef res = builder_.GetObjectFromConstPool(
1309 glue_, gate, sharedConstPool, Circuit::NullGate(), module, stringId, ConstPoolType::STRING);
1310 return res;
1311 }
1312
LowerThrowUndefinedIfHoleWithName(GateRef gate)1313 void SlowPathLowering::LowerThrowUndefinedIfHoleWithName(GateRef gate)
1314 {
1315 // 2: number of value inputs
1316 ASSERT(acc_.GetNumValueIn(gate) == 2);
1317 GateRef hole = acc_.GetValueIn(gate, 1);
1318 Label successExit(&builder_);
1319 Label exceptionExit(&builder_);
1320 Label isHole(&builder_);
1321 Label notHole(&builder_);
1322 BRANCH_CIR(builder_.TaggedIsHole(hole), &isHole, ¬Hole);
1323 builder_.Bind(¬Hole);
1324 {
1325 builder_.Jump(&successExit);
1326 }
1327 builder_.Bind(&isHole);
1328 {
1329 GateRef stringId = builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 0));
1330 GateRef obj = GetStringFromConstPool(gate, stringId);
1331 LowerCallRuntime(gate, RTSTUB_ID(ThrowUndefinedIfHole), {obj}, true);
1332 builder_.Jump(&exceptionExit);
1333 }
1334 CREATE_DOUBLE_EXIT(successExit, exceptionExit)
1335 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
1336 }
1337
LowerThrowIfSuperNotCorrectCall(GateRef gate)1338 void SlowPathLowering::LowerThrowIfSuperNotCorrectCall(GateRef gate)
1339 {
1340 // 2: number of value inputs
1341 ASSERT(acc_.GetNumValueIn(gate) == 2);
1342 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(ThrowIfSuperNotCorrectCall),
1343 {builder_.ToTaggedInt(acc_.GetValueIn(gate, 0)), acc_.GetValueIn(gate, 1)}, true);
1344 ReplaceHirWithValue(gate, result);
1345 }
1346
LowerThrowDeleteSuperProperty(GateRef gate)1347 void SlowPathLowering::LowerThrowDeleteSuperProperty(GateRef gate)
1348 {
1349 const int id = RTSTUB_ID(ThrowDeleteSuperProperty);
1350 GateRef newGate = LowerCallRuntime(gate, id, {});
1351 ReplaceHirToThrowCall(gate, newGate);
1352 }
1353
LowerExceptionHandler(GateRef hirGate)1354 void SlowPathLowering::LowerExceptionHandler(GateRef hirGate)
1355 {
1356 GateRef depend = acc_.GetDep(hirGate);
1357 GateRef exceptionOffset = builder_.Int64(JSThread::GlueData::GetExceptionOffset(false));
1358 GateRef val = builder_.Int64Add(glue_, exceptionOffset);
1359 auto bit = LoadStoreAccessor::ToValue(MemoryAttribute::Default());
1360 GateRef loadException = circuit_->NewGate(circuit_->LoadWithoutBarrier(bit),
1361 VariableType::JS_ANY().GetMachineType(), { depend, val }, VariableType::JS_ANY().GetGateType());
1362 acc_.SetDep(loadException, depend);
1363 GateRef holeCst = builder_.HoleConstant();
1364 GateRef clearException = circuit_->NewGate(circuit_->Store(bit), MachineType::NOVALUE,
1365 { loadException, glue_, glue_, exceptionOffset, holeCst, holeCst }, VariableType::INT64().GetGateType());
1366 auto uses = acc_.Uses(hirGate);
1367 for (auto it = uses.begin(); it != uses.end();) {
1368 if (acc_.GetOpCode(*it) != OpCode::VALUE_SELECTOR && acc_.IsDependIn(it)) {
1369 it = acc_.ReplaceIn(it, clearException);
1370 } else {
1371 it = acc_.ReplaceIn(it, loadException);
1372 }
1373 }
1374 acc_.DeleteGate(hirGate);
1375 }
1376
LowerLdSymbol(GateRef gate)1377 void SlowPathLowering::LowerLdSymbol(GateRef gate)
1378 {
1379 GateRef globalEnv = circuit_->GetGlobalEnvCache();
1380 GateRef newGate = builder_.GetGlobalEnvValue(VariableType::JS_POINTER(), glue_,
1381 globalEnv, GlobalEnv::SYMBOL_FUNCTION_INDEX);
1382 ReplaceHirWithValue(gate, newGate);
1383 }
1384
LowerLdGlobal(GateRef gate)1385 void SlowPathLowering::LowerLdGlobal(GateRef gate)
1386 {
1387 GateRef globalEnv = circuit_->GetGlobalEnvCache();
1388 GateRef newGate = builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glue_,
1389 globalEnv, GlobalEnv::JS_GLOBAL_OBJECT_INDEX);
1390 ReplaceHirWithValue(gate, newGate);
1391 }
1392
LowerSub2(GateRef gate)1393 void SlowPathLowering::LowerSub2(GateRef gate)
1394 {
1395 // 2: number of value inputs
1396 ASSERT(acc_.GetNumValueIn(gate) == 2);
1397 GateRef result =
1398 builder_.CallStub(glue_, gate, CommonStubCSigns::Sub,
1399 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1400 ReplaceHirWithValue(gate, result);
1401 }
1402
LowerMul2(GateRef gate)1403 void SlowPathLowering::LowerMul2(GateRef gate)
1404 {
1405 // 2: number of value inputs
1406 ASSERT(acc_.GetNumValueIn(gate) == 2);
1407 GateRef result =
1408 builder_.CallStub(glue_, gate, CommonStubCSigns::Mul,
1409 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1410 ReplaceHirWithValue(gate, result);
1411 }
1412
LowerDiv2(GateRef gate)1413 void SlowPathLowering::LowerDiv2(GateRef gate)
1414 {
1415 // 2: number of value inputs
1416 ASSERT(acc_.GetNumValueIn(gate) == 2);
1417 GateRef result =
1418 builder_.CallStub(glue_, gate, CommonStubCSigns::Div,
1419 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1420 ReplaceHirWithValue(gate, result);
1421 }
1422
LowerMod2(GateRef gate)1423 void SlowPathLowering::LowerMod2(GateRef gate)
1424 {
1425 // 2: number of value inputs
1426 ASSERT(acc_.GetNumValueIn(gate) == 2);
1427 GateRef result =
1428 builder_.CallStub(glue_, gate, CommonStubCSigns::Mod,
1429 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1430 ReplaceHirWithValue(gate, result);
1431 }
1432
LowerEq(GateRef gate)1433 void SlowPathLowering::LowerEq(GateRef gate)
1434 {
1435 // 2: number of value inputs
1436 ASSERT(acc_.GetNumValueIn(gate) == 2);
1437 GateRef result =
1438 builder_.CallStub(glue_, gate, CommonStubCSigns::Equal,
1439 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1440 ReplaceHirWithValue(gate, result);
1441 }
1442
LowerNotEq(GateRef gate)1443 void SlowPathLowering::LowerNotEq(GateRef gate)
1444 {
1445 // 2: number of value inputs
1446 ASSERT(acc_.GetNumValueIn(gate) == 2);
1447 GateRef result =
1448 builder_.CallStub(glue_, gate, CommonStubCSigns::NotEqual,
1449 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1450 ReplaceHirWithValue(gate, result);
1451 }
1452
LowerLess(GateRef gate)1453 void SlowPathLowering::LowerLess(GateRef gate)
1454 {
1455 // 2: number of value inputs
1456 ASSERT(acc_.GetNumValueIn(gate) == 2);
1457 GateRef result =
1458 builder_.CallStub(glue_, gate, CommonStubCSigns::Less,
1459 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1460 ReplaceHirWithValue(gate, result);
1461 }
1462
LowerLessEq(GateRef gate)1463 void SlowPathLowering::LowerLessEq(GateRef gate)
1464 {
1465 // 2: number of value inputs
1466 ASSERT(acc_.GetNumValueIn(gate) == 2);
1467 GateRef result =
1468 builder_.CallStub(glue_, gate, CommonStubCSigns::LessEq,
1469 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1470 ReplaceHirWithValue(gate, result);
1471 }
1472
LowerGreater(GateRef gate)1473 void SlowPathLowering::LowerGreater(GateRef gate)
1474 {
1475 // 2: number of value inputs
1476 ASSERT(acc_.GetNumValueIn(gate) == 2);
1477 GateRef result =
1478 builder_.CallStub(glue_, gate, CommonStubCSigns::Greater,
1479 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1480 ReplaceHirWithValue(gate, result);
1481 }
1482
LowerGreaterEq(GateRef gate)1483 void SlowPathLowering::LowerGreaterEq(GateRef gate)
1484 {
1485 // 2: number of value inputs
1486 ASSERT(acc_.GetNumValueIn(gate) == 2);
1487 GateRef result =
1488 builder_.CallStub(glue_, gate, CommonStubCSigns::GreaterEq,
1489 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1490 ReplaceHirWithValue(gate, result);
1491 }
1492
LowerGetPropIterator(GateRef gate)1493 void SlowPathLowering::LowerGetPropIterator(GateRef gate)
1494 {
1495 // 1: number of value inputs
1496 ASSERT(acc_.GetNumValueIn(gate) == 1);
1497 GateRef object = {acc_.GetValueIn(gate, 0)};
1498 GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::Getpropiterator,
1499 {glue_, object, circuit_->GetGlobalEnvCache()});
1500 ReplaceHirWithValue(gate, newGate);
1501 }
1502
LowerCloseIterator(GateRef gate)1503 void SlowPathLowering::LowerCloseIterator(GateRef gate)
1504 {
1505 const int id = RTSTUB_ID(CloseIterator);
1506 // 1: number of value inputs
1507 ASSERT(acc_.GetNumValueIn(gate) == 1);
1508 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)});
1509 ReplaceHirWithValue(gate, newGate);
1510 }
1511
LowerInc(GateRef gate)1512 void SlowPathLowering::LowerInc(GateRef gate)
1513 {
1514 // 1: number of value inputs
1515 ASSERT(acc_.GetNumValueIn(gate) == 1);
1516 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Inc,
1517 { glue_, acc_.GetValueIn(gate, 0) });
1518 ReplaceHirWithValue(gate, result);
1519 }
1520
LowerDec(GateRef gate)1521 void SlowPathLowering::LowerDec(GateRef gate)
1522 {
1523 // 1: number of value inputs
1524 ASSERT(acc_.GetNumValueIn(gate) == 1);
1525 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Dec,
1526 { glue_, acc_.GetValueIn(gate, 0) });
1527 ReplaceHirWithValue(gate, result);
1528 }
1529
LowerToNumber(GateRef gate)1530 void SlowPathLowering::LowerToNumber(GateRef gate)
1531 {
1532 // 1: number of value inputs
1533 ASSERT(acc_.GetNumValueIn(gate) == 1);
1534 Label notNumber(&builder_);
1535 Label checkResult(&builder_);
1536 GateRef value = acc_.GetValueIn(gate, 0);
1537 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), value);
1538 BRANCH_CIR(builder_.TaggedIsNumber(value), &checkResult, ¬Number);
1539 builder_.Bind(¬Number);
1540 {
1541 result = LowerCallRuntime(gate, RTSTUB_ID(ToNumber), { value }, true);
1542 builder_.Jump(&checkResult);
1543 }
1544 builder_.Bind(&checkResult);
1545 ReplaceHirWithValue(gate, *result);
1546 }
1547
LowerNeg(GateRef gate)1548 void SlowPathLowering::LowerNeg(GateRef gate)
1549 {
1550 // 1: number of value inputs
1551 ASSERT(acc_.GetNumValueIn(gate) == 1);
1552 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Neg,
1553 { glue_, acc_.GetValueIn(gate, 0) });
1554 ReplaceHirWithValue(gate, result);
1555 }
1556
LowerNot(GateRef gate)1557 void SlowPathLowering::LowerNot(GateRef gate)
1558 {
1559 // 1: number of value inputs
1560 ASSERT(acc_.GetNumValueIn(gate) == 1);
1561 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::Not,
1562 { glue_, acc_.GetValueIn(gate, 0) });
1563 ReplaceHirWithValue(gate, result);
1564 }
1565
LowerShl2(GateRef gate)1566 void SlowPathLowering::LowerShl2(GateRef gate)
1567 {
1568 // 2: number of value inputs
1569 ASSERT(acc_.GetNumValueIn(gate) == 2);
1570 GateRef result =
1571 builder_.CallStub(glue_, gate, CommonStubCSigns::Shl,
1572 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1573 ReplaceHirWithValue(gate, result);
1574 }
1575
LowerShr2(GateRef gate)1576 void SlowPathLowering::LowerShr2(GateRef gate)
1577 {
1578 // 2: number of value inputs
1579 ASSERT(acc_.GetNumValueIn(gate) == 2);
1580 GateRef result =
1581 builder_.CallStub(glue_, gate, CommonStubCSigns::Shr,
1582 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1583 ReplaceHirWithValue(gate, result);
1584 }
1585
LowerAshr2(GateRef gate)1586 void SlowPathLowering::LowerAshr2(GateRef gate)
1587 {
1588 // 2: number of value inputs
1589 ASSERT(acc_.GetNumValueIn(gate) == 2);
1590 GateRef result =
1591 builder_.CallStub(glue_, gate, CommonStubCSigns::Ashr,
1592 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1593 ReplaceHirWithValue(gate, result);
1594 }
1595
LowerAnd2(GateRef gate)1596 void SlowPathLowering::LowerAnd2(GateRef gate)
1597 {
1598 // 2: number of value inputs
1599 ASSERT(acc_.GetNumValueIn(gate) == 2);
1600 GateRef result =
1601 builder_.CallStub(glue_, gate, CommonStubCSigns::And,
1602 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1603 ReplaceHirWithValue(gate, result);
1604 }
1605
LowerOr2(GateRef gate)1606 void SlowPathLowering::LowerOr2(GateRef gate)
1607 {
1608 // 2: number of value inputs
1609 ASSERT(acc_.GetNumValueIn(gate) == 2);
1610 GateRef result =
1611 builder_.CallStub(glue_, gate, CommonStubCSigns::Or,
1612 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1613 ReplaceHirWithValue(gate, result);
1614 }
1615
LowerXor2(GateRef gate)1616 void SlowPathLowering::LowerXor2(GateRef gate)
1617 {
1618 // 2: number of value inputs
1619 ASSERT(acc_.GetNumValueIn(gate) == 2);
1620 GateRef result =
1621 builder_.CallStub(glue_, gate, CommonStubCSigns::Xor,
1622 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1623 ReplaceHirWithValue(gate, result);
1624 }
1625
LowerDelObjProp(GateRef gate)1626 void SlowPathLowering::LowerDelObjProp(GateRef gate)
1627 {
1628 // 2: number of value inputs
1629 ASSERT(acc_.GetNumValueIn(gate) == 2);
1630 Label successExit(&builder_);
1631 Label exceptionExit(&builder_);
1632 GateRef newGate =
1633 builder_.CallStub(glue_, gate, CommonStubCSigns::DeleteObjectProperty,
1634 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1635 BRANCH_CIR(builder_.IsSpecial(newGate, JSTaggedValue::VALUE_EXCEPTION),
1636 &exceptionExit, &successExit);
1637 CREATE_DOUBLE_EXIT(successExit, exceptionExit)
1638 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, newGate);
1639 }
1640
LowerExp(GateRef gate)1641 void SlowPathLowering::LowerExp(GateRef gate)
1642 {
1643 const int id = RTSTUB_ID(Exp);
1644 // 2: number of value inputs
1645 ASSERT(acc_.GetNumValueIn(gate) == 2);
1646 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
1647 ReplaceHirWithValue(gate, newGate);
1648 }
1649
LowerIsIn(GateRef gate)1650 void SlowPathLowering::LowerIsIn(GateRef gate)
1651 {
1652 // 2: number of value inputs
1653 ASSERT(acc_.GetNumValueIn(gate) == 2);
1654 #if ENABLE_NEXT_OPTIMIZATION
1655
1656 GateRef newGate =
1657 builder_.CallStub(glue_, gate, CommonStubCSigns::IsIn,
1658 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1659 #else
1660 const int id = RTSTUB_ID(IsIn);
1661 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
1662 #endif
1663 ReplaceHirWithValue(gate, newGate);
1664 }
1665
LowerInstanceof(GateRef gate)1666 void SlowPathLowering::LowerInstanceof(GateRef gate)
1667 {
1668 // 3: number of value inputs
1669 ASSERT(acc_.GetNumValueIn(gate) == 3);
1670 GateRef obj = acc_.GetValueIn(gate, 1); // 1: the second parameter
1671 GateRef target = acc_.GetValueIn(gate, 2); // 2: the third parameter
1672 LowerCallStubWithIC(gate, CommonStubCSigns::Instanceof, {obj, target, circuit_->GetGlobalEnvCache()});
1673 }
1674
LowerFastStrictNotEqual(GateRef gate)1675 void SlowPathLowering::LowerFastStrictNotEqual(GateRef gate)
1676 {
1677 // 2: number of value inputs
1678 ASSERT(acc_.GetNumValueIn(gate) == 2);
1679 // 2: number of value inputs
1680 ASSERT(acc_.GetNumValueIn(gate) == 2);
1681 GateRef result =
1682 builder_.CallStub(glue_, gate, CommonStubCSigns::StrictNotEqual,
1683 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1684 ReplaceHirWithValue(gate, result);
1685 }
1686
LowerFastStrictEqual(GateRef gate)1687 void SlowPathLowering::LowerFastStrictEqual(GateRef gate)
1688 {
1689 // 2: number of value inputs
1690 ASSERT(acc_.GetNumValueIn(gate) == 2);
1691 GateRef result =
1692 builder_.CallStub(glue_, gate, CommonStubCSigns::StrictEqual,
1693 {glue_, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), circuit_->GetGlobalEnvCache()});
1694 ReplaceHirWithValue(gate, result);
1695 }
1696
LowerCreateEmptyArray(GateRef gate)1697 void SlowPathLowering::LowerCreateEmptyArray(GateRef gate)
1698 {
1699 GateRef result =
1700 builder_.CallStub(glue_, gate, CommonStubCSigns::CreateEmptyArray, {glue_, circuit_->GetGlobalEnvCache()});
1701 GateRef newRes = LowerUpdateArrayHClassAtDefine(gate, result);
1702 ReplaceHirWithValue(gate, newRes);
1703 }
1704
LowerCreateEmptyObject(GateRef gate)1705 void SlowPathLowering::LowerCreateEmptyObject(GateRef gate)
1706 {
1707 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(CreateEmptyObject), {}, true);
1708 ReplaceHirWithValue(gate, result);
1709 }
1710
LowerCreateArrayWithBuffer(GateRef gate)1711 void SlowPathLowering::LowerCreateArrayWithBuffer(GateRef gate)
1712 {
1713 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1714 GateRef index = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
1715 GateRef slotId = builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 1));
1716 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::CreateArrayWithBuffer,
1717 {glue_, index, jsFunc, slotId, circuit_->GetGlobalEnvCache()});
1718 // when elementsKind switch on, we should not update arrayHClass here.
1719 GateRef newRes = LowerUpdateArrayHClassAtDefine(gate, result);
1720 ReplaceHirWithValue(gate, newRes);
1721 }
1722
LowerUpdateArrayHClassAtDefine(GateRef gate,GateRef array)1723 GateRef SlowPathLowering::LowerUpdateArrayHClassAtDefine(GateRef gate, GateRef array)
1724 {
1725 ElementsKind kind = acc_.TryGetElementsKind(gate);
1726 if (!Elements::IsGeneric(kind)) {
1727 GateRef globalEnv = circuit_->GetGlobalEnvCache();
1728 size_t elementIndex = static_cast<size_t>(compilationEnv_->GetArrayHClassIndex(kind, false));
1729 GateRef hclass = builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glue_, globalEnv, elementIndex);
1730 builder_.Store(VariableType::JS_POINTER(), glue_, array, builder_.IntPtr(0), hclass);
1731 }
1732 return array;
1733 }
1734
LowerCreateObjectWithBuffer(GateRef gate)1735 void SlowPathLowering::LowerCreateObjectWithBuffer(GateRef gate)
1736 {
1737 // 2: number of value inputs
1738 ASSERT(acc_.GetNumValueIn(gate) == 2);
1739 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1740 GateRef sharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
1741 GateRef unsharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
1742 GateRef index = acc_.GetValueIn(gate, 0);
1743 GateRef module = builder_.GetModuleFromFunction(glue_, jsFunc);
1744 GateRef obj = 0;
1745 auto GetObjectFromConstpoolForJit = [&]() -> bool {
1746 if (!compilationEnv_->SupportHeapConstant()) {
1747 return false;
1748 }
1749 auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
1750 uint32_t objIndex = acc_.GetConstantValue(index);
1751 auto methodOffset = acc_.TryGetMethodOffset(gate);
1752 JSTaggedValue constpool = jitCompilationEnv->GetConstantPoolByMethodOffset(methodOffset);
1753 if (constpool.IsUndefined()) {
1754 return false;
1755 }
1756 JSTaggedValue objInConstpool =
1757 jitCompilationEnv->GetObjectLiteralFromCache(constpool, objIndex, recordName_);
1758 if (objInConstpool.IsUndefined()) {
1759 return false;
1760 }
1761 JSHandle<JSTaggedValue> objHandle = jitCompilationEnv->NewJSHandle(objInConstpool);
1762 auto constpoolId = static_cast<uint32_t>(
1763 ConstantPool::Cast(constpool.GetTaggedObject())->GetSharedConstpoolId().GetInt());
1764 uint32_t indexInConstantTable = jitCompilationEnv->RecordHeapConstant(
1765 { constpoolId, objIndex, JitCompilationEnv::IN_UNSHARED_CONSTANTPOOL }, objHandle);
1766 obj = builder_.HeapConstant(indexInConstantTable);
1767 return true;
1768 };
1769 if (!GetObjectFromConstpoolForJit()) {
1770 obj = builder_.GetObjectFromConstPool(glue_, gate, sharedConstPool, unsharedConstPool, module,
1771 builder_.TruncInt64ToInt32(index), ConstPoolType::OBJECT_LITERAL);
1772 }
1773 GateRef lexEnv = acc_.GetValueIn(gate, 1);
1774 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::CreateObjectHavingMethod, {glue_, obj, lexEnv});
1775 ReplaceHirWithValue(gate, result);
1776 }
1777
LowerStModuleVar(GateRef gate)1778 void SlowPathLowering::LowerStModuleVar(GateRef gate)
1779 {
1780 // 2: number of value inputs
1781 ASSERT(acc_.GetNumValueIn(gate) == 2);
1782 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1783 GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
1784 auto result = LowerCallRuntime(gate, RTSTUB_ID(StModuleVarByIndexOnJSFunc),
1785 {index, acc_.GetValueIn(gate, 1), jsFunc}, true);
1786 ReplaceHirWithValue(gate, result);
1787 }
1788
LowerSetGeneratorState(GateRef gate)1789 void SlowPathLowering::LowerSetGeneratorState(GateRef gate)
1790 {
1791 // 2: number of value inputs
1792 ASSERT(acc_.GetNumValueIn(gate) == 2);
1793 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1794 GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
1795 auto result = LowerCallRuntime(gate, RTSTUB_ID(SetGeneratorState),
1796 {acc_.GetValueIn(gate, 1), index, jsFunc}, true);
1797 ReplaceHirWithValue(gate, result);
1798 }
1799
LowerGetTemplateObject(GateRef gate)1800 void SlowPathLowering::LowerGetTemplateObject(GateRef gate)
1801 {
1802 const int id = RTSTUB_ID(GetTemplateObject);
1803 // 1: number of value inputs
1804 ASSERT(acc_.GetNumValueIn(gate) == 1);
1805 GateRef literal = acc_.GetValueIn(gate, 0);
1806 GateRef newGate = LowerCallRuntime(gate, id, { literal });
1807 ReplaceHirWithValue(gate, newGate);
1808 }
1809
LowerSetObjectWithProto(GateRef gate)1810 void SlowPathLowering::LowerSetObjectWithProto(GateRef gate)
1811 {
1812 const int id = RTSTUB_ID(SetObjectWithProto);
1813 // 2: number of value inputs
1814 ASSERT(acc_.GetNumValueIn(gate) == 2);
1815 GateRef proto = acc_.GetValueIn(gate, 0);
1816 GateRef obj = acc_.GetValueIn(gate, 1);
1817 GateRef newGate = LowerCallRuntime(gate, id, { proto, obj });
1818 ReplaceHirWithValue(gate, newGate);
1819 }
1820
LowerLdBigInt(GateRef gate)1821 void SlowPathLowering::LowerLdBigInt(GateRef gate)
1822 {
1823 // 1: number of value inputs
1824 ASSERT(acc_.GetNumValueIn(gate) == 1);
1825 GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
1826 GateRef numberBigInt = GetStringFromConstPool(gate, stringId);
1827 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(LdBigInt), {numberBigInt}, true);
1828 ReplaceHirWithValue(gate, result);
1829 }
1830
LowerToNumeric(GateRef gate)1831 void SlowPathLowering::LowerToNumeric(GateRef gate)
1832 {
1833 // 1: number of value inputs
1834 ASSERT(acc_.GetNumValueIn(gate) == 1);
1835 Label notNumber(&builder_);
1836 Label checkResult(&builder_);
1837 GateRef value = acc_.GetValueIn(gate, 0);
1838 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), value);
1839 BRANCH_CIR(builder_.TaggedIsNumeric(glue_, value), &checkResult, ¬Number);
1840 builder_.Bind(¬Number);
1841 {
1842 result = LowerCallRuntime(gate, RTSTUB_ID(ToNumeric), { value }, true);
1843 builder_.Jump(&checkResult);
1844 }
1845 builder_.Bind(&checkResult);
1846 ReplaceHirWithValue(gate, *result);
1847 }
1848
LowerDynamicImport(GateRef gate)1849 void SlowPathLowering::LowerDynamicImport(GateRef gate)
1850 {
1851 const int id = RTSTUB_ID(DynamicImport);
1852 // 1: number of value inputs
1853 ASSERT(acc_.GetNumValueIn(gate) == 1);
1854 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1855 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), jsFunc});
1856 ReplaceHirWithValue(gate, newGate);
1857 }
1858
LowerLdLocalModuleVarByIndex(GateRef gate)1859 void SlowPathLowering::LowerLdLocalModuleVarByIndex(GateRef gate)
1860 {
1861 // 2: number of value inputs
1862 ASSERT(acc_.GetNumValueIn(gate) == 1);
1863 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1864 GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
1865 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(LdLocalModuleVarByIndexOnJSFunc), {index, jsFunc}, true);
1866 ReplaceHirWithValue(gate, result);
1867 }
1868
LowerExternalModule(GateRef gate)1869 void SlowPathLowering::LowerExternalModule(GateRef gate)
1870 {
1871 ASSERT(acc_.GetNumValueIn(gate) == 1);
1872 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1873 GateRef index = acc_.GetValueIn(gate, 0);
1874
1875 GateRef indexTagged = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
1876 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(LdExternalModuleVarByIndexOnJSFunc), {indexTagged, jsFunc}, true);
1877 ReplaceHirWithValue(gate, result);
1878 }
1879
LowerGetModuleNamespace(GateRef gate)1880 void SlowPathLowering::LowerGetModuleNamespace(GateRef gate)
1881 {
1882 // 1: number of value inputs
1883 ASSERT(acc_.GetNumValueIn(gate) == 1);
1884 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1885 GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
1886 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(GetModuleNamespaceByIndexOnJSFunc), {index, jsFunc}, true);
1887 ReplaceHirWithValue(gate, result);
1888 }
1889
GetTaggedArrayFromValueIn(Environment * env,GateRef gate,size_t length)1890 GateRef SlowPathLowering::GetTaggedArrayFromValueIn(Environment *env, GateRef gate, size_t length)
1891 {
1892 NewObjectStubBuilder objBuilder(env);
1893 GateRef taggedArray = objBuilder.NewTaggedArray(glue_, builder_.Int32(length));
1894 for (size_t i = 0; i < length; i++) {
1895 builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue_, taggedArray,
1896 builder_.Int32(i), acc_.GetValueIn(gate, i));
1897 }
1898 return taggedArray;
1899 }
1900
LowerSuperCall(GateRef gate)1901 void SlowPathLowering::LowerSuperCall(GateRef gate)
1902 {
1903 Environment env(gate, circuit_, &builder_);
1904 NewObjectStubBuilder objBuilder(&env);
1905 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1906 DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1907 DEFVALUE(newTarget, (&builder_), VariableType::JS_ANY(), argAcc_->GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET));
1908 Label fastPath(&builder_);
1909 Label slowPath(&builder_);
1910 Label callExit(&builder_);
1911 Label replaceGate(&builder_);
1912 size_t length = acc_.GetNumValueIn(gate);
1913 GateRef taggedLength = builder_.ToTaggedInt(builder_.Int64(length));
1914 GateRef taggedArray = GetTaggedArrayFromValueIn(&env, gate, length);
1915 GateRef func = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1916 GateRef superFunc = objBuilder.GetPrototype(glue_, func);
1917
1918 CheckSuperAndNewTarget(objBuilder, superFunc, newTarget, thisObj, fastPath, slowPath);
1919 builder_.Bind(&fastPath);
1920 {
1921 LowerFastSuperCallWithArgArray(taggedArray, {gate, superFunc, *newTarget, *thisObj,
1922 builder_.Int64(length)}, false, result, callExit); // false: not spread
1923 builder_.Bind(&callExit);
1924 result = objBuilder.ConstructorCheck(glue_, superFunc, *result, *thisObj);
1925 builder_.Jump(&replaceGate);
1926 }
1927 builder_.Bind(&slowPath);
1928 {
1929 result = LowerCallRuntime(gate, RTSTUB_ID(OptSuperCall), { func, *newTarget, taggedArray, taggedLength });
1930 builder_.Jump(&replaceGate);
1931 }
1932 builder_.Bind(&replaceGate);
1933 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
1934 }
1935
LowerSuperCallForJIT(GateRef gate)1936 void SlowPathLowering::LowerSuperCallForJIT(GateRef gate)
1937 {
1938 Environment env(gate, circuit_, &builder_);
1939 NewObjectStubBuilder objBuilder(&env);
1940 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1941 DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1942 DEFVALUE(newTarget, (&builder_), VariableType::JS_ANY(), argAcc_->GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET));
1943 Label fastPath(&builder_);
1944 Label slowPath(&builder_);
1945 Label callExit(&builder_);
1946 Label replaceGate(&builder_);
1947 size_t length = acc_.GetNumValueIn(gate);
1948 GateRef taggedLength = builder_.ToTaggedInt(builder_.Int64(length));
1949 GateRef taggedArray = GetTaggedArrayFromValueIn(&env, gate, length);
1950 GateRef func = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1951 GateRef superFunc = objBuilder.GetPrototype(glue_, func);
1952
1953 GateRef ret = CheckSuperAndNewTargetForJIT(gate, superFunc, newTarget, fastPath, slowPath);
1954 builder_.Bind(&fastPath);
1955 {
1956 // when CommonStubCSigns::CheckSuperAndNew returns not hole, it will return what we want here.
1957 thisObj = ret;
1958 GateRef elementsPtr = builder_.GetDataOfTaggedArray(taggedArray);
1959 result = builder_.CallStub(glue_, gate, CommonStubCSigns::SuperCallAndConstructorCheck,
1960 {glue_, superFunc, *newTarget, *thisObj, builder_.Int64(length), elementsPtr});
1961 builder_.Jump(&replaceGate);
1962 }
1963 builder_.Bind(&slowPath);
1964 {
1965 result = LowerCallRuntime(gate, RTSTUB_ID(OptSuperCall), {func, *newTarget, taggedArray, taggedLength});
1966 builder_.Jump(&replaceGate);
1967 }
1968 builder_.Bind(&replaceGate);
1969 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
1970 }
1971
LowerSuperCallArrow(GateRef gate)1972 void SlowPathLowering::LowerSuperCallArrow(GateRef gate)
1973 {
1974 Environment env(gate, circuit_, &builder_);
1975 NewObjectStubBuilder objBuilder(&env);
1976 const int id = RTSTUB_ID(OptSuperCall);
1977 ASSERT(acc_.GetNumValueIn(gate) > 0);
1978 GateRef newTarget = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
1979 size_t funcIndex = acc_.GetNumValueIn(gate) - 1;
1980 GateRef taggedLength = builder_.ToTaggedInt(builder_.Int64(funcIndex));
1981 GateRef taggedArray = GetTaggedArrayFromValueIn(&env, gate, funcIndex);
1982 GateRef func = acc_.GetValueIn(gate, funcIndex);
1983 std::vector<GateRef> vec { func, newTarget, taggedArray, taggedLength};
1984 GateRef newGate = LowerCallRuntime(gate, id, vec);
1985 ReplaceHirWithValue(gate, newGate);
1986 }
1987
LowerSuperCallSpread(GateRef gate)1988 void SlowPathLowering::LowerSuperCallSpread(GateRef gate)
1989 {
1990 Environment env(gate, circuit_, &builder_);
1991 NewObjectStubBuilder objBuilder(&env);
1992 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1993 DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1994 DEFVALUE(newTarget, (&builder_), VariableType::JS_ANY(), argAcc_->GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET));
1995 Label fastPath(&builder_);
1996 Label slowPath(&builder_);
1997 Label callExit(&builder_);
1998 Label replaceGate(&builder_);
1999
2000 GateRef array = acc_.GetValueIn(gate, 0);
2001 GateRef func = acc_.GetValueIn(gate, 1);
2002 GateRef superFunc = objBuilder.GetPrototype(glue_, func);
2003 CheckSuperAndNewTarget(objBuilder, superFunc, newTarget, thisObj, fastPath, slowPath);
2004 builder_.Bind(&fastPath);
2005 {
2006 GateRef actualArgc = builder_.ZExtInt32ToInt64(
2007 builder_.LoadWithoutBarrier(VariableType::INT32(), array, builder_.IntPtr(JSArray::LENGTH_OFFSET)));
2008 LowerFastSuperCallWithArgArray(array, {gate, superFunc, *newTarget, *thisObj, actualArgc},
2009 true, result, callExit); // true: is spread
2010 builder_.Bind(&callExit);
2011 result = objBuilder.ConstructorCheck(glue_, superFunc, *result, *thisObj);
2012 builder_.Jump(&replaceGate);
2013 }
2014 builder_.Bind(&slowPath);
2015 {
2016 GateRef argsTaggedArray = builder_.CallStub(glue_, gate, CommonStubCSigns::GetCallSpreadArgs,
2017 {glue_, array, circuit_->GetGlobalEnvCache()});
2018 result = LowerCallRuntime(gate, RTSTUB_ID(OptSuperCallSpread), {func, *newTarget, argsTaggedArray});
2019 builder_.Jump(&replaceGate);
2020 }
2021 builder_.Bind(&replaceGate);
2022 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
2023 }
2024
IsAotOrFastCall(GateRef func,CircuitBuilder::JudgeMethodType type)2025 GateRef SlowPathLowering::IsAotOrFastCall(GateRef func, CircuitBuilder::JudgeMethodType type)
2026 {
2027 return builder_.JudgeAotAndFastCall(func, type);
2028 }
2029
LowerFastSuperCallWithArgArray(GateRef array,const std::vector<GateRef> & args,bool isSpread,Variable & result,Label & exit)2030 void SlowPathLowering::LowerFastSuperCallWithArgArray(GateRef array, const std::vector<GateRef> &args,
2031 bool isSpread, Variable &result, Label &exit)
2032 {
2033 ASSERT(args.size() == 5); // 5: size of args
2034 GateRef srcElements;
2035 if (isSpread) {
2036 GateRef gate = args[0]; // 0: index of gate
2037 srcElements = builder_.CallStub(glue_, gate, CommonStubCSigns::GetCallSpreadArgs,
2038 {glue_, array, circuit_->GetGlobalEnvCache()});
2039 } else {
2040 srcElements = array;
2041 }
2042 GateRef elementsPtr = builder_.GetDataOfTaggedArray(srcElements);
2043 CallCoStubBuilder::LowerFastSuperCall(glue_, builder_, args, elementsPtr, result, exit);
2044 }
2045
CheckSuperAndNewTarget(NewObjectStubBuilder & objBuilder,GateRef super,Variable & newTarget,Variable & thisObj,Label & fastPath,Label & slowPath)2046 void SlowPathLowering::CheckSuperAndNewTarget(NewObjectStubBuilder &objBuilder, GateRef super, Variable &newTarget,
2047 Variable &thisObj, Label &fastPath, Label &slowPath)
2048 {
2049 Label isHeapObj(&builder_);
2050 Label isJsFunc(&builder_);
2051 Label isCtor(&builder_);
2052 Label targetUndefined(&builder_);
2053 Label normalPath(&builder_);
2054 Label needAllocateThis(&builder_);
2055
2056 BRANCH_CIR(builder_.TaggedIsHeapObject(super, compilationEnv_), &isHeapObj, &slowPath);
2057 builder_.Bind(&isHeapObj);
2058 BRANCH_CIR(builder_.IsJSFunction(glue_, super), &isJsFunc, &slowPath);
2059 builder_.Bind(&isJsFunc);
2060 BRANCH_CIR(builder_.IsConstructor(glue_, super), &isCtor, &slowPath);
2061 builder_.Bind(&isCtor);
2062 BRANCH_CIR(builder_.TaggedIsUndefined(*newTarget), &targetUndefined, &normalPath);
2063 builder_.Bind(&targetUndefined);
2064 newTarget = super;
2065 builder_.Jump(&normalPath);
2066 builder_.Bind(&normalPath);
2067 BRANCH_CIR(builder_.IsBase(glue_, super), &needAllocateThis, &fastPath);
2068 builder_.Bind(&needAllocateThis);
2069 thisObj = objBuilder.FastSuperAllocateThis(glue_, super, *newTarget);
2070 builder_.Jump(&fastPath);
2071 }
2072
CheckSuperAndNewTargetForJIT(GateRef gate,GateRef super,Variable & newTarget,Label & fastPath,Label & slowPath)2073 GateRef SlowPathLowering::CheckSuperAndNewTargetForJIT(GateRef gate, GateRef super, Variable &newTarget,
2074 Label &fastPath, Label &slowPath)
2075 {
2076 Label targetUndefined(&builder_);
2077 Label normalPath(&builder_);
2078
2079 BRANCH_CIR(builder_.TaggedIsUndefined(*newTarget), &targetUndefined, &normalPath);
2080 builder_.Bind(&targetUndefined);
2081 newTarget = super;
2082 builder_.Jump(&normalPath);
2083 builder_.Bind(&normalPath);
2084
2085 // return value: hole: slowpath; undefined: noalloc; other: allocthis.
2086 auto ret = builder_.CallStub(glue_, gate, CommonStubCSigns::CheckSuperAndNew, {glue_, super, *newTarget});
2087 BRANCH_CIR(builder_.TaggedIsHole(ret), &slowPath, &fastPath);
2088 return ret;
2089 }
2090
LowerSuperCallForwardAllArgsForJIT(GateRef gate)2091 void SlowPathLowering::LowerSuperCallForwardAllArgsForJIT(GateRef gate)
2092 {
2093 Environment env(gate, circuit_, &builder_);
2094 NewObjectStubBuilder objBuilder(&env);
2095 DEFVALUE(newTarget, (&builder_), VariableType::JS_ANY(), argAcc_->GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET));
2096 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2097 DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2098 GateRef func = acc_.GetValueIn(gate, 0);
2099 GateRef actualArgc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGC);
2100 GateRef actualArgv = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGV);
2101 GateRef super = builder_.CallStub(glue_, gate, CommonStubCSigns::GetPrototype, {glue_, func});
2102 Label fastPath(&builder_);
2103 Label fastPathWithArgv(&builder_);
2104 Label slowPath(&builder_);
2105 Label threadCheck(&builder_);
2106 Label argvIsNull(&builder_);
2107 Label getArgsFromArgAcc(&builder_);
2108
2109 GateRef ret = CheckSuperAndNewTargetForJIT(gate, super, newTarget, fastPath, slowPath);
2110 builder_.Bind(&fastPath);
2111 {
2112 // when CommonStubCSigns::CheckSuperAndNew returns not hole, it will return what we want here.
2113 thisObj = ret;
2114 BRANCH_CIR(builder_.Equal(actualArgv, builder_.IntPtr(0)), &argvIsNull, &fastPathWithArgv);
2115 builder_.Bind(&argvIsNull);
2116 {
2117 GateRef expected =
2118 builder_.Int64Add(GetExpectedNumOfArgsFromFunc(func), builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS));
2119 BRANCH_CIR(builder_.Int64Equal(expected, actualArgc), &getArgsFromArgAcc, &slowPath);
2120 builder_.Bind(&getArgsFromArgAcc);
2121 std::vector<GateRef> args {gate, super, actualArgc, *newTarget, *thisObj};
2122 GenerateSuperCallForwardAllArgsWithoutArgv(args, result, threadCheck);
2123 }
2124 builder_.Bind(&fastPathWithArgv);
2125 {
2126 GateRef argc = builder_.Int64Sub(actualArgc, builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS));
2127 GateRef argv = builder_.PtrAdd(actualArgv, builder_.IntPtr(NUM_MANDATORY_JSFUNC_ARGS * 8)); // 8: ptr size
2128 result = builder_.CallStub(glue_, gate, CommonStubCSigns::SuperCallAndConstructorCheck,
2129 {glue_, super, *newTarget, *thisObj, argc, argv});
2130 builder_.Jump(&threadCheck);
2131 }
2132 }
2133 builder_.Bind(&slowPath);
2134 {
2135 std::vector<GateRef> args {super, *newTarget, builder_.ToTaggedInt(actualArgc)};
2136 result = LowerCallRuntime(gate, RTSTUB_ID(OptSuperCallForwardAllArgs), args, true);
2137 builder_.Jump(&threadCheck);
2138 }
2139 builder_.Bind(&threadCheck);
2140 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
2141 }
2142
GetExpectedNumOfArgsFromFunc(GateRef func)2143 GateRef SlowPathLowering::GetExpectedNumOfArgsFromFunc(GateRef func)
2144 {
2145 GateRef method = builder_.GetMethodFromFunction(glue_, func);
2146 return builder_.GetExpectedNumOfArgs(method);
2147 }
2148
LowerSuperCallForwardAllArgs(GateRef gate)2149 void SlowPathLowering::LowerSuperCallForwardAllArgs(GateRef gate)
2150 {
2151 Environment env(gate, circuit_, &builder_);
2152 NewObjectStubBuilder objBuilder(&env);
2153 DEFVALUE(newTarget, (&builder_), VariableType::JS_ANY(), argAcc_->GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET));
2154 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2155 DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2156 GateRef func = acc_.GetValueIn(gate, 0);
2157 GateRef actualArgc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGC);
2158 GateRef actualArgv = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGV);
2159 GateRef super = objBuilder.GetPrototype(glue_, func);
2160 Label fastPath(&builder_);
2161 Label fastPathWithArgv(&builder_);
2162 Label callExit(&builder_);
2163 Label slowPath(&builder_);
2164 Label threadCheck(&builder_);
2165 Label argvIsNull(&builder_);
2166 Label getArgsFromArgAcc(&builder_);
2167
2168 CheckSuperAndNewTarget(objBuilder, super, newTarget, thisObj, fastPath, slowPath);
2169 builder_.Bind(&fastPath);
2170 {
2171 BRANCH_CIR(builder_.Equal(actualArgv, builder_.IntPtr(0)), &argvIsNull, &fastPathWithArgv);
2172 builder_.Bind(&argvIsNull);
2173 {
2174 GateRef expected =
2175 builder_.Int64Add(GetExpectedNumOfArgsFromFunc(func), builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS));
2176 BRANCH_CIR(builder_.Int64Equal(expected, actualArgc), &getArgsFromArgAcc, &slowPath);
2177 builder_.Bind(&getArgsFromArgAcc);
2178 std::vector<GateRef> args {gate, super, actualArgc, *newTarget, *thisObj};
2179 GenerateSuperCallForwardAllArgsWithoutArgv(args, result, threadCheck);
2180 }
2181 builder_.Bind(&fastPathWithArgv);
2182 {
2183 GateRef argc = builder_.Int64Sub(actualArgc, builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS));
2184 GateRef argv = builder_.PtrAdd(actualArgv, builder_.IntPtr(NUM_MANDATORY_JSFUNC_ARGS * 8)); // 8: ptr size
2185 CallCoStubBuilder::LowerFastSuperCall(glue_, builder_, {gate, super, *newTarget, *thisObj, argc}, argv,
2186 result, callExit);
2187 builder_.Bind(&callExit);
2188 result = objBuilder.ConstructorCheck(glue_, super, *result, *thisObj);
2189 builder_.Jump(&threadCheck);
2190 }
2191 }
2192 builder_.Bind(&slowPath);
2193 {
2194 std::vector<GateRef> args {super, *newTarget, builder_.ToTaggedInt(actualArgc)};
2195 result = LowerCallRuntime(gate, RTSTUB_ID(OptSuperCallForwardAllArgs), args, true);
2196 builder_.Jump(&threadCheck);
2197 }
2198 builder_.Bind(&threadCheck);
2199 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
2200 }
2201
GenerateSuperCallForwardAllArgsWithoutArgv(const std::vector<GateRef> & args,Variable & result,Label & exit)2202 void SlowPathLowering::GenerateSuperCallForwardAllArgsWithoutArgv(const std::vector<GateRef> &args, Variable &result,
2203 Label &exit)
2204 {
2205 ASSERT(args.size() == 5); // 5: size of args
2206 GateRef gate = args[0]; // 0: gate
2207 GateRef super = args[1]; // 1: super constructor
2208 GateRef actualArgc = args[2]; // 2: num of args
2209 GateRef newTarget = args[3]; // 3: argv
2210 GateRef thisObj = args[4]; // 4: newTarget
2211
2212 Label afterCallSuper(&builder_);
2213 std::vector<GateRef> callArgs { glue_, actualArgc, builder_.IntPtr(0), super, newTarget, thisObj };
2214 std::vector<GateRef> argsFastCall { glue_, super, thisObj };
2215
2216 uint32_t startIdx = static_cast<uint32_t>(CommonArgIdx::NUM_OF_ARGS);
2217 ASSERT(argAcc_->ArgsCount() >= startIdx);
2218 for (uint32_t i = startIdx; i < argAcc_->ArgsCount(); ++i) {
2219 GateRef value = argAcc_->ArgsAt(i);
2220 callArgs.emplace_back(value);
2221 argsFastCall.emplace_back(value);
2222 }
2223
2224 if (compilationEnv_->IsJitCompiler()) {
2225 auto selectCall = builder_.CallStub(glue_, gate, CommonStubCSigns::FastCallSelector,
2226 { glue_, super, actualArgc });
2227 SelectFastNew(selectCall, gate, super, callArgs, argsFastCall, &result, &afterCallSuper);
2228 } else {
2229 CallCoStubBuilder::LowerFastCall(gate, glue_, builder_, super, actualArgc, callArgs, argsFastCall, &result,
2230 &afterCallSuper, true, g_isEnableCMCGC);
2231 }
2232 builder_.Bind(&afterCallSuper);
2233 result = builder_.CallStub(glue_, gate, CommonStubCSigns::ConstructorCheck, { glue_, super, *result, thisObj });
2234 builder_.Jump(&exit);
2235 }
2236
LowerIsTrueOrFalse(GateRef gate,bool flag)2237 void SlowPathLowering::LowerIsTrueOrFalse(GateRef gate, bool flag)
2238 {
2239 Label slowpath(&builder_);
2240 Label isTrue(&builder_);
2241 Label isFalse(&builder_);
2242 Label successExit(&builder_);
2243 // 1: number of value inputs
2244 ASSERT(acc_.GetNumValueIn(gate) == 1);
2245 auto value = acc_.GetValueIn(gate, 0);
2246 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), value);
2247 if (flag) {
2248 result = builder_.CallStub(glue_, gate, CommonStubCSigns::ToBooleanTrue, { glue_, value });
2249 } else {
2250 result = builder_.CallStub(glue_, gate, CommonStubCSigns::ToBooleanFalse, { glue_, value });
2251 }
2252 ReplaceHirWithValue(gate, *result);
2253 }
2254
LowerNewObjRange(GateRef gate)2255 void SlowPathLowering::LowerNewObjRange(GateRef gate)
2256 {
2257 Label fastPath(&builder_);
2258 Label slowPath(&builder_);
2259 Label threadCheck(&builder_);
2260 Label successExit(&builder_);
2261 Label exit(&builder_);
2262
2263 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2264
2265 GateRef ctor = acc_.GetValueIn(gate, 0);
2266 GateRef thisObj = builder_.CallStub(glue_, gate, CommonStubCSigns::NewThisObjectChecked, {glue_, ctor});
2267 BRANCH_CIR(builder_.TaggedIsHole(thisObj), &slowPath, &fastPath);
2268 builder_.Bind(&fastPath);
2269 {
2270 GateRef actualArgc = builder_.Int64(
2271 BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate), EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
2272 GateRef actualArgv = builder_.IntPtr(0);
2273 size_t range = acc_.GetNumValueIn(gate);
2274 std::vector<GateRef> args {glue_, actualArgc, actualArgv, ctor, ctor, thisObj};
2275 std::vector<GateRef> argsFastCall {glue_, ctor, thisObj};
2276 for (size_t i = 1; i < range; ++i) {
2277 args.emplace_back(acc_.GetValueIn(gate, i));
2278 argsFastCall.emplace_back(acc_.GetValueIn(gate, i));
2279 }
2280 if (compilationEnv_->IsJitCompiler()) {
2281 auto selectCall =
2282 builder_.CallStub(glue_, gate, CommonStubCSigns::FastCallSelector, {glue_, ctor, actualArgc});
2283 SelectFastNew(selectCall, gate, ctor, args, argsFastCall, &result, &exit);
2284 } else {
2285 CallCoStubBuilder::LowerFastCall(gate, glue_, builder_, ctor, actualArgc, args, argsFastCall, &result,
2286 &exit, true, g_isEnableCMCGC);
2287 }
2288 builder_.Bind(&exit);
2289 result = builder_.CallStub(glue_, gate, CommonStubCSigns::ConstructorCheck, {glue_, ctor, *result, thisObj});
2290 builder_.Jump(&threadCheck);
2291 }
2292 builder_.Bind(&slowPath);
2293 {
2294 size_t range = acc_.GetNumValueIn(gate);
2295 std::vector<GateRef> args(range);
2296 for (size_t i = 0; i < range; ++i) {
2297 args[i] = acc_.GetValueIn(gate, i);
2298 }
2299 result = LowerCallRuntime(gate, RTSTUB_ID(OptNewObjRange), args, true);
2300 builder_.Jump(&threadCheck);
2301 }
2302 builder_.Bind(&threadCheck);
2303 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
2304 }
2305
CallWithTimer(const CallSignature * cs,GateRef target,GateRef gate,GateRef func,const std::vector<GateRef> & args,Variable * result,Label * exit,const char * comment)2306 void SlowPathLowering::CallWithTimer(const CallSignature *cs, GateRef target, GateRef gate, GateRef func,
2307 const std::vector<GateRef> &args, Variable *result, Label *exit,
2308 const char *comment)
2309 {
2310 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
2311 auto depend = builder_.GetDepend();
2312 result->WriteVariable(builder_.Call(cs, glue_, target, depend, args, gate, comment));
2313 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
2314 builder_.Jump(exit);
2315 }
2316
SelectFastNew(GateRef selectCall,GateRef gate,GateRef func,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,Variable * result,Label * exit)2317 void SlowPathLowering::SelectFastNew(GateRef selectCall, GateRef gate, GateRef func, const std::vector<GateRef> &args,
2318 const std::vector<GateRef> &argsFastCall, Variable *result, Label *exit)
2319 {
2320 Label fastAotCall(&builder_);
2321 Label fastAotCallBridge(&builder_);
2322 Label aotCall(&builder_);
2323 Label aotCallBridge(&builder_);
2324 Label slowCall(&builder_);
2325 const int32_t lableCount = 4;
2326 Label labelBuffer[lableCount] = {fastAotCall, fastAotCallBridge, aotCall, aotCallBridge};
2327 int64_t valueBuffer[lableCount] = {
2328 static_cast<int64_t>(FastCallType::FAST_AOT_CALL),
2329 static_cast<int64_t>(FastCallType::FAST_AOT_CALL_BRIDGE),
2330 static_cast<int64_t>(FastCallType::AOT_CALL),
2331 static_cast<int64_t>(FastCallType::AOT_CALL_BRIDGE),
2332 };
2333 if (g_isEnableCMCGC) {
2334 Label needReadBarrier(&builder_);
2335 Label skipReadBarrier(&builder_);
2336
2337 BRANCH_CIR_LIKELY(builder_.NeedSkipReadBarrier(glue_), &skipReadBarrier, &needReadBarrier);
2338
2339 builder_.Bind(&needReadBarrier);
2340 {
2341 builder_.CallNGCRuntime(glue_, RTSTUB_ID(CopyCallTarget), Gate::InvalidGateRef, {glue_, func}, glue_);
2342 builder_.Jump(&skipReadBarrier);
2343 }
2344
2345 builder_.Bind(&skipReadBarrier);
2346 }
2347 builder_.Switch(selectCall, &slowCall, valueBuffer, labelBuffer, lableCount);
2348 builder_.Bind(&fastAotCall);
2349 {
2350 const CallSignature *cs = RuntimeStubCSigns::GetOptimizedFastCallSign();
2351 GateRef code = builder_.GetCodeAddr(func);
2352 CallWithTimer(cs, code, gate, func, argsFastCall, result, exit, "callFastAOT");
2353 }
2354 builder_.Bind(&fastAotCallBridge);
2355 {
2356 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(OptimizedFastCallAndPushArgv));
2357 GateRef target = builder_.IntPtr(RTSTUB_ID(OptimizedFastCallAndPushArgv));
2358 CallWithTimer(cs, target, gate, func, args, result, exit, "callFastBridge");
2359 }
2360 builder_.Bind(&aotCall);
2361 {
2362 const CallSignature *cs = RuntimeStubCSigns::GetOptimizedCallSign();
2363 GateRef code = builder_.GetCodeAddr(func);
2364 CallWithTimer(cs, code, gate, func, args, result, exit, "callAOT");
2365 }
2366 builder_.Bind(&aotCallBridge);
2367 {
2368 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(OptimizedCallAndPushArgv));
2369 GateRef target = builder_.IntPtr(RTSTUB_ID(OptimizedCallAndPushArgv));
2370 CallWithTimer(cs, target, gate, func, args, result, exit, "callBridge");
2371 }
2372 builder_.Bind(&slowCall);
2373 {
2374 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCallNew));
2375 GateRef target = builder_.IntPtr(RTSTUB_ID(JSCallNew));
2376 CallWithTimer(cs, target, gate, func, args, result, exit, "slowNew");
2377 }
2378 }
2379
IsDependIfStateMent(GateRef gate,size_t idx)2380 bool SlowPathLowering::IsDependIfStateMent(GateRef gate, size_t idx)
2381 {
2382 return ((acc_.GetOpCode(gate) == OpCode::DEPEND_SELECTOR) || (acc_.GetOpCode(gate) == OpCode::DEPEND_RELAY)) &&
2383 (idx > 0 && (acc_.GetOpCode(acc_.GetIn(acc_.GetIn(gate, 0), idx - 1)) != OpCode::IF_EXCEPTION));
2384 }
2385
LowerConditionJump(GateRef gate,bool isEqualJump)2386 void SlowPathLowering::LowerConditionJump(GateRef gate, bool isEqualJump)
2387 {
2388 GateRef value = acc_.GetValueIn(gate, 0);
2389 Label ifTrue(&builder_);
2390 Label ifFalse(&builder_);
2391
2392 // GET_ACC().IsFalse()
2393 Label needIntCheck(&builder_);
2394 Label &checkTrue = (isEqualJump ? ifTrue : needIntCheck);
2395 Label &checkFalse = (isEqualJump ? needIntCheck : ifTrue);
2396 BRANCH_CIR(builder_.IsSpecial(value, JSTaggedValue::VALUE_FALSE), &checkTrue, &checkFalse);
2397 builder_.Bind(&needIntCheck);
2398 {
2399 // (GET_ACC().IsInt() && GET_ACC().GetInt() == 0)
2400 Label isInt(&builder_);
2401 Label needDoubleCheck(&builder_);
2402 BRANCH_CIR(builder_.TaggedIsInt(value), &isInt, &needDoubleCheck);
2403 builder_.Bind(&isInt);
2404 checkTrue = (isEqualJump ? ifTrue : needDoubleCheck);
2405 checkFalse = (isEqualJump ? needDoubleCheck : ifTrue);
2406 BRANCH_CIR(builder_.Equal(builder_.TaggedGetInt(value), builder_.Int32(0)), &checkTrue, &checkFalse);
2407 builder_.Bind(&needDoubleCheck);
2408 {
2409 // (GET_ACC().IsDouble() && GET_ACC().GetDouble() == 0.0)
2410 Label isDouble(&builder_);
2411 BRANCH_CIR(builder_.TaggedIsDouble(value), &isDouble, &ifFalse);
2412 builder_.Bind(&isDouble);
2413 checkTrue = (isEqualJump ? ifTrue : ifFalse);
2414 checkFalse = (isEqualJump ? ifFalse : ifTrue);
2415 BRANCH_CIR(builder_.Equal(builder_.GetDoubleOfTDouble(value), builder_.Double(0.0)),
2416 &checkTrue, &checkFalse);
2417 builder_.Bind(&ifFalse);
2418 }
2419 }
2420 builder_.Bind(&ifTrue);
2421
2422 auto uses = acc_.Uses(gate);
2423 for (auto it = uses.begin(); it != uses.end();) {
2424 if (acc_.GetOpCode(*it) == OpCode::IF_TRUE) {
2425 acc_.SetMetaData(*it, circuit_->OrdinaryBlock());
2426 it = acc_.ReplaceIn(it, ifTrue.GetControl());
2427 } else if (acc_.GetOpCode(*it) == OpCode::IF_FALSE) {
2428 acc_.SetMetaData(*it, circuit_->OrdinaryBlock());
2429 it = acc_.ReplaceIn(it, ifFalse.GetControl());
2430 } else if (IsDependIfStateMent(*it, it.GetIndex())) {
2431 it = acc_.ReplaceIn(it, acc_.GetDep(gate));
2432 } else {
2433 LOG_ECMA(FATAL) << "this branch is unreachable";
2434 UNREACHABLE();
2435 }
2436 }
2437 // delete old gate
2438 acc_.DeleteGate(gate);
2439 }
2440
LowerGetNextPropName(GateRef gate)2441 void SlowPathLowering::LowerGetNextPropName(GateRef gate)
2442 {
2443 // 1: number of value inputs
2444 ASSERT(acc_.GetNumValueIn(gate) == 1);
2445 GateRef iter = acc_.GetValueIn(gate, 0);
2446
2447 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2448
2449 Label notFinish(&builder_);
2450 Label notEnumCacheValid(&builder_);
2451 Label fastGetKey(&builder_);
2452 Label slowpath(&builder_);
2453 Label exit(&builder_);
2454
2455 GateRef index = builder_.GetIndexFromForInIterator(iter);
2456 GateRef length = builder_.GetLengthFromForInIterator(iter);
2457 BRANCH_CIR(builder_.Int32GreaterThanOrEqual(index, length), &exit, ¬Finish);
2458 builder_.Bind(¬Finish);
2459 GateRef keys = builder_.GetKeysFromForInIterator(glue_, iter);
2460 GateRef receiver = builder_.GetObjectFromForInIterator(glue_, iter);
2461 GateRef cachedHClass = builder_.GetCachedHClassFromForInIterator(glue_, iter);
2462 GateRef kind = builder_.GetCacheKindFromForInIterator(iter);
2463 BRANCH_CIR(builder_.IsEnumCacheValid(glue_, receiver, cachedHClass, kind), &fastGetKey, ¬EnumCacheValid);
2464 builder_.Bind(¬EnumCacheValid);
2465 BRANCH_CIR(builder_.NeedCheckProperty(glue_, receiver), &slowpath, &fastGetKey);
2466 builder_.Bind(&fastGetKey);
2467 {
2468 result = builder_.GetValueFromTaggedArray(glue_, keys, index);
2469 builder_.IncreaseIteratorIndex(glue_, iter, index);
2470 builder_.Jump(&exit);
2471 }
2472 builder_.Bind(&slowpath);
2473 {
2474 result = LowerCallRuntime(gate, RTSTUB_ID(GetNextPropNameSlowpath), { iter }, true);
2475 builder_.Jump(&exit);
2476 }
2477
2478 builder_.Bind(&exit);
2479 ReplaceHirWithValue(gate, *result);
2480 }
2481
LowerCopyDataProperties(GateRef gate)2482 void SlowPathLowering::LowerCopyDataProperties(GateRef gate)
2483 {
2484 const int id = RTSTUB_ID(CopyDataProperties);
2485 // 2: number of value inputs
2486 ASSERT(acc_.GetNumValueIn(gate) == 2);
2487 GateRef dst = acc_.GetValueIn(gate, 0);
2488 GateRef src = acc_.GetValueIn(gate, 1);
2489 GateRef newGate = LowerCallRuntime(gate, id, { dst, src });
2490 ReplaceHirWithValue(gate, newGate);
2491 }
2492
LowerCreateObjectWithExcludedKeys(GateRef gate)2493 void SlowPathLowering::LowerCreateObjectWithExcludedKeys(GateRef gate)
2494 {
2495 const int id = RTSTUB_ID(OptCreateObjectWithExcludedKeys);
2496 // 2: number of value inputs
2497 ASSERT(acc_.GetNumValueIn(gate) >= 2);
2498 size_t numIn = acc_.GetNumValueIn(gate);
2499 std::vector<GateRef> args;
2500 for (size_t idx = 0; idx < numIn; idx++) {
2501 GateRef tmpGate = acc_.GetValueIn(gate, idx);
2502 args.emplace_back(tmpGate);
2503 }
2504 GateRef newGate = LowerCallRuntime(gate, id, args);
2505 ReplaceHirWithValue(gate, newGate);
2506 }
2507
LowerCreateRegExpWithLiteral(GateRef gate)2508 void SlowPathLowering::LowerCreateRegExpWithLiteral(GateRef gate)
2509 {
2510 const int id = RTSTUB_ID(CreateRegExpWithLiteral);
2511 // 2: number of value inputs
2512 ASSERT(acc_.GetNumValueIn(gate) == 2);
2513 GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
2514 GateRef pattern = GetStringFromConstPool(gate, stringId);
2515 GateRef flags = acc_.GetValueIn(gate, 1);
2516 GateRef newGate = LowerCallRuntime(gate, id, { pattern, builder_.ToTaggedInt(flags) }, true);
2517 ReplaceHirWithValue(gate, newGate);
2518 }
2519
LowerStOwnByValue(GateRef gate)2520 void SlowPathLowering::LowerStOwnByValue(GateRef gate)
2521 {
2522 // 3: number of value inputs
2523 ASSERT(acc_.GetNumValueIn(gate) == 3);
2524 GateRef receiver = acc_.GetValueIn(gate, 0);
2525 GateRef propKey = acc_.GetValueIn(gate, 1);
2526 GateRef accValue = acc_.GetValueIn(gate, 2);
2527 // we do not need to merge outValueGate, so using GateRef directly instead of using Variable
2528 GateRef holeConst = builder_.HoleConstant();
2529 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
2530 result = builder_.CallStub(glue_, gate, CommonStubCSigns::StOwnByValue,
2531 {glue_, receiver, propKey, accValue, circuit_->GetGlobalEnvCache()});
2532 ReplaceHirWithValue(gate, *result);
2533 }
2534
LowerStOwnByIndex(GateRef gate)2535 void SlowPathLowering::LowerStOwnByIndex(GateRef gate)
2536 {
2537 // 3: number of value inputs
2538 ASSERT(acc_.GetNumValueIn(gate) == 3);
2539 GateRef receiver = acc_.GetValueIn(gate, 0);
2540 GateRef index = acc_.GetValueIn(gate, 1);
2541 GateRef accValue = acc_.GetValueIn(gate, 2);
2542 // we do not need to merge outValueGate, so using GateRef directly instead of using Variable
2543 GateRef holeConst = builder_.HoleConstant();
2544 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
2545 result = builder_.CallStub(
2546 glue_, gate, CommonStubCSigns::StOwnByIndex,
2547 {glue_, receiver, builder_.TruncInt64ToInt32(index), accValue, circuit_->GetGlobalEnvCache()});
2548 ReplaceHirWithValue(gate, *result);
2549 }
2550
LowerStOwnByName(GateRef gate)2551 void SlowPathLowering::LowerStOwnByName(GateRef gate)
2552 {
2553 // 3: number of value inputs
2554 ASSERT(acc_.GetNumValueIn(gate) == 3);
2555 GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
2556 GateRef propKey = GetStringFromConstPool(gate, stringId);
2557 GateRef receiver = acc_.GetValueIn(gate, 1);
2558 GateRef accValue = acc_.GetValueIn(gate, 2);
2559 // we do not need to merge outValueGate, so using GateRef directly instead of using Variable
2560 GateRef holeConst = builder_.HoleConstant();
2561 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), holeConst);
2562 result = builder_.CallStub(glue_, gate, CommonStubCSigns::StOwnByName,
2563 {glue_, receiver, propKey, accValue, circuit_->GetGlobalEnvCache()});
2564 ReplaceHirWithValue(gate, *result);
2565 }
2566
LowerNewLexicalEnv(GateRef gate)2567 void SlowPathLowering::LowerNewLexicalEnv(GateRef gate)
2568 {
2569 // 2: number of value inputs
2570 ASSERT(acc_.GetNumValueIn(gate) == 2);
2571 GateRef lexEnv = acc_.GetValueIn(gate, 1);
2572 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::NewLexicalEnv,
2573 { glue_, lexEnv, builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0)) });
2574 ReplaceHirWithValue(gate, result);
2575 }
2576
LowerNewLexicalEnvWithName(GateRef gate)2577 void SlowPathLowering::LowerNewLexicalEnvWithName(GateRef gate)
2578 {
2579 // 3: number of value inputs
2580 ASSERT(acc_.GetNumValueIn(gate) == 3);
2581 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2582 GateRef lexEnv = acc_.GetValueIn(gate, 2); // 2: Get current lexEnv
2583 auto args = { builder_.ToTaggedInt(acc_.GetValueIn(gate, 0)),
2584 builder_.ToTaggedInt(acc_.GetValueIn(gate, 1)),
2585 lexEnv, jsFunc };
2586 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(OptNewLexicalEnvWithName), args, true);
2587 ReplaceHirWithValue(gate, result);
2588 }
2589
LowerNewSendableEnv(GateRef gate)2590 void SlowPathLowering::LowerNewSendableEnv(GateRef gate)
2591 {
2592 // 2: number of value inputs
2593 ASSERT(acc_.GetNumValueIn(gate) == 1);
2594 auto args = { builder_.ToTaggedInt(acc_.GetValueIn(gate, 0)) };
2595 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(NewSendableEnv), args, true);
2596 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2597 GateRef module = builder_.GetModuleFromFunction(glue_, jsFunc);
2598 builder_.SetSendableEnvToModule(glue_, module, result);
2599 ReplaceHirWithValue(gate, result);
2600 }
2601
LowerPopLexicalEnv(GateRef gate)2602 void SlowPathLowering::LowerPopLexicalEnv(GateRef gate)
2603 {
2604 GateRef currentEnv = acc_.GetValueIn(gate, 0);
2605 GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
2606 GateRef parentEnv = builder_.GetValueFromTaggedArray(glue_, currentEnv, index);
2607 ReplaceHirWithValue(gate, parentEnv);
2608 }
2609
LowerLdSuperByValue(GateRef gate)2610 void SlowPathLowering::LowerLdSuperByValue(GateRef gate)
2611 {
2612 const int id = RTSTUB_ID(OptLdSuperByValue);
2613 // 2: number of value inputs
2614 ASSERT(acc_.GetNumValueIn(gate) == 2);
2615 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2616 GateRef receiver = acc_.GetValueIn(gate, 0);
2617 GateRef propKey = acc_.GetValueIn(gate, 1);
2618 GateRef newGate = LowerCallRuntime(gate, id, { receiver, propKey, jsFunc });
2619 ReplaceHirWithValue(gate, newGate);
2620 }
2621
LowerStSuperByValue(GateRef gate)2622 void SlowPathLowering::LowerStSuperByValue(GateRef gate)
2623 {
2624 const int id = RTSTUB_ID(OptStSuperByValue);
2625 // 3: number of value inputs
2626 ASSERT(acc_.GetNumValueIn(gate) == 3);
2627 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2628 GateRef receiver = acc_.GetValueIn(gate, 0);
2629 GateRef propKey = acc_.GetValueIn(gate, 1);
2630 GateRef value = acc_.GetValueIn(gate, 2);
2631 GateRef newGate = LowerCallRuntime(gate, id, { receiver, propKey, value, jsFunc});
2632 ReplaceHirWithValue(gate, newGate);
2633 }
2634
LowerTryStGlobalByName(GateRef gate)2635 void SlowPathLowering::LowerTryStGlobalByName(GateRef gate)
2636 {
2637 // 3: number of value inputs
2638 ASSERT(acc_.GetNumValueIn(gate) == 3);
2639 GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
2640 GateRef value = acc_.GetValueIn(gate, 2); // 2: the 2nd para is value
2641 LowerCallStubWithIC(gate, CommonStubCSigns::TryStGlobalByName, {stringId, value, circuit_->GetGlobalEnvCache()});
2642 }
2643
LowerStConstToGlobalRecord(GateRef gate,bool isConst)2644 void SlowPathLowering::LowerStConstToGlobalRecord(GateRef gate, bool isConst)
2645 {
2646 GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
2647 GateRef propKey = GetStringFromConstPool(gate, stringId);
2648 acc_.SetDep(gate, propKey);
2649 // 2 : number of value inputs
2650 ASSERT(acc_.GetNumValueIn(gate) == 2);
2651 const int id = RTSTUB_ID(StGlobalRecord);
2652 GateRef value = acc_.GetValueIn(gate, 1);
2653 GateRef isConstGate = isConst ? builder_.TaggedTrue() : builder_.TaggedFalse();
2654 GateRef result = LowerCallRuntime(gate, id, { propKey, value, isConstGate }, true);
2655 ReplaceHirWithValue(gate, result);
2656 }
2657
LowerStOwnByValueWithNameSet(GateRef gate)2658 void SlowPathLowering::LowerStOwnByValueWithNameSet(GateRef gate)
2659 {
2660 // 3: number of value inputs
2661 ASSERT(acc_.GetNumValueIn(gate) == 3);
2662 GateRef receiver = acc_.GetValueIn(gate, 0);
2663 GateRef propKey = acc_.GetValueIn(gate, 1);
2664 GateRef accValue = acc_.GetValueIn(gate, 2);
2665 Label successExit(&builder_);
2666 Label exceptionExit(&builder_);
2667 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::StOwnByValueWithNameSet,
2668 {glue_, receiver, propKey, accValue, circuit_->GetGlobalEnvCache()});
2669 BRANCH_CIR(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
2670 &exceptionExit, &successExit);
2671 CREATE_DOUBLE_EXIT(successExit, exceptionExit)
2672 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
2673 }
2674
LowerStOwnByNameWithNameSet(GateRef gate)2675 void SlowPathLowering::LowerStOwnByNameWithNameSet(GateRef gate)
2676 {
2677 // 3: number of value inputs
2678 ASSERT(acc_.GetNumValueIn(gate) == 3);
2679 GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
2680 GateRef propKey = GetStringFromConstPool(gate, stringId);
2681 GateRef receiver = acc_.GetValueIn(gate, 1);
2682 GateRef accValue = acc_.GetValueIn(gate, 2);
2683 Label successExit(&builder_);
2684 Label exceptionExit(&builder_);
2685 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::StOwnByNameWithNameSet,
2686 {glue_, receiver, propKey, accValue, circuit_->GetGlobalEnvCache()});
2687 BRANCH_CIR(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
2688 &exceptionExit, &successExit);
2689 CREATE_DOUBLE_EXIT(successExit, exceptionExit)
2690 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, Circuit::NullGate());
2691 }
2692
LowerLdGlobalVar(GateRef gate)2693 void SlowPathLowering::LowerLdGlobalVar(GateRef gate)
2694 {
2695 // 2: number of value inputs
2696 ASSERT(acc_.GetNumValueIn(gate) == 2);
2697 GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
2698 LowerCallStubWithIC(gate, CommonStubCSigns::LdGlobalVar, {stringId, circuit_->GetGlobalEnvCache()});
2699 }
2700
enableMegaIC(GateRef gate)2701 bool SlowPathLowering::enableMegaIC(GateRef gate)
2702 {
2703 // AOT is currently not enabled, but will be enabled later.
2704 return compilationEnv_->GetJSOptions().IsEnableMegaIC() && compilationEnv_->IsJitCompiler() &&
2705 acc_.TryGetMegaProp(gate);
2706 }
2707
LowerLdObjByName(GateRef gate)2708 void SlowPathLowering::LowerLdObjByName(GateRef gate)
2709 {
2710 // 3: number of value inputs
2711 ASSERT(acc_.GetNumValueIn(gate) == 3);
2712 GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
2713 GateRef receiver = acc_.GetValueIn(gate, 2); // 2: the thi+rd parameter
2714 if (enableMegaIC(gate)) {
2715 // The JIT will assume that the cache will not change and that the String is always present in the constantPool.
2716 auto cache = builder_.IntPtr((int64_t)(compilationEnv_->GetHostThread()->GetLoadMegaICCache()));
2717 GateRef sharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
2718 GateRef prop = builder_.GetValueFromTaggedArray(glue_, sharedConstPool, builder_.TruncInt64ToInt32(stringId));
2719 LowerCallStubWithIC(gate, CommonStubCSigns::GetPropertyByNameWithMega,
2720 {receiver, stringId, cache, prop, circuit_->GetGlobalEnvCache()});
2721 } else {
2722 LowerCallStubWithIC(gate, CommonStubCSigns::GetPropertyByName,
2723 {receiver, stringId, circuit_->GetGlobalEnvCache()});
2724 }
2725 }
2726
LowerStObjByName(GateRef gate,bool isThis)2727 void SlowPathLowering::LowerStObjByName(GateRef gate, bool isThis)
2728 {
2729 GateRef receiver;
2730 GateRef value;
2731 if (isThis) {
2732 ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: number of value inputs
2733 receiver = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
2734 value = acc_.GetValueIn(gate, 2); // 2: the third para is value
2735 } else {
2736 ASSERT(acc_.GetNumValueIn(gate) == 4); // 4: number of value inputs
2737 receiver = acc_.GetValueIn(gate, 2); // 2: the third para is receiver
2738 value = acc_.GetValueIn(gate, 3); // 3: the 4th para is value
2739 }
2740 GateRef stringId = acc_.GetValueIn(gate, 1); // 1: the second parameter
2741 if (enableMegaIC(gate)) {
2742 // The JIT will assume that the cache will not change and that the String is always present in the constantPool.
2743 auto cache = builder_.IntPtr((int64_t)(compilationEnv_->GetHostThread()->GetStoreMegaICCache()));
2744 GateRef sharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
2745 GateRef prop = builder_.GetValueFromTaggedArray(glue_, sharedConstPool, builder_.TruncInt64ToInt32(stringId));
2746 LowerCallStubWithIC(gate, CommonStubCSigns::SetPropertyByNameWithMega,
2747 {receiver, stringId, value, cache, prop, circuit_->GetGlobalEnvCache()});
2748 } else {
2749 LowerCallStubWithIC(gate, CommonStubCSigns::SetPropertyByName,
2750 {receiver, stringId, value, circuit_->GetGlobalEnvCache()});
2751 }
2752 }
2753
LowerDefineGetterSetterByValue(GateRef gate)2754 void SlowPathLowering::LowerDefineGetterSetterByValue(GateRef gate)
2755 {
2756 const int id = RTSTUB_ID(DefineGetterSetterByValue);
2757 // 5: number of value inputs
2758 ASSERT(acc_.GetNumValueIn(gate) == 5);
2759 GateRef obj = acc_.GetValueIn(gate, 0);
2760 GateRef prop = acc_.GetValueIn(gate, 1);
2761 GateRef getter = acc_.GetValueIn(gate, 2);
2762 GateRef setter = acc_.GetValueIn(gate, 3);
2763 GateRef acc = acc_.GetValueIn(gate, 4);
2764 auto args = { obj, prop, getter, setter, acc,
2765 builder_.UndefineConstant(), builder_.Int32ToTaggedInt(builder_.Int32(1)) };
2766 GateRef result = LowerCallRuntime(gate, id, args);
2767 ReplaceHirWithValue(gate, result);
2768 }
2769
LowerLdObjByIndex(GateRef gate)2770 void SlowPathLowering::LowerLdObjByIndex(GateRef gate)
2771 {
2772 // 2: number of value inputs
2773 ASSERT(acc_.GetNumValueIn(gate) == 2);
2774 GateRef holeConst = builder_.HoleConstant();
2775 DEFVALUE(varAcc, (&builder_), VariableType::JS_ANY(), holeConst);
2776 GateRef index = acc_.GetValueIn(gate, 0);
2777 GateRef receiver = acc_.GetValueIn(gate, 1);
2778 varAcc = builder_.CallStub(glue_, gate, CommonStubCSigns::LdObjByIndex,
2779 {glue_, receiver, builder_.TruncInt64ToInt32(index), circuit_->GetGlobalEnvCache()});
2780 ReplaceHirWithValue(gate, *varAcc);
2781 }
2782
LowerStObjByIndex(GateRef gate)2783 void SlowPathLowering::LowerStObjByIndex(GateRef gate)
2784 {
2785 // 3: number of value inputs
2786 ASSERT(acc_.GetNumValueIn(gate) == 3);
2787 GateRef receiver = acc_.GetValueIn(gate, 0);
2788 GateRef index = acc_.GetValueIn(gate, 1);
2789 GateRef accValue = acc_.GetValueIn(gate, 2);
2790 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
2791 result = builder_.CallStub(
2792 glue_, gate, CommonStubCSigns::StObjByIndex,
2793 {glue_, receiver, builder_.TruncInt64ToInt32(index), accValue, circuit_->GetGlobalEnvCache()});
2794 ReplaceHirWithValue(gate, *result);
2795 }
2796
LowerLdObjByValue(GateRef gate,bool isThis)2797 void SlowPathLowering::LowerLdObjByValue(GateRef gate, bool isThis)
2798 {
2799 GateRef receiver;
2800 GateRef propKey;
2801 if (isThis) {
2802 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: number of value inputs
2803 receiver = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
2804 propKey = acc_.GetValueIn(gate, 1);
2805 } else {
2806 ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: number of value inputs
2807 receiver = acc_.GetValueIn(gate, 1);
2808 propKey = acc_.GetValueIn(gate, 2); // 2: the third parameter
2809 }
2810 LowerCallStubWithIC(gate, CommonStubCSigns::GetPropertyByValue, {receiver, propKey, circuit_->GetGlobalEnvCache()});
2811 }
2812
LowerStObjByValue(GateRef gate,bool isThis)2813 void SlowPathLowering::LowerStObjByValue(GateRef gate, bool isThis)
2814 {
2815 GateRef receiver;
2816 GateRef propKey;
2817 GateRef value;
2818 if (isThis) {
2819 ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: number of value inputs
2820 receiver = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
2821 propKey = acc_.GetValueIn(gate, 1);
2822 value = acc_.GetValueIn(gate, 2); // 2: the third parameter
2823 } else {
2824 // 4: number of value inputs
2825 ASSERT(acc_.GetNumValueIn(gate) == 4);
2826 receiver = acc_.GetValueIn(gate, 1);
2827 propKey = acc_.GetValueIn(gate, 2); // 2: the third parameter
2828 value = acc_.GetValueIn(gate, 3); // 3: the 4th parameter
2829 }
2830 LowerCallStubWithIC(gate, CommonStubCSigns::SetPropertyByValue,
2831 {receiver, propKey, value, circuit_->GetGlobalEnvCache()});
2832 }
2833
LowerLdSuperByName(GateRef gate)2834 void SlowPathLowering::LowerLdSuperByName(GateRef gate)
2835 {
2836 // 2: number of value inputs
2837 ASSERT(acc_.GetNumValueIn(gate) == 2);
2838 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2839 GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
2840 GateRef prop = GetStringFromConstPool(gate, stringId);
2841 GateRef result =
2842 LowerCallRuntime(gate, RTSTUB_ID(OptLdSuperByValue), {acc_.GetValueIn(gate, 1), prop, jsFunc}, true);
2843 ReplaceHirWithValue(gate, result);
2844 }
2845
LowerStSuperByName(GateRef gate)2846 void SlowPathLowering::LowerStSuperByName(GateRef gate)
2847 {
2848 // 3: number of value inputs
2849 ASSERT(acc_.GetNumValueIn(gate) == 3);
2850 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2851 GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
2852 GateRef prop = GetStringFromConstPool(gate, stringId);
2853 auto args2 = { acc_.GetValueIn(gate, 1), prop, acc_.GetValueIn(gate, 2), jsFunc };
2854 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(OptStSuperByValue), args2, true);
2855 ReplaceHirWithValue(gate, result);
2856 }
2857
LowerCreateGeneratorObj(GateRef gate)2858 void SlowPathLowering::LowerCreateGeneratorObj(GateRef gate)
2859 {
2860 const int id = RTSTUB_ID(CreateGeneratorObj);
2861 // 1: number of value inputs
2862 ASSERT(acc_.GetNumValueIn(gate) == 1);
2863 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)});
2864 ReplaceHirWithValue(gate, newGate);
2865 }
2866
LowerCreateAsyncGeneratorObj(GateRef gate)2867 void SlowPathLowering::LowerCreateAsyncGeneratorObj(GateRef gate)
2868 {
2869 int id = RTSTUB_ID(CreateAsyncGeneratorObj);
2870 // 1: number of value inputs
2871 ASSERT(acc_.GetNumValueIn(gate) == 1);
2872 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0)});
2873 ReplaceHirWithValue(gate, newGate);
2874 }
2875
LowerAsyncGeneratorResolve(GateRef gate)2876 void SlowPathLowering::LowerAsyncGeneratorResolve(GateRef gate)
2877 {
2878 SaveFrameToContext(gate);
2879 acc_.SetDep(gate, builder_.GetDepend());
2880 int id = RTSTUB_ID(OptAsyncGeneratorResolve);
2881 GateRef asyncGen = acc_.GetValueIn(gate, 1);
2882 GateRef value = acc_.GetValueIn(gate, 2);
2883 GateRef flag = acc_.GetValueIn(gate, 3);
2884 GateRef newGate = LowerCallRuntime(gate, id, {asyncGen, value, flag});
2885 ReplaceHirWithValue(gate, newGate);
2886 }
2887
LowerAsyncGeneratorReject(GateRef gate)2888 void SlowPathLowering::LowerAsyncGeneratorReject(GateRef gate)
2889 {
2890 int id = RTSTUB_ID(AsyncGeneratorReject);
2891 // 2: number of value inputs
2892 ASSERT(acc_.GetNumValueIn(gate) == 2);
2893 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
2894 ReplaceHirWithValue(gate, newGate);
2895 }
2896
LowerStArraySpread(GateRef gate)2897 void SlowPathLowering::LowerStArraySpread(GateRef gate)
2898 {
2899 const int id = RTSTUB_ID(StArraySpread);
2900 // 3: number of value inputs
2901 ASSERT(acc_.GetNumValueIn(gate) == 3);
2902 auto args = { acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2) };
2903 GateRef newGate = LowerCallRuntime(gate, id, args);
2904 ReplaceHirWithValue(gate, newGate);
2905 }
2906
LowerLdLexVar(GateRef gate)2907 void SlowPathLowering::LowerLdLexVar(GateRef gate)
2908 {
2909 // 3: number of value inputs
2910 ASSERT(acc_.GetNumValueIn(gate) == 3);
2911 GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
2912 GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
2913 DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 2)); // 2: Get current lexEnv
2914 GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
2915 Label exit(&builder_);
2916 uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
2917 if (constLevel == 0) {
2918 builder_.Jump(&exit);
2919 } else if (constLevel == 1) {
2920 currentEnv = builder_.GetValueFromTaggedArray(glue_, *currentEnv, index);
2921 builder_.Jump(&exit);
2922 } else {
2923 DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
2924 Label loopHead(&builder_);
2925 Label loopEnd(&builder_);
2926 BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopHead, &exit);
2927 builder_.LoopBegin(&loopHead);
2928 currentEnv = builder_.GetValueFromTaggedArray(glue_, *currentEnv, index);
2929 i = builder_.Int32Add(*i, builder_.Int32(1));
2930 BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopEnd, &exit);
2931 builder_.Bind(&loopEnd);
2932 builder_.LoopEnd(&loopHead);
2933 }
2934 builder_.Bind(&exit);
2935 GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(LexicalEnv::RESERVED_ENV_LENGTH));
2936 GateRef result = builder_.GetValueFromTaggedArray(glue_, *currentEnv, valueIndex);
2937 ReplaceHirWithValue(gate, result);
2938 }
2939
LowerLdSendableVar(GateRef gate)2940 void SlowPathLowering::LowerLdSendableVar(GateRef gate)
2941 {
2942 // 2: number of value inputs
2943 ASSERT(acc_.GetNumValueIn(gate) == 2);
2944 GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
2945 GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
2946 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2947 GateRef module = builder_.GetModuleFromFunction(glue_, jsFunc);
2948 DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), builder_.GetSendableEnvFromModule(glue_, module));
2949 GateRef index = builder_.Int32(SendableEnv::SENDABLE_PARENT_ENV_INDEX);
2950 Label exit(&builder_);
2951 uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
2952 if (constLevel == 0) {
2953 builder_.Jump(&exit);
2954 } else if (constLevel == 1) {
2955 currentEnv = builder_.GetValueFromTaggedArray(glue_, *currentEnv, index);
2956 builder_.Jump(&exit);
2957 } else {
2958 DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
2959 Label loopHead(&builder_);
2960 Label loopEnd(&builder_);
2961 BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopHead, &exit);
2962 builder_.LoopBegin(&loopHead);
2963 currentEnv = builder_.GetValueFromTaggedArray(glue_, *currentEnv, index);
2964 i = builder_.Int32Add(*i, builder_.Int32(1));
2965 BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopEnd, &exit);
2966 builder_.Bind(&loopEnd);
2967 builder_.LoopEnd(&loopHead);
2968 }
2969 builder_.Bind(&exit);
2970 GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(SendableEnv::SENDABLE_RESERVED_ENV_LENGTH));
2971 GateRef result = builder_.GetValueFromTaggedArray(glue_, *currentEnv, valueIndex);
2972 ReplaceHirWithValue(gate, result);
2973 }
2974
LowerStLexVar(GateRef gate)2975 void SlowPathLowering::LowerStLexVar(GateRef gate)
2976 {
2977 // 4: number of value inputs
2978 ASSERT(acc_.GetNumValueIn(gate) == 4);
2979 GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
2980 GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
2981 GateRef value = acc_.GetValueIn(gate, 3);
2982 DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), acc_.GetValueIn(gate, 2)); // 2: Get current lexEnv
2983 GateRef index = builder_.Int32(LexicalEnv::PARENT_ENV_INDEX);
2984 Label exit(&builder_);
2985 uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
2986 if (constLevel == 0) {
2987 builder_.Jump(&exit);
2988 } else if (constLevel == 1) {
2989 currentEnv = builder_.GetValueFromTaggedArray(glue_, *currentEnv, index);
2990 builder_.Jump(&exit);
2991 } else {
2992 DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
2993 Label loopHead(&builder_);
2994 Label loopEnd(&builder_);
2995 BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopHead, &exit);
2996 builder_.LoopBegin(&loopHead);
2997 currentEnv = builder_.GetValueFromTaggedArray(glue_, *currentEnv, index);
2998 i = builder_.Int32Add(*i, builder_.Int32(1));
2999 BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopEnd, &exit);
3000 builder_.Bind(&loopEnd);
3001 builder_.LoopEnd(&loopHead);
3002 }
3003 builder_.Bind(&exit);
3004 GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(LexicalEnv::RESERVED_ENV_LENGTH));
3005 builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue_, *currentEnv, valueIndex, value);
3006 auto result = *currentEnv;
3007 ReplaceHirWithValue(gate, result);
3008 }
3009
LowerStSendableVar(GateRef gate)3010 void SlowPathLowering::LowerStSendableVar(GateRef gate)
3011 {
3012 // 3: number of value inputs
3013 ASSERT(acc_.GetNumValueIn(gate) == 3);
3014 GateRef level = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
3015 GateRef slot = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
3016 GateRef value = acc_.GetValueIn(gate, 2);
3017 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
3018 GateRef module = builder_.GetModuleFromFunction(glue_, jsFunc);
3019 DEFVALUE(currentEnv, (&builder_), VariableType::JS_ANY(), builder_.GetSendableEnvFromModule(glue_, module));
3020 GateRef index = builder_.Int32(SendableEnv::SENDABLE_PARENT_ENV_INDEX);
3021 Label exit(&builder_);
3022 uint64_t constLevel = acc_.TryGetValue(acc_.GetValueIn(gate, 0));
3023 if (constLevel == 0) {
3024 builder_.Jump(&exit);
3025 } else if (constLevel == 1) {
3026 currentEnv = builder_.GetValueFromTaggedArray(glue_, *currentEnv, index);
3027 builder_.Jump(&exit);
3028 } else {
3029 DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
3030 Label loopHead(&builder_);
3031 Label loopEnd(&builder_);
3032 BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopHead, &exit);
3033 builder_.LoopBegin(&loopHead);
3034 currentEnv = builder_.GetValueFromTaggedArray(glue_, *currentEnv, index);
3035 i = builder_.Int32Add(*i, builder_.Int32(1));
3036 BRANCH_CIR(builder_.Int32LessThan(*i, level), &loopEnd, &exit);
3037 builder_.Bind(&loopEnd);
3038 builder_.LoopEnd(&loopHead);
3039 }
3040 builder_.Bind(&exit);
3041 GateRef valueIndex = builder_.Int32Add(slot, builder_.Int32(SendableEnv::SENDABLE_RESERVED_ENV_LENGTH));
3042 builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue_, *currentEnv, valueIndex, value);
3043 auto result = *currentEnv;
3044 ReplaceHirWithValue(gate, result);
3045 }
3046
LowerDefineClassWithBuffer(GateRef gate)3047 void SlowPathLowering::LowerDefineClassWithBuffer(GateRef gate)
3048 {
3049 ASSERT(acc_.GetNumValueIn(gate) == 6); // 6: number of value inputs
3050 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
3051 GateRef methodId = acc_.GetValueIn(gate, 0);
3052 GateRef literalId = acc_.GetValueIn(gate, 1);
3053 GateRef length = acc_.GetValueIn(gate, 2); // 2: second arg
3054 GateRef proto = acc_.GetValueIn(gate, 3);
3055 GateRef lexicalEnv = acc_.GetValueIn(gate, 4); // 4: Get current env
3056 GateRef sharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
3057 GateRef module = builder_.GetModuleFromFunction(glue_, jsFunc);
3058 Label isException(&builder_);
3059 Label isNotException(&builder_);
3060
3061 GateRef result;
3062 auto args = { proto, lexicalEnv, sharedConstPool,
3063 builder_.ToTaggedInt(methodId), builder_.ToTaggedInt(literalId), module,
3064 builder_.ToTaggedInt(length),
3065 #if ECMASCRIPT_ENABLE_IC
3066 // 5: slot id
3067 builder_.Int32ToTaggedInt(builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 5))), jsFunc
3068 #endif
3069 };
3070 result = LowerCallRuntime(gate, RTSTUB_ID(CreateClassWithBuffer), args, true);
3071 BRANCH_CIR(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION), &isException, &isNotException);
3072 CREATE_DOUBLE_EXIT(isNotException, isException)
3073 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, result);
3074 }
3075
OptimizeDefineFuncForJit(GateRef gate,GateRef jsFunc,GateRef length,GateRef methodId,GateRef lexEnv,GateRef slotId)3076 bool SlowPathLowering::OptimizeDefineFuncForJit(GateRef gate, GateRef jsFunc, GateRef length, GateRef methodId,
3077 GateRef lexEnv, GateRef slotId)
3078 {
3079 if (!compilationEnv_->SupportHeapConstant()) {
3080 return false;
3081 }
3082 Label success(&builder_);
3083 Label failed(&builder_);
3084 if (!acc_.IsConstant(methodId) || !acc_.IsConstant(slotId)) {
3085 return false;
3086 }
3087 auto slotIdValue = acc_.GetConstantValue(slotId);
3088 auto methodIdValue = acc_.GetConstantValue(methodId);
3089 if (slotIdValue == ProfileTypeInfo::INVALID_SLOT_INDEX) {
3090 return false;
3091 }
3092 auto constPool = compilationEnv_->FindConstpool(compilationEnv_->GetJSPandaFile(), 0);
3093 auto unsharedConstPool = compilationEnv_->FindOrCreateUnsharedConstpool(methodLiteral_->GetMethodId().GetOffset());
3094 // not optimize if it may use ihc to define function
3095 if (!unsharedConstPool.IsHole() &&
3096 !ConstantPool::GetIhcFromAOTLiteralInfo(compilationEnv_->GetHostThread(),
3097 unsharedConstPool, methodIdValue).IsUndefined()) {
3098 return false;
3099 }
3100
3101 auto method = ConstantPool::GetMethodFromCache(constPool, methodIdValue, compilationEnv_->GetJSThread());
3102 if (!method.IsMethod()) {
3103 return false;
3104 }
3105 auto methodObj = Method::Cast(method);
3106 if (methodObj->IsSendableMethod() || methodObj->IsNativeWithCallField() || methodObj->IsAotWithCallField()) {
3107 return false;
3108 }
3109 auto kind = methodObj->GetFunctionKind();
3110
3111 auto jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
3112 auto func = jitCompilationEnv->GetJsFunctionByMethodOffset(acc_.TryGetMethodOffset(gate));
3113 auto profileTypeInfo = func->GetProfileTypeInfo(compilationEnv_->GetJSThread());
3114 if (profileTypeInfo.IsUndefined()) {
3115 return false;
3116 }
3117 auto constPoolId =
3118 static_cast<uint32_t>(ConstantPool::Cast(constPool.GetTaggedObject())->GetSharedConstpoolId().GetInt());
3119 auto methodHandle = jitCompilationEnv->NewJSHandle(method);
3120 auto index = jitCompilationEnv->RecordHeapConstant(
3121 {constPoolId, methodIdValue, JitCompilationEnv::IN_SHARED_CONSTANTPOOL}, methodHandle);
3122 GateRef methodNode = builder_.HeapConstant(index);
3123 GateRef result;
3124 JSHandle<JSTaggedValue> hclass;
3125 int callTarget = CommonStubCSigns::NUM_OF_STUBS;
3126 switch (kind) {
3127 case FunctionKind::NORMAL_FUNCTION: {
3128 hclass = compilationEnv_->GetGlobalEnv()->GetFunctionClassWithoutProto();
3129 callTarget = CommonStubCSigns::DefineNormalFuncForJit;
3130 break;
3131 }
3132 case FunctionKind::ARROW_FUNCTION: {
3133 hclass = compilationEnv_->GetGlobalEnv()->GetFunctionClassWithoutProto();
3134 callTarget = CommonStubCSigns::DefineArrowFuncForJit;
3135 break;
3136 }
3137 case FunctionKind::BASE_CONSTRUCTOR: {
3138 hclass = compilationEnv_->GetGlobalEnv()->GetFunctionClassWithProto();
3139 callTarget = CommonStubCSigns::DefineBaseConstructorForJit;
3140 break;
3141 }
3142 default:
3143 return false;
3144 }
3145
3146 result = builder_.CallStub(glue_, gate, callTarget,
3147 {glue_, jsFunc, builder_.TaggedValueConstant(hclass.GetTaggedValue()), methodNode,
3148 builder_.TruncInt64ToInt32(length), lexEnv, slotId});
3149 BRANCH_CIR(builder_.TaggedIsException(result), &failed, &success);
3150 CREATE_DOUBLE_EXIT(success, failed)
3151 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, result);
3152 return true;
3153 }
3154
LowerDefineFunc(GateRef gate)3155 void SlowPathLowering::LowerDefineFunc(GateRef gate)
3156 {
3157 Jit::JitLockHolder lock(compilationEnv_, "SlowPathLowering");
3158 Environment env(gate, circuit_, &builder_);
3159 GateRef methodId = acc_.GetValueIn(gate, 1);
3160
3161 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
3162 GateRef length = acc_.GetValueIn(gate, 2);
3163 GateRef lexEnv = acc_.GetValueIn(gate, 3); // 3: Get current env
3164 GateRef slotId = acc_.GetValueIn(gate, 0);
3165 Label success(&builder_);
3166 Label failed(&builder_);
3167 if (OptimizeDefineFuncForJit(gate, jsFunc, length, methodId, lexEnv, slotId)) {
3168 return;
3169 }
3170
3171 GateRef result =
3172 builder_.CallStub(glue_, gate, CommonStubCSigns::Definefunc,
3173 {glue_, jsFunc, builder_.TruncInt64ToInt32(methodId), builder_.TruncInt64ToInt32(length),
3174 lexEnv, slotId, circuit_->GetGlobalEnvCache()});
3175 BRANCH_CIR(builder_.TaggedIsException(result), &failed, &success);
3176 CREATE_DOUBLE_EXIT(success, failed)
3177 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, result);
3178 }
3179
LowerAsyncFunctionEnter(GateRef gate)3180 void SlowPathLowering::LowerAsyncFunctionEnter(GateRef gate)
3181 {
3182 const int id = RTSTUB_ID(AsyncFunctionEnter);
3183 // 0: number of value inputs
3184 ASSERT(acc_.GetNumValueIn(gate) == 0);
3185 GateRef newGate = LowerCallRuntime(gate, id, {});
3186 ReplaceHirWithValue(gate, newGate);
3187 }
3188
LowerTypeof(GateRef gate)3189 void SlowPathLowering::LowerTypeof(GateRef gate)
3190 {
3191 // 1: number of value inputs
3192 ASSERT(acc_.GetNumValueIn(gate) == 1);
3193 GateRef obj = acc_.GetValueIn(gate, 0);
3194 GateRef result = builder_.CallStub(glue_, gate, CommonStubCSigns::TypeOf, {glue_, obj});
3195 ReplaceHirWithValue(gate, result);
3196 }
3197
GetValueFromTaggedArray(GateRef arrayGate,GateRef indexOffset)3198 GateRef SlowPathLowering::GetValueFromTaggedArray(GateRef arrayGate, GateRef indexOffset)
3199 {
3200 GateRef offset = builder_.PtrMul(builder_.ZExtInt32ToPtr(indexOffset),
3201 builder_.IntPtr(JSTaggedValue::TaggedTypeSize()));
3202 GateRef dataOffset = builder_.PtrAdd(offset, builder_.IntPtr(TaggedArray::DATA_OFFSET));
3203 GateRef value = builder_.Load(VariableType::JS_ANY(), glue_, arrayGate, dataOffset);
3204 return value;
3205 }
3206
LowerStoreRegister(GateRef gate,GateRef arrayGate)3207 void SlowPathLowering::LowerStoreRegister(GateRef gate, GateRef arrayGate)
3208 {
3209 ASSERT((acc_.GetOpCode(gate) == OpCode::RESTORE_REGISTER));
3210 auto index = acc_.GetVirtualRegisterIndex(gate);
3211 auto indexOffset = builder_.Int32(index);
3212 GateRef value = GetValueFromTaggedArray(arrayGate, indexOffset);
3213 acc_.ReplaceGate(gate, Circuit::NullGate(), Circuit::NullGate(), value);
3214 }
3215
LowerResumeGenerator(GateRef gate)3216 void SlowPathLowering::LowerResumeGenerator(GateRef gate)
3217 {
3218 GateRef obj = acc_.GetValueIn(gate, 0);
3219 std::vector<GateRef> registerGates {};
3220
3221 AddProfiling(gate, false);
3222 GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
3223 GateRef contextGate = builder_.Load(VariableType::JS_POINTER(), glue_, obj, contextOffset);
3224 GateRef arrayOffset = builder_.IntPtr(GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET);
3225 GateRef arrayGate = builder_.Load(VariableType::JS_POINTER(), glue_, contextGate, arrayOffset);
3226
3227 auto uses = acc_.Uses(gate);
3228 for (auto it = uses.begin(); it != uses.end(); it++) {
3229 if (acc_.IsValueIn(it) && acc_.GetOpCode(*it) == OpCode::RESTORE_REGISTER) {
3230 registerGates.emplace_back(*it);
3231 }
3232 }
3233 for (auto item : registerGates) {
3234 LowerStoreRegister(item, arrayGate);
3235 }
3236
3237 // 1: number of value inputs
3238 ASSERT(acc_.GetNumValueIn(gate) == 1);
3239 Label isAsyncGeneratorObj(&builder_);
3240 Label notAsyncGeneratorObj(&builder_);
3241 Label exit(&builder_);
3242 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
3243 BRANCH_CIR(builder_.TaggedIsAsyncGeneratorObject(glue_, obj), &isAsyncGeneratorObj, ¬AsyncGeneratorObj);
3244 builder_.Bind(&isAsyncGeneratorObj);
3245 {
3246 GateRef resumeResultOffset = builder_.IntPtr(JSAsyncGeneratorObject::GENERATOR_RESUME_RESULT_OFFSET);
3247 result = builder_.Load(VariableType::JS_ANY(), glue_, obj, resumeResultOffset);
3248 builder_.Jump(&exit);
3249 }
3250 builder_.Bind(¬AsyncGeneratorObj);
3251 {
3252 GateRef resumeResultOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_RESUME_RESULT_OFFSET);
3253 result = builder_.Load(VariableType::JS_ANY(), glue_, obj, resumeResultOffset);
3254 GateRef taskInfoOffset = builder_.IntPtr(JSGeneratorObject::TASK_INFO_OFFSET);
3255 GateRef taskInfo = builder_.LoadWithoutBarrier(VariableType::NATIVE_POINTER(), obj, taskInfoOffset);
3256 GateRef glueTaskOffset =
3257 builder_.IntPtr(JSThread::GlueData::GetTaskInfoOffset(builder_.GetCompilationConfig()->Is32Bit()));
3258 builder_.Store(VariableType::NATIVE_POINTER(), glue_, glue_, glueTaskOffset, taskInfo);
3259 builder_.Store(VariableType::NATIVE_POINTER(), glue_, obj, taskInfoOffset, builder_.IntPtr(0));
3260 builder_.Jump(&exit);
3261 }
3262 builder_.Bind(&exit);
3263 ReplaceHirWithValue(gate, *result);
3264 }
3265
LowerGetResumeMode(GateRef gate)3266 void SlowPathLowering::LowerGetResumeMode(GateRef gate)
3267 {
3268 // 1: number of value inputs
3269 ASSERT(acc_.GetNumValueIn(gate) == 1);
3270 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
3271 Label isAsyncGeneratorObj(&builder_);
3272 Label notAsyncGeneratorObj(&builder_);
3273 Label exit(&builder_);
3274 GateRef obj = acc_.GetValueIn(gate, 0);
3275 BRANCH_CIR(builder_.TaggedIsAsyncGeneratorObject(glue_, obj), &isAsyncGeneratorObj, ¬AsyncGeneratorObj);
3276 builder_.Bind(&isAsyncGeneratorObj);
3277 {
3278 GateRef bitFieldOffset = builder_.IntPtr(JSAsyncGeneratorObject::BIT_FIELD_OFFSET);
3279 GateRef bitField = builder_.LoadWithoutBarrier(VariableType::INT32(), obj, bitFieldOffset);
3280 auto bitfieldlsr = builder_.Int32LSR(bitField,
3281 builder_.Int32(JSAsyncGeneratorObject::ResumeModeBits::START_BIT));
3282 GateRef modeBits = builder_.Int32And(bitfieldlsr,
3283 builder_.Int32((1LU << JSAsyncGeneratorObject::ResumeModeBits::SIZE) - 1));
3284 auto resumeMode = builder_.SExtInt32ToInt64(modeBits);
3285 result = builder_.ToTaggedIntPtr(resumeMode);
3286 builder_.Jump(&exit);
3287 }
3288 builder_.Bind(¬AsyncGeneratorObj);
3289 {
3290 GateRef bitFieldOffset = builder_.IntPtr(JSGeneratorObject::BIT_FIELD_OFFSET);
3291 GateRef bitField = builder_.LoadWithoutBarrier(VariableType::INT32(), obj, bitFieldOffset);
3292 auto bitfieldlsr = builder_.Int32LSR(bitField, builder_.Int32(JSGeneratorObject::ResumeModeBits::START_BIT));
3293 GateRef modeBits = builder_.Int32And(bitfieldlsr,
3294 builder_.Int32((1LU << JSGeneratorObject::ResumeModeBits::SIZE) - 1));
3295 auto resumeMode = builder_.SExtInt32ToInt64(modeBits);
3296 result = builder_.ToTaggedIntPtr(resumeMode);
3297 builder_.Jump(&exit);
3298 }
3299 builder_.Bind(&exit);
3300 ReplaceHirWithValue(gate, *result);
3301 }
3302
TryGetMethodHeapConstantIndex(CompilationEnv * compilationEnv,const GateAccessor & acc,GateRef gate)3303 static uint32_t TryGetMethodHeapConstantIndex(CompilationEnv *compilationEnv, const GateAccessor &acc, GateRef gate)
3304 {
3305 if (!compilationEnv->SupportHeapConstant()) {
3306 return JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX;
3307 }
3308 auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv);
3309 auto methodOffset = acc.TryGetMethodOffset(gate);
3310 JSTaggedValue constpool = jitCompilationEnv->GetConstantPoolByMethodOffset(methodOffset);
3311 if (constpool.IsUndefined()) {
3312 return JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX;
3313 }
3314 uint32_t methodIndex = acc.GetConstantValue(acc.GetValueIn(gate, 0));
3315 JSTaggedValue methodObj = jitCompilationEnv->GetMethodFromCache(constpool, methodIndex);
3316 if (methodObj.IsUndefined()) {
3317 return JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX;
3318 }
3319 JSHandle<JSTaggedValue> methodHandle = jitCompilationEnv->NewJSHandle(methodObj);
3320 auto constpoolId = static_cast<uint32_t>(
3321 ConstantPool::Cast(constpool.GetTaggedObject())->GetSharedConstpoolId().GetInt());
3322 uint32_t indexInConstantTable = jitCompilationEnv->RecordHeapConstant(
3323 { constpoolId, methodIndex, JitCompilationEnv::IN_SHARED_CONSTANTPOOL }, methodHandle);
3324 return indexInConstantTable;
3325 }
3326
LowerDefineMethod(GateRef gate)3327 void SlowPathLowering::LowerDefineMethod(GateRef gate)
3328 {
3329 // 5: number of value inputs
3330 ASSERT(acc_.GetNumValueIn(gate) == 5);
3331 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
3332 GateRef sharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
3333 GateRef methodId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
3334 GateRef module = builder_.GetModuleFromFunction(glue_, jsFunc);
3335 GateRef method = 0;
3336
3337 uint32_t indexInConstantTable = TryGetMethodHeapConstantIndex(compilationEnv_, acc_, gate);
3338 if (indexInConstantTable != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
3339 method = builder_.HeapConstant(indexInConstantTable);
3340 } else {
3341 method = builder_.GetObjectFromConstPool(
3342 glue_, gate, sharedConstPool, Circuit::NullGate(), module, methodId, ConstPoolType::METHOD);
3343 }
3344 GateRef length = acc_.GetValueIn(gate, 1);
3345 GateRef env = acc_.GetValueIn(gate, 2); // 2: Get current env
3346 GateRef homeObject = acc_.GetValueIn(gate, 4); // 4: homeObject
3347
3348 Label defaultLabel(&builder_);
3349 Label successExit(&builder_);
3350 Label exceptionExit(&builder_);
3351 auto args = {method, homeObject, builder_.ToTaggedInt(length), env, builder_.GetModuleFromFunction(glue_, jsFunc),
3352 #if ECMASCRIPT_ENABLE_IC
3353 builder_.Int32ToTaggedInt(builder_.ZExtInt16ToInt32(acc_.GetValueIn(gate, 3))), jsFunc // 3: slot id
3354 #endif
3355 };
3356 GateRef result = LowerCallRuntime(gate, RTSTUB_ID(DefineMethod), args, true);
3357 BRANCH_CIR(builder_.IsSpecial(result, JSTaggedValue::VALUE_EXCEPTION),
3358 &exceptionExit, &successExit);
3359 CREATE_DOUBLE_EXIT(successExit, exceptionExit)
3360 acc_.ReplaceHirWithIfBranch(gate, successControl, failControl, result);
3361 }
3362
LowerGetUnmappedArgs(GateRef gate)3363 void SlowPathLowering::LowerGetUnmappedArgs(GateRef gate)
3364 {
3365 GateRef actualArgc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGC);
3366 GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::GetUnmappedArgs,
3367 {glue_, builder_.IntPtr(0), builder_.TruncInt64ToInt32(actualArgc),
3368 builder_.Undefined(), circuit_->GetGlobalEnvCache()});
3369 ReplaceHirWithValue(gate, newGate);
3370 }
3371
LowerCopyRestArgs(GateRef gate)3372 void SlowPathLowering::LowerCopyRestArgs(GateRef gate)
3373 {
3374 GateRef actualArgc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::ACTUAL_ARGC);
3375 GateRef taggedArgc = builder_.ToTaggedInt(actualArgc);
3376 GateRef restIdx = acc_.GetValueIn(gate, 0);
3377 GateRef taggedRestIdx = builder_.ToTaggedInt(restIdx);
3378
3379 const int id = RTSTUB_ID(OptCopyRestArgs);
3380 GateRef newGate = LowerCallRuntime(gate, id, {taggedArgc, taggedRestIdx});
3381 ReplaceHirWithValue(gate, newGate);
3382 }
3383
LowerWideLdPatchVar(GateRef gate)3384 void SlowPathLowering::LowerWideLdPatchVar(GateRef gate)
3385 {
3386 const int id = RTSTUB_ID(LdPatchVar);
3387 GateRef index = acc_.GetValueIn(gate, 0);
3388 GateRef newGate = LowerCallRuntime(gate, id, {builder_.ToTaggedInt(index)});
3389 ReplaceHirWithValue(gate, newGate);
3390 }
3391
LowerWideStPatchVar(GateRef gate)3392 void SlowPathLowering::LowerWideStPatchVar(GateRef gate)
3393 {
3394 const int id = RTSTUB_ID(StPatchVar);
3395 GateRef index = acc_.GetValueIn(gate, 0);
3396 GateRef newGate = LowerCallRuntime(gate, id, {builder_.ToTaggedInt(index)});
3397 ReplaceHirWithValue(gate, newGate);
3398 }
3399
AddProfiling(GateRef gate,bool skipGenerator)3400 void SlowPathLowering::AddProfiling(GateRef gate, bool skipGenerator)
3401 {
3402 if (IsTraceBC()) {
3403 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
3404 if ((ecmaOpcode == EcmaOpcode::SUSPENDGENERATOR_V8 || ecmaOpcode == EcmaOpcode::RESUMEGENERATOR) &&
3405 skipGenerator) {
3406 return;
3407 }
3408 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
3409 GateRef constOpcode = builder_.ToTaggedInt(builder_.ZExtInt32ToInt64(ecmaOpcodeGate));
3410 GateRef slowPath = builder_.Int32ToTaggedInt(builder_.Int32(0));
3411 GateRef debugGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(gate),
3412 { constOpcode, slowPath }, gate);
3413 acc_.SetDep(gate, debugGate);
3414 }
3415
3416 if (IsProfiling()) {
3417 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
3418 if ((ecmaOpcode == EcmaOpcode::SUSPENDGENERATOR_V8 || ecmaOpcode == EcmaOpcode::RESUMEGENERATOR) &&
3419 skipGenerator) {
3420 return;
3421 }
3422
3423 GateRef func = builder_.Undefined();
3424 if (acc_.HasFrameState(gate)) {
3425 func = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
3426 }
3427 GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
3428 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
3429 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
3430 GateRef mode =
3431 builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::SLOW_PATH)));
3432 GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(gate),
3433 { func, bcIndex, constOpcode, mode }, gate);
3434 acc_.SetDep(gate, profiling);
3435 }
3436 }
3437
LowerCallArg0Stub(GateRef gate)3438 void SlowPathLowering::LowerCallArg0Stub(GateRef gate)
3439 {
3440 // 1: number of value inputs
3441 ASSERT(acc_.GetNumValueIn(gate) == 1);
3442 GateRef func = acc_.GetValueIn(gate, 0);
3443
3444 GateRef result = builder_.CallStub(
3445 glue_, gate, CommonStubCSigns::CallArg0Stub, { glue_, func });
3446 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), result);
3447 }
3448
LowerCallArg1Stub(GateRef gate)3449 void SlowPathLowering::LowerCallArg1Stub(GateRef gate)
3450 {
3451 // 2: number of value inputs
3452 ASSERT(acc_.GetNumValueIn(gate) == 2);
3453 GateRef a0Value = acc_.GetValueIn(gate, 0);
3454 GateRef func = acc_.GetValueIn(gate, 1);
3455
3456 GateRef result = builder_.CallStub(
3457 glue_, gate, CommonStubCSigns::CallArg1Stub, { glue_, func, a0Value });
3458 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), result);
3459 }
3460
LowerCallArg2Stub(GateRef gate)3461 void SlowPathLowering::LowerCallArg2Stub(GateRef gate)
3462 {
3463 // 3: number of value inputs
3464 ASSERT(acc_.GetNumValueIn(gate) == 3);
3465 GateRef a0Value = acc_.GetValueIn(gate, 0);
3466 GateRef a1Value = acc_.GetValueIn(gate, 1);
3467 GateRef func = acc_.GetValueIn(gate, 2); // 2: func
3468
3469 GateRef result = builder_.CallStub(
3470 glue_, gate, CommonStubCSigns::CallArg2Stub, { glue_, func, a0Value, a1Value });
3471 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), result);
3472 }
3473
LowerCallArg3Stub(GateRef gate)3474 void SlowPathLowering::LowerCallArg3Stub(GateRef gate)
3475 {
3476 // 4: number of value inputs
3477 ASSERT(acc_.GetNumValueIn(gate) == 4);
3478 GateRef a0Value = acc_.GetValueIn(gate, 0);
3479 GateRef a1Value = acc_.GetValueIn(gate, 1);
3480 GateRef a2Value = acc_.GetValueIn(gate, 2); // 2: 3rd arg
3481 GateRef func = acc_.GetValueIn(gate, 3); // 3: func
3482
3483 GateRef result = builder_.CallStub(
3484 glue_, gate, CommonStubCSigns::CallArg3Stub, { glue_, func, a0Value, a1Value, a2Value });
3485 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), result);
3486 }
3487
LowerCallThis0Stub(GateRef gate)3488 void SlowPathLowering::LowerCallThis0Stub(GateRef gate)
3489 {
3490 // 2: number of value inputs
3491 ASSERT(acc_.GetNumValueIn(gate) == 2);
3492 GateRef thisObj = acc_.GetValueIn(gate, 0);
3493 GateRef func = acc_.GetValueIn(gate, 1);
3494
3495 GateRef result = builder_.CallStub(
3496 glue_, gate, CommonStubCSigns::CallThis0Stub, { glue_, func, thisObj });
3497 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), result);
3498 }
3499
LowerCallThis1Stub(GateRef gate)3500 void SlowPathLowering::LowerCallThis1Stub(GateRef gate)
3501 {
3502 // 3: number of value inputs
3503 ASSERT(acc_.GetNumValueIn(gate) == 3);
3504 GateRef thisObj = acc_.GetValueIn(gate, 0);
3505 GateRef a0Value = acc_.GetValueIn(gate, 1);
3506 GateRef func = acc_.GetValueIn(gate, 2); // 2: func
3507
3508 GateRef result = builder_.CallStub(
3509 glue_, gate, CommonStubCSigns::CallThis1Stub, { glue_, func, thisObj, a0Value });
3510 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), result);
3511 }
3512
LowerCallThis2Stub(GateRef gate)3513 void SlowPathLowering::LowerCallThis2Stub(GateRef gate)
3514 {
3515 // 4: number of value inputs
3516 ASSERT(acc_.GetNumValueIn(gate) == 4);
3517 GateRef thisObj = acc_.GetValueIn(gate, 0);
3518 GateRef a0Value = acc_.GetValueIn(gate, 1);
3519 GateRef a1Value = acc_.GetValueIn(gate, 2); // 2: 2nd arg
3520 GateRef func = acc_.GetValueIn(gate, 3); // 3: func
3521
3522 GateRef result = builder_.CallStub(
3523 glue_, gate, CommonStubCSigns::CallThis2Stub, { glue_, func, thisObj, a0Value, a1Value });
3524 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), result);
3525 }
3526
LowerCallThis3Stub(GateRef gate)3527 void SlowPathLowering::LowerCallThis3Stub(GateRef gate)
3528 {
3529 // 5: number of value inputs
3530 ASSERT(acc_.GetNumValueIn(gate) == 5);
3531 GateRef thisObj = acc_.GetValueIn(gate, 0);
3532 GateRef a0Value = acc_.GetValueIn(gate, 1);
3533 GateRef a1Value = acc_.GetValueIn(gate, 2); // 2: 2nd arg
3534 GateRef a2Value = acc_.GetValueIn(gate, 3); // 3: 3rd arg
3535 GateRef func = acc_.GetValueIn(gate, 4); // 4: func
3536
3537 GateRef result = builder_.CallStub(
3538 glue_, gate, CommonStubCSigns::CallThis3Stub, { glue_, func, thisObj, a0Value, a1Value, a2Value });
3539 ReplaceHirWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), result);
3540 }
3541
LowerWideCallrangePrefImm16V8(GateRef gate)3542 void SlowPathLowering::LowerWideCallrangePrefImm16V8(GateRef gate)
3543 {
3544 std::vector<GateRef> vec;
3545 std::vector<GateRef> vec1;
3546 size_t numIns = acc_.GetNumValueIn(gate);
3547 size_t fixedInputsNum = 1; // 1: acc
3548 ASSERT(acc_.GetNumValueIn(gate) >= fixedInputsNum);
3549 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
3550 EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8));
3551 GateRef actualArgv = builder_.IntPtr(0);
3552 GateRef callTarget = acc_.GetValueIn(gate, numIns - fixedInputsNum); // acc
3553 GateRef newTarget = builder_.Undefined();
3554 GateRef thisObj = builder_.Undefined();
3555
3556 vec.emplace_back(glue_);
3557 vec.emplace_back(actualArgc);
3558 vec.emplace_back(actualArgv);
3559 vec.emplace_back(callTarget);
3560 vec.emplace_back(newTarget);
3561 vec.emplace_back(thisObj);
3562 // add args
3563 for (size_t i = 0; i < numIns - fixedInputsNum; i++) { // skip acc
3564 vec.emplace_back(acc_.GetValueIn(gate, i));
3565 }
3566
3567 vec1.emplace_back(glue_);
3568 vec1.emplace_back(callTarget);
3569 vec1.emplace_back(thisObj);
3570 // add args
3571 for (size_t i = 0; i < numIns - fixedInputsNum; i++) { // skip acc
3572 vec1.emplace_back(acc_.GetValueIn(gate, i));
3573 }
3574 LowerToJSCall(gate, vec, vec1);
3575 }
3576
LowerLdThisByName(GateRef gate)3577 void SlowPathLowering::LowerLdThisByName(GateRef gate)
3578 {
3579 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: number of parameter
3580 GateRef thisObj = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
3581 GateRef prop = acc_.GetValueIn(gate, 1); // 1: the second parameter
3582 LowerCallStubWithIC(gate, CommonStubCSigns::GetPropertyByName, {thisObj, prop, circuit_->GetGlobalEnvCache()});
3583 }
3584
IsFastCallArgs(size_t index)3585 bool SlowPathLowering::IsFastCallArgs(size_t index)
3586 {
3587 return index != static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC) &&
3588 index != static_cast<size_t>(CommonArgIdx::ACTUAL_ARGV) &&
3589 index != static_cast<size_t>(CommonArgIdx::NEW_TARGET);
3590 }
3591
LowerConstruct(GateRef gate)3592 void SlowPathLowering::LowerConstruct(GateRef gate)
3593 {
3594 Environment env(gate, circuit_, &builder_);
3595 size_t num = acc_.GetNumValueIn(gate);
3596 std::vector<GateRef> args(num);
3597 for (size_t i = 0; i < num; ++i) {
3598 args[i] = acc_.GetValueIn(gate, i);
3599 }
3600 ASSERT(num >= 3); // 3: skip argc argv newtarget
3601 std::vector<GateRef> argsFastCall(num - 3); // 3: skip argc argv newtarget
3602 size_t j = 0;
3603 for (size_t i = 0; i < num; ++i) {
3604 if (IsFastCallArgs(i)) {
3605 argsFastCall[j++] = acc_.GetValueIn(gate, i);
3606 }
3607 }
3608 GateRef ctor = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
3609 GateRef argc = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC));
3610 Label exit(&builder_);
3611 DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
3612 if (compilationEnv_->IsJitCompiler()) {
3613 auto selectCall = builder_.CallStub(glue_, gate, CommonStubCSigns::FastCallSelector, {glue_, ctor, argc});
3614 SelectFastNew(selectCall, gate, ctor, args, argsFastCall, &res, &exit);
3615 } else {
3616 CallCoStubBuilder::LowerFastCall(gate, glue_, builder_, ctor, argc, args, argsFastCall, &res, &exit, true,
3617 g_isEnableCMCGC);
3618 }
3619 builder_.Bind(&exit);
3620 GateRef thisObj = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::THIS_OBJECT));
3621 GateRef result = builder_.CallStub(
3622 glue_, gate, CommonStubCSigns::ConstructorCheck, { glue_, ctor, *res, thisObj });
3623 GateRef state = builder_.GetState();
3624 acc_.ReplaceGate(gate, state, result, result);
3625 }
3626
LowerCallInternal(GateRef gate)3627 void SlowPathLowering::LowerCallInternal(GateRef gate)
3628 {
3629 Environment env(gate, circuit_, &builder_);
3630 size_t num = acc_.GetNumValueIn(gate);
3631 std::vector<GateRef> args(num);
3632 for (size_t i = 0; i < num; ++i) {
3633 args[i] = acc_.GetValueIn(gate, i);
3634 }
3635 ASSERT(num >= 3); // 3:skip argc argv newtarget
3636 std::vector<GateRef> argsFastCall(num - 3); // 3:skip argc argv newtarget
3637 size_t j = 0;
3638 for (size_t i = 0; i < num; ++i) {
3639 if (IsFastCallArgs(i)) { // 1: argc index 3: newtarget index 2:ActualArgv
3640 argsFastCall[j++] = acc_.GetValueIn(gate, i);
3641 }
3642 }
3643 GateRef func = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
3644 GateRef argc = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::ACTUAL_ARGC));
3645 Label exit(&builder_);
3646 DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
3647 CallCoStubBuilder::LowerFastCall(gate, glue_, builder_, func, argc, args, argsFastCall, &res, &exit, false,
3648 g_isEnableCMCGC);
3649 builder_.Bind(&exit);
3650 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *res);
3651 }
3652
LowerCallNew(GateRef gate)3653 void SlowPathLowering::LowerCallNew(GateRef gate)
3654 {
3655 Environment env(gate, circuit_, &builder_);
3656 size_t num = acc_.GetNumValueIn(gate);
3657 bool needPushArgv = acc_.NeedPushArgv(gate);
3658 bool isFastCall = acc_.IsFastCall(gate);
3659 std::vector<GateRef> args(num);
3660 for (size_t i = 0; i < num; ++i) {
3661 args[i] = acc_.GetValueIn(gate, i);
3662 }
3663 ASSERT(num >= 3); // 3: skip argc argv newtarget
3664 std::vector<GateRef> argsFastCall(num - 3); // 3:skip argc argv newtarget
3665 size_t j = 0;
3666 for (size_t i = 0; i < num; ++i) {
3667 if (IsFastCallArgs(i)) {
3668 argsFastCall[j++] = acc_.GetValueIn(gate, i);
3669 }
3670 }
3671 GateRef ctor = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
3672 Label exit(&builder_);
3673 DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
3674 LowerNewFastCall(gate, glue_, ctor, needPushArgv, isFastCall, args, argsFastCall, &res, &exit);
3675 builder_.Bind(&exit);
3676 GateRef thisObj = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::THIS_OBJECT));
3677 GateRef result = builder_.CallStub(
3678 glue_, gate, CommonStubCSigns::ConstructorCheck, { glue_, ctor, *res, thisObj });
3679 GateRef state = builder_.GetState();
3680 acc_.ReplaceGate(gate, state, result, result);
3681 }
3682
LowerCallNewBuiltin(GateRef gate)3683 void SlowPathLowering::LowerCallNewBuiltin(GateRef gate)
3684 {
3685 Environment env(gate, circuit_, &builder_);
3686 size_t num = acc_.GetNumValueIn(gate);
3687 std::vector<GateRef> args(num);
3688 for (size_t i = 0; i < num; ++i) {
3689 args[i] = acc_.GetValueIn(gate, i);
3690 }
3691 ASSERT(num >= 3); // 3: skip argc argv newtarget
3692
3693 GateRef ctor = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
3694
3695 if (g_isEnableCMCGC) {
3696 Label needReadBarrier(&builder_);
3697 Label skipReadBarrier(&builder_);
3698 BRANCH_CIR_LIKELY(builder_.NeedSkipReadBarrier(glue_), &skipReadBarrier, &needReadBarrier);
3699
3700 builder_.Bind(&needReadBarrier);
3701 {
3702 builder_.CallNGCRuntime(glue_, RTSTUB_ID(CopyCallTarget), Gate::InvalidGateRef, {glue_, ctor}, glue_);
3703 builder_.Jump(&skipReadBarrier);
3704 }
3705
3706 builder_.Bind(&skipReadBarrier);
3707 }
3708 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCallNew));
3709 GateRef target = builder_.IntPtr(RTSTUB_ID(JSCallNew));
3710 auto depend = builder_.GetDepend();
3711 GateRef result = builder_.Call(cs, glue_, target, depend, args, gate, "slowNewBuiltin");
3712
3713 GateRef state = builder_.GetState();
3714 acc_.ReplaceGate(gate, state, result, result);
3715 }
3716
LowerNewFastCall(GateRef gate,GateRef glue,GateRef func,bool needPushArgv,bool isFastCall,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,Variable * result,Label * exit)3717 void SlowPathLowering::LowerNewFastCall(GateRef gate, GateRef glue, GateRef func, bool needPushArgv, bool isFastCall,
3718 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall,
3719 Variable *result, Label *exit)
3720 {
3721 Label compiled(&builder_);
3722 Label slowPath(&builder_);
3723 if (g_isEnableCMCGC) {
3724 Label needReadBarrier(&builder_);
3725 Label skipReadBarrier(&builder_);
3726 BRANCH_CIR_LIKELY(builder_.NeedSkipReadBarrier(glue), &skipReadBarrier, &needReadBarrier);
3727
3728 builder_.Bind(&needReadBarrier);
3729 {
3730 builder_.CallNGCRuntime(glue, RTSTUB_ID(CopyCallTarget), Gate::InvalidGateRef, {glue, func}, glue);
3731 builder_.Jump(&skipReadBarrier);
3732 }
3733
3734 builder_.Bind(&skipReadBarrier);
3735 }
3736 BRANCH_CIR(IsAotOrFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT), &compiled, &slowPath);
3737 builder_.Bind(&compiled);
3738 {
3739 if (isFastCall) {
3740 if (!needPushArgv) {
3741 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
3742 GateRef code = builder_.GetCodeAddr(func);
3743 auto depend = builder_.GetDepend();
3744 const CallSignature *cs = RuntimeStubCSigns::GetOptimizedFastCallSign();
3745 result->WriteVariable(builder_.Call(cs, glue, code, depend, argsFastCall, gate, "callFastAOT"));
3746 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
3747 builder_.Jump(exit);
3748 } else {
3749 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
3750 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(OptimizedFastCallAndPushArgv));
3751 GateRef target = builder_.IntPtr(RTSTUB_ID(OptimizedFastCallAndPushArgv));
3752 auto depend = builder_.GetDepend();
3753 result->WriteVariable(builder_.Call(cs, glue, target, depend, args, gate, "callFastBridge"));
3754 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
3755 builder_.Jump(exit);
3756 }
3757 } else if (!needPushArgv) {
3758 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
3759 GateRef code = builder_.GetCodeAddr(func);
3760 auto depend = builder_.GetDepend();
3761 const CallSignature *cs = RuntimeStubCSigns::GetOptimizedCallSign();
3762 result->WriteVariable(builder_.Call(cs, glue, code, depend, args, gate, "callAOT"));
3763 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
3764 builder_.Jump(exit);
3765 } else {
3766 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
3767 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(OptimizedCallAndPushArgv));
3768 GateRef target = builder_.IntPtr(RTSTUB_ID(OptimizedCallAndPushArgv));
3769 auto depend = builder_.GetDepend();
3770 result->WriteVariable(builder_.Call(cs, glue, target, depend, args, gate, "callBridge"));
3771 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
3772 builder_.Jump(exit);
3773 }
3774 }
3775 builder_.Bind(&slowPath);
3776 {
3777 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
3778 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCallNew));
3779 GateRef target = builder_.IntPtr(RTSTUB_ID(JSCallNew));
3780 auto depend = builder_.GetDepend();
3781 result->WriteVariable(builder_.Call(cs, glue, target, depend, args, gate, "slowNew"));
3782 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
3783 builder_.Jump(exit);
3784 }
3785 }
3786
LowerTypedCall(GateRef gate)3787 void SlowPathLowering::LowerTypedCall(GateRef gate)
3788 {
3789 Environment env(gate, circuit_, &builder_);
3790 GateRef func = acc_.GetValueIn(gate, static_cast<size_t>(CommonArgIdx::FUNC));
3791 if (g_isEnableCMCGC) {
3792 Label needReadBarrier(&builder_);
3793 Label skipReadBarrier(&builder_);
3794 BRANCH_CIR_LIKELY(builder_.NeedSkipReadBarrier(glue_), &skipReadBarrier, &needReadBarrier);
3795
3796 builder_.Bind(&needReadBarrier);
3797 {
3798 builder_.CallNGCRuntime(glue_, RTSTUB_ID(CopyCallTarget), Gate::InvalidGateRef, {glue_, func}, glue_);
3799 builder_.Jump(&skipReadBarrier);
3800 }
3801
3802 builder_.Bind(&skipReadBarrier);
3803 }
3804 GateRef code = builder_.GetCodeAddr(func);
3805 size_t num = acc_.GetNumValueIn(gate);
3806 std::vector<GateRef> args(num);
3807 for (size_t i = 0; i < num; ++i) {
3808 args[i] = acc_.GetValueIn(gate, i);
3809 }
3810 GateRef state = builder_.GetState();
3811 auto depend = builder_.GetDepend();
3812 const CallSignature *cs = RuntimeStubCSigns::GetOptimizedCallSign();
3813 GateRef result = builder_.Call(cs, glue_, code, depend, args, gate, "callAOT");
3814 acc_.ReplaceGate(gate, state, result, result);
3815 }
3816
LowerTypedFastCall(GateRef gate)3817 void SlowPathLowering::LowerTypedFastCall(GateRef gate)
3818 {
3819 Environment env(gate, circuit_, &builder_);
3820 GateRef func = acc_.GetValueIn(gate, static_cast<size_t>(FastCallArgIdx::FUNC));
3821 if (g_isEnableCMCGC) {
3822 Label needReadBarrier(&builder_);
3823 Label skipReadBarrier(&builder_);
3824 BRANCH_CIR_LIKELY(builder_.NeedSkipReadBarrier(glue_), &skipReadBarrier, &needReadBarrier);
3825
3826 builder_.Bind(&needReadBarrier);
3827 {
3828 builder_.CallNGCRuntime(glue_, RTSTUB_ID(CopyCallTarget), Gate::InvalidGateRef, {glue_, func}, glue_);
3829 builder_.Jump(&skipReadBarrier);
3830 }
3831
3832 builder_.Bind(&skipReadBarrier);
3833 }
3834 GateRef code = builder_.GetCodeAddr(func);
3835 size_t num = acc_.GetNumValueIn(gate);
3836 std::vector<GateRef> args(num);
3837 for (size_t i = 0; i < num; ++i) {
3838 args[i] = acc_.GetValueIn(gate, i);
3839 }
3840 GateRef state = builder_.GetState();
3841 auto depend = builder_.GetDepend();
3842 const CallSignature *cs = RuntimeStubCSigns::GetOptimizedFastCallSign();
3843 GateRef result = builder_.Call(cs, glue_, code, depend, args, gate, "callFastAOT");
3844 acc_.ReplaceGate(gate, state, result, result);
3845 }
3846
LowerCheckSafePointAndStackOver(GateRef gate)3847 void SlowPathLowering::LowerCheckSafePointAndStackOver(GateRef gate)
3848 {
3849 Environment env(gate, circuit_, &builder_);
3850 Label slowPath(&builder_);
3851 Label dispatch(&builder_);
3852 Label checkStackOver(&builder_);
3853 Label stackOverflow(&builder_);
3854 GateRef stackLimit = builder_.LoadWithoutBarrier(VariableType::INT64(), glue_,
3855 builder_.IntPtr(JSThread::GlueData::GetStackLimitOffset(builder_.GetCompilationConfig()->Is32Bit())));
3856 GateRef spValue = builder_.ReadSp();
3857 GateRef checkSafePoint = Circuit::NullGate();
3858 if (!g_isEnableCMCGC) {
3859 GateRef interruptsFlag = builder_.LoadWithoutBarrier(VariableType::INT8(), glue_,
3860 builder_.IntPtr(JSThread::GlueData::GetInterruptVectorOffset(builder_.GetCompilationConfig()->Is32Bit())));
3861 checkSafePoint = builder_.Int8Equal(interruptsFlag, builder_.Int8(VmThreadControl::VM_NEED_SUSPENSION));
3862 } else {
3863 GateRef threadHolderOffset = builder_.IntPtr(JSThread::GlueData::GetThreadHolderOffset(env.IsArch32Bit()));
3864 GateRef threadHolder = builder_.LoadWithoutBarrier(VariableType::NATIVE_POINTER(), glue_, threadHolderOffset);
3865 GateRef mutatorBase = builder_.LoadWithoutBarrier(VariableType::NATIVE_POINTER(), threadHolder,
3866 builder_.IntPtr(ThreadHolder::GetMutatorBaseOffset()));
3867 GateRef safepointActive = builder_.LoadWithoutBarrier(VariableType::INT32(), mutatorBase,
3868 builder_.IntPtr(common::MutatorBase::GetSafepointActiveOffset()));
3869 checkSafePoint = builder_.Int32Equal(builder_.Int32(ThreadFlag::SUSPEND_REQUEST), safepointActive);
3870 }
3871 builder_.Branch(checkSafePoint,
3872 &slowPath, &checkStackOver, BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "checkSafePoint");
3873 builder_.Bind(&slowPath);
3874 {
3875 LowerCallRuntime(glue_, RTSTUB_ID(CheckSafePoint), {}, true);
3876 builder_.Jump(&checkStackOver);
3877 }
3878 builder_.Bind(&checkStackOver);
3879 {
3880 builder_.Branch(builder_.Int64LessThanOrEqual(spValue, stackLimit), &stackOverflow, &dispatch,
3881 BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "checkStackOverflow");
3882 builder_.Bind(&stackOverflow);
3883 {
3884 GateRef res = LowerCallRuntime(glue_, RTSTUB_ID(ThrowStackOverflowException), {}, true);
3885 builder_.Return(res);
3886 }
3887 }
3888 builder_.Bind(&dispatch);
3889 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
3890 }
3891
LowerLdPrivateProperty(GateRef gate)3892 void SlowPathLowering::LowerLdPrivateProperty(GateRef gate)
3893 {
3894 const int id = RTSTUB_ID(LdPrivateProperty);
3895 // 5: number of value inputs + env + acc
3896 ASSERT(acc_.GetNumValueIn(gate) == 5);
3897 [[maybe_unused]] GateRef slotId = acc_.GetValueIn(gate, 0);
3898 GateRef levelIndex = acc_.GetValueIn(gate, 1);
3899 GateRef slotIndex = acc_.GetValueIn(gate, 2);
3900 GateRef lexicalEnv = acc_.GetValueIn(gate, 3);
3901 GateRef obj = acc_.GetValueIn(gate, 4); // acc
3902
3903 GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
3904 builder_.ToTaggedInt(levelIndex), builder_.ToTaggedInt(slotIndex), obj});
3905 ReplaceHirWithValue(gate, newGate);
3906 }
3907
LowerStPrivateProperty(GateRef gate)3908 void SlowPathLowering::LowerStPrivateProperty(GateRef gate)
3909 {
3910 const int id = RTSTUB_ID(StPrivateProperty);
3911 // 6: number of value inputs + env + acc
3912 ASSERT(acc_.GetNumValueIn(gate) == 6);
3913 [[maybe_unused]] GateRef slotId = acc_.GetValueIn(gate, 0);
3914 GateRef levelIndex = acc_.GetValueIn(gate, 1);
3915 GateRef slotIndex = acc_.GetValueIn(gate, 2);
3916 GateRef obj = acc_.GetValueIn(gate, 3);
3917 GateRef lexicalEnv = acc_.GetValueIn(gate, 4);
3918 GateRef value = acc_.GetValueIn(gate, 5); // acc
3919
3920 GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
3921 builder_.ToTaggedInt(levelIndex), builder_.ToTaggedInt(slotIndex), obj, value});
3922 ReplaceHirWithValue(gate, newGate);
3923 }
3924
LowerTestIn(GateRef gate)3925 void SlowPathLowering::LowerTestIn(GateRef gate)
3926 {
3927 const int id = RTSTUB_ID(TestIn);
3928 // 5: number of value inputs + acc
3929 ASSERT(acc_.GetNumValueIn(gate) == 5);
3930 [[maybe_unused]] GateRef slotId = acc_.GetValueIn(gate, 0);
3931 GateRef levelIndex = acc_.GetValueIn(gate, 1);
3932 GateRef slotIndex = acc_.GetValueIn(gate, 2);
3933 GateRef lexicalEnv = acc_.GetValueIn(gate, 3);
3934 GateRef obj = acc_.GetValueIn(gate, 4); // acc
3935
3936 GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
3937 builder_.ToTaggedInt(levelIndex), builder_.ToTaggedInt(slotIndex), obj});
3938 ReplaceHirWithValue(gate, newGate);
3939 }
3940
LowerNotifyConcurrentResult(GateRef gate)3941 void SlowPathLowering::LowerNotifyConcurrentResult(GateRef gate)
3942 {
3943 const int id = RTSTUB_ID(NotifyConcurrentResult);
3944
3945 GateRef newGate = LowerCallRuntime(gate, id, {acc_.GetValueIn(gate, 0),
3946 argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC)});
3947 ReplaceHirWithValue(gate, newGate);
3948 }
3949
LowerDefineFieldByName(GateRef gate)3950 void SlowPathLowering::LowerDefineFieldByName(GateRef gate)
3951 {
3952 // 4: number of value inputs + acc
3953 ASSERT(acc_.GetNumValueIn(gate) == 4);
3954 GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 1));
3955 GateRef obj = acc_.GetValueIn(gate, 2);
3956 GateRef propKey = GetStringFromConstPool(gate, stringId, 1); // 1: index of the stringId
3957 GateRef value = acc_.GetValueIn(gate, 3); // acc
3958
3959 GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::DefineField,
3960 {glue_, obj, propKey, value, circuit_->GetGlobalEnvCache()});
3961 ReplaceHirWithValue(gate, newGate);
3962 }
3963
LowerDefineFieldByValue(GateRef gate)3964 void SlowPathLowering::LowerDefineFieldByValue(GateRef gate)
3965 {
3966 // 3: number of value inputs + acc
3967 ASSERT(acc_.GetNumValueIn(gate) == 3);
3968 GateRef obj = acc_.GetValueIn(gate, 1);
3969 GateRef propKey = acc_.GetValueIn(gate, 0);
3970 GateRef value = acc_.GetValueIn(gate, 2); // acc
3971
3972 GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::DefineField,
3973 {glue_, obj, propKey, value, circuit_->GetGlobalEnvCache()});
3974 ReplaceHirWithValue(gate, newGate);
3975 }
3976
LowerDefineFieldByIndex(GateRef gate)3977 void SlowPathLowering::LowerDefineFieldByIndex(GateRef gate)
3978 {
3979 // 3: number of value inputs + acc
3980 ASSERT(acc_.GetNumValueIn(gate) == 3);
3981 GateRef obj = acc_.GetValueIn(gate, 1);
3982 GateRef propKey = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
3983 GateRef value = acc_.GetValueIn(gate, 2); // acc
3984
3985 GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::DefineField,
3986 {glue_, obj, propKey, value, circuit_->GetGlobalEnvCache()});
3987 ReplaceHirWithValue(gate, newGate);
3988 }
3989
LowerToPropertyKey(GateRef gate)3990 void SlowPathLowering::LowerToPropertyKey(GateRef gate)
3991 {
3992 const int id = RTSTUB_ID(ToPropertyKey);
3993 // 1: number of acc
3994 ASSERT(acc_.GetNumValueIn(gate) == 1);
3995 GateRef value = acc_.GetValueIn(gate, 0); // acc
3996
3997 GateRef newGate = LowerCallRuntime(gate, id, {value});
3998 ReplaceHirWithValue(gate, newGate);
3999 }
4000
LowerCreatePrivateProperty(GateRef gate)4001 void SlowPathLowering::LowerCreatePrivateProperty(GateRef gate)
4002 {
4003 const int id = RTSTUB_ID(CreatePrivateProperty);
4004 // 3: number of value inputs
4005 ASSERT(acc_.GetNumValueIn(gate) == 3);
4006 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
4007 GateRef count = acc_.GetValueIn(gate, 0);
4008 GateRef literalId = acc_.GetValueIn(gate, 1);
4009 GateRef lexicalEnv = acc_.GetValueIn(gate, 2);
4010 GateRef constpool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
4011 GateRef module = builder_.GetModuleFromFunction(glue_, jsFunc);
4012
4013 GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
4014 builder_.ToTaggedInt(count), constpool, builder_.ToTaggedInt(literalId), module});
4015 ReplaceHirWithValue(gate, newGate);
4016 }
4017
LowerDefinePrivateProperty(GateRef gate)4018 void SlowPathLowering::LowerDefinePrivateProperty(GateRef gate)
4019 {
4020 const int id = RTSTUB_ID(DefinePrivateProperty);
4021 // 5: number of value inputs + acc
4022 ASSERT(acc_.GetNumValueIn(gate) == 5);
4023 GateRef levelIndex = acc_.GetValueIn(gate, 0);
4024 GateRef slotIndex = acc_.GetValueIn(gate, 1);
4025 GateRef obj = acc_.GetValueIn(gate, 2);
4026 GateRef lexicalEnv = acc_.GetValueIn(gate, 3);
4027 GateRef value = acc_.GetValueIn(gate, 4); // acc
4028
4029 GateRef newGate = LowerCallRuntime(gate, id, {lexicalEnv,
4030 builder_.ToTaggedInt(levelIndex), builder_.ToTaggedInt(slotIndex), obj, value});
4031 ReplaceHirWithValue(gate, newGate);
4032 }
4033
LowerDefineSendableClass(GateRef gate)4034 void SlowPathLowering::LowerDefineSendableClass(GateRef gate)
4035 {
4036 // 4: number of value inputs
4037 ASSERT(acc_.GetNumValueIn(gate) == 4);
4038 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
4039 GateRef methodId = acc_.GetValueIn(gate, 0);
4040 GateRef proto = acc_.GetValueIn(gate, 3);
4041 GateRef literalId = acc_.GetValueIn(gate, 1);
4042 GateRef length = acc_.GetValueIn(gate, 2); // 2: second arg
4043 GateRef constpool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::SHARED_CONST_POOL);
4044 GateRef module = builder_.GetModuleFromFunction(glue_, jsFunc);
4045
4046 auto args = { proto, constpool, builder_.ToTaggedInt(methodId), builder_.ToTaggedInt(literalId),
4047 builder_.ToTaggedInt(length), module };
4048 GateRef newGate = LowerCallRuntime(gate, RTSTUB_ID(CreateSharedClass), args);
4049 ReplaceHirWithValue(gate, newGate);
4050 }
4051
LowerLdSendableClass(GateRef gate)4052 void SlowPathLowering::LowerLdSendableClass(GateRef gate)
4053 {
4054 GateRef level = acc_.GetValueIn(gate, 0);
4055 GateRef lexicalEnv = acc_.GetValueIn(gate, 1);
4056 GateRef newGate = LowerCallRuntime(gate, RTSTUB_ID(LdSendableClass), { lexicalEnv, builder_.ToTaggedInt(level) });
4057 ReplaceHirWithValue(gate, newGate);
4058 }
4059
LowerSendableExternalModule(GateRef gate)4060 void SlowPathLowering::LowerSendableExternalModule(GateRef gate)
4061 {
4062 ASSERT(acc_.GetNumValueIn(gate) == 1);
4063 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
4064 GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
4065 GateRef result = LowerCallRuntime(gate,
4066 RTSTUB_ID(LdSendableExternalModuleVarByIndex), {index, jsFunc}, true);
4067 ReplaceHirWithValue(gate, result);
4068 }
4069
LowerSendableLocalModule(GateRef gate)4070 void SlowPathLowering::LowerSendableLocalModule(GateRef gate)
4071 {
4072 ASSERT(acc_.GetNumValueIn(gate) == 1);
4073 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
4074 GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
4075 GateRef result = LowerCallRuntime(gate,
4076 RTSTUB_ID(LdSendableLocalModuleVarByIndex), {index, jsFunc}, true);
4077 ReplaceHirWithValue(gate, result);
4078 }
4079
LowerLdStr(GateRef gate)4080 void SlowPathLowering::LowerLdStr(GateRef gate)
4081 {
4082 GateRef stringId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
4083 GateRef res = GetStringFromConstPool(gate, stringId);
4084 ReplaceHirWithValue(gate, res);
4085 }
4086
LowerGetSharedConstPool(GateRef gate)4087 void SlowPathLowering::LowerGetSharedConstPool(GateRef gate)
4088 {
4089 bool useConstPool = false;
4090 auto uses = acc_.Uses(gate);
4091 for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
4092 if (acc_.GetOpCode(*useIt) != OpCode::FRAME_ARGS) {
4093 useConstPool = true;
4094 break;
4095 }
4096 }
4097 if (!useConstPool) {
4098 acc_.UpdateAllUses(gate, builder_.Undefined());
4099 acc_.DeleteGate(gate);
4100 return;
4101 }
4102 GateRef jsFunc = acc_.GetValueIn(gate, 0);
4103 GateRef methodOffset = builder_.IntPtr(JSFunctionBase::METHOD_OFFSET);
4104 GateRef method = builder_.Load(VariableType::JS_POINTER(), glue_, jsFunc, methodOffset, acc_.GetDependRoot());
4105 GateRef sharedConstpool =
4106 builder_.Load(VariableType::JS_ANY(), glue_, method, builder_.IntPtr(Method::CONSTANT_POOL_OFFSET), method);
4107 acc_.UpdateAllUses(gate, sharedConstpool);
4108 acc_.DeleteGate(gate);
4109 }
4110
LowerGetUnsharedConstPool(GateRef gate)4111 void SlowPathLowering::LowerGetUnsharedConstPool(GateRef gate)
4112 {
4113 bool useConstPool = false;
4114 auto uses = acc_.Uses(gate);
4115 for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
4116 if (acc_.GetOpCode(*useIt) != OpCode::FRAME_ARGS) {
4117 useConstPool = true;
4118 break;
4119 }
4120 }
4121 if (!useConstPool) {
4122 acc_.UpdateAllUses(gate, builder_.Undefined());
4123 acc_.DeleteGate(gate);
4124 return;
4125 }
4126 GateRef sharedConstPool = acc_.GetValueIn(gate, 0);
4127 GateRef constPoolSize = builder_.LoadWithoutBarrier(VariableType::INT32(), sharedConstPool,
4128 builder_.IntPtr(TaggedArray::LENGTH_OFFSET), sharedConstPool);
4129 GateRef unshareIdx = builder_.Int32Sub(constPoolSize, builder_.Int32(ConstantPool::UNSHARED_CONSTPOOL_INDEX));
4130 GateRef offset =
4131 builder_.PtrMul(builder_.ZExtInt32ToPtr(unshareIdx), builder_.IntPtr(JSTaggedValue::TaggedTypeSize()));
4132 GateRef dataOffset = builder_.PtrAdd(offset, builder_.IntPtr(TaggedArray::DATA_OFFSET));
4133 GateRef index = builder_.Load(VariableType::JS_ANY(), glue_, sharedConstPool, dataOffset, constPoolSize);
4134 GateRef unshareCpOffset = static_cast<int32_t>(JSThread::GlueData::GetUnSharedConstpoolsOffset(false));
4135 GateRef unshareCpAddr =
4136 builder_.LoadWithoutBarrier(VariableType::NATIVE_POINTER(), glue_, builder_.IntPtr(unshareCpOffset), index);
4137 GateRef unshareCpDataOffset =
4138 builder_.PtrAdd(unshareCpAddr, builder_.PtrMul(builder_.IntPtr(JSTaggedValue::TaggedTypeSize()),
4139 builder_.ZExtInt32ToPtr(builder_.TaggedGetInt(index))));
4140 GateRef unsharedConstPool =
4141 builder_.Load(VariableType::JS_ANY(), glue_, unshareCpDataOffset, builder_.IntPtr(0), unshareCpAddr);
4142
4143 acc_.UpdateAllUses(gate, unsharedConstPool);
4144
4145 // delete old gate
4146 acc_.DeleteGate(gate);
4147 }
4148
LowerLdLazyExternalModuleVar(GateRef gate)4149 void SlowPathLowering::LowerLdLazyExternalModuleVar(GateRef gate)
4150 {
4151 ASSERT(acc_.GetNumValueIn(gate) == 1);
4152 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
4153 GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
4154 GateRef result = LowerCallRuntime(gate,
4155 RTSTUB_ID(LdLazyExternalModuleVarByIndex), {index, jsFunc}, true);
4156 ReplaceHirWithValue(gate, result);
4157 }
4158
LowerLdLazySendableExternalModuleVar(GateRef gate)4159 void SlowPathLowering::LowerLdLazySendableExternalModuleVar(GateRef gate)
4160 {
4161 ASSERT(acc_.GetNumValueIn(gate) == 1);
4162 GateRef jsFunc = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
4163 GateRef index = builder_.ToTaggedInt(acc_.GetValueIn(gate, 0));
4164 GateRef result = LowerCallRuntime(gate,
4165 RTSTUB_ID(LdLazySendableExternalModuleVarByIndex), {index, jsFunc}, true);
4166 ReplaceHirWithValue(gate, result);
4167 }
4168 } // namespace panda::ecmascript
4169