1 /*
2  * Copyright (c) 2021 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 #ifndef ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H
17 #define ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H
18 
19 #include "ecmascript/debugger/js_debugger_manager.h"
20 #include "ecmascript/ecma_context.h"
21 #include "ecmascript/ecma_string.h"
22 #include "ecmascript/ecma_vm.h"
23 #include "ecmascript/global_env.h"
24 #include "ecmascript/ic/ic_runtime_stub-inl.h"
25 #include "ecmascript/interpreter/fast_runtime_stub-inl.h"
26 #include "ecmascript/interpreter/interpreter.h"
27 #include "ecmascript/interpreter/interpreter_assembly.h"
28 #include "ecmascript/interpreter/frame_handler.h"
29 #include "ecmascript/interpreter/slow_runtime_stub.h"
30 #include "ecmascript/jspandafile/literal_data_extractor.h"
31 #include "ecmascript/jspandafile/program_object.h"
32 #include "ecmascript/js_async_generator_object.h"
33 #include "ecmascript/js_generator_object.h"
34 #include "ecmascript/js_tagged_value.h"
35 #include "ecmascript/jit/jit_task.h"
36 #include "ecmascript/mem/concurrent_marker.h"
37 #include "ecmascript/module/js_module_manager.h"
38 #include "ecmascript/module/js_module_source_text.h"
39 #include "ecmascript/runtime_call_id.h"
40 #include "ecmascript/stubs/runtime_stubs.h"
41 #include "ecmascript/sendable_env.h"
42 #include "ecmascript/template_string.h"
43 #include "ecmascript/checkpoint/thread_state_transition.h"
44 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
45 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
46 #endif
47 
48 namespace panda::ecmascript {
49 using CommonStubCSigns = kungfu::CommonStubCSigns;
50 #if defined(__clang__)
51 #pragma clang diagnostic push
52 #pragma clang diagnostic ignored "-Wvoid-ptr-dereference"
53 #pragma clang diagnostic ignored "-Wgnu-label-as-value"
54 #elif defined(__GNUC__)
55 #pragma GCC diagnostic push
56 #pragma GCC diagnostic ignored "-Wpedantic"
57 #endif
58 
59 #if ECMASCRIPT_ENABLE_INTERPRETER_LOG
60 #define HANDLE_OPCODE(opcode)                                           \
61     HANDLE_##opcode:                                                    \
62     {                                                                   \
63         RuntimeStubs::DebugPrintInstruction(thread->GetGlueAddr(), pc); \
64     }
65 #else
66 #define HANDLE_OPCODE(opcode)       \
67     HANDLE_##opcode:
68 #endif
69 
70 #define NOPRINT_HANDLE_OPCODE(opcode) \
71     HANDLE_##opcode:
72 
73 #define LOG_INST() false && LOG_INTERPRETER(DEBUG)
74 
75 #define DEBUG_HANDLE_OPCODE(opcode) \
76     DEBUG_HANDLE_##opcode:
77 
78 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
79 #define ADVANCE_PC(offset) \
80     pc += (offset);  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-macro-usage)
81 
82 #define GOTO_NEXT()  // NOLINT(clang-diagnostic-gnu-label-as-value, cppcoreguidelines-macro-usage)
83 
84 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
85 #define DISPATCH(curOpcode)                                       \
86     do {                                                          \
87         ADVANCE_PC(BytecodeInstruction::Size(EcmaOpcode::curOpcode))  \
88         opcode = READ_INST_OP(); goto *dispatchTable[opcode];     \
89     } while (false)
90 
91 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
92 #define DISPATCH_OFFSET(offset)                               \
93     do {                                                      \
94         ADVANCE_PC(offset)                                    \
95         opcode = READ_INST_OP(); goto *dispatchTable[opcode]; \
96     } while (false)
97 
98 #define DISPATCH_THROW()                  \
99     do {                                  \
100         opcode = *(pc + 1);               \
101         goto *throwDispatchTable[opcode]; \
102     } while (false)
103 
104 #define DISPATCH_WIDE()                  \
105     do {                                 \
106         opcode = *(pc + 1);              \
107         goto *wideDispatchTable[opcode]; \
108     } while (false)
109 
110 #define DISPATCH_DEPRECATED()                  \
111     do {                                       \
112         opcode = *(pc + 1);                    \
113         goto *deprecatedDispatchTable[opcode]; \
114     } while (false)
115 
116 #define DISPATCH_CALLRUNTIME()                  \
117     do {                                        \
118         opcode = *(pc + 1);                     \
119         goto *callRuntimeDispatchTable[opcode]; \
120     } while (false)
121 
122 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
123 #define GET_FRAME(CurrentSp) \
124     (reinterpret_cast<InterpretedFrame *>(CurrentSp) - 1)  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
125 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
126 #define GET_ENTRY_FRAME(sp) \
127     (reinterpret_cast<InterpretedEntryFrame *>(sp) - 1)  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
128 #define GET_BUILTIN_FRAME(sp) \
129     (reinterpret_cast<InterpretedBuiltinFrame *>(sp) - 1)  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
130 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
131 #define SAVE_PC() (GET_FRAME(sp)->pc = pc)  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
132 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
133 #define SAVE_ACC() (GET_FRAME(sp)->acc = acc)  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
134 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
135 #define RESTORE_ACC() (acc = GET_FRAME(sp)->acc)  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
136 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
137 #define GET_VREG(idx) (sp[idx])  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
138 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
139 #define GET_VREG_VALUE(idx) (JSTaggedValue(sp[idx]))  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
140 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
141 #define SET_VREG(idx, val) (sp[idx] = (val));  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
142 #define GET_ACC() (acc)                        // NOLINT(cppcoreguidelines-macro-usage)
143 #define SET_ACC(val) (acc = val)               // NOLINT(cppcoreguidelines-macro-usage)
144 
145 #define GET_METHOD_FROM_CACHE(index) \
146     ConstantPool::GetMethodFromCache(thread, constpool, index)
147 
148 #define GET_STR_FROM_CACHE(index) \
149     ConstantPool::GetStringFromCache(thread, constpool, index)
150 
151 #define GET_LITERA_FROM_CACHE(index, type, module) \
152     ConstantPool::GetLiteralFromCache<type>(thread, constpool, index, module)
153 
154 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
155 #define INTERPRETER_GOTO_EXCEPTION_HANDLER()          \
156     do {                                              \
157         SAVE_PC();                                    \
158         goto *dispatchTable[EXCEPTION_OPCODE]; \
159     } while (false)
160 
161 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
162 #define INTERPRETER_HANDLE_RETURN()                                                     \
163     do {                                                                                \
164         size_t jumpSize = GetJumpSizeAfterCall(pc);                                     \
165         DISPATCH_OFFSET(jumpSize);                                                      \
166     } while (false)
167 
168 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
169 #define CHECK_SWITCH_TO_DEBUGGER_TABLE()                 \
170     if (ecmaVm->GetJsDebuggerManager()->IsDebugMode()) { \
171         dispatchTable = debugDispatchTable.data();       \
172     }
173 
174 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
175 #define REAL_GOTO_DISPATCH_OPCODE(opcode)                       \
176     do {                                                        \
177         ASSERT(static_cast<uint16_t>(opcode) <= 0xff);          \
178         goto *instDispatchTable[static_cast<uint8_t>(opcode)];  \
179     } while (false)
180 
181 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
182 #define REAL_GOTO_EXCEPTION_HANDLER()                     \
183     do {                                                  \
184         SAVE_PC();                                        \
185         goto *instDispatchTable[EXCEPTION_OPCODE]; \
186     } while (false)
187 
188 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
189 #define INTERPRETER_RETURN_IF_ABRUPT(result)      \
190     do {                                          \
191         if (result.IsException()) {               \
192             INTERPRETER_GOTO_EXCEPTION_HANDLER(); \
193         }                                         \
194     } while (false)
195 
196 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
197 #define HANDLE_EXCEPTION_IF_ABRUPT_COMPLETION(_thread)    \
198     do {                                                  \
199         if (UNLIKELY((_thread)->HasPendingException())) { \
200             INTERPRETER_GOTO_EXCEPTION_HANDLER();         \
201         }                                                 \
202     } while (false)
203 
204 #define JUMP_IF_ENTRYFRAME_PENDING()                \
205     do {                                            \
206         if (thread->IsEntryFrameDroppedPending()) { \
207             thread->ResetEntryFrameDroppedState();  \
208             DROPFRAME_JUMP();                       \
209         }                                           \
210     } while (false)
211 
212 #define DROPFRAME_JUMP()                                              \
213     do {                                                              \
214         thread->ResetFrameDroppedState();                             \
215         sp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame()); \
216         InterpretedFrame *state = GET_FRAME(sp);                      \
217         pc = state->pc;                                               \
218         RESTORE_ACC();                                                \
219         DISPATCH_OFFSET(0);                                           \
220     } while (false)
221 
222 #define RESET_AND_JUMP_IF_DROPFRAME()                \
223     do {                                             \
224         if (thread->IsFrameDropped()) {              \
225             if (thread->IsEntryFrameDroppedTrue()) { \
226                 return;                              \
227             }                                        \
228             DROPFRAME_JUMP();                        \
229         }                                            \
230     } while (false)
231 
232 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
233 #define NOTIFY_DEBUGGER_EVENT()          \
234     do {                                 \
235         JUMP_IF_ENTRYFRAME_PENDING();    \
236         SAVE_ACC();                      \
237         SAVE_PC();                       \
238         NotifyBytecodePcChanged(thread); \
239         RESET_AND_JUMP_IF_DROPFRAME();   \
240         RESTORE_ACC();                   \
241     } while (false)
242 
243 /*
244  * reasons of set acc with hole:
245  * 1. acc will become illegal when new error
246  * 2. debugger logic will save acc, so illegal acc will set to frame
247  * 3. when debugger trigger gc, will mark an invalid acc and crash
248  * 4. acc will set to exception later, so it can set to hole template
249  */
250 #define NOTIFY_DEBUGGER_EXCEPTION_EVENT() \
251     do {                                  \
252         SET_ACC(JSTaggedValue::Hole());   \
253         NOTIFY_DEBUGGER_EVENT();          \
254     } while (false)
255 
256 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
257 #define DEPRECATED_CALL_INITIALIZE()                                            \
258     do {                                                                        \
259         SAVE_PC();                                                              \
260         thread->CheckSafepoint();                                               \
261         funcTagged = sp[startReg];                                              \
262         JSTaggedValue funcValue(funcTagged);                                    \
263         if (!funcValue.IsCallable()) {                                          \
264             {                                                                   \
265                 [[maybe_unused]] EcmaHandleScope handleScope(thread);           \
266                 JSHandle<JSObject> error = factory->GetJSError(                 \
267                     ErrorType::TYPE_ERROR, "is not callable", StackCheck::NO);  \
268                 thread->SetException(error.GetTaggedValue());                   \
269             }                                                                   \
270             INTERPRETER_GOTO_EXCEPTION_HANDLER();                               \
271         }                                                                       \
272         funcObject = ECMAObject::Cast(funcValue.GetTaggedObject());             \
273         methodHandle.Update(JSTaggedValue(funcObject->GetCallTarget()));        \
274         newSp = sp - InterpretedFrame::NumOfMembers();                          \
275     } while (false)
276 
277 #define CALL_INITIALIZE()                                                       \
278     do {                                                                        \
279         SAVE_PC();                                                              \
280         SAVE_ACC();                                                             \
281         thread->CheckSafepoint();                                               \
282         RESTORE_ACC();                                                          \
283         funcTagged = acc.GetRawData();                                          \
284         JSTaggedValue funcValue = acc;                                          \
285         if (!funcValue.IsCallable()) {                                          \
286             {                                                                   \
287                 [[maybe_unused]] EcmaHandleScope handleScope(thread);           \
288                 JSHandle<JSObject> error = factory->GetJSError(                 \
289                     ErrorType::TYPE_ERROR, "is not callable", StackCheck::NO);  \
290                 thread->SetException(error.GetTaggedValue());                   \
291             }                                                                   \
292             INTERPRETER_GOTO_EXCEPTION_HANDLER();                               \
293         }                                                                       \
294         funcObject = ECMAObject::Cast(funcValue.GetTaggedObject());             \
295         methodHandle.Update(JSTaggedValue(funcObject->GetCallTarget()));        \
296         newSp = sp - InterpretedFrame::NumOfMembers();                          \
297     } while (false)
298 
299 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
300 #define CALL_PUSH_UNDEFINED(n)                           \
301     do {                                                 \
302         for (int i = 0; i < (n); i++) {                  \
303             *(--newSp) = JSTaggedValue::VALUE_UNDEFINED; \
304         }                                                \
305     } while (false)
306 
307 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
308 #define CALL_PUSH_ARGS_0()          \
309     do {                            \
310         /* do nothing when 0 arg */ \
311     } while (false)
312 
313 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
314 #define DEPRECATED_CALL_PUSH_ARGS_0() CALL_PUSH_ARGS_0()
315 
316 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
317 #define CALL_PUSH_ARGS_1()   \
318     do {                     \
319         *(--newSp) = sp[a0]; \
320     } while (false)
321 
322 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
323 #define DEPRECATED_CALL_PUSH_ARGS_1() CALL_PUSH_ARGS_1()
324 
325 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
326 #define CALL_PUSH_ARGS_2()   \
327     do {                     \
328         *(--newSp) = sp[a1]; \
329         CALL_PUSH_ARGS_1();  \
330     } while (false)
331 
332 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
333 #define DEPRECATED_CALL_PUSH_ARGS_2() CALL_PUSH_ARGS_2()
334 
335 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
336 #define CALL_PUSH_ARGS_3()   \
337     do {                     \
338         *(--newSp) = sp[a2]; \
339         CALL_PUSH_ARGS_2();  \
340     } while (false)
341 
342 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
343 #define DEPRECATED_CALL_PUSH_ARGS_3() CALL_PUSH_ARGS_3()
344 
345 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
346 #define CALL_PUSH_ARGS_RANGE()                                               \
347     do {                                                                     \
348         if (UNLIKELY(thread->DoStackOverflowCheck(newSp - actualNumArgs))) { \
349             INTERPRETER_GOTO_EXCEPTION_HANDLER();                            \
350         }                                                                    \
351         for (int i = actualNumArgs - 1; i >= 0; i--) {                           \
352             *(--newSp) = sp[startReg + static_cast<uint32_t>(i)];            \
353         }                                                                    \
354     } while (false)
355 
356 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
357 #define DEPRECATED_CALL_PUSH_ARGS_RANGE()                                               \
358     do {                                                                     \
359         if (UNLIKELY(thread->DoStackOverflowCheck(newSp - actualNumArgs))) { \
360             INTERPRETER_GOTO_EXCEPTION_HANDLER();                            \
361         }                                                                    \
362         for (int i = actualNumArgs; i > 0; i--) {                            \
363             *(--newSp) = sp[startReg + static_cast<uint32_t>(i)];             \
364         }                                                                    \
365     } while (false)
366 
367 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
368 #define CALL_PUSH_ARGS_THISRANGE()                                          \
369     do {                                                                     \
370         if (UNLIKELY(thread->DoStackOverflowCheck(newSp - actualNumArgs))) { \
371             INTERPRETER_GOTO_EXCEPTION_HANDLER();                            \
372         }                                                                    \
373         /* 1: skip this */                                                   \
374         for (int i = actualNumArgs; i > 0; i--) {                        \
375             *(--newSp) = sp[startReg + static_cast<uint32_t>(i)];             \
376         }                                                                    \
377     } while (false)
378 
379 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
380 #define DEPRECATED_CALL_PUSH_ARGS_THISRANGE()                                          \
381     do {                                                                     \
382         if (UNLIKELY(thread->DoStackOverflowCheck(newSp - actualNumArgs))) { \
383             INTERPRETER_GOTO_EXCEPTION_HANDLER();                            \
384         }                                                                    \
385         /* 1: skip this */                                                   \
386         for (int i = actualNumArgs + 1; i > 1; i--) {                        \
387             *(--newSp) = sp[startReg + static_cast<uint32_t>(i)];             \
388         }                                                                    \
389     } while (false)
390 
391 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
392 #define CALL_PUSH_ARGS_0_NO_EXTRA() \
393     do {                            \
394         /* do nothing when 0 arg */ \
395     } while (false)
396 
397 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
398 #define DEPRECATED_CALL_PUSH_ARGS_0_NO_EXTRA() CALL_PUSH_ARGS_0_NO_EXTRA()
399 
400 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
401 #define CALL_PUSH_ARGS_1_NO_EXTRA()                             \
402     do {                                                        \
403         if (declaredNumArgs >= ActualNumArgsOfCall::CALLARG1) { \
404             *(--newSp) = sp[a0];                                \
405         }                                                       \
406     } while (false)
407 
408 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
409 #define DEPRECATED_CALL_PUSH_ARGS_1_NO_EXTRA() CALL_PUSH_ARGS_1_NO_EXTRA()
410 
411 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
412 #define CALL_PUSH_ARGS_2_NO_EXTRA()                              \
413     do {                                                         \
414         if (declaredNumArgs >= ActualNumArgsOfCall::CALLARGS2) { \
415             *(--newSp) = sp[a1];                                 \
416         }                                                        \
417         DEPRECATED_CALL_PUSH_ARGS_1_NO_EXTRA();                             \
418     } while (false)
419 
420 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
421 #define DEPRECATED_CALL_PUSH_ARGS_2_NO_EXTRA() CALL_PUSH_ARGS_2_NO_EXTRA()
422 
423 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
424 #define CALL_PUSH_ARGS_3_NO_EXTRA()                              \
425     do {                                                         \
426         if (declaredNumArgs >= ActualNumArgsOfCall::CALLARGS3) { \
427             *(--newSp) = sp[a2];                                 \
428         }                                                        \
429         DEPRECATED_CALL_PUSH_ARGS_2_NO_EXTRA();                             \
430     } while (false)
431 
432 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
433 #define DEPRECATED_CALL_PUSH_ARGS_3_NO_EXTRA() CALL_PUSH_ARGS_3_NO_EXTRA()
434 
435 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
436 #define CALL_PUSH_ARGS_RANGE_NO_EXTRA()                                      \
437     do {                                                                     \
438         int num = std::min(actualNumArgs, declaredNumArgs);                  \
439         if (UNLIKELY(thread->DoStackOverflowCheck(newSp - num))) {           \
440             INTERPRETER_GOTO_EXCEPTION_HANDLER();                            \
441         }                                                                    \
442         for (int i = num - 1; i >= 0; i--) {                                 \
443             *(--newSp) = sp[startReg + static_cast<uint32_t>(i)];            \
444         }                                                                    \
445     } while (false)
446 
447 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
448 #define DEPRECATED_CALL_PUSH_ARGS_RANGE_NO_EXTRA()                           \
449     do {                                                                     \
450         int num = std::min(actualNumArgs, declaredNumArgs);                  \
451         if (UNLIKELY(thread->DoStackOverflowCheck(newSp - num))) {           \
452             INTERPRETER_GOTO_EXCEPTION_HANDLER();                            \
453         }                                                                    \
454         for (int i = num; i > 0; i--) {                                      \
455             *(--newSp) = sp[startReg + static_cast<uint32_t>(i)];            \
456         }                                                                    \
457     } while (false)
458 
459 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
460 #define CALL_PUSH_ARGS_THISRANGE_NO_EXTRA()                                      \
461     do {                                                                         \
462         int num = std::min(actualNumArgs, declaredNumArgs);                      \
463         if (UNLIKELY(thread->DoStackOverflowCheck(newSp - num))) {               \
464             INTERPRETER_GOTO_EXCEPTION_HANDLER();                                \
465         }                                                                        \
466         /* 1: skip this */                                                       \
467         for (int i = num; i > 0; i--) {                                          \
468             *(--newSp) = sp[startReg + static_cast<uint32_t>(i)];                \
469         }                                                                        \
470     } while (false)
471 
472 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
473 #define DEPRECATED_CALL_PUSH_ARGS_THISRANGE_NO_EXTRA()                                      \
474     do {                                                                         \
475         int num = std::min(actualNumArgs, declaredNumArgs);                      \
476         if (UNLIKELY(thread->DoStackOverflowCheck(newSp - num))) {               \
477             INTERPRETER_GOTO_EXCEPTION_HANDLER();                                \
478         }                                                                        \
479         /* 1: skip this */                                                       \
480         for (int i = num + 1; i > 1; i--) {                                      \
481             *(--newSp) = sp[startReg + static_cast<uint32_t>(i)];                 \
482         }                                                                        \
483     } while (false)
484 
485 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
486 #define CALL_PUSH_ARGS(ARG_TYPE)                                                   \
487     do {                                                                           \
488         if (methodHandle->IsNativeWithCallField()) {                               \
489             /* native, just push all args directly */                              \
490             CALL_PUSH_ARGS_##ARG_TYPE();                                           \
491             goto setVregsAndFrameNative;                                           \
492         }                                                                          \
493         int32_t declaredNumArgs =                                                  \
494             static_cast<int32_t>(methodHandle->GetNumArgsWithCallField());         \
495         if (actualNumArgs == declaredNumArgs) {                                    \
496             /* fast path, just push all args directly */                           \
497             CALL_PUSH_ARGS_##ARG_TYPE();                                           \
498             goto setVregsAndFrameNotNative;                                        \
499         }                                                                          \
500         /* slow path */                                                            \
501         if (!methodHandle->HaveExtraWithCallField()) {                             \
502             /* push length = declaredNumArgs, may push undefined */                \
503             CALL_PUSH_UNDEFINED(declaredNumArgs - actualNumArgs);                  \
504             CALL_PUSH_ARGS_##ARG_TYPE##_NO_EXTRA();                                \
505         } else {                                                                   \
506             /* push actualNumArgs in the end, then all args, may push undefined */ \
507             *(--newSp) = JSTaggedValue(actualNumArgs).GetRawData();                \
508             CALL_PUSH_UNDEFINED(declaredNumArgs - actualNumArgs);                  \
509             CALL_PUSH_ARGS_##ARG_TYPE();                                           \
510         }                                                                          \
511         goto setVregsAndFrameNotNative;                                            \
512     } while (false)
513 
514 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
515 #define DEPRECATED_CALL_PUSH_ARGS(ARG_TYPE)                                                   \
516     do {                                                                           \
517         if (methodHandle->IsNativeWithCallField()) {                                     \
518             /* native, just push all args directly */                              \
519             DEPRECATED_CALL_PUSH_ARGS_##ARG_TYPE();                                           \
520             goto deprecatedSetVregsAndFrameNative;                                           \
521         }                                                                          \
522         int32_t declaredNumArgs =                                                  \
523             static_cast<int32_t>(methodHandle->GetNumArgsWithCallField());               \
524         if (actualNumArgs == declaredNumArgs) {                                    \
525             /* fast path, just push all args directly */                           \
526             DEPRECATED_CALL_PUSH_ARGS_##ARG_TYPE();                                           \
527             goto deprecatedSetVregsAndFrameNotNative;                                        \
528         }                                                                          \
529         /* slow path */                                                            \
530         if (!methodHandle->HaveExtraWithCallField()) {                                   \
531             /* push length = declaredNumArgs, may push undefined */                \
532             CALL_PUSH_UNDEFINED(declaredNumArgs - actualNumArgs);                  \
533             DEPRECATED_CALL_PUSH_ARGS_##ARG_TYPE##_NO_EXTRA();                                \
534         } else {                                                                   \
535             /* push actualNumArgs in the end, then all args, may push undefined */ \
536             *(--newSp) = JSTaggedValue(actualNumArgs).GetRawData();                \
537             CALL_PUSH_UNDEFINED(declaredNumArgs - actualNumArgs);                  \
538             DEPRECATED_CALL_PUSH_ARGS_##ARG_TYPE();                                           \
539         }                                                                          \
540         goto deprecatedSetVregsAndFrameNotNative;                                            \
541     } while (false)
542 
543 #if ECMASCRIPT_ENABLE_IC
544 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
545 #define UPDATE_HOTNESS_COUNTER_NON_ACC(offset)   (UpdateHotnessCounter(thread, sp, acc, offset))
546 
547 #define UPDATE_HOTNESS_COUNTER(offset)                       \
548     do {                                                     \
549         if (UpdateHotnessCounter(thread, sp, acc, offset)) { \
550             HANDLE_EXCEPTION_IF_ABRUPT_COMPLETION(thread);   \
551             RESTORE_ACC();                                   \
552         }                                                    \
553     } while (false)
554 #else
555 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
556 #define UPDATE_HOTNESS_COUNTER(offset) static_cast<void>(0)
557 #define UPDATE_HOTNESS_COUNTER_NON_ACC(offset) static_cast<void>(0)
558 #endif
559 
560 #define READ_INST_OP() READ_INST_8(0)               // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
561 #define READ_INST_4_0() (READ_INST_8(1) & 0xf)      // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
562 #define READ_INST_4_1() (READ_INST_8(1) >> 4 & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
563 #define READ_INST_4_2() (READ_INST_8(2) & 0xf)      // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
564 #define READ_INST_4_3() (READ_INST_8(2) >> 4 & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
565 #define READ_INST_8_0() READ_INST_8(1)              // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
566 #define READ_INST_8_1() READ_INST_8(2)              // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
567 #define READ_INST_8_2() READ_INST_8(3)              // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
568 #define READ_INST_8_3() READ_INST_8(4)              // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
569 #define READ_INST_8_4() READ_INST_8(5)              // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
570 #define READ_INST_8_5() READ_INST_8(6)              // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
571 #define READ_INST_8_6() READ_INST_8(7)              // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
572 #define READ_INST_8_7() READ_INST_8(8)              // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
573 #define READ_INST_8_8() READ_INST_8(9)              // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
574 #define READ_INST_8_9() READ_INST_8(10)             // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage)
575 #define READ_INST_8(offset) (*(pc + (offset)))
576 #define MOVE_AND_READ_INST_8(currentInst, offset) \
577     currentInst <<= 8;                            \
578     currentInst += READ_INST_8(offset);           \
579 
580 #define READ_INST_16_0() READ_INST_16(2)
581 #define READ_INST_16_1() READ_INST_16(3)
582 #define READ_INST_16_2() READ_INST_16(4)
583 #define READ_INST_16_3() READ_INST_16(5)
584 #define READ_INST_16_4() READ_INST_16(6)
585 #define READ_INST_16_5() READ_INST_16(7)
586 #define READ_INST_16_6() READ_INST_16(8)
587 #define READ_INST_16_7() READ_INST_16(9)
588 #define READ_INST_16(offset)                          \
589     ({                                                \
590         uint16_t currentInst = READ_INST_8(offset);   \
591         MOVE_AND_READ_INST_8(currentInst, offset - 1) \
592     })
593 
594 #define READ_INST_32_0() READ_INST_32(4)
595 #define READ_INST_32_1() READ_INST_32(5)
596 #define READ_INST_32_2() READ_INST_32(6)
597 #define READ_INST_32(offset)                          \
598     ({                                                \
599         uint32_t currentInst = READ_INST_8(offset);   \
600         MOVE_AND_READ_INST_8(currentInst, offset - 1) \
601         MOVE_AND_READ_INST_8(currentInst, offset - 2) \
602         MOVE_AND_READ_INST_8(currentInst, offset - 3) \
603     })
604 
605 #define READ_INST_64_0()                       \
606     ({                                         \
607         uint64_t currentInst = READ_INST_8(8); \
608         MOVE_AND_READ_INST_8(currentInst, 7)   \
609         MOVE_AND_READ_INST_8(currentInst, 6)   \
610         MOVE_AND_READ_INST_8(currentInst, 5)   \
611         MOVE_AND_READ_INST_8(currentInst, 4)   \
612         MOVE_AND_READ_INST_8(currentInst, 3)   \
613         MOVE_AND_READ_INST_8(currentInst, 2)   \
614         MOVE_AND_READ_INST_8(currentInst, 1)   \
615     })
616 
617 #undef LOG_INST
618 #undef HANDLE_OPCODE
619 #undef ADVANCE_PC
620 #undef GOTO_NEXT
621 #undef DISPATCH
622 #undef DISPATCH_OFFSET
623 #undef GET_FRAME
624 #undef GET_ENTRY_FRAME
625 #undef SAVE_PC
626 #undef SAVE_ACC
627 #undef RESTORE_ACC
628 #undef INTERPRETER_GOTO_EXCEPTION_HANDLER
629 #undef CHECK_SWITCH_TO_DEBUGGER_TABLE
630 #undef REAL_GOTO_DISPATCH_OPCODE
631 #undef REAL_GOTO_EXCEPTION_HANDLER
632 #undef INTERPRETER_RETURN_IF_ABRUPT
633 #undef NOTIFY_DEBUGGER_EVENT
634 #undef DEPRECATED_CALL_INITIALIZE
635 #undef CALL_PUSH_UNDEFINED
636 #undef DEPRECATED_CALL_PUSH_ARGS_0
637 #undef DEPRECATED_CALL_PUSH_ARGS_1
638 #undef DEPRECATED_CALL_PUSH_ARGS_2
639 #undef DEPRECATED_CALL_PUSH_ARGS_3
640 #undef DEPRECATED_CALL_PUSH_ARGS_RANGE
641 #undef DEPRECATED_CALL_PUSH_ARGS_THISRANGE
642 #undef DEPRECATED_CALL_PUSH_ARGS_0_NO_EXTRA
643 #undef DEPRECATED_CALL_PUSH_ARGS_1_NO_EXTRA
644 #undef DEPRECATED_CALL_PUSH_ARGS_2_NO_EXTRA
645 #undef DEPRECATED_CALL_PUSH_ARGS_3_NO_EXTRA
646 #undef DEPRECATED_CALL_PUSH_ARGS_RANGE_NO_EXTRA
647 #undef DEPRECATED_CALL_PUSH_ARGS_THISRANGE_NO_EXTRA
648 #undef DEPRECATED_CALL_PUSH_ARGS
649 #undef UPDATE_HOTNESS_COUNTER_NON_ACC
650 #undef UPDATE_HOTNESS_COUNTER
651 #undef GET_VREG
652 #undef GET_VREG_VALUE
653 #undef SET_VREG
654 #undef GET_ACC
655 #undef SET_ACC
656 #if defined(__clang__)
657 #pragma clang diagnostic pop
658 #elif defined(__GNUC__)
659 #pragma GCC diagnostic pop
660 #endif
661 }  // namespace panda::ecmascript
662 #endif  // ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H
663