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 DeoptPushAsmInterpBridgeFrame(ExtendedAssembler *assembler, Register context); 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 PushAsmBridgeFrame(ExtendedAssembler *assembler); 103 static void CallBuiltinTrampoline(ExtendedAssembler *assembler, Register temp); 104 static void PopAsmBridgeFrame(ExtendedAssembler *assembler); 105 static void CallBuiltinConstructorStub(ExtendedAssembler *assembler, Register builtinStub, Register argv, 106 Register glue, Register temp); 107 static void RemoveArgv(ExtendedAssembler *assembler, Register temp); 108 109 friend class OptimizedFastCall; 110 }; 111 112 class OptimizedFastCall : public CommonCall { 113 public: 114 static void OptimizedFastCallEntry(ExtendedAssembler *assembler); 115 116 static void OptimizedFastCallAndPushArgv(ExtendedAssembler *assembler); 117 118 static void JSFastCallWithArgV(ExtendedAssembler *assembler); 119 120 static void JSFastCallWithArgVAndPushArgv(ExtendedAssembler *assembler); 121 }; 122 123 class AsmInterpreterCall : public CommonCall { 124 public: 125 static void GeneratorReEnterAsmInterp(ExtendedAssembler *assembler); 126 127 static void GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *assembler); 128 129 static void AsmInterpEntryDispatch(ExtendedAssembler *assembler); 130 131 static void AsmInterpreterEntry(ExtendedAssembler *assembler); 132 133 static void PushCallThisRangeAndDispatch(ExtendedAssembler *assembler); 134 135 static void PushCallRangeAndDispatch(ExtendedAssembler *assembler); 136 137 static void PushCallArgs3AndDispatch(ExtendedAssembler *assembler); 138 139 static void PushCallArgs2AndDispatch(ExtendedAssembler *assembler); 140 141 static void PushCallArg1AndDispatch(ExtendedAssembler *assembler); 142 143 static void PushCallArg0AndDispatch(ExtendedAssembler *assembler); 144 145 static void PushCallThisArg0AndDispatch(ExtendedAssembler *assembler); 146 147 static void PushCallThisArg1AndDispatch(ExtendedAssembler *assembler); 148 149 static void PushCallThisArgs2AndDispatch(ExtendedAssembler *assembler); 150 151 static void PushCallThisArgs3AndDispatch(ExtendedAssembler *assembler); 152 153 static void PushCallNewAndDispatch(ExtendedAssembler *assembler); 154 155 static void PushSuperCallAndDispatch(ExtendedAssembler *assembler); 156 157 static void PushCallNewAndDispatchNative(ExtendedAssembler *assembler); 158 159 static void PushNewTargetAndDispatchNative(ExtendedAssembler *assembler); 160 161 static void PushCallRangeAndDispatchNative(ExtendedAssembler *assembler); 162 163 static void PushCallArgsAndDispatchNative(ExtendedAssembler *assembler); 164 165 static void ResumeRspAndDispatch(ExtendedAssembler *assembler); 166 167 static void ResumeRspAndReturn([[maybe_unused]] ExtendedAssembler *assembler); 168 169 static void ResumeRspAndReturnBaseline([[maybe_unused]] ExtendedAssembler *assembler); 170 171 static void CallGetter(ExtendedAssembler *assembler); 172 173 static void CallSetter(ExtendedAssembler *assembler); 174 175 static void CallContainersArgs2(ExtendedAssembler *assembler); 176 177 static void CallContainersArgs3(ExtendedAssembler *assembler); 178 179 static void CallReturnWithArgv(ExtendedAssembler *assembler); 180 181 static void ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler); 182 183 static void ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler); 184 185 static void ResumeRspAndRollback(ExtendedAssembler *assembler); 186 187 static void ASMFastWriteBarrier(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 ThrowStackOverflowExceptionAndReturnToAsmInterpBridgeFrame(ExtendedAssembler *assembler, Register glue, 206 Register fp, Register op); 207 static void HasPendingException(ExtendedAssembler *assembler, Register threadRegister); 208 static void PushCallThis(ExtendedAssembler *assembler, JSCallMode mode, 209 Label *stackOverflow, FrameTransitionType type); 210 static Register GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 211 static Register GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 212 static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow, FrameTransitionType type); 213 static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister, 214 Register callTargetRegister, Register methodRegister, Register accRegister = rInvalid, 215 bool hasException = false); 216 static void CallNativeEntry(ExtendedAssembler *assembler, bool isJSFunction); 217 static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget = false); 218 static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode); 219 static bool PushBuiltinFrame(ExtendedAssembler *assembler, Register glue, FrameType type); 220 static void JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode, FrameTransitionType type); 221 static void JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow); 222 static void JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode, 223 Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow); 224 static void PreserveMostCall(ExtendedAssembler* assembler); 225 static void ASMFastSharedWriteBarrier(ExtendedAssembler *assembler, Label &needcall); 226 friend class OptimizedCall; 227 friend class BaselineCall; 228 }; 229 230 class BaselineCall : public CommonCall { 231 public: 232 /* other call baseline: need to check whether baseline code exists */ 233 static void CallArg0AndCheckToBaseline(ExtendedAssembler *assembler); 234 static void CallArg1AndCheckToBaseline(ExtendedAssembler *assembler); 235 static void CallArgs2AndCheckToBaseline(ExtendedAssembler *assembler); 236 static void CallArgs3AndCheckToBaseline(ExtendedAssembler *assembler); 237 static void CallThisArg0AndCheckToBaseline(ExtendedAssembler *assembler); 238 static void CallThisArg1AndCheckToBaseline(ExtendedAssembler *assembler); 239 static void CallThisArgs2AndCheckToBaseline(ExtendedAssembler *assembler); 240 static void CallThisArgs3AndCheckToBaseline(ExtendedAssembler *assembler); 241 static void CallRangeAndCheckToBaseline(ExtendedAssembler *assembler); 242 static void CallNewAndCheckToBaseline(ExtendedAssembler *assembler); 243 static void SuperCallAndCheckToBaseline(ExtendedAssembler *assembler); 244 static void CallThisRangeAndCheckToBaseline(ExtendedAssembler *assembler); 245 /* baseline call other: need to save fp and lr */ 246 static void CallArg0AndDispatchFromBaseline(ExtendedAssembler *assembler); 247 static void CallArg1AndDispatchFromBaseline(ExtendedAssembler *assembler); 248 static void CallArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler); 249 static void CallArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler); 250 static void CallThisArg0AndDispatchFromBaseline(ExtendedAssembler *assembler); 251 static void CallThisArg1AndDispatchFromBaseline(ExtendedAssembler *assembler); 252 static void CallThisArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler); 253 static void CallThisArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler); 254 static void CallRangeAndDispatchFromBaseline(ExtendedAssembler *assembler); 255 static void CallNewAndDispatchFromBaseline(ExtendedAssembler *assembler); 256 static void SuperCallAndDispatchFromBaseline(ExtendedAssembler *assembler); 257 static void CallThisRangeAndDispatchFromBaseline(ExtendedAssembler *assembler); 258 /* baseline call baseline: need to check whether baseline code exists and save fp and lr */ 259 static void CallArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 260 static void CallArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 261 static void CallArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 262 static void CallArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 263 static void CallThisArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 264 static void CallThisArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 265 static void CallThisArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 266 static void CallThisArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 267 static void CallRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 268 static void CallNewAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 269 static void SuperCallAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 270 static void CallThisRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler); 271 /* get baselineBuiltinFp when baselineBuiltin call the others */ 272 static void GetBaselineBuiltinFp(ExtendedAssembler *assembler); 273 }; 274 275 class JsFunctionArgsConfigFrameScope { 276 public: 277 static constexpr int FRAME_SLOT_SIZE = 8; JsFunctionArgsConfigFrameScope(ExtendedAssembler * assembler)278 explicit JsFunctionArgsConfigFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 279 { 280 assembler_->Pushq(rbp); 281 assembler_->Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); 282 // 2: skip jsFunc and frameType 283 assembler_->Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp); 284 // callee save 285 assembler_->Pushq(r12); 286 assembler_->Pushq(r13); 287 assembler_->Pushq(r14); 288 assembler_->Pushq(rbx); 289 assembler_->Pushq(rax); 290 } ~JsFunctionArgsConfigFrameScope()291 ~JsFunctionArgsConfigFrameScope() 292 { 293 assembler_->Movq(rbp, rsp); 294 assembler_->Addq(-5 * FRAME_SLOT_SIZE, rsp); // -5: get r12 r13 r14 rbx 295 assembler_->Popq(rbx); 296 assembler_->Popq(r14); 297 assembler_->Popq(r13); 298 assembler_->Popq(r12); 299 assembler_->Addq(FRAME_SLOT_SIZE, rsp); // skip frame type 300 assembler_->Pop(rbp); 301 assembler_->Ret(); 302 } 303 NO_COPY_SEMANTIC(JsFunctionArgsConfigFrameScope); 304 NO_MOVE_SEMANTIC(JsFunctionArgsConfigFrameScope); 305 private: 306 ExtendedAssembler *assembler_; 307 }; 308 309 class OptimizedUnfoldArgVFrameFrameScope { 310 public: 311 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler * assembler)312 explicit OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 313 { 314 assembler_->Pushq(rbp); 315 // construct frame 316 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 317 assembler_->Pushq(assembler_->AvailableRegister2()); 318 // 2: skip callSiteSp and frameType 319 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 320 assembler_->Pushq(rbx); 321 assembler_->Pushq(r12); // callee save 322 } ~OptimizedUnfoldArgVFrameFrameScope()323 ~OptimizedUnfoldArgVFrameFrameScope() 324 { 325 assembler_->Movq(rbp, rsp); 326 assembler_->Addq(-4 * FRAME_SLOT_SIZE, rsp); // -4: get r12 rbx 327 assembler_->Popq(r12); 328 assembler_->Popq(rbx); 329 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 330 assembler_->Popq(rbp); 331 assembler_->Ret(); 332 } 333 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 334 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 335 private: 336 ExtendedAssembler *assembler_; 337 }; 338 339 class OptimizedUnfoldArgVFrameFrame1Scope { 340 public: 341 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler * assembler)342 explicit OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler *assembler) : assembler_(assembler) 343 { 344 assembler_->Pushq(rbp); 345 // construct frame 346 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 347 assembler_->Pushq(assembler_->AvailableRegister2()); 348 // 2: skip callSiteSp and frameType 349 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 350 assembler_->Pushq(rbx); 351 assembler_->Pushq(r12); // callee save 352 assembler_->Pushq(r13); 353 assembler_->Pushq(r14); // callee save 354 } ~OptimizedUnfoldArgVFrameFrame1Scope()355 ~OptimizedUnfoldArgVFrameFrame1Scope() 356 { 357 assembler_->Movq(rbp, rsp); 358 assembler_->Addq(-6 * FRAME_SLOT_SIZE, rsp); // -6: get r12 r13 r14 rbx 359 assembler_->Popq(r14); 360 assembler_->Popq(r13); 361 assembler_->Popq(r12); 362 assembler_->Popq(rbx); 363 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 364 assembler_->Popq(rbp); 365 assembler_->Ret(); 366 } 367 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 368 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 369 private: 370 ExtendedAssembler *assembler_; 371 }; 372 } // namespace panda::ecmascript::x64 373 #endif // ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H 374