| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
| 6 | 6 |
| 7 #include "src/arm64/frames-arm64.h" | 7 #include "src/arm64/frames-arm64.h" |
| 8 #include "src/arm64/macro-assembler-arm64-inl.h" | 8 #include "src/arm64/macro-assembler-arm64-inl.h" |
| 9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
| 10 #include "src/counters.h" | 10 #include "src/counters.h" |
| (...skipping 2206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2217 | 2217 |
| 2218 // 4c. The new.target is not a constructor, throw an appropriate TypeError. | 2218 // 4c. The new.target is not a constructor, throw an appropriate TypeError. |
| 2219 __ Bind(&new_target_not_constructor); | 2219 __ Bind(&new_target_not_constructor); |
| 2220 { | 2220 { |
| 2221 __ Poke(new_target, 0); | 2221 __ Poke(new_target, 0); |
| 2222 __ TailCallRuntime(Runtime::kThrowNotConstructor); | 2222 __ TailCallRuntime(Runtime::kThrowNotConstructor); |
| 2223 } | 2223 } |
| 2224 } | 2224 } |
| 2225 | 2225 |
| 2226 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { | 2226 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { |
| 2227 __ SmiTag(x10, x0); | 2227 __ Push(lr, fp); |
| 2228 __ Mov(x11, StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)); | 2228 __ Mov(x11, StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2229 __ Push(lr, fp); | 2229 __ Push(x11, x1); // x1: function |
| 2230 __ Push(x11, x1, x10); | 2230 // We do not yet push the number of arguments, to maintain a 16-byte aligned |
| 2231 __ Add(fp, jssp, | 2231 // stack pointer. This is done in step (3) in |
| 2232 StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize); | 2232 // Generate_ArgumentsAdaptorTrampoline. |
| 2233 __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp); |
| 2233 } | 2234 } |
| 2234 | 2235 |
| 2235 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { | 2236 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { |
| 2236 // ----------- S t a t e ------------- | 2237 // ----------- S t a t e ------------- |
| 2237 // -- x0 : result being passed through | 2238 // -- x0 : result being passed through |
| 2238 // ----------------------------------- | 2239 // ----------------------------------- |
| 2239 // Get the number of arguments passed (as a smi), tear down the frame and | 2240 // Get the number of arguments passed (as a smi), tear down the frame and |
| 2240 // then drop the parameters and the receiver. | 2241 // then drop the parameters and the receiver. |
| 2241 __ Ldr(x10, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp + | 2242 __ Ldr(x10, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp + |
| 2242 kPointerSize))); | 2243 kPointerSize))); |
| 2243 __ Mov(jssp, fp); | 2244 __ Mov(jssp, fp); |
| 2244 __ Pop(fp, lr); | 2245 __ Pop(fp, lr); |
| 2246 |
| 2247 // Drop actual parameters and receiver. |
| 2248 // TODO(all): This will need to be rounded up to a multiple of two when using |
| 2249 // the CSP, as we will have claimed an even number of slots in total for the |
| 2250 // parameters. |
| 2245 __ DropBySMI(x10, kXRegSize); | 2251 __ DropBySMI(x10, kXRegSize); |
| 2246 __ Drop(1); | 2252 __ Drop(1); |
| 2247 } | 2253 } |
| 2248 | 2254 |
| 2249 // static | 2255 // static |
| 2250 void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, | 2256 void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, |
| 2251 Handle<Code> code) { | 2257 Handle<Code> code) { |
| 2252 // ----------- S t a t e ------------- | 2258 // ----------- S t a t e ------------- |
| 2253 // -- x1 : target | 2259 // -- x1 : target |
| 2254 // -- x0 : number of parameters on the stack (not including the receiver) | 2260 // -- x0 : number of parameters on the stack (not including the receiver) |
| (...skipping 802 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3057 | 3063 |
| 3058 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { | 3064 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
| 3059 ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline"); | 3065 ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline"); |
| 3060 // ----------- S t a t e ------------- | 3066 // ----------- S t a t e ------------- |
| 3061 // -- x0 : actual number of arguments | 3067 // -- x0 : actual number of arguments |
| 3062 // -- x1 : function (passed through to callee) | 3068 // -- x1 : function (passed through to callee) |
| 3063 // -- x2 : expected number of arguments | 3069 // -- x2 : expected number of arguments |
| 3064 // -- x3 : new target (passed through to callee) | 3070 // -- x3 : new target (passed through to callee) |
| 3065 // ----------------------------------- | 3071 // ----------------------------------- |
| 3066 | 3072 |
| 3073 // The frame we are about to construct will look like: |
| 3074 // |
| 3075 // slot Adaptor frame |
| 3076 // +-----------------+-------------------------------- |
| 3077 // -n-1 | receiver | ^ |
| 3078 // | (parameter 0) | | |
| 3079 // |- - - - - - - - -| | |
| 3080 // -n | | Caller |
| 3081 // ... | ... | frame slots --> actual args |
| 3082 // -2 | parameter n-1 | | |
| 3083 // |- - - - - - - - -| | |
| 3084 // -1 | parameter n | v |
| 3085 // -----+-----------------+-------------------------------- |
| 3086 // 0 | return addr | ^ |
| 3087 // |- - - - - - - - -| | |
| 3088 // 1 | saved frame ptr | <-- frame ptr | |
| 3089 // |- - - - - - - - -| | |
| 3090 // 2 |Frame Type Marker| | |
| 3091 // |- - - - - - - - -| | |
| 3092 // 3 | function | Callee |
| 3093 // |- - - - - - - - -| frame slots |
| 3094 // 4 | num of | | |
| 3095 // | actual args | | |
| 3096 // |- - - - - - - - -| | |
| 3097 // [5] | [padding] | | |
| 3098 // |-----------------+---- | |
| 3099 // 5+pad | receiver | ^ | |
| 3100 // | (parameter 0) | | | |
| 3101 // |- - - - - - - - -| | | |
| 3102 // 6+pad | parameter 1 | | | |
| 3103 // |- - - - - - - - -| Frame slots ----> expected args |
| 3104 // 7+pad | parameter 2 | | | |
| 3105 // |- - - - - - - - -| | | |
| 3106 // | | | | |
| 3107 // ... | ... | | | |
| 3108 // | parameter m | | | |
| 3109 // |- - - - - - - - -| | | |
| 3110 // | [undefined] | | | |
| 3111 // |- - - - - - - - -| | | |
| 3112 // | | | | |
| 3113 // | ... | | | |
| 3114 // | [undefined] | v <-- stack ptr v |
| 3115 // -----+-----------------+--------------------------------- |
| 3116 // |
| 3117 // There is an optional slot of padding to ensure stack alignment. |
| 3118 // If the number of expected arguments is larger than the number of actual |
| 3119 // arguments, the remaining expected slots will be filled with undefined. |
| 3120 |
| 3067 Register argc_actual = x0; // Excluding the receiver. | 3121 Register argc_actual = x0; // Excluding the receiver. |
| 3068 Register argc_expected = x2; // Excluding the receiver. | 3122 Register argc_expected = x2; // Excluding the receiver. |
| 3069 Register function = x1; | 3123 Register function = x1; |
| 3070 Register code_entry = x10; | 3124 Register code_entry = x10; |
| 3071 | 3125 |
| 3072 Label invoke, dont_adapt_arguments, stack_overflow; | 3126 Label dont_adapt_arguments, stack_overflow; |
| 3073 | 3127 |
| 3074 Label enough, too_few; | 3128 Label enough_arguments; |
| 3075 __ Cmp(argc_actual, argc_expected); | |
| 3076 __ B(lt, &too_few); | |
| 3077 __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel); | 3129 __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
| 3078 __ B(eq, &dont_adapt_arguments); | 3130 __ B(eq, &dont_adapt_arguments); |
| 3079 | 3131 |
| 3080 { // Enough parameters: actual >= expected | 3132 EnterArgumentsAdaptorFrame(masm); |
| 3081 EnterArgumentsAdaptorFrame(masm); | |
| 3082 Generate_StackOverflowCheck(masm, x2, x10, &stack_overflow); | |
| 3083 | 3133 |
| 3084 Register copy_start = x10; | 3134 Register copy_from = x10; |
| 3085 Register copy_end = x11; | 3135 Register copy_end = x11; |
| 3086 Register copy_to = x12; | 3136 Register copy_to = x12; |
| 3087 Register scratch1 = x13, scratch2 = x14; | 3137 Register argc_to_copy = x13; |
| 3138 Register argc_unused_actual = x14; |
| 3139 Register scratch1 = x15, scratch2 = x16; |
| 3088 | 3140 |
| 3089 __ Lsl(scratch2, argc_expected, kPointerSizeLog2); | 3141 // We need slots for the expected arguments, with two extra slots for the |
| 3142 // number of actual arguments and the receiver. |
| 3143 __ RecordComment("-- Stack check --"); |
| 3144 __ Add(scratch1, argc_expected, 2); |
| 3145 Generate_StackOverflowCheck(masm, scratch1, scratch2, &stack_overflow); |
| 3090 | 3146 |
| 3091 // Adjust for fp, lr, and the receiver. | 3147 // Round up number of slots to be even, to maintain stack alignment. |
| 3092 __ Add(copy_start, fp, 3 * kPointerSize); | 3148 __ RecordComment("-- Allocate callee frame slots --"); |
| 3093 __ Add(copy_start, copy_start, Operand(argc_actual, LSL, kPointerSizeLog2)); | 3149 __ Add(scratch1, scratch1, 1); |
| 3094 __ Sub(copy_end, copy_start, scratch2); | 3150 __ Bic(scratch1, scratch1, 1); |
| 3095 __ Sub(copy_end, copy_end, kPointerSize); | 3151 __ Claim(scratch1, kPointerSize); |
| 3096 __ Mov(copy_to, jssp); | |
| 3097 | 3152 |
| 3098 // Claim space for the arguments, the receiver, and one extra slot. | 3153 __ Mov(copy_to, jssp); |
| 3099 // The extra slot ensures we do not write under jssp. It will be popped | |
| 3100 // later. | |
| 3101 __ Add(scratch1, scratch2, 2 * kPointerSize); | |
| 3102 __ Claim(scratch1, 1); | |
| 3103 | 3154 |
| 3104 // Copy the arguments (including the receiver) to the new stack frame. | 3155 // Preparing the expected arguments is done in four steps, the order of |
| 3105 Label copy_2_by_2; | 3156 // which is chosen so we can use LDP/STP and avoid conditional branches as |
| 3106 __ Bind(©_2_by_2); | 3157 // much as possible. |
| 3107 __ Ldp(scratch1, scratch2, | |
| 3108 MemOperand(copy_start, -2 * kPointerSize, PreIndex)); | |
| 3109 __ Stp(scratch1, scratch2, | |
| 3110 MemOperand(copy_to, -2 * kPointerSize, PreIndex)); | |
| 3111 __ Cmp(copy_start, copy_end); | |
| 3112 __ B(hi, ©_2_by_2); | |
| 3113 | 3158 |
| 3114 // Correct the space allocated for the extra slot. | 3159 // (1) If we don't have enough arguments, fill the remaining expected |
| 3115 __ Drop(1); | 3160 // arguments with undefined, otherwise skip this step. |
| 3161 __ Subs(scratch1, argc_actual, argc_expected); |
| 3162 __ Csel(argc_unused_actual, xzr, scratch1, lt); |
| 3163 __ Csel(argc_to_copy, argc_expected, argc_actual, ge); |
| 3164 __ B(ge, &enough_arguments); |
| 3116 | 3165 |
| 3117 __ B(&invoke); | 3166 // Fill the remaining expected arguments with undefined. |
| 3118 } | 3167 __ RecordComment("-- Fill slots with undefined --"); |
| 3168 __ Sub(copy_end, copy_to, Operand(scratch1, LSL, kPointerSizeLog2)); |
| 3169 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); |
| 3119 | 3170 |
| 3120 { // Too few parameters: Actual < expected | 3171 Label fill; |
| 3121 __ Bind(&too_few); | 3172 __ Bind(&fill); |
| 3173 __ Stp(scratch1, scratch1, MemOperand(copy_to, 2 * kPointerSize, PostIndex)); |
| 3174 // We might write one slot extra, but that is ok because we'll overwrite it |
| 3175 // below. |
| 3176 __ Cmp(copy_end, copy_to); |
| 3177 __ B(hi, &fill); |
| 3122 | 3178 |
| 3123 Register copy_from = x10; | 3179 // Correct copy_to, for the case where we wrote one additional slot. |
| 3124 Register copy_end = x11; | 3180 __ Mov(copy_to, copy_end); |
| 3125 Register copy_to = x12; | |
| 3126 Register scratch1 = x13, scratch2 = x14; | |
| 3127 | 3181 |
| 3128 EnterArgumentsAdaptorFrame(masm); | 3182 __ Bind(&enough_arguments); |
| 3129 Generate_StackOverflowCheck(masm, x2, x10, &stack_overflow); | 3183 // (2) Copy all of the actual arguments, or as many as we need. |
| 3184 __ RecordComment("-- Copy actual arguments --"); |
| 3185 __ Add(copy_end, copy_to, Operand(argc_to_copy, LSL, kPointerSizeLog2)); |
| 3186 __ Add(copy_from, fp, 2 * kPointerSize); |
| 3187 // Adjust for difference between actual and expected arguments. |
| 3188 __ Add(copy_from, copy_from, |
| 3189 Operand(argc_unused_actual, LSL, kPointerSizeLog2)); |
| 3130 | 3190 |
| 3131 __ Lsl(scratch2, argc_expected, kPointerSizeLog2); | 3191 // Copy arguments. We use load/store pair instructions, so we might overshoot |
| 3132 __ Lsl(argc_actual, argc_actual, kPointerSizeLog2); | 3192 // by one slot, but since we copy the arguments starting from the last one, if |
| 3193 // we do overshoot, the extra slot will be overwritten later by the receiver. |
| 3194 Label copy_2_by_2; |
| 3195 __ Bind(©_2_by_2); |
| 3196 __ Ldp(scratch1, scratch2, |
| 3197 MemOperand(copy_from, 2 * kPointerSize, PostIndex)); |
| 3198 __ Stp(scratch1, scratch2, MemOperand(copy_to, 2 * kPointerSize, PostIndex)); |
| 3199 __ Cmp(copy_end, copy_to); |
| 3200 __ B(hi, ©_2_by_2); |
| 3133 | 3201 |
| 3134 // Adjust for fp, lr, and the receiver. | 3202 // (3) Store number of actual arguments and padding. The padding might be |
| 3135 __ Add(copy_from, fp, 3 * kPointerSize); | 3203 // unnecessary, in which case it will be overwritten by the receiver. |
| 3136 __ Add(copy_from, copy_from, argc_actual); | 3204 __ RecordComment("-- Store number of args and padding --"); |
| 3137 __ Mov(copy_to, jssp); | 3205 __ SmiTag(scratch1, argc_actual); |
| 3138 __ Sub(copy_end, copy_to, 1 * kPointerSize); // Adjust for the receiver. | 3206 __ Stp(xzr, scratch1, MemOperand(fp, -4 * kPointerSize)); |
| 3139 __ Sub(copy_end, copy_end, argc_actual); | |
| 3140 | 3207 |
| 3141 // Claim space for the arguments, the receiver, and one extra slot. | 3208 // (4) Store receiver. Calculate target address from jssp to avoid checking |
| 3142 // The extra slot ensures we do not write under jssp. It will be popped | 3209 // for padding. Storing the receiver will overwrite either the extra slot |
| 3143 // later. | 3210 // we copied with the actual arguments, if we did copy one, or the padding we |
| 3144 __ Add(scratch1, scratch2, 2 * kPointerSize); | 3211 // stored above. |
| 3145 __ Claim(scratch1, 1); | 3212 __ RecordComment("-- Store receiver --"); |
| 3146 | 3213 __ Add(copy_from, fp, 2 * kPointerSize); |
| 3147 // Copy the arguments (including the receiver) to the new stack frame. | 3214 __ Ldr(scratch1, MemOperand(copy_from, argc_actual, LSL, kPointerSizeLog2)); |
| 3148 Label copy_2_by_2; | 3215 __ Str(scratch1, MemOperand(jssp, argc_expected, LSL, kPointerSizeLog2)); |
| 3149 __ Bind(©_2_by_2); | |
| 3150 __ Ldp(scratch1, scratch2, | |
| 3151 MemOperand(copy_from, -2 * kPointerSize, PreIndex)); | |
| 3152 __ Stp(scratch1, scratch2, | |
| 3153 MemOperand(copy_to, -2 * kPointerSize, PreIndex)); | |
| 3154 __ Cmp(copy_to, copy_end); | |
| 3155 __ B(hi, ©_2_by_2); | |
| 3156 | |
| 3157 __ Mov(copy_to, copy_end); | |
| 3158 | |
| 3159 // Fill the remaining expected arguments with undefined. | |
| 3160 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); | |
| 3161 __ Add(copy_end, jssp, kPointerSize); | |
| 3162 | |
| 3163 Label fill; | |
| 3164 __ Bind(&fill); | |
| 3165 __ Stp(scratch1, scratch1, | |
| 3166 MemOperand(copy_to, -2 * kPointerSize, PreIndex)); | |
| 3167 __ Cmp(copy_to, copy_end); | |
| 3168 __ B(hi, &fill); | |
| 3169 | |
| 3170 // Correct the space allocated for the extra slot. | |
| 3171 __ Drop(1); | |
| 3172 } | |
| 3173 | 3216 |
| 3174 // Arguments have been adapted. Now call the entry point. | 3217 // Arguments have been adapted. Now call the entry point. |
| 3175 __ Bind(&invoke); | 3218 __ RecordComment("-- Call entry point --"); |
| 3176 __ Mov(argc_actual, argc_expected); | 3219 __ Mov(argc_actual, argc_expected); |
| 3177 // x0 : expected number of arguments | 3220 // x0 : expected number of arguments |
| 3178 // x1 : function (passed through to callee) | 3221 // x1 : function (passed through to callee) |
| 3179 // x3 : new target (passed through to callee) | 3222 // x3 : new target (passed through to callee) |
| 3180 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); | 3223 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); |
| 3181 __ Call(code_entry); | 3224 __ Call(code_entry); |
| 3182 | 3225 |
| 3183 // Store offset of return address for deoptimizer. | 3226 // Store offset of return address for deoptimizer. |
| 3184 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset()); | 3227 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset()); |
| 3185 | 3228 |
| 3186 // Exit frame and return. | 3229 // Exit frame and return. |
| 3187 LeaveArgumentsAdaptorFrame(masm); | 3230 LeaveArgumentsAdaptorFrame(masm); |
| 3188 __ Ret(); | 3231 __ Ret(); |
| 3189 | 3232 |
| 3190 // Call the entry point without adapting the arguments. | 3233 // Call the entry point without adapting the arguments. |
| 3234 __ RecordComment("-- Call without adapting args --"); |
| 3191 __ Bind(&dont_adapt_arguments); | 3235 __ Bind(&dont_adapt_arguments); |
| 3192 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); | 3236 __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); |
| 3193 __ Jump(code_entry); | 3237 __ Jump(code_entry); |
| 3194 | 3238 |
| 3195 __ Bind(&stack_overflow); | 3239 __ Bind(&stack_overflow); |
| 3240 __ RecordComment("-- Stack overflow --"); |
| 3196 { | 3241 { |
| 3197 FrameScope frame(masm, StackFrame::MANUAL); | 3242 FrameScope frame(masm, StackFrame::MANUAL); |
| 3198 __ CallRuntime(Runtime::kThrowStackOverflow); | 3243 __ CallRuntime(Runtime::kThrowStackOverflow); |
| 3199 __ Unreachable(); | 3244 __ Unreachable(); |
| 3200 } | 3245 } |
| 3201 } | 3246 } |
| 3202 | 3247 |
| 3203 void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { | 3248 void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { |
| 3204 // Wasm code uses the csp. This builtin excepts to use the jssp. | 3249 // Wasm code uses the csp. This builtin excepts to use the jssp. |
| 3205 // Thus, move csp to jssp when entering this builtin (called from wasm). | 3250 // Thus, move csp to jssp when entering this builtin (called from wasm). |
| (...skipping 29 matching lines...) Expand all Loading... |
| 3235 // Now jump to the instructions of the returned code object. | 3280 // Now jump to the instructions of the returned code object. |
| 3236 __ Jump(x8); | 3281 __ Jump(x8); |
| 3237 } | 3282 } |
| 3238 | 3283 |
| 3239 #undef __ | 3284 #undef __ |
| 3240 | 3285 |
| 3241 } // namespace internal | 3286 } // namespace internal |
| 3242 } // namespace v8 | 3287 } // namespace v8 |
| 3243 | 3288 |
| 3244 #endif // V8_TARGET_ARCH_ARM | 3289 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |