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 static void PushAsmBridgeFrame(ExtendedAssembler *assembler); 50 static void PopAsmBridgeFrame(ExtendedAssembler *assembler); 51 }; 52 53 class OptimizedCall : public CommonCall { 54 public: 55 static void CallRuntime(ExtendedAssembler *assembler); 56 57 static void JSFunctionEntry(ExtendedAssembler *assembler); 58 59 static void OptimizedCallAndPushArgv(ExtendedAssembler *assembler); 60 61 static void JSProxyCallInternalWithArgV(ExtendedAssembler *assembler); 62 63 static void JSCall(ExtendedAssembler *assembler); 64 65 static void CallOptimized(ExtendedAssembler *assembler); 66 67 static void CallRuntimeWithArgv(ExtendedAssembler *assembler); 68 69 static void JSCallWithArgV(ExtendedAssembler *assembler); 70 71 static void JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler); 72 73 static void SuperCallWithArgV(ExtendedAssembler *assembler); 74 75 static void AOTCallToAsmInterBridge(ExtendedAssembler *assembler); 76 77 static void FastCallToAsmInterBridge(ExtendedAssembler *assembler); 78 79 static void DeoptHandlerAsm(ExtendedAssembler *assembler); 80 81 static void JSCallNew(ExtendedAssembler *assembler); 82 83 static void GenJSCall(ExtendedAssembler *assembler, bool isNew); 84 85 static void GenJSCallWithArgV(ExtendedAssembler *assembler, int id); 86 private: 87 static void DeoptEnterAsmInterpOrBaseline(ExtendedAssembler *assembler); 88 static void JSCallCheck(ExtendedAssembler *assembler, Register jsFuncReg, 89 Label *lNonCallable, Label *lNotJSFunction, Label *lJSFunctionCall); 90 static void ThrowNonCallableInternal(ExtendedAssembler *assembler, Register glueReg); 91 static void JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register jsFuncReg, Label *jsCall); 92 static void OptimizedCallAsmInterpreter(ExtendedAssembler *assembler); 93 static void PushArgsWithArgV(ExtendedAssembler *assembler, Register jsfunc, 94 Register actualNumArgs, Register argV, Label *pushCallThis); 95 static void PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc, 96 Register thisObj, Register newTarget); 97 static void PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs); 98 static void PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp); 99 static void PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue); 100 static void PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp); 101 static void PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler); 102 static void CallBuiltinTrampoline(ExtendedAssembler *assembler, Register temp); 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 CallGetterToBaseline(ExtendedAssembler *assembler); 180 181 static void CallSetterToBaseline(ExtendedAssembler *assembler); 182 183 static void CallContainersArgs2ToBaseline(ExtendedAssembler *assembler); 184 185 static void CallContainersArgs3ToBaseline(ExtendedAssembler *assembler); 186 187 static void CallReturnWithArgvToBaseline(ExtendedAssembler *assembler); 188 189 static void ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler); 190 191 static void ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler); 192 193 static void ResumeRspAndRollback(ExtendedAssembler *assembler); 194 195 static void ASMFastWriteBarrier(ExtendedAssembler *assembler); 196 private: 197 static void PushFrameState(ExtendedAssembler *assembler, Register prevSpRegister, Register fpRegister, 198 Register callTargetRegister, Register thisRegister, Register methodRegister, Register pcRegister, 199 Register operatorRegister); 200 static void PushGeneratorFrameState(ExtendedAssembler *assembler, Register prevSpRegister, 201 Register fpRegister, Register callTargetRegister, Register thisRegister, Register methodRegister, 202 Register contextRegister, Register pcRegister, Register operatorRegister); 203 static void PushAsmInterpEntryFrame(ExtendedAssembler *assembler); 204 static void PopAsmInterpEntryFrame(ExtendedAssembler *assembler); 205 static void GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister, 206 Register declaredNumArgsRegister); 207 static void GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister, 208 Register numVregsRegister); 209 static void PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc, 210 Register op1, Register op2, Label *stackOverflow); 211 static void ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp, 212 Register op); 213 static void ThrowStackOverflowExceptionAndReturnToAsmInterpBridgeFrame(ExtendedAssembler *assembler, Register glue, 214 Register fp, Register op); 215 static void HasPendingException(ExtendedAssembler *assembler, Register threadRegister); 216 static void PushCallThis(ExtendedAssembler *assembler, JSCallMode mode, 217 Label *stackOverflow, FrameTransitionType type); 218 static Register GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 219 static Register GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 220 static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow, FrameTransitionType type); 221 static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister, 222 Register callTargetRegister, Register methodRegister, Register accRegister = rInvalid); 223 static void CallNativeEntry(ExtendedAssembler *assembler, bool isJsProxy); 224 static void CallFastBuiltin(ExtendedAssembler *assembler, Label *callNativeBuiltin); 225 static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget = false); 226 static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode); 227 static bool PushBuiltinFrame(ExtendedAssembler *assembler, Register glue, FrameType type); 228 static void JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode, FrameTransitionType type); 229 static void JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow); 230 static void JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode, 231 Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow); 232 static void PreserveMostCall(ExtendedAssembler* assembler); 233 static void ASMFastSharedWriteBarrier(ExtendedAssembler *assembler, Label &needcall); 234 friend class OptimizedCall; 235 friend class BaselineCall; 236 }; 237 238 class BaselineCall : public CommonCall { 239 public: 240 /* other call baseline: need to check whether baseline code exists */ 241 static void CallArg0AndCheckToBaseline(ExtendedAssembler *assembler); 242 static void CallArg1AndCheckToBaseline(ExtendedAssembler *assembler); 243 static void CallArgs2AndCheckToBaseline(ExtendedAssembler *assembler); 244 static void CallArgs3AndCheckToBaseline(ExtendedAssembler *assembler); 245 static void CallThisArg0AndCheckToBaseline(ExtendedAssembler *assembler); 246 static void CallThisArg1AndCheckToBaseline(ExtendedAssembler *assembler); 247 static void CallThisArgs2AndCheckToBaseline(ExtendedAssembler *assembler); 248 static void CallThisArgs3AndCheckToBaseline(ExtendedAssembler *assembler); 249 static void CallRangeAndCheckToBaseline(ExtendedAssembler *assembler); 250 static void CallNewAndCheckToBaseline(ExtendedAssembler *assembler); 251 static void SuperCallAndCheckToBaseline(ExtendedAssembler *assembler); 252 static void CallThisRangeAndCheckToBaseline(ExtendedAssembler *assembler); 253 /* baseline call other: need to save fp and lr */ 254 static void CallArg0AndDispatchFromBaseline(ExtendedAssembler *assembler); 255 static void CallArg1AndDispatchFromBaseline(ExtendedAssembler *assembler); 256 static void CallArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler); 257 static void CallArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler); 258 static void CallThisArg0AndDispatchFromBaseline(ExtendedAssembler *assembler); 259 static void CallThisArg1AndDispatchFromBaseline(ExtendedAssembler *assembler); 260 static void CallThisArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler); 261 static void CallThisArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler); 262 static void CallRangeAndDispatchFromBaseline(ExtendedAssembler *assembler); 263 static void CallNewAndDispatchFromBaseline(ExtendedAssembler *assembler); 264 static void SuperCallAndDispatchFromBaseline(ExtendedAssembler *assembler); 265 static void CallThisRangeAndDispatchFromBaseline(ExtendedAssembler *assembler); 266 /* baseline call baseline: need to check whether baseline code exists and save fp and lr */ 267 static void CallArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 268 static void CallArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 269 static void CallArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 270 static void CallArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 271 static void CallThisArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 272 static void CallThisArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 273 static void CallThisArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 274 static void CallThisArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 275 static void CallRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 276 static void CallNewAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 277 static void SuperCallAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 278 static void CallThisRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 279 /* get baselineBuiltinFp when baselineBuiltin call the others */ 280 static void GetBaselineBuiltinFp(ExtendedAssembler *assembler); 281 }; 282 283 class JsFunctionArgsConfigFrameScope { 284 public: 285 static constexpr int FRAME_SLOT_SIZE = 8; JsFunctionArgsConfigFrameScope(ExtendedAssembler * assembler)286 explicit JsFunctionArgsConfigFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 287 { 288 assembler_->Pushq(rbp); 289 assembler_->Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); 290 // 2: skip jsFunc and frameType 291 assembler_->Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp); 292 // callee save 293 assembler_->Pushq(r12); 294 assembler_->Pushq(r13); 295 assembler_->Pushq(r14); 296 assembler_->Pushq(rbx); 297 assembler_->Pushq(rax); 298 } ~JsFunctionArgsConfigFrameScope()299 ~JsFunctionArgsConfigFrameScope() 300 { 301 assembler_->Movq(rbp, rsp); 302 assembler_->Addq(-5 * FRAME_SLOT_SIZE, rsp); // -5: get r12 r13 r14 rbx 303 assembler_->Popq(rbx); 304 assembler_->Popq(r14); 305 assembler_->Popq(r13); 306 assembler_->Popq(r12); 307 assembler_->Addq(FRAME_SLOT_SIZE, rsp); // skip frame type 308 assembler_->Pop(rbp); 309 assembler_->Ret(); 310 } 311 NO_COPY_SEMANTIC(JsFunctionArgsConfigFrameScope); 312 NO_MOVE_SEMANTIC(JsFunctionArgsConfigFrameScope); 313 private: 314 ExtendedAssembler *assembler_; 315 }; 316 317 class OptimizedUnfoldArgVFrameFrameScope { 318 public: 319 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler * assembler)320 explicit OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 321 { 322 assembler_->Pushq(rbp); 323 // construct frame 324 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 325 assembler_->Pushq(assembler_->AvailableRegister2()); 326 // 2: skip callSiteSp and frameType 327 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 328 assembler_->Pushq(rbx); 329 assembler_->Pushq(r12); // callee save 330 } ~OptimizedUnfoldArgVFrameFrameScope()331 ~OptimizedUnfoldArgVFrameFrameScope() 332 { 333 assembler_->Movq(rbp, rsp); 334 assembler_->Addq(-4 * FRAME_SLOT_SIZE, rsp); // -4: get r12 rbx 335 assembler_->Popq(r12); 336 assembler_->Popq(rbx); 337 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 338 assembler_->Popq(rbp); 339 assembler_->Ret(); 340 } 341 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 342 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 343 private: 344 ExtendedAssembler *assembler_; 345 }; 346 347 class OptimizedUnfoldArgVFrameFrame1Scope { 348 public: 349 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler * assembler)350 explicit OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler *assembler) : assembler_(assembler) 351 { 352 assembler_->Pushq(rbp); 353 // construct frame 354 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 355 assembler_->Pushq(assembler_->AvailableRegister2()); 356 // 2: skip callSiteSp and frameType 357 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 358 assembler_->Pushq(rbx); 359 assembler_->Pushq(r12); // callee save 360 assembler_->Pushq(r13); 361 assembler_->Pushq(r14); // callee save 362 } ~OptimizedUnfoldArgVFrameFrame1Scope()363 ~OptimizedUnfoldArgVFrameFrame1Scope() 364 { 365 assembler_->Movq(rbp, rsp); 366 assembler_->Addq(-6 * FRAME_SLOT_SIZE, rsp); // -6: get r12 r13 r14 rbx 367 assembler_->Popq(r14); 368 assembler_->Popq(r13); 369 assembler_->Popq(r12); 370 assembler_->Popq(rbx); 371 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 372 assembler_->Popq(rbp); 373 assembler_->Ret(); 374 } 375 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 376 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 377 private: 378 ExtendedAssembler *assembler_; 379 }; 380 } // namespace panda::ecmascript::x64 381 #endif // ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H 382