OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3020 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3031 __ bind(&miss_force_generic); | 3031 __ bind(&miss_force_generic); |
3032 // ----------- S t a t e ------------- | 3032 // ----------- S t a t e ------------- |
3033 // -- rax : key | 3033 // -- rax : key |
3034 // -- rdx : receiver | 3034 // -- rdx : receiver |
3035 // -- rsp[0] : return address | 3035 // -- rsp[0] : return address |
3036 // ----------------------------------- | 3036 // ----------------------------------- |
3037 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric); | 3037 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric); |
3038 } | 3038 } |
3039 | 3039 |
3040 | 3040 |
3041 static void GenerateSmiKeyCheck(MacroAssembler* masm, | |
3042 Register key, | |
3043 Register scratch, | |
3044 XMMRegister xmm_scratch0, | |
3045 XMMRegister xmm_scratch1, | |
3046 Label* fail) { | |
3047 // Check that key is a smi or a heap number containing a smi and branch | |
3048 // if the check fails. | |
3049 Label key_ok; | |
3050 __ JumpIfSmi(key, &key_ok); | |
3051 __ CheckMap(key, | |
3052 masm->isolate()->factory()->heap_number_map(), | |
3053 fail, | |
3054 DONT_DO_SMI_CHECK); | |
3055 __ movsd(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset)); | |
3056 __ cvttsd2si(scratch, xmm_scratch0); | |
3057 __ cvtlsi2sd(xmm_scratch1, scratch); | |
3058 __ ucomisd(xmm_scratch1, xmm_scratch0); | |
3059 __ j(not_equal, fail); | |
3060 __ j(parity_even, fail); // NaN. | |
3061 __ Integer32ToSmi(key, scratch); | |
3062 __ bind(&key_ok); | |
3063 } | |
3064 | |
3065 | |
3066 void KeyedStoreStubCompiler::GenerateStoreExternalArray( | |
3067 MacroAssembler* masm, | |
3068 ElementsKind elements_kind) { | |
3069 // ----------- S t a t e ------------- | |
3070 // -- rax : value | |
3071 // -- rcx : key | |
3072 // -- rdx : receiver | |
3073 // -- rsp[0] : return address | |
3074 // ----------------------------------- | |
3075 Label slow, miss_force_generic; | |
3076 | |
3077 // This stub is meant to be tail-jumped to, the receiver must already | |
3078 // have been verified by the caller to not be a smi. | |
3079 | |
3080 // Check that the key is a smi or a heap number convertible to a smi. | |
3081 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic); | |
3082 | |
3083 // Check that the index is in range. | |
3084 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | |
3085 __ SmiToInteger32(rdi, rcx); // Untag the index. | |
3086 __ cmpq(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset)); | |
3087 // Unsigned comparison catches both negative and too-large values. | |
3088 __ j(above_equal, &miss_force_generic); | |
3089 | |
3090 // Handle both smis and HeapNumbers in the fast path. Go to the | |
3091 // runtime for all other kinds of values. | |
3092 // rax: value | |
3093 // rcx: key (a smi) | |
3094 // rdx: receiver (a JSObject) | |
3095 // rbx: elements array | |
3096 // rdi: untagged key | |
3097 Label check_heap_number; | |
3098 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) { | |
3099 // Float to pixel conversion is only implemented in the runtime for now. | |
3100 __ JumpIfNotSmi(rax, &slow); | |
3101 } else { | |
3102 __ JumpIfNotSmi(rax, &check_heap_number, Label::kNear); | |
3103 } | |
3104 // No more branches to slow case on this path. Key and receiver not needed. | |
3105 __ SmiToInteger32(rdx, rax); | |
3106 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); | |
3107 // rbx: base pointer of external storage | |
3108 switch (elements_kind) { | |
3109 case EXTERNAL_PIXEL_ELEMENTS: | |
3110 { // Clamp the value to [0..255]. | |
3111 Label done; | |
3112 __ testl(rdx, Immediate(0xFFFFFF00)); | |
3113 __ j(zero, &done, Label::kNear); | |
3114 __ setcc(negative, rdx); // 1 if negative, 0 if positive. | |
3115 __ decb(rdx); // 0 if negative, 255 if positive. | |
3116 __ bind(&done); | |
3117 } | |
3118 __ movb(Operand(rbx, rdi, times_1, 0), rdx); | |
3119 break; | |
3120 case EXTERNAL_BYTE_ELEMENTS: | |
3121 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
3122 __ movb(Operand(rbx, rdi, times_1, 0), rdx); | |
3123 break; | |
3124 case EXTERNAL_SHORT_ELEMENTS: | |
3125 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
3126 __ movw(Operand(rbx, rdi, times_2, 0), rdx); | |
3127 break; | |
3128 case EXTERNAL_INT_ELEMENTS: | |
3129 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
3130 __ movl(Operand(rbx, rdi, times_4, 0), rdx); | |
3131 break; | |
3132 case EXTERNAL_FLOAT_ELEMENTS: | |
3133 // Need to perform int-to-float conversion. | |
3134 __ cvtlsi2ss(xmm0, rdx); | |
3135 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); | |
3136 break; | |
3137 case EXTERNAL_DOUBLE_ELEMENTS: | |
3138 // Need to perform int-to-float conversion. | |
3139 __ cvtlsi2sd(xmm0, rdx); | |
3140 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0); | |
3141 break; | |
3142 case FAST_ELEMENTS: | |
3143 case FAST_SMI_ELEMENTS: | |
3144 case FAST_DOUBLE_ELEMENTS: | |
3145 case FAST_HOLEY_ELEMENTS: | |
3146 case FAST_HOLEY_SMI_ELEMENTS: | |
3147 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
3148 case DICTIONARY_ELEMENTS: | |
3149 case NON_STRICT_ARGUMENTS_ELEMENTS: | |
3150 UNREACHABLE(); | |
3151 break; | |
3152 } | |
3153 __ ret(0); | |
3154 | |
3155 // TODO(danno): handle heap number -> pixel array conversion | |
3156 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) { | |
3157 __ bind(&check_heap_number); | |
3158 // rax: value | |
3159 // rcx: key (a smi) | |
3160 // rdx: receiver (a JSObject) | |
3161 // rbx: elements array | |
3162 // rdi: untagged key | |
3163 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister); | |
3164 __ j(not_equal, &slow); | |
3165 // No more branches to slow case on this path. | |
3166 | |
3167 // The WebGL specification leaves the behavior of storing NaN and | |
3168 // +/-Infinity into integer arrays basically undefined. For more | |
3169 // reproducible behavior, convert these to zero. | |
3170 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); | |
3171 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); | |
3172 // rdi: untagged index | |
3173 // rbx: base pointer of external storage | |
3174 // top of FPU stack: value | |
3175 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { | |
3176 __ cvtsd2ss(xmm0, xmm0); | |
3177 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); | |
3178 __ ret(0); | |
3179 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { | |
3180 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0); | |
3181 __ ret(0); | |
3182 } else { | |
3183 // Perform float-to-int conversion with truncation (round-to-zero) | |
3184 // behavior. | |
3185 // Fast path: use machine instruction to convert to int64. If that | |
3186 // fails (out-of-range), go into the runtime. | |
3187 __ cvttsd2siq(r8, xmm0); | |
3188 __ Set(kScratchRegister, V8_UINT64_C(0x8000000000000000)); | |
3189 __ cmpq(r8, kScratchRegister); | |
3190 __ j(equal, &slow); | |
3191 | |
3192 // rdx: value (converted to an untagged integer) | |
3193 // rdi: untagged index | |
3194 // rbx: base pointer of external storage | |
3195 switch (elements_kind) { | |
3196 case EXTERNAL_BYTE_ELEMENTS: | |
3197 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
3198 __ movb(Operand(rbx, rdi, times_1, 0), r8); | |
3199 break; | |
3200 case EXTERNAL_SHORT_ELEMENTS: | |
3201 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
3202 __ movw(Operand(rbx, rdi, times_2, 0), r8); | |
3203 break; | |
3204 case EXTERNAL_INT_ELEMENTS: | |
3205 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
3206 __ movl(Operand(rbx, rdi, times_4, 0), r8); | |
3207 break; | |
3208 case EXTERNAL_PIXEL_ELEMENTS: | |
3209 case EXTERNAL_FLOAT_ELEMENTS: | |
3210 case EXTERNAL_DOUBLE_ELEMENTS: | |
3211 case FAST_ELEMENTS: | |
3212 case FAST_SMI_ELEMENTS: | |
3213 case FAST_DOUBLE_ELEMENTS: | |
3214 case FAST_HOLEY_ELEMENTS: | |
3215 case FAST_HOLEY_SMI_ELEMENTS: | |
3216 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
3217 case DICTIONARY_ELEMENTS: | |
3218 case NON_STRICT_ARGUMENTS_ELEMENTS: | |
3219 UNREACHABLE(); | |
3220 break; | |
3221 } | |
3222 __ ret(0); | |
3223 } | |
3224 } | |
3225 | |
3226 // Slow case: call runtime. | |
3227 __ bind(&slow); | |
3228 | |
3229 // ----------- S t a t e ------------- | |
3230 // -- rax : value | |
3231 // -- rcx : key | |
3232 // -- rdx : receiver | |
3233 // -- rsp[0] : return address | |
3234 // ----------------------------------- | |
3235 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | |
3236 | |
3237 // Miss case: call runtime. | |
3238 __ bind(&miss_force_generic); | |
3239 | |
3240 // ----------- S t a t e ------------- | |
3241 // -- rax : value | |
3242 // -- rcx : key | |
3243 // -- rdx : receiver | |
3244 // -- rsp[0] : return address | |
3245 // ----------------------------------- | |
3246 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); | |
3247 } | |
3248 | |
3249 | |
3250 void KeyedStoreStubCompiler::GenerateStoreFastElement( | |
3251 MacroAssembler* masm, | |
3252 bool is_js_array, | |
3253 ElementsKind elements_kind, | |
3254 KeyedAccessStoreMode store_mode) { | |
3255 // ----------- S t a t e ------------- | |
3256 // -- rax : value | |
3257 // -- rcx : key | |
3258 // -- rdx : receiver | |
3259 // -- rsp[0] : return address | |
3260 // ----------------------------------- | |
3261 Label miss_force_generic, transition_elements_kind, finish_store, grow; | |
3262 Label check_capacity, slow; | |
3263 | |
3264 // This stub is meant to be tail-jumped to, the receiver must already | |
3265 // have been verified by the caller to not be a smi. | |
3266 | |
3267 // Check that the key is a smi or a heap number convertible to a smi. | |
3268 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic); | |
3269 | |
3270 if (IsFastSmiElementsKind(elements_kind)) { | |
3271 __ JumpIfNotSmi(rax, &transition_elements_kind); | |
3272 } | |
3273 | |
3274 // Get the elements array and make sure it is a fast element array, not 'cow'. | |
3275 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); | |
3276 // Check that the key is within bounds. | |
3277 if (is_js_array) { | |
3278 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); | |
3279 if (IsGrowStoreMode(store_mode)) { | |
3280 __ j(above_equal, &grow); | |
3281 } else { | |
3282 __ j(above_equal, &miss_force_generic); | |
3283 } | |
3284 } else { | |
3285 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); | |
3286 __ j(above_equal, &miss_force_generic); | |
3287 } | |
3288 | |
3289 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset), | |
3290 Heap::kFixedArrayMapRootIndex); | |
3291 __ j(not_equal, &miss_force_generic); | |
3292 | |
3293 __ bind(&finish_store); | |
3294 if (IsFastSmiElementsKind(elements_kind)) { | |
3295 __ SmiToInteger32(rcx, rcx); | |
3296 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), | |
3297 rax); | |
3298 } else { | |
3299 // Do the store and update the write barrier. | |
3300 ASSERT(IsFastObjectElementsKind(elements_kind)); | |
3301 __ SmiToInteger32(rcx, rcx); | |
3302 __ lea(rcx, | |
3303 FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize)); | |
3304 __ movq(Operand(rcx, 0), rax); | |
3305 // Make sure to preserve the value in register rax. | |
3306 __ movq(rbx, rax); | |
3307 __ RecordWrite(rdi, rcx, rbx, kDontSaveFPRegs); | |
3308 } | |
3309 | |
3310 // Done. | |
3311 __ ret(0); | |
3312 | |
3313 // Handle store cache miss. | |
3314 __ bind(&miss_force_generic); | |
3315 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); | |
3316 | |
3317 __ bind(&transition_elements_kind); | |
3318 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); | |
3319 | |
3320 if (is_js_array && IsGrowStoreMode(store_mode)) { | |
3321 // Grow the array by a single element if possible. | |
3322 __ bind(&grow); | |
3323 | |
3324 // Make sure the array is only growing by a single element, anything else | |
3325 // must be handled by the runtime. Flags are already set by previous | |
3326 // compare. | |
3327 __ j(not_equal, &miss_force_generic); | |
3328 | |
3329 // Check for the empty array, and preallocate a small backing store if | |
3330 // possible. | |
3331 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); | |
3332 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex); | |
3333 __ j(not_equal, &check_capacity); | |
3334 | |
3335 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); | |
3336 __ Allocate(size, rdi, rbx, r8, &slow, TAG_OBJECT); | |
3337 | |
3338 // rax: value | |
3339 // rcx: key | |
3340 // rdx: receiver | |
3341 // rdi: elements | |
3342 // Make sure that the backing store can hold additional elements. | |
3343 __ Move(FieldOperand(rdi, JSObject::kMapOffset), | |
3344 masm->isolate()->factory()->fixed_array_map()); | |
3345 __ Move(FieldOperand(rdi, FixedArray::kLengthOffset), | |
3346 Smi::FromInt(JSArray::kPreallocatedArrayElements)); | |
3347 __ LoadRoot(rbx, Heap::kTheHoleValueRootIndex); | |
3348 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) { | |
3349 __ movq(FieldOperand(rdi, FixedArray::SizeFor(i)), rbx); | |
3350 } | |
3351 | |
3352 // Store the element at index zero. | |
3353 __ movq(FieldOperand(rdi, FixedArray::SizeFor(0)), rax); | |
3354 | |
3355 // Install the new backing store in the JSArray. | |
3356 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi); | |
3357 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx, | |
3358 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | |
3359 | |
3360 // Increment the length of the array. | |
3361 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1)); | |
3362 __ ret(0); | |
3363 | |
3364 __ bind(&check_capacity); | |
3365 // Check for cow elements, in general they are not handled by this stub. | |
3366 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset), | |
3367 Heap::kFixedCOWArrayMapRootIndex); | |
3368 __ j(equal, &miss_force_generic); | |
3369 | |
3370 // rax: value | |
3371 // rcx: key | |
3372 // rdx: receiver | |
3373 // rdi: elements | |
3374 // Make sure that the backing store can hold additional elements. | |
3375 __ cmpq(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); | |
3376 __ j(above_equal, &slow); | |
3377 | |
3378 // Grow the array and finish the store. | |
3379 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset), | |
3380 Smi::FromInt(1)); | |
3381 __ jmp(&finish_store); | |
3382 | |
3383 __ bind(&slow); | |
3384 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | |
3385 } | |
3386 } | |
3387 | |
3388 | |
3389 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( | |
3390 MacroAssembler* masm, | |
3391 bool is_js_array, | |
3392 KeyedAccessStoreMode store_mode) { | |
3393 // ----------- S t a t e ------------- | |
3394 // -- rax : value | |
3395 // -- rcx : key | |
3396 // -- rdx : receiver | |
3397 // -- rsp[0] : return address | |
3398 // ----------------------------------- | |
3399 Label miss_force_generic, transition_elements_kind, finish_store; | |
3400 Label grow, slow, check_capacity, restore_key_transition_elements_kind; | |
3401 | |
3402 // This stub is meant to be tail-jumped to, the receiver must already | |
3403 // have been verified by the caller to not be a smi. | |
3404 | |
3405 // Check that the key is a smi or a heap number convertible to a smi. | |
3406 GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic); | |
3407 | |
3408 // Get the elements array. | |
3409 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); | |
3410 __ AssertFastElements(rdi); | |
3411 | |
3412 // Check that the key is within bounds. | |
3413 if (is_js_array) { | |
3414 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); | |
3415 if (IsGrowStoreMode(store_mode)) { | |
3416 __ j(above_equal, &grow); | |
3417 } else { | |
3418 __ j(above_equal, &miss_force_generic); | |
3419 } | |
3420 } else { | |
3421 __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset)); | |
3422 __ j(above_equal, &miss_force_generic); | |
3423 } | |
3424 | |
3425 // Handle smi values specially | |
3426 __ bind(&finish_store); | |
3427 __ SmiToInteger32(rcx, rcx); | |
3428 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, | |
3429 &restore_key_transition_elements_kind); | |
3430 __ ret(0); | |
3431 | |
3432 // Handle store cache miss, replacing the ic with the generic stub. | |
3433 __ bind(&miss_force_generic); | |
3434 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); | |
3435 | |
3436 __ bind(&restore_key_transition_elements_kind); | |
3437 // Restore smi-tagging of rcx. | |
3438 __ Integer32ToSmi(rcx, rcx); | |
3439 __ bind(&transition_elements_kind); | |
3440 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); | |
3441 | |
3442 if (is_js_array && IsGrowStoreMode(store_mode)) { | |
3443 // Grow the array by a single element if possible. | |
3444 __ bind(&grow); | |
3445 | |
3446 // Make sure the array is only growing by a single element, anything else | |
3447 // must be handled by the runtime. Flags are already set by previous | |
3448 // compare. | |
3449 __ j(not_equal, &miss_force_generic); | |
3450 | |
3451 // Transition on values that can't be stored in a FixedDoubleArray. | |
3452 Label value_is_smi; | |
3453 __ JumpIfSmi(rax, &value_is_smi); | |
3454 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | |
3455 Heap::kHeapNumberMapRootIndex); | |
3456 __ j(not_equal, &transition_elements_kind); | |
3457 __ bind(&value_is_smi); | |
3458 | |
3459 // Check for the empty array, and preallocate a small backing store if | |
3460 // possible. | |
3461 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); | |
3462 __ CompareRoot(rdi, Heap::kEmptyFixedArrayRootIndex); | |
3463 __ j(not_equal, &check_capacity); | |
3464 | |
3465 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements); | |
3466 __ Allocate(size, rdi, rbx, r8, &slow, TAG_OBJECT); | |
3467 | |
3468 // rax: value | |
3469 // rcx: key | |
3470 // rdx: receiver | |
3471 // rdi: elements | |
3472 // Initialize the new FixedDoubleArray. Leave elements unitialized for | |
3473 // efficiency, they are guaranteed to be initialized before use. | |
3474 __ Move(FieldOperand(rdi, JSObject::kMapOffset), | |
3475 masm->isolate()->factory()->fixed_double_array_map()); | |
3476 __ Move(FieldOperand(rdi, FixedDoubleArray::kLengthOffset), | |
3477 Smi::FromInt(JSArray::kPreallocatedArrayElements)); | |
3478 | |
3479 // Increment the length of the array. | |
3480 __ SmiToInteger32(rcx, rcx); | |
3481 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, | |
3482 &restore_key_transition_elements_kind); | |
3483 | |
3484 __ movq(r8, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE64); | |
3485 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { | |
3486 __ movq(FieldOperand(rdi, FixedDoubleArray::OffsetOfElementAt(i)), r8); | |
3487 } | |
3488 | |
3489 // Install the new backing store in the JSArray. | |
3490 __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi); | |
3491 __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx, | |
3492 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | |
3493 | |
3494 // Increment the length of the array. | |
3495 __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1)); | |
3496 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); | |
3497 __ ret(0); | |
3498 | |
3499 __ bind(&check_capacity); | |
3500 // rax: value | |
3501 // rcx: key | |
3502 // rdx: receiver | |
3503 // rdi: elements | |
3504 // Make sure that the backing store can hold additional elements. | |
3505 __ cmpq(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset)); | |
3506 __ j(above_equal, &slow); | |
3507 | |
3508 // Grow the array and finish the store. | |
3509 __ SmiAddConstant(FieldOperand(rdx, JSArray::kLengthOffset), | |
3510 Smi::FromInt(1)); | |
3511 __ jmp(&finish_store); | |
3512 | |
3513 __ bind(&slow); | |
3514 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | |
3515 } | |
3516 } | |
3517 | |
3518 | |
3519 #undef __ | 3041 #undef __ |
3520 | 3042 |
3521 } } // namespace v8::internal | 3043 } } // namespace v8::internal |
3522 | 3044 |
3523 #endif // V8_TARGET_ARCH_X64 | 3045 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |