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 class CommonCall { 25 public: 26 static constexpr int FRAME_SLOT_SIZE = 8; 27 static constexpr int DOUBLE_SLOT_SIZE = 16; 28 static constexpr int TRIPLE_SLOT_SIZE = 24; 29 static constexpr int QUADRUPLE_SLOT_SIZE = 32; 30 static constexpr int QUINTUPLE_SLOT_SIZE = 40; 31 static constexpr int SEXTUPLE_SLOT_SIZE = 48; 32 static void CopyArgumentWithArgV(ExtendedAssembler *assembler, Register argc, Register argV); 33 static void PushAsmInterpBridgeFrame(ExtendedAssembler *assembler); 34 static void PopAsmInterpBridgeFrame(ExtendedAssembler *assembler); 35 static void PushUndefinedWithArgc(ExtendedAssembler *assembler, Register argc); 36 static void GetArgvAtStack(ExtendedAssembler *assembler); 37 static void PushArgsWithArgvAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc, Register argv, 38 Register op1, Register op2, Label *stackOverflow); 39 static void StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register numArgs, Register op1, 40 Register op2, Label *stackOverflow); 41 }; 42 43 class OptimizedCall : public CommonCall { 44 public: 45 static void CallRuntime(ExtendedAssembler *assembler); 46 47 static void JSFunctionEntry(ExtendedAssembler *assembler); 48 49 static void OptimizedCallAndPushUndefined(ExtendedAssembler *assembler); 50 51 static void CallBuiltinTrampoline(ExtendedAssembler *assembler); 52 53 static void JSProxyCallInternalWithArgV(ExtendedAssembler *assembler); 54 55 static void JSCall(ExtendedAssembler *assembler); 56 57 static void CallOptimized(ExtendedAssembler *assembler); 58 59 static void CallRuntimeWithArgv(ExtendedAssembler *assembler); 60 61 static void JSCallWithArgV(ExtendedAssembler *assembler); 62 63 static void JSCallWithArgVAndPushUndefined(ExtendedAssembler *assembler); 64 65 static void DeoptHandlerAsm(ExtendedAssembler *assembler); 66 67 static void JSCallNew(ExtendedAssembler *assembler); 68 69 static void GenJSCall(ExtendedAssembler *assembler, bool isNew); 70 71 static void GenJSCallWithArgV(ExtendedAssembler *assembler, bool needAddExpectedArgs); 72 private: 73 static void DeoptEnterAsmInterp(ExtendedAssembler *assembler); 74 static void JSCallCheck(ExtendedAssembler *assembler, Register jsFuncReg, 75 Label *lNonCallable, Label *lNotJSFunction, Label *lJSFunctionCall); 76 static void ThrowNonCallableInternal(ExtendedAssembler *assembler, Register glueReg); 77 static void JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register jsFuncReg, Label *jsCall); 78 static void JSProxyCallInternal(ExtendedAssembler *assembler, Register jsFuncReg); 79 static void OptimizedCallAsmInterpreter(ExtendedAssembler *assembler); 80 static void PushArgsWithArgV(ExtendedAssembler *assembler, Register jsfunc, 81 Register actualNumArgs, Register argV, Label *pushCallThis); 82 static void PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc, 83 Register thisObj, Register newTarget); 84 static void PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs); 85 static void PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp); 86 static void PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue); 87 static void PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp); 88 static void PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler); 89 90 friend class OptimizedFastCall; 91 }; 92 93 class OptimizedFastCall : public CommonCall { 94 public: 95 static void OptimizedFastCallEntry(ExtendedAssembler *assembler); 96 97 static void OptimizedFastCallAndPushUndefined(ExtendedAssembler *assembler); 98 99 static void JSFastCallWithArgV(ExtendedAssembler *assembler); 100 101 static void JSFastCallWithArgVAndPushUndefined(ExtendedAssembler *assembler); 102 }; 103 104 class AsmInterpreterCall : public CommonCall { 105 public: 106 static void GeneratorReEnterAsmInterp(ExtendedAssembler *assembler); 107 108 static void GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *assembler); 109 110 static void AsmInterpEntryDispatch(ExtendedAssembler *assembler); 111 112 static void AsmInterpreterEntry(ExtendedAssembler *assembler); 113 114 static void PushCallThisRangeAndDispatch(ExtendedAssembler *assembler); 115 116 static void PushCallRangeAndDispatch(ExtendedAssembler *assembler); 117 118 static void PushCallArgs3AndDispatch(ExtendedAssembler *assembler); 119 120 static void PushCallArgs2AndDispatch(ExtendedAssembler *assembler); 121 122 static void PushCallArg1AndDispatch(ExtendedAssembler *assembler); 123 124 static void PushCallArg0AndDispatch(ExtendedAssembler *assembler); 125 126 static void PushCallThisArg0AndDispatch(ExtendedAssembler *assembler); 127 128 static void PushCallThisArg1AndDispatch(ExtendedAssembler *assembler); 129 130 static void PushCallThisArgs2AndDispatch(ExtendedAssembler *assembler); 131 132 static void PushCallThisArgs3AndDispatch(ExtendedAssembler *assembler); 133 134 static void PushCallNewAndDispatch(ExtendedAssembler *assembler); 135 136 static void PushSuperCallAndDispatch(ExtendedAssembler *assembler); 137 138 static void PushCallNewAndDispatchNative(ExtendedAssembler *assembler); 139 140 static void PushNewTargetAndDispatchNative(ExtendedAssembler *assembler); 141 142 static void PushCallRangeAndDispatchNative(ExtendedAssembler *assembler); 143 144 static void PushCallArgsAndDispatchNative(ExtendedAssembler *assembler); 145 146 static void ResumeRspAndDispatch(ExtendedAssembler *assembler); 147 148 static void ResumeRspAndReturn([[maybe_unused]] ExtendedAssembler *assembler); 149 150 static void CallGetter(ExtendedAssembler *assembler); 151 152 static void CallSetter(ExtendedAssembler *assembler); 153 154 static void CallContainersArgs3(ExtendedAssembler *assembler); 155 156 static void CallReturnWithArgv(ExtendedAssembler *assembler); 157 158 static void ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler); 159 160 static void ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler); 161 162 static void ResumeRspAndRollback(ExtendedAssembler *assembler); 163 164 private: 165 static void PushFrameState(ExtendedAssembler *assembler, Register prevSpRegister, Register fpRegister, 166 Register callTargetRegister, Register thisRegister, Register methodRegister, Register pcRegister, 167 Register operatorRegister); 168 static void PushGeneratorFrameState(ExtendedAssembler *assembler, Register prevSpRegister, 169 Register fpRegister, Register callTargetRegister, Register thisRegister, Register methodRegister, 170 Register contextRegister, Register pcRegister, Register operatorRegister); 171 static void PushAsmInterpEntryFrame(ExtendedAssembler *assembler); 172 static void PopAsmInterpEntryFrame(ExtendedAssembler *assembler); 173 static void GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister, 174 Register declaredNumArgsRegister); 175 static void GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister, 176 Register numVregsRegister); 177 static void PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc, 178 Register op1, Register op2, Label *stackOverflow); 179 static void ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp, 180 Register op); 181 static void HasPendingException(ExtendedAssembler *assembler, Register threadRegister); 182 static void PushCallThis(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow); 183 static Register GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 184 static Register GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 185 static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow); 186 static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister, 187 Register methodRegister, Register accRegister = rInvalid); 188 static void CallNativeEntry(ExtendedAssembler *assemblSer); 189 static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget = false); 190 static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode); 191 static void PushBuiltinFrame(ExtendedAssembler *assembler, Register glue, FrameType type); 192 static void JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode); 193 static void JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow); 194 static void JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode, 195 Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow); 196 friend class OptimizedCall; 197 }; 198 199 class JsFunctionArgsConfigFrameScope { 200 public: 201 static constexpr int FRAME_SLOT_SIZE = 8; JsFunctionArgsConfigFrameScope(ExtendedAssembler * assembler)202 explicit JsFunctionArgsConfigFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 203 { 204 assembler_->Pushq(rbp); 205 assembler_->Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); 206 // 2: skip jsFunc and frameType 207 assembler_->Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp); 208 // callee save 209 assembler_->Pushq(r12); 210 assembler_->Pushq(r13); 211 assembler_->Pushq(r14); 212 assembler_->Pushq(rbx); 213 assembler_->Pushq(rax); 214 } ~JsFunctionArgsConfigFrameScope()215 ~JsFunctionArgsConfigFrameScope() 216 { 217 assembler_->Movq(rbp, rsp); 218 assembler_->Addq(-5 * FRAME_SLOT_SIZE, rsp); // -5: get r12 r13 r14 rbx 219 assembler_->Popq(rbx); 220 assembler_->Popq(r14); 221 assembler_->Popq(r13); 222 assembler_->Popq(r12); 223 assembler_->Addq(FRAME_SLOT_SIZE, rsp); // skip frame type 224 assembler_->Pop(rbp); 225 assembler_->Ret(); 226 } 227 NO_COPY_SEMANTIC(JsFunctionArgsConfigFrameScope); 228 NO_MOVE_SEMANTIC(JsFunctionArgsConfigFrameScope); 229 private: 230 ExtendedAssembler *assembler_; 231 }; 232 233 class OptimizedUnfoldArgVFrameFrameScope { 234 public: 235 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler * assembler)236 explicit OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 237 { 238 assembler_->Pushq(rbp); 239 // construct frame 240 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 241 assembler_->Pushq(assembler_->AvailableRegister2()); 242 // 2: skip callSiteSp and frameType 243 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 244 assembler_->Pushq(rbx); 245 assembler_->Pushq(r12); // callee save 246 } ~OptimizedUnfoldArgVFrameFrameScope()247 ~OptimizedUnfoldArgVFrameFrameScope() 248 { 249 assembler_->Movq(rbp, rsp); 250 assembler_->Addq(-4 * FRAME_SLOT_SIZE, rsp); // -4: get r12 rbx 251 assembler_->Popq(r12); 252 assembler_->Popq(rbx); 253 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 254 assembler_->Popq(rbp); 255 assembler_->Ret(); 256 } 257 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 258 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 259 private: 260 ExtendedAssembler *assembler_; 261 }; 262 263 class OptimizedUnfoldArgVFrameFrame1Scope { 264 public: 265 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler * assembler)266 explicit OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler *assembler) : assembler_(assembler) 267 { 268 assembler_->Pushq(rbp); 269 // construct frame 270 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 271 assembler_->Pushq(assembler_->AvailableRegister2()); 272 // 2: skip callSiteSp and frameType 273 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 274 assembler_->Pushq(rbx); 275 assembler_->Pushq(r12); // callee save 276 assembler_->Pushq(r13); 277 assembler_->Pushq(r14); // callee save 278 } ~OptimizedUnfoldArgVFrameFrame1Scope()279 ~OptimizedUnfoldArgVFrameFrame1Scope() 280 { 281 assembler_->Movq(rbp, rsp); 282 assembler_->Addq(-6 * FRAME_SLOT_SIZE, rsp); // -6: get r12 r13 r14 rbx 283 assembler_->Popq(r14); 284 assembler_->Popq(r13); 285 assembler_->Popq(r12); 286 assembler_->Popq(rbx); 287 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 288 assembler_->Popq(rbp); 289 assembler_->Ret(); 290 } 291 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 292 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 293 private: 294 ExtendedAssembler *assembler_; 295 }; 296 } // namespace panda::ecmascript::x64 297 #endif // ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H 298