OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
7 | 7 |
8 #include "vm/instructions.h" | 8 #include "vm/instructions.h" |
9 #include "vm/instructions_arm64.h" | 9 #include "vm/instructions_arm64.h" |
10 | 10 |
(...skipping 13 matching lines...) Expand all Loading... |
24 ASSERT(code.ContainsInstructionAt(pc)); | 24 ASSERT(code.ContainsInstructionAt(pc)); |
25 // Last instruction: blr ip0. | 25 // Last instruction: blr ip0. |
26 ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200); | 26 ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200); |
27 | 27 |
28 Register reg; | 28 Register reg; |
29 ic_data_load_end_ = InstructionPattern::DecodeLoadWordFromPool( | 29 ic_data_load_end_ = InstructionPattern::DecodeLoadWordFromPool( |
30 end_ - 2 * Instr::kInstrSize, ®, &target_code_pool_index_); | 30 end_ - 2 * Instr::kInstrSize, ®, &target_code_pool_index_); |
31 ASSERT(reg == CODE_REG); | 31 ASSERT(reg == CODE_REG); |
32 } | 32 } |
33 | 33 |
34 | |
35 NativeCallPattern::NativeCallPattern(uword pc, const Code& code) | 34 NativeCallPattern::NativeCallPattern(uword pc, const Code& code) |
36 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 35 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
37 end_(pc), | 36 end_(pc), |
38 native_function_pool_index_(-1), | 37 native_function_pool_index_(-1), |
39 target_code_pool_index_(-1) { | 38 target_code_pool_index_(-1) { |
40 ASSERT(code.ContainsInstructionAt(pc)); | 39 ASSERT(code.ContainsInstructionAt(pc)); |
41 // Last instruction: blr ip0. | 40 // Last instruction: blr ip0. |
42 ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200); | 41 ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200); |
43 | 42 |
44 Register reg; | 43 Register reg; |
45 uword native_function_load_end = InstructionPattern::DecodeLoadWordFromPool( | 44 uword native_function_load_end = InstructionPattern::DecodeLoadWordFromPool( |
46 end_ - 2 * Instr::kInstrSize, ®, &target_code_pool_index_); | 45 end_ - 2 * Instr::kInstrSize, ®, &target_code_pool_index_); |
47 ASSERT(reg == CODE_REG); | 46 ASSERT(reg == CODE_REG); |
48 InstructionPattern::DecodeLoadWordFromPool(native_function_load_end, ®, | 47 InstructionPattern::DecodeLoadWordFromPool(native_function_load_end, ®, |
49 &native_function_pool_index_); | 48 &native_function_pool_index_); |
50 ASSERT(reg == R5); | 49 ASSERT(reg == R5); |
51 } | 50 } |
52 | 51 |
53 | |
54 RawCode* NativeCallPattern::target() const { | 52 RawCode* NativeCallPattern::target() const { |
55 return reinterpret_cast<RawCode*>( | 53 return reinterpret_cast<RawCode*>( |
56 object_pool_.ObjectAt(target_code_pool_index_)); | 54 object_pool_.ObjectAt(target_code_pool_index_)); |
57 } | 55 } |
58 | 56 |
59 | |
60 void NativeCallPattern::set_target(const Code& target) const { | 57 void NativeCallPattern::set_target(const Code& target) const { |
61 object_pool_.SetObjectAt(target_code_pool_index_, target); | 58 object_pool_.SetObjectAt(target_code_pool_index_, target); |
62 // No need to flush the instruction cache, since the code is not modified. | 59 // No need to flush the instruction cache, since the code is not modified. |
63 } | 60 } |
64 | 61 |
65 | |
66 NativeFunction NativeCallPattern::native_function() const { | 62 NativeFunction NativeCallPattern::native_function() const { |
67 return reinterpret_cast<NativeFunction>( | 63 return reinterpret_cast<NativeFunction>( |
68 object_pool_.RawValueAt(native_function_pool_index_)); | 64 object_pool_.RawValueAt(native_function_pool_index_)); |
69 } | 65 } |
70 | 66 |
71 | |
72 void NativeCallPattern::set_native_function(NativeFunction func) const { | 67 void NativeCallPattern::set_native_function(NativeFunction func) const { |
73 object_pool_.SetRawValueAt(native_function_pool_index_, | 68 object_pool_.SetRawValueAt(native_function_pool_index_, |
74 reinterpret_cast<uword>(func)); | 69 reinterpret_cast<uword>(func)); |
75 } | 70 } |
76 | 71 |
77 | |
78 intptr_t InstructionPattern::OffsetFromPPIndex(intptr_t index) { | 72 intptr_t InstructionPattern::OffsetFromPPIndex(intptr_t index) { |
79 return Array::element_offset(index); | 73 return Array::element_offset(index); |
80 } | 74 } |
81 | 75 |
82 | |
83 // Decodes a load sequence ending at 'end' (the last instruction of the load | 76 // Decodes a load sequence ending at 'end' (the last instruction of the load |
84 // sequence is the instruction before the one at end). Returns a pointer to | 77 // sequence is the instruction before the one at end). Returns a pointer to |
85 // the first instruction in the sequence. Returns the register being loaded | 78 // the first instruction in the sequence. Returns the register being loaded |
86 // and the loaded object in the output parameters 'reg' and 'obj' | 79 // and the loaded object in the output parameters 'reg' and 'obj' |
87 // respectively. | 80 // respectively. |
88 uword InstructionPattern::DecodeLoadObject(uword end, | 81 uword InstructionPattern::DecodeLoadObject(uword end, |
89 const ObjectPool& object_pool, | 82 const ObjectPool& object_pool, |
90 Register* reg, | 83 Register* reg, |
91 Object* obj) { | 84 Object* obj) { |
92 // 1. LoadWordFromPool | 85 // 1. LoadWordFromPool |
93 // or | 86 // or |
94 // 2. LoadDecodableImmediate | 87 // 2. LoadDecodableImmediate |
95 uword start = 0; | 88 uword start = 0; |
96 Instr* instr = Instr::At(end - Instr::kInstrSize); | 89 Instr* instr = Instr::At(end - Instr::kInstrSize); |
97 if (instr->IsLoadStoreRegOp()) { | 90 if (instr->IsLoadStoreRegOp()) { |
98 // Case 1. | 91 // Case 1. |
99 intptr_t index = 0; | 92 intptr_t index = 0; |
100 start = DecodeLoadWordFromPool(end, reg, &index); | 93 start = DecodeLoadWordFromPool(end, reg, &index); |
101 *obj = object_pool.ObjectAt(index); | 94 *obj = object_pool.ObjectAt(index); |
102 } else { | 95 } else { |
103 // Case 2. | 96 // Case 2. |
104 intptr_t value = 0; | 97 intptr_t value = 0; |
105 start = DecodeLoadWordImmediate(end, reg, &value); | 98 start = DecodeLoadWordImmediate(end, reg, &value); |
106 *obj = reinterpret_cast<RawObject*>(value); | 99 *obj = reinterpret_cast<RawObject*>(value); |
107 } | 100 } |
108 return start; | 101 return start; |
109 } | 102 } |
110 | 103 |
111 | |
112 // Decodes a load sequence ending at 'end' (the last instruction of the load | 104 // Decodes a load sequence ending at 'end' (the last instruction of the load |
113 // sequence is the instruction before the one at end). Returns a pointer to | 105 // sequence is the instruction before the one at end). Returns a pointer to |
114 // the first instruction in the sequence. Returns the register being loaded | 106 // the first instruction in the sequence. Returns the register being loaded |
115 // and the loaded immediate value in the output parameters 'reg' and 'value' | 107 // and the loaded immediate value in the output parameters 'reg' and 'value' |
116 // respectively. | 108 // respectively. |
117 uword InstructionPattern::DecodeLoadWordImmediate(uword end, | 109 uword InstructionPattern::DecodeLoadWordImmediate(uword end, |
118 Register* reg, | 110 Register* reg, |
119 intptr_t* value) { | 111 intptr_t* value) { |
120 // 1. LoadWordFromPool | 112 // 1. LoadWordFromPool |
121 // or | 113 // or |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 instr = Instr::At(start); | 167 instr = Instr::At(start); |
176 ASSERT(instr->IsMoveWideOp()); | 168 ASSERT(instr->IsMoveWideOp()); |
177 ASSERT(instr->Bits(29, 2) == 2); | 169 ASSERT(instr->Bits(29, 2) == 2); |
178 ASSERT(instr->HWField() == 0); // movz dst, imm0, 0 | 170 ASSERT(instr->HWField() == 0); // movz dst, imm0, 0 |
179 ASSERT(instr->RdField() == *reg); | 171 ASSERT(instr->RdField() == *reg); |
180 *value |= static_cast<int64_t>(instr->Imm16Field()); | 172 *value |= static_cast<int64_t>(instr->Imm16Field()); |
181 | 173 |
182 return start; | 174 return start; |
183 } | 175 } |
184 | 176 |
185 | |
186 // Decodes a load sequence ending at 'end' (the last instruction of the load | 177 // Decodes a load sequence ending at 'end' (the last instruction of the load |
187 // sequence is the instruction before the one at end). Returns a pointer to | 178 // sequence is the instruction before the one at end). Returns a pointer to |
188 // the first instruction in the sequence. Returns the register being loaded | 179 // the first instruction in the sequence. Returns the register being loaded |
189 // and the index in the pool being read from in the output parameters 'reg' | 180 // and the index in the pool being read from in the output parameters 'reg' |
190 // and 'index' respectively. | 181 // and 'index' respectively. |
191 uword InstructionPattern::DecodeLoadWordFromPool(uword end, | 182 uword InstructionPattern::DecodeLoadWordFromPool(uword end, |
192 Register* reg, | 183 Register* reg, |
193 intptr_t* index) { | 184 intptr_t* index) { |
194 // 1. ldr dst, [pp, offset] | 185 // 1. ldr dst, [pp, offset] |
195 // or | 186 // or |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 ASSERT(instr->HWField() == 0); | 239 ASSERT(instr->HWField() == 0); |
249 offset |= instr->Imm16Field(); | 240 offset |= instr->Imm16Field(); |
250 } | 241 } |
251 } | 242 } |
252 // PP is untagged on ARM64. | 243 // PP is untagged on ARM64. |
253 ASSERT(Utils::IsAligned(offset, 8)); | 244 ASSERT(Utils::IsAligned(offset, 8)); |
254 *index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag); | 245 *index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag); |
255 return start; | 246 return start; |
256 } | 247 } |
257 | 248 |
258 | |
259 bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code& code, Object* obj) { | 249 bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code& code, Object* obj) { |
260 ASSERT(code.ContainsInstructionAt(pc)); | 250 ASSERT(code.ContainsInstructionAt(pc)); |
261 | 251 |
262 Instr* instr = Instr::At(pc); | 252 Instr* instr = Instr::At(pc); |
263 if (instr->IsLoadStoreRegOp() && (instr->Bit(22) == 1) && | 253 if (instr->IsLoadStoreRegOp() && (instr->Bit(22) == 1) && |
264 (instr->Bits(30, 2) == 3) && instr->Bit(24) == 1) { | 254 (instr->Bits(30, 2) == 3) && instr->Bit(24) == 1) { |
265 intptr_t offset = (instr->Imm12Field() << 3); | 255 intptr_t offset = (instr->Imm12Field() << 3); |
266 if (instr->RnField() == PP) { | 256 if (instr->RnField() == PP) { |
267 // PP is untagged on ARM64. | 257 // PP is untagged on ARM64. |
268 ASSERT(Utils::IsAligned(offset, 8)); | 258 ASSERT(Utils::IsAligned(offset, 8)); |
269 intptr_t index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag); | 259 intptr_t index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag); |
270 const ObjectPool& pool = ObjectPool::Handle(code.object_pool()); | 260 const ObjectPool& pool = ObjectPool::Handle(code.object_pool()); |
271 if (pool.InfoAt(index) == ObjectPool::kTaggedObject) { | 261 if (pool.InfoAt(index) == ObjectPool::kTaggedObject) { |
272 *obj = pool.ObjectAt(index); | 262 *obj = pool.ObjectAt(index); |
273 return true; | 263 return true; |
274 } | 264 } |
275 } else if (instr->RnField() == THR) { | 265 } else if (instr->RnField() == THR) { |
276 return Thread::ObjectAtOffset(offset, obj); | 266 return Thread::ObjectAtOffset(offset, obj); |
277 } | 267 } |
278 } | 268 } |
279 // TODO(rmacnak): Loads with offsets beyond 12 bits. | 269 // TODO(rmacnak): Loads with offsets beyond 12 bits. |
280 | 270 |
281 return false; | 271 return false; |
282 } | 272 } |
283 | 273 |
284 | |
285 // Encodes a load sequence ending at 'end'. Encodes a fixed length two | 274 // Encodes a load sequence ending at 'end'. Encodes a fixed length two |
286 // instruction load from the pool pointer in PP using the destination | 275 // instruction load from the pool pointer in PP using the destination |
287 // register reg as a temporary for the base address. | 276 // register reg as a temporary for the base address. |
288 // Assumes that the location has already been validated for patching. | 277 // Assumes that the location has already been validated for patching. |
289 void InstructionPattern::EncodeLoadWordFromPoolFixed(uword end, | 278 void InstructionPattern::EncodeLoadWordFromPoolFixed(uword end, |
290 int32_t offset) { | 279 int32_t offset) { |
291 uword start = end - Instr::kInstrSize; | 280 uword start = end - Instr::kInstrSize; |
292 Instr* instr = Instr::At(start); | 281 Instr* instr = Instr::At(start); |
293 const int32_t upper12 = offset & 0x00fff000; | 282 const int32_t upper12 = offset & 0x00fff000; |
294 const int32_t lower12 = offset & 0x00000fff; | 283 const int32_t lower12 = offset & 0x00000fff; |
295 ASSERT((offset & 0xff000000) == 0); // Can't encode > 24 bits. | 284 ASSERT((offset & 0xff000000) == 0); // Can't encode > 24 bits. |
296 ASSERT(((lower12 >> 3) << 3) == lower12); // 8-byte aligned. | 285 ASSERT(((lower12 >> 3) << 3) == lower12); // 8-byte aligned. |
297 instr->SetImm12Bits(instr->InstructionBits(), lower12 >> 3); | 286 instr->SetImm12Bits(instr->InstructionBits(), lower12 >> 3); |
298 | 287 |
299 start -= Instr::kInstrSize; | 288 start -= Instr::kInstrSize; |
300 instr = Instr::At(start); | 289 instr = Instr::At(start); |
301 instr->SetImm12Bits(instr->InstructionBits(), upper12 >> 12); | 290 instr->SetImm12Bits(instr->InstructionBits(), upper12 >> 12); |
302 instr->SetInstructionBits(instr->InstructionBits() | B22); | 291 instr->SetInstructionBits(instr->InstructionBits() | B22); |
303 } | 292 } |
304 | 293 |
305 | |
306 RawICData* CallPattern::IcData() { | 294 RawICData* CallPattern::IcData() { |
307 if (ic_data_.IsNull()) { | 295 if (ic_data_.IsNull()) { |
308 Register reg; | 296 Register reg; |
309 InstructionPattern::DecodeLoadObject(ic_data_load_end_, object_pool_, ®, | 297 InstructionPattern::DecodeLoadObject(ic_data_load_end_, object_pool_, ®, |
310 &ic_data_); | 298 &ic_data_); |
311 ASSERT(reg == R5); | 299 ASSERT(reg == R5); |
312 } | 300 } |
313 return ic_data_.raw(); | 301 return ic_data_.raw(); |
314 } | 302 } |
315 | 303 |
316 | |
317 RawCode* CallPattern::TargetCode() const { | 304 RawCode* CallPattern::TargetCode() const { |
318 return reinterpret_cast<RawCode*>( | 305 return reinterpret_cast<RawCode*>( |
319 object_pool_.ObjectAt(target_code_pool_index_)); | 306 object_pool_.ObjectAt(target_code_pool_index_)); |
320 } | 307 } |
321 | 308 |
322 | |
323 void CallPattern::SetTargetCode(const Code& target) const { | 309 void CallPattern::SetTargetCode(const Code& target) const { |
324 object_pool_.SetObjectAt(target_code_pool_index_, target); | 310 object_pool_.SetObjectAt(target_code_pool_index_, target); |
325 // No need to flush the instruction cache, since the code is not modified. | 311 // No need to flush the instruction cache, since the code is not modified. |
326 } | 312 } |
327 | 313 |
328 | |
329 SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code) | 314 SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code) |
330 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 315 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
331 data_pool_index_(-1), | 316 data_pool_index_(-1), |
332 target_pool_index_(-1) { | 317 target_pool_index_(-1) { |
333 ASSERT(code.ContainsInstructionAt(pc)); | 318 ASSERT(code.ContainsInstructionAt(pc)); |
334 // Last instruction: blr ip0. | 319 // Last instruction: blr ip0. |
335 ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f0200); | 320 ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f0200); |
336 | 321 |
337 Register reg; | 322 Register reg; |
338 uword data_load_end = InstructionPattern::DecodeLoadWordFromPool( | 323 uword data_load_end = InstructionPattern::DecodeLoadWordFromPool( |
339 pc - Instr::kInstrSize, ®, &data_pool_index_); | 324 pc - Instr::kInstrSize, ®, &data_pool_index_); |
340 ASSERT(reg == R5); | 325 ASSERT(reg == R5); |
341 InstructionPattern::DecodeLoadWordFromPool(data_load_end - Instr::kInstrSize, | 326 InstructionPattern::DecodeLoadWordFromPool(data_load_end - Instr::kInstrSize, |
342 ®, &target_pool_index_); | 327 ®, &target_pool_index_); |
343 ASSERT(reg == CODE_REG); | 328 ASSERT(reg == CODE_REG); |
344 } | 329 } |
345 | 330 |
346 | |
347 RawObject* SwitchableCallPattern::data() const { | 331 RawObject* SwitchableCallPattern::data() const { |
348 return object_pool_.ObjectAt(data_pool_index_); | 332 return object_pool_.ObjectAt(data_pool_index_); |
349 } | 333 } |
350 | 334 |
351 | |
352 RawCode* SwitchableCallPattern::target() const { | 335 RawCode* SwitchableCallPattern::target() const { |
353 return reinterpret_cast<RawCode*>(object_pool_.ObjectAt(target_pool_index_)); | 336 return reinterpret_cast<RawCode*>(object_pool_.ObjectAt(target_pool_index_)); |
354 } | 337 } |
355 | 338 |
356 | |
357 void SwitchableCallPattern::SetData(const Object& data) const { | 339 void SwitchableCallPattern::SetData(const Object& data) const { |
358 ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode()); | 340 ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode()); |
359 object_pool_.SetObjectAt(data_pool_index_, data); | 341 object_pool_.SetObjectAt(data_pool_index_, data); |
360 } | 342 } |
361 | 343 |
362 | |
363 void SwitchableCallPattern::SetTarget(const Code& target) const { | 344 void SwitchableCallPattern::SetTarget(const Code& target) const { |
364 ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode()); | 345 ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode()); |
365 object_pool_.SetObjectAt(target_pool_index_, target); | 346 object_pool_.SetObjectAt(target_pool_index_, target); |
366 } | 347 } |
367 | 348 |
368 | |
369 ReturnPattern::ReturnPattern(uword pc) : pc_(pc) {} | 349 ReturnPattern::ReturnPattern(uword pc) : pc_(pc) {} |
370 | 350 |
371 | |
372 bool ReturnPattern::IsValid() const { | 351 bool ReturnPattern::IsValid() const { |
373 Instr* bx_lr = Instr::At(pc_); | 352 Instr* bx_lr = Instr::At(pc_); |
374 const Register crn = ConcreteRegister(LR); | 353 const Register crn = ConcreteRegister(LR); |
375 const int32_t instruction = RET | (static_cast<int32_t>(crn) << kRnShift); | 354 const int32_t instruction = RET | (static_cast<int32_t>(crn) << kRnShift); |
376 return bx_lr->InstructionBits() == instruction; | 355 return bx_lr->InstructionBits() == instruction; |
377 } | 356 } |
378 | 357 |
379 } // namespace dart | 358 } // namespace dart |
380 | 359 |
381 #endif // defined TARGET_ARCH_ARM64 | 360 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |