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 PushCallNewAndDispatchNative(ExtendedAssembler *assembler); 137 138 static void PushCallRangeAndDispatchNative(ExtendedAssembler *assembler); 139 140 static void PushCallArgsAndDispatchNative(ExtendedAssembler *assembler); 141 142 static void ResumeRspAndDispatch(ExtendedAssembler *assembler); 143 144 static void ResumeRspAndReturn([[maybe_unused]] ExtendedAssembler *assembler); 145 146 static void CallGetter(ExtendedAssembler *assembler); 147 148 static void CallSetter(ExtendedAssembler *assembler); 149 150 static void CallContainersArgs3(ExtendedAssembler *assembler); 151 152 static void CallReturnWithArgv(ExtendedAssembler *assembler); 153 154 static void ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler); 155 156 static void ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler); 157 158 private: 159 static void PushFrameState(ExtendedAssembler *assembler, Register prevSpRegister, Register fpRegister, 160 Register callTargetRegister, Register thisRegister, Register methodRegister, Register pcRegister, 161 Register operatorRegister); 162 static void PushGeneratorFrameState(ExtendedAssembler *assembler, Register prevSpRegister, 163 Register fpRegister, Register callTargetRegister, Register thisRegister, Register methodRegister, 164 Register contextRegister, Register pcRegister, Register operatorRegister); 165 static void PushAsmInterpEntryFrame(ExtendedAssembler *assembler); 166 static void PopAsmInterpEntryFrame(ExtendedAssembler *assembler); 167 static void GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister, 168 Register declaredNumArgsRegister); 169 static void GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister, 170 Register numVregsRegister); 171 static void PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc, 172 Register op1, Register op2, Label *stackOverflow); 173 static void ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp, 174 Register op); 175 static void HasPendingException(ExtendedAssembler *assembler, Register threadRegister); 176 static void PushCallThis(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow); 177 static Register GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 178 static Register GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister); 179 static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow); 180 static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister, 181 Register methodRegister, Register accRegister = rInvalid); 182 static void CallNativeEntry(ExtendedAssembler *assemblSer); 183 static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew); 184 static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode); 185 static void PushBuiltinFrame(ExtendedAssembler *assembler, Register glue, FrameType type); 186 static void JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode); 187 static void JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow); 188 static void JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode, 189 Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow); 190 friend class OptimizedCall; 191 }; 192 193 class JsFunctionArgsConfigFrameScope { 194 public: 195 static constexpr int FRAME_SLOT_SIZE = 8; JsFunctionArgsConfigFrameScope(ExtendedAssembler * assembler)196 explicit JsFunctionArgsConfigFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 197 { 198 assembler_->Pushq(rbp); 199 assembler_->Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)); 200 // 2: skip jsFunc and frameType 201 assembler_->Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp); 202 // callee save 203 assembler_->Pushq(r12); 204 assembler_->Pushq(r13); 205 assembler_->Pushq(r14); 206 assembler_->Pushq(rbx); 207 assembler_->Pushq(rax); 208 } ~JsFunctionArgsConfigFrameScope()209 ~JsFunctionArgsConfigFrameScope() 210 { 211 assembler_->Movq(rbp, rsp); 212 assembler_->Addq(-5 * FRAME_SLOT_SIZE, rsp); // -5: get r12 r13 r14 rbx 213 assembler_->Popq(rbx); 214 assembler_->Popq(r14); 215 assembler_->Popq(r13); 216 assembler_->Popq(r12); 217 assembler_->Addq(FRAME_SLOT_SIZE, rsp); // skip frame type 218 assembler_->Pop(rbp); 219 assembler_->Ret(); 220 } 221 NO_COPY_SEMANTIC(JsFunctionArgsConfigFrameScope); 222 NO_MOVE_SEMANTIC(JsFunctionArgsConfigFrameScope); 223 private: 224 ExtendedAssembler *assembler_; 225 }; 226 227 class OptimizedUnfoldArgVFrameFrameScope { 228 public: 229 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler * assembler)230 explicit OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler *assembler) : assembler_(assembler) 231 { 232 assembler_->Pushq(rbp); 233 // construct frame 234 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 235 assembler_->Pushq(assembler_->AvailableRegister2()); 236 // 2: skip callSiteSp and frameType 237 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 238 assembler_->Pushq(rbx); 239 assembler_->Pushq(r12); // callee save 240 } ~OptimizedUnfoldArgVFrameFrameScope()241 ~OptimizedUnfoldArgVFrameFrameScope() 242 { 243 assembler_->Movq(rbp, rsp); 244 assembler_->Addq(-4 * FRAME_SLOT_SIZE, rsp); // -4: get r12 rbx 245 assembler_->Popq(r12); 246 assembler_->Popq(rbx); 247 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 248 assembler_->Popq(rbp); 249 assembler_->Ret(); 250 } 251 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 252 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope); 253 private: 254 ExtendedAssembler *assembler_; 255 }; 256 257 class OptimizedUnfoldArgVFrameFrame1Scope { 258 public: 259 static constexpr int FRAME_SLOT_SIZE = 8; OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler * assembler)260 explicit OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler *assembler) : assembler_(assembler) 261 { 262 assembler_->Pushq(rbp); 263 // construct frame 264 assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME)); 265 assembler_->Pushq(assembler_->AvailableRegister2()); 266 // 2: skip callSiteSp and frameType 267 assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp); 268 assembler_->Pushq(rbx); 269 assembler_->Pushq(r12); // callee save 270 assembler_->Pushq(r13); 271 assembler_->Pushq(r14); // callee save 272 } ~OptimizedUnfoldArgVFrameFrame1Scope()273 ~OptimizedUnfoldArgVFrameFrame1Scope() 274 { 275 assembler_->Movq(rbp, rsp); 276 assembler_->Addq(-6 * FRAME_SLOT_SIZE, rsp); // -6: get r12 r13 r14 rbx 277 assembler_->Popq(r14); 278 assembler_->Popq(r13); 279 assembler_->Popq(r12); 280 assembler_->Popq(rbx); 281 assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp 282 assembler_->Popq(rbp); 283 assembler_->Ret(); 284 } 285 NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 286 NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope); 287 private: 288 ExtendedAssembler *assembler_; 289 }; 290 } // namespace panda::ecmascript::x64 291 #endif // ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H 292