OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
638 Register scratch2, | 638 Register scratch2, |
639 Register scratch3, | 639 Register scratch3, |
640 String* name, | 640 String* name, |
641 JSObject* interceptor_holder, | 641 JSObject* interceptor_holder, |
642 Label* miss_label) { | 642 Label* miss_label) { |
643 Register holder = | 643 Register holder = |
644 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, | 644 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
645 scratch1, scratch2, scratch3, name, | 645 scratch1, scratch2, scratch3, name, |
646 miss_label); | 646 miss_label); |
647 | 647 |
648 __ EnterInternalFrame(); | 648 FrameScope scope(masm, StackFrame::INTERNAL); |
649 // Save the name_ register across the call. | 649 // Save the name_ register across the call. |
650 __ push(name_); | 650 __ push(name_); |
651 | 651 |
652 PushInterceptorArguments(masm, | 652 PushInterceptorArguments(masm, |
653 receiver, | 653 receiver, |
654 holder, | 654 holder, |
655 name_, | 655 name_, |
656 interceptor_holder); | 656 interceptor_holder); |
657 | 657 |
658 __ CallExternalReference( | 658 __ CallExternalReference( |
659 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), | 659 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), |
660 masm->isolate()), | 660 masm->isolate()), |
661 5); | 661 5); |
662 | 662 |
663 // Restore the name_ register. | 663 // Restore the name_ register. |
664 __ pop(name_); | 664 __ pop(name_); |
665 __ LeaveInternalFrame(); | 665 |
| 666 // Leave the internal frame. |
666 } | 667 } |
667 | 668 |
668 void LoadWithInterceptor(MacroAssembler* masm, | 669 void LoadWithInterceptor(MacroAssembler* masm, |
669 Register receiver, | 670 Register receiver, |
670 Register holder, | 671 Register holder, |
671 JSObject* holder_obj, | 672 JSObject* holder_obj, |
672 Label* interceptor_succeeded) { | 673 Label* interceptor_succeeded) { |
673 __ EnterInternalFrame(); | 674 { |
674 __ push(holder); // Save the holder. | 675 FrameScope scope(masm, StackFrame::INTERNAL); |
675 __ push(name_); // Save the name. | 676 __ push(holder); // Save the holder. |
| 677 __ push(name_); // Save the name. |
676 | 678 |
677 CompileCallLoadPropertyWithInterceptor(masm, | 679 CompileCallLoadPropertyWithInterceptor(masm, |
678 receiver, | 680 receiver, |
679 holder, | 681 holder, |
680 name_, | 682 name_, |
681 holder_obj); | 683 holder_obj); |
682 | 684 |
683 __ pop(name_); // Restore the name. | 685 __ pop(name_); // Restore the name. |
684 __ pop(receiver); // Restore the holder. | 686 __ pop(receiver); // Restore the holder. |
685 __ LeaveInternalFrame(); | 687 // Leave the internal frame. |
| 688 } |
686 | 689 |
687 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); | 690 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); |
688 __ j(not_equal, interceptor_succeeded); | 691 __ j(not_equal, interceptor_succeeded); |
689 } | 692 } |
690 | 693 |
691 StubCompiler* stub_compiler_; | 694 StubCompiler* stub_compiler_; |
692 const ParameterCount& arguments_; | 695 const ParameterCount& arguments_; |
693 Register name_; | 696 Register name_; |
694 Code::ExtraICState extra_ic_state_; | 697 Code::ExtraICState extra_ic_state_; |
695 }; | 698 }; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 index -= object->map()->inobject_properties(); | 777 index -= object->map()->inobject_properties(); |
775 | 778 |
776 if (index < 0) { | 779 if (index < 0) { |
777 // Set the property straight into the object. | 780 // Set the property straight into the object. |
778 int offset = object->map()->instance_size() + (index * kPointerSize); | 781 int offset = object->map()->instance_size() + (index * kPointerSize); |
779 __ movq(FieldOperand(receiver_reg, offset), rax); | 782 __ movq(FieldOperand(receiver_reg, offset), rax); |
780 | 783 |
781 // Update the write barrier for the array address. | 784 // Update the write barrier for the array address. |
782 // Pass the value being stored in the now unused name_reg. | 785 // Pass the value being stored in the now unused name_reg. |
783 __ movq(name_reg, rax); | 786 __ movq(name_reg, rax); |
784 __ RecordWrite(receiver_reg, offset, name_reg, scratch); | 787 __ RecordWriteField( |
| 788 receiver_reg, offset, name_reg, scratch, kDontSaveFPRegs); |
785 } else { | 789 } else { |
786 // Write to the properties array. | 790 // Write to the properties array. |
787 int offset = index * kPointerSize + FixedArray::kHeaderSize; | 791 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
788 // Get the properties array (optimistically). | 792 // Get the properties array (optimistically). |
789 __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); | 793 __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); |
790 __ movq(FieldOperand(scratch, offset), rax); | 794 __ movq(FieldOperand(scratch, offset), rax); |
791 | 795 |
792 // Update the write barrier for the array address. | 796 // Update the write barrier for the array address. |
793 // Pass the value being stored in the now unused name_reg. | 797 // Pass the value being stored in the now unused name_reg. |
794 __ movq(name_reg, rax); | 798 __ movq(name_reg, rax); |
795 __ RecordWrite(scratch, offset, name_reg, receiver_reg); | 799 __ RecordWriteField( |
| 800 scratch, offset, name_reg, receiver_reg, kDontSaveFPRegs); |
796 } | 801 } |
797 | 802 |
798 // Return the value (register rax). | 803 // Return the value (register rax). |
799 __ ret(0); | 804 __ ret(0); |
800 } | 805 } |
801 | 806 |
802 | 807 |
803 // Generate code to check that a global property cell is empty. Create | 808 // Generate code to check that a global property cell is empty. Create |
804 // the property cell at compilation time if no cell exists for the | 809 // the property cell at compilation time if no cell exists for the |
805 // property. | 810 // property. |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1132 // Compile the interceptor call, followed by inline code to load the | 1137 // Compile the interceptor call, followed by inline code to load the |
1133 // property from further up the prototype chain if the call fails. | 1138 // property from further up the prototype chain if the call fails. |
1134 // Check that the maps haven't changed. | 1139 // Check that the maps haven't changed. |
1135 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1140 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, |
1136 scratch1, scratch2, scratch3, | 1141 scratch1, scratch2, scratch3, |
1137 name, miss); | 1142 name, miss); |
1138 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); | 1143 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); |
1139 | 1144 |
1140 // Save necessary data before invoking an interceptor. | 1145 // Save necessary data before invoking an interceptor. |
1141 // Requires a frame to make GC aware of pushed pointers. | 1146 // Requires a frame to make GC aware of pushed pointers. |
1142 __ EnterInternalFrame(); | 1147 { |
| 1148 FrameScope frame_scope(masm(), StackFrame::INTERNAL); |
1143 | 1149 |
1144 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { | 1150 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
1145 // CALLBACKS case needs a receiver to be passed into C++ callback. | 1151 // CALLBACKS case needs a receiver to be passed into C++ callback. |
1146 __ push(receiver); | 1152 __ push(receiver); |
| 1153 } |
| 1154 __ push(holder_reg); |
| 1155 __ push(name_reg); |
| 1156 |
| 1157 // Invoke an interceptor. Note: map checks from receiver to |
| 1158 // interceptor's holder has been compiled before (see a caller |
| 1159 // of this method.) |
| 1160 CompileCallLoadPropertyWithInterceptor(masm(), |
| 1161 receiver, |
| 1162 holder_reg, |
| 1163 name_reg, |
| 1164 interceptor_holder); |
| 1165 |
| 1166 // Check if interceptor provided a value for property. If it's |
| 1167 // the case, return immediately. |
| 1168 Label interceptor_failed; |
| 1169 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); |
| 1170 __ j(equal, &interceptor_failed); |
| 1171 frame_scope.GenerateLeaveFrame(); |
| 1172 __ ret(0); |
| 1173 |
| 1174 __ bind(&interceptor_failed); |
| 1175 __ pop(name_reg); |
| 1176 __ pop(holder_reg); |
| 1177 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
| 1178 __ pop(receiver); |
| 1179 } |
| 1180 |
| 1181 // Leave the internal frame. |
1147 } | 1182 } |
1148 __ push(holder_reg); | |
1149 __ push(name_reg); | |
1150 | |
1151 // Invoke an interceptor. Note: map checks from receiver to | |
1152 // interceptor's holder has been compiled before (see a caller | |
1153 // of this method.) | |
1154 CompileCallLoadPropertyWithInterceptor(masm(), | |
1155 receiver, | |
1156 holder_reg, | |
1157 name_reg, | |
1158 interceptor_holder); | |
1159 | |
1160 // Check if interceptor provided a value for property. If it's | |
1161 // the case, return immediately. | |
1162 Label interceptor_failed; | |
1163 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); | |
1164 __ j(equal, &interceptor_failed); | |
1165 __ LeaveInternalFrame(); | |
1166 __ ret(0); | |
1167 | |
1168 __ bind(&interceptor_failed); | |
1169 __ pop(name_reg); | |
1170 __ pop(holder_reg); | |
1171 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { | |
1172 __ pop(receiver); | |
1173 } | |
1174 | |
1175 __ LeaveInternalFrame(); | |
1176 | 1183 |
1177 // Check that the maps from interceptor's holder to lookup's holder | 1184 // Check that the maps from interceptor's holder to lookup's holder |
1178 // haven't changed. And load lookup's holder into |holder| register. | 1185 // haven't changed. And load lookup's holder into |holder| register. |
1179 if (interceptor_holder != lookup->holder()) { | 1186 if (interceptor_holder != lookup->holder()) { |
1180 holder_reg = CheckPrototypes(interceptor_holder, | 1187 holder_reg = CheckPrototypes(interceptor_holder, |
1181 holder_reg, | 1188 holder_reg, |
1182 lookup->holder(), | 1189 lookup->holder(), |
1183 scratch1, | 1190 scratch1, |
1184 scratch2, | 1191 scratch2, |
1185 scratch3, | 1192 scratch3, |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1414 | 1421 |
1415 // Get the elements array of the object. | 1422 // Get the elements array of the object. |
1416 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); | 1423 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); |
1417 | 1424 |
1418 // Check that the elements are in fast mode and writable. | 1425 // Check that the elements are in fast mode and writable. |
1419 __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), | 1426 __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), |
1420 factory()->fixed_array_map()); | 1427 factory()->fixed_array_map()); |
1421 __ j(not_equal, &call_builtin); | 1428 __ j(not_equal, &call_builtin); |
1422 | 1429 |
1423 if (argc == 1) { // Otherwise fall through to call builtin. | 1430 if (argc == 1) { // Otherwise fall through to call builtin. |
1424 Label exit, with_write_barrier, attempt_to_grow_elements; | 1431 Label attempt_to_grow_elements, with_write_barrier; |
1425 | 1432 |
1426 // Get the array's length into rax and calculate new length. | 1433 // Get the array's length into rax and calculate new length. |
1427 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset)); | 1434 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset)); |
1428 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue); | 1435 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue); |
1429 __ addl(rax, Immediate(argc)); | 1436 __ addl(rax, Immediate(argc)); |
1430 | 1437 |
1431 // Get the element's length into rcx. | 1438 // Get the element's length into rcx. |
1432 __ SmiToInteger32(rcx, FieldOperand(rbx, FixedArray::kLengthOffset)); | 1439 __ SmiToInteger32(rcx, FieldOperand(rbx, FixedArray::kLengthOffset)); |
1433 | 1440 |
1434 // Check if we could survive without allocation. | 1441 // Check if we could survive without allocation. |
1435 __ cmpl(rax, rcx); | 1442 __ cmpl(rax, rcx); |
1436 __ j(greater, &attempt_to_grow_elements); | 1443 __ j(greater, &attempt_to_grow_elements); |
1437 | 1444 |
| 1445 // Check if value is a smi. |
| 1446 __ movq(rcx, Operand(rsp, argc * kPointerSize)); |
| 1447 __ JumpIfNotSmi(rcx, &with_write_barrier); |
| 1448 |
1438 // Save new length. | 1449 // Save new length. |
1439 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); | 1450 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); |
1440 | 1451 |
1441 // Push the element. | 1452 // Push the element. |
1442 __ movq(rcx, Operand(rsp, argc * kPointerSize)); | |
1443 __ lea(rdx, FieldOperand(rbx, | 1453 __ lea(rdx, FieldOperand(rbx, |
1444 rax, times_pointer_size, | 1454 rax, times_pointer_size, |
1445 FixedArray::kHeaderSize - argc * kPointerSize)); | 1455 FixedArray::kHeaderSize - argc * kPointerSize)); |
1446 __ movq(Operand(rdx, 0), rcx); | 1456 __ movq(Operand(rdx, 0), rcx); |
1447 | 1457 |
1448 // Check if value is a smi. | |
1449 __ Integer32ToSmi(rax, rax); // Return new length as smi. | 1458 __ Integer32ToSmi(rax, rax); // Return new length as smi. |
1450 | |
1451 __ JumpIfNotSmi(rcx, &with_write_barrier); | |
1452 | |
1453 __ bind(&exit); | |
1454 __ ret((argc + 1) * kPointerSize); | 1459 __ ret((argc + 1) * kPointerSize); |
1455 | 1460 |
1456 __ bind(&with_write_barrier); | 1461 __ bind(&with_write_barrier); |
1457 | 1462 |
1458 __ InNewSpace(rbx, rcx, equal, &exit); | 1463 if (FLAG_smi_only_arrays) { |
| 1464 __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 1465 __ CheckFastObjectElements(rdi, &call_builtin); |
| 1466 } |
1459 | 1467 |
1460 __ RecordWriteHelper(rbx, rdx, rcx); | 1468 // Save new length. |
| 1469 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); |
1461 | 1470 |
| 1471 // Push the element. |
| 1472 __ lea(rdx, FieldOperand(rbx, |
| 1473 rax, times_pointer_size, |
| 1474 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 1475 __ movq(Operand(rdx, 0), rcx); |
| 1476 |
| 1477 __ RecordWrite( |
| 1478 rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 1479 |
| 1480 __ Integer32ToSmi(rax, rax); // Return new length as smi. |
1462 __ ret((argc + 1) * kPointerSize); | 1481 __ ret((argc + 1) * kPointerSize); |
1463 | 1482 |
1464 __ bind(&attempt_to_grow_elements); | 1483 __ bind(&attempt_to_grow_elements); |
1465 if (!FLAG_inline_new) { | 1484 if (!FLAG_inline_new) { |
1466 __ jmp(&call_builtin); | 1485 __ jmp(&call_builtin); |
1467 } | 1486 } |
1468 | 1487 |
| 1488 __ movq(rdi, Operand(rsp, argc * kPointerSize)); |
| 1489 if (FLAG_smi_only_arrays) { |
| 1490 // Growing elements that are SMI-only requires special handling in case |
| 1491 // the new element is non-Smi. For now, delegate to the builtin. |
| 1492 Label no_fast_elements_check; |
| 1493 __ JumpIfSmi(rdi, &no_fast_elements_check); |
| 1494 __ movq(rsi, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 1495 __ CheckFastObjectElements(rsi, &call_builtin, Label::kFar); |
| 1496 __ bind(&no_fast_elements_check); |
| 1497 } |
| 1498 |
1469 ExternalReference new_space_allocation_top = | 1499 ExternalReference new_space_allocation_top = |
1470 ExternalReference::new_space_allocation_top_address(isolate()); | 1500 ExternalReference::new_space_allocation_top_address(isolate()); |
1471 ExternalReference new_space_allocation_limit = | 1501 ExternalReference new_space_allocation_limit = |
1472 ExternalReference::new_space_allocation_limit_address(isolate()); | 1502 ExternalReference::new_space_allocation_limit_address(isolate()); |
1473 | 1503 |
1474 const int kAllocationDelta = 4; | 1504 const int kAllocationDelta = 4; |
1475 // Load top. | 1505 // Load top. |
1476 __ Load(rcx, new_space_allocation_top); | 1506 __ Load(rcx, new_space_allocation_top); |
1477 | 1507 |
1478 // Check if it's the end of elements. | 1508 // Check if it's the end of elements. |
1479 __ lea(rdx, FieldOperand(rbx, | 1509 __ lea(rdx, FieldOperand(rbx, |
1480 rax, times_pointer_size, | 1510 rax, times_pointer_size, |
1481 FixedArray::kHeaderSize - argc * kPointerSize)); | 1511 FixedArray::kHeaderSize - argc * kPointerSize)); |
1482 __ cmpq(rdx, rcx); | 1512 __ cmpq(rdx, rcx); |
1483 __ j(not_equal, &call_builtin); | 1513 __ j(not_equal, &call_builtin); |
1484 __ addq(rcx, Immediate(kAllocationDelta * kPointerSize)); | 1514 __ addq(rcx, Immediate(kAllocationDelta * kPointerSize)); |
1485 Operand limit_operand = | 1515 Operand limit_operand = |
1486 masm()->ExternalOperand(new_space_allocation_limit); | 1516 masm()->ExternalOperand(new_space_allocation_limit); |
1487 __ cmpq(rcx, limit_operand); | 1517 __ cmpq(rcx, limit_operand); |
1488 __ j(above, &call_builtin); | 1518 __ j(above, &call_builtin); |
1489 | 1519 |
1490 // We fit and could grow elements. | 1520 // We fit and could grow elements. |
1491 __ Store(new_space_allocation_top, rcx); | 1521 __ Store(new_space_allocation_top, rcx); |
1492 __ movq(rcx, Operand(rsp, argc * kPointerSize)); | |
1493 | 1522 |
1494 // Push the argument... | 1523 // Push the argument... |
1495 __ movq(Operand(rdx, 0), rcx); | 1524 __ movq(Operand(rdx, 0), rdi); |
1496 // ... and fill the rest with holes. | 1525 // ... and fill the rest with holes. |
1497 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 1526 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
1498 for (int i = 1; i < kAllocationDelta; i++) { | 1527 for (int i = 1; i < kAllocationDelta; i++) { |
1499 __ movq(Operand(rdx, i * kPointerSize), kScratchRegister); | 1528 __ movq(Operand(rdx, i * kPointerSize), kScratchRegister); |
1500 } | 1529 } |
1501 | 1530 |
| 1531 // We know the elements array is in new space so we don't need the |
| 1532 // remembered set, but we just pushed a value onto it so we may have to |
| 1533 // tell the incremental marker to rescan the object that we just grew. We |
| 1534 // don't need to worry about the holes because they are in old space and |
| 1535 // already marked black. |
| 1536 __ RecordWrite(rbx, rdx, rdi, kDontSaveFPRegs, OMIT_REMEMBERED_SET); |
| 1537 |
1502 // Restore receiver to rdx as finish sequence assumes it's here. | 1538 // Restore receiver to rdx as finish sequence assumes it's here. |
1503 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 1539 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
1504 | 1540 |
1505 // Increment element's and array's sizes. | 1541 // Increment element's and array's sizes. |
1506 __ SmiAddConstant(FieldOperand(rbx, FixedArray::kLengthOffset), | 1542 __ SmiAddConstant(FieldOperand(rbx, FixedArray::kLengthOffset), |
1507 Smi::FromInt(kAllocationDelta)); | 1543 Smi::FromInt(kAllocationDelta)); |
1508 | 1544 |
1509 // Make new length a smi before returning it. | 1545 // Make new length a smi before returning it. |
1510 __ Integer32ToSmi(rax, rax); | 1546 __ Integer32ToSmi(rax, rax); |
1511 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax); | 1547 __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax); |
1512 | 1548 |
1513 // Elements are in new space, so write barrier is not required. | |
1514 __ ret((argc + 1) * kPointerSize); | 1549 __ ret((argc + 1) * kPointerSize); |
1515 } | 1550 } |
1516 | 1551 |
1517 __ bind(&call_builtin); | 1552 __ bind(&call_builtin); |
1518 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush, | 1553 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush, |
1519 isolate()), | 1554 isolate()), |
1520 argc + 1, | 1555 argc + 1, |
1521 1); | 1556 1); |
1522 } | 1557 } |
1523 | 1558 |
(...skipping 932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2456 // -- rdx : receiver | 2491 // -- rdx : receiver |
2457 // -- rsp[0] : return address | 2492 // -- rsp[0] : return address |
2458 // ----------------------------------- | 2493 // ----------------------------------- |
2459 Label miss; | 2494 Label miss; |
2460 | 2495 |
2461 // Check that the map of the global has not changed. | 2496 // Check that the map of the global has not changed. |
2462 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), | 2497 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), |
2463 Handle<Map>(object->map())); | 2498 Handle<Map>(object->map())); |
2464 __ j(not_equal, &miss); | 2499 __ j(not_equal, &miss); |
2465 | 2500 |
| 2501 // Compute the cell operand to use. |
| 2502 __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); |
| 2503 Operand cell_operand = FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset); |
| 2504 |
2466 // Check that the value in the cell is not the hole. If it is, this | 2505 // Check that the value in the cell is not the hole. If it is, this |
2467 // cell could have been deleted and reintroducing the global needs | 2506 // cell could have been deleted and reintroducing the global needs |
2468 // to update the property details in the property dictionary of the | 2507 // to update the property details in the property dictionary of the |
2469 // global object. We bail out to the runtime system to do that. | 2508 // global object. We bail out to the runtime system to do that. |
2470 __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); | 2509 __ CompareRoot(cell_operand, Heap::kTheHoleValueRootIndex); |
2471 __ CompareRoot(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), | |
2472 Heap::kTheHoleValueRootIndex); | |
2473 __ j(equal, &miss); | 2510 __ j(equal, &miss); |
2474 | 2511 |
2475 // Store the value in the cell. | 2512 // Store the value in the cell. |
2476 __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rax); | 2513 __ movq(cell_operand, rax); |
| 2514 Label done; |
| 2515 __ JumpIfSmi(rax, &done); |
| 2516 |
| 2517 __ movq(rcx, rax); |
| 2518 __ lea(rdx, cell_operand); |
| 2519 // Cells are always in the remembered set. |
| 2520 __ RecordWrite(rbx, // Object. |
| 2521 rdx, // Address. |
| 2522 rcx, // Value. |
| 2523 kDontSaveFPRegs, |
| 2524 OMIT_REMEMBERED_SET, |
| 2525 OMIT_SMI_CHECK); |
| 2526 |
2477 | 2527 |
2478 // Return the value (register rax). | 2528 // Return the value (register rax). |
| 2529 __ bind(&done); |
| 2530 |
2479 Counters* counters = isolate()->counters(); | 2531 Counters* counters = isolate()->counters(); |
2480 __ IncrementCounter(counters->named_store_global_inline(), 1); | 2532 __ IncrementCounter(counters->named_store_global_inline(), 1); |
2481 __ ret(0); | 2533 __ ret(0); |
2482 | 2534 |
2483 // Handle store cache miss. | 2535 // Handle store cache miss. |
2484 __ bind(&miss); | 2536 __ bind(&miss); |
2485 __ IncrementCounter(counters->named_store_global_inline_miss(), 1); | 2537 __ IncrementCounter(counters->named_store_global_inline_miss(), 1); |
2486 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); | 2538 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); |
2487 __ Jump(ic, RelocInfo::CODE_TARGET); | 2539 __ Jump(ic, RelocInfo::CODE_TARGET); |
2488 | 2540 |
(...skipping 940 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3429 // Need to perform int-to-float conversion. | 3481 // Need to perform int-to-float conversion. |
3430 __ cvtlsi2ss(xmm0, rdx); | 3482 __ cvtlsi2ss(xmm0, rdx); |
3431 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); | 3483 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); |
3432 break; | 3484 break; |
3433 case EXTERNAL_DOUBLE_ELEMENTS: | 3485 case EXTERNAL_DOUBLE_ELEMENTS: |
3434 // Need to perform int-to-float conversion. | 3486 // Need to perform int-to-float conversion. |
3435 __ cvtlsi2sd(xmm0, rdx); | 3487 __ cvtlsi2sd(xmm0, rdx); |
3436 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0); | 3488 __ movsd(Operand(rbx, rdi, times_8, 0), xmm0); |
3437 break; | 3489 break; |
3438 case FAST_ELEMENTS: | 3490 case FAST_ELEMENTS: |
| 3491 case FAST_SMI_ONLY_ELEMENTS: |
3439 case FAST_DOUBLE_ELEMENTS: | 3492 case FAST_DOUBLE_ELEMENTS: |
3440 case DICTIONARY_ELEMENTS: | 3493 case DICTIONARY_ELEMENTS: |
3441 case NON_STRICT_ARGUMENTS_ELEMENTS: | 3494 case NON_STRICT_ARGUMENTS_ELEMENTS: |
3442 UNREACHABLE(); | 3495 UNREACHABLE(); |
3443 break; | 3496 break; |
3444 } | 3497 } |
3445 __ ret(0); | 3498 __ ret(0); |
3446 | 3499 |
3447 // TODO(danno): handle heap number -> pixel array conversion | 3500 // TODO(danno): handle heap number -> pixel array conversion |
3448 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) { | 3501 if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3496 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3549 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
3497 // Convert to int64, so that NaN and infinities become | 3550 // Convert to int64, so that NaN and infinities become |
3498 // 0x8000000000000000, which is zero mod 2^32. | 3551 // 0x8000000000000000, which is zero mod 2^32. |
3499 __ cvttsd2siq(rdx, xmm0); | 3552 __ cvttsd2siq(rdx, xmm0); |
3500 __ movl(Operand(rbx, rdi, times_4, 0), rdx); | 3553 __ movl(Operand(rbx, rdi, times_4, 0), rdx); |
3501 break; | 3554 break; |
3502 case EXTERNAL_PIXEL_ELEMENTS: | 3555 case EXTERNAL_PIXEL_ELEMENTS: |
3503 case EXTERNAL_FLOAT_ELEMENTS: | 3556 case EXTERNAL_FLOAT_ELEMENTS: |
3504 case EXTERNAL_DOUBLE_ELEMENTS: | 3557 case EXTERNAL_DOUBLE_ELEMENTS: |
3505 case FAST_ELEMENTS: | 3558 case FAST_ELEMENTS: |
| 3559 case FAST_SMI_ONLY_ELEMENTS: |
3506 case FAST_DOUBLE_ELEMENTS: | 3560 case FAST_DOUBLE_ELEMENTS: |
3507 case DICTIONARY_ELEMENTS: | 3561 case DICTIONARY_ELEMENTS: |
3508 case NON_STRICT_ARGUMENTS_ELEMENTS: | 3562 case NON_STRICT_ARGUMENTS_ELEMENTS: |
3509 UNREACHABLE(); | 3563 UNREACHABLE(); |
3510 break; | 3564 break; |
3511 } | 3565 } |
3512 __ ret(0); | 3566 __ ret(0); |
3513 } | 3567 } |
3514 } | 3568 } |
3515 | 3569 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3627 masm->isolate()->builtins()->KeyedLoadIC_Slow(); | 3681 masm->isolate()->builtins()->KeyedLoadIC_Slow(); |
3628 __ jmp(slow_ic, RelocInfo::CODE_TARGET); | 3682 __ jmp(slow_ic, RelocInfo::CODE_TARGET); |
3629 | 3683 |
3630 __ bind(&miss_force_generic); | 3684 __ bind(&miss_force_generic); |
3631 Handle<Code> miss_ic = | 3685 Handle<Code> miss_ic = |
3632 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); | 3686 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
3633 __ jmp(miss_ic, RelocInfo::CODE_TARGET); | 3687 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
3634 } | 3688 } |
3635 | 3689 |
3636 | 3690 |
3637 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, | 3691 void KeyedStoreStubCompiler::GenerateStoreFastElement( |
3638 bool is_js_array) { | 3692 MacroAssembler* masm, |
| 3693 bool is_js_array, |
| 3694 ElementsKind elements_kind) { |
3639 // ----------- S t a t e ------------- | 3695 // ----------- S t a t e ------------- |
3640 // -- rax : value | 3696 // -- rax : value |
3641 // -- rcx : key | 3697 // -- rcx : key |
3642 // -- rdx : receiver | 3698 // -- rdx : receiver |
3643 // -- rsp[0] : return address | 3699 // -- rsp[0] : return address |
3644 // ----------------------------------- | 3700 // ----------------------------------- |
3645 Label miss_force_generic; | 3701 Label miss_force_generic; |
3646 | 3702 |
3647 // This stub is meant to be tail-jumped to, the receiver must already | 3703 // This stub is meant to be tail-jumped to, the receiver must already |
3648 // have been verified by the caller to not be a smi. | 3704 // have been verified by the caller to not be a smi. |
3649 | 3705 |
3650 // Check that the key is a smi. | 3706 // Check that the key is a smi. |
3651 __ JumpIfNotSmi(rcx, &miss_force_generic); | 3707 __ JumpIfNotSmi(rcx, &miss_force_generic); |
3652 | 3708 |
3653 // Get the elements array and make sure it is a fast element array, not 'cow'. | 3709 // Get the elements array and make sure it is a fast element array, not 'cow'. |
3654 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); | 3710 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); |
3655 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset), | 3711 __ CompareRoot(FieldOperand(rdi, HeapObject::kMapOffset), |
3656 Heap::kFixedArrayMapRootIndex); | 3712 Heap::kFixedArrayMapRootIndex); |
3657 __ j(not_equal, &miss_force_generic); | 3713 __ j(not_equal, &miss_force_generic); |
3658 | 3714 |
3659 // Check that the key is within bounds. | 3715 // Check that the key is within bounds. |
3660 if (is_js_array) { | 3716 if (is_js_array) { |
3661 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); | 3717 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); |
3662 __ j(above_equal, &miss_force_generic); | 3718 __ j(above_equal, &miss_force_generic); |
3663 } else { | 3719 } else { |
3664 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); | 3720 __ SmiCompare(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); |
3665 __ j(above_equal, &miss_force_generic); | 3721 __ j(above_equal, &miss_force_generic); |
3666 } | 3722 } |
3667 | 3723 |
3668 // Do the store and update the write barrier. Make sure to preserve | 3724 // Do the store and update the write barrier. |
3669 // the value in register eax. | 3725 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
3670 __ movq(rdx, rax); | 3726 __ JumpIfNotSmi(rax, &miss_force_generic); |
3671 __ SmiToInteger32(rcx, rcx); | 3727 __ SmiToInteger32(rcx, rcx); |
3672 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), | 3728 __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), |
3673 rax); | 3729 rax); |
3674 __ RecordWrite(rdi, 0, rdx, rcx); | 3730 } else { |
| 3731 ASSERT(elements_kind == FAST_ELEMENTS); |
| 3732 __ SmiToInteger32(rcx, rcx); |
| 3733 __ lea(rcx, |
| 3734 FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize)); |
| 3735 __ movq(Operand(rcx, 0), rax); |
| 3736 // Make sure to preserve the value in register rax. |
| 3737 __ movq(rdx, rax); |
| 3738 __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs); |
| 3739 } |
3675 | 3740 |
3676 // Done. | 3741 // Done. |
3677 __ ret(0); | 3742 __ ret(0); |
3678 | 3743 |
3679 // Handle store cache miss. | 3744 // Handle store cache miss. |
3680 __ bind(&miss_force_generic); | 3745 __ bind(&miss_force_generic); |
3681 Handle<Code> ic_force_generic = | 3746 Handle<Code> ic_force_generic = |
3682 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 3747 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
3683 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); | 3748 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
3684 } | 3749 } |
3685 | 3750 |
3686 | 3751 |
3687 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( | 3752 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( |
3688 MacroAssembler* masm, | 3753 MacroAssembler* masm, |
3689 bool is_js_array) { | 3754 bool is_js_array) { |
3690 // ----------- S t a t e ------------- | 3755 // ----------- S t a t e ------------- |
3691 // -- rax : value | 3756 // -- rax : value |
3692 // -- rcx : key | 3757 // -- rcx : key |
3693 // -- rdx : receiver | 3758 // -- rdx : receiver |
3694 // -- rsp[0] : return address | 3759 // -- rsp[0] : return address |
3695 // ----------------------------------- | 3760 // ----------------------------------- |
3696 Label miss_force_generic, smi_value, is_nan, maybe_nan; | 3761 Label miss_force_generic; |
3697 Label have_double_value, not_nan; | |
3698 | 3762 |
3699 // This stub is meant to be tail-jumped to, the receiver must already | 3763 // This stub is meant to be tail-jumped to, the receiver must already |
3700 // have been verified by the caller to not be a smi. | 3764 // have been verified by the caller to not be a smi. |
3701 | 3765 |
3702 // Check that the key is a smi. | 3766 // Check that the key is a smi. |
3703 __ JumpIfNotSmi(rcx, &miss_force_generic); | 3767 __ JumpIfNotSmi(rcx, &miss_force_generic); |
3704 | 3768 |
3705 // Get the elements array. | 3769 // Get the elements array. |
3706 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); | 3770 __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); |
3707 __ AssertFastElements(rdi); | 3771 __ AssertFastElements(rdi); |
3708 | 3772 |
3709 // Check that the key is within bounds. | 3773 // Check that the key is within bounds. |
3710 if (is_js_array) { | 3774 if (is_js_array) { |
3711 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); | 3775 __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); |
3712 } else { | 3776 } else { |
3713 __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset)); | 3777 __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset)); |
3714 } | 3778 } |
3715 __ j(above_equal, &miss_force_generic); | 3779 __ j(above_equal, &miss_force_generic); |
3716 | 3780 |
3717 // Handle smi values specially | 3781 // Handle smi values specially |
3718 __ JumpIfSmi(rax, &smi_value, Label::kNear); | |
3719 | |
3720 __ CheckMap(rax, | |
3721 masm->isolate()->factory()->heap_number_map(), | |
3722 &miss_force_generic, | |
3723 DONT_DO_SMI_CHECK); | |
3724 | |
3725 // Double value, canonicalize NaN. | |
3726 uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); | |
3727 __ cmpl(FieldOperand(rax, offset), | |
3728 Immediate(kNaNOrInfinityLowerBoundUpper32)); | |
3729 __ j(greater_equal, &maybe_nan, Label::kNear); | |
3730 | |
3731 __ bind(¬_nan); | |
3732 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); | |
3733 __ bind(&have_double_value); | |
3734 __ SmiToInteger32(rcx, rcx); | 3782 __ SmiToInteger32(rcx, rcx); |
3735 __ movsd(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize), | 3783 __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, &miss_force_generic); |
3736 xmm0); | |
3737 __ ret(0); | |
3738 | |
3739 __ bind(&maybe_nan); | |
3740 // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise | |
3741 // it's an Infinity, and the non-NaN code path applies. | |
3742 __ j(greater, &is_nan, Label::kNear); | |
3743 __ cmpl(FieldOperand(rax, HeapNumber::kValueOffset), Immediate(0)); | |
3744 __ j(zero, ¬_nan); | |
3745 __ bind(&is_nan); | |
3746 // Convert all NaNs to the same canonical NaN value when they are stored in | |
3747 // the double array. | |
3748 __ Set(kScratchRegister, BitCast<uint64_t>( | |
3749 FixedDoubleArray::canonical_not_the_hole_nan_as_double())); | |
3750 __ movq(xmm0, kScratchRegister); | |
3751 __ jmp(&have_double_value, Label::kNear); | |
3752 | |
3753 __ bind(&smi_value); | |
3754 // Value is a smi. convert to a double and store. | |
3755 // Preserve original value. | |
3756 __ SmiToInteger32(rdx, rax); | |
3757 __ push(rdx); | |
3758 __ fild_s(Operand(rsp, 0)); | |
3759 __ pop(rdx); | |
3760 __ SmiToInteger32(rcx, rcx); | |
3761 __ fstp_d(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize)); | |
3762 __ ret(0); | 3784 __ ret(0); |
3763 | 3785 |
3764 // Handle store cache miss, replacing the ic with the generic stub. | 3786 // Handle store cache miss, replacing the ic with the generic stub. |
3765 __ bind(&miss_force_generic); | 3787 __ bind(&miss_force_generic); |
3766 Handle<Code> ic_force_generic = | 3788 Handle<Code> ic_force_generic = |
3767 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 3789 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
3768 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); | 3790 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
3769 } | 3791 } |
3770 | 3792 |
3771 | 3793 |
3772 #undef __ | 3794 #undef __ |
3773 | 3795 |
3774 } } // namespace v8::internal | 3796 } } // namespace v8::internal |
3775 | 3797 |
3776 #endif // V8_TARGET_ARCH_X64 | 3798 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |