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, ¬Exception); 50 Bind(&isException); 51 { 52 Return(); 53 } 54 Bind(¬Exception); 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, ¬Exception); 68 Bind(&isException); 69 { 70 (void) acc; 71 Return(); 72 } 73 Bind(¬Exception); 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, ¬Exception); 85 Bind(&isException); 86 { 87 Return(acc); 88 } 89 Bind(¬Exception); 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, ¬Exception); 102 Bind(&isException); 103 { 104 Return(); 105 } 106 Bind(¬Exception); 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