| 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 Register addr, | 51 Register addr, |
| 52 Register scratch) { | 52 Register scratch) { |
| 53 if (FLAG_debug_code) { | 53 if (FLAG_debug_code) { |
| 54 // Check that the object is not in new space. | 54 // Check that the object is not in new space. |
| 55 Label not_in_new_space; | 55 Label not_in_new_space; |
| 56 InNewSpace(object, scratch, not_equal, ¬_in_new_space); | 56 InNewSpace(object, scratch, not_equal, ¬_in_new_space); |
| 57 Abort("new-space object passed to RecordWriteHelper"); | 57 Abort("new-space object passed to RecordWriteHelper"); |
| 58 bind(¬_in_new_space); | 58 bind(¬_in_new_space); |
| 59 } | 59 } |
| 60 | 60 |
| 61 Label fast; | |
| 62 | |
| 63 // Compute the page start address from the heap object pointer, and reuse | 61 // Compute the page start address from the heap object pointer, and reuse |
| 64 // the 'object' register for it. | 62 // the 'object' register for it. |
| 65 and_(object, ~Page::kPageAlignmentMask); | 63 and_(object, ~Page::kPageAlignmentMask); |
| 66 Register page_start = object; | |
| 67 | 64 |
| 68 // Compute the bit addr in the remembered set/index of the pointer in the | 65 // Compute number of region covering addr. See Page::GetRegionNumberForAddress |
| 69 // page. Reuse 'addr' as pointer_offset. | 66 // method for more details. |
| 70 sub(addr, Operand(page_start)); | 67 and_(addr, Page::kPageAlignmentMask); |
| 71 shr(addr, kObjectAlignmentBits); | 68 shr(addr, Page::kRegionSizeLog2); |
| 72 Register pointer_offset = addr; | |
| 73 | 69 |
| 74 // If the bit offset lies beyond the normal remembered set range, it is in | 70 // Set dirty mark for region. |
| 75 // the extra remembered set area of a large object. | 71 bts(Operand(object, Page::kDirtyFlagOffset), addr); |
| 76 cmp(pointer_offset, Page::kPageSize / kPointerSize); | |
| 77 j(less, &fast); | |
| 78 | |
| 79 // Adjust 'page_start' so that addressing using 'pointer_offset' hits the | |
| 80 // extra remembered set after the large object. | |
| 81 | |
| 82 // Find the length of the large object (FixedArray). | |
| 83 mov(scratch, Operand(page_start, Page::kObjectStartOffset | |
| 84 + FixedArray::kLengthOffset)); | |
| 85 Register array_length = scratch; | |
| 86 | |
| 87 // Extra remembered set starts right after the large object (a FixedArray), at | |
| 88 // page_start + kObjectStartOffset + objectSize | |
| 89 // where objectSize is FixedArray::kHeaderSize + kPointerSize * array_length. | |
| 90 // Add the delta between the end of the normal RSet and the start of the | |
| 91 // extra RSet to 'page_start', so that addressing the bit using | |
| 92 // 'pointer_offset' hits the extra RSet words. | |
| 93 lea(page_start, | |
| 94 Operand(page_start, array_length, times_pointer_size, | |
| 95 Page::kObjectStartOffset + FixedArray::kHeaderSize | |
| 96 - Page::kRSetEndOffset)); | |
| 97 | |
| 98 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction | |
| 99 // to limit code size. We should probably evaluate this decision by | |
| 100 // measuring the performance of an equivalent implementation using | |
| 101 // "simpler" instructions | |
| 102 bind(&fast); | |
| 103 bts(Operand(page_start, Page::kRSetOffset), pointer_offset); | |
| 104 } | 72 } |
| 105 | 73 |
| 106 | 74 |
| 107 void MacroAssembler::InNewSpace(Register object, | 75 void MacroAssembler::InNewSpace(Register object, |
| 108 Register scratch, | 76 Register scratch, |
| 109 Condition cc, | 77 Condition cc, |
| 110 Label* branch) { | 78 Label* branch) { |
| 111 ASSERT(cc == equal || cc == not_equal); | 79 ASSERT(cc == equal || cc == not_equal); |
| 112 if (Serializer::enabled()) { | 80 if (Serializer::enabled()) { |
| 113 // Can't do arithmetic on external references if it might get serialized. | 81 // Can't do arithmetic on external references if it might get serialized. |
| 114 mov(scratch, Operand(object)); | 82 mov(scratch, Operand(object)); |
| 115 // The mask isn't really an address. We load it as an external reference in | 83 // The mask isn't really an address. We load it as an external reference in |
| 116 // case the size of the new space is different between the snapshot maker | 84 // case the size of the new space is different between the snapshot maker |
| 117 // and the running system. | 85 // and the running system. |
| 118 and_(Operand(scratch), Immediate(ExternalReference::new_space_mask())); | 86 and_(Operand(scratch), Immediate(ExternalReference::new_space_mask())); |
| 119 cmp(Operand(scratch), Immediate(ExternalReference::new_space_start())); | 87 cmp(Operand(scratch), Immediate(ExternalReference::new_space_start())); |
| 120 j(cc, branch); | 88 j(cc, branch); |
| 121 } else { | 89 } else { |
| 122 int32_t new_space_start = reinterpret_cast<int32_t>( | 90 int32_t new_space_start = reinterpret_cast<int32_t>( |
| 123 ExternalReference::new_space_start().address()); | 91 ExternalReference::new_space_start().address()); |
| 124 lea(scratch, Operand(object, -new_space_start)); | 92 lea(scratch, Operand(object, -new_space_start)); |
| 125 and_(scratch, Heap::NewSpaceMask()); | 93 and_(scratch, Heap::NewSpaceMask()); |
| 126 j(cc, branch); | 94 j(cc, branch); |
| 127 } | 95 } |
| 128 } | 96 } |
| 129 | 97 |
| 130 | 98 |
| 131 // Set the remembered set bit for [object+offset]. | 99 // For page containing |object| mark region covering [object+offset] dirty. |
| 132 // object is the object being stored into, value is the object being stored. | 100 // object is the object being stored into, value is the object being stored. |
| 133 // If offset is zero, then the scratch register contains the array index into | 101 // If offset is zero, then the scratch register contains the array index into |
| 134 // the elements array represented as a Smi. | 102 // the elements array represented as a Smi. |
| 135 // All registers are clobbered by the operation. | 103 // All registers are clobbered by the operation. |
| 136 void MacroAssembler::RecordWrite(Register object, int offset, | 104 void MacroAssembler::RecordWrite(Register object, int offset, |
| 137 Register value, Register scratch) { | 105 Register value, Register scratch) { |
| 138 // The compiled code assumes that record write doesn't change the | 106 // The compiled code assumes that record write doesn't change the |
| 139 // context register, so we check that none of the clobbered | 107 // context register, so we check that none of the clobbered |
| 140 // registers are esi. | 108 // registers are esi. |
| 141 ASSERT(!object.is(esi) && !value.is(esi) && !scratch.is(esi)); | 109 ASSERT(!object.is(esi) && !value.is(esi) && !scratch.is(esi)); |
| 142 | 110 |
| 143 // First, check if a remembered set write is even needed. The tests below | 111 // First, check if a write barrier is even needed. The tests below |
| 144 // catch stores of Smis and stores into young gen (which does not have space | 112 // catch stores of Smis and stores into young gen. |
| 145 // for the remembered set bits). | |
| 146 Label done; | 113 Label done; |
| 147 | 114 |
| 148 // Skip barrier if writing a smi. | 115 // Skip barrier if writing a smi. |
| 149 ASSERT_EQ(0, kSmiTag); | 116 ASSERT_EQ(0, kSmiTag); |
| 150 test(value, Immediate(kSmiTagMask)); | 117 test(value, Immediate(kSmiTagMask)); |
| 151 j(zero, &done); | 118 j(zero, &done); |
| 152 | 119 |
| 153 InNewSpace(object, value, equal, &done); | 120 InNewSpace(object, value, equal, &done); |
| 154 | 121 |
| 155 // The offset is relative to a tagged or untagged HeapObject pointer, | 122 // The offset is relative to a tagged or untagged HeapObject pointer, |
| 156 // so either offset or offset + kHeapObjectTag must be a | 123 // so either offset or offset + kHeapObjectTag must be a |
| 157 // multiple of kPointerSize. | 124 // multiple of kPointerSize. |
| 158 ASSERT(IsAligned(offset, kPointerSize) || | 125 ASSERT(IsAligned(offset, kPointerSize) || |
| 159 IsAligned(offset + kHeapObjectTag, kPointerSize)); | 126 IsAligned(offset + kHeapObjectTag, kPointerSize)); |
| 160 | 127 |
| 161 // We use optimized write barrier code if the word being written to is not in | 128 Register dst = scratch; |
| 162 // a large object chunk or is in the first page of a large object chunk. | 129 if (offset != 0) { |
| 163 // We make sure that an offset is inside the right limits whether it is | 130 lea(dst, Operand(object, offset)); |
| 164 // tagged or untagged. | |
| 165 if ((offset > 0) && (offset < Page::kMaxHeapObjectSize - kHeapObjectTag)) { | |
| 166 // Compute the bit offset in the remembered set, leave it in 'value'. | |
| 167 lea(value, Operand(object, offset)); | |
| 168 and_(value, Page::kPageAlignmentMask); | |
| 169 shr(value, kPointerSizeLog2); | |
| 170 | |
| 171 // Compute the page address from the heap object pointer, leave it in | |
| 172 // 'object'. | |
| 173 and_(object, ~Page::kPageAlignmentMask); | |
| 174 | |
| 175 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction | |
| 176 // to limit code size. We should probably evaluate this decision by | |
| 177 // measuring the performance of an equivalent implementation using | |
| 178 // "simpler" instructions | |
| 179 bts(Operand(object, Page::kRSetOffset), value); | |
| 180 } else { | 131 } else { |
| 181 Register dst = scratch; | 132 // Array access: calculate the destination address in the same manner as |
| 182 if (offset != 0) { | 133 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset |
| 183 lea(dst, Operand(object, offset)); | 134 // into an array of words. |
| 184 } else { | 135 ASSERT_EQ(1, kSmiTagSize); |
| 185 // array access: calculate the destination address in the same manner as | 136 ASSERT_EQ(0, kSmiTag); |
| 186 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset | 137 lea(dst, Operand(object, dst, times_half_pointer_size, |
| 187 // into an array of words. | 138 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 188 ASSERT_EQ(1, kSmiTagSize); | |
| 189 ASSERT_EQ(0, kSmiTag); | |
| 190 lea(dst, Operand(object, dst, times_half_pointer_size, | |
| 191 FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 192 } | |
| 193 // If we are already generating a shared stub, not inlining the | |
| 194 // record write code isn't going to save us any memory. | |
| 195 if (generating_stub()) { | |
| 196 RecordWriteHelper(object, dst, value); | |
| 197 } else { | |
| 198 RecordWriteStub stub(object, dst, value); | |
| 199 CallStub(&stub); | |
| 200 } | |
| 201 } | 139 } |
| 140 RecordWriteHelper(object, dst, value); |
| 202 | 141 |
| 203 bind(&done); | 142 bind(&done); |
| 204 | 143 |
| 205 // Clobber all input registers when running with the debug-code flag | 144 // Clobber all input registers when running with the debug-code flag |
| 206 // turned on to provoke errors. | 145 // turned on to provoke errors. |
| 207 if (FLAG_debug_code) { | 146 if (FLAG_debug_code) { |
| 208 mov(object, Immediate(BitCast<int32_t>(kZapValue))); | 147 mov(object, Immediate(BitCast<int32_t>(kZapValue))); |
| 209 mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 148 mov(value, Immediate(BitCast<int32_t>(kZapValue))); |
| 210 mov(scratch, Immediate(BitCast<int32_t>(kZapValue))); | 149 mov(scratch, Immediate(BitCast<int32_t>(kZapValue))); |
| 211 } | 150 } |
| (...skipping 1163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1375 } | 1314 } |
| 1376 | 1315 |
| 1377 | 1316 |
| 1378 void MacroAssembler::InvokeFunction(Register fun, | 1317 void MacroAssembler::InvokeFunction(Register fun, |
| 1379 const ParameterCount& actual, | 1318 const ParameterCount& actual, |
| 1380 InvokeFlag flag) { | 1319 InvokeFlag flag) { |
| 1381 ASSERT(fun.is(edi)); | 1320 ASSERT(fun.is(edi)); |
| 1382 mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 1321 mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 1383 mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 1322 mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 1384 mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); | 1323 mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); |
| 1324 SmiUntag(ebx); |
| 1385 mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); | 1325 mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); |
| 1386 lea(edx, FieldOperand(edx, Code::kHeaderSize)); | 1326 lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
| 1387 | 1327 |
| 1388 ParameterCount expected(ebx); | 1328 ParameterCount expected(ebx); |
| 1389 InvokeCode(Operand(edx), expected, actual, flag); | 1329 InvokeCode(Operand(edx), expected, actual, flag); |
| 1390 } | 1330 } |
| 1391 | 1331 |
| 1392 | 1332 |
| 1393 void MacroAssembler::InvokeFunction(JSFunction* function, | 1333 void MacroAssembler::InvokeFunction(JSFunction* function, |
| 1394 const ParameterCount& actual, | 1334 const ParameterCount& actual, |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1699 // Indicate that code has changed. | 1639 // Indicate that code has changed. |
| 1700 CPU::FlushICache(address_, size_); | 1640 CPU::FlushICache(address_, size_); |
| 1701 | 1641 |
| 1702 // Check that the code was patched as expected. | 1642 // Check that the code was patched as expected. |
| 1703 ASSERT(masm_.pc_ == address_ + size_); | 1643 ASSERT(masm_.pc_ == address_ + size_); |
| 1704 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 1644 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 1705 } | 1645 } |
| 1706 | 1646 |
| 1707 | 1647 |
| 1708 } } // namespace v8::internal | 1648 } } // namespace v8::internal |
| OLD | NEW |