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