| 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 : Assembler(buffer, size), | 45 : Assembler(buffer, size), |
| 46 generating_stub_(false), | 46 generating_stub_(false), |
| 47 allow_stub_calls_(true), | 47 allow_stub_calls_(true), |
| 48 code_object_(Heap::undefined_value()) { | 48 code_object_(Heap::undefined_value()) { |
| 49 } | 49 } |
| 50 | 50 |
| 51 | 51 |
| 52 void MacroAssembler::IncrementalMarkingRecordWriteHelper( | 52 void MacroAssembler::IncrementalMarkingRecordWriteHelper( |
| 53 Register object, | 53 Register object, |
| 54 Register value, | 54 Register value, |
| 55 Register scratch, | 55 Register address) { |
| 56 ObjectMode object_mode, | 56 ASSERT(!object.is(address)); |
| 57 ValueMode value_mode, | 57 ASSERT(!value.is(address)); |
| 58 ScratchMode scratch_mode) { | |
| 59 ASSERT(!object.is(scratch)); | |
| 60 ASSERT(!value.is(scratch)); | |
| 61 ASSERT(!value.is(object)); | 58 ASSERT(!value.is(object)); |
| 62 | 59 |
| 63 bool preserve[Register::kNumRegisters]; | 60 bool preserve[Register::kNumRegisters]; |
| 64 | 61 |
| 65 for (int i = 0; i < Register::kNumRegisters; i++) preserve[i] = false; | 62 for (int i = 0; i < Register::kNumRegisters; i++) preserve[i] = false; |
| 66 | 63 |
| 67 preserve[eax.code()] = true; | 64 preserve[eax.code()] = true; |
| 68 preserve[ecx.code()] = true; | 65 preserve[ecx.code()] = true; |
| 69 preserve[edx.code()] = true; | 66 preserve[edx.code()] = true; |
| 70 preserve[object.code()] = (object_mode == PRESERVE_OBJECT); | 67 preserve[object.code()] = true; |
| 71 preserve[value.code()] = (value_mode == PRESERVE_VALUE); | 68 preserve[value.code()] = true; |
| 72 preserve[scratch.code()] = (scratch_mode == PRESERVE_SCRATCH); | 69 preserve[address.code()] = true; |
| 73 | 70 |
| 74 for (int i = 0; i < Register::kNumRegisters; i++) { | 71 for (int i = 0; i < Register::kNumRegisters; i++) { |
| 75 if (preserve[i]) push(Register::from_code(i)); | 72 if (preserve[i]) push(Register::from_code(i)); |
| 76 } | 73 } |
| 77 | 74 |
| 78 // TODO(gc) we are assuming that xmm registers are not modified by | 75 // TODO(gc) we are assuming that xmm registers are not modified by |
| 79 // the C function we are calling. | 76 // the C function we are calling. |
| 80 PrepareCallCFunction(2, scratch); | 77 PrepareCallCFunction(2, address); |
| 81 mov(Operand(esp, 0 * kPointerSize), object); | 78 mov(Operand(esp, 0 * kPointerSize), object); |
| 82 mov(Operand(esp, 1 * kPointerSize), value); | 79 mov(Operand(esp, 1 * kPointerSize), value); |
| 83 CallCFunction( | 80 CallCFunction( |
| 84 ExternalReference::incremental_marking_record_write_function(), 2); | 81 ExternalReference::incremental_marking_record_write_function(), 2); |
| 85 | 82 |
| 86 for (int i = Register::kNumRegisters - 1; i >= 0; i--) { | 83 for (int i = Register::kNumRegisters - 1; i >= 0; i--) { |
| 87 if (preserve[i]) pop(Register::from_code(i)); | 84 if (preserve[i]) pop(Register::from_code(i)); |
| 88 } | 85 } |
| 89 } | 86 } |
| 90 | 87 |
| 91 | 88 |
| 92 void MacroAssembler::IncrementalMarkingRecordWrite(Register object, | 89 void MacroAssembler::RememberedSetHelper(Register object, |
| 93 Register value, | 90 Register addr, |
| 94 Register scratch, | 91 Register scratch, |
| 95 SmiCheck smi_check, | 92 SaveFPRegsMode save_fp) { |
| 96 ObjectMode object_mode, | |
| 97 ValueMode value_mode, | |
| 98 ScratchMode scratch_mode) { | |
| 99 if (FLAG_incremental_marking) { | |
| 100 Label done; | |
| 101 | |
| 102 if (smi_check == INLINE_SMI_CHECK) { | |
| 103 ASSERT_EQ(0, kSmiTag); | |
| 104 test(value, Immediate(kSmiTagMask)); | |
| 105 j(zero, &done); | |
| 106 } | |
| 107 | |
| 108 IncrementalMarkingRecordWriteStub stub( | |
| 109 object, value, scratch, object_mode, value_mode, scratch_mode); | |
| 110 CallStub(&stub); | |
| 111 | |
| 112 if (smi_check == INLINE_SMI_CHECK) { | |
| 113 bind(&done); | |
| 114 } | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 | |
| 119 void MacroAssembler::RecordWriteHelper(Register object, | |
| 120 Register addr, | |
| 121 Register scratch, | |
| 122 SaveFPRegsMode save_fp) { | |
| 123 if (emit_debug_code()) { | 93 if (emit_debug_code()) { |
| 124 // Check that the object is not in new space. | 94 // Check that the object is not in new space. |
| 125 Label not_in_new_space; | 95 Label not_in_new_space; |
| 126 InNewSpace(object, scratch, not_equal, ¬_in_new_space); | 96 InNewSpace(object, scratch, not_equal, ¬_in_new_space); |
| 127 Abort("new-space object passed to RecordWriteHelper"); | 97 Abort("new-space object passed to RememberedSetHelper"); |
| 128 bind(¬_in_new_space); | 98 bind(¬_in_new_space); |
| 129 } | 99 } |
| 130 | 100 |
| 131 // Load store buffer top. | 101 // Load store buffer top. |
| 132 ExternalReference store_buffer = ExternalReference::store_buffer_top(); | 102 ExternalReference store_buffer = ExternalReference::store_buffer_top(); |
| 133 mov(scratch, Operand::StaticVariable(store_buffer)); | 103 mov(scratch, Operand::StaticVariable(store_buffer)); |
| 134 // Store pointer to buffer. | 104 // Store pointer to buffer. |
| 135 mov(Operand(scratch, 0), addr); | 105 mov(Operand(scratch, 0), addr); |
| 136 // Increment buffer top. | 106 // Increment buffer top. |
| 137 add(Operand(scratch), Immediate(kPointerSize)); | 107 add(Operand(scratch), Immediate(kPointerSize)); |
| 138 // Write back new top of buffer. | 108 // Write back new top of buffer. |
| 139 mov(Operand::StaticVariable(store_buffer), scratch); | 109 mov(Operand::StaticVariable(store_buffer), scratch); |
| 140 // Call stub on end of buffer. | 110 // Call stub on end of buffer. |
| 141 NearLabel no_overflow; | 111 NearLabel no_overflow; |
| 142 // Check for end of buffer. | 112 // Check for end of buffer. |
| 143 test(scratch, Immediate(StoreBuffer::kStoreBufferOverflowBit)); | 113 test(scratch, Immediate(StoreBuffer::kStoreBufferOverflowBit)); |
| 144 j(equal, &no_overflow); | 114 j(equal, &no_overflow); |
| 145 StoreBufferOverflowStub store_buffer_overflow = | 115 StoreBufferOverflowStub store_buffer_overflow = |
| 146 StoreBufferOverflowStub(save_fp); | 116 StoreBufferOverflowStub(save_fp); |
| 147 CallStub(&store_buffer_overflow); | 117 CallStub(&store_buffer_overflow); |
| 148 bind(&no_overflow); | 118 bind(&no_overflow); |
| 149 } | 119 } |
| 150 | 120 |
| 151 | 121 |
| 152 void MacroAssembler::RecordWrite(Register object, | 122 void MacroAssembler::RecordWrite(Register object, |
| 153 int offset, | 123 int offset, |
| 154 Register value, | 124 Register value, |
| 155 Register scratch, | 125 Register dst, |
| 156 SaveFPRegsMode save_fp) { | 126 SaveFPRegsMode save_fp) { |
| 157 // First, check if a write barrier is even needed. The tests below | 127 // First, check if a write barrier is even needed. The tests below |
| 158 // catch stores of Smis and stores into young gen. | 128 // catch stores of Smis and stores into young gen. |
| 159 Label done; | 129 NearLabel done; |
| 160 | 130 |
| 161 // Skip barrier if writing a smi. | 131 // Skip barrier if writing a smi. |
| 162 ASSERT_EQ(0, kSmiTag); | 132 ASSERT_EQ(0, kSmiTag); |
| 163 test(value, Immediate(kSmiTagMask)); | 133 test(value, Immediate(kSmiTagMask)); |
| 164 j(zero, &done); | 134 j(zero, &done); |
| 165 | 135 |
| 166 IncrementalMarkingRecordWrite(object, | |
| 167 value, | |
| 168 scratch, | |
| 169 OMIT_SMI_CHECK, | |
| 170 PRESERVE_OBJECT, | |
| 171 DESTROY_VALUE, | |
| 172 (offset == 0) ? PRESERVE_SCRATCH | |
| 173 : DESTROY_SCRATCH); | |
| 174 | |
| 175 InNewSpace(object, value, equal, &done); | |
| 176 | |
| 177 // The offset is relative to a tagged or untagged HeapObject pointer, | 136 // The offset is relative to a tagged or untagged HeapObject pointer, |
| 178 // so either offset or offset + kHeapObjectTag must be a | 137 // so either offset or offset + kHeapObjectTag must be a |
| 179 // multiple of kPointerSize. | 138 // multiple of kPointerSize. |
| 180 ASSERT(IsAligned(offset, kPointerSize) || | 139 ASSERT(IsAligned(offset, kPointerSize) || |
| 181 IsAligned(offset + kHeapObjectTag, kPointerSize)); | 140 IsAligned(offset + kHeapObjectTag, kPointerSize)); |
| 182 | 141 |
| 183 Register dst = scratch; | |
| 184 if (offset != 0) { | 142 if (offset != 0) { |
| 143 // If offset is unspecified, then dst is a scratch register. We use it |
| 144 // to store the address of the cell that is being stored to. |
| 185 lea(dst, Operand(object, offset)); | 145 lea(dst, Operand(object, offset)); |
| 186 } else { | 146 } else { |
| 187 // Array access: calculate the destination address in the same manner as | 147 // Array access: calculate the destination address in the same manner as |
| 188 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset | 148 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset |
| 189 // into an array of words. | 149 // into an array of words. |
| 190 ASSERT_EQ(1, kSmiTagSize); | 150 ASSERT_EQ(1, kSmiTagSize); |
| 191 ASSERT_EQ(0, kSmiTag); | 151 ASSERT_EQ(0, kSmiTag); |
| 192 lea(dst, Operand(object, dst, times_half_pointer_size, | 152 lea(dst, Operand(object, dst, times_half_pointer_size, |
| 193 FixedArray::kHeaderSize - kHeapObjectTag)); | 153 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 194 } | 154 } |
| 195 RecordWriteHelper(object, dst, value, save_fp); | 155 |
| 156 RecordWrite(object, dst, value, EMIT_REMEMBERED_SET, save_fp, OMIT_SMI_CHECK); |
| 196 | 157 |
| 197 bind(&done); | 158 bind(&done); |
| 198 | 159 |
| 199 // Clobber all input registers when running with the debug-code flag | 160 // Clobber all input registers when running with the debug-code flag |
| 200 // turned on to provoke errors. | 161 // turned on to provoke errors. |
| 201 if (emit_debug_code()) { | 162 if (emit_debug_code()) { |
| 202 mov(object, Immediate(BitCast<int32_t>(kZapValue))); | 163 mov(object, Immediate(BitCast<int32_t>(kZapValue))); |
| 203 mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 164 mov(value, Immediate(BitCast<int32_t>(kZapValue))); |
| 204 mov(scratch, Immediate(BitCast<int32_t>(kZapValue))); | 165 mov(dst, Immediate(BitCast<int32_t>(kZapValue))); |
| 205 } | 166 } |
| 206 } | 167 } |
| 207 | 168 |
| 208 | 169 |
| 209 void MacroAssembler::RecordWrite(Register object, | 170 void MacroAssembler::RecordWrite(Register object, |
| 210 Register address, | 171 Register address, |
| 211 Register value, | 172 Register value, |
| 212 SaveFPRegsMode save_fp) { | 173 EmitRememberedSet emit_remembered_set, |
| 174 SaveFPRegsMode fp_mode, |
| 175 SmiCheck smi_check) { |
| 176 if (emit_remembered_set == OMIT_REMEMBERED_SET && |
| 177 FLAG_incremental_marking == false) { |
| 178 return; |
| 179 } |
| 213 // First, check if a write barrier is even needed. The tests below | 180 // First, check if a write barrier is even needed. The tests below |
| 214 // catch stores of Smis and stores into young gen. | 181 // catch stores of Smis and stores into young gen. |
| 215 Label done; | 182 NearLabel done; |
| 216 | 183 |
| 217 // Skip barrier if writing a smi. | 184 if (smi_check == INLINE_SMI_CHECK) { |
| 218 ASSERT_EQ(0, kSmiTag); | 185 // Skip barrier if writing a smi. |
| 219 test(value, Immediate(kSmiTagMask)); | 186 ASSERT_EQ(0, kSmiTag); |
| 220 j(zero, &done); | 187 test(value, Immediate(kSmiTagMask)); |
| 188 j(zero, &done); |
| 189 } |
| 221 | 190 |
| 222 IncrementalMarkingRecordWrite(object, | 191 RecordWriteStub stub(object, value, address, emit_remembered_set, fp_mode); |
| 223 value, | 192 CallStub(&stub); |
| 224 address, | |
| 225 OMIT_SMI_CHECK, | |
| 226 PRESERVE_OBJECT, | |
| 227 DESTROY_VALUE, | |
| 228 PRESERVE_SCRATCH); | |
| 229 | 193 |
| 230 InNewSpace(object, value, equal, &done); | 194 if (smi_check == INLINE_SMI_CHECK) { |
| 231 | 195 bind(&done); |
| 232 RecordWriteHelper(object, address, value, save_fp); | 196 } |
| 233 | |
| 234 bind(&done); | |
| 235 | 197 |
| 236 // Clobber all input registers when running with the debug-code flag | 198 // Clobber all input registers when running with the debug-code flag |
| 237 // turned on to provoke errors. | 199 // turned on to provoke errors. |
| 238 if (emit_debug_code()) { | 200 if (emit_debug_code()) { |
| 239 mov(object, Immediate(BitCast<int32_t>(kZapValue))); | 201 mov(object, Immediate(BitCast<int32_t>(kZapValue))); |
| 240 mov(address, Immediate(BitCast<int32_t>(kZapValue))); | 202 mov(address, Immediate(BitCast<int32_t>(kZapValue))); |
| 241 mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 203 mov(value, Immediate(BitCast<int32_t>(kZapValue))); |
| 242 } | 204 } |
| 243 } | 205 } |
| 244 | 206 |
| (...skipping 1870 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2115 | 2077 |
| 2116 // Check that the code was patched as expected. | 2078 // Check that the code was patched as expected. |
| 2117 ASSERT(masm_.pc_ == address_ + size_); | 2079 ASSERT(masm_.pc_ == address_ + size_); |
| 2118 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 2080 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 2119 } | 2081 } |
| 2120 | 2082 |
| 2121 | 2083 |
| 2122 } } // namespace v8::internal | 2084 } } // namespace v8::internal |
| 2123 | 2085 |
| 2124 #endif // V8_TARGET_ARCH_IA32 | 2086 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |