| 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 |