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, ¬Exception);
39 Bind(&isException);
40 {
41 DispatchLast(glue, sp, acc);
42 Return(acc);
43 }
44 Bind(¬Exception);
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, ¬Exception);
56 Bind(&isException);
57 {
58 GateRef frame = GetFrame(sp);
59 GateRef acc = GetAccFromFrame(frame);
60 DispatchLast(glue, sp, acc);
61 Return();
62 }
63 Bind(¬Exception);
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, ¬Exception);
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(¬Exception);
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, ¬Exception);
94 Bind(&isException);
95 {
96 DispatchLast(glue, sp, acc);
97 Return();
98 }
99 Bind(¬Exception);
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, ¬Exception);
112 Bind(&isException);
113 {
114 DispatchLast(glue, sp, acc);
115 Return(acc);
116 }
117 Bind(¬Exception);
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, ¬Exception);
129 Bind(&isException);
130 {
131 DispatchLast(glue, sp, acc);
132 Return(acc);
133 }
134 Bind(¬Exception);
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