• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notException);
40     Bind(&isException);
41     {
42         DispatchLast(glue, sp, acc);
43         Return(acc);
44     }
45     Bind(&notException);
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, &notException);
57     Bind(&isException);
58     {
59         GateRef frame = GetFrame(sp);
60         GateRef acc = GetAccFromFrame(frame);
61         DispatchLast(glue, sp, acc);
62         Return();
63     }
64     Bind(&notException);
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, &notException);
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(&notException);
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, &notException);
95     Bind(&isException);
96     {
97         DispatchLast(glue, sp, acc);
98         Return();
99     }
100     Bind(&notException);
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, &notException);
113     Bind(&isException);
114     {
115         DispatchLast(glue, sp, acc);
116         Return(acc);
117     }
118     Bind(&notException);
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, &notException);
130     Bind(&isException);
131     {
132         DispatchLast(glue, sp, acc);
133         Return(acc);
134     }
135     Bind(&notException);
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