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_STUBS_INL_H
17#define ECMASCRIPT_COMPILER_BASELINE_BASELINE_STUBS_INL_H
18
19#include "ecmascript/compiler/baseline/baseline_stubs.h"
20#include "ecmascript/js_function.h"
21#include "ecmascript/js_generator_object.h"
22#include "ecmascript/js_async_generator_object.h"
23
24namespace panda::ecmascript::kungfu {
25using namespace panda::ecmascript;
26
27void BaselineStubBuilder::SetEnvToFrame(GateRef glue, GateRef frame, GateRef value)
28{
29    Store(VariableType::INT64(), glue, frame,
30          IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())), value);
31}
32
33void BaselineStubBuilder::CheckExceptionWithVar(GateRef glue, GateRef sp, GateRef res, GateRef acc)
34{
35    auto env = GetEnvironment();
36    Label isException(env);
37    Label notException(env);
38    Branch(TaggedIsException(res), &isException, &notException);
39    Bind(&isException);
40    {
41        DispatchLast(glue, sp, acc);
42        Return(acc);
43    }
44    Bind(&notException);
45    {
46        Return(res);
47    }
48}
49
50void BaselineStubBuilder::CheckException(GateRef glue, GateRef sp, GateRef res)
51{
52    auto env = GetEnvironment();
53    Label isException(env);
54    Label notException(env);
55    Branch(TaggedIsException(res), &isException, &notException);
56    Bind(&isException);
57    {
58        GateRef frame = GetFrame(sp);
59        GateRef acc = GetAccFromFrame(frame);
60        DispatchLast(glue, sp, acc);
61        Return();
62    }
63    Bind(&notException);
64    {
65        Return();
66    }
67}
68
69void BaselineStubBuilder::CheckExceptionReturn(GateRef glue, GateRef sp, GateRef res)
70{
71    auto env = GetEnvironment();
72    Label isException(env);
73    Label notException(env);
74    Branch(TaggedIsException(res), &isException, &notException);
75    Bind(&isException);
76    {
77        GateRef frame = GetFrame(sp);
78        GateRef acc = GetAccFromFrame(frame);
79        DispatchLast(glue, sp, acc);
80        Return(acc);
81    }
82    Bind(&notException);
83    {
84        Return(res);
85    }
86}
87
88void BaselineStubBuilder::CheckExceptionWithJump(GateRef glue, GateRef sp, GateRef res, GateRef acc, Label *jump)
89{
90    auto env = GetEnvironment();
91    Label isException(env);
92    Label notException(env);
93    Branch(TaggedIsException(res), &isException, &notException);
94    Bind(&isException);
95    {
96        DispatchLast(glue, sp, acc);
97        Return();
98    }
99    Bind(&notException);
100    {
101        Jump(jump);
102    }
103}
104
105void BaselineStubBuilder::CheckExceptionWithJumpAndReturn(GateRef glue, GateRef sp, GateRef res, GateRef acc,
106                                                          Label *jump)
107{
108    auto env = GetEnvironment();
109    Label isException(env);
110    Label notException(env);
111    Branch(TaggedIsException(res), &isException, &notException);
112    Bind(&isException);
113    {
114        DispatchLast(glue, sp, acc);
115        Return(acc);
116    }
117    Bind(&notException);
118    {
119        Jump(jump);
120    }
121}
122
123void BaselineStubBuilder::CheckPendingException(GateRef glue, GateRef sp, GateRef res, GateRef acc)
124{
125    auto env = GetEnvironment();
126    Label isException(env);
127    Label notException(env);
128    Branch(HasPendingException(glue), &isException, &notException);
129    Bind(&isException);
130    {
131        DispatchLast(glue, sp, acc);
132        Return(acc);
133    }
134    Bind(&notException);
135    {
136        Return(res);
137    }
138}
139
140void BaselineStubBuilder::DispatchLast(GateRef glue, GateRef sp, GateRef acc)
141{
142    // Get baseline exceptionHandler index
143    GateRef baselineEHIndex = BaselineStubCSigns::BaselineExceptionHandler;
144    CallBaselineStub(glue, baselineEHIndex, { glue, sp, acc });
145}
146
147GateRef BaselineStubBuilder::CallBaselineStub(GateRef glue, int index, const std::initializer_list<GateRef>& args)
148{
149    auto env = GetEnvironment();
150    const std::string name = BaselineStubCSigns::GetName(index);
151    GateRef result = env->GetBuilder()->CallStub(glue, Circuit::NullGate(), index, args, name.c_str());
152    return result;
153}
154
155GateRef BaselineStubBuilder::GetFunctionFromFrame(GateRef frame)
156{
157    return Load(VariableType::JS_POINTER(), frame,
158                IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
159}
160
161GateRef BaselineStubBuilder::GetEnvFromFrame(GateRef frame)
162{
163    return Load(VariableType::JS_POINTER(), frame,
164                IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())));
165}
166
167GateRef BaselineStubBuilder::GetAccFromFrame(GateRef frame)
168{
169    return Load(VariableType::JS_ANY(), frame,
170                IntPtr(AsmInterpretedFrame::GetAccOffset(GetEnvironment()->IsArch32Bit())));
171}
172
173GateRef BaselineStubBuilder::GetConstpoolFromMethod(GateRef method)
174{
175    return Load(VariableType::JS_POINTER(), method, IntPtr(Method::CONSTANT_POOL_OFFSET));
176}
177
178GateRef BaselineStubBuilder::GetProfileTypeInfoFromFunction(GateRef function)
179{
180    GateRef raw = Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
181    return Load(VariableType::JS_POINTER(), raw, IntPtr(ProfileTypeInfoCell::VALUE_OFFSET));
182}
183
184GateRef BaselineStubBuilder::GetHotnessCounterFromMethod(GateRef method)
185{
186    GateRef x = Load(VariableType::INT16(), method, IntPtr(Method::LITERAL_INFO_OFFSET));
187    return GetEnvironment()->GetBuilder()->SExtInt1ToInt32(x);
188}
189
190GateRef BaselineStubBuilder::GetModuleFromFunction(GateRef function)
191{
192    return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::ECMA_MODULE_OFFSET));
193}
194
195GateRef BaselineStubBuilder::GetHomeObjectFromFunction(GateRef function)
196{
197    return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::HOME_OBJECT_OFFSET));
198}
199
200GateRef BaselineStubBuilder::GetModule(GateRef sp)
201{
202    GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
203    return GetModuleFromFunction(currentFunc);
204}
205
206GateRef BaselineStubBuilder::GetCurrentFrame(GateRef glue)
207{
208    return GetLastLeaveFrame(glue);
209}
210
211GateRef BaselineStubBuilder::GetFrame(GateRef CurrentSp)
212{
213    return PtrSub(CurrentSp, IntPtr(AsmInterpretedFrame::GetSize(GetEnvironment()->IsArch32Bit())));
214}
215
216GateRef BaselineStubBuilder::GetPcFromFrame(GateRef frame)
217{
218    return Load(VariableType::NATIVE_POINTER(), frame,
219                IntPtr(AsmInterpretedFrame::GetPcOffset(GetEnvironment()->IsArch32Bit())));
220}
221
222GateRef BaselineStubBuilder::GetCallSizeFromFrame(GateRef frame)
223{
224    return Load(VariableType::NATIVE_POINTER(), frame,
225                IntPtr(AsmInterpretedFrame::GetCallSizeOffset(GetEnvironment()->IsArch32Bit())));
226}
227
228GateRef BaselineStubBuilder::GetThisFromFrame(GateRef frame)
229{
230    return Load(VariableType::JS_POINTER(), frame,
231                IntPtr(AsmInterpretedFrame::GetThisOffset(GetEnvironment()->IsArch32Bit())));
232}
233
234GateRef BaselineStubBuilder::GetNewTarget(GateRef sp)
235{
236    GateRef function = Load(VariableType::JS_POINTER(), GetFrame(sp),
237                            IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
238    GateRef method = GetMethodFromFunction(function);
239    GateRef callField = GetCallFieldFromMethod(method);
240    // ASSERT: callField has "extra" bit.
241    GateRef numVregs =
242            TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(MethodLiteral::NumVregsBits::START_BIT)),
243                                       Int64((1LLU << MethodLiteral::NumVregsBits::SIZE) - 1)));
244    GateRef haveFunc =
245            ZExtInt1ToInt32(Int64NotEqual(Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveFuncBit::START_BIT)),
246                Int64((1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1)), Int64(0)));
247    GateRef idx = ZExtInt32ToPtr(Int32Add(numVregs, haveFunc));
248    return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), idx));
249}
250
251GateRef BaselineStubBuilder::GetStartIdxAndNumArgs(GateRef sp, GateRef restIdx)
252{
253    auto env = GetEnvironment();
254    Label subEntry(env);
255    env->SubCfgEntry(&subEntry);
256    DEFVARIABLE(numArgs, VariableType::INT32(), Int32(0));
257    GateRef state = PtrSub(sp, IntPtr(AsmInterpretedFrame::GetSize(env->IsArch32Bit())));
258    GateRef function = GetFunctionFromFrame(state);
259    GateRef method = GetMethodFromJSFunctionOrProxy(function);
260    GateRef callField = GetCallFieldFromMethod(method);
261    // ASSERT: callField has "extra" bit.
262    GateRef numVregs = TruncInt64ToInt32(Int64And(
263        Int64LSR(callField, Int64(MethodLiteral::NumVregsBits::START_BIT)),
264        Int64((1LLU << MethodLiteral::NumVregsBits::SIZE) - 1)));
265    GateRef haveFunc = Int64NotEqual(Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveFuncBit::START_BIT)),
266        Int64((1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1)), Int64(0));
267    GateRef haveNewTarget = Int64NotEqual(
268        Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveNewTargetBit::START_BIT)),
269        Int64((1LLU << MethodLiteral::HaveNewTargetBit::SIZE) - 1)), Int64(0));
270    GateRef haveThis = Int64NotEqual(Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveThisBit::START_BIT)),
271        Int64((1LLU << MethodLiteral::HaveThisBit::SIZE) - 1)), Int64(0));
272    GateRef copyArgs = Int32Add(Int32Add(ZExtInt1ToInt32(haveFunc), ZExtInt1ToInt32(haveNewTarget)),
273                                ZExtInt1ToInt32(haveThis));
274    numArgs = TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
275                                         Int64((1LLU << MethodLiteral::NumArgsBits::SIZE) - 1)));
276    GateRef fp = Load(VariableType::NATIVE_POINTER(), state,
277                      IntPtr(AsmInterpretedFrame::GetFpOffset(env->IsArch32Bit())));
278    Label actualEqualDeclared(env);
279    Label actualNotEqualDeclared(env);
280    Branch(Int32UnsignedGreaterThan(ChangeIntPtrToInt32(PtrSub(fp, sp)),
281                                    Int32Mul(Int32Add(Int32Add(numVregs, copyArgs), *numArgs),
282                                             Int32(sizeof(JSTaggedType)))),
283           &actualNotEqualDeclared, &actualEqualDeclared);
284    Bind(&actualNotEqualDeclared);
285    {
286        numArgs = GetInt32OfTInt(Load(VariableType::JS_ANY(), fp, IntPtr(static_cast<int64_t>(-sizeof(JSTaggedType)))));
287        Jump(&actualEqualDeclared);
288    }
289    Bind(&actualEqualDeclared);
290    GateRef startIdx = Int32Add(Int32Add(numVregs, copyArgs), restIdx);
291    Label numArgsGreater(env);
292    Label numArgsNotGreater(env);
293    Label exit(env);
294    Branch(Int32UnsignedGreaterThan(*numArgs, restIdx), &numArgsGreater, &numArgsNotGreater);
295    Bind(&numArgsGreater);
296    {
297        numArgs = Int32Sub(*numArgs, restIdx);
298        Jump(&exit);
299    }
300    Bind(&numArgsNotGreater);
301    {
302        numArgs = Int32(0);
303        Jump(&exit);
304    }
305    Bind(&exit);
306    // 32: high 32 bits = startIdx, low 32 bits = numArgs
307    GateRef ret = Int64Or(Int64LSL(ZExtInt32ToInt64(startIdx), Int64(32)), ZExtInt32ToInt64(*numArgs));
308    env->SubCfgExit();
309    return ret;
310}
311
312void BaselineStubBuilder::SetVregValue(GateRef glue, GateRef sp, GateRef idx, GateRef val)
313{
314    Store(VariableType::INT64(), glue, sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx), val);
315}
316
317GateRef BaselineStubBuilder::GetVregValue(GateRef sp, GateRef idx)
318{
319    return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx));
320}
321
322GateRef BaselineStubBuilder::GetResumeModeFromGeneratorObject(GateRef obj)
323{
324    GateRef bitfieldOffset = IntPtr(JSGeneratorObject::BIT_FIELD_OFFSET);
325    GateRef bitfield = Load(VariableType::INT32(), obj, bitfieldOffset);
326    return Int32And(
327        Int32LSR(bitfield, Int32(JSGeneratorObject::ResumeModeBits::START_BIT)),
328        Int32((1LU << JSGeneratorObject::ResumeModeBits::SIZE) - 1));
329}
330
331GateRef BaselineStubBuilder::GetResumeModeFromAsyncGeneratorObject(GateRef obj)
332{
333    GateRef bitfieldOffset = IntPtr(JSAsyncGeneratorObject::BIT_FIELD_OFFSET);
334    GateRef bitfield = Load(VariableType::INT32(), obj, bitfieldOffset);
335    return Int32And(
336        Int32LSR(bitfield, Int32(JSAsyncGeneratorObject::ResumeModeBits::START_BIT)),
337        Int32((1LU << JSAsyncGeneratorObject::ResumeModeBits::SIZE) - 1));
338}
339
340GateRef BaselineStubBuilder::GetLastLeaveFrame(GateRef glue)
341{
342    bool isArch32 = GetEnvironment()->Is32Bit();
343    GateRef spOffset = IntPtr(JSThread::GlueData::GetLeaveFrameOffset(isArch32));
344    return Load(VariableType::NATIVE_POINTER(), glue, spOffset);
345}
346}
347
348#endif // ECMASCRIPT_COMPILER_BASELINE_BASELINE_STUBS_INL_H
349