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 1138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1149 Handle<GlobalObject>::cast(current), | 1149 Handle<GlobalObject>::cast(current), |
1150 name, | 1150 name, |
1151 scratch, | 1151 scratch, |
1152 miss); | 1152 miss); |
1153 } | 1153 } |
1154 current = Handle<JSObject>(JSObject::cast(current->GetPrototype())); | 1154 current = Handle<JSObject>(JSObject::cast(current->GetPrototype())); |
1155 } | 1155 } |
1156 } | 1156 } |
1157 | 1157 |
1158 | 1158 |
1159 // Convert and store int passed in register ival to IEEE 754 single precision | |
1160 // floating point value at memory location (dst + 4 * wordoffset) | |
1161 // If FPU is available use it for conversion. | |
1162 static void StoreIntAsFloat(MacroAssembler* masm, | |
1163 Register dst, | |
1164 Register wordoffset, | |
1165 Register ival, | |
1166 Register scratch1) { | |
1167 __ mtc1(ival, f0); | |
1168 __ cvt_s_w(f0, f0); | |
1169 __ sll(scratch1, wordoffset, 2); | |
1170 __ addu(scratch1, dst, scratch1); | |
1171 __ swc1(f0, MemOperand(scratch1, 0)); | |
1172 } | |
1173 | |
1174 | |
1175 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { | 1159 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { |
1176 __ Jump(code, RelocInfo::CODE_TARGET); | 1160 __ Jump(code, RelocInfo::CODE_TARGET); |
1177 } | 1161 } |
1178 | 1162 |
1179 | 1163 |
1180 #undef __ | 1164 #undef __ |
1181 #define __ ACCESS_MASM(masm()) | 1165 #define __ ACCESS_MASM(masm()) |
1182 | 1166 |
1183 | 1167 |
1184 Register StubCompiler::CheckPrototypes(Handle<JSObject> object, | 1168 Register StubCompiler::CheckPrototypes(Handle<JSObject> object, |
(...skipping 2037 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3222 | 3206 |
3223 // ---------- S t a t e -------------- | 3207 // ---------- S t a t e -------------- |
3224 // -- ra : return address | 3208 // -- ra : return address |
3225 // -- a0 : key | 3209 // -- a0 : key |
3226 // -- a1 : receiver | 3210 // -- a1 : receiver |
3227 // ----------------------------------- | 3211 // ----------------------------------- |
3228 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric); | 3212 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_MissForceGeneric); |
3229 } | 3213 } |
3230 | 3214 |
3231 | 3215 |
3232 static void GenerateSmiKeyCheck(MacroAssembler* masm, | |
3233 Register key, | |
3234 Register scratch0, | |
3235 Register scratch1, | |
3236 FPURegister double_scratch0, | |
3237 FPURegister double_scratch1, | |
3238 Label* fail) { | |
3239 Label key_ok; | |
3240 // Check for smi or a smi inside a heap number. We convert the heap | |
3241 // number and check if the conversion is exact and fits into the smi | |
3242 // range. | |
3243 __ JumpIfSmi(key, &key_ok); | |
3244 __ CheckMap(key, | |
3245 scratch0, | |
3246 Heap::kHeapNumberMapRootIndex, | |
3247 fail, | |
3248 DONT_DO_SMI_CHECK); | |
3249 __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset)); | |
3250 __ EmitFPUTruncate(kRoundToZero, | |
3251 scratch0, | |
3252 double_scratch0, | |
3253 at, | |
3254 double_scratch1, | |
3255 scratch1, | |
3256 kCheckForInexactConversion); | |
3257 | |
3258 __ Branch(fail, ne, scratch1, Operand(zero_reg)); | |
3259 | |
3260 __ SmiTagCheckOverflow(key, scratch0, scratch1); | |
3261 __ BranchOnOverflow(fail, scratch1); | |
3262 __ bind(&key_ok); | |
3263 } | |
3264 | |
3265 | |
3266 void KeyedStoreStubCompiler::GenerateStoreExternalArray( | |
3267 MacroAssembler* masm, | |
3268 ElementsKind elements_kind) { | |
3269 // ---------- S t a t e -------------- | |
3270 // -- a0 : value | |
3271 // -- a1 : key | |
3272 // -- a2 : receiver | |
3273 // -- ra : return address | |
3274 // ----------------------------------- | |
3275 | |
3276 Label slow, check_heap_number, miss_force_generic; | |
3277 | |
3278 // Register usage. | |
3279 Register value = a0; | |
3280 Register key = a1; | |
3281 Register receiver = a2; | |
3282 // a3 mostly holds the elements array or the destination external array. | |
3283 | |
3284 // This stub is meant to be tail-jumped to, the receiver must already | |
3285 // have been verified by the caller to not be a smi. | |
3286 | |
3287 // Check that the key is a smi or a heap number convertible to a smi. | |
3288 GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic); | |
3289 | |
3290 __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
3291 | |
3292 // Check that the index is in range. | |
3293 __ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset)); | |
3294 // Unsigned comparison catches both negative and too-large values. | |
3295 __ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1)); | |
3296 | |
3297 // Handle both smis and HeapNumbers in the fast path. Go to the | |
3298 // runtime for all other kinds of values. | |
3299 // a3: external array. | |
3300 | |
3301 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) { | |
3302 // Double to pixel conversion is only implemented in the runtime for now. | |
3303 __ JumpIfNotSmi(value, &slow); | |
3304 } else { | |
3305 __ JumpIfNotSmi(value, &check_heap_number); | |
3306 } | |
3307 __ SmiUntag(t1, value); | |
3308 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset)); | |
3309 | |
3310 // a3: base pointer of external storage. | |
3311 // t1: value (integer). | |
3312 | |
3313 switch (elements_kind) { | |
3314 case EXTERNAL_PIXEL_ELEMENTS: { | |
3315 // Clamp the value to [0..255]. | |
3316 // v0 is used as a scratch register here. | |
3317 Label done; | |
3318 __ li(v0, Operand(255)); | |
3319 // Normal branch: nop in delay slot. | |
3320 __ Branch(&done, gt, t1, Operand(v0)); | |
3321 // Use delay slot in this branch. | |
3322 __ Branch(USE_DELAY_SLOT, &done, lt, t1, Operand(zero_reg)); | |
3323 __ mov(v0, zero_reg); // In delay slot. | |
3324 __ mov(v0, t1); // Value is in range 0..255. | |
3325 __ bind(&done); | |
3326 __ mov(t1, v0); | |
3327 | |
3328 __ srl(t8, key, 1); | |
3329 __ addu(t8, a3, t8); | |
3330 __ sb(t1, MemOperand(t8, 0)); | |
3331 } | |
3332 break; | |
3333 case EXTERNAL_BYTE_ELEMENTS: | |
3334 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
3335 __ srl(t8, key, 1); | |
3336 __ addu(t8, a3, t8); | |
3337 __ sb(t1, MemOperand(t8, 0)); | |
3338 break; | |
3339 case EXTERNAL_SHORT_ELEMENTS: | |
3340 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
3341 __ addu(t8, a3, key); | |
3342 __ sh(t1, MemOperand(t8, 0)); | |
3343 break; | |
3344 case EXTERNAL_INT_ELEMENTS: | |
3345 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
3346 __ sll(t8, key, 1); | |
3347 __ addu(t8, a3, t8); | |
3348 __ sw(t1, MemOperand(t8, 0)); | |
3349 break; | |
3350 case EXTERNAL_FLOAT_ELEMENTS: | |
3351 // Perform int-to-float conversion and store to memory. | |
3352 __ SmiUntag(t0, key); | |
3353 StoreIntAsFloat(masm, a3, t0, t1, t2); | |
3354 break; | |
3355 case EXTERNAL_DOUBLE_ELEMENTS: | |
3356 __ sll(t8, key, 2); | |
3357 __ addu(a3, a3, t8); | |
3358 // a3: effective address of the double element | |
3359 FloatingPointHelper::Destination destination; | |
3360 destination = FloatingPointHelper::kFPURegisters; | |
3361 FloatingPointHelper::ConvertIntToDouble( | |
3362 masm, t1, destination, | |
3363 f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent. | |
3364 t0, f2); // These are: scratch2, single_scratch. | |
3365 __ sdc1(f0, MemOperand(a3, 0)); | |
3366 break; | |
3367 case FAST_ELEMENTS: | |
3368 case FAST_SMI_ELEMENTS: | |
3369 case FAST_DOUBLE_ELEMENTS: | |
3370 case FAST_HOLEY_ELEMENTS: | |
3371 case FAST_HOLEY_SMI_ELEMENTS: | |
3372 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
3373 case DICTIONARY_ELEMENTS: | |
3374 case NON_STRICT_ARGUMENTS_ELEMENTS: | |
3375 UNREACHABLE(); | |
3376 break; | |
3377 } | |
3378 | |
3379 // Entry registers are intact, a0 holds the value which is the return value. | |
3380 __ Ret(USE_DELAY_SLOT); | |
3381 __ mov(v0, a0); | |
3382 | |
3383 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) { | |
3384 // a3: external array. | |
3385 __ bind(&check_heap_number); | |
3386 __ GetObjectType(value, t1, t2); | |
3387 __ Branch(&slow, ne, t2, Operand(HEAP_NUMBER_TYPE)); | |
3388 | |
3389 __ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset)); | |
3390 | |
3391 // a3: base pointer of external storage. | |
3392 | |
3393 // The WebGL specification leaves the behavior of storing NaN and | |
3394 // +/-Infinity into integer arrays basically undefined. For more | |
3395 // reproducible behavior, convert these to zero. | |
3396 | |
3397 | |
3398 __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset)); | |
3399 | |
3400 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { | |
3401 __ cvt_s_d(f0, f0); | |
3402 __ sll(t8, key, 1); | |
3403 __ addu(t8, a3, t8); | |
3404 __ swc1(f0, MemOperand(t8, 0)); | |
3405 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { | |
3406 __ sll(t8, key, 2); | |
3407 __ addu(t8, a3, t8); | |
3408 __ sdc1(f0, MemOperand(t8, 0)); | |
3409 } else { | |
3410 __ EmitECMATruncate(t3, f0, f2, t2, t1, t5); | |
3411 | |
3412 switch (elements_kind) { | |
3413 case EXTERNAL_BYTE_ELEMENTS: | |
3414 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
3415 __ srl(t8, key, 1); | |
3416 __ addu(t8, a3, t8); | |
3417 __ sb(t3, MemOperand(t8, 0)); | |
3418 break; | |
3419 case EXTERNAL_SHORT_ELEMENTS: | |
3420 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
3421 __ addu(t8, a3, key); | |
3422 __ sh(t3, MemOperand(t8, 0)); | |
3423 break; | |
3424 case EXTERNAL_INT_ELEMENTS: | |
3425 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
3426 __ sll(t8, key, 1); | |
3427 __ addu(t8, a3, t8); | |
3428 __ sw(t3, MemOperand(t8, 0)); | |
3429 break; | |
3430 case EXTERNAL_PIXEL_ELEMENTS: | |
3431 case EXTERNAL_FLOAT_ELEMENTS: | |
3432 case EXTERNAL_DOUBLE_ELEMENTS: | |
3433 case FAST_ELEMENTS: | |
3434 case FAST_SMI_ELEMENTS: | |
3435 case FAST_DOUBLE_ELEMENTS: | |
3436 case FAST_HOLEY_ELEMENTS: | |
3437 case FAST_HOLEY_SMI_ELEMENTS: | |
3438 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
3439 case DICTIONARY_ELEMENTS: | |
3440 case NON_STRICT_ARGUMENTS_ELEMENTS: | |
3441 UNREACHABLE(); | |
3442 break; | |
3443 } | |
3444 } | |
3445 | |
3446 // Entry registers are intact, a0 holds the value | |
3447 // which is the return value. | |
3448 __ Ret(USE_DELAY_SLOT); | |
3449 __ mov(v0, a0); | |
3450 } | |
3451 | |
3452 // Slow case, key and receiver still in a0 and a1. | |
3453 __ bind(&slow); | |
3454 __ IncrementCounter( | |
3455 masm->isolate()->counters()->keyed_load_external_array_slow(), | |
3456 1, a2, a3); | |
3457 // Entry registers are intact. | |
3458 // ---------- S t a t e -------------- | |
3459 // -- ra : return address | |
3460 // -- a0 : key | |
3461 // -- a1 : receiver | |
3462 // ----------------------------------- | |
3463 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | |
3464 | |
3465 // Miss case, call the runtime. | |
3466 __ bind(&miss_force_generic); | |
3467 | |
3468 // ---------- S t a t e -------------- | |
3469 // -- ra : return address | |
3470 // -- a0 : key | |
3471 // -- a1 : receiver | |
3472 // ----------------------------------- | |
3473 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); | |
3474 } | |
3475 | |
3476 | |
3477 void KeyedStoreStubCompiler::GenerateStoreFastElement( | |
3478 MacroAssembler* masm, | |
3479 bool is_js_array, | |
3480 ElementsKind elements_kind, | |
3481 KeyedAccessStoreMode store_mode) { | |
3482 // ----------- S t a t e ------------- | |
3483 // -- a0 : value | |
3484 // -- a1 : key | |
3485 // -- a2 : receiver | |
3486 // -- ra : return address | |
3487 // -- a3 : scratch | |
3488 // -- a4 : scratch (elements) | |
3489 // ----------------------------------- | |
3490 Label miss_force_generic, transition_elements_kind, grow, slow; | |
3491 Label finish_store, check_capacity; | |
3492 | |
3493 Register value_reg = a0; | |
3494 Register key_reg = a1; | |
3495 Register receiver_reg = a2; | |
3496 Register scratch = t0; | |
3497 Register elements_reg = a3; | |
3498 Register length_reg = t1; | |
3499 Register scratch2 = t2; | |
3500 | |
3501 // This stub is meant to be tail-jumped to, the receiver must already | |
3502 // have been verified by the caller to not be a smi. | |
3503 | |
3504 // Check that the key is a smi or a heap number convertible to a smi. | |
3505 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic); | |
3506 | |
3507 if (IsFastSmiElementsKind(elements_kind)) { | |
3508 __ JumpIfNotSmi(value_reg, &transition_elements_kind); | |
3509 } | |
3510 | |
3511 // Check that the key is within bounds. | |
3512 __ lw(elements_reg, | |
3513 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); | |
3514 if (is_js_array) { | |
3515 __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); | |
3516 } else { | |
3517 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); | |
3518 } | |
3519 // Compare smis. | |
3520 if (is_js_array && IsGrowStoreMode(store_mode)) { | |
3521 __ Branch(&grow, hs, key_reg, Operand(scratch)); | |
3522 } else { | |
3523 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch)); | |
3524 } | |
3525 | |
3526 // Make sure elements is a fast element array, not 'cow'. | |
3527 __ CheckMap(elements_reg, | |
3528 scratch, | |
3529 Heap::kFixedArrayMapRootIndex, | |
3530 &miss_force_generic, | |
3531 DONT_DO_SMI_CHECK); | |
3532 | |
3533 __ bind(&finish_store); | |
3534 | |
3535 if (IsFastSmiElementsKind(elements_kind)) { | |
3536 __ Addu(scratch, | |
3537 elements_reg, | |
3538 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
3539 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | |
3540 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize); | |
3541 __ Addu(scratch, scratch, scratch2); | |
3542 __ sw(value_reg, MemOperand(scratch)); | |
3543 } else { | |
3544 ASSERT(IsFastObjectElementsKind(elements_kind)); | |
3545 __ Addu(scratch, | |
3546 elements_reg, | |
3547 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
3548 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | |
3549 __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize); | |
3550 __ Addu(scratch, scratch, scratch2); | |
3551 __ sw(value_reg, MemOperand(scratch)); | |
3552 __ mov(receiver_reg, value_reg); | |
3553 __ RecordWrite(elements_reg, // Object. | |
3554 scratch, // Address. | |
3555 receiver_reg, // Value. | |
3556 kRAHasNotBeenSaved, | |
3557 kDontSaveFPRegs); | |
3558 } | |
3559 // value_reg (a0) is preserved. | |
3560 // Done. | |
3561 __ Ret(); | |
3562 | |
3563 __ bind(&miss_force_generic); | |
3564 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); | |
3565 | |
3566 __ bind(&transition_elements_kind); | |
3567 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); | |
3568 | |
3569 if (is_js_array && IsGrowStoreMode(store_mode)) { | |
3570 // Grow the array by a single element if possible. | |
3571 __ bind(&grow); | |
3572 | |
3573 // Make sure the array is only growing by a single element, anything else | |
3574 // must be handled by the runtime. | |
3575 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch)); | |
3576 | |
3577 // Check for the empty array, and preallocate a small backing store if | |
3578 // possible. | |
3579 __ lw(length_reg, | |
3580 FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); | |
3581 __ lw(elements_reg, | |
3582 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); | |
3583 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex); | |
3584 __ Branch(&check_capacity, ne, elements_reg, Operand(at)); | |
3585 | |
3586 int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); | |
3587 __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT); | |
3588 | |
3589 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex); | |
3590 __ sw(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset)); | |
3591 __ li(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements))); | |
3592 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); | |
3593 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); | |
3594 for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) { | |
3595 __ sw(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i))); | |
3596 } | |
3597 | |
3598 // Store the element at index zero. | |
3599 __ sw(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0))); | |
3600 | |
3601 // Install the new backing store in the JSArray. | |
3602 __ sw(elements_reg, | |
3603 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); | |
3604 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg, | |
3605 scratch, kRAHasNotBeenSaved, kDontSaveFPRegs, | |
3606 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | |
3607 | |
3608 // Increment the length of the array. | |
3609 __ li(length_reg, Operand(Smi::FromInt(1))); | |
3610 __ Ret(USE_DELAY_SLOT); | |
3611 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); | |
3612 | |
3613 __ bind(&check_capacity); | |
3614 // Check for cow elements, in general they are not handled by this stub | |
3615 __ CheckMap(elements_reg, | |
3616 scratch, | |
3617 Heap::kFixedCOWArrayMapRootIndex, | |
3618 &miss_force_generic, | |
3619 DONT_DO_SMI_CHECK); | |
3620 | |
3621 __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); | |
3622 __ Branch(&slow, hs, length_reg, Operand(scratch)); | |
3623 | |
3624 // Grow the array and finish the store. | |
3625 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1))); | |
3626 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); | |
3627 __ jmp(&finish_store); | |
3628 | |
3629 __ bind(&slow); | |
3630 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | |
3631 } | |
3632 } | |
3633 | |
3634 | |
3635 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( | |
3636 MacroAssembler* masm, | |
3637 bool is_js_array, | |
3638 KeyedAccessStoreMode store_mode) { | |
3639 // ----------- S t a t e ------------- | |
3640 // -- a0 : value | |
3641 // -- a1 : key | |
3642 // -- a2 : receiver | |
3643 // -- ra : return address | |
3644 // -- a3 : scratch (elements backing store) | |
3645 // -- t0 : scratch (elements_reg) | |
3646 // -- t1 : scratch (mantissa_reg) | |
3647 // -- t2 : scratch (exponent_reg) | |
3648 // -- t3 : scratch4 | |
3649 // -- t4 : scratch | |
3650 // ----------------------------------- | |
3651 Label miss_force_generic, transition_elements_kind, grow, slow; | |
3652 Label finish_store, check_capacity; | |
3653 | |
3654 Register value_reg = a0; | |
3655 Register key_reg = a1; | |
3656 Register receiver_reg = a2; | |
3657 Register elements_reg = a3; | |
3658 Register scratch1 = t0; | |
3659 Register scratch2 = t1; | |
3660 Register scratch3 = t2; | |
3661 Register scratch4 = t3; | |
3662 Register scratch5 = t4; | |
3663 Register length_reg = t3; | |
3664 | |
3665 // This stub is meant to be tail-jumped to, the receiver must already | |
3666 // have been verified by the caller to not be a smi. | |
3667 | |
3668 // Check that the key is a smi or a heap number convertible to a smi. | |
3669 GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic); | |
3670 | |
3671 __ lw(elements_reg, | |
3672 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); | |
3673 | |
3674 // Check that the key is within bounds. | |
3675 if (is_js_array) { | |
3676 __ lw(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); | |
3677 } else { | |
3678 __ lw(scratch1, | |
3679 FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); | |
3680 } | |
3681 // Compare smis, unsigned compare catches both negative and out-of-bound | |
3682 // indexes. | |
3683 if (IsGrowStoreMode(store_mode)) { | |
3684 __ Branch(&grow, hs, key_reg, Operand(scratch1)); | |
3685 } else { | |
3686 __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch1)); | |
3687 } | |
3688 | |
3689 __ bind(&finish_store); | |
3690 | |
3691 __ StoreNumberToDoubleElements(value_reg, | |
3692 key_reg, | |
3693 // All registers after this are overwritten. | |
3694 elements_reg, | |
3695 scratch1, | |
3696 scratch2, | |
3697 scratch3, | |
3698 scratch4, | |
3699 &transition_elements_kind); | |
3700 | |
3701 __ Ret(USE_DELAY_SLOT); | |
3702 __ mov(v0, value_reg); // In delay slot. | |
3703 | |
3704 // Handle store cache miss, replacing the ic with the generic stub. | |
3705 __ bind(&miss_force_generic); | |
3706 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); | |
3707 | |
3708 __ bind(&transition_elements_kind); | |
3709 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); | |
3710 | |
3711 if (is_js_array && IsGrowStoreMode(store_mode)) { | |
3712 // Grow the array by a single element if possible. | |
3713 __ bind(&grow); | |
3714 | |
3715 // Make sure the array is only growing by a single element, anything else | |
3716 // must be handled by the runtime. | |
3717 __ Branch(&miss_force_generic, ne, key_reg, Operand(scratch1)); | |
3718 | |
3719 // Transition on values that can't be stored in a FixedDoubleArray. | |
3720 Label value_is_smi; | |
3721 __ JumpIfSmi(value_reg, &value_is_smi); | |
3722 __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); | |
3723 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); | |
3724 __ Branch(&transition_elements_kind, ne, scratch1, Operand(at)); | |
3725 __ bind(&value_is_smi); | |
3726 | |
3727 // Check for the empty array, and preallocate a small backing store if | |
3728 // possible. | |
3729 __ lw(length_reg, | |
3730 FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); | |
3731 __ lw(elements_reg, | |
3732 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); | |
3733 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex); | |
3734 __ Branch(&check_capacity, ne, elements_reg, Operand(at)); | |
3735 | |
3736 int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements); | |
3737 __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT); | |
3738 | |
3739 // Initialize the new FixedDoubleArray. | |
3740 __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex); | |
3741 __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset)); | |
3742 __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements))); | |
3743 __ sw(scratch1, | |
3744 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset)); | |
3745 | |
3746 __ mov(scratch1, elements_reg); | |
3747 __ StoreNumberToDoubleElements(value_reg, | |
3748 key_reg, | |
3749 // All registers after this are overwritten. | |
3750 scratch1, | |
3751 scratch2, | |
3752 scratch3, | |
3753 scratch4, | |
3754 scratch5, | |
3755 &transition_elements_kind); | |
3756 | |
3757 __ li(scratch1, Operand(kHoleNanLower32)); | |
3758 __ li(scratch2, Operand(kHoleNanUpper32)); | |
3759 for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { | |
3760 int offset = FixedDoubleArray::OffsetOfElementAt(i); | |
3761 __ sw(scratch1, FieldMemOperand(elements_reg, offset)); | |
3762 __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize)); | |
3763 } | |
3764 | |
3765 // Install the new backing store in the JSArray. | |
3766 __ sw(elements_reg, | |
3767 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); | |
3768 __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg, | |
3769 scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs, | |
3770 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | |
3771 | |
3772 // Increment the length of the array. | |
3773 __ li(length_reg, Operand(Smi::FromInt(1))); | |
3774 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); | |
3775 __ Ret(USE_DELAY_SLOT); | |
3776 __ lw(elements_reg, | |
3777 FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); | |
3778 | |
3779 __ bind(&check_capacity); | |
3780 // Make sure that the backing store can hold additional elements. | |
3781 __ lw(scratch1, | |
3782 FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset)); | |
3783 __ Branch(&slow, hs, length_reg, Operand(scratch1)); | |
3784 | |
3785 // Grow the array and finish the store. | |
3786 __ Addu(length_reg, length_reg, Operand(Smi::FromInt(1))); | |
3787 __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); | |
3788 __ jmp(&finish_store); | |
3789 | |
3790 __ bind(&slow); | |
3791 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | |
3792 } | |
3793 } | |
3794 | |
3795 | |
3796 #undef __ | 3216 #undef __ |
3797 | 3217 |
3798 } } // namespace v8::internal | 3218 } } // namespace v8::internal |
3799 | 3219 |
3800 #endif // V8_TARGET_ARCH_MIPS | 3220 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |