OLD | NEW |
1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. |
2 // All Rights Reserved. | 2 // All Rights Reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions | 5 // modification, are permitted provided that the following conditions |
6 // are met: | 6 // are met: |
7 // | 7 // |
8 // - Redistributions of source code must retain the above copyright notice, | 8 // - Redistributions of source code must retain the above copyright notice, |
9 // this list of conditions and the following disclaimer. | 9 // this list of conditions and the following disclaimer. |
10 // | 10 // |
(...skipping 16 matching lines...) Expand all Loading... |
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | 28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | 30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
31 // OF THE POSSIBILITY OF SUCH DAMAGE. | 31 // OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | 32 |
33 // The original source code covered by the above license above has been modified | 33 // The original source code covered by the above license above has been modified |
34 // significantly by Google Inc. | 34 // significantly by Google Inc. |
35 // Copyright 2014 the V8 project authors. All rights reserved. | 35 // Copyright 2014 the V8 project authors. All rights reserved. |
36 | 36 |
37 #ifndef V8_PPC_ASSEMBLER_PPC_INL_H_ | 37 #ifndef V8_S390_ASSEMBLER_S390_INL_H_ |
38 #define V8_PPC_ASSEMBLER_PPC_INL_H_ | 38 #define V8_S390_ASSEMBLER_S390_INL_H_ |
39 | 39 |
40 #include "src/ppc/assembler-ppc.h" | 40 #include "src/s390/assembler-s390.h" |
41 | 41 |
42 #include "src/assembler.h" | 42 #include "src/assembler.h" |
43 #include "src/debug/debug.h" | 43 #include "src/debug/debug.h" |
44 | 44 |
45 | |
46 namespace v8 { | 45 namespace v8 { |
47 namespace internal { | 46 namespace internal { |
48 | 47 |
49 | |
50 bool CpuFeatures::SupportsCrankshaft() { return true; } | 48 bool CpuFeatures::SupportsCrankshaft() { return true; } |
51 | 49 |
52 | |
53 void RelocInfo::apply(intptr_t delta) { | 50 void RelocInfo::apply(intptr_t delta) { |
54 // absolute code pointer inside code object moves with the code object. | 51 // Absolute code pointer inside code object moves with the code object. |
55 if (IsInternalReference(rmode_)) { | 52 if (IsInternalReference(rmode_)) { |
56 // Jump table entry | 53 // Jump table entry |
57 Address target = Memory::Address_at(pc_); | 54 Address target = Memory::Address_at(pc_); |
58 Memory::Address_at(pc_) = target + delta; | 55 Memory::Address_at(pc_) = target + delta; |
| 56 } else if (IsCodeTarget(rmode_)) { |
| 57 SixByteInstr instr = |
| 58 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc_)); |
| 59 int32_t dis = static_cast<int32_t>(instr & 0xFFFFFFFF) * 2 // halfwords |
| 60 - static_cast<int32_t>(delta); |
| 61 instr >>= 32; // Clear the 4-byte displacement field. |
| 62 instr <<= 32; |
| 63 instr |= static_cast<uint32_t>(dis / 2); |
| 64 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc_), |
| 65 instr); |
59 } else { | 66 } else { |
60 // mov sequence | 67 // mov sequence |
61 DCHECK(IsInternalReferenceEncoded(rmode_)); | 68 DCHECK(IsInternalReferenceEncoded(rmode_)); |
62 Address target = Assembler::target_address_at(pc_, host_); | 69 Address target = Assembler::target_address_at(pc_, host_); |
63 Assembler::set_target_address_at(isolate_, pc_, host_, target + delta, | 70 Assembler::set_target_address_at(isolate_, pc_, host_, target + delta, |
64 SKIP_ICACHE_FLUSH); | 71 SKIP_ICACHE_FLUSH); |
65 } | 72 } |
66 } | 73 } |
67 | 74 |
68 | |
69 Address RelocInfo::target_internal_reference() { | 75 Address RelocInfo::target_internal_reference() { |
70 if (IsInternalReference(rmode_)) { | 76 if (IsInternalReference(rmode_)) { |
71 // Jump table entry | 77 // Jump table entry |
72 return Memory::Address_at(pc_); | 78 return Memory::Address_at(pc_); |
73 } else { | 79 } else { |
74 // mov sequence | 80 // mov sequence |
75 DCHECK(IsInternalReferenceEncoded(rmode_)); | 81 DCHECK(IsInternalReferenceEncoded(rmode_)); |
76 return Assembler::target_address_at(pc_, host_); | 82 return Assembler::target_address_at(pc_, host_); |
77 } | 83 } |
78 } | 84 } |
79 | 85 |
80 | |
81 Address RelocInfo::target_internal_reference_address() { | 86 Address RelocInfo::target_internal_reference_address() { |
82 DCHECK(IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)); | 87 DCHECK(IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)); |
83 return reinterpret_cast<Address>(pc_); | 88 return reinterpret_cast<Address>(pc_); |
84 } | 89 } |
85 | 90 |
86 | |
87 Address RelocInfo::target_address() { | 91 Address RelocInfo::target_address() { |
88 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); | 92 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); |
89 return Assembler::target_address_at(pc_, host_); | 93 return Assembler::target_address_at(pc_, host_); |
90 } | 94 } |
91 | 95 |
92 | |
93 Address RelocInfo::target_address_address() { | 96 Address RelocInfo::target_address_address() { |
94 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || | 97 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || |
95 rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE); | 98 rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE); |
96 | 99 |
97 if (FLAG_enable_embedded_constant_pool && | |
98 Assembler::IsConstantPoolLoadStart(pc_)) { | |
99 // We return the PC for embedded constant pool since this function is used | |
100 // by the serializer and expects the address to reside within the code | |
101 // object. | |
102 return reinterpret_cast<Address>(pc_); | |
103 } | |
104 | |
105 // Read the address of the word containing the target_address in an | 100 // Read the address of the word containing the target_address in an |
106 // instruction stream. | 101 // instruction stream. |
107 // The only architecture-independent user of this function is the serializer. | 102 // The only architecture-independent user of this function is the serializer. |
108 // The serializer uses it to find out how many raw bytes of instruction to | 103 // The serializer uses it to find out how many raw bytes of instruction to |
109 // output before the next target. | 104 // output before the next target. |
110 // For an instruction like LIS/ORI where the target bits are mixed into the | 105 // For an instruction like LIS/ORI where the target bits are mixed into the |
111 // instruction bits, the size of the target will be zero, indicating that the | 106 // instruction bits, the size of the target will be zero, indicating that the |
112 // serializer should not step forward in memory after a target is resolved | 107 // serializer should not step forward in memory after a target is resolved |
113 // and written. | 108 // and written. |
114 return reinterpret_cast<Address>(pc_); | 109 return reinterpret_cast<Address>(pc_); |
115 } | 110 } |
116 | 111 |
117 | |
118 Address RelocInfo::constant_pool_entry_address() { | 112 Address RelocInfo::constant_pool_entry_address() { |
119 if (FLAG_enable_embedded_constant_pool) { | |
120 Address constant_pool = host_->constant_pool(); | |
121 DCHECK(constant_pool); | |
122 ConstantPoolEntry::Access access; | |
123 if (Assembler::IsConstantPoolLoadStart(pc_, &access)) | |
124 return Assembler::target_constant_pool_address_at( | |
125 pc_, constant_pool, access, ConstantPoolEntry::INTPTR); | |
126 } | |
127 UNREACHABLE(); | 113 UNREACHABLE(); |
128 return NULL; | 114 return NULL; |
129 } | 115 } |
130 | 116 |
131 | |
132 int RelocInfo::target_address_size() { return Assembler::kSpecialTargetSize; } | 117 int RelocInfo::target_address_size() { return Assembler::kSpecialTargetSize; } |
133 | 118 |
134 | |
135 void RelocInfo::set_target_address(Address target, | 119 void RelocInfo::set_target_address(Address target, |
136 WriteBarrierMode write_barrier_mode, | 120 WriteBarrierMode write_barrier_mode, |
137 ICacheFlushMode icache_flush_mode) { | 121 ICacheFlushMode icache_flush_mode) { |
138 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); | 122 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); |
139 Assembler::set_target_address_at(isolate_, pc_, host_, target, | 123 Assembler::set_target_address_at(isolate_, pc_, host_, target, |
140 icache_flush_mode); | 124 icache_flush_mode); |
141 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL && | 125 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL && |
142 IsCodeTarget(rmode_)) { | 126 IsCodeTarget(rmode_)) { |
143 Object* target_code = Code::GetCodeFromTargetAddress(target); | 127 Object* target_code = Code::GetCodeFromTargetAddress(target); |
144 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( | 128 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( |
145 host(), this, HeapObject::cast(target_code)); | 129 host(), this, HeapObject::cast(target_code)); |
146 } | 130 } |
147 } | 131 } |
148 | 132 |
149 | |
150 Address Assembler::target_address_from_return_address(Address pc) { | 133 Address Assembler::target_address_from_return_address(Address pc) { |
151 // Returns the address of the call target from the return address that will | 134 // Returns the address of the call target from the return address that will |
152 // be returned to after a call. | 135 // be returned to after a call. |
153 // Call sequence is : | 136 // Sequence is: |
154 // mov ip, @ call address | 137 // BRASL r14, RI |
155 // mtlr ip | 138 return pc - kCallTargetAddressOffset; |
156 // blrl | |
157 // @ return address | |
158 int len; | |
159 ConstantPoolEntry::Access access; | |
160 if (FLAG_enable_embedded_constant_pool && | |
161 IsConstantPoolLoadEnd(pc - 3 * kInstrSize, &access)) { | |
162 len = (access == ConstantPoolEntry::OVERFLOWED) ? 2 : 1; | |
163 } else { | |
164 len = kMovInstructionsNoConstantPool; | |
165 } | |
166 return pc - (len + 2) * kInstrSize; | |
167 } | 139 } |
168 | 140 |
169 | |
170 Address Assembler::return_address_from_call_start(Address pc) { | 141 Address Assembler::return_address_from_call_start(Address pc) { |
171 int len; | 142 // Sequence is: |
172 ConstantPoolEntry::Access access; | 143 // BRASL r14, RI |
173 if (FLAG_enable_embedded_constant_pool && | 144 return pc + kCallTargetAddressOffset; |
174 IsConstantPoolLoadStart(pc, &access)) { | |
175 len = (access == ConstantPoolEntry::OVERFLOWED) ? 2 : 1; | |
176 } else { | |
177 len = kMovInstructionsNoConstantPool; | |
178 } | |
179 return pc + (len + 2) * kInstrSize; | |
180 } | 145 } |
181 | 146 |
| 147 Handle<Object> Assembler::code_target_object_handle_at(Address pc) { |
| 148 SixByteInstr instr = |
| 149 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc)); |
| 150 int index = instr & 0xFFFFFFFF; |
| 151 return code_targets_[index]; |
| 152 } |
182 | 153 |
183 Object* RelocInfo::target_object() { | 154 Object* RelocInfo::target_object() { |
184 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); | 155 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); |
185 return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_)); | 156 return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_)); |
186 } | 157 } |
187 | 158 |
188 | |
189 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) { | 159 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) { |
190 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); | 160 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); |
191 return Handle<Object>( | 161 if (rmode_ == EMBEDDED_OBJECT) { |
192 reinterpret_cast<Object**>(Assembler::target_address_at(pc_, host_))); | 162 return Handle<Object>( |
| 163 reinterpret_cast<Object**>(Assembler::target_address_at(pc_, host_))); |
| 164 } else { |
| 165 return origin->code_target_object_handle_at(pc_); |
| 166 } |
193 } | 167 } |
194 | 168 |
195 | |
196 void RelocInfo::set_target_object(Object* target, | 169 void RelocInfo::set_target_object(Object* target, |
197 WriteBarrierMode write_barrier_mode, | 170 WriteBarrierMode write_barrier_mode, |
198 ICacheFlushMode icache_flush_mode) { | 171 ICacheFlushMode icache_flush_mode) { |
199 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); | 172 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); |
200 Assembler::set_target_address_at(isolate_, pc_, host_, | 173 Assembler::set_target_address_at(isolate_, pc_, host_, |
201 reinterpret_cast<Address>(target), | 174 reinterpret_cast<Address>(target), |
202 icache_flush_mode); | 175 icache_flush_mode); |
203 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL && | 176 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL && |
204 target->IsHeapObject()) { | 177 target->IsHeapObject()) { |
205 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( | 178 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( |
206 host(), this, HeapObject::cast(target)); | 179 host(), this, HeapObject::cast(target)); |
207 } | 180 } |
208 } | 181 } |
209 | 182 |
210 | |
211 Address RelocInfo::target_external_reference() { | 183 Address RelocInfo::target_external_reference() { |
212 DCHECK(rmode_ == EXTERNAL_REFERENCE); | 184 DCHECK(rmode_ == EXTERNAL_REFERENCE); |
213 return Assembler::target_address_at(pc_, host_); | 185 return Assembler::target_address_at(pc_, host_); |
214 } | 186 } |
215 | 187 |
216 | |
217 Address RelocInfo::target_runtime_entry(Assembler* origin) { | 188 Address RelocInfo::target_runtime_entry(Assembler* origin) { |
218 DCHECK(IsRuntimeEntry(rmode_)); | 189 DCHECK(IsRuntimeEntry(rmode_)); |
219 return target_address(); | 190 return target_address(); |
220 } | 191 } |
221 | 192 |
222 | |
223 void RelocInfo::set_target_runtime_entry(Address target, | 193 void RelocInfo::set_target_runtime_entry(Address target, |
224 WriteBarrierMode write_barrier_mode, | 194 WriteBarrierMode write_barrier_mode, |
225 ICacheFlushMode icache_flush_mode) { | 195 ICacheFlushMode icache_flush_mode) { |
226 DCHECK(IsRuntimeEntry(rmode_)); | 196 DCHECK(IsRuntimeEntry(rmode_)); |
227 if (target_address() != target) | 197 if (target_address() != target) |
228 set_target_address(target, write_barrier_mode, icache_flush_mode); | 198 set_target_address(target, write_barrier_mode, icache_flush_mode); |
229 } | 199 } |
230 | 200 |
231 | |
232 Handle<Cell> RelocInfo::target_cell_handle() { | 201 Handle<Cell> RelocInfo::target_cell_handle() { |
233 DCHECK(rmode_ == RelocInfo::CELL); | 202 DCHECK(rmode_ == RelocInfo::CELL); |
234 Address address = Memory::Address_at(pc_); | 203 Address address = Memory::Address_at(pc_); |
235 return Handle<Cell>(reinterpret_cast<Cell**>(address)); | 204 return Handle<Cell>(reinterpret_cast<Cell**>(address)); |
236 } | 205 } |
237 | 206 |
238 | |
239 Cell* RelocInfo::target_cell() { | 207 Cell* RelocInfo::target_cell() { |
240 DCHECK(rmode_ == RelocInfo::CELL); | 208 DCHECK(rmode_ == RelocInfo::CELL); |
241 return Cell::FromValueAddress(Memory::Address_at(pc_)); | 209 return Cell::FromValueAddress(Memory::Address_at(pc_)); |
242 } | 210 } |
243 | 211 |
244 | |
245 void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode write_barrier_mode, | 212 void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode write_barrier_mode, |
246 ICacheFlushMode icache_flush_mode) { | 213 ICacheFlushMode icache_flush_mode) { |
247 DCHECK(rmode_ == RelocInfo::CELL); | 214 DCHECK(rmode_ == RelocInfo::CELL); |
248 Address address = cell->address() + Cell::kValueOffset; | 215 Address address = cell->address() + Cell::kValueOffset; |
249 Memory::Address_at(pc_) = address; | 216 Memory::Address_at(pc_) = address; |
250 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) { | 217 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) { |
251 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this, | 218 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this, |
252 cell); | 219 cell); |
253 } | 220 } |
254 } | 221 } |
255 | 222 |
256 | 223 #if V8_TARGET_ARCH_S390X |
257 static const int kNoCodeAgeInstructions = | 224 // NOP(2byte) + PUSH + MOV + BASR = |
258 FLAG_enable_embedded_constant_pool ? 7 : 6; | 225 // NOP + LAY + STG + IIHF + IILF + BASR |
259 static const int kCodeAgingInstructions = | 226 static const int kCodeAgingSequenceLength = 28; |
260 Assembler::kMovInstructionsNoConstantPool + 3; | 227 static const int kCodeAgingTargetDelta = 14; // Jump past NOP + PUSH to IIHF |
261 static const int kNoCodeAgeSequenceInstructions = | 228 // LAY + 4 * STG + LA |
262 ((kNoCodeAgeInstructions >= kCodeAgingInstructions) | 229 static const int kNoCodeAgeSequenceLength = 34; |
263 ? kNoCodeAgeInstructions | 230 #else |
264 : kCodeAgingInstructions); | 231 #if (V8_HOST_ARCH_S390) |
265 static const int kNoCodeAgeSequenceNops = | 232 // NOP + NILH + LAY + ST + IILF + BASR |
266 (kNoCodeAgeSequenceInstructions - kNoCodeAgeInstructions); | 233 static const int kCodeAgingSequenceLength = 24; |
267 static const int kCodeAgingSequenceNops = | 234 static const int kCodeAgingTargetDelta = 16; // Jump past NOP to IILF |
268 (kNoCodeAgeSequenceInstructions - kCodeAgingInstructions); | 235 // NILH + LAY + 4 * ST + LA |
269 static const int kCodeAgingTargetDelta = 1 * Assembler::kInstrSize; | 236 static const int kNoCodeAgeSequenceLength = 30; |
270 static const int kNoCodeAgeSequenceLength = | 237 #else |
271 (kNoCodeAgeSequenceInstructions * Assembler::kInstrSize); | 238 // NOP + LAY + ST + IILF + BASR |
272 | 239 static const int kCodeAgingSequenceLength = 20; |
| 240 static const int kCodeAgingTargetDelta = 12; // Jump past NOP to IILF |
| 241 // LAY + 4 * ST + LA |
| 242 static const int kNoCodeAgeSequenceLength = 26; |
| 243 #endif |
| 244 #endif |
273 | 245 |
274 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) { | 246 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) { |
275 UNREACHABLE(); // This should never be reached on PPC. | 247 UNREACHABLE(); // This should never be reached on S390. |
276 return Handle<Object>(); | 248 return Handle<Object>(); |
277 } | 249 } |
278 | 250 |
279 | |
280 Code* RelocInfo::code_age_stub() { | 251 Code* RelocInfo::code_age_stub() { |
281 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); | 252 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); |
282 return Code::GetCodeFromTargetAddress( | 253 return Code::GetCodeFromTargetAddress( |
283 Assembler::target_address_at(pc_ + kCodeAgingTargetDelta, host_)); | 254 Assembler::target_address_at(pc_ + kCodeAgingTargetDelta, host_)); |
284 } | 255 } |
285 | 256 |
286 | |
287 void RelocInfo::set_code_age_stub(Code* stub, | 257 void RelocInfo::set_code_age_stub(Code* stub, |
288 ICacheFlushMode icache_flush_mode) { | 258 ICacheFlushMode icache_flush_mode) { |
289 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); | 259 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); |
290 Assembler::set_target_address_at(isolate_, pc_ + kCodeAgingTargetDelta, host_, | 260 Assembler::set_target_address_at(isolate_, pc_ + kCodeAgingTargetDelta, host_, |
291 stub->instruction_start(), | 261 stub->instruction_start(), |
292 icache_flush_mode); | 262 icache_flush_mode); |
293 } | 263 } |
294 | 264 |
295 | |
296 Address RelocInfo::debug_call_address() { | 265 Address RelocInfo::debug_call_address() { |
297 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); | 266 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); |
298 return Assembler::target_address_at(pc_, host_); | 267 return Assembler::target_address_at(pc_, host_); |
299 } | 268 } |
300 | 269 |
301 | |
302 void RelocInfo::set_debug_call_address(Address target) { | 270 void RelocInfo::set_debug_call_address(Address target) { |
303 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); | 271 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); |
304 Assembler::set_target_address_at(isolate_, pc_, host_, target); | 272 Assembler::set_target_address_at(isolate_, pc_, host_, target); |
305 if (host() != NULL) { | 273 if (host() != NULL) { |
306 Object* target_code = Code::GetCodeFromTargetAddress(target); | 274 Object* target_code = Code::GetCodeFromTargetAddress(target); |
307 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( | 275 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( |
308 host(), this, HeapObject::cast(target_code)); | 276 host(), this, HeapObject::cast(target_code)); |
309 } | 277 } |
310 } | 278 } |
311 | 279 |
312 | |
313 void RelocInfo::WipeOut() { | 280 void RelocInfo::WipeOut() { |
314 DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) || | 281 DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) || |
315 IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) || | 282 IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) || |
316 IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)); | 283 IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)); |
317 if (IsInternalReference(rmode_)) { | 284 if (IsInternalReference(rmode_)) { |
318 // Jump table entry | 285 // Jump table entry |
319 Memory::Address_at(pc_) = NULL; | 286 Memory::Address_at(pc_) = NULL; |
320 } else if (IsInternalReferenceEncoded(rmode_)) { | 287 } else if (IsInternalReferenceEncoded(rmode_)) { |
321 // mov sequence | 288 // mov sequence |
322 // Currently used only by deserializer, no need to flush. | 289 // Currently used only by deserializer, no need to flush. |
323 Assembler::set_target_address_at(isolate_, pc_, host_, NULL, | 290 Assembler::set_target_address_at(isolate_, pc_, host_, NULL, |
324 SKIP_ICACHE_FLUSH); | 291 SKIP_ICACHE_FLUSH); |
325 } else { | 292 } else { |
326 Assembler::set_target_address_at(isolate_, pc_, host_, NULL); | 293 Assembler::set_target_address_at(isolate_, pc_, host_, NULL); |
327 } | 294 } |
328 } | 295 } |
329 | 296 |
330 | |
331 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) { | 297 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) { |
332 RelocInfo::Mode mode = rmode(); | 298 RelocInfo::Mode mode = rmode(); |
333 if (mode == RelocInfo::EMBEDDED_OBJECT) { | 299 if (mode == RelocInfo::EMBEDDED_OBJECT) { |
334 visitor->VisitEmbeddedPointer(this); | 300 visitor->VisitEmbeddedPointer(this); |
335 } else if (RelocInfo::IsCodeTarget(mode)) { | 301 } else if (RelocInfo::IsCodeTarget(mode)) { |
336 visitor->VisitCodeTarget(this); | 302 visitor->VisitCodeTarget(this); |
337 } else if (mode == RelocInfo::CELL) { | 303 } else if (mode == RelocInfo::CELL) { |
338 visitor->VisitCell(this); | 304 visitor->VisitCell(this); |
339 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { | 305 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { |
340 visitor->VisitExternalReference(this); | 306 visitor->VisitExternalReference(this); |
341 } else if (mode == RelocInfo::INTERNAL_REFERENCE || | 307 } else if (mode == RelocInfo::INTERNAL_REFERENCE) { |
342 mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) { | |
343 visitor->VisitInternalReference(this); | 308 visitor->VisitInternalReference(this); |
344 } else if (RelocInfo::IsCodeAgeSequence(mode)) { | 309 } else if (RelocInfo::IsCodeAgeSequence(mode)) { |
345 visitor->VisitCodeAgeSequence(this); | 310 visitor->VisitCodeAgeSequence(this); |
346 } else if (RelocInfo::IsDebugBreakSlot(mode) && | 311 } else if (RelocInfo::IsDebugBreakSlot(mode) && |
347 IsPatchedDebugBreakSlotSequence()) { | 312 IsPatchedDebugBreakSlotSequence()) { |
348 visitor->VisitDebugTarget(this); | 313 visitor->VisitDebugTarget(this); |
349 } else if (IsRuntimeEntry(mode)) { | 314 } else if (IsRuntimeEntry(mode)) { |
350 visitor->VisitRuntimeEntry(this); | 315 visitor->VisitRuntimeEntry(this); |
351 } | 316 } |
352 } | 317 } |
353 | 318 |
354 | |
355 template <typename StaticVisitor> | 319 template <typename StaticVisitor> |
356 void RelocInfo::Visit(Heap* heap) { | 320 void RelocInfo::Visit(Heap* heap) { |
357 RelocInfo::Mode mode = rmode(); | 321 RelocInfo::Mode mode = rmode(); |
358 if (mode == RelocInfo::EMBEDDED_OBJECT) { | 322 if (mode == RelocInfo::EMBEDDED_OBJECT) { |
359 StaticVisitor::VisitEmbeddedPointer(heap, this); | 323 StaticVisitor::VisitEmbeddedPointer(heap, this); |
360 } else if (RelocInfo::IsCodeTarget(mode)) { | 324 } else if (RelocInfo::IsCodeTarget(mode)) { |
361 StaticVisitor::VisitCodeTarget(heap, this); | 325 StaticVisitor::VisitCodeTarget(heap, this); |
362 } else if (mode == RelocInfo::CELL) { | 326 } else if (mode == RelocInfo::CELL) { |
363 StaticVisitor::VisitCell(heap, this); | 327 StaticVisitor::VisitCell(heap, this); |
364 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { | 328 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { |
365 StaticVisitor::VisitExternalReference(this); | 329 StaticVisitor::VisitExternalReference(this); |
366 } else if (mode == RelocInfo::INTERNAL_REFERENCE || | 330 } else if (mode == RelocInfo::INTERNAL_REFERENCE) { |
367 mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) { | |
368 StaticVisitor::VisitInternalReference(this); | 331 StaticVisitor::VisitInternalReference(this); |
369 } else if (RelocInfo::IsCodeAgeSequence(mode)) { | 332 } else if (RelocInfo::IsCodeAgeSequence(mode)) { |
370 StaticVisitor::VisitCodeAgeSequence(heap, this); | 333 StaticVisitor::VisitCodeAgeSequence(heap, this); |
371 } else if (RelocInfo::IsDebugBreakSlot(mode) && | 334 } else if (RelocInfo::IsDebugBreakSlot(mode) && |
372 IsPatchedDebugBreakSlotSequence()) { | 335 IsPatchedDebugBreakSlotSequence()) { |
373 StaticVisitor::VisitDebugTarget(heap, this); | 336 StaticVisitor::VisitDebugTarget(heap, this); |
374 } else if (IsRuntimeEntry(mode)) { | 337 } else if (IsRuntimeEntry(mode)) { |
375 StaticVisitor::VisitRuntimeEntry(this); | 338 StaticVisitor::VisitRuntimeEntry(this); |
376 } | 339 } |
377 } | 340 } |
378 | 341 |
| 342 // Operand constructors |
379 Operand::Operand(intptr_t immediate, RelocInfo::Mode rmode) { | 343 Operand::Operand(intptr_t immediate, RelocInfo::Mode rmode) { |
380 rm_ = no_reg; | 344 rm_ = no_reg; |
381 imm_ = immediate; | 345 imm_ = immediate; |
382 rmode_ = rmode; | 346 rmode_ = rmode; |
383 } | 347 } |
384 | 348 |
385 Operand::Operand(const ExternalReference& f) { | 349 Operand::Operand(const ExternalReference& f) { |
386 rm_ = no_reg; | 350 rm_ = no_reg; |
387 imm_ = reinterpret_cast<intptr_t>(f.address()); | 351 imm_ = reinterpret_cast<intptr_t>(f.address()); |
388 rmode_ = RelocInfo::EXTERNAL_REFERENCE; | 352 rmode_ = RelocInfo::EXTERNAL_REFERENCE; |
389 } | 353 } |
390 | 354 |
391 Operand::Operand(Smi* value) { | 355 Operand::Operand(Smi* value) { |
392 rm_ = no_reg; | 356 rm_ = no_reg; |
393 imm_ = reinterpret_cast<intptr_t>(value); | 357 imm_ = reinterpret_cast<intptr_t>(value); |
394 rmode_ = kRelocInfo_NONEPTR; | 358 rmode_ = kRelocInfo_NONEPTR; |
395 } | 359 } |
396 | 360 |
397 Operand::Operand(Register rm) { | 361 Operand::Operand(Register rm) { |
398 rm_ = rm; | 362 rm_ = rm; |
399 rmode_ = kRelocInfo_NONEPTR; // PPC -why doesn't ARM do this? | 363 rmode_ = kRelocInfo_NONEPTR; // S390 -why doesn't ARM do this? |
400 } | 364 } |
401 | 365 |
402 void Assembler::CheckBuffer() { | 366 void Assembler::CheckBuffer() { |
403 if (buffer_space() <= kGap) { | 367 if (buffer_space() <= kGap) { |
404 GrowBuffer(); | 368 GrowBuffer(); |
405 } | 369 } |
406 } | 370 } |
407 | 371 |
408 void Assembler::TrackBranch() { | 372 int32_t Assembler::emit_code_target(Handle<Code> target, RelocInfo::Mode rmode, |
409 DCHECK(!trampoline_emitted_); | 373 TypeFeedbackId ast_id) { |
410 int count = tracked_branch_count_++; | 374 DCHECK(RelocInfo::IsCodeTarget(rmode)); |
411 if (count == 0) { | 375 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) { |
412 // We leave space (kMaxBlockTrampolineSectionSize) | 376 SetRecordedAstId(ast_id); |
413 // for BlockTrampolinePoolScope buffer. | 377 RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID); |
414 next_trampoline_check_ = | |
415 pc_offset() + kMaxCondBranchReach - kMaxBlockTrampolineSectionSize; | |
416 } else { | 378 } else { |
417 next_trampoline_check_ -= kTrampolineSlotsSize; | 379 RecordRelocInfo(rmode); |
418 } | 380 } |
| 381 |
| 382 int current = code_targets_.length(); |
| 383 if (current > 0 && code_targets_.last().is_identical_to(target)) { |
| 384 // Optimization if we keep jumping to the same code target. |
| 385 current--; |
| 386 } else { |
| 387 code_targets_.Add(target); |
| 388 } |
| 389 return current; |
419 } | 390 } |
420 | 391 |
421 void Assembler::UntrackBranch() { | 392 // Helper to emit the binary encoding of a 2 byte instruction |
422 DCHECK(!trampoline_emitted_); | 393 void Assembler::emit2bytes(uint16_t x) { |
423 DCHECK(tracked_branch_count_ > 0); | 394 CheckBuffer(); |
424 int count = --tracked_branch_count_; | 395 #if V8_TARGET_LITTLE_ENDIAN |
425 if (count == 0) { | 396 // We need to emit instructions in big endian format as disassembler / |
426 // Reset | 397 // simulator require the first byte of the instruction in order to decode |
427 next_trampoline_check_ = kMaxInt; | 398 // the instruction length. Swap the bytes. |
428 } else { | 399 x = ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8); |
429 next_trampoline_check_ += kTrampolineSlotsSize; | 400 #endif |
430 } | 401 *reinterpret_cast<uint16_t*>(pc_) = x; |
| 402 pc_ += 2; |
431 } | 403 } |
432 | 404 |
433 void Assembler::CheckTrampolinePoolQuick() { | 405 // Helper to emit the binary encoding of a 4 byte instruction |
434 if (pc_offset() >= next_trampoline_check_) { | 406 void Assembler::emit4bytes(uint32_t x) { |
435 CheckTrampolinePool(); | 407 CheckBuffer(); |
436 } | 408 #if V8_TARGET_LITTLE_ENDIAN |
| 409 // We need to emit instructions in big endian format as disassembler / |
| 410 // simulator require the first byte of the instruction in order to decode |
| 411 // the instruction length. Swap the bytes. |
| 412 x = ((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | |
| 413 ((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24); |
| 414 #endif |
| 415 *reinterpret_cast<uint32_t*>(pc_) = x; |
| 416 pc_ += 4; |
437 } | 417 } |
438 | 418 |
439 void Assembler::emit(Instr x) { | 419 // Helper to emit the binary encoding of a 6 byte instruction |
| 420 void Assembler::emit6bytes(uint64_t x) { |
440 CheckBuffer(); | 421 CheckBuffer(); |
441 *reinterpret_cast<Instr*>(pc_) = x; | 422 #if V8_TARGET_LITTLE_ENDIAN |
442 pc_ += kInstrSize; | 423 // We need to emit instructions in big endian format as disassembler / |
443 CheckTrampolinePoolQuick(); | 424 // simulator require the first byte of the instruction in order to decode |
| 425 // the instruction length. Swap the bytes. |
| 426 x = (static_cast<uint64_t>(x & 0xFF) << 40) | |
| 427 (static_cast<uint64_t>((x >> 8) & 0xFF) << 32) | |
| 428 (static_cast<uint64_t>((x >> 16) & 0xFF) << 24) | |
| 429 (static_cast<uint64_t>((x >> 24) & 0xFF) << 16) | |
| 430 (static_cast<uint64_t>((x >> 32) & 0xFF) << 8) | |
| 431 (static_cast<uint64_t>((x >> 40) & 0xFF)); |
| 432 x |= (*reinterpret_cast<uint64_t*>(pc_) >> 48) << 48; |
| 433 #else |
| 434 // We need to pad two bytes of zeros in order to get the 6-bytes |
| 435 // stored from low address. |
| 436 x = x << 16; |
| 437 x |= *reinterpret_cast<uint64_t*>(pc_) & 0xFFFF; |
| 438 #endif |
| 439 // It is safe to store 8-bytes, as CheckBuffer() guarantees we have kGap |
| 440 // space left over. |
| 441 *reinterpret_cast<uint64_t*>(pc_) = x; |
| 442 pc_ += 6; |
444 } | 443 } |
445 | 444 |
446 bool Operand::is_reg() const { return rm_.is_valid(); } | 445 bool Operand::is_reg() const { return rm_.is_valid(); } |
447 | 446 |
| 447 // Fetch the 32bit value from the FIXED_SEQUENCE IIHF / IILF |
| 448 Address Assembler::target_address_at(Address pc, Address constant_pool) { |
| 449 // S390 Instruction! |
| 450 // We want to check for instructions generated by Asm::mov() |
| 451 Opcode op1 = Instruction::S390OpcodeValue(reinterpret_cast<const byte*>(pc)); |
| 452 SixByteInstr instr_1 = |
| 453 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc)); |
448 | 454 |
449 // Fetch the 32bit value from the FIXED_SEQUENCE lis/ori | 455 if (BRASL == op1 || BRCL == op1) { |
450 Address Assembler::target_address_at(Address pc, Address constant_pool) { | 456 int32_t dis = static_cast<int32_t>(instr_1 & 0xFFFFFFFF) * 2; |
451 if (FLAG_enable_embedded_constant_pool && constant_pool) { | 457 return reinterpret_cast<Address>(reinterpret_cast<uint64_t>(pc) + dis); |
452 ConstantPoolEntry::Access access; | |
453 if (IsConstantPoolLoadStart(pc, &access)) | |
454 return Memory::Address_at(target_constant_pool_address_at( | |
455 pc, constant_pool, access, ConstantPoolEntry::INTPTR)); | |
456 } | 458 } |
457 | 459 |
458 Instr instr1 = instr_at(pc); | 460 #if V8_TARGET_ARCH_S390X |
459 Instr instr2 = instr_at(pc + kInstrSize); | 461 int instr1_length = |
460 // Interpret 2 instructions generated by lis/ori | 462 Instruction::InstructionLength(reinterpret_cast<const byte*>(pc)); |
461 if (IsLis(instr1) && IsOri(instr2)) { | 463 Opcode op2 = Instruction::S390OpcodeValue( |
462 #if V8_TARGET_ARCH_PPC64 | 464 reinterpret_cast<const byte*>(pc + instr1_length)); |
463 Instr instr4 = instr_at(pc + (3 * kInstrSize)); | 465 SixByteInstr instr_2 = Instruction::InstructionBits( |
464 Instr instr5 = instr_at(pc + (4 * kInstrSize)); | 466 reinterpret_cast<const byte*>(pc + instr1_length)); |
465 // Assemble the 64 bit value. | 467 // IIHF for hi_32, IILF for lo_32 |
466 uint64_t hi = (static_cast<uint32_t>((instr1 & kImm16Mask) << 16) | | 468 if (IIHF == op1 && IILF == op2) { |
467 static_cast<uint32_t>(instr2 & kImm16Mask)); | 469 return reinterpret_cast<Address>(((instr_1 & 0xFFFFFFFF) << 32) | |
468 uint64_t lo = (static_cast<uint32_t>((instr4 & kImm16Mask) << 16) | | 470 ((instr_2 & 0xFFFFFFFF))); |
469 static_cast<uint32_t>(instr5 & kImm16Mask)); | 471 } |
470 return reinterpret_cast<Address>((hi << 32) | lo); | |
471 #else | 472 #else |
472 // Assemble the 32 bit value. | 473 // IILF loads 32-bits |
473 return reinterpret_cast<Address>(((instr1 & kImm16Mask) << 16) | | 474 if (IILF == op1 || CFI == op1) { |
474 (instr2 & kImm16Mask)); | 475 return reinterpret_cast<Address>((instr_1 & 0xFFFFFFFF)); |
475 #endif | |
476 } | 476 } |
477 | |
478 UNREACHABLE(); | |
479 return NULL; | |
480 } | |
481 | |
482 | |
483 #if V8_TARGET_ARCH_PPC64 | |
484 const int kLoadIntptrOpcode = LD; | |
485 #else | |
486 const int kLoadIntptrOpcode = LWZ; | |
487 #endif | 477 #endif |
488 | 478 |
489 // Constant pool load sequence detection: | 479 UNIMPLEMENTED(); |
490 // 1) REGULAR access: | 480 return (Address)0; |
491 // load <dst>, kConstantPoolRegister + <offset> | |
492 // | |
493 // 2) OVERFLOWED access: | |
494 // addis <scratch>, kConstantPoolRegister, <offset_high> | |
495 // load <dst>, <scratch> + <offset_low> | |
496 bool Assembler::IsConstantPoolLoadStart(Address pc, | |
497 ConstantPoolEntry::Access* access) { | |
498 Instr instr = instr_at(pc); | |
499 int opcode = instr & kOpcodeMask; | |
500 if (!GetRA(instr).is(kConstantPoolRegister)) return false; | |
501 bool overflowed = (opcode == ADDIS); | |
502 #ifdef DEBUG | |
503 if (overflowed) { | |
504 opcode = instr_at(pc + kInstrSize) & kOpcodeMask; | |
505 } | |
506 DCHECK(opcode == kLoadIntptrOpcode || opcode == LFD); | |
507 #endif | |
508 if (access) { | |
509 *access = (overflowed ? ConstantPoolEntry::OVERFLOWED | |
510 : ConstantPoolEntry::REGULAR); | |
511 } | |
512 return true; | |
513 } | 481 } |
514 | 482 |
515 | |
516 bool Assembler::IsConstantPoolLoadEnd(Address pc, | |
517 ConstantPoolEntry::Access* access) { | |
518 Instr instr = instr_at(pc); | |
519 int opcode = instr & kOpcodeMask; | |
520 bool overflowed = false; | |
521 if (!(opcode == kLoadIntptrOpcode || opcode == LFD)) return false; | |
522 if (!GetRA(instr).is(kConstantPoolRegister)) { | |
523 instr = instr_at(pc - kInstrSize); | |
524 opcode = instr & kOpcodeMask; | |
525 if ((opcode != ADDIS) || !GetRA(instr).is(kConstantPoolRegister)) { | |
526 return false; | |
527 } | |
528 overflowed = true; | |
529 } | |
530 if (access) { | |
531 *access = (overflowed ? ConstantPoolEntry::OVERFLOWED | |
532 : ConstantPoolEntry::REGULAR); | |
533 } | |
534 return true; | |
535 } | |
536 | |
537 | |
538 int Assembler::GetConstantPoolOffset(Address pc, | |
539 ConstantPoolEntry::Access access, | |
540 ConstantPoolEntry::Type type) { | |
541 bool overflowed = (access == ConstantPoolEntry::OVERFLOWED); | |
542 #ifdef DEBUG | |
543 ConstantPoolEntry::Access access_check = | |
544 static_cast<ConstantPoolEntry::Access>(-1); | |
545 DCHECK(IsConstantPoolLoadStart(pc, &access_check)); | |
546 DCHECK(access_check == access); | |
547 #endif | |
548 int offset; | |
549 if (overflowed) { | |
550 offset = (instr_at(pc) & kImm16Mask) << 16; | |
551 offset += SIGN_EXT_IMM16(instr_at(pc + kInstrSize) & kImm16Mask); | |
552 DCHECK(!is_int16(offset)); | |
553 } else { | |
554 offset = SIGN_EXT_IMM16((instr_at(pc) & kImm16Mask)); | |
555 } | |
556 return offset; | |
557 } | |
558 | |
559 | |
560 void Assembler::PatchConstantPoolAccessInstruction( | |
561 int pc_offset, int offset, ConstantPoolEntry::Access access, | |
562 ConstantPoolEntry::Type type) { | |
563 Address pc = buffer_ + pc_offset; | |
564 bool overflowed = (access == ConstantPoolEntry::OVERFLOWED); | |
565 CHECK(overflowed != is_int16(offset)); | |
566 #ifdef DEBUG | |
567 ConstantPoolEntry::Access access_check = | |
568 static_cast<ConstantPoolEntry::Access>(-1); | |
569 DCHECK(IsConstantPoolLoadStart(pc, &access_check)); | |
570 DCHECK(access_check == access); | |
571 #endif | |
572 if (overflowed) { | |
573 int hi_word = static_cast<int>(offset >> 16); | |
574 int lo_word = static_cast<int>(offset & 0xffff); | |
575 if (lo_word & 0x8000) hi_word++; | |
576 | |
577 Instr instr1 = instr_at(pc); | |
578 Instr instr2 = instr_at(pc + kInstrSize); | |
579 instr1 &= ~kImm16Mask; | |
580 instr1 |= (hi_word & kImm16Mask); | |
581 instr2 &= ~kImm16Mask; | |
582 instr2 |= (lo_word & kImm16Mask); | |
583 instr_at_put(pc, instr1); | |
584 instr_at_put(pc + kInstrSize, instr2); | |
585 } else { | |
586 Instr instr = instr_at(pc); | |
587 instr &= ~kImm16Mask; | |
588 instr |= (offset & kImm16Mask); | |
589 instr_at_put(pc, instr); | |
590 } | |
591 } | |
592 | |
593 | |
594 Address Assembler::target_constant_pool_address_at( | |
595 Address pc, Address constant_pool, ConstantPoolEntry::Access access, | |
596 ConstantPoolEntry::Type type) { | |
597 Address addr = constant_pool; | |
598 DCHECK(addr); | |
599 addr += GetConstantPoolOffset(pc, access, type); | |
600 return addr; | |
601 } | |
602 | |
603 | |
604 // This sets the branch destination (which gets loaded at the call address). | 483 // This sets the branch destination (which gets loaded at the call address). |
605 // This is for calls and branches within generated code. The serializer | 484 // This is for calls and branches within generated code. The serializer |
606 // has already deserialized the mov instructions etc. | 485 // has already deserialized the mov instructions etc. |
607 // There is a FIXED_SEQUENCE assumption here | 486 // There is a FIXED_SEQUENCE assumption here |
608 void Assembler::deserialization_set_special_target_at( | 487 void Assembler::deserialization_set_special_target_at( |
609 Isolate* isolate, Address instruction_payload, Code* code, Address target) { | 488 Isolate* isolate, Address instruction_payload, Code* code, Address target) { |
610 set_target_address_at(isolate, instruction_payload, code, target); | 489 set_target_address_at(isolate, instruction_payload, code, target); |
611 } | 490 } |
612 | 491 |
613 | |
614 void Assembler::deserialization_set_target_internal_reference_at( | 492 void Assembler::deserialization_set_target_internal_reference_at( |
615 Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) { | 493 Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) { |
616 if (RelocInfo::IsInternalReferenceEncoded(mode)) { | 494 if (RelocInfo::IsInternalReferenceEncoded(mode)) { |
617 Code* code = NULL; | 495 Code* code = NULL; |
618 set_target_address_at(isolate, pc, code, target, SKIP_ICACHE_FLUSH); | 496 set_target_address_at(isolate, pc, code, target, SKIP_ICACHE_FLUSH); |
619 } else { | 497 } else { |
620 Memory::Address_at(pc) = target; | 498 Memory::Address_at(pc) = target; |
621 } | 499 } |
622 } | 500 } |
623 | 501 |
624 | 502 // This code assumes the FIXED_SEQUENCE of IIHF/IILF |
625 // This code assumes the FIXED_SEQUENCE of lis/ori | |
626 void Assembler::set_target_address_at(Isolate* isolate, Address pc, | 503 void Assembler::set_target_address_at(Isolate* isolate, Address pc, |
627 Address constant_pool, Address target, | 504 Address constant_pool, Address target, |
628 ICacheFlushMode icache_flush_mode) { | 505 ICacheFlushMode icache_flush_mode) { |
629 if (FLAG_enable_embedded_constant_pool && constant_pool) { | 506 // Check for instructions generated by Asm::mov() |
630 ConstantPoolEntry::Access access; | 507 Opcode op1 = Instruction::S390OpcodeValue(reinterpret_cast<const byte*>(pc)); |
631 if (IsConstantPoolLoadStart(pc, &access)) { | 508 SixByteInstr instr_1 = |
632 Memory::Address_at(target_constant_pool_address_at( | 509 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc)); |
633 pc, constant_pool, access, ConstantPoolEntry::INTPTR)) = target; | 510 bool patched = false; |
634 return; | 511 |
| 512 if (BRASL == op1 || BRCL == op1) { |
| 513 instr_1 >>= 32; // Zero out the lower 32-bits |
| 514 instr_1 <<= 32; |
| 515 int32_t halfwords = (target - pc) / 2; // number of halfwords |
| 516 instr_1 |= static_cast<uint32_t>(halfwords); |
| 517 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc), |
| 518 instr_1); |
| 519 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { |
| 520 Assembler::FlushICache(isolate, pc, 6); |
635 } | 521 } |
636 } | 522 patched = true; |
| 523 } else { |
| 524 #if V8_TARGET_ARCH_S390X |
| 525 int instr1_length = |
| 526 Instruction::InstructionLength(reinterpret_cast<const byte*>(pc)); |
| 527 Opcode op2 = Instruction::S390OpcodeValue( |
| 528 reinterpret_cast<const byte*>(pc + instr1_length)); |
| 529 SixByteInstr instr_2 = Instruction::InstructionBits( |
| 530 reinterpret_cast<const byte*>(pc + instr1_length)); |
| 531 // IIHF for hi_32, IILF for lo_32 |
| 532 if (IIHF == op1 && IILF == op2) { |
| 533 // IIHF |
| 534 instr_1 >>= 32; // Zero out the lower 32-bits |
| 535 instr_1 <<= 32; |
| 536 instr_1 |= reinterpret_cast<uint64_t>(target) >> 32; |
637 | 537 |
638 Instr instr1 = instr_at(pc); | 538 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc), |
639 Instr instr2 = instr_at(pc + kInstrSize); | 539 instr_1); |
640 // Interpret 2 instructions generated by lis/ori | |
641 if (IsLis(instr1) && IsOri(instr2)) { | |
642 #if V8_TARGET_ARCH_PPC64 | |
643 Instr instr4 = instr_at(pc + (3 * kInstrSize)); | |
644 Instr instr5 = instr_at(pc + (4 * kInstrSize)); | |
645 // Needs to be fixed up when mov changes to handle 64-bit values. | |
646 uint32_t* p = reinterpret_cast<uint32_t*>(pc); | |
647 uintptr_t itarget = reinterpret_cast<uintptr_t>(target); | |
648 | 540 |
649 instr5 &= ~kImm16Mask; | 541 // IILF |
650 instr5 |= itarget & kImm16Mask; | 542 instr_2 >>= 32; |
651 itarget = itarget >> 16; | 543 instr_2 <<= 32; |
| 544 instr_2 |= reinterpret_cast<uint64_t>(target) & 0xFFFFFFFF; |
652 | 545 |
653 instr4 &= ~kImm16Mask; | 546 Instruction::SetInstructionBits<SixByteInstr>( |
654 instr4 |= itarget & kImm16Mask; | 547 reinterpret_cast<byte*>(pc + instr1_length), instr_2); |
655 itarget = itarget >> 16; | 548 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { |
656 | 549 Assembler::FlushICache(isolate, pc, 12); |
657 instr2 &= ~kImm16Mask; | 550 } |
658 instr2 |= itarget & kImm16Mask; | 551 patched = true; |
659 itarget = itarget >> 16; | |
660 | |
661 instr1 &= ~kImm16Mask; | |
662 instr1 |= itarget & kImm16Mask; | |
663 itarget = itarget >> 16; | |
664 | |
665 *p = instr1; | |
666 *(p + 1) = instr2; | |
667 *(p + 3) = instr4; | |
668 *(p + 4) = instr5; | |
669 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { | |
670 Assembler::FlushICache(isolate, p, 5 * kInstrSize); | |
671 } | 552 } |
672 #else | 553 #else |
673 uint32_t* p = reinterpret_cast<uint32_t*>(pc); | 554 // IILF loads 32-bits |
674 uint32_t itarget = reinterpret_cast<uint32_t>(target); | 555 if (IILF == op1 || CFI == op1) { |
675 int lo_word = itarget & kImm16Mask; | 556 instr_1 >>= 32; // Zero out the lower 32-bits |
676 int hi_word = itarget >> 16; | 557 instr_1 <<= 32; |
677 instr1 &= ~kImm16Mask; | 558 instr_1 |= reinterpret_cast<uint32_t>(target); |
678 instr1 |= hi_word; | |
679 instr2 &= ~kImm16Mask; | |
680 instr2 |= lo_word; | |
681 | 559 |
682 *p = instr1; | 560 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc), |
683 *(p + 1) = instr2; | 561 instr_1); |
684 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { | 562 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { |
685 Assembler::FlushICache(isolate, p, 2 * kInstrSize); | 563 Assembler::FlushICache(isolate, pc, 6); |
| 564 } |
| 565 patched = true; |
686 } | 566 } |
687 #endif | 567 #endif |
688 return; | |
689 } | 568 } |
690 UNREACHABLE(); | 569 if (!patched) UNREACHABLE(); |
691 } | 570 } |
| 571 |
692 } // namespace internal | 572 } // namespace internal |
693 } // namespace v8 | 573 } // namespace v8 |
694 | 574 |
695 #endif // V8_PPC_ASSEMBLER_PPC_INL_H_ | 575 #endif // V8_S390_ASSEMBLER_S390_INL_H_ |
OLD | NEW |