| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 29 matching lines...) Expand all Loading... |
| 40 // MacroAssembler implementation. | 40 // MacroAssembler implementation. |
| 41 | 41 |
| 42 MacroAssembler::MacroAssembler(void* buffer, int size) | 42 MacroAssembler::MacroAssembler(void* buffer, int size) |
| 43 : Assembler(buffer, size), | 43 : Assembler(buffer, size), |
| 44 generating_stub_(false), | 44 generating_stub_(false), |
| 45 allow_stub_calls_(true), | 45 allow_stub_calls_(true), |
| 46 code_object_(Heap::undefined_value()) { | 46 code_object_(Heap::undefined_value()) { |
| 47 } | 47 } |
| 48 | 48 |
| 49 | 49 |
| 50 static void RecordWriteHelper(MacroAssembler* masm, | 50 void MacroAssembler::RecordWriteHelper(Register object, |
| 51 Register object, | 51 Register addr, |
| 52 Register addr, | 52 Register scratch) { |
| 53 Register scratch) { | |
| 54 Label fast; | 53 Label fast; |
| 55 | 54 |
| 56 // Compute the page start address from the heap object pointer, and reuse | 55 // Compute the page start address from the heap object pointer, and reuse |
| 57 // the 'object' register for it. | 56 // the 'object' register for it. |
| 58 masm->and_(object, ~Page::kPageAlignmentMask); | 57 and_(object, ~Page::kPageAlignmentMask); |
| 59 Register page_start = object; | 58 Register page_start = object; |
| 60 | 59 |
| 61 // Compute the bit addr in the remembered set/index of the pointer in the | 60 // Compute the bit addr in the remembered set/index of the pointer in the |
| 62 // page. Reuse 'addr' as pointer_offset. | 61 // page. Reuse 'addr' as pointer_offset. |
| 63 masm->sub(addr, Operand(page_start)); | 62 sub(addr, Operand(page_start)); |
| 64 masm->shr(addr, kObjectAlignmentBits); | 63 shr(addr, kObjectAlignmentBits); |
| 65 Register pointer_offset = addr; | 64 Register pointer_offset = addr; |
| 66 | 65 |
| 67 // If the bit offset lies beyond the normal remembered set range, it is in | 66 // If the bit offset lies beyond the normal remembered set range, it is in |
| 68 // the extra remembered set area of a large object. | 67 // the extra remembered set area of a large object. |
| 69 masm->cmp(pointer_offset, Page::kPageSize / kPointerSize); | 68 cmp(pointer_offset, Page::kPageSize / kPointerSize); |
| 70 masm->j(less, &fast); | 69 j(less, &fast); |
| 71 | 70 |
| 72 // Adjust 'page_start' so that addressing using 'pointer_offset' hits the | 71 // Adjust 'page_start' so that addressing using 'pointer_offset' hits the |
| 73 // extra remembered set after the large object. | 72 // extra remembered set after the large object. |
| 74 | 73 |
| 75 // Find the length of the large object (FixedArray). | 74 // Find the length of the large object (FixedArray). |
| 76 masm->mov(scratch, Operand(page_start, Page::kObjectStartOffset | 75 mov(scratch, Operand(page_start, Page::kObjectStartOffset |
| 77 + FixedArray::kLengthOffset)); | 76 + FixedArray::kLengthOffset)); |
| 78 Register array_length = scratch; | 77 Register array_length = scratch; |
| 79 | 78 |
| 80 // Extra remembered set starts right after the large object (a FixedArray), at | 79 // Extra remembered set starts right after the large object (a FixedArray), at |
| 81 // page_start + kObjectStartOffset + objectSize | 80 // page_start + kObjectStartOffset + objectSize |
| 82 // where objectSize is FixedArray::kHeaderSize + kPointerSize * array_length. | 81 // where objectSize is FixedArray::kHeaderSize + kPointerSize * array_length. |
| 83 // Add the delta between the end of the normal RSet and the start of the | 82 // Add the delta between the end of the normal RSet and the start of the |
| 84 // extra RSet to 'page_start', so that addressing the bit using | 83 // extra RSet to 'page_start', so that addressing the bit using |
| 85 // 'pointer_offset' hits the extra RSet words. | 84 // 'pointer_offset' hits the extra RSet words. |
| 86 masm->lea(page_start, | 85 lea(page_start, |
| 87 Operand(page_start, array_length, times_pointer_size, | 86 Operand(page_start, array_length, times_pointer_size, |
| 88 Page::kObjectStartOffset + FixedArray::kHeaderSize | 87 Page::kObjectStartOffset + FixedArray::kHeaderSize |
| 89 - Page::kRSetEndOffset)); | 88 - Page::kRSetEndOffset)); |
| 90 | 89 |
| 91 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction | 90 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction |
| 92 // to limit code size. We should probably evaluate this decision by | 91 // to limit code size. We should probably evaluate this decision by |
| 93 // measuring the performance of an equivalent implementation using | 92 // measuring the performance of an equivalent implementation using |
| 94 // "simpler" instructions | 93 // "simpler" instructions |
| 95 masm->bind(&fast); | 94 bind(&fast); |
| 96 masm->bts(Operand(page_start, Page::kRSetOffset), pointer_offset); | 95 bts(Operand(page_start, Page::kRSetOffset), pointer_offset); |
| 97 } | 96 } |
| 98 | 97 |
| 99 | 98 |
| 100 class RecordWriteStub : public CodeStub { | 99 void MacroAssembler::InNewSpace(Register object, |
| 101 public: | 100 Register scratch, |
| 102 RecordWriteStub(Register object, Register addr, Register scratch) | 101 Condition cc, |
| 103 : object_(object), addr_(addr), scratch_(scratch) { } | 102 Label* branch) { |
| 104 | 103 if (Serializer::enabled()) { |
| 105 void Generate(MacroAssembler* masm); | 104 // Can't do arithmetic on external references if it might get serialized. |
| 106 | 105 mov(scratch, Operand(object)); |
| 107 private: | 106 // The mask isn't really an address. We load it as an external reference in |
| 108 Register object_; | 107 // case the size of the new space is different between the snapshot maker |
| 109 Register addr_; | 108 // and the running system. |
| 110 Register scratch_; | 109 and_(Operand(scratch), Immediate(ExternalReference::new_space_mask())); |
| 111 | 110 cmp(Operand(scratch), Immediate(ExternalReference::new_space_start())); |
| 112 #ifdef DEBUG | 111 j(cc, branch); |
| 113 void Print() { | 112 } else { |
| 114 PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n", | 113 int32_t new_space_start = reinterpret_cast<int32_t>( |
| 115 object_.code(), addr_.code(), scratch_.code()); | 114 ExternalReference::new_space_start().address()); |
| 115 lea(scratch, Operand(object, -new_space_start)); |
| 116 and_(scratch, Heap::NewSpaceMask()); |
| 117 j(cc, branch); |
| 116 } | 118 } |
| 117 #endif | |
| 118 | |
| 119 // Minor key encoding in 12 bits of three registers (object, address and | |
| 120 // scratch) OOOOAAAASSSS. | |
| 121 class ScratchBits: public BitField<uint32_t, 0, 4> {}; | |
| 122 class AddressBits: public BitField<uint32_t, 4, 4> {}; | |
| 123 class ObjectBits: public BitField<uint32_t, 8, 4> {}; | |
| 124 | |
| 125 Major MajorKey() { return RecordWrite; } | |
| 126 | |
| 127 int MinorKey() { | |
| 128 // Encode the registers. | |
| 129 return ObjectBits::encode(object_.code()) | | |
| 130 AddressBits::encode(addr_.code()) | | |
| 131 ScratchBits::encode(scratch_.code()); | |
| 132 } | |
| 133 }; | |
| 134 | |
| 135 | |
| 136 void RecordWriteStub::Generate(MacroAssembler* masm) { | |
| 137 RecordWriteHelper(masm, object_, addr_, scratch_); | |
| 138 masm->ret(0); | |
| 139 } | 119 } |
| 140 | 120 |
| 141 | 121 |
| 142 // Set the remembered set bit for [object+offset]. | 122 // Set the remembered set bit for [object+offset]. |
| 143 // object is the object being stored into, value is the object being stored. | 123 // object is the object being stored into, value is the object being stored. |
| 144 // If offset is zero, then the scratch register contains the array index into | 124 // If offset is zero, then the scratch register contains the array index into |
| 145 // the elements array represented as a Smi. | 125 // the elements array represented as a Smi. |
| 146 // All registers are clobbered by the operation. | 126 // All registers are clobbered by the operation. |
| 147 void MacroAssembler::RecordWrite(Register object, int offset, | 127 void MacroAssembler::RecordWrite(Register object, int offset, |
| 148 Register value, Register scratch) { | 128 Register value, Register scratch) { |
| 149 // The compiled code assumes that record write doesn't change the | 129 // The compiled code assumes that record write doesn't change the |
| 150 // context register, so we check that none of the clobbered | 130 // context register, so we check that none of the clobbered |
| 151 // registers are esi. | 131 // registers are esi. |
| 152 ASSERT(!object.is(esi) && !value.is(esi) && !scratch.is(esi)); | 132 ASSERT(!object.is(esi) && !value.is(esi) && !scratch.is(esi)); |
| 153 | 133 |
| 154 // First, check if a remembered set write is even needed. The tests below | 134 // First, check if a remembered set write is even needed. The tests below |
| 155 // catch stores of Smis and stores into young gen (which does not have space | 135 // catch stores of Smis and stores into young gen (which does not have space |
| 156 // for the remembered set bits. | 136 // for the remembered set bits. |
| 157 Label done; | 137 Label done; |
| 158 | 138 |
| 159 // Skip barrier if writing a smi. | 139 // Skip barrier if writing a smi. |
| 160 ASSERT_EQ(0, kSmiTag); | 140 ASSERT_EQ(0, kSmiTag); |
| 161 test(value, Immediate(kSmiTagMask)); | 141 test(value, Immediate(kSmiTagMask)); |
| 162 j(zero, &done); | 142 j(zero, &done); |
| 163 | 143 |
| 164 if (Serializer::enabled()) { | 144 InNewSpace(object, value, equal, &done); |
| 165 // Can't do arithmetic on external references if it might get serialized. | |
| 166 mov(value, Operand(object)); | |
| 167 // The mask isn't really an address. We load it as an external reference in | |
| 168 // case the size of the new space is different between the snapshot maker | |
| 169 // and the running system. | |
| 170 and_(Operand(value), Immediate(ExternalReference::new_space_mask())); | |
| 171 cmp(Operand(value), Immediate(ExternalReference::new_space_start())); | |
| 172 j(equal, &done); | |
| 173 } else { | |
| 174 int32_t new_space_start = reinterpret_cast<int32_t>( | |
| 175 ExternalReference::new_space_start().address()); | |
| 176 lea(value, Operand(object, -new_space_start)); | |
| 177 and_(value, Heap::NewSpaceMask()); | |
| 178 j(equal, &done); | |
| 179 } | |
| 180 | 145 |
| 181 if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) { | 146 if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) { |
| 182 // Compute the bit offset in the remembered set, leave it in 'value'. | 147 // Compute the bit offset in the remembered set, leave it in 'value'. |
| 183 lea(value, Operand(object, offset)); | 148 lea(value, Operand(object, offset)); |
| 184 and_(value, Page::kPageAlignmentMask); | 149 and_(value, Page::kPageAlignmentMask); |
| 185 shr(value, kPointerSizeLog2); | 150 shr(value, kPointerSizeLog2); |
| 186 | 151 |
| 187 // Compute the page address from the heap object pointer, leave it in | 152 // Compute the page address from the heap object pointer, leave it in |
| 188 // 'object'. | 153 // 'object'. |
| 189 and_(object, ~Page::kPageAlignmentMask); | 154 and_(object, ~Page::kPageAlignmentMask); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 202 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset | 167 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset |
| 203 // into an array of words. | 168 // into an array of words. |
| 204 ASSERT_EQ(1, kSmiTagSize); | 169 ASSERT_EQ(1, kSmiTagSize); |
| 205 ASSERT_EQ(0, kSmiTag); | 170 ASSERT_EQ(0, kSmiTag); |
| 206 lea(dst, Operand(object, dst, times_half_pointer_size, | 171 lea(dst, Operand(object, dst, times_half_pointer_size, |
| 207 FixedArray::kHeaderSize - kHeapObjectTag)); | 172 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 208 } | 173 } |
| 209 // If we are already generating a shared stub, not inlining the | 174 // If we are already generating a shared stub, not inlining the |
| 210 // record write code isn't going to save us any memory. | 175 // record write code isn't going to save us any memory. |
| 211 if (generating_stub()) { | 176 if (generating_stub()) { |
| 212 RecordWriteHelper(this, object, dst, value); | 177 RecordWriteHelper(object, dst, value); |
| 213 } else { | 178 } else { |
| 214 RecordWriteStub stub(object, dst, value); | 179 RecordWriteStub stub(object, dst, value); |
| 215 CallStub(&stub); | 180 CallStub(&stub); |
| 216 } | 181 } |
| 217 } | 182 } |
| 218 | 183 |
| 219 bind(&done); | 184 bind(&done); |
| 220 | 185 |
| 221 // Clobber all input registers when running with the debug-code flag | 186 // Clobber all input registers when running with the debug-code flag |
| 222 // turned on to provoke errors. | 187 // turned on to provoke errors. |
| (...skipping 1456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1679 // Indicate that code has changed. | 1644 // Indicate that code has changed. |
| 1680 CPU::FlushICache(address_, size_); | 1645 CPU::FlushICache(address_, size_); |
| 1681 | 1646 |
| 1682 // Check that the code was patched as expected. | 1647 // Check that the code was patched as expected. |
| 1683 ASSERT(masm_.pc_ == address_ + size_); | 1648 ASSERT(masm_.pc_ == address_ + size_); |
| 1684 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 1649 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 1685 } | 1650 } |
| 1686 | 1651 |
| 1687 | 1652 |
| 1688 } } // namespace v8::internal | 1653 } } // namespace v8::internal |
| OLD | NEW |