OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_ARM | 5 #if V8_TARGET_ARCH_ARM |
6 | 6 |
7 #include "src/codegen.h" | 7 #include "src/codegen.h" |
8 #include "src/ic/ic.h" | 8 #include "src/ic/ic.h" |
9 #include "src/ic/ic-compiler.h" | 9 #include "src/ic/ic-compiler.h" |
10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow, | 480 MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow, |
481 KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length, | 481 KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length, |
482 Register value, Register key, Register receiver, Register receiver_map, | 482 Register value, Register key, Register receiver, Register receiver_map, |
483 Register elements_map, Register elements) { | 483 Register elements_map, Register elements) { |
484 Label transition_smi_elements; | 484 Label transition_smi_elements; |
485 Label finish_object_store, non_double_value, transition_double_elements; | 485 Label finish_object_store, non_double_value, transition_double_elements; |
486 Label fast_double_without_map_check; | 486 Label fast_double_without_map_check; |
487 | 487 |
488 // Fast case: Do the store, could be either Object or double. | 488 // Fast case: Do the store, could be either Object or double. |
489 __ bind(fast_object); | 489 __ bind(fast_object); |
490 Register scratch_value = r4; | 490 Register scratch = r4; |
491 Register address = r5; | 491 Register address = r5; |
| 492 DCHECK(!AreAliased(value, key, receiver, receiver_map, elements_map, elements, |
| 493 scratch, address)); |
| 494 |
492 if (check_map == kCheckMap) { | 495 if (check_map == kCheckMap) { |
493 __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); | 496 __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); |
494 __ cmp(elements_map, | 497 __ cmp(elements_map, |
495 Operand(masm->isolate()->factory()->fixed_array_map())); | 498 Operand(masm->isolate()->factory()->fixed_array_map())); |
496 __ b(ne, fast_double); | 499 __ b(ne, fast_double); |
497 } | 500 } |
498 | 501 |
499 // HOLECHECK: guards "A[i] = V" | 502 // HOLECHECK: guards "A[i] = V" |
500 // We have to go to the runtime if the current value is the hole because | 503 // We have to go to the runtime if the current value is the hole because |
501 // there may be a callback on the element | 504 // there may be a callback on the element |
502 Label holecheck_passed1; | 505 Label holecheck_passed1; |
503 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 506 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
504 __ ldr(scratch_value, | 507 __ ldr(scratch, MemOperand::PointerAddressFromSmiKey(address, key, PreIndex)); |
505 MemOperand::PointerAddressFromSmiKey(address, key, PreIndex)); | 508 __ cmp(scratch, Operand(masm->isolate()->factory()->the_hole_value())); |
506 __ cmp(scratch_value, Operand(masm->isolate()->factory()->the_hole_value())); | |
507 __ b(ne, &holecheck_passed1); | 509 __ b(ne, &holecheck_passed1); |
508 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value, | 510 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow); |
509 slow); | |
510 | 511 |
511 __ bind(&holecheck_passed1); | 512 __ bind(&holecheck_passed1); |
512 | 513 |
513 // Smi stores don't require further checks. | 514 // Smi stores don't require further checks. |
514 Label non_smi_value; | 515 Label non_smi_value; |
515 __ JumpIfNotSmi(value, &non_smi_value); | 516 __ JumpIfNotSmi(value, &non_smi_value); |
516 | 517 |
517 if (increment_length == kIncrementLength) { | 518 if (increment_length == kIncrementLength) { |
518 // Add 1 to receiver->length. | 519 // Add 1 to receiver->length. |
519 __ add(scratch_value, key, Operand(Smi::FromInt(1))); | 520 __ add(scratch, key, Operand(Smi::FromInt(1))); |
520 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 521 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
521 } | 522 } |
522 // It's irrelevant whether array is smi-only or not when writing a smi. | 523 // It's irrelevant whether array is smi-only or not when writing a smi. |
523 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 524 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
524 __ str(value, MemOperand::PointerAddressFromSmiKey(address, key)); | 525 __ str(value, MemOperand::PointerAddressFromSmiKey(address, key)); |
525 __ Ret(); | 526 __ Ret(); |
526 | 527 |
527 __ bind(&non_smi_value); | 528 __ bind(&non_smi_value); |
528 // Escape to elements kind transition case. | 529 // Escape to elements kind transition case. |
529 __ CheckFastObjectElements(receiver_map, scratch_value, | 530 __ CheckFastObjectElements(receiver_map, scratch, &transition_smi_elements); |
530 &transition_smi_elements); | |
531 | 531 |
532 // Fast elements array, store the value to the elements backing store. | 532 // Fast elements array, store the value to the elements backing store. |
533 __ bind(&finish_object_store); | 533 __ bind(&finish_object_store); |
534 if (increment_length == kIncrementLength) { | 534 if (increment_length == kIncrementLength) { |
535 // Add 1 to receiver->length. | 535 // Add 1 to receiver->length. |
536 __ add(scratch_value, key, Operand(Smi::FromInt(1))); | 536 __ add(scratch, key, Operand(Smi::FromInt(1))); |
537 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 537 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
538 } | 538 } |
539 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 539 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
540 __ add(address, address, Operand::PointerOffsetFromSmiKey(key)); | 540 __ add(address, address, Operand::PointerOffsetFromSmiKey(key)); |
541 __ str(value, MemOperand(address)); | 541 __ str(value, MemOperand(address)); |
542 // Update write barrier for the elements array address. | 542 // Update write barrier for the elements array address. |
543 __ mov(scratch_value, value); // Preserve the value which is returned. | 543 __ mov(scratch, value); // Preserve the value which is returned. |
544 __ RecordWrite(elements, address, scratch_value, kLRHasNotBeenSaved, | 544 __ RecordWrite(elements, address, scratch, kLRHasNotBeenSaved, |
545 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 545 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
546 __ Ret(); | 546 __ Ret(); |
547 | 547 |
548 __ bind(fast_double); | 548 __ bind(fast_double); |
549 if (check_map == kCheckMap) { | 549 if (check_map == kCheckMap) { |
550 // Check for fast double array case. If this fails, call through to the | 550 // Check for fast double array case. If this fails, call through to the |
551 // runtime. | 551 // runtime. |
552 __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex); | 552 __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex); |
553 __ b(ne, slow); | 553 __ b(ne, slow); |
554 } | 554 } |
555 | 555 |
556 // HOLECHECK: guards "A[i] double hole?" | 556 // HOLECHECK: guards "A[i] double hole?" |
557 // We have to see if the double version of the hole is present. If so | 557 // We have to see if the double version of the hole is present. If so |
558 // go to the runtime. | 558 // go to the runtime. |
559 __ add(address, elements, | 559 __ add(address, elements, |
560 Operand((FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32)) - | 560 Operand((FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32)) - |
561 kHeapObjectTag)); | 561 kHeapObjectTag)); |
562 __ ldr(scratch_value, | 562 __ ldr(scratch, MemOperand(address, key, LSL, kPointerSizeLog2, PreIndex)); |
563 MemOperand(address, key, LSL, kPointerSizeLog2, PreIndex)); | 563 __ cmp(scratch, Operand(kHoleNanUpper32)); |
564 __ cmp(scratch_value, Operand(kHoleNanUpper32)); | |
565 __ b(ne, &fast_double_without_map_check); | 564 __ b(ne, &fast_double_without_map_check); |
566 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value, | 565 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch, slow); |
567 slow); | |
568 | 566 |
569 __ bind(&fast_double_without_map_check); | 567 __ bind(&fast_double_without_map_check); |
570 __ StoreNumberToDoubleElements(value, key, elements, r3, d0, | 568 __ StoreNumberToDoubleElements(value, key, elements, scratch, d0, |
571 &transition_double_elements); | 569 &transition_double_elements); |
572 if (increment_length == kIncrementLength) { | 570 if (increment_length == kIncrementLength) { |
573 // Add 1 to receiver->length. | 571 // Add 1 to receiver->length. |
574 __ add(scratch_value, key, Operand(Smi::FromInt(1))); | 572 __ add(scratch, key, Operand(Smi::FromInt(1))); |
575 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 573 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
576 } | 574 } |
577 __ Ret(); | 575 __ Ret(); |
578 | 576 |
579 __ bind(&transition_smi_elements); | 577 __ bind(&transition_smi_elements); |
580 // Transition the array appropriately depending on the value type. | 578 // Transition the array appropriately depending on the value type. |
581 __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset)); | 579 __ ldr(scratch, FieldMemOperand(value, HeapObject::kMapOffset)); |
582 __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex); | 580 __ CompareRoot(scratch, Heap::kHeapNumberMapRootIndex); |
583 __ b(ne, &non_double_value); | 581 __ b(ne, &non_double_value); |
584 | 582 |
585 // Value is a double. Transition FAST_SMI_ELEMENTS -> | 583 // Value is a double. Transition FAST_SMI_ELEMENTS -> |
586 // FAST_DOUBLE_ELEMENTS and complete the store. | 584 // FAST_DOUBLE_ELEMENTS and complete the store. |
587 __ LoadTransitionedArrayMapConditional( | 585 __ LoadTransitionedArrayMapConditional( |
588 FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, r4, slow); | 586 FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, scratch, slow); |
589 AllocationSiteMode mode = | 587 AllocationSiteMode mode = |
590 AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS); | 588 AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS); |
591 ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value, | 589 ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value, |
592 receiver_map, mode, slow); | 590 receiver_map, mode, slow); |
593 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 591 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
594 __ jmp(&fast_double_without_map_check); | 592 __ jmp(&fast_double_without_map_check); |
595 | 593 |
596 __ bind(&non_double_value); | 594 __ bind(&non_double_value); |
597 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS | 595 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS |
598 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, | 596 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, |
599 receiver_map, r4, slow); | 597 receiver_map, scratch, slow); |
600 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); | 598 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); |
601 ElementsTransitionGenerator::GenerateMapChangeElementsTransition( | 599 ElementsTransitionGenerator::GenerateMapChangeElementsTransition( |
602 masm, receiver, key, value, receiver_map, mode, slow); | 600 masm, receiver, key, value, receiver_map, mode, slow); |
603 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 601 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
604 __ jmp(&finish_object_store); | 602 __ jmp(&finish_object_store); |
605 | 603 |
606 __ bind(&transition_double_elements); | 604 __ bind(&transition_double_elements); |
607 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a | 605 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a |
608 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and | 606 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and |
609 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS | 607 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS |
610 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS, | 608 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS, |
611 receiver_map, r4, slow); | 609 receiver_map, scratch, slow); |
612 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); | 610 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); |
613 ElementsTransitionGenerator::GenerateDoubleToObject( | 611 ElementsTransitionGenerator::GenerateDoubleToObject( |
614 masm, receiver, key, value, receiver_map, mode, slow); | 612 masm, receiver, key, value, receiver_map, mode, slow); |
615 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 613 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
616 __ jmp(&finish_object_store); | 614 __ jmp(&finish_object_store); |
617 } | 615 } |
618 | 616 |
619 | 617 |
620 void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm, | 618 void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm, |
621 LanguageMode language_mode) { | 619 LanguageMode language_mode) { |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
900 patcher.EmitCondition(ne); | 898 patcher.EmitCondition(ne); |
901 } else { | 899 } else { |
902 DCHECK(Assembler::GetCondition(branch_instr) == ne); | 900 DCHECK(Assembler::GetCondition(branch_instr) == ne); |
903 patcher.EmitCondition(eq); | 901 patcher.EmitCondition(eq); |
904 } | 902 } |
905 } | 903 } |
906 } // namespace internal | 904 } // namespace internal |
907 } // namespace v8 | 905 } // namespace v8 |
908 | 906 |
909 #endif // V8_TARGET_ARCH_ARM | 907 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |