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_STUB_BUILDER_H
17 #define ECMASCRIPT_COMPILER_BASELINE_BASELINE_STUB_BUILDER_H
18 
19 #include "ecmascript/compiler/stub_builder.h"
20 #include "ecmascript/base/config.h"
21 #include "ecmascript/compiler/bc_call_signature.h"
22 #include "ecmascript/compiler/profiler_operation.h"
23 #include "ecmascript/compiler/rt_call_signature.h"
24 #include "ecmascript/compiler/circuit_builder_helper.h"
25 
26 namespace panda::ecmascript::kungfu {
27 
28 class BaselineStubBuilder : public StubBuilder {
29 public:
30     static_assert(false);
BaselineStubBuilder(CallSignature *callSignature, Environment *env)31     BaselineStubBuilder(CallSignature *callSignature, Environment *env)
32         : StubBuilder(callSignature, env) {}
33     ~BaselineStubBuilder() override = default;
34     NO_MOVE_SEMANTIC(BaselineStubBuilder);
35     NO_COPY_SEMANTIC(BaselineStubBuilder);
36     virtual void GenerateCircuit() override = 0;
37 
SetEnvToFrame(GateRef glue, GateRef frame, GateRef value)38     inline void SetEnvToFrame(GateRef glue, GateRef frame, GateRef value)
39     {
40         Store(VariableType::INT64(), glue, frame,
41             IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())), value);
42     }
43 
CheckExceptionWithVar(GateRef acc, GateRef res)44     void CheckExceptionWithVar(GateRef acc, GateRef res)
45     {
46         auto env = GetEnvironment();
47         Label isException(env);
48         Label notException(env);
49         Branch(TaggedIsException(res), &isException, &notException);
50         Bind(&isException);
51         {
52             Return();
53         }
54         Bind(&notException);
55         {
56             DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
57             varAcc = res;
58             Return();
59         }
60     }
61 
CheckException(GateRef acc, GateRef res)62     void CheckException(GateRef acc, GateRef res)
63     {
64         auto env = GetEnvironment();
65         Label isException(env);
66         Label notException(env);
67         Branch(TaggedIsException(res), &isException, &notException);
68         Bind(&isException);
69         {
70             (void) acc;
71             Return();
72         }
73         Bind(&notException);
74         {
75             Return();
76         }
77     }
78 
CheckExceptionWithJump(GateRef acc, GateRef res, Label *jump)79     void CheckExceptionWithJump(GateRef acc, GateRef res, Label *jump)
80     {
81         auto env = GetEnvironment();
82         Label isException(env);
83         Label notException(env);
84         Branch(TaggedIsException(res), &isException, &notException);
85         Bind(&isException);
86         {
87             Return(acc);
88         }
89         Bind(&notException);
90         {
91             Jump(jump);
92         }
93     }
94 
CheckPendingException(GateRef glue, GateRef res, GateRef offset)95     void CheckPendingException(GateRef glue, GateRef res, GateRef offset)
96     {
97         (void)offset;
98         auto env = GetEnvironment();
99         Label isException(env);
100         Label notException(env);
101         Branch(HasPendingException(glue), &isException, &notException);
102         Bind(&isException);
103         {
104             Return();
105         }
106         Bind(&notException);
107         {
108             (void)res;
109             Return();
110         }
111     }
112 
113     template<typename... Args>
DispatchBase(GateRef target, GateRef glue, Args... args)114     void DispatchBase(GateRef target, GateRef glue, Args... args)
115     {
116         GetEnvironment()->GetBuilder()->CallBCHandler(glue, target, {glue, args...});
117     }
118 
DispatchLast(GateRef glue, GateRef sp, GateRef pc, GateRef constpool, GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter)119     inline void DispatchLast(GateRef glue, GateRef sp, GateRef pc, GateRef constpool,
120                              GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter)
121     {
122         GateRef target = PtrMul(IntPtr(BytecodeStubCSigns::ID_ExceptionHandler), IntPtrSize());
123         DispatchBase(target, glue, sp, pc, constpool, profileTypeInfo, acc, hotnessCounter);
124         Return();
125     }
126 
Dispatch(GateRef glue, GateRef sp, GateRef pc, GateRef constpool, GateRef profileTypeInfo, GateRef acc, GateRef hotnessCounter, GateRef format)127     void Dispatch(GateRef glue, GateRef sp, GateRef pc, GateRef constpool, GateRef profileTypeInfo,
128                   GateRef acc, GateRef hotnessCounter, GateRef format)
129     {
130         GateRef newPc = PtrAdd(pc, format);
131         GateRef opcode = Load(VariableType::INT8(), newPc);
132         GateRef target = PtrMul(ZExtInt32ToPtr(ZExtInt8ToInt32(opcode)), IntPtrSize());
133         DispatchBase(target, glue, sp, newPc, constpool, profileTypeInfo, acc, hotnessCounter);
134         Return();
135     }
136 
GetFunctionFromFrame(GateRef frame)137     inline GateRef GetFunctionFromFrame(GateRef frame)
138     {
139         return Load(VariableType::JS_POINTER(), frame,
140             IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
141     }
142 
GetEnvFromFrame(GateRef frame)143     inline GateRef GetEnvFromFrame(GateRef frame)
144     {
145         return Load(VariableType::JS_POINTER(), frame,
146             IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())));
147     }
148 
GetAccFromFrame(GateRef frame)149     inline GateRef GetAccFromFrame(GateRef frame)
150     {
151         return Load(VariableType::JS_ANY(), frame,
152             IntPtr(AsmInterpretedFrame::GetAccOffset(GetEnvironment()->IsArch32Bit())));
153     }
154 
GetConstpoolFromMethod(GateRef method)155     inline GateRef GetConstpoolFromMethod(GateRef method)
156     {
157         return Load(VariableType::JS_POINTER(), method, IntPtr(Method::CONSTANT_POOL_OFFSET));
158     }
159 
160     GateRef GetProfileTypeInfoFromFunction(GateRef function);
161 
GetHotnessCounterFromMethod(GateRef method)162     inline GateRef GetHotnessCounterFromMethod(GateRef method)
163     {
164         GateRef x = Load(VariableType::INT16(), method, IntPtr(Method::LITERAL_INFO_OFFSET));
165         return GetEnvironment()->GetBuilder()->SExtInt1ToInt32(x);
166     }
167 
168     GateRef GetModuleFromFunction(GateRef function);
169 
170     GateRef GetHomeObjectFromFunction(GateRef function);
171 
GetModule(GateRef sp)172     inline GateRef GetModule(GateRef sp)
173     {
174         GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
175         return GetModuleFromFunction(currentFunc);
176     }
177 
GetCurrentFrame(GateRef glue)178     inline GateRef GetCurrentFrame(GateRef glue)
179     {
180         return GetLastLeaveFrame(glue);
181     }
182 
GetFrame(GateRef CurrentSp)183     inline GateRef GetFrame(GateRef CurrentSp)
184     {
185         return PtrSub(CurrentSp, IntPtr(AsmInterpretedFrame::GetSize(GetEnvironment()->IsArch32Bit())));
186     }
187 
GetPcFromFrame(GateRef frame)188     inline GateRef GetPcFromFrame(GateRef frame)
189     {
190         return Load(VariableType::NATIVE_POINTER(), frame,
191             IntPtr(AsmInterpretedFrame::GetPcOffset(GetEnvironment()->IsArch32Bit())));
192     }
193 
GetCallSizeFromFrame(GateRef frame)194     inline GateRef GetCallSizeFromFrame(GateRef frame)
195     {
196         return Load(VariableType::NATIVE_POINTER(), frame,
197             IntPtr(AsmInterpretedFrame::GetCallSizeOffset(GetEnvironment()->IsArch32Bit())));
198     }
199 
GetThisFromFrame(GateRef frame)200     inline GateRef GetThisFromFrame(GateRef frame)
201     {
202         return Load(VariableType::JS_POINTER(), frame,
203             IntPtr(AsmInterpretedFrame::GetThisOffset(GetEnvironment()->IsArch32Bit())));
204     }
205 
GetNewTarget(GateRef sp)206     GateRef GetNewTarget(GateRef sp)
207     {
208         GateRef function = Load(VariableType::JS_POINTER(), GetFrame(sp),
209             IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
210         GateRef method = GetMethodFromFunction(function);
211         GateRef callField = GetCallFieldFromMethod(method);
212         // ASSERT: callField has "extra" bit.
213         GateRef numVregs =
214             TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(MethodLiteral::NumVregsBits::START_BIT)),
215                                        Int64((1LLU << MethodLiteral::NumVregsBits::SIZE) - 1)));
216         GateRef haveFunc = ZExtInt1ToInt32(Int64NotEqual(Int64And(Int64LSR(callField,
217             Int64(MethodLiteral::HaveFuncBit::START_BIT)),
218             Int64((1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1)), Int64(0)));
219         GateRef idx = ZExtInt32ToPtr(Int32Add(numVregs, haveFunc));
220         return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), idx));
221     }
222 
GetStartIdxAndNumArgs(GateRef sp, GateRef restIdx)223     GateRef GetStartIdxAndNumArgs(GateRef sp, GateRef restIdx)
224     {
225         auto env = GetEnvironment();
226         Label subEntry(env);
227         env->SubCfgEntry(&subEntry);
228         DEFVARIABLE(numArgs, VariableType::INT32(), Int32(0));
229         GateRef state = PtrSub(sp, IntPtr(AsmInterpretedFrame::GetSize(env->IsArch32Bit())));
230         GateRef function = GetFunctionFromFrame(state);
231         GateRef method = GetMethodFromJSFunctionOrProxy(function);
232         GateRef callField = GetCallFieldFromMethod(method);
233         // ASSERT: callField has "extra" bit.
234         GateRef numVregs = TruncInt64ToInt32(Int64And(
235             Int64LSR(callField, Int64(MethodLiteral::NumVregsBits::START_BIT)),
236             Int64((1LLU << MethodLiteral::NumVregsBits::SIZE) - 1)));
237         GateRef haveFunc = Int64NotEqual(Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveFuncBit::START_BIT)),
238             Int64((1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1)), Int64(0));
239         GateRef haveNewTarget = Int64NotEqual(
240             Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveNewTargetBit::START_BIT)),
241             Int64((1LLU << MethodLiteral::HaveNewTargetBit::SIZE) - 1)), Int64(0));
242         GateRef haveThis = Int64NotEqual(Int64And(Int64LSR(callField, Int64(MethodLiteral::HaveThisBit::START_BIT)),
243             Int64((1LLU << MethodLiteral::HaveThisBit::SIZE) - 1)), Int64(0));
244         GateRef copyArgs = Int32Add(Int32Add(ZExtInt1ToInt32(haveFunc), ZExtInt1ToInt32(haveNewTarget)),
245                                     ZExtInt1ToInt32(haveThis));
246         numArgs = TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(MethodLiteral::NumArgsBits::START_BIT)),
247                                              Int64((1LLU << MethodLiteral::NumArgsBits::SIZE) - 1)));
248         GateRef fp = Load(VariableType::NATIVE_POINTER(), state,
249                           IntPtr(AsmInterpretedFrame::GetFpOffset(env->IsArch32Bit())));
250         Label actualEqualDeclared(env);
251         Label actualNotEqualDeclared(env);
252         Branch(Int32UnsignedGreaterThan(ChangeIntPtrToInt32(PtrSub(fp, sp)),
253                                         Int32Mul(Int32Add(Int32Add(numVregs, copyArgs), *numArgs),
254                                                  Int32(sizeof(JSTaggedType)))),
255                &actualNotEqualDeclared, &actualEqualDeclared);
256         Bind(&actualNotEqualDeclared);
257         {
258             numArgs = GetInt32OfTInt(Load(VariableType::JS_ANY(), fp,
259                                           IntPtr(-static_cast<int64_t>(sizeof(JSTaggedType)))));
260             Jump(&actualEqualDeclared);
261         }
262         Bind(&actualEqualDeclared);
263         GateRef startIdx = Int32Add(Int32Add(numVregs, copyArgs), restIdx);
264         Label numArgsGreater(env);
265         Label numArgsNotGreater(env);
266         Label exit(env);
267         Branch(Int32UnsignedGreaterThan(*numArgs, restIdx), &numArgsGreater, &numArgsNotGreater);
268         Bind(&numArgsGreater);
269         {
270             numArgs = Int32Sub(*numArgs, restIdx);
271             Jump(&exit);
272         }
273         Bind(&numArgsNotGreater);
274         {
275             numArgs = Int32(0);
276             Jump(&exit);
277         }
278         Bind(&exit);
279         // 32: high 32 bits = startIdx, low 32 bits = numArgs
280         GateRef ret = Int64Or(Int64LSL(ZExtInt32ToInt64(startIdx), Int64(32)), ZExtInt32ToInt64(*numArgs));
281         env->SubCfgExit();
282         return ret;
283     }
284 
SetVregValue(GateRef glue, GateRef sp, GateRef idx, GateRef val)285     inline void SetVregValue(GateRef glue, GateRef sp, GateRef idx, GateRef val)
286     {
287         Store(VariableType::INT64(), glue, sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx), val);
288     }
289 
GetVregValue(GateRef sp, GateRef idx)290     inline GateRef GetVregValue(GateRef sp, GateRef idx)
291     {
292         return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx));
293     }
294 
295     GateRef GetResumeModeFromGeneratorObject(GateRef obj);
296     GateRef GetResumeModeFromAsyncGeneratorObject(GateRef obj);
297     GateRef GetLastLeaveFrame(GateRef glue);
298 }; // class BaselineStubBuilder
299 }  // namespace panda::ecmascript::kungfu
300 #endif  // ECMASCRIPT_COMPILER_BASELINE_BASELINE_STUB_BUILDER_H
301