| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 | 163 |
| 164 // Jump to the first instruction in the code stub. | 164 // Jump to the first instruction in the code stub. |
| 165 __ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag); | 165 __ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag); |
| 166 __ Br(scratch); | 166 __ Br(scratch); |
| 167 | 167 |
| 168 // Miss: fall through. | 168 // Miss: fall through. |
| 169 __ Bind(&miss); | 169 __ Bind(&miss); |
| 170 } | 170 } |
| 171 | 171 |
| 172 | 172 |
| 173 // Check if key is a smi or can be converted into a smi. | |
| 174 // If not jump on 'fail' and fall-through otherwise. | |
| 175 static void GenerateSmiKeyCheck(MacroAssembler* masm, | |
| 176 Register key, | |
| 177 Register scratch0, | |
| 178 FPRegister double_scratch0, | |
| 179 FPRegister double_scratch1, | |
| 180 Label* fail) { | |
| 181 Label key_ok; | |
| 182 __ JumpIfSmi(key, &key_ok); | |
| 183 | |
| 184 // The key is not a smi. Check for a smi inside a heap number. | |
| 185 __ CheckMap(key, | |
| 186 scratch0, | |
| 187 masm->isolate()->factory()->heap_number_map(), | |
| 188 fail, | |
| 189 DONT_DO_SMI_CHECK); | |
| 190 | |
| 191 __ Ldr(scratch0, FieldMemOperand(key, HeapNumber::kValueOffset)); | |
| 192 __ Fmov(double_scratch0, scratch0); | |
| 193 __ TryConvertDoubleToInt32(scratch0.W(), | |
| 194 double_scratch0, | |
| 195 double_scratch1, | |
| 196 NULL, | |
| 197 fail); | |
| 198 // The double value has been coverted to a 32-bit signed integer. | |
| 199 // We just need to tag it. | |
| 200 __ SmiTag(key, scratch0); | |
| 201 | |
| 202 __ Bind(&key_ok); | |
| 203 } | |
| 204 | |
| 205 | |
| 206 void StubCache::GenerateProbe(MacroAssembler* masm, | 173 void StubCache::GenerateProbe(MacroAssembler* masm, |
| 207 Code::Flags flags, | 174 Code::Flags flags, |
| 208 Register receiver, | 175 Register receiver, |
| 209 Register name, | 176 Register name, |
| 210 Register scratch, | 177 Register scratch, |
| 211 Register extra, | 178 Register extra, |
| 212 Register extra2, | 179 Register extra2, |
| 213 Register extra3) { | 180 Register extra3) { |
| 214 Isolate* isolate = masm->isolate(); | 181 Isolate* isolate = masm->isolate(); |
| 215 Label miss; | 182 Label miss; |
| (...skipping 3064 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3280 __ IncrementCounter( | 3247 __ IncrementCounter( |
| 3281 masm->isolate()->counters()->keyed_load_external_array_slow(), 1, x2, x3); | 3248 masm->isolate()->counters()->keyed_load_external_array_slow(), 1, x2, x3); |
| 3282 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); | 3249 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); |
| 3283 | 3250 |
| 3284 // Miss case, call the runtime. | 3251 // Miss case, call the runtime. |
| 3285 __ Bind(&miss_force_generic); | 3252 __ Bind(&miss_force_generic); |
| 3286 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric); | 3253 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric); |
| 3287 } | 3254 } |
| 3288 | 3255 |
| 3289 | 3256 |
| 3290 static void GenerateStoreSmiToExternalArray( | |
| 3291 MacroAssembler* masm, | |
| 3292 ElementsKind elements_kind, | |
| 3293 Register value, | |
| 3294 Register key_raw, // Untagged 'key'. | |
| 3295 Register elements_ext, // elements[ExternalArray::kExternalPointerOffset] | |
| 3296 Register scratch, | |
| 3297 FPRegister double_scratch) { | |
| 3298 // Convert the smi in value (x0) to the specified element kind, and store it | |
| 3299 // in the external array. No input registers are clobbered by this helper, | |
| 3300 // other than the scratch registers. | |
| 3301 | |
| 3302 ASSERT(!AreAliased(value, key_raw, elements_ext, scratch, double_scratch)); | |
| 3303 | |
| 3304 switch (elements_kind) { | |
| 3305 case EXTERNAL_PIXEL_ELEMENTS: | |
| 3306 __ SmiUntag(scratch, value); | |
| 3307 // Clamp the value to [0..255]. | |
| 3308 __ Cmp(scratch, Operand(scratch, UXTB)); | |
| 3309 // If scratch < scratch & 0xff, it must be < 0, so saturate to 0. | |
| 3310 __ CzeroX(scratch, lt); | |
| 3311 // If scratch > scratch & 0xff, it must be > 255, so saturate to 255. | |
| 3312 // This actually generates ~0, but it doesn't matter if we use strb. | |
| 3313 __ Csinv(scratch, scratch, xzr, le); | |
| 3314 __ Strb(scratch.W(), MemOperand(elements_ext, key_raw)); | |
| 3315 break; | |
| 3316 case EXTERNAL_BYTE_ELEMENTS: | |
| 3317 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 3318 __ SmiUntag(scratch, value); | |
| 3319 __ Strb(scratch.W(), MemOperand(elements_ext, key_raw)); | |
| 3320 break; | |
| 3321 case EXTERNAL_SHORT_ELEMENTS: | |
| 3322 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 3323 __ SmiUntag(scratch, value); | |
| 3324 __ Strh(scratch.W(), | |
| 3325 MemOperand(elements_ext, key_raw, LSL, kHalfWordSizeInBytesLog2)); | |
| 3326 break; | |
| 3327 case EXTERNAL_INT_ELEMENTS: | |
| 3328 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 3329 __ SmiUntag(scratch, value); | |
| 3330 __ Str(scratch.W(), | |
| 3331 MemOperand(elements_ext, key_raw, LSL, kWordSizeInBytesLog2)); | |
| 3332 break; | |
| 3333 case EXTERNAL_FLOAT_ELEMENTS: | |
| 3334 __ SmiUntagToFloat(double_scratch.S(), value); | |
| 3335 __ Str(double_scratch.S(), | |
| 3336 MemOperand(elements_ext, key_raw, LSL, kSRegSizeInBytesLog2)); | |
| 3337 break; | |
| 3338 case EXTERNAL_DOUBLE_ELEMENTS: | |
| 3339 __ SmiUntagToDouble(double_scratch, value); | |
| 3340 __ Str(double_scratch, | |
| 3341 MemOperand(elements_ext, key_raw, LSL, kDRegSizeInBytesLog2)); | |
| 3342 break; | |
| 3343 case FAST_ELEMENTS: | |
| 3344 case FAST_SMI_ELEMENTS: | |
| 3345 case FAST_DOUBLE_ELEMENTS: | |
| 3346 case FAST_HOLEY_ELEMENTS: | |
| 3347 case FAST_HOLEY_SMI_ELEMENTS: | |
| 3348 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
| 3349 case DICTIONARY_ELEMENTS: | |
| 3350 case NON_STRICT_ARGUMENTS_ELEMENTS: | |
| 3351 UNREACHABLE(); | |
| 3352 break; | |
| 3353 } | |
| 3354 } | |
| 3355 | |
| 3356 | |
| 3357 static void GenerateStoreHeapNumberToExternalArray( | |
| 3358 MacroAssembler* masm, | |
| 3359 ElementsKind elements_kind, | |
| 3360 Register value, | |
| 3361 Register key_raw, // Untagged 'key'. | |
| 3362 Register elements_ext, // elements[ExternalArray::kExternalPointerOffset] | |
| 3363 Register scratch, | |
| 3364 FPRegister double_scratch1, | |
| 3365 FPRegister double_scratch2) { | |
| 3366 // Convert the heap number in value (x0) to the specified element kind, and | |
| 3367 // store it in the external array. No input registers are clobbered by this | |
| 3368 // helper, other than the scratch registers. | |
| 3369 | |
| 3370 ASSERT(!AreAliased(value, key_raw, elements_ext, scratch, | |
| 3371 double_scratch1, double_scratch2)); | |
| 3372 | |
| 3373 FPRegister value_d = double_scratch1; | |
| 3374 __ Ldr(value_d, FieldMemOperand(value, HeapNumber::kValueOffset)); | |
| 3375 | |
| 3376 // Convert the (double) input to an integral type. | |
| 3377 switch (elements_kind) { | |
| 3378 case EXTERNAL_FLOAT_ELEMENTS: | |
| 3379 __ Fcvt(s16, value_d); | |
| 3380 __ Str(s16, MemOperand(elements_ext, key_raw, LSL, 2)); | |
| 3381 break; | |
| 3382 case EXTERNAL_DOUBLE_ELEMENTS: | |
| 3383 __ Str(value_d, MemOperand(elements_ext, key_raw, LSL, 3)); | |
| 3384 break; | |
| 3385 case EXTERNAL_PIXEL_ELEMENTS: | |
| 3386 // This conversion follows the WebIDL "[Clamp]" rules: | |
| 3387 // - Inputs lower than 0 (including -infinity) produce 0. | |
| 3388 // - Inputs higher than 255 (including +infinity) produce 255. | |
| 3389 // Also, it seems that PIXEL types use round-to-nearest rather than | |
| 3390 // round-towards-zero. | |
| 3391 | |
| 3392 // Squash +infinity before the conversion, since Fcvtnu will normally | |
| 3393 // convert it to 0. | |
| 3394 __ Fmov(double_scratch2, 255); | |
| 3395 __ Fmin(double_scratch2, double_scratch2, value_d); | |
| 3396 | |
| 3397 // Convert double to unsigned integer. Values less than zero become zero. | |
| 3398 // Values greater than 255 have already been clamped to 255. | |
| 3399 __ Fcvtnu(scratch.W(), double_scratch2); | |
| 3400 | |
| 3401 __ Strb(scratch.W(), MemOperand(elements_ext, key_raw)); | |
| 3402 break; | |
| 3403 case EXTERNAL_BYTE_ELEMENTS: | |
| 3404 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 3405 __ ECMA262ToInt32(scratch, value_d, x11, x12, MacroAssembler::INT32_IN_W); | |
| 3406 __ Strb(scratch.W(), MemOperand(elements_ext, key_raw)); | |
| 3407 break; | |
| 3408 case EXTERNAL_SHORT_ELEMENTS: | |
| 3409 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 3410 __ ECMA262ToInt32(scratch, value_d, x11, x12, MacroAssembler::INT32_IN_W); | |
| 3411 __ Strh(scratch.W(), | |
| 3412 MemOperand(elements_ext, key_raw, LSL, kHalfWordSizeInBytesLog2)); | |
| 3413 break; | |
| 3414 case EXTERNAL_INT_ELEMENTS: | |
| 3415 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 3416 __ ECMA262ToInt32(scratch, value_d, x11, x12, MacroAssembler::INT32_IN_W); | |
| 3417 __ Str(scratch.W(), | |
| 3418 MemOperand(elements_ext, key_raw, LSL, kWordSizeInBytesLog2)); | |
| 3419 break; | |
| 3420 case FAST_ELEMENTS: | |
| 3421 case FAST_SMI_ELEMENTS: | |
| 3422 case FAST_DOUBLE_ELEMENTS: | |
| 3423 case FAST_HOLEY_ELEMENTS: | |
| 3424 case FAST_HOLEY_SMI_ELEMENTS: | |
| 3425 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
| 3426 case DICTIONARY_ELEMENTS: | |
| 3427 case NON_STRICT_ARGUMENTS_ELEMENTS: | |
| 3428 UNREACHABLE(); | |
| 3429 break; | |
| 3430 } | |
| 3431 } | |
| 3432 | |
| 3433 | |
| 3434 void KeyedStoreStubCompiler::GenerateStoreExternalArray( | |
| 3435 MacroAssembler* masm, | |
| 3436 ElementsKind elements_kind) { | |
| 3437 // ---------- S t a t e -------------- | |
| 3438 // -- lr : return address | |
| 3439 // -- x0 : value | |
| 3440 // -- x1 : key | |
| 3441 // -- x2 : receiver | |
| 3442 // ----------------------------------- | |
| 3443 Label slow, check_heap_number, miss_force_generic; | |
| 3444 | |
| 3445 // Register usage. | |
| 3446 Register value = x0; | |
| 3447 Register key = x1; | |
| 3448 Register receiver = x2; | |
| 3449 | |
| 3450 // This stub is meant to be tail-jumped to, the receiver must already | |
| 3451 // have been verified by the caller to not be a smi. | |
| 3452 if (__ emit_debug_code()) { | |
| 3453 __ AssertNotSmi(receiver); | |
| 3454 } | |
| 3455 | |
| 3456 // Check that the key is a smi or a heap number convertible to a smi. | |
| 3457 GenerateSmiKeyCheck(masm, key, x10, d16, d17, &miss_force_generic); | |
| 3458 | |
| 3459 Register elements = x3; | |
| 3460 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 3461 | |
| 3462 Register key_raw = x4; | |
| 3463 __ SmiUntag(key_raw, key); | |
| 3464 | |
| 3465 // Check that the key is within bounds. An unsigned comparison catches both | |
| 3466 // negative and out-of-bound indexes. | |
| 3467 __ Ldrsw(x10, | |
| 3468 UntagSmiFieldMemOperand(elements, ExternalArray::kLengthOffset)); | |
| 3469 __ Cmp(key_raw.W(), w10); | |
| 3470 __ B(&miss_force_generic, hs); | |
| 3471 | |
| 3472 // Get the externally-stored elements. | |
| 3473 Register elements_ext = x5; | |
| 3474 __ Ldr(elements_ext, | |
| 3475 FieldMemOperand(elements, ExternalArray::kExternalPointerOffset)); | |
| 3476 | |
| 3477 // x0: value | |
| 3478 // x1: key | |
| 3479 // x2: receiver | |
| 3480 // x3: elements | |
| 3481 // x4: key_raw Untagged 'key'. | |
| 3482 // x5: elements_ext From elements[ExternalArray::kExternalPointerOffset]. | |
| 3483 | |
| 3484 // Handle both smis and HeapNumbers in the fast path. Go to the | |
| 3485 // runtime for all other kinds of values. | |
| 3486 __ JumpIfNotSmi(value, &check_heap_number); | |
| 3487 | |
| 3488 GenerateStoreSmiToExternalArray( | |
| 3489 masm, elements_kind, value, key_raw, elements_ext, x10, d16); | |
| 3490 // Entry registers are intact and x0 holds 'value', which is the return value. | |
| 3491 __ Ret(); | |
| 3492 | |
| 3493 __ Bind(&check_heap_number); | |
| 3494 // Convert the double at 'value' to the specified element kind. | |
| 3495 // | |
| 3496 // x0: value | |
| 3497 // x1: key | |
| 3498 // x2: receiver | |
| 3499 // x3: elements | |
| 3500 // x4: key_raw Untagged 'key'. | |
| 3501 // x5: elements_ext From elements[ExternalArray::kExternalPointerOffset]. | |
| 3502 __ JumpIfNotObjectType(value, x10, x11, HEAP_NUMBER_TYPE, &slow); | |
| 3503 | |
| 3504 GenerateStoreHeapNumberToExternalArray( | |
| 3505 masm, elements_kind, value, key_raw, elements_ext, x10, d16, d17); | |
| 3506 // Entry registers are intact and x0 holds 'value', which is the return value. | |
| 3507 __ Ret(); | |
| 3508 | |
| 3509 __ Bind(&slow); | |
| 3510 // ---------- S t a t e -------------- | |
| 3511 // -- lr : return address | |
| 3512 // -- x0 : value | |
| 3513 // -- x1 : key | |
| 3514 // -- x2 : receiver | |
| 3515 // ----------------------------------- | |
| 3516 __ IncrementCounter( | |
| 3517 masm->isolate()->counters()->keyed_load_external_array_slow(), | |
| 3518 1, x10, x11); | |
| 3519 | |
| 3520 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | |
| 3521 | |
| 3522 // Miss case, call the runtime. | |
| 3523 __ Bind(&miss_force_generic); | |
| 3524 // ---------- S t a t e -------------- | |
| 3525 // -- lr : return address | |
| 3526 // -- x0 : value | |
| 3527 // -- x1 : key | |
| 3528 // -- x2 : receiver | |
| 3529 // ----------------------------------- | |
| 3530 | |
| 3531 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); | |
| 3532 } | |
| 3533 | |
| 3534 | |
| 3535 static void GenerateStoreFastSmiOrDoubleElement( | |
| 3536 MacroAssembler* masm, | |
| 3537 bool is_js_array, | |
| 3538 ElementsKind elements_kind, | |
| 3539 KeyedAccessStoreMode store_mode, | |
| 3540 bool store_double) { | |
| 3541 Label miss_force_generic, transition_elements_kind, grow, slow; | |
| 3542 Label finish_store, check_capacity; | |
| 3543 | |
| 3544 Register value = x0; | |
| 3545 Register key = x1; | |
| 3546 Register receiver = x2; | |
| 3547 | |
| 3548 // This stub is meant to be tail-jumped to, the receiver must already | |
| 3549 // have been verified by the caller to not be a smi. | |
| 3550 if (__ emit_debug_code()) { | |
| 3551 __ AssertNotSmi(receiver); | |
| 3552 } | |
| 3553 | |
| 3554 // Check that the key is a smi or a heap number convertible to a smi. | |
| 3555 GenerateSmiKeyCheck(masm, key, x10, d16, d17, &miss_force_generic); | |
| 3556 | |
| 3557 if (!store_double && IsFastSmiElementsKind(elements_kind)) { | |
| 3558 __ JumpIfNotSmi(value, &transition_elements_kind); | |
| 3559 } | |
| 3560 | |
| 3561 Register elements = x3; | |
| 3562 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 3563 | |
| 3564 // Check that the key is within bounds. | |
| 3565 Register length = x4; | |
| 3566 if (is_js_array) { | |
| 3567 __ Ldr(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 3568 } else { | |
| 3569 __ Ldr(length, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 3570 } | |
| 3571 // Compare smis. An unsigned comparison catches both negative and out-of-bound | |
| 3572 // indexes. | |
| 3573 __ Cmp(key, length); | |
| 3574 if (is_js_array && IsGrowStoreMode(store_mode)) { | |
| 3575 // We can handle the case where the array needs to grow by a single element | |
| 3576 // without falling back to run-time. | |
| 3577 __ B(&grow, eq); | |
| 3578 } | |
| 3579 // Fall back to the run-time if the key is out of bounds. | |
| 3580 __ B(&miss_force_generic, hs); | |
| 3581 | |
| 3582 if (store_double) { | |
| 3583 __ Bind(&finish_store); | |
| 3584 __ StoreNumberToDoubleElements(value, key, elements, x10, d16, d17, | |
| 3585 &transition_elements_kind); | |
| 3586 } else { | |
| 3587 // Make sure elements is a fast element array, not 'cow'. | |
| 3588 // TODO(jbramley): Why is this only done when storing a smi? | |
| 3589 __ CheckMap(elements, x10, | |
| 3590 Heap::kFixedArrayMapRootIndex, | |
| 3591 &miss_force_generic, | |
| 3592 DONT_DO_SMI_CHECK); | |
| 3593 | |
| 3594 __ Bind(&finish_store); | |
| 3595 | |
| 3596 STATIC_ASSERT(kSmiTag == 0 && kSmiShift > kPointerSizeLog2); | |
| 3597 __ Add(x10, elements, FixedArray::kHeaderSize - kHeapObjectTag); | |
| 3598 __ Add(x10, x10, Operand::UntagSmiAndScale(key, kPointerSizeLog2)); | |
| 3599 __ Str(value, MemOperand(x10)); | |
| 3600 if (!IsFastSmiElementsKind(elements_kind)) { | |
| 3601 ASSERT(IsFastObjectElementsKind(elements_kind)); | |
| 3602 __ Mov(receiver, value); | |
| 3603 __ RecordWrite(elements, // Object. | |
| 3604 x10, // Address. | |
| 3605 receiver, // Value. | |
| 3606 kLRHasNotBeenSaved, | |
| 3607 kDontSaveFPRegs, | |
| 3608 EMIT_REMEMBERED_SET, | |
| 3609 INLINE_SMI_CHECK, | |
| 3610 EXPECT_PREGENERATED); | |
| 3611 } | |
| 3612 // Value (x0) is preserved. | |
| 3613 } | |
| 3614 __ Ret(); | |
| 3615 | |
| 3616 __ Bind(&miss_force_generic); | |
| 3617 KeyedStoreStubCompiler::TailCallBuiltin( | |
| 3618 masm, Builtins::kKeyedStoreIC_MissForceGeneric); | |
| 3619 | |
| 3620 __ Bind(&transition_elements_kind); | |
| 3621 KeyedStoreStubCompiler::TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); | |
| 3622 | |
| 3623 if (is_js_array && IsGrowStoreMode(store_mode)) { | |
| 3624 // Grow a JSArray by a single element. | |
| 3625 __ Bind(&grow); | |
| 3626 | |
| 3627 // x1: key | |
| 3628 // x2: receiver | |
| 3629 // x3: elements From receiver[JSObject::kElementsOffset]. | |
| 3630 // x4: length From receiver[JSArray::kLengthOffset]. | |
| 3631 | |
| 3632 if (__ emit_debug_code()) { | |
| 3633 // Check that 'elements' and 'length' are pre-loaded. | |
| 3634 __ Ldr(x10, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 3635 __ Cmp(x10, x3); | |
| 3636 __ Ldr(x11, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 3637 __ Ccmp(x11, x4, NoFlag, eq); | |
| 3638 | |
| 3639 // Check that the key is equal to length, so we need to extend the array | |
| 3640 // by one element. | |
| 3641 __ Ccmp(x1, x4, NoFlag, eq); | |
| 3642 | |
| 3643 __ Check(eq, kPreconditionsWereNotMet); | |
| 3644 } | |
| 3645 | |
| 3646 __ JumpIfNotRoot(elements, Heap::kEmptyFixedArrayRootIndex, | |
| 3647 &check_capacity); | |
| 3648 | |
| 3649 // The array is currently empty, so allocate a new backing store. | |
| 3650 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); | |
| 3651 __ Allocate(size, elements, x10, x11, &slow, TAG_OBJECT); | |
| 3652 Heap::RootListIndex root_index = store_double | |
| 3653 ? Heap::kFixedDoubleArrayMapRootIndex | |
| 3654 : Heap::kFixedArrayMapRootIndex; | |
| 3655 __ LoadRoot(x12, root_index); | |
| 3656 __ Str(x12, FieldMemOperand(elements, JSObject::kMapOffset)); | |
| 3657 __ Mov(x13, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements))); | |
| 3658 __ Str(x13, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 3659 | |
| 3660 // Store the element at index zero, and fill the rest with the hole value. | |
| 3661 if (store_double) { | |
| 3662 __ StoreNumberToDoubleElements(value, | |
| 3663 key, | |
| 3664 elements, | |
| 3665 x10, | |
| 3666 d16, | |
| 3667 d17, | |
| 3668 &transition_elements_kind); | |
| 3669 __ Fmov(d16, rawbits_to_double(kHoleNanInt64)); | |
| 3670 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { | |
| 3671 __ Str(d16, FieldMemOperand(elements, | |
| 3672 FixedDoubleArray::OffsetOfElementAt(i))); | |
| 3673 } | |
| 3674 } else { | |
| 3675 __ Str(value, FieldMemOperand(elements, FixedArray::SizeFor(0))); | |
| 3676 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex); | |
| 3677 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { | |
| 3678 __ Str(x10, FieldMemOperand(elements, | |
| 3679 FixedArray::OffsetOfElementAt(i))); | |
| 3680 } | |
| 3681 } | |
| 3682 | |
| 3683 // Install the new backing store in the JSArray. | |
| 3684 __ Str(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 3685 __ RecordWriteField(receiver, JSObject::kElementsOffset, elements, | |
| 3686 x10, kLRHasNotBeenSaved, kDontSaveFPRegs, | |
| 3687 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK, | |
| 3688 EXPECT_PREGENERATED); | |
| 3689 | |
| 3690 // Increment the length of the array. | |
| 3691 __ Mov(length, Operand(Smi::FromInt(1))); | |
| 3692 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 3693 __ Ret(); | |
| 3694 | |
| 3695 __ Bind(&check_capacity); | |
| 3696 | |
| 3697 if (!store_double) { | |
| 3698 // Check for cow elements, in general they are not handled by this stub | |
| 3699 // TODO(jbramley): Why is this only done when storing a smi? | |
| 3700 __ CheckMap(elements, x10, | |
| 3701 Heap::kFixedCOWArrayMapRootIndex, | |
| 3702 &miss_force_generic, | |
| 3703 DONT_DO_SMI_CHECK); | |
| 3704 } | |
| 3705 | |
| 3706 // See if there are any free preallocated slots. If not, defer to the | |
| 3707 // runtime to extend the backing store. | |
| 3708 __ Ldr(x10, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 3709 __ Cmp(length, x10); | |
| 3710 __ B(&slow, hs); | |
| 3711 | |
| 3712 // Grow the array and finish the store. | |
| 3713 __ Add(length, length, Operand(Smi::FromInt(1))); | |
| 3714 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 3715 __ B(&finish_store); | |
| 3716 | |
| 3717 __ Bind(&slow); | |
| 3718 KeyedStoreStubCompiler::TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | |
| 3719 } | |
| 3720 } | |
| 3721 | |
| 3722 | |
| 3723 void KeyedStoreStubCompiler::GenerateStoreFastElement( | |
| 3724 MacroAssembler* masm, | |
| 3725 bool is_js_array, | |
| 3726 ElementsKind elements_kind, | |
| 3727 KeyedAccessStoreMode store_mode) { | |
| 3728 | |
| 3729 // ----------- S t a t e ------------- | |
| 3730 // -- lr : return address | |
| 3731 // -- x0 : value | |
| 3732 // -- x1 : key | |
| 3733 // -- x2 : receiver | |
| 3734 // ----------------------------------- | |
| 3735 | |
| 3736 GenerateStoreFastSmiOrDoubleElement(masm, is_js_array, elements_kind, | |
| 3737 store_mode, false); | |
| 3738 } | |
| 3739 | |
| 3740 | |
| 3741 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( | |
| 3742 MacroAssembler* masm, | |
| 3743 bool is_js_array, | |
| 3744 KeyedAccessStoreMode store_mode) { | |
| 3745 | |
| 3746 // ----------- S t a t e ------------- | |
| 3747 // -- lr : return address | |
| 3748 // -- x0 : value | |
| 3749 // -- x1 : key | |
| 3750 // -- x2 : receiver | |
| 3751 // ----------- S t a t e ------------- | |
| 3752 | |
| 3753 GenerateStoreFastSmiOrDoubleElement(masm, is_js_array, FAST_DOUBLE_ELEMENTS, | |
| 3754 store_mode, true); | |
| 3755 } | |
| 3756 | |
| 3757 | |
| 3758 } } // namespace v8::internal | 3257 } } // namespace v8::internal |
| 3759 | 3258 |
| 3760 #endif // V8_TARGET_ARCH_A64 | 3259 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |