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 
24 namespace panda::ecmascript::kungfu {
25 using namespace panda::ecmascript;
26 
SetEnvToFrame(GateRef glue, GateRef frame, GateRef value)27 void BaselineStubBuilder::SetEnvToFrame(GateRef glue, GateRef frame, GateRef value)
28 {
29     Store(VariableType::INT64(), glue, frame,
30           IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())), value);
31 }
32 
CheckExceptionWithVar(GateRef glue, GateRef sp, GateRef res, GateRef acc)33 void 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 
CheckException(GateRef glue, GateRef sp, GateRef res)50 void 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 
CheckExceptionReturn(GateRef glue, GateRef sp, GateRef res)69 void 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 
CheckExceptionWithJump(GateRef glue, GateRef sp, GateRef res, GateRef acc, Label *jump)88 void 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 
CheckExceptionWithJumpAndReturn(GateRef glue, GateRef sp, GateRef res, GateRef acc, Label *jump)105 void 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 
CheckPendingException(GateRef glue, GateRef sp, GateRef res, GateRef acc)123 void 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 
DispatchLast(GateRef glue, GateRef sp, GateRef acc)140 void 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 
CallBaselineStub(GateRef glue, int index, const std::initializer_list<GateRef>& args)147 GateRef 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 
GetFunctionFromFrame(GateRef frame)155 GateRef BaselineStubBuilder::GetFunctionFromFrame(GateRef frame)
156 {
157     return Load(VariableType::JS_POINTER(), frame,
158                 IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
159 }
160 
GetEnvFromFrame(GateRef frame)161 GateRef BaselineStubBuilder::GetEnvFromFrame(GateRef frame)
162 {
163     return Load(VariableType::JS_POINTER(), frame,
164                 IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())));
165 }
166 
GetAccFromFrame(GateRef frame)167 GateRef BaselineStubBuilder::GetAccFromFrame(GateRef frame)
168 {
169     return Load(VariableType::JS_ANY(), frame,
170                 IntPtr(AsmInterpretedFrame::GetAccOffset(GetEnvironment()->IsArch32Bit())));
171 }
172 
GetConstpoolFromMethod(GateRef method)173 GateRef BaselineStubBuilder::GetConstpoolFromMethod(GateRef method)
174 {
175     return Load(VariableType::JS_POINTER(), method, IntPtr(Method::CONSTANT_POOL_OFFSET));
176 }
177 
GetProfileTypeInfoFromFunction(GateRef function)178 GateRef 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 
GetHotnessCounterFromMethod(GateRef method)184 GateRef 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 
GetModuleFromFunction(GateRef function)190 GateRef BaselineStubBuilder::GetModuleFromFunction(GateRef function)
191 {
192     return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::ECMA_MODULE_OFFSET));
193 }
194 
GetHomeObjectFromFunction(GateRef function)195 GateRef BaselineStubBuilder::GetHomeObjectFromFunction(GateRef function)
196 {
197     return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::HOME_OBJECT_OFFSET));
198 }
199 
GetModule(GateRef sp)200 GateRef BaselineStubBuilder::GetModule(GateRef sp)
201 {
202     GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
203     return GetModuleFromFunction(currentFunc);
204 }
205 
GetCurrentFrame(GateRef glue)206 GateRef BaselineStubBuilder::GetCurrentFrame(GateRef glue)
207 {
208     return GetLastLeaveFrame(glue);
209 }
210 
GetFrame(GateRef CurrentSp)211 GateRef BaselineStubBuilder::GetFrame(GateRef CurrentSp)
212 {
213     return PtrSub(CurrentSp, IntPtr(AsmInterpretedFrame::GetSize(GetEnvironment()->IsArch32Bit())));
214 }
215 
GetPcFromFrame(GateRef frame)216 GateRef BaselineStubBuilder::GetPcFromFrame(GateRef frame)
217 {
218     return Load(VariableType::NATIVE_POINTER(), frame,
219                 IntPtr(AsmInterpretedFrame::GetPcOffset(GetEnvironment()->IsArch32Bit())));
220 }
221 
GetCallSizeFromFrame(GateRef frame)222 GateRef BaselineStubBuilder::GetCallSizeFromFrame(GateRef frame)
223 {
224     return Load(VariableType::NATIVE_POINTER(), frame,
225                 IntPtr(AsmInterpretedFrame::GetCallSizeOffset(GetEnvironment()->IsArch32Bit())));
226 }
227 
GetThisFromFrame(GateRef frame)228 GateRef BaselineStubBuilder::GetThisFromFrame(GateRef frame)
229 {
230     return Load(VariableType::JS_POINTER(), frame,
231                 IntPtr(AsmInterpretedFrame::GetThisOffset(GetEnvironment()->IsArch32Bit())));
232 }
233 
GetNewTarget(GateRef sp)234 GateRef 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 
GetStartIdxAndNumArgs(GateRef sp, GateRef restIdx)251 GateRef 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 
SetVregValue(GateRef glue, GateRef sp, GateRef idx, GateRef val)312 void 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 
GetVregValue(GateRef sp, GateRef idx)317 GateRef BaselineStubBuilder::GetVregValue(GateRef sp, GateRef idx)
318 {
319     return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx));
320 }
321 
GetResumeModeFromGeneratorObject(GateRef obj)322 GateRef 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 
GetResumeModeFromAsyncGeneratorObject(GateRef obj)331 GateRef 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 
GetLastLeaveFrame(GateRef glue)340 GateRef 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