1/*
2 * Copyright (c) 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#ifndef ECMASCRIPT_COMPILER_BASELINE_BASELINE_STUB_BUILDER_H
17#define ECMASCRIPT_COMPILER_BASELINE_BASELINE_STUB_BUILDER_H
18
19#include "ecmascript/compiler/stub_builder.h"
20#include "ecmascript/base/config.h"
21#include "ecmascript/compiler/bc_call_signature.h"
22#include "ecmascript/compiler/profiler_operation.h"
23#include "ecmascript/compiler/rt_call_signature.h"
24#include "ecmascript/compiler/circuit_builder_helper.h"
25
26namespace panda::ecmascript::kungfu {
27
28class BaselineStubBuilder : public StubBuilder {
29public:
30    static_assert(false);
31    BaselineStubBuilder(CallSignature *callSignature, Environment *env)
32        : StubBuilder(callSignature, env) {}
33    ~BaselineStubBuilder() override = default;
34    NO_MOVE_SEMANTIC(BaselineStubBuilder);
35    NO_COPY_SEMANTIC(BaselineStubBuilder);
36    virtual void GenerateCircuit() override = 0;
37
38    inline void SetEnvToFrame(GateRef glue, GateRef frame, GateRef value)
39    {
40        Store(VariableType::INT64(), glue, frame,
41            IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())), value);
42    }
43
44    void CheckExceptionWithVar(GateRef acc, GateRef res)
45    {
46        auto env = GetEnvironment();
47        Label isException(env);
48        Label notException(env);
49        Branch(TaggedIsException(res), &isException, &notException);
50        Bind(&isException);
51        {
52            Return();
53        }
54        Bind(&notException);
55        {
56            DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
57            varAcc = res;
58            Return();
59        }
60    }
61
62    void CheckException(GateRef acc, GateRef res)
63    {
64        auto env = GetEnvironment();
65        Label isException(env);
66        Label notException(env);
67        Branch(TaggedIsException(res), &isException, &notException);
68        Bind(&isException);
69        {
70            (void) acc;
71            Return();
72        }
73        Bind(&notException);
74        {
75            Return();
76        }
77    }
78
79    void CheckExceptionWithJump(GateRef acc, GateRef res, Label *jump)
80    {
81        auto env = GetEnvironment();
82        Label isException(env);
83        Label notException(env);
84        Branch(TaggedIsException(res), &isException, &notException);
85        Bind(&isException);
86        {
87            Return(acc);
88        }
89        Bind(&notException);
90        {
91            Jump(jump);
92        }
93    }
94
95    void CheckPendingException(GateRef glue, GateRef res, GateRef offset)
96    {
97        (void)offset;
98        auto env = GetEnvironment();
99        Label isException(env);
100        Label notException(env);
101        Branch(HasPendingException(glue), &isException, &notException);
102        Bind(&isException);
103        {
104            Return();
105        }
106        Bind(&notException);
107        {
108            (void)res;
109            Return();
110        }
111    }
112
113    template<typename... Args>
114    void DispatchBase(GateRef target, GateRef glue, Args... args)
115    {
116        GetEnvironment()->GetBuilder()->CallBCHandler(glue, target, {glue, args...});
117    }
118
119    inline void DispatchLast(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
120                             GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter)
121    {
122        GateRef target = PtrMul(IntPtr(BytecodeStubCSigns::ID_ExceptionHandler), IntPtrSize());
123        DispatchBase(target, glue, sp, pc, constpool, profileTypeInfo, acc, hotnessCounter);
124        Return();
125    }
126
127    void Dispatch(GateRef glue, GateRef sp, GateRef pc, GateRef constpool, GateRef profileTypeInfo,
128                  GateRef acc, GateRef hotnessCounter, GateRef format)
129    {
130        GateRef newPc = PtrAdd(pc, format);
131        GateRef opcode = Load(VariableType::INT8(), newPc);
132        GateRef target = PtrMul(ZExtInt32ToPtr(ZExtInt8ToInt32(opcode)), IntPtrSize());
133        DispatchBase(target, glue, sp, newPc, constpool, profileTypeInfo, acc, hotnessCounter);
134        Return();
135    }
136
137    inline GateRef GetFunctionFromFrame(GateRef frame)
138    {
139        return Load(VariableType::JS_POINTER(), frame,
140            IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
141    }
142
143    inline GateRef GetEnvFromFrame(GateRef frame)
144    {
145        return Load(VariableType::JS_POINTER(), frame,
146            IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())));
147    }
148
149    inline GateRef GetAccFromFrame(GateRef frame)
150    {
151        return Load(VariableType::JS_ANY(), frame,
152            IntPtr(AsmInterpretedFrame::GetAccOffset(GetEnvironment()->IsArch32Bit())));
153    }
154
155    inline GateRef GetConstpoolFromMethod(GateRef method)
156    {
157        return Load(VariableType::JS_POINTER(), method, IntPtr(Method::CONSTANT_POOL_OFFSET));
158    }
159
160    GateRef GetProfileTypeInfoFromFunction(GateRef function);
161
162    inline GateRef GetHotnessCounterFromMethod(GateRef method)
163    {
164        GateRef x = Load(VariableType::INT16(), method, IntPtr(Method::LITERAL_INFO_OFFSET));
165        return GetEnvironment()->GetBuilder()->SExtInt1ToInt32(x);
166    }
167
168    GateRef GetModuleFromFunction(GateRef function);
169
170    GateRef GetHomeObjectFromFunction(GateRef function);
171
172    inline GateRef GetModule(GateRef sp)
173    {
174        GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
175        return GetModuleFromFunction(currentFunc);
176    }
177
178    inline GateRef GetCurrentFrame(GateRef glue)
179    {
180        return GetLastLeaveFrame(glue);
181    }
182
183    inline GateRef GetFrame(GateRef CurrentSp)
184    {
185        return PtrSub(CurrentSp, IntPtr(AsmInterpretedFrame::GetSize(GetEnvironment()->IsArch32Bit())));
186    }
187
188    inline GateRef GetPcFromFrame(GateRef frame)
189    {
190        return Load(VariableType::NATIVE_POINTER(), frame,
191            IntPtr(AsmInterpretedFrame::GetPcOffset(GetEnvironment()->IsArch32Bit())));
192    }
193
194    inline GateRef GetCallSizeFromFrame(GateRef frame)
195    {
196        return Load(VariableType::NATIVE_POINTER(), frame,
197            IntPtr(AsmInterpretedFrame::GetCallSizeOffset(GetEnvironment()->IsArch32Bit())));
198    }
199
200    inline GateRef GetThisFromFrame(GateRef frame)
201    {
202        return Load(VariableType::JS_POINTER(), frame,
203            IntPtr(AsmInterpretedFrame::GetThisOffset(GetEnvironment()->IsArch32Bit())));
204    }
205
206    GateRef GetNewTarget(GateRef sp)
207    {
208        GateRef function = Load(VariableType::JS_POINTER(), GetFrame(sp),
209            IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
210        GateRef method = GetMethodFromFunction(function);
211        GateRef callField = GetCallFieldFromMethod(method);
212        // ASSERT: callField has "extra" bit.
213        GateRef numVregs =
214            TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(MethodLiteral::NumVregsBits::START_BIT)),
215                                       Int64((1LLU << MethodLiteral::NumVregsBits::SIZE) - 1)));
216        GateRef haveFunc = ZExtInt1ToInt32(Int64NotEqual(Int64And(Int64LSR(callField,
217            Int64(MethodLiteral::HaveFuncBit::START_BIT)),
218            Int64((1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1)), Int64(0)));
219        GateRef idx = ZExtInt32ToPtr(Int32Add(numVregs, haveFunc));
220        return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), idx));
221    }
222
223    GateRef GetStartIdxAndNumArgs(GateRef sp, GateRef restIdx)
224    {
225        auto env = GetEnvironment();
226        Label subEntry(env);
227        env->SubCfgEntry(&subEntry);
228        DEFVARIABLE(numArgs, VariableType::INT32(), Int32(0));
229        GateRef state = PtrSub(sp, IntPtr(AsmInterpretedFrame::GetSize(env->IsArch32Bit())));
230        GateRef function = GetFunctionFromFrame(state);
231        GateRef method = GetMethodFromJSFunctionOrProxy(function);
232        GateRef callField = GetCallFieldFromMethod(method);
233        // ASSERT: callField has "extra" bit.
234        GateRef numVregs = TruncInt64ToInt32(Int64And(
235            Int64LSR(callField, Int64(MethodLiteral::NumVregsBits::START_BIT)),
236            Int64((1LLU << MethodLiteral::NumVregsBits::SIZE) - 1)));
237        GateRef haveFunc = Int64NotEqual(Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveFuncBit::START_BIT)),
238            Int64((1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1)), Int64(0));
239        GateRef haveNewTarget = Int64NotEqual(
240            Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveNewTargetBit::START_BIT)),
241            Int64((1LLU << MethodLiteral::HaveNewTargetBit::SIZE) - 1)), Int64(0));
242        GateRef haveThis = Int64NotEqual(Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveThisBit::START_BIT)),
243            Int64((1LLU << MethodLiteral::HaveThisBit::SIZE) - 1)), Int64(0));
244        GateRef copyArgs = Int32Add(Int32Add(ZExtInt1ToInt32(haveFunc), ZExtInt1ToInt32(haveNewTarget)),
245                                    ZExtInt1ToInt32(haveThis));
246        numArgs = TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
247                                             Int64((1LLU << MethodLiteral::NumArgsBits::SIZE) - 1)));
248        GateRef fp = Load(VariableType::NATIVE_POINTER(), state,
249                          IntPtr(AsmInterpretedFrame::GetFpOffset(env->IsArch32Bit())));
250        Label actualEqualDeclared(env);
251        Label actualNotEqualDeclared(env);
252        Branch(Int32UnsignedGreaterThan(ChangeIntPtrToInt32(PtrSub(fp, sp)),
253                                        Int32Mul(Int32Add(Int32Add(numVregs, copyArgs), *numArgs),
254                                                 Int32(sizeof(JSTaggedType)))),
255               &actualNotEqualDeclared, &actualEqualDeclared);
256        Bind(&actualNotEqualDeclared);
257        {
258            numArgs = GetInt32OfTInt(Load(VariableType::JS_ANY(), fp,
259                                          IntPtr(-static_cast<int64_t>(sizeof(JSTaggedType)))));
260            Jump(&actualEqualDeclared);
261        }
262        Bind(&actualEqualDeclared);
263        GateRef startIdx = Int32Add(Int32Add(numVregs, copyArgs), restIdx);
264        Label numArgsGreater(env);
265        Label numArgsNotGreater(env);
266        Label exit(env);
267        Branch(Int32UnsignedGreaterThan(*numArgs, restIdx), &numArgsGreater, &numArgsNotGreater);
268        Bind(&numArgsGreater);
269        {
270            numArgs = Int32Sub(*numArgs, restIdx);
271            Jump(&exit);
272        }
273        Bind(&numArgsNotGreater);
274        {
275            numArgs = Int32(0);
276            Jump(&exit);
277        }
278        Bind(&exit);
279        // 32: high 32 bits = startIdx, low 32 bits = numArgs
280        GateRef ret = Int64Or(Int64LSL(ZExtInt32ToInt64(startIdx), Int64(32)), ZExtInt32ToInt64(*numArgs));
281        env->SubCfgExit();
282        return ret;
283    }
284
285    inline void SetVregValue(GateRef glue, GateRef sp, GateRef idx, GateRef val)
286    {
287        Store(VariableType::INT64(), glue, sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx), val);
288    }
289
290    inline GateRef GetVregValue(GateRef sp, GateRef idx)
291    {
292        return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx));
293    }
294
295    GateRef GetResumeModeFromGeneratorObject(GateRef obj);
296    GateRef GetResumeModeFromAsyncGeneratorObject(GateRef obj);
297    GateRef GetLastLeaveFrame(GateRef glue);
298}; // class BaselineStubBuilder
299}  // namespace panda::ecmascript::kungfu
300#endif  // ECMASCRIPT_COMPILER_BASELINE_BASELINE_STUB_BUILDER_H
301