1 /* 2 * Copyright (c) 2022 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_ASSEMBLER_MODULE_X64_H 17 #define ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H 18 19 #include "ecmascript/compiler/assembler/x64/assembler_x64.h" 20 #include "ecmascript/compiler/assembler/x64/extended_assembler_x64.h" 21 #include "ecmascript/frames.h" 22 23 namespace panda::ecmascript::x64 { 24 25 enum class FrameTransitionType : uint8_t { 26 BASELINE_TO_OTHER, 27 BASELINE_TO_BASELINE_CHECK, 28 OTHER_TO_BASELINE_CHECK, 29 OTHER_TO_OTHER 30 }; 31 32 class CommonCall { 33 public: 34 static constexpr int FRAME_SLOT_SIZE = 8; 35 static constexpr int DOUBLE_SLOT_SIZE = 16; 36 static constexpr int TRIPLE_SLOT_SIZE = 24; 37 static constexpr int QUADRUPLE_SLOT_SIZE = 32; 38 static constexpr int QUINTUPLE_SLOT_SIZE = 40; 39 static constexpr int SEXTUPLE_SLOT_SIZE = 48; 40 static void CopyArgumentWithArgV(ExtendedAssembler *assembler, Register argc, Register argV); 41 static void PushAsmInterpBridgeFrame(ExtendedAssembler *assembler); 42 static void PopAsmInterpBridgeFrame(ExtendedAssembler *assembler); 43 static void PushUndefinedWithArgc(ExtendedAssembler *assembler, Register argc); 44 static void GetArgvAtStack(ExtendedAssembler *assembler); 45 static void PushArgsWithArgvAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc, Register argv, 46 Register op1, Register op2, Label *stackOverflow); 47 static void StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register numArgs, Register op1, 48 Register op2, Label *stackOverflow); 49 }; 50 51 class OptimizedCall : public CommonCall { 52 public: 53 static void CallRuntime(ExtendedAssembler *assembler); 54 55 static void JSFunctionEntry(ExtendedAssembler *assembler); 56 57 static void OptimizedCallAndPushArgv(ExtendedAssembler *assembler); 58 59 static void JSProxyCallInternalWithArgV(ExtendedAssembler *assembler); 60 61 static void JSCall(ExtendedAssembler *assembler); 62 63 static void CallOptimized(ExtendedAssembler *assembler); 64 65 static void CallRuntimeWithArgv(ExtendedAssembler *assembler); 66 67 static void JSCallWithArgV(ExtendedAssembler *assembler); 68 69 static void JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler); 70 71 static void SuperCallWithArgV(ExtendedAssembler *assembler); 72 73 static void AOTCallToAsmInterBridge(ExtendedAssembler *assembler); 74 75 static void FastCallToAsmInterBridge(ExtendedAssembler *assembler); 76 77 static void DeoptHandlerAsm(ExtendedAssembler *assembler); 78 79 static void JSCallNew(ExtendedAssembler *assembler); 80 81 static void GenJSCall(ExtendedAssembler *assembler, bool isNew); 82 83 static void GenJSCallWithArgV(ExtendedAssembler *assembler, int id); 84 private: 85 static void DeoptEnterAsmInterp(ExtendedAssembler *assembler); 86 static void JSCallCheck(ExtendedAssembler *assembler, Register jsFuncReg, 87 Label *lNonCallable, Label *lNotJSFunction, Label *lJSFunctionCall); 88 static void ThrowNonCallableInternal(ExtendedAssembler *assembler, Register glueReg); 89 static void JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register jsFuncReg, Label *jsCall); 90 static void OptimizedCallAsmInterpreter(ExtendedAssembler *assembler); 91 static void PushArgsWithArgV(ExtendedAssembler *assembler, Register jsfunc, 92 Register actualNumArgs, Register argV, Label *pushCallThis); 93 static void PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc, 94 Register thisObj, Register newTarget); 95 static void PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs); 96 static void PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp); 97 static void PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue); 98 static void PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp); 99 static void PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler); 100 static void PushAsmBridgeFrame(ExtendedAssembler *assembler); 101 static void CallBuiltinTrampoline(ExtendedAssembler *assembler, Register temp); 102 static void PopAsmBridgeFrame(ExtendedAssembler *assembler); 103 static void CallBuiltinConstructorStub(ExtendedAssembler *assembler, Register builtinStub, Register argv, 104 Register glue, Register temp); 105 static void RemoveArgv(ExtendedAssembler *assembler, Register temp); 106 107 friend class OptimizedFastCall; 108 }; 109 110 class OptimizedFastCall : public CommonCall { 111 public: 112 static void OptimizedFastCallEntry(ExtendedAssembler *assembler); 113 114 static void OptimizedFastCallAndPushArgv(ExtendedAssembler *assembler); 115 116 static void JSFastCallWithArgV(ExtendedAssembler *assembler); 117 118 static void JSFastCallWithArgVAndPushArgv(ExtendedAssembler *assembler); 119 }; 120 121 class AsmInterpreterCall : public CommonCall { 122 public: 123 static void GeneratorReEnterAsmInterp(ExtendedAssembler *assembler); 124 125 static void GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *assembler); 126 127 static void AsmInterpEntryDispatch(ExtendedAssembler *assembler); 128 129 static void AsmInterpreterEntry(ExtendedAssembler *assembler); 130 131 static void PushCallThisRangeAndDispatch(ExtendedAssembler *assembler); 132 133 static void PushCallRangeAndDispatch(ExtendedAssembler *assembler); 134 135 static void PushCallArgs3AndDispatch(ExtendedAssembler *assembler); 136 137 static void PushCallArgs2AndDispatch(ExtendedAssembler *assembler); 138 139 static void PushCallArg1AndDispatch(ExtendedAssembler *assembler); 140 141 static void PushCallArg0AndDispatch(ExtendedAssembler *assembler); 142 143 static void PushCallThisArg0AndDispatch(ExtendedAssembler *assembler); 144 145 static void PushCallThisArg1AndDispatch(ExtendedAssembler *assembler); 146 147 static void PushCallThisArgs2AndDispatch(ExtendedAssembler *assembler); 148 149 static void PushCallThisArgs3AndDispatch(ExtendedAssembler *assembler); 150 151 static void PushCallNewAndDispatch(ExtendedAssembler *assembler); 152 153 static void PushSuperCallAndDispatch(ExtendedAssembler *assembler); 154 155 static void PushCallNewAndDispatchNative(ExtendedAssembler *assembler); 156 157 static void PushNewTargetAndDispatchNative(ExtendedAssembler *assembler); 158 159 static void PushCallRangeAndDispatchNative(ExtendedAssembler *assembler); 160 161 static void PushCallArgsAndDispatchNative(ExtendedAssembler *assembler); 162 163 static void ResumeRspAndDispatch(ExtendedAssembler *assembler); 164 165 static void ResumeRspAndReturn([[maybe_unused]] ExtendedAssembler *assembler); 166 167 static void ResumeRspAndReturnBaseline([[maybe_unused]] ExtendedAssembler *assembler); 168 169 static void CallGetter(ExtendedAssembler *assembler); 170 171 static void CallSetter(ExtendedAssembler *assembler); 172 173 static void CallContainersArgs2(ExtendedAssembler *assembler); 174 175 static void CallContainersArgs3(ExtendedAssembler *assembler); 176 177 static void CallReturnWithArgv(ExtendedAssembler *assembler); 178 179 static void ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler); 180 181 static void ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler); 182 183 static void ResumeRspAndRollback(ExtendedAssembler *assembler); 184 185 static void ASMFastWriteBarrier(ExtendedAssembler *assembler); 186 187 static void ASMWriteBarrierWithEden(ExtendedAssembler *assembler); 188 private: 189 static void PushFrameState(ExtendedAssembler *assembler, Register prevSpRegister, Register fpRegister, 190 Register callTargetRegister, Register thisRegister, Register methodRegister, Register pcRegister, 191 Register operatorRegister); 192 static void PushGeneratorFrameState(ExtendedAssembler *assembler, Register prevSpRegister, 193 Register fpRegister, Register callTargetRegister, Register thisRegister, Register methodRegister, 194 Register contextRegister, Register pcRegister, Register operatorRegister); 195 static void PushAsmInterpEntryFrame(ExtendedAssembler *assembler); 196 static void PopAsmInterpEntryFrame(ExtendedAssembler *assembler); 197 static void GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister, 198 Register declaredNumArgsRegister); 199 static void GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister, 200 Register numVregsRegister); 201 static void PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc, 202 Register op1, Register op2, Label *stackOverflow); 203 static void ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp, 204 Register op); 205 static void HasPendingException(ExtendedAssembler *assembler, Register threadRegister); 206 static void PushCallThis(ExtendedAssembler *assembler, JSCallMode mode, 207 Label *stackOverflow, FrameTransitionType type); 208 static Register GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 209 static Register GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 210 static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow, FrameTransitionType type); 211 static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister, 212 Register callTargetRegister, Register methodRegister, Register accRegister = rInvalid); 213 static void CallNativeEntry(ExtendedAssembler *assemblSer); 214 static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget = false); 215 static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode); 216 static bool PushBuiltinFrame(ExtendedAssembler *assembler, Register glue, FrameType type); 217 static void JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode, FrameTransitionType type); 218 static void JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow); 219 static void JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode, 220 Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow); 221 static void PreserveMostCall(ExtendedAssembler* assembler); 222 friend class OptimizedCall; 223 friend class BaselineCall; 224 }; 225 226 class BaselineCall : public CommonCall { 227 public: 228 /* other call baseline: need to check whether baseline code exists */ 229 static void CallArg0AndCheckToBaseline(ExtendedAssembler *assembler); 230 static void CallArg1AndCheckToBaseline(ExtendedAssembler *assembler); 231 static void CallArgs2AndCheckToBaseline(ExtendedAssembler *assembler); 232 static void CallArgs3AndCheckToBaseline(ExtendedAssembler *assembler); 233 static void CallThisArg0AndCheckToBaseline(ExtendedAssembler *assembler); 234 static void CallThisArg1AndCheckToBaseline(ExtendedAssembler *assembler); 235 static void CallThisArgs2AndCheckToBaseline(ExtendedAssembler *assembler); 236 static void CallThisArgs3AndCheckToBaseline(ExtendedAssembler *assembler); 237 static void CallRangeAndCheckToBaseline(ExtendedAssembler *assembler); 238 static void CallNewAndCheckToBaseline(ExtendedAssembler *assembler); 239 static void SuperCallAndCheckToBaseline(ExtendedAssembler *assembler); 240 static void CallThisRangeAndCheckToBaseline(ExtendedAssembler *assembler); 241 /* baseline call other: need to save fp and lr */ 242 static void CallArg0AndDispatchFromBaseline(ExtendedAssembler *assembler); 243 static void CallArg1AndDispatchFromBaseline(ExtendedAssembler *assembler); 244 static void CallArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler); 245 static void CallArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler); 246 static void CallThisArg0AndDispatchFromBaseline(ExtendedAssembler *assembler); 247 static void CallThisArg1AndDispatchFromBaseline(ExtendedAssembler *assembler); 248 static void CallThisArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler); 249 static void CallThisArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler); 250 static void CallRangeAndDispatchFromBaseline(ExtendedAssembler *assembler); 251 static void CallNewAndDispatchFromBaseline(ExtendedAssembler *assembler); 252 static void SuperCallAndDispatchFromBaseline(ExtendedAssembler *assembler); 253 static void CallThisRangeAndDispatchFromBaseline(ExtendedAssembler *assembler); 254 /* baseline call baseline: need to check whether baseline code exists and save fp and lr */ 255 static void CallArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 256 static void CallArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 257 static void CallArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 258 static void CallArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 259 static void CallThisArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 260 static void CallThisArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 261 static void CallThisArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 262 static void CallThisArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 263 static void CallRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 264 static void CallNewAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 265 static void SuperCallAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 266 static void CallThisRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 267 /* get baselineBuiltinFp when baselineBuiltin call the others */ 268 static void GetBaselineBuiltinFp(ExtendedAssembler *assembler); 269 }; 270 271 class JsFunctionArgsConfigFrameScope { 272 public: 273 static constexpr int FRAME_SLOT_SIZE = 8; JsFunctionArgsConfigFrameScope(ExtendedAssembler * assembler)274 explicit JsFunctionArgsConfigFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 275 { 276 assembler_->Pushq(rbp); 277 assembler_->Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); 278 // 2: skip jsFunc and frameType 279 assembler_->Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp); 280 // callee save 281 assembler_->Pushq(r12); 282 assembler_->Pushq(r13); 283 assembler_->Pushq(r14); 284 assembler_->Pushq(rbx); 285 assembler_->Pushq(rax); 286 } ~JsFunctionArgsConfigFrameScope()287 ~JsFunctionArgsConfigFrameScope() 288 { 289 assembler_->Movq(rbp, rsp); 290 assembler_->Addq(-5 * FRAME_SLOT_SIZE, rsp); // -5: get r12 r13 r14 rbx 291 assembler_->Popq(rbx); 292 assembler_->Popq(r14); 293 assembler_->Popq(r13); 294 assembler_->Popq(r12); 295 assembler_->Addq(FRAME_SLOT_SIZE, rsp); // skip frame type 296 assembler_->Pop(rbp); 297 assembler_->Ret(); 298 } 299 NO_COPY_SEMANTIC(JsFunctionArgsConfigFrameScope); 300 NO_MOVE_SEMANTIC(JsFunctionArgsConfigFrameScope); 301 private: 302 ExtendedAssembler *assembler_; 303 }; 304 305 class OptimizedUnfoldArgVFrameFrameScope { 306 public: 307 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler * assembler)308 explicit OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 309 { 310 assembler_->Pushq(rbp); 311 // construct frame 312 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 313 assembler_->Pushq(assembler_->AvailableRegister2()); 314 // 2: skip callSiteSp and frameType 315 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 316 assembler_->Pushq(rbx); 317 assembler_->Pushq(r12); // callee save 318 } ~OptimizedUnfoldArgVFrameFrameScope()319 ~OptimizedUnfoldArgVFrameFrameScope() 320 { 321 assembler_->Movq(rbp, rsp); 322 assembler_->Addq(-4 * FRAME_SLOT_SIZE, rsp); // -4: get r12 rbx 323 assembler_->Popq(r12); 324 assembler_->Popq(rbx); 325 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 326 assembler_->Popq(rbp); 327 assembler_->Ret(); 328 } 329 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 330 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 331 private: 332 ExtendedAssembler *assembler_; 333 }; 334 335 class OptimizedUnfoldArgVFrameFrame1Scope { 336 public: 337 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler * assembler)338 explicit OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler *assembler) : assembler_(assembler) 339 { 340 assembler_->Pushq(rbp); 341 // construct frame 342 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 343 assembler_->Pushq(assembler_->AvailableRegister2()); 344 // 2: skip callSiteSp and frameType 345 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 346 assembler_->Pushq(rbx); 347 assembler_->Pushq(r12); // callee save 348 assembler_->Pushq(r13); 349 assembler_->Pushq(r14); // callee save 350 } ~OptimizedUnfoldArgVFrameFrame1Scope()351 ~OptimizedUnfoldArgVFrameFrame1Scope() 352 { 353 assembler_->Movq(rbp, rsp); 354 assembler_->Addq(-6 * FRAME_SLOT_SIZE, rsp); // -6: get r12 r13 r14 rbx 355 assembler_->Popq(r14); 356 assembler_->Popq(r13); 357 assembler_->Popq(r12); 358 assembler_->Popq(rbx); 359 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 360 assembler_->Popq(rbp); 361 assembler_->Ret(); 362 } 363 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 364 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 365 private: 366 ExtendedAssembler *assembler_; 367 }; 368 } // namespace panda::ecmascript::x64 369 #endif // ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H 370