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 |