| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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_IA32 | 5 #if V8_TARGET_ARCH_IA32 |
| 6 | 6 |
| 7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
| 8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| (...skipping 3047 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3058 | 3058 |
| 3059 Label fast_elements_case; | 3059 Label fast_elements_case; |
| 3060 __ cmp(ecx, Immediate(FAST_ELEMENTS)); | 3060 __ cmp(ecx, Immediate(FAST_ELEMENTS)); |
| 3061 __ j(equal, &fast_elements_case); | 3061 __ j(equal, &fast_elements_case); |
| 3062 GenerateCase(masm, FAST_HOLEY_ELEMENTS); | 3062 GenerateCase(masm, FAST_HOLEY_ELEMENTS); |
| 3063 | 3063 |
| 3064 __ bind(&fast_elements_case); | 3064 __ bind(&fast_elements_case); |
| 3065 GenerateCase(masm, FAST_ELEMENTS); | 3065 GenerateCase(masm, FAST_ELEMENTS); |
| 3066 } | 3066 } |
| 3067 | 3067 |
| 3068 void FastNewRestParameterStub::Generate(MacroAssembler* masm) { | |
| 3069 // ----------- S t a t e ------------- | |
| 3070 // -- edi : function | |
| 3071 // -- esi : context | |
| 3072 // -- ebp : frame pointer | |
| 3073 // -- esp[0] : return address | |
| 3074 // ----------------------------------- | |
| 3075 __ AssertFunction(edi); | |
| 3076 | |
| 3077 // Make edx point to the JavaScript frame. | |
| 3078 __ mov(edx, ebp); | |
| 3079 if (skip_stub_frame()) { | |
| 3080 // For Ignition we need to skip the handler/stub frame to reach the | |
| 3081 // JavaScript frame for the function. | |
| 3082 __ mov(edx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); | |
| 3083 } | |
| 3084 if (FLAG_debug_code) { | |
| 3085 Label ok; | |
| 3086 __ cmp(edi, Operand(edx, StandardFrameConstants::kFunctionOffset)); | |
| 3087 __ j(equal, &ok); | |
| 3088 __ Abort(kInvalidFrameForFastNewRestArgumentsStub); | |
| 3089 __ bind(&ok); | |
| 3090 } | |
| 3091 | |
| 3092 // Check if we have rest parameters (only possible if we have an | |
| 3093 // arguments adaptor frame below the function frame). | |
| 3094 Label no_rest_parameters; | |
| 3095 __ mov(ebx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); | |
| 3096 __ cmp(Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset), | |
| 3097 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | |
| 3098 __ j(not_equal, &no_rest_parameters, Label::kNear); | |
| 3099 | |
| 3100 // Check if the arguments adaptor frame contains more arguments than | |
| 3101 // specified by the function's internal formal parameter count. | |
| 3102 Label rest_parameters; | |
| 3103 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
| 3104 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | |
| 3105 __ sub(eax, | |
| 3106 FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset)); | |
| 3107 __ j(greater, &rest_parameters); | |
| 3108 | |
| 3109 // Return an empty rest parameter array. | |
| 3110 __ bind(&no_rest_parameters); | |
| 3111 { | |
| 3112 // ----------- S t a t e ------------- | |
| 3113 // -- esi : context | |
| 3114 // -- esp[0] : return address | |
| 3115 // ----------------------------------- | |
| 3116 | |
| 3117 // Allocate an empty rest parameter array. | |
| 3118 Label allocate, done_allocate; | |
| 3119 __ Allocate(JSArray::kSize, eax, edx, ecx, &allocate, NO_ALLOCATION_FLAGS); | |
| 3120 __ bind(&done_allocate); | |
| 3121 | |
| 3122 // Setup the rest parameter array in rax. | |
| 3123 __ LoadGlobalFunction(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, ecx); | |
| 3124 __ mov(FieldOperand(eax, JSArray::kMapOffset), ecx); | |
| 3125 __ mov(ecx, isolate()->factory()->empty_fixed_array()); | |
| 3126 __ mov(FieldOperand(eax, JSArray::kPropertiesOffset), ecx); | |
| 3127 __ mov(FieldOperand(eax, JSArray::kElementsOffset), ecx); | |
| 3128 __ mov(FieldOperand(eax, JSArray::kLengthOffset), Immediate(Smi::kZero)); | |
| 3129 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); | |
| 3130 __ Ret(); | |
| 3131 | |
| 3132 // Fall back to %AllocateInNewSpace. | |
| 3133 __ bind(&allocate); | |
| 3134 { | |
| 3135 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 3136 __ Push(Smi::FromInt(JSArray::kSize)); | |
| 3137 __ CallRuntime(Runtime::kAllocateInNewSpace); | |
| 3138 } | |
| 3139 __ jmp(&done_allocate); | |
| 3140 } | |
| 3141 | |
| 3142 __ bind(&rest_parameters); | |
| 3143 { | |
| 3144 // Compute the pointer to the first rest parameter (skippping the receiver). | |
| 3145 __ lea(ebx, | |
| 3146 Operand(ebx, eax, times_half_pointer_size, | |
| 3147 StandardFrameConstants::kCallerSPOffset - 1 * kPointerSize)); | |
| 3148 | |
| 3149 // ----------- S t a t e ------------- | |
| 3150 // -- esi : context | |
| 3151 // -- eax : number of rest parameters (tagged) | |
| 3152 // -- ebx : pointer to first rest parameters | |
| 3153 // -- esp[0] : return address | |
| 3154 // ----------------------------------- | |
| 3155 | |
| 3156 // Allocate space for the rest parameter array plus the backing store. | |
| 3157 Label allocate, done_allocate; | |
| 3158 __ lea(ecx, Operand(eax, times_half_pointer_size, | |
| 3159 JSArray::kSize + FixedArray::kHeaderSize)); | |
| 3160 __ Allocate(ecx, edx, edi, no_reg, &allocate, NO_ALLOCATION_FLAGS); | |
| 3161 __ bind(&done_allocate); | |
| 3162 | |
| 3163 // Setup the elements array in edx. | |
| 3164 __ mov(FieldOperand(edx, FixedArray::kMapOffset), | |
| 3165 isolate()->factory()->fixed_array_map()); | |
| 3166 __ mov(FieldOperand(edx, FixedArray::kLengthOffset), eax); | |
| 3167 { | |
| 3168 Label loop, done_loop; | |
| 3169 __ Move(ecx, Smi::kZero); | |
| 3170 __ bind(&loop); | |
| 3171 __ cmp(ecx, eax); | |
| 3172 __ j(equal, &done_loop, Label::kNear); | |
| 3173 __ mov(edi, Operand(ebx, 0 * kPointerSize)); | |
| 3174 __ mov(FieldOperand(edx, ecx, times_half_pointer_size, | |
| 3175 FixedArray::kHeaderSize), | |
| 3176 edi); | |
| 3177 __ sub(ebx, Immediate(1 * kPointerSize)); | |
| 3178 __ add(ecx, Immediate(Smi::FromInt(1))); | |
| 3179 __ jmp(&loop); | |
| 3180 __ bind(&done_loop); | |
| 3181 } | |
| 3182 | |
| 3183 // Setup the rest parameter array in edi. | |
| 3184 __ lea(edi, | |
| 3185 Operand(edx, eax, times_half_pointer_size, FixedArray::kHeaderSize)); | |
| 3186 __ LoadGlobalFunction(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, ecx); | |
| 3187 __ mov(FieldOperand(edi, JSArray::kMapOffset), ecx); | |
| 3188 __ mov(FieldOperand(edi, JSArray::kPropertiesOffset), | |
| 3189 isolate()->factory()->empty_fixed_array()); | |
| 3190 __ mov(FieldOperand(edi, JSArray::kElementsOffset), edx); | |
| 3191 __ mov(FieldOperand(edi, JSArray::kLengthOffset), eax); | |
| 3192 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); | |
| 3193 __ mov(eax, edi); | |
| 3194 __ Ret(); | |
| 3195 | |
| 3196 // Fall back to %AllocateInNewSpace (if not too big). | |
| 3197 Label too_big_for_new_space; | |
| 3198 __ bind(&allocate); | |
| 3199 __ cmp(ecx, Immediate(kMaxRegularHeapObjectSize)); | |
| 3200 __ j(greater, &too_big_for_new_space); | |
| 3201 { | |
| 3202 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 3203 __ SmiTag(ecx); | |
| 3204 __ Push(eax); | |
| 3205 __ Push(ebx); | |
| 3206 __ Push(ecx); | |
| 3207 __ CallRuntime(Runtime::kAllocateInNewSpace); | |
| 3208 __ mov(edx, eax); | |
| 3209 __ Pop(ebx); | |
| 3210 __ Pop(eax); | |
| 3211 } | |
| 3212 __ jmp(&done_allocate); | |
| 3213 | |
| 3214 // Fall back to %NewRestParameter. | |
| 3215 __ bind(&too_big_for_new_space); | |
| 3216 __ PopReturnAddressTo(ecx); | |
| 3217 // We reload the function from the caller frame due to register pressure | |
| 3218 // within this stub. This is the slow path, hence reloading is preferable. | |
| 3219 if (skip_stub_frame()) { | |
| 3220 // For Ignition we need to skip the handler/stub frame to reach the | |
| 3221 // JavaScript frame for the function. | |
| 3222 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | |
| 3223 __ Push(Operand(edx, StandardFrameConstants::kFunctionOffset)); | |
| 3224 } else { | |
| 3225 __ Push(Operand(ebp, StandardFrameConstants::kFunctionOffset)); | |
| 3226 } | |
| 3227 __ PushReturnAddressFrom(ecx); | |
| 3228 __ TailCallRuntime(Runtime::kNewRestParameter); | |
| 3229 } | |
| 3230 } | |
| 3231 | |
| 3232 | |
| 3233 void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) { | |
| 3234 // ----------- S t a t e ------------- | |
| 3235 // -- edi : function | |
| 3236 // -- esi : context | |
| 3237 // -- ebp : frame pointer | |
| 3238 // -- esp[0] : return address | |
| 3239 // ----------------------------------- | |
| 3240 __ AssertFunction(edi); | |
| 3241 | |
| 3242 // Make ecx point to the JavaScript frame. | |
| 3243 __ mov(ecx, ebp); | |
| 3244 if (skip_stub_frame()) { | |
| 3245 // For Ignition we need to skip the handler/stub frame to reach the | |
| 3246 // JavaScript frame for the function. | |
| 3247 __ mov(ecx, Operand(ecx, StandardFrameConstants::kCallerFPOffset)); | |
| 3248 } | |
| 3249 if (FLAG_debug_code) { | |
| 3250 Label ok; | |
| 3251 __ cmp(edi, Operand(ecx, StandardFrameConstants::kFunctionOffset)); | |
| 3252 __ j(equal, &ok); | |
| 3253 __ Abort(kInvalidFrameForFastNewSloppyArgumentsStub); | |
| 3254 __ bind(&ok); | |
| 3255 } | |
| 3256 | |
| 3257 // TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub. | |
| 3258 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
| 3259 __ mov(ebx, | |
| 3260 FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset)); | |
| 3261 __ lea(edx, Operand(ecx, ebx, times_half_pointer_size, | |
| 3262 StandardFrameConstants::kCallerSPOffset)); | |
| 3263 | |
| 3264 // ebx : number of parameters (tagged) | |
| 3265 // edx : parameters pointer | |
| 3266 // edi : function | |
| 3267 // ecx : JavaScript frame pointer. | |
| 3268 // esp[0] : return address | |
| 3269 | |
| 3270 // Check if the calling frame is an arguments adaptor frame. | |
| 3271 Label adaptor_frame, try_allocate, runtime; | |
| 3272 __ mov(eax, Operand(ecx, StandardFrameConstants::kCallerFPOffset)); | |
| 3273 __ mov(eax, Operand(eax, CommonFrameConstants::kContextOrFrameTypeOffset)); | |
| 3274 __ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | |
| 3275 __ j(equal, &adaptor_frame, Label::kNear); | |
| 3276 | |
| 3277 // No adaptor, parameter count = argument count. | |
| 3278 __ mov(ecx, ebx); | |
| 3279 __ push(ebx); | |
| 3280 __ jmp(&try_allocate, Label::kNear); | |
| 3281 | |
| 3282 // We have an adaptor frame. Patch the parameters pointer. | |
| 3283 __ bind(&adaptor_frame); | |
| 3284 __ push(ebx); | |
| 3285 __ mov(edx, Operand(ecx, StandardFrameConstants::kCallerFPOffset)); | |
| 3286 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | |
| 3287 __ lea(edx, Operand(edx, ecx, times_2, | |
| 3288 StandardFrameConstants::kCallerSPOffset)); | |
| 3289 | |
| 3290 // ebx = parameter count (tagged) | |
| 3291 // ecx = argument count (smi-tagged) | |
| 3292 // Compute the mapped parameter count = min(ebx, ecx) in ebx. | |
| 3293 __ cmp(ebx, ecx); | |
| 3294 __ j(less_equal, &try_allocate, Label::kNear); | |
| 3295 __ mov(ebx, ecx); | |
| 3296 | |
| 3297 // Save mapped parameter count and function. | |
| 3298 __ bind(&try_allocate); | |
| 3299 __ push(edi); | |
| 3300 __ push(ebx); | |
| 3301 | |
| 3302 // Compute the sizes of backing store, parameter map, and arguments object. | |
| 3303 // 1. Parameter map, has 2 extra words containing context and backing store. | |
| 3304 const int kParameterMapHeaderSize = | |
| 3305 FixedArray::kHeaderSize + 2 * kPointerSize; | |
| 3306 Label no_parameter_map; | |
| 3307 __ test(ebx, ebx); | |
| 3308 __ j(zero, &no_parameter_map, Label::kNear); | |
| 3309 __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); | |
| 3310 __ bind(&no_parameter_map); | |
| 3311 | |
| 3312 // 2. Backing store. | |
| 3313 __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); | |
| 3314 | |
| 3315 // 3. Arguments object. | |
| 3316 __ add(ebx, Immediate(JSSloppyArgumentsObject::kSize)); | |
| 3317 | |
| 3318 // Do the allocation of all three objects in one go. | |
| 3319 __ Allocate(ebx, eax, edi, no_reg, &runtime, NO_ALLOCATION_FLAGS); | |
| 3320 | |
| 3321 // eax = address of new object(s) (tagged) | |
| 3322 // ecx = argument count (smi-tagged) | |
| 3323 // esp[0] = mapped parameter count (tagged) | |
| 3324 // esp[4] = function | |
| 3325 // esp[8] = parameter count (tagged) | |
| 3326 // Get the arguments map from the current native context into edi. | |
| 3327 Label has_mapped_parameters, instantiate; | |
| 3328 __ mov(edi, NativeContextOperand()); | |
| 3329 __ mov(ebx, Operand(esp, 0 * kPointerSize)); | |
| 3330 __ test(ebx, ebx); | |
| 3331 __ j(not_zero, &has_mapped_parameters, Label::kNear); | |
| 3332 __ mov( | |
| 3333 edi, | |
| 3334 Operand(edi, Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX))); | |
| 3335 __ jmp(&instantiate, Label::kNear); | |
| 3336 | |
| 3337 __ bind(&has_mapped_parameters); | |
| 3338 __ mov(edi, Operand(edi, Context::SlotOffset( | |
| 3339 Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX))); | |
| 3340 __ bind(&instantiate); | |
| 3341 | |
| 3342 // eax = address of new object (tagged) | |
| 3343 // ebx = mapped parameter count (tagged) | |
| 3344 // ecx = argument count (smi-tagged) | |
| 3345 // edi = address of arguments map (tagged) | |
| 3346 // esp[0] = mapped parameter count (tagged) | |
| 3347 // esp[4] = function | |
| 3348 // esp[8] = parameter count (tagged) | |
| 3349 // Copy the JS object part. | |
| 3350 __ mov(FieldOperand(eax, JSObject::kMapOffset), edi); | |
| 3351 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), | |
| 3352 masm->isolate()->factory()->empty_fixed_array()); | |
| 3353 __ mov(FieldOperand(eax, JSObject::kElementsOffset), | |
| 3354 masm->isolate()->factory()->empty_fixed_array()); | |
| 3355 | |
| 3356 // Set up the callee in-object property. | |
| 3357 STATIC_ASSERT(JSSloppyArgumentsObject::kCalleeIndex == 1); | |
| 3358 __ mov(edi, Operand(esp, 1 * kPointerSize)); | |
| 3359 __ AssertNotSmi(edi); | |
| 3360 __ mov(FieldOperand(eax, JSSloppyArgumentsObject::kCalleeOffset), edi); | |
| 3361 | |
| 3362 // Use the length (smi tagged) and set that as an in-object property too. | |
| 3363 __ AssertSmi(ecx); | |
| 3364 __ mov(FieldOperand(eax, JSSloppyArgumentsObject::kLengthOffset), ecx); | |
| 3365 | |
| 3366 // Set up the elements pointer in the allocated arguments object. | |
| 3367 // If we allocated a parameter map, edi will point there, otherwise to the | |
| 3368 // backing store. | |
| 3369 __ lea(edi, Operand(eax, JSSloppyArgumentsObject::kSize)); | |
| 3370 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); | |
| 3371 | |
| 3372 // eax = address of new object (tagged) | |
| 3373 // ebx = mapped parameter count (tagged) | |
| 3374 // ecx = argument count (tagged) | |
| 3375 // edx = address of receiver argument | |
| 3376 // edi = address of parameter map or backing store (tagged) | |
| 3377 // esp[0] = mapped parameter count (tagged) | |
| 3378 // esp[4] = function | |
| 3379 // esp[8] = parameter count (tagged) | |
| 3380 // Free two registers. | |
| 3381 __ push(edx); | |
| 3382 __ push(eax); | |
| 3383 | |
| 3384 // Initialize parameter map. If there are no mapped arguments, we're done. | |
| 3385 Label skip_parameter_map; | |
| 3386 __ test(ebx, ebx); | |
| 3387 __ j(zero, &skip_parameter_map); | |
| 3388 | |
| 3389 __ mov(FieldOperand(edi, FixedArray::kMapOffset), | |
| 3390 Immediate(isolate()->factory()->sloppy_arguments_elements_map())); | |
| 3391 __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); | |
| 3392 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); | |
| 3393 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); | |
| 3394 __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); | |
| 3395 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); | |
| 3396 | |
| 3397 // Copy the parameter slots and the holes in the arguments. | |
| 3398 // We need to fill in mapped_parameter_count slots. They index the context, | |
| 3399 // where parameters are stored in reverse order, at | |
| 3400 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 | |
| 3401 // The mapped parameter thus need to get indices | |
| 3402 // MIN_CONTEXT_SLOTS+parameter_count-1 .. | |
| 3403 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count | |
| 3404 // We loop from right to left. | |
| 3405 Label parameters_loop, parameters_test; | |
| 3406 __ push(ecx); | |
| 3407 __ mov(eax, Operand(esp, 3 * kPointerSize)); | |
| 3408 __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); | |
| 3409 __ add(ebx, Operand(esp, 5 * kPointerSize)); | |
| 3410 __ sub(ebx, eax); | |
| 3411 __ mov(ecx, isolate()->factory()->the_hole_value()); | |
| 3412 __ mov(edx, edi); | |
| 3413 __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); | |
| 3414 // eax = loop variable (tagged) | |
| 3415 // ebx = mapping index (tagged) | |
| 3416 // ecx = the hole value | |
| 3417 // edx = address of parameter map (tagged) | |
| 3418 // edi = address of backing store (tagged) | |
| 3419 // esp[0] = argument count (tagged) | |
| 3420 // esp[4] = address of new object (tagged) | |
| 3421 // esp[8] = address of receiver argument | |
| 3422 // esp[12] = mapped parameter count (tagged) | |
| 3423 // esp[16] = function | |
| 3424 // esp[20] = parameter count (tagged) | |
| 3425 __ jmp(¶meters_test, Label::kNear); | |
| 3426 | |
| 3427 __ bind(¶meters_loop); | |
| 3428 __ sub(eax, Immediate(Smi::FromInt(1))); | |
| 3429 __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); | |
| 3430 __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); | |
| 3431 __ add(ebx, Immediate(Smi::FromInt(1))); | |
| 3432 __ bind(¶meters_test); | |
| 3433 __ test(eax, eax); | |
| 3434 __ j(not_zero, ¶meters_loop, Label::kNear); | |
| 3435 __ pop(ecx); | |
| 3436 | |
| 3437 __ bind(&skip_parameter_map); | |
| 3438 | |
| 3439 // ecx = argument count (tagged) | |
| 3440 // edi = address of backing store (tagged) | |
| 3441 // esp[0] = address of new object (tagged) | |
| 3442 // esp[4] = address of receiver argument | |
| 3443 // esp[8] = mapped parameter count (tagged) | |
| 3444 // esp[12] = function | |
| 3445 // esp[16] = parameter count (tagged) | |
| 3446 // Copy arguments header and remaining slots (if there are any). | |
| 3447 __ mov(FieldOperand(edi, FixedArray::kMapOffset), | |
| 3448 Immediate(isolate()->factory()->fixed_array_map())); | |
| 3449 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); | |
| 3450 | |
| 3451 Label arguments_loop, arguments_test; | |
| 3452 __ mov(ebx, Operand(esp, 2 * kPointerSize)); | |
| 3453 __ mov(edx, Operand(esp, 1 * kPointerSize)); | |
| 3454 __ sub(edx, ebx); // Is there a smarter way to do negative scaling? | |
| 3455 __ sub(edx, ebx); | |
| 3456 __ jmp(&arguments_test, Label::kNear); | |
| 3457 | |
| 3458 __ bind(&arguments_loop); | |
| 3459 __ sub(edx, Immediate(kPointerSize)); | |
| 3460 __ mov(eax, Operand(edx, 0)); | |
| 3461 __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); | |
| 3462 __ add(ebx, Immediate(Smi::FromInt(1))); | |
| 3463 | |
| 3464 __ bind(&arguments_test); | |
| 3465 __ cmp(ebx, ecx); | |
| 3466 __ j(less, &arguments_loop, Label::kNear); | |
| 3467 | |
| 3468 // Restore. | |
| 3469 __ pop(eax); // Address of arguments object. | |
| 3470 __ Drop(4); | |
| 3471 | |
| 3472 // Return. | |
| 3473 __ ret(0); | |
| 3474 | |
| 3475 // Do the runtime call to allocate the arguments object. | |
| 3476 __ bind(&runtime); | |
| 3477 __ pop(eax); // Remove saved mapped parameter count. | |
| 3478 __ pop(edi); // Pop saved function. | |
| 3479 __ pop(eax); // Remove saved parameter count. | |
| 3480 __ pop(eax); // Pop return address. | |
| 3481 __ push(edi); // Push function. | |
| 3482 __ push(edx); // Push parameters pointer. | |
| 3483 __ push(ecx); // Push parameter count. | |
| 3484 __ push(eax); // Push return address. | |
| 3485 __ TailCallRuntime(Runtime::kNewSloppyArguments); | |
| 3486 } | |
| 3487 | |
| 3488 void FastNewStrictArgumentsStub::Generate(MacroAssembler* masm) { | |
| 3489 // ----------- S t a t e ------------- | |
| 3490 // -- edi : function | |
| 3491 // -- esi : context | |
| 3492 // -- ebp : frame pointer | |
| 3493 // -- esp[0] : return address | |
| 3494 // ----------------------------------- | |
| 3495 __ AssertFunction(edi); | |
| 3496 | |
| 3497 // Make edx point to the JavaScript frame. | |
| 3498 __ mov(edx, ebp); | |
| 3499 if (skip_stub_frame()) { | |
| 3500 // For Ignition we need to skip the handler/stub frame to reach the | |
| 3501 // JavaScript frame for the function. | |
| 3502 __ mov(edx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); | |
| 3503 } | |
| 3504 if (FLAG_debug_code) { | |
| 3505 Label ok; | |
| 3506 __ cmp(edi, Operand(edx, StandardFrameConstants::kFunctionOffset)); | |
| 3507 __ j(equal, &ok); | |
| 3508 __ Abort(kInvalidFrameForFastNewStrictArgumentsStub); | |
| 3509 __ bind(&ok); | |
| 3510 } | |
| 3511 | |
| 3512 // Check if we have an arguments adaptor frame below the function frame. | |
| 3513 Label arguments_adaptor, arguments_done; | |
| 3514 __ mov(ebx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); | |
| 3515 __ cmp(Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset), | |
| 3516 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | |
| 3517 __ j(equal, &arguments_adaptor, Label::kNear); | |
| 3518 { | |
| 3519 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
| 3520 __ mov(eax, | |
| 3521 FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset)); | |
| 3522 __ lea(ebx, | |
| 3523 Operand(edx, eax, times_half_pointer_size, | |
| 3524 StandardFrameConstants::kCallerSPOffset - 1 * kPointerSize)); | |
| 3525 } | |
| 3526 __ jmp(&arguments_done, Label::kNear); | |
| 3527 __ bind(&arguments_adaptor); | |
| 3528 { | |
| 3529 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | |
| 3530 __ lea(ebx, | |
| 3531 Operand(ebx, eax, times_half_pointer_size, | |
| 3532 StandardFrameConstants::kCallerSPOffset - 1 * kPointerSize)); | |
| 3533 } | |
| 3534 __ bind(&arguments_done); | |
| 3535 | |
| 3536 // ----------- S t a t e ------------- | |
| 3537 // -- eax : number of arguments (tagged) | |
| 3538 // -- ebx : pointer to the first argument | |
| 3539 // -- esi : context | |
| 3540 // -- esp[0] : return address | |
| 3541 // ----------------------------------- | |
| 3542 | |
| 3543 // Allocate space for the strict arguments object plus the backing store. | |
| 3544 Label allocate, done_allocate; | |
| 3545 __ lea(ecx, | |
| 3546 Operand(eax, times_half_pointer_size, | |
| 3547 JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize)); | |
| 3548 __ Allocate(ecx, edx, edi, no_reg, &allocate, NO_ALLOCATION_FLAGS); | |
| 3549 __ bind(&done_allocate); | |
| 3550 | |
| 3551 // Setup the elements array in edx. | |
| 3552 __ mov(FieldOperand(edx, FixedArray::kMapOffset), | |
| 3553 isolate()->factory()->fixed_array_map()); | |
| 3554 __ mov(FieldOperand(edx, FixedArray::kLengthOffset), eax); | |
| 3555 { | |
| 3556 Label loop, done_loop; | |
| 3557 __ Move(ecx, Smi::kZero); | |
| 3558 __ bind(&loop); | |
| 3559 __ cmp(ecx, eax); | |
| 3560 __ j(equal, &done_loop, Label::kNear); | |
| 3561 __ mov(edi, Operand(ebx, 0 * kPointerSize)); | |
| 3562 __ mov(FieldOperand(edx, ecx, times_half_pointer_size, | |
| 3563 FixedArray::kHeaderSize), | |
| 3564 edi); | |
| 3565 __ sub(ebx, Immediate(1 * kPointerSize)); | |
| 3566 __ add(ecx, Immediate(Smi::FromInt(1))); | |
| 3567 __ jmp(&loop); | |
| 3568 __ bind(&done_loop); | |
| 3569 } | |
| 3570 | |
| 3571 // Setup the rest parameter array in edi. | |
| 3572 __ lea(edi, | |
| 3573 Operand(edx, eax, times_half_pointer_size, FixedArray::kHeaderSize)); | |
| 3574 __ LoadGlobalFunction(Context::STRICT_ARGUMENTS_MAP_INDEX, ecx); | |
| 3575 __ mov(FieldOperand(edi, JSStrictArgumentsObject::kMapOffset), ecx); | |
| 3576 __ mov(FieldOperand(edi, JSStrictArgumentsObject::kPropertiesOffset), | |
| 3577 isolate()->factory()->empty_fixed_array()); | |
| 3578 __ mov(FieldOperand(edi, JSStrictArgumentsObject::kElementsOffset), edx); | |
| 3579 __ mov(FieldOperand(edi, JSStrictArgumentsObject::kLengthOffset), eax); | |
| 3580 STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); | |
| 3581 __ mov(eax, edi); | |
| 3582 __ Ret(); | |
| 3583 | |
| 3584 // Fall back to %AllocateInNewSpace (if not too big). | |
| 3585 Label too_big_for_new_space; | |
| 3586 __ bind(&allocate); | |
| 3587 __ cmp(ecx, Immediate(kMaxRegularHeapObjectSize)); | |
| 3588 __ j(greater, &too_big_for_new_space); | |
| 3589 { | |
| 3590 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 3591 __ SmiTag(ecx); | |
| 3592 __ Push(eax); | |
| 3593 __ Push(ebx); | |
| 3594 __ Push(ecx); | |
| 3595 __ CallRuntime(Runtime::kAllocateInNewSpace); | |
| 3596 __ mov(edx, eax); | |
| 3597 __ Pop(ebx); | |
| 3598 __ Pop(eax); | |
| 3599 } | |
| 3600 __ jmp(&done_allocate); | |
| 3601 | |
| 3602 // Fall back to %NewStrictArguments. | |
| 3603 __ bind(&too_big_for_new_space); | |
| 3604 __ PopReturnAddressTo(ecx); | |
| 3605 // We reload the function from the caller frame due to register pressure | |
| 3606 // within this stub. This is the slow path, hence reloading is preferable. | |
| 3607 if (skip_stub_frame()) { | |
| 3608 // For Ignition we need to skip the handler/stub frame to reach the | |
| 3609 // JavaScript frame for the function. | |
| 3610 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | |
| 3611 __ Push(Operand(edx, StandardFrameConstants::kFunctionOffset)); | |
| 3612 } else { | |
| 3613 __ Push(Operand(ebp, StandardFrameConstants::kFunctionOffset)); | |
| 3614 } | |
| 3615 __ PushReturnAddressFrom(ecx); | |
| 3616 __ TailCallRuntime(Runtime::kNewStrictArguments); | |
| 3617 } | |
| 3618 | |
| 3619 | |
| 3620 // Generates an Operand for saving parameters after PrepareCallApiFunction. | 3068 // Generates an Operand for saving parameters after PrepareCallApiFunction. |
| 3621 static Operand ApiParameterOperand(int index) { | 3069 static Operand ApiParameterOperand(int index) { |
| 3622 return Operand(esp, index * kPointerSize); | 3070 return Operand(esp, index * kPointerSize); |
| 3623 } | 3071 } |
| 3624 | 3072 |
| 3625 | 3073 |
| 3626 // Prepares stack to put arguments (aligns and so on). Reserves | 3074 // Prepares stack to put arguments (aligns and so on). Reserves |
| 3627 // space for return value if needed (assumes the return value is a handle). | 3075 // space for return value if needed (assumes the return value is a handle). |
| 3628 // Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1) | 3076 // Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1) |
| 3629 // etc. Saves context (esi). If space was reserved for return value then | 3077 // etc. Saves context (esi). If space was reserved for return value then |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3994 kStackUnwindSpace, nullptr, return_value_operand, | 3442 kStackUnwindSpace, nullptr, return_value_operand, |
| 3995 NULL); | 3443 NULL); |
| 3996 } | 3444 } |
| 3997 | 3445 |
| 3998 #undef __ | 3446 #undef __ |
| 3999 | 3447 |
| 4000 } // namespace internal | 3448 } // namespace internal |
| 4001 } // namespace v8 | 3449 } // namespace v8 |
| 4002 | 3450 |
| 4003 #endif // V8_TARGET_ARCH_IA32 | 3451 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |