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 24namespace panda::ecmascript::kungfu { 25using namespace panda::ecmascript; 26 27void BaselineStubBuilder::SetEnvToFrame(GateRef glue, GateRef frame, GateRef value) 28{ 29 Store(VariableType::INT64(), glue, frame, 30 IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())), value); 31} 32 33void 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 50void 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 69void 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 88void 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 105void 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 123void 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 140void 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 147GateRef 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 155GateRef BaselineStubBuilder::GetFunctionFromFrame(GateRef frame) 156{ 157 return Load(VariableType::JS_POINTER(), frame, 158 IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit()))); 159} 160 161GateRef BaselineStubBuilder::GetEnvFromFrame(GateRef frame) 162{ 163 return Load(VariableType::JS_POINTER(), frame, 164 IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit()))); 165} 166 167GateRef BaselineStubBuilder::GetAccFromFrame(GateRef frame) 168{ 169 return Load(VariableType::JS_ANY(), frame, 170 IntPtr(AsmInterpretedFrame::GetAccOffset(GetEnvironment()->IsArch32Bit()))); 171} 172 173GateRef BaselineStubBuilder::GetConstpoolFromMethod(GateRef method) 174{ 175 return Load(VariableType::JS_POINTER(), method, IntPtr(Method::CONSTANT_POOL_OFFSET)); 176} 177 178GateRef 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 184GateRef 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 190GateRef BaselineStubBuilder::GetModuleFromFunction(GateRef function) 191{ 192 return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::ECMA_MODULE_OFFSET)); 193} 194 195GateRef BaselineStubBuilder::GetHomeObjectFromFunction(GateRef function) 196{ 197 return Load(VariableType::JS_POINTER(), function, IntPtr(JSFunction::HOME_OBJECT_OFFSET)); 198} 199 200GateRef BaselineStubBuilder::GetModule(GateRef sp) 201{ 202 GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp)); 203 return GetModuleFromFunction(currentFunc); 204} 205 206GateRef BaselineStubBuilder::GetCurrentFrame(GateRef glue) 207{ 208 return GetLastLeaveFrame(glue); 209} 210 211GateRef BaselineStubBuilder::GetFrame(GateRef CurrentSp) 212{ 213 return PtrSub(CurrentSp, IntPtr(AsmInterpretedFrame::GetSize(GetEnvironment()->IsArch32Bit()))); 214} 215 216GateRef BaselineStubBuilder::GetPcFromFrame(GateRef frame) 217{ 218 return Load(VariableType::NATIVE_POINTER(), frame, 219 IntPtr(AsmInterpretedFrame::GetPcOffset(GetEnvironment()->IsArch32Bit()))); 220} 221 222GateRef BaselineStubBuilder::GetCallSizeFromFrame(GateRef frame) 223{ 224 return Load(VariableType::NATIVE_POINTER(), frame, 225 IntPtr(AsmInterpretedFrame::GetCallSizeOffset(GetEnvironment()->IsArch32Bit()))); 226} 227 228GateRef BaselineStubBuilder::GetThisFromFrame(GateRef frame) 229{ 230 return Load(VariableType::JS_POINTER(), frame, 231 IntPtr(AsmInterpretedFrame::GetThisOffset(GetEnvironment()->IsArch32Bit()))); 232} 233 234GateRef 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 251GateRef 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 312void 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 317GateRef BaselineStubBuilder::GetVregValue(GateRef sp, GateRef idx) 318{ 319 return Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx)); 320} 321 322GateRef 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 331GateRef 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 340GateRef 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