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