OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 | 94 |
95 // Compute the bit addr in the remembered set/index of the pointer in the | 95 // Compute the bit addr in the remembered set/index of the pointer in the |
96 // page. Reuse 'addr' as pointer_offset. | 96 // page. Reuse 'addr' as pointer_offset. |
97 subq(addr, page_start); | 97 subq(addr, page_start); |
98 shr(addr, Immediate(kPointerSizeLog2)); | 98 shr(addr, Immediate(kPointerSizeLog2)); |
99 Register pointer_offset = addr; | 99 Register pointer_offset = addr; |
100 | 100 |
101 // If the bit offset lies beyond the normal remembered set range, it is in | 101 // If the bit offset lies beyond the normal remembered set range, it is in |
102 // the extra remembered set area of a large object. | 102 // the extra remembered set area of a large object. |
103 cmpq(pointer_offset, Immediate(Page::kPageSize / kPointerSize)); | 103 cmpq(pointer_offset, Immediate(Page::kPageSize / kPointerSize)); |
104 j(less, &fast); | 104 j(below, &fast); |
| 105 |
| 106 // We have a large object containing pointers. It must be a FixedArray. |
105 | 107 |
106 // Adjust 'page_start' so that addressing using 'pointer_offset' hits the | 108 // Adjust 'page_start' so that addressing using 'pointer_offset' hits the |
107 // extra remembered set after the large object. | 109 // extra remembered set after the large object. |
108 | 110 |
109 // Load the array length into 'scratch'. | 111 // Load the array length into 'scratch'. |
110 movl(scratch, | 112 movl(scratch, |
111 Operand(page_start, | 113 Operand(page_start, |
112 Page::kObjectStartOffset + FixedArray::kLengthOffset)); | 114 Page::kObjectStartOffset + FixedArray::kLengthOffset)); |
113 Register array_length = scratch; | 115 Register array_length = scratch; |
114 | 116 |
115 // Extra remembered set starts right after the large object (a FixedArray), at | 117 // Extra remembered set starts right after the large object (a FixedArray), at |
116 // page_start + kObjectStartOffset + objectSize | 118 // page_start + kObjectStartOffset + objectSize |
117 // where objectSize is FixedArray::kHeaderSize + kPointerSize * array_length. | 119 // where objectSize is FixedArray::kHeaderSize + kPointerSize * array_length. |
118 // Add the delta between the end of the normal RSet and the start of the | 120 // Add the delta between the end of the normal RSet and the start of the |
119 // extra RSet to 'page_start', so that addressing the bit using | 121 // extra RSet to 'page_start', so that addressing the bit using |
120 // 'pointer_offset' hits the extra RSet words. | 122 // 'pointer_offset' hits the extra RSet words. |
121 lea(page_start, | 123 lea(page_start, |
122 Operand(page_start, array_length, times_pointer_size, | 124 Operand(page_start, array_length, times_pointer_size, |
123 Page::kObjectStartOffset + FixedArray::kHeaderSize | 125 Page::kObjectStartOffset + FixedArray::kHeaderSize |
124 - Page::kRSetEndOffset)); | 126 - Page::kRSetEndOffset)); |
125 | 127 |
126 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction | 128 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction |
127 // to limit code size. We should probably evaluate this decision by | 129 // to limit code size. We should probably evaluate this decision by |
128 // measuring the performance of an equivalent implementation using | 130 // measuring the performance of an equivalent implementation using |
129 // "simpler" instructions | 131 // "simpler" instructions |
130 bind(&fast); | 132 bind(&fast); |
131 bts(Operand(page_start, Page::kRSetOffset), pointer_offset); | 133 bts(Operand(page_start, Page::kRSetOffset), pointer_offset); |
132 } | 134 } |
133 | 135 |
134 | 136 |
135 void MacroAssembler::InNewSpace(Register object, | |
136 Register scratch, | |
137 Condition cc, | |
138 Label* branch) { | |
139 ASSERT(cc == equal || cc == not_equal); | |
140 if (!scratch.is(object)) { | |
141 movq(scratch, object); | |
142 } | |
143 ASSERT(is_int32(static_cast<int64_t>(Heap::NewSpaceMask()))); | |
144 and_(scratch, Immediate(static_cast<int32_t>(Heap::NewSpaceMask()))); | |
145 movq(kScratchRegister, ExternalReference::new_space_start()); | |
146 cmpq(scratch, kScratchRegister); | |
147 j(cc, branch); | |
148 } | |
149 | |
150 | |
151 // Set the remembered set bit for [object+offset]. | 137 // Set the remembered set bit for [object+offset]. |
152 // object is the object being stored into, value is the object being stored. | 138 // object is the object being stored into, value is the object being stored. |
153 // If offset is zero, then the smi_index register contains the array index into | 139 // If offset is zero, then the smi_index register contains the array index into |
154 // the elements array represented as a smi. Otherwise it can be used as a | 140 // the elements array represented as a smi. Otherwise it can be used as a |
155 // scratch register. | 141 // scratch register. |
156 // All registers are clobbered by the operation. | 142 // All registers are clobbered by the operation. |
157 void MacroAssembler::RecordWrite(Register object, | 143 void MacroAssembler::RecordWrite(Register object, |
158 int offset, | 144 int offset, |
159 Register value, | 145 Register value, |
160 Register smi_index) { | 146 Register smi_index) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 // so either offset or offset + kHeapObjectTag must be a | 192 // so either offset or offset + kHeapObjectTag must be a |
207 // multiple of kPointerSize. | 193 // multiple of kPointerSize. |
208 ASSERT(IsAligned(offset, kPointerSize) || | 194 ASSERT(IsAligned(offset, kPointerSize) || |
209 IsAligned(offset + kHeapObjectTag, kPointerSize)); | 195 IsAligned(offset + kHeapObjectTag, kPointerSize)); |
210 | 196 |
211 // We use optimized write barrier code if the word being written to is not in | 197 // We use optimized write barrier code if the word being written to is not in |
212 // a large object page, or is in the first "page" of a large object page. | 198 // a large object page, or is in the first "page" of a large object page. |
213 // We make sure that an offset is inside the right limits whether it is | 199 // We make sure that an offset is inside the right limits whether it is |
214 // tagged or untagged. | 200 // tagged or untagged. |
215 if ((offset > 0) && (offset < Page::kMaxHeapObjectSize - kHeapObjectTag)) { | 201 if ((offset > 0) && (offset < Page::kMaxHeapObjectSize - kHeapObjectTag)) { |
216 // Compute the bit offset in the remembered set, leave it in 'value'. | 202 // Compute the bit offset in the remembered set, leave it in 'scratch'. |
217 lea(scratch, Operand(object, offset)); | 203 lea(scratch, Operand(object, offset)); |
218 ASSERT(is_int32(Page::kPageAlignmentMask)); | 204 ASSERT(is_int32(Page::kPageAlignmentMask)); |
219 and_(scratch, Immediate(static_cast<int32_t>(Page::kPageAlignmentMask))); | 205 and_(scratch, Immediate(static_cast<int32_t>(Page::kPageAlignmentMask))); |
220 shr(scratch, Immediate(kObjectAlignmentBits)); | 206 shr(scratch, Immediate(kPointerSizeLog2)); |
221 | 207 |
222 // Compute the page address from the heap object pointer, leave it in | 208 // Compute the page address from the heap object pointer, leave it in |
223 // 'object' (immediate value is sign extended). | 209 // 'object' (immediate value is sign extended). |
224 and_(object, Immediate(~Page::kPageAlignmentMask)); | 210 and_(object, Immediate(~Page::kPageAlignmentMask)); |
225 | 211 |
226 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction | 212 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction |
227 // to limit code size. We should probably evaluate this decision by | 213 // to limit code size. We should probably evaluate this decision by |
228 // measuring the performance of an equivalent implementation using | 214 // measuring the performance of an equivalent implementation using |
229 // "simpler" instructions | 215 // "simpler" instructions |
230 bts(Operand(object, Page::kRSetOffset), scratch); | 216 bts(Operand(object, Page::kRSetOffset), scratch); |
231 } else { | 217 } else { |
232 Register dst = smi_index; | 218 Register dst = smi_index; |
233 if (offset != 0) { | 219 if (offset != 0) { |
234 lea(dst, Operand(object, offset)); | 220 lea(dst, Operand(object, offset)); |
235 } else { | 221 } else { |
236 // array access: calculate the destination address in the same manner as | 222 // array access: calculate the destination address in the same manner as |
237 // KeyedStoreIC::GenerateGeneric. | 223 // KeyedStoreIC::GenerateGeneric. |
238 SmiIndex index = SmiToIndex(smi_index, smi_index, kPointerSizeLog2); | 224 SmiIndex index = SmiToIndex(smi_index, smi_index, kPointerSizeLog2); |
239 lea(dst, Operand(object, | 225 lea(dst, FieldOperand(object, |
240 index.reg, | 226 index.reg, |
241 index.scale, | 227 index.scale, |
242 FixedArray::kHeaderSize - kHeapObjectTag)); | 228 FixedArray::kHeaderSize)); |
243 } | 229 } |
244 // If we are already generating a shared stub, not inlining the | 230 // If we are already generating a shared stub, not inlining the |
245 // record write code isn't going to save us any memory. | 231 // record write code isn't going to save us any memory. |
246 if (generating_stub()) { | 232 if (generating_stub()) { |
247 RecordWriteHelper(object, dst, scratch); | 233 RecordWriteHelper(object, dst, scratch); |
248 } else { | 234 } else { |
249 RecordWriteStub stub(object, dst, scratch); | 235 RecordWriteStub stub(object, dst, scratch); |
250 CallStub(&stub); | 236 CallStub(&stub); |
251 } | 237 } |
252 } | 238 } |
253 | 239 |
254 bind(&done); | 240 bind(&done); |
255 | 241 |
256 // Clobber all input registers when running with the debug-code flag | 242 // Clobber all input registers when running with the debug-code flag |
257 // turned on to provoke errors. | 243 // turned on to provoke errors. |
258 if (FLAG_debug_code) { | 244 if (FLAG_debug_code) { |
259 movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | 245 movq(object, BitCast<int64_t>(kZapValue), RelocInfo::NONE); |
260 movq(scratch, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | 246 movq(scratch, BitCast<int64_t>(kZapValue), RelocInfo::NONE); |
261 movq(smi_index, BitCast<int64_t>(kZapValue), RelocInfo::NONE); | 247 movq(smi_index, BitCast<int64_t>(kZapValue), RelocInfo::NONE); |
262 } | 248 } |
263 } | 249 } |
264 | 250 |
265 | 251 |
| 252 void MacroAssembler::InNewSpace(Register object, |
| 253 Register scratch, |
| 254 Condition cc, |
| 255 Label* branch) { |
| 256 if (Serializer::enabled()) { |
| 257 // Can't do arithmetic on external references if it might get serialized. |
| 258 // The mask isn't really an address. We load it as an external reference in |
| 259 // case the size of the new space is different between the snapshot maker |
| 260 // and the running system. |
| 261 if (scratch.is(object)) { |
| 262 movq(kScratchRegister, ExternalReference::new_space_mask()); |
| 263 and_(scratch, kScratchRegister); |
| 264 } else { |
| 265 movq(scratch, ExternalReference::new_space_mask()); |
| 266 and_(scratch, object); |
| 267 } |
| 268 movq(kScratchRegister, ExternalReference::new_space_start()); |
| 269 cmpq(scratch, kScratchRegister); |
| 270 j(cc, branch); |
| 271 } else { |
| 272 ASSERT(is_int32(static_cast<int64_t>(Heap::NewSpaceMask()))); |
| 273 intptr_t new_space_start = |
| 274 reinterpret_cast<intptr_t>(Heap::NewSpaceStart()); |
| 275 movq(kScratchRegister, -new_space_start, RelocInfo::NONE); |
| 276 if (scratch.is(object)) { |
| 277 addq(scratch, kScratchRegister); |
| 278 } else { |
| 279 lea(scratch, Operand(object, kScratchRegister, times_1, 0)); |
| 280 } |
| 281 and_(scratch, Immediate(static_cast<int32_t>(Heap::NewSpaceMask()))); |
| 282 j(cc, branch); |
| 283 } |
| 284 } |
| 285 |
| 286 |
266 void MacroAssembler::Assert(Condition cc, const char* msg) { | 287 void MacroAssembler::Assert(Condition cc, const char* msg) { |
267 if (FLAG_debug_code) Check(cc, msg); | 288 if (FLAG_debug_code) Check(cc, msg); |
268 } | 289 } |
269 | 290 |
270 | 291 |
271 void MacroAssembler::Check(Condition cc, const char* msg) { | 292 void MacroAssembler::Check(Condition cc, const char* msg) { |
272 Label L; | 293 Label L; |
273 j(cc, &L); | 294 j(cc, &L); |
274 Abort(msg); | 295 Abort(msg); |
275 // will not return here | 296 // will not return here |
(...skipping 1878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2154 // registers. | 2175 // registers. |
2155 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg)); | 2176 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg)); |
2156 | 2177 |
2157 // Keep track of the current object in register reg. On the first | 2178 // Keep track of the current object in register reg. On the first |
2158 // iteration, reg is an alias for object_reg, on later iterations, | 2179 // iteration, reg is an alias for object_reg, on later iterations, |
2159 // it is an alias for holder_reg. | 2180 // it is an alias for holder_reg. |
2160 Register reg = object_reg; | 2181 Register reg = object_reg; |
2161 int depth = 0; | 2182 int depth = 0; |
2162 | 2183 |
2163 if (save_at_depth == depth) { | 2184 if (save_at_depth == depth) { |
2164 movq(Operand(rsp, kPointerSize), reg); | 2185 movq(Operand(rsp, kPointerSize), object_reg); |
2165 } | 2186 } |
2166 | 2187 |
2167 // Check the maps in the prototype chain. | 2188 // Check the maps in the prototype chain. |
2168 // Traverse the prototype chain from the object and do map checks. | 2189 // Traverse the prototype chain from the object and do map checks. |
2169 while (object != holder) { | 2190 while (object != holder) { |
2170 depth++; | 2191 depth++; |
2171 | 2192 |
2172 // Only global objects and objects that do not require access | 2193 // Only global objects and objects that do not require access |
2173 // checks are allowed in stubs. | 2194 // checks are allowed in stubs. |
2174 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 2195 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2680 CodePatcher::~CodePatcher() { | 2701 CodePatcher::~CodePatcher() { |
2681 // Indicate that code has changed. | 2702 // Indicate that code has changed. |
2682 CPU::FlushICache(address_, size_); | 2703 CPU::FlushICache(address_, size_); |
2683 | 2704 |
2684 // Check that the code was patched as expected. | 2705 // Check that the code was patched as expected. |
2685 ASSERT(masm_.pc_ == address_ + size_); | 2706 ASSERT(masm_.pc_ == address_ + size_); |
2686 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 2707 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
2687 } | 2708 } |
2688 | 2709 |
2689 } } // namespace v8::internal | 2710 } } // namespace v8::internal |
OLD | NEW |