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 |