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_COMPILER_INTERPRETER_STUB_INL_H
17#define ECMASCRIPT_COMPILER_INTERPRETER_STUB_INL_H
18
19#include "ecmascript/compiler/interpreter_stub.h"
20#include "ecmascript/compiler/new_object_stub_builder.h"
21#include "ecmascript/compiler/share_gate_meta_data.h"
22#include "ecmascript/module/js_module_source_text.h"
23#include "ecmascript/global_env.h"
24#include "ecmascript/js_async_generator_object.h"
25#include "ecmascript/js_arguments.h"
26#include "ecmascript/js_function.h"
27#include "ecmascript/js_generator_object.h"
28
29namespace panda::ecmascript::kungfu {
30void InterpreterStubBuilder::SetVregValue(GateRef glue, GateRef sp, GateRef idx, GateRef val)
31{
32    Store(VariableType::INT64(), glue, sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx), val);
33}
34
35inline GateRef InterpreterStubBuilder::GetVregValue(GateRef sp, GateRef idx)
36{
37    return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx));
38}
39
40GateRef InterpreterStubBuilder::ReadInst8_0(GateRef pc)
41{
42    return Load(VariableType::INT8(), pc, IntPtr(1));  // 1 : skip 1 byte of bytecode
43}
44
45GateRef InterpreterStubBuilder::ReadInst8_1(GateRef pc)
46{
47    return Load(VariableType::INT8(), pc, IntPtr(2));  // 2 : skip 1 byte of bytecode
48}
49
50GateRef InterpreterStubBuilder::ReadInst8_2(GateRef pc)
51{
52    return Load(VariableType::INT8(), pc, IntPtr(3));  // 3 : skip 1 byte of bytecode
53}
54
55GateRef InterpreterStubBuilder::ReadInst8_3(GateRef pc)
56{
57    return Load(VariableType::INT8(), pc, IntPtr(4));  // 4 : skip 1 byte of bytecode
58}
59
60GateRef InterpreterStubBuilder::ReadInst8_4(GateRef pc)
61{
62    return Load(VariableType::INT8(), pc, IntPtr(5));  // 5 : skip 1 byte of bytecode
63}
64
65GateRef InterpreterStubBuilder::ReadInst8_5(GateRef pc)
66{
67    return Load(VariableType::INT8(), pc, IntPtr(6));  // 6 : skip 1 byte of bytecode
68}
69
70GateRef InterpreterStubBuilder::ReadInst8_6(GateRef pc)
71{
72    return Load(VariableType::INT8(), pc, IntPtr(7));  // 7 : skip 1 byte of bytecode
73}
74
75GateRef InterpreterStubBuilder::ReadInst8_7(GateRef pc)
76{
77    return Load(VariableType::INT8(), pc, IntPtr(8));  // 8 : skip 1 byte of bytecode
78}
79
80GateRef InterpreterStubBuilder::ReadInst8_8(GateRef pc)
81{
82    return Load(VariableType::INT8(), pc, IntPtr(9));  // 9 : skip 1 byte of bytecode
83}
84
85GateRef InterpreterStubBuilder::ReadInst8_9(GateRef pc)
86{
87    return Load(VariableType::INT8(), pc, IntPtr(10));  // 10 : skip 1 byte of bytecode
88}
89
90GateRef InterpreterStubBuilder::ReadInst4_0(GateRef pc)
91{
92    return Int8And(Load(VariableType::INT8(), pc, IntPtr(1)), Int8(0xf));
93}
94
95GateRef InterpreterStubBuilder::ReadInst4_1(GateRef pc)
96{
97    // 1 : skip 1 byte of bytecode
98    return Int8And(
99        Int8LSR(Load(VariableType::INT8(), pc, IntPtr(1)), Int8(4)), Int8(0xf));  // 4: read 4 byte of bytecode
100}
101
102GateRef InterpreterStubBuilder::ReadInst4_2(GateRef pc)
103{
104    // 2 : skip 1 byte of bytecode
105    return Int8And(Load(VariableType::INT8(), pc, IntPtr(2)), Int8(0xf));
106}
107
108GateRef InterpreterStubBuilder::ReadInst4_3(GateRef pc)
109{
110    // 2 : skip 1 byte of bytecode
111    return Int8And(
112        Int8LSR(Load(VariableType::INT8(), pc, IntPtr(2)), Int8(4)), Int8(0xf));  // 4 : read 4 byte of bytecode
113}
114
115GateRef InterpreterStubBuilder::ReadInstSigned8_0(GateRef pc)
116{
117    GateRef x = Load(VariableType::INT8(), pc, IntPtr(1));  // 1 : skip 1 byte of bytecode
118    return GetEnvironment()->GetBuilder()->SExtInt1ToInt32(x);
119}
120
121GateRef InterpreterStubBuilder::ReadInstSigned16_0(GateRef pc)
122{
123    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
124        GateRef currentInst = Load(VariableType::INT16(), pc, IntPtr(1));  // 1 : skip 1 byte of bytecode
125        return GetEnvironment()->GetBuilder()->SExtInt16ToInt32(currentInst);
126    }
127    /* 2 : skip 8 bits of opcode and 8 bits of low bits */
128    GateRef currentInst = Load(VariableType::INT8(), pc, IntPtr(2));
129    GateRef currentInst1 = GetEnvironment()->GetBuilder()->SExtInt1ToInt32(currentInst);
130    GateRef currentInst2 = Int32LSL(currentInst1, Int32(8));  // 8 : set as high 8 bits
131    return Int32Add(currentInst2, ZExtInt8ToInt32(ReadInst8_0(pc)));
132}
133
134GateRef InterpreterStubBuilder::ReadInstSigned32_0(GateRef pc)
135{
136    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
137        GateRef x = Load(VariableType::INT32(), pc, IntPtr(1));  // 1 : skip 1 byte of bytecode
138        return GetEnvironment()->GetBuilder()->SExtInt1ToInt32(x);
139    }
140    /* 4 : skip 8 bits of opcode and 24 bits of low bits */
141    GateRef x = Load(VariableType::INT8(), pc, IntPtr(4));
142    GateRef currentInst = GetEnvironment()->GetBuilder()->SExtInt1ToInt32(x);
143    GateRef currentInst1 = Int32LSL(currentInst, Int32(8));  // 8 : set as high 8 bits
144    GateRef currentInst2 = Int32Add(currentInst1, ZExtInt8ToInt32(ReadInst8_2(pc)));
145    GateRef currentInst3 = Int32LSL(currentInst2, Int32(8));  // 8 : set as high 8 bits
146    GateRef currentInst4 = Int32Add(currentInst3, ZExtInt8ToInt32(ReadInst8_1(pc)));
147    GateRef currentInst5 = Int32LSL(currentInst4, Int32(8));  // 8 : set as high 8 bits
148    return Int32Add(currentInst5, ZExtInt8ToInt32(ReadInst8_0(pc)));
149}
150
151GateRef InterpreterStubBuilder::ReadInst16_0(GateRef pc)
152{
153    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
154        return Load(VariableType::INT16(), pc, IntPtr(1));  // 1 : skip 1 byte of bytecode
155    }
156    /* 2 : skip 8 bits of opcode and 8 bits of low bits */
157    GateRef currentInst1 = ZExtInt8ToInt16(ReadInst8_1(pc));
158    GateRef currentInst2 = Int16LSL(currentInst1, Int16(8));  // 8 : set as high 8 bits
159    return Int16Add(currentInst2, ZExtInt8ToInt16(ReadInst8_0(pc)));
160}
161
162GateRef InterpreterStubBuilder::ReadInst16_1(GateRef pc)
163{
164    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
165        return Load(VariableType::INT16(), pc, IntPtr(2));  // 2 : skip 2 bytes of bytecode
166    }
167    /* 3 : skip 8 bits of opcode, 8 bits of prefix and 8 bits of low bits */
168    GateRef currentInst1 = ZExtInt8ToInt16(ReadInst8_2(pc));
169    GateRef currentInst2 = Int16LSL(currentInst1, Int16(8));  // 8 : set as high 8 bits
170    /* 2 : skip 8 bits of opcode and 8 bits of prefix */
171    return Int16Add(currentInst2, ZExtInt8ToInt16(ReadInst8_1(pc)));
172}
173
174GateRef InterpreterStubBuilder::ReadInst16_2(GateRef pc)
175{
176    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
177        return Load(VariableType::INT16(), pc, IntPtr(3));  // 3 : skip 3 bytes of bytecode
178    }
179    /* 4 : skip 8 bits of opcode, first parameter of 16 bits and 8 bits of low bits */
180    GateRef currentInst1 = ZExtInt8ToInt16(ReadInst8_3(pc));
181    GateRef currentInst2 = Int16LSL(currentInst1, Int16(8));  // 8 : set as high 8 bits
182    /* 3 : skip 8 bits of opcode and first parameter of 16 bits */
183    return Int16Add(currentInst2, ZExtInt8ToInt16(ReadInst8_2(pc)));
184}
185
186GateRef InterpreterStubBuilder::ReadInst16_3(GateRef pc)
187{
188    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
189        return Load(VariableType::INT16(), pc, IntPtr(4));  // 4 : skip 4 bytes of bytecode
190    }
191    /* 5 : skip 8 bits of opcode, 8 bits of prefix, first parameter of 16 bits and 8 bits of low bits */
192    GateRef currentInst1 = ZExtInt8ToInt16(ReadInst8_4(pc));
193    GateRef currentInst2 = Int16LSL(currentInst1, Int16(8));  // 8 : set as high 8 bits
194    /* 4 : skip 8 bits of opcode, 8 bits of prefix and first parameter of 16 bits */
195    return Int16Add(currentInst2, ZExtInt8ToInt16(ReadInst8_3(pc)));
196}
197
198GateRef InterpreterStubBuilder::ReadInst16_4(GateRef pc)
199{
200    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
201        return Load(VariableType::INT16(), pc, IntPtr(5));  // 5 : skip 5 bytes of bytecode
202    }
203    /* 7 : skip 8 bits of opcode, 8 bits of prefix, first 2 parameters of 16 bits and 8 bits of low bits */
204    GateRef currentInst1 = ZExtInt8ToInt16(ReadInst8_5(pc));
205    GateRef currentInst2 = Int16LSL(currentInst1, Int16(8));  // 8 : set as high 8 bits
206    /* 6 : skip 8 bits of opcode, 8 bits of prefix and first 2 parameters of 16 bits */
207    return Int16Add(currentInst2, ZExtInt8ToInt16(ReadInst8_4(pc)));
208}
209
210GateRef InterpreterStubBuilder::ReadInst16_5(GateRef pc)
211{
212    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
213        return Load(VariableType::INT16(), pc, IntPtr(6));  // 6 : skip 6 bytes of bytecode
214    }
215    /* 7 : skip 8 bits of opcode, 8 bits of prefix, first 2 parameters of 16 bits and 8 bits of low bits */
216    GateRef currentInst1 = ZExtInt8ToInt16(ReadInst8_6(pc));
217    GateRef currentInst2 = Int16LSL(currentInst1, Int16(8));  // 8 : set as high 8 bits
218    /* 6 : skip 8 bits of opcode, 8 bits of prefix and first 2 parameters of 16 bits */
219    return Int16Add(currentInst2, ZExtInt8ToInt16(ReadInst8_5(pc)));
220}
221
222GateRef InterpreterStubBuilder::ReadInst16_6(GateRef pc)
223{
224    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
225        return Load(VariableType::INT16(), pc, IntPtr(7));  // 7 : skip 7 bytes of bytecode
226    }
227    /* 7 : skip 8 bits of opcode, 8 bits of prefix, first 2 parameters of 16 bits and 8 bits of low bits */
228    GateRef currentInst1 = ZExtInt8ToInt16(ReadInst8_7(pc));
229    GateRef currentInst2 = Int16LSL(currentInst1, Int16(8));  // 8 : set as high 8 bits
230    /* 6 : skip 8 bits of opcode, 8 bits of prefix and first 2 parameters of 16 bits */
231    return Int16Add(currentInst2, ZExtInt8ToInt16(ReadInst8_6(pc)));
232}
233
234GateRef InterpreterStubBuilder::ReadInst16_7(GateRef pc)
235{
236    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
237        return Load(VariableType::INT16(), pc, IntPtr(8));  // 8 : skip 8 bytes of bytecode
238    }
239    /* 7 : skip 8 bits of opcode, 8 bits of prefix, first 2 parameters of 16 bits and 8 bits of low bits */
240    GateRef currentInst1 = ZExtInt8ToInt16(ReadInst8_8(pc));
241    GateRef currentInst2 = Int16LSL(currentInst1, Int16(8));  // 8 : set as high 8 bits
242    /* 6 : skip 8 bits of opcode, 8 bits of prefix and first 2 parameters of 16 bits */
243    return Int16Add(currentInst2, ZExtInt8ToInt16(ReadInst8_9(pc)));
244}
245
246GateRef InterpreterStubBuilder::GetFrame(GateRef CurrentSp)
247{
248    return PtrSub(CurrentSp, IntPtr(AsmInterpretedFrame::GetSize(GetEnvironment()->IsArch32Bit())));
249}
250
251GateRef InterpreterStubBuilder::GetPcFromFrame(GateRef frame)
252{
253    return Load(VariableType::NATIVE_POINTER(), frame,
254        IntPtr(AsmInterpretedFrame::GetPcOffset(GetEnvironment()->IsArch32Bit())));
255}
256
257GateRef InterpreterStubBuilder::GetFunctionFromFrame(GateRef frame)
258{
259    return Load(VariableType::JS_POINTER(), frame,
260        IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
261}
262
263GateRef InterpreterStubBuilder::GetNewTarget(GateRef sp)
264{
265    GateRef function = Load(VariableType::JS_POINTER(), GetFrame(sp),
266        IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
267    GateRef method = GetMethodFromFunction(function);
268    GateRef callField = GetCallFieldFromMethod(method);
269    // ASSERT: callField has "extra" bit.
270    GateRef numVregs = TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(MethodLiteral::NumVregsBits::START_BIT)),
271        Int64((1LLU << MethodLiteral::NumVregsBits::SIZE) - 1)));
272    GateRef haveFunc = ZExtInt1ToInt32(Int64NotEqual(Int64And(Int64LSR(callField,
273        Int64(MethodLiteral::HaveFuncBit::START_BIT)),
274        Int64((1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1)), Int64(0)));
275    GateRef idx = ZExtInt32ToPtr(Int32Add(numVregs, haveFunc));
276    return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), idx));
277}
278
279GateRef InterpreterStubBuilder::GetThisFromFrame(GateRef frame)
280{
281    return Load(VariableType::JS_POINTER(), frame,
282        IntPtr(AsmInterpretedFrame::GetThisOffset(GetEnvironment()->IsArch32Bit())));
283}
284
285GateRef InterpreterStubBuilder::GetCallSizeFromFrame(GateRef frame)
286{
287    return Load(VariableType::NATIVE_POINTER(), frame,
288        IntPtr(AsmInterpretedFrame::GetCallSizeOffset(GetEnvironment()->IsArch32Bit())));
289}
290
291GateRef InterpreterStubBuilder::GetAccFromFrame(GateRef frame)
292{
293    return Load(VariableType::JS_ANY(), frame,
294        IntPtr(AsmInterpretedFrame::GetAccOffset(GetEnvironment()->IsArch32Bit())));
295}
296
297GateRef InterpreterStubBuilder::GetEnvFromFrame(GateRef frame)
298{
299    return Load(VariableType::JS_POINTER(), frame,
300        IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())));
301}
302
303GateRef InterpreterStubBuilder::GetEnvFromFunction(GateRef function)
304{
305    return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::LEXICAL_ENV_OFFSET));
306}
307
308GateRef InterpreterStubBuilder::GetProfileTypeInfoFromFunction(GateRef function)
309{
310    GateRef raw = Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
311    return Load(VariableType::JS_POINTER(), raw, IntPtr(ProfileTypeInfoCell::VALUE_OFFSET));
312}
313
314GateRef InterpreterStubBuilder::GetModuleFromFunction(GateRef function)
315{
316    return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::ECMA_MODULE_OFFSET));
317}
318
319GateRef InterpreterStubBuilder::GetSendableEnvFromModule(GateRef module)
320{
321    return Load(VariableType::JS_POINTER(), module, IntPtr(SourceTextModule::SENDABLE_ENV_OFFSET));
322}
323
324GateRef InterpreterStubBuilder::GetHomeObjectFromFunction(GateRef function)
325{
326    return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::HOME_OBJECT_OFFSET));
327}
328
329GateRef InterpreterStubBuilder::GetConstpoolFromMethod(GateRef method)
330{
331    return Load(VariableType::JS_POINTER(), method, IntPtr(Method::CONSTANT_POOL_OFFSET));
332}
333
334GateRef InterpreterStubBuilder::GetModule(GateRef sp)
335{
336    GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
337    return GetModuleFromFunction(currentFunc);
338}
339
340GateRef InterpreterStubBuilder::GetResumeModeFromGeneratorObject(GateRef obj)
341{
342    GateRef bitfieldOffset = IntPtr(JSGeneratorObject::BIT_FIELD_OFFSET);
343    GateRef bitfield = Load(VariableType::INT32(), obj, bitfieldOffset);
344    return Int32And(
345        Int32LSR(bitfield, Int32(JSGeneratorObject::ResumeModeBits::START_BIT)),
346        Int32((1LU << JSGeneratorObject::ResumeModeBits::SIZE) - 1));
347}
348
349GateRef InterpreterStubBuilder::GetResumeModeFromAsyncGeneratorObject(GateRef obj)
350{
351    GateRef bitfieldOffset = IntPtr(JSAsyncGeneratorObject::BIT_FIELD_OFFSET);
352    GateRef bitfield = Load(VariableType::INT32(), obj, bitfieldOffset);
353    return Int32And(
354        Int32LSR(bitfield, Int32(JSAsyncGeneratorObject::ResumeModeBits::START_BIT)),
355        Int32((1LU << JSAsyncGeneratorObject::ResumeModeBits::SIZE) - 1));
356}
357
358void InterpreterStubBuilder::SetPcToFrame(GateRef glue, GateRef frame, GateRef value)
359{
360    Store(VariableType::INT64(), glue, frame,
361        IntPtr(AsmInterpretedFrame::GetPcOffset(GetEnvironment()->IsArch32Bit())), value);
362}
363
364void InterpreterStubBuilder::SetCallSizeToFrame(GateRef glue, GateRef frame, GateRef value)
365{
366    Store(VariableType::NATIVE_POINTER(), glue, frame,
367          IntPtr(AsmInterpretedFrame::GetCallSizeOffset(GetEnvironment()->IsArch32Bit())), value);
368}
369
370void InterpreterStubBuilder::SetAccToFrame(GateRef glue, GateRef frame, GateRef value)
371{
372    Store(VariableType::INT64(), glue, frame,
373          IntPtr(AsmInterpretedFrame::GetAccOffset(GetEnvironment()->IsArch32Bit())), value);
374}
375
376void InterpreterStubBuilder::SetEnvToFrame(GateRef glue, GateRef frame, GateRef value)
377{
378    Store(VariableType::INT64(), glue, frame,
379          IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())), value);
380}
381
382void InterpreterStubBuilder::SetFunctionToFrame(GateRef glue, GateRef frame, GateRef value)
383{
384    Store(VariableType::INT64(), glue, frame,
385          IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())), value);
386}
387
388void InterpreterStubBuilder::SetHomeObjectToFunction(GateRef glue, GateRef function, GateRef value)
389{
390    GateRef offset = IntPtr(JSFunction::HOME_OBJECT_OFFSET);
391    Store(VariableType::JS_ANY(), glue, function, offset, value);
392}
393
394void InterpreterStubBuilder::SetFrameState(GateRef glue, GateRef sp, GateRef function, GateRef acc,
395    GateRef env, GateRef pc, GateRef prev, GateRef type)
396{
397    GateRef state = GetFrame(sp);
398    SetFunctionToFrame(glue, state, function);
399    SetAccToFrame(glue, state, acc);
400    SetEnvToFrame(glue, state, env);
401    SetPcToFrame(glue, state, pc);
402    GateRef prevOffset = IntPtr(AsmInterpretedFrame::GetBaseOffset(GetEnvironment()->IsArch32Bit()));
403    Store(VariableType::NATIVE_POINTER(), glue, state, prevOffset, prev);
404    GateRef frameTypeOffset = PtrAdd(prevOffset, IntPtr(
405        InterpretedFrameBase::GetTypeOffset(GetEnvironment()->IsArch32Bit())));
406    Store(VariableType::INT64(), glue, state, frameTypeOffset, type);
407}
408
409GateRef InterpreterStubBuilder::GetCurrentSpFrame(GateRef glue)
410{
411    bool isArch32 = GetEnvironment()->Is32Bit();
412    GateRef spOffset = IntPtr(JSThread::GlueData::GetCurrentFrameOffset(isArch32));
413    return Load(VariableType::NATIVE_POINTER(), glue, spOffset);
414}
415
416void InterpreterStubBuilder::SetCurrentSpFrame(GateRef glue, GateRef value)
417{
418    GateRef spOffset = IntPtr(JSThread::GlueData::GetCurrentFrameOffset(GetEnvironment()->Is32Bit()));
419    Store(VariableType::NATIVE_POINTER(), glue, glue, spOffset, value);
420}
421
422GateRef InterpreterStubBuilder::GetLastLeaveFrame(GateRef glue)
423{
424    bool isArch32 = GetEnvironment()->Is32Bit();
425    GateRef spOffset = IntPtr(JSThread::GlueData::GetLeaveFrameOffset(isArch32));
426    return Load(VariableType::NATIVE_POINTER(), glue, spOffset);
427}
428
429void InterpreterStubBuilder::SetLastLeaveFrame(GateRef glue, GateRef value)
430{
431    GateRef spOffset = IntPtr(JSThread::GlueData::GetLeaveFrameOffset(GetEnvironment()->Is32Bit()));
432    Store(VariableType::NATIVE_POINTER(), glue, glue, spOffset, value);
433}
434
435GateRef InterpreterStubBuilder::CheckStackOverflow(GateRef glue, GateRef sp)
436{
437    GateRef frameBaseOffset = IntPtr(JSThread::GlueData::GetFrameBaseOffset(GetEnvironment()->IsArch32Bit()));
438    GateRef frameBase = Load(VariableType::NATIVE_POINTER(), glue, frameBaseOffset);
439    return Int64UnsignedLessThanOrEqual(sp,
440        PtrAdd(frameBase, IntPtr(JSThread::RESERVE_STACK_SIZE * sizeof(JSTaggedType))));
441}
442
443GateRef InterpreterStubBuilder::PushArg(GateRef glue, GateRef sp, GateRef value)
444{
445    GateRef newSp = PtrSub(sp, IntPtr(sizeof(JSTaggedType)));
446    // 0 : skip 0 byte of bytecode
447    Store(VariableType::INT64(), glue, newSp, IntPtr(0), value);
448    return newSp;
449}
450
451GateRef InterpreterStubBuilder::PushUndefined(GateRef glue, GateRef sp, GateRef num)
452{
453    auto env = GetEnvironment();
454    Label subEntry(env);
455    env->SubCfgEntry(&subEntry);
456    DEFVARIABLE(newSp, VariableType::NATIVE_POINTER(), sp);
457    DEFVARIABLE(i, VariableType::INT32(), Int32(0));
458    Label pushUndefinedBegin(env);
459    Label pushUndefinedAgain(env);
460    Label pushUndefinedEnd(env);
461    BRANCH(Int32LessThan(*i, num), &pushUndefinedBegin, &pushUndefinedEnd);
462    LoopBegin(&pushUndefinedBegin);
463    newSp = PushArg(glue, *newSp, Undefined());
464    i = Int32Add(*i, Int32(1));  // 1 : set as high 1 bits
465    BRANCH(Int32LessThan(*i, num), &pushUndefinedAgain, &pushUndefinedEnd);
466    Bind(&pushUndefinedAgain);
467    LoopEnd(&pushUndefinedBegin);
468    Bind(&pushUndefinedEnd);
469    auto ret = *newSp;
470    env->SubCfgExit();
471    return ret;
472}
473
474GateRef InterpreterStubBuilder::PushRange(GateRef glue, GateRef sp, GateRef array, GateRef startIndex, GateRef endIndex)
475{
476    auto env = GetEnvironment();
477    Label subEntry(env);
478    env->SubCfgEntry(&subEntry);
479    DEFVARIABLE(newSp, VariableType::NATIVE_POINTER(), sp);
480    DEFVARIABLE(i, VariableType::INT32(), endIndex);
481    Label pushArgsBegin(env);
482    Label pushArgsAgain(env);
483    Label pushArgsEnd(env);
484    BRANCH(Int32GreaterThanOrEqual(*i, startIndex), &pushArgsBegin, &pushArgsEnd);
485    LoopBegin(&pushArgsBegin);
486    GateRef arg = GetVregValue(array, ZExtInt32ToPtr(*i));
487    newSp = PushArg(glue, *newSp, arg);
488    i = Int32Sub(*i, Int32(1));  // 1 : set as high 1 bits
489    BRANCH(Int32GreaterThanOrEqual(*i, startIndex), &pushArgsAgain, &pushArgsEnd);
490    Bind(&pushArgsAgain);
491    LoopEnd(&pushArgsBegin);
492    Bind(&pushArgsEnd);
493    auto ret = *newSp;
494    env->SubCfgExit();
495    return ret;
496}
497
498GateRef InterpreterStubBuilder::GetStartIdxAndNumArgs(GateRef sp, GateRef restIdx)
499{
500    auto env = GetEnvironment();
501    Label subEntry(env);
502    env->SubCfgEntry(&subEntry);
503    DEFVARIABLE(numArgs, VariableType::INT32(), Int32(0));
504    GateRef state = PtrSub(sp, IntPtr(AsmInterpretedFrame::GetSize(env->IsArch32Bit())));
505    GateRef function = GetFunctionFromFrame(state);
506    GateRef method = GetMethodFromJSFunctionOrProxy(function);
507    GateRef callField = GetCallFieldFromMethod(method);
508    // ASSERT: callField has "extra" bit.
509    GateRef numVregs = TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(MethodLiteral::NumVregsBits::START_BIT)),
510        Int64((1LLU << MethodLiteral::NumVregsBits::SIZE) - 1)));
511    GateRef haveFunc = Int64NotEqual(Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveFuncBit::START_BIT)),
512        Int64((1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1)), Int64(0));
513    GateRef haveNewTarget = Int64NotEqual(
514        Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveNewTargetBit::START_BIT)),
515        Int64((1LLU << MethodLiteral::HaveNewTargetBit::SIZE) - 1)), Int64(0));
516    GateRef haveThis = Int64NotEqual(Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveThisBit::START_BIT)),
517        Int64((1LLU << MethodLiteral::HaveThisBit::SIZE) - 1)), Int64(0));
518    GateRef copyArgs = Int32Add(Int32Add(ZExtInt1ToInt32(haveFunc), ZExtInt1ToInt32(haveNewTarget)),
519                                ZExtInt1ToInt32(haveThis));
520    numArgs = TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
521                                         Int64((1LLU << MethodLiteral::NumArgsBits::SIZE) - 1)));
522    GateRef fp = Load(VariableType::NATIVE_POINTER(), state,
523                      IntPtr(AsmInterpretedFrame::GetFpOffset(env->IsArch32Bit())));
524    Label actualEqualDeclared(env);
525    Label actualNotEqualDeclared(env);
526    BRANCH(Int32UnsignedGreaterThan(ChangeIntPtrToInt32(PtrSub(fp, sp)),
527                                    Int32Mul(Int32Add(Int32Add(numVregs, copyArgs), *numArgs),
528                                             Int32(sizeof(JSTaggedType)))),
529           &actualNotEqualDeclared, &actualEqualDeclared);
530    Bind(&actualNotEqualDeclared);
531    {
532        numArgs = GetInt32OfTInt(Load(VariableType::JS_ANY(), fp, IntPtr(-sizeof(JSTaggedType))));
533        Jump(&actualEqualDeclared);
534    }
535    Bind(&actualEqualDeclared);
536    GateRef startIdx = Int32Add(Int32Add(numVregs, copyArgs), restIdx);
537    Label numArgsGreater(env);
538    Label numArgsNotGreater(env);
539    Label exit(env);
540    BRANCH(Int32UnsignedGreaterThan(*numArgs, restIdx), &numArgsGreater, &numArgsNotGreater);
541    Bind(&numArgsGreater);
542    {
543        numArgs = Int32Sub(*numArgs, restIdx);
544        Jump(&exit);
545    }
546    Bind(&numArgsNotGreater);
547    {
548        numArgs = Int32(0);
549        Jump(&exit);
550    }
551    Bind(&exit);
552    // 32: high 32 bits = startIdx, low 32 bits = numArgs
553    GateRef ret = Int64Or(Int64LSL(ZExtInt32ToInt64(startIdx), Int64(32)), ZExtInt32ToInt64(*numArgs));
554    env->SubCfgExit();
555    return ret;
556}
557
558GateRef InterpreterStubBuilder::GetCurrentFrame(GateRef glue)
559{
560    return GetLastLeaveFrame(glue);
561}
562
563void InterpreterStubBuilder::UpdateProfileTypeInfoCellToFunction(GateRef glue, GateRef function,
564                                                                 GateRef profileTypeInfo, GateRef slotId)
565{
566    auto env = GetEnvironment();
567    Label subEntry(env);
568    env->SubCfgEntry(&subEntry);
569
570    Label profileTypeInfoNotUndefined(env);
571    Label slotValueUpdate(env);
572    Label slotValueNotUndefined(env);
573    Label slotValueNotHole(env);
574    Label profileTypeInfoEnd(env);
575    NewObjectStubBuilder newBuilder(this);
576    BRANCH(TaggedIsUndefined(profileTypeInfo), &profileTypeInfoEnd, &profileTypeInfoNotUndefined);
577    Bind(&profileTypeInfoNotUndefined);
578    {
579        GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
580        BRANCH_UNLIKELY(TaggedIsUndefined(slotValue), &slotValueUpdate, &slotValueNotUndefined);
581        Bind(&slotValueUpdate);
582        {
583            GateRef newProfileTypeInfoCell = newBuilder.NewProfileTypeInfoCell(glue, Undefined());
584            SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, newProfileTypeInfoCell,
585                                  MemoryAttribute::NeedNotShareBarrier());
586            SetRawProfileTypeInfoToFunction(glue, function, newProfileTypeInfoCell,
587                                            MemoryAttribute::NeedNotShareBarrier());
588            Jump(&profileTypeInfoEnd);
589        }
590        Bind(&slotValueNotUndefined);
591        BRANCH_UNLIKELY(TaggedIsHole(slotValue), &profileTypeInfoEnd, &slotValueNotHole);
592        Bind(&slotValueNotHole);
593        {
594            UpdateProfileTypeInfoCellType(glue, slotValue);
595            SetRawProfileTypeInfoToFunction(glue, function, slotValue, MemoryAttribute::NeedNotShareBarrier());
596            TryToJitReuseCompiledFunc(glue, function, slotValue);
597        }
598        Jump(&profileTypeInfoEnd);
599    }
600    Bind(&profileTypeInfoEnd);
601
602    env->SubCfgExit();
603}
604
605GateRef InterpreterStubBuilder::ReadInst32_0(GateRef pc)
606{
607    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
608        return Load(VariableType::INT32(), pc, IntPtr(1));  // 1 : skip 1 byte of bytecode
609    }
610    GateRef currentInst = ZExtInt8ToInt32(ReadInst8_3(pc));
611    GateRef currentInst1 = Int32LSL(currentInst, Int32(8));  // 8 : set as high 8 bits
612    GateRef currentInst2 = Int32Add(currentInst1, ZExtInt8ToInt32(ReadInst8_2(pc)));
613    GateRef currentInst3 = Int32LSL(currentInst2, Int32(8));  // 8 : set as high 8 bits
614    GateRef currentInst4 = Int32Add(currentInst3, ZExtInt8ToInt32(ReadInst8_1(pc)));
615    GateRef currentInst5 = Int32LSL(currentInst4, Int32(8));  // 8 : set as high 8 bits
616    return Int32Add(currentInst5, ZExtInt8ToInt32(ReadInst8_0(pc)));
617}
618
619GateRef InterpreterStubBuilder::ReadInst32_1(GateRef pc)
620{
621    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
622        return Load(VariableType::INT32(), pc, IntPtr(2));  // 2 : skip 2 bytes of bytecode
623    }
624    GateRef currentInst = ZExtInt8ToInt32(ReadInst8_4(pc));
625    GateRef currentInst1 = Int32LSL(currentInst, Int32(8));  // 8 : set as high 8 bits
626    GateRef currentInst2 = Int32Add(currentInst1, ZExtInt8ToInt32(ReadInst8_3(pc)));
627    GateRef currentInst3 = Int32LSL(currentInst2, Int32(8));  // 8 : set as high 8 bits
628    GateRef currentInst4 = Int32Add(currentInst3, ZExtInt8ToInt32(ReadInst8_2(pc)));
629    GateRef currentInst5 = Int32LSL(currentInst4, Int32(8));  // 8 : set as high 8 bits
630    return Int32Add(currentInst5, ZExtInt8ToInt32(ReadInst8_1(pc)));
631}
632
633GateRef InterpreterStubBuilder::ReadInst32_2(GateRef pc)
634{
635    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
636        return Load(VariableType::INT32(), pc, IntPtr(3));  // 3 : skip 3 bytes of bytecode
637    }
638    GateRef currentInst = ZExtInt8ToInt32(ReadInst8_5(pc));
639    GateRef currentInst1 = Int32LSL(currentInst, Int32(8));  // 8 : set as high 8 bits
640    GateRef currentInst2 = Int32Add(currentInst1, ZExtInt8ToInt32(ReadInst8_4(pc)));
641    GateRef currentInst3 = Int32LSL(currentInst2, Int32(8));  // 8 : set as high 8 bits
642    GateRef currentInst4 = Int32Add(currentInst3, ZExtInt8ToInt32(ReadInst8_3(pc)));
643    GateRef currentInst5 = Int32LSL(currentInst4, Int32(8));  // 8 : set as high 8 bits
644    return Int32Add(currentInst5, ZExtInt8ToInt32(ReadInst8_2(pc)));
645}
646
647GateRef InterpreterStubBuilder::ReadInst64_0(GateRef pc)
648{
649    if (GetEnvironment()->IsAArch64() || GetEnvironment()->IsAmd64()) {
650        return Load(VariableType::INT64(), pc, IntPtr(1));  // 1 : skip 1 byte of bytecode
651    }
652    GateRef currentInst = ZExtInt8ToInt64(ReadInst8_7(pc));
653    GateRef currentInst1 = Int64LSL(currentInst, Int64(8));  // 8 : set as high 8 bits
654    GateRef currentInst2 = Int64Add(currentInst1, ZExtInt8ToInt64(ReadInst8_6(pc)));
655    GateRef currentInst3 = Int64LSL(currentInst2, Int64(8));  // 8 : set as high 8 bits
656    GateRef currentInst4 = Int64Add(currentInst3, ZExtInt8ToInt64(ReadInst8_5(pc)));
657    GateRef currentInst5 = Int64LSL(currentInst4, Int64(8));  // 8 : set as high 8 bits
658    GateRef currentInst6 = Int64Add(currentInst5, ZExtInt8ToInt64(ReadInst8_4(pc)));
659    GateRef currentInst7 = Int64LSL(currentInst6, Int64(8));  // 8 : set as high 8 bits
660    GateRef currentInst8 = Int64Add(currentInst7, ZExtInt8ToInt64(ReadInst8_3(pc)));
661    GateRef currentInst9 = Int64LSL(currentInst8, Int64(8));  // 8 : set as high 8 bits
662    GateRef currentInst10 = Int64Add(currentInst9, ZExtInt8ToInt64(ReadInst8_2(pc)));
663    GateRef currentInst11 = Int64LSL(currentInst10, Int64(8));  // 8 : set as high 8 bits
664    GateRef currentInst12 = Int64Add(currentInst11, ZExtInt8ToInt64(ReadInst8_1(pc)));
665    GateRef currentInst13 = Int64LSL(currentInst12, Int64(8));  // 8 : set as high 8 bits
666    return Int64Add(currentInst13, ZExtInt8ToInt64(ReadInst8_0(pc)));
667}
668
669template<typename... Args>
670void InterpreterStubBuilder::DispatchBase(GateRef target, GateRef glue, Args... args)
671{
672    GetEnvironment()->GetBuilder()->CallBCHandler(glue, target, {glue, args...});
673}
674
675void InterpreterStubBuilder::Dispatch(GateRef glue, GateRef sp, GateRef pc, GateRef constpool, GateRef profileTypeInfo,
676    GateRef acc, GateRef hotnessCounter, GateRef format)
677{
678    GateRef newPc = PtrAdd(pc, format);
679    GateRef opcode = Load(VariableType::INT8(), newPc);
680    GateRef target = PtrMul(ZExtInt32ToPtr(ZExtInt8ToInt32(opcode)), IntPtrSize());
681    DispatchBase(target, glue, sp, newPc, constpool, profileTypeInfo, acc, hotnessCounter);
682    Return();
683}
684
685void InterpreterStubBuilder::DispatchLast(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
686    GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter)
687{
688    GateRef target = PtrMul(IntPtr(BytecodeStubCSigns::ID_ExceptionHandler), IntPtrSize());
689    DispatchBase(target, glue, sp, pc, constpool, profileTypeInfo, acc, hotnessCounter);
690    Return();
691}
692
693void InterpreterStubBuilder::DispatchDebugger(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
694    GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter)
695{
696    GateRef opcode = Load(VariableType::INT8(), pc);
697    GateRef target = PtrMul(ZExtInt32ToPtr(ZExtInt8ToInt32(opcode)), IntPtrSize());
698    auto args = { glue, sp, pc, constpool, profileTypeInfo, acc, hotnessCounter };
699    GetEnvironment()->GetBuilder()->CallBCDebugger(glue, target, args);
700    Return();
701}
702
703void InterpreterStubBuilder::DispatchDebuggerLast(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
704    GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter)
705{
706    GateRef target = PtrMul(IntPtr(BytecodeStubCSigns::ID_ExceptionHandler), IntPtrSize());
707    auto args = { glue, sp, pc, constpool, profileTypeInfo, acc, hotnessCounter };
708    GetEnvironment()->GetBuilder()->CallBCDebugger(glue, target, args);
709    Return();
710}
711
712GateRef InterpreterStubBuilder::GetHotnessCounterFromMethod(GateRef method)
713{
714    GateRef x = Load(VariableType::INT16(), method, IntPtr(Method::LITERAL_INFO_OFFSET));
715    return GetEnvironment()->GetBuilder()->SExtInt1ToInt32(x);
716}
717
718void InterpreterStubBuilder::DispatchWithId(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
719    GateRef profileTypeInfo, GateRef acc,
720    GateRef hotnessCounter, GateRef index)
721{
722    GateRef target = PtrMul(index, IntPtrSize());
723    DispatchBase(target, glue, sp, pc, constpool, profileTypeInfo, acc, hotnessCounter);
724    Return();
725}
726
727#define DISPATCH_LAST(acc)                                                                  \
728    DispatchLast(glue, sp, pc, constpool, profileTypeInfo, acc, hotnessCounter)
729#define DISPATCH(acc)                                                                       \
730    Dispatch(glue, sp, pc, constpool, profileTypeInfo, acc, hotnessCounter, offset)
731void InterpreterStubBuilder::CheckException(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
732                                            GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter,
733                                            GateRef res, GateRef offset)
734{
735    auto env = GetEnvironment();
736    Label isException(env);
737    Label notException(env);
738    BRANCH(TaggedIsException(res), &isException, &notException);
739    Bind(&isException);
740    {
741        DISPATCH_LAST(acc);
742    }
743    Bind(&notException);
744    {
745        DISPATCH(acc);
746    }
747}
748
749void InterpreterStubBuilder::CheckPendingException(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
750                                                   GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter,
751                                                   GateRef res, GateRef offset)
752{
753    auto env = GetEnvironment();
754    Label isException(env);
755    Label notException(env);
756    BRANCH(HasPendingException(glue), &isException, &notException);
757    Bind(&isException);
758    {
759        DISPATCH_LAST(acc);
760    }
761    Bind(&notException);
762    {
763        DISPATCH(res);
764    }
765}
766
767void InterpreterStubBuilder::CheckExceptionWithVar(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
768                                                   GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter,
769                                                   GateRef res, GateRef offset)
770{
771    auto env = GetEnvironment();
772    Label isException(env);
773    Label notException(env);
774    BRANCH(TaggedIsException(res), &isException, &notException);
775    Bind(&isException);
776    {
777        DISPATCH_LAST(acc);
778    }
779    Bind(&notException);
780    {
781        DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
782        varAcc = res;
783        DISPATCH(*varAcc);
784    }
785}
786
787void InterpreterStubBuilder::CheckExceptionWithJump(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
788                                                    GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter,
789                                                    GateRef res, Label *jump)
790{
791    auto env = GetEnvironment();
792    Label isException(env);
793    Label notException(env);
794    BRANCH(TaggedIsException(res), &isException, &notException);
795    Bind(&isException);
796    {
797        DISPATCH_LAST(acc);
798    }
799    Bind(&notException);
800    {
801        Jump(jump);
802    }
803}
804
805GateRef InterpreterToolsStubBuilder::GetStringId(const StringIdInfo &info)
806{
807    if (info.GetStringIdType() == StringIdInfo::StringIdType::STRING_ID) {
808        return info.GetStringId();
809    }
810    GateRef stringId;
811    switch (info.GetOffset()) {
812        case StringIdInfo::Offset::BYTE_0: {
813            if (info.GetLength() == StringIdInfo::Length::BITS_16) {
814                stringId = ZExtInt16ToInt32(ReadInst16_0(info.GetPc()));
815            } else {
816                std::abort();
817            }
818            break;
819        }
820        case StringIdInfo::Offset::BYTE_1: {
821            if (info.GetLength() == StringIdInfo::Length::BITS_16) {
822                stringId = ZExtInt16ToInt32(ReadInst16_1(info.GetPc()));
823            } else if (info.GetLength() == StringIdInfo::Length::BITS_32) {
824                stringId = ReadInst32_1(info.GetPc());
825            } else {
826                std::abort();
827            }
828            break;
829        }
830        case StringIdInfo::Offset::BYTE_2: {
831            if (info.GetLength() == StringIdInfo::Length::BITS_16) {
832                stringId = ZExtInt16ToInt32(ReadInst16_2(info.GetPc()));
833            } else {
834                std::abort();
835            }
836            break;
837        }
838        default: {
839            std::abort();
840            break;
841        }
842    }
843    return stringId;
844}
845#undef DISPATCH_LAST
846#undef DISPATCH
847} //  namespace panda::ecmascript::kungfu
848#endif // ECMASCRIPT_COMPILER_INTERPRETER_STUB_INL_H
849