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 |
11 #include "vm/assembler.h" | 11 #include "vm/assembler.h" |
12 #include "vm/constants_arm64.h" | 12 #include "vm/constants_arm64.h" |
13 #include "vm/cpu.h" | 13 #include "vm/cpu.h" |
14 #include "vm/object.h" | 14 #include "vm/object.h" |
15 | 15 |
16 namespace dart { | 16 namespace dart { |
17 | 17 |
18 CallPattern::CallPattern(uword pc, const Code& code) | 18 CallPattern::CallPattern(uword pc, const Code& code) |
19 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 19 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
20 end_(pc), | 20 end_(pc), |
21 ic_data_load_end_(0), | 21 ic_data_load_end_(0), |
22 target_code_pool_index_(-1), | 22 target_code_pool_index_(-1), |
23 ic_data_(ICData::Handle()) { | 23 ic_data_(ICData::Handle()) { |
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_ = | 29 ic_data_load_end_ = InstructionPattern::DecodeLoadWordFromPool( |
30 InstructionPattern::DecodeLoadWordFromPool(end_ - 2 * Instr::kInstrSize, | 30 end_ - 2 * Instr::kInstrSize, ®, &target_code_pool_index_); |
31 ®, | |
32 &target_code_pool_index_); | |
33 ASSERT(reg == CODE_REG); | 31 ASSERT(reg == CODE_REG); |
34 } | 32 } |
35 | 33 |
36 | 34 |
37 NativeCallPattern::NativeCallPattern(uword pc, const Code& code) | 35 NativeCallPattern::NativeCallPattern(uword pc, const Code& code) |
38 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 36 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
39 end_(pc), | 37 end_(pc), |
40 native_function_pool_index_(-1), | 38 native_function_pool_index_(-1), |
41 target_code_pool_index_(-1) { | 39 target_code_pool_index_(-1) { |
42 ASSERT(code.ContainsInstructionAt(pc)); | 40 ASSERT(code.ContainsInstructionAt(pc)); |
43 // Last instruction: blr ip0. | 41 // Last instruction: blr ip0. |
44 ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200); | 42 ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200); |
45 | 43 |
46 Register reg; | 44 Register reg; |
47 uword native_function_load_end = | 45 uword native_function_load_end = InstructionPattern::DecodeLoadWordFromPool( |
48 InstructionPattern::DecodeLoadWordFromPool(end_ - 2 * Instr::kInstrSize, | 46 end_ - 2 * Instr::kInstrSize, ®, &target_code_pool_index_); |
49 ®, | |
50 &target_code_pool_index_); | |
51 ASSERT(reg == CODE_REG); | 47 ASSERT(reg == CODE_REG); |
52 InstructionPattern::DecodeLoadWordFromPool(native_function_load_end, | 48 InstructionPattern::DecodeLoadWordFromPool(native_function_load_end, ®, |
53 ®, | |
54 &native_function_pool_index_); | 49 &native_function_pool_index_); |
55 ASSERT(reg == R5); | 50 ASSERT(reg == R5); |
56 } | 51 } |
57 | 52 |
58 | 53 |
59 RawCode* NativeCallPattern::target() const { | 54 RawCode* NativeCallPattern::target() const { |
60 return reinterpret_cast<RawCode*>( | 55 return reinterpret_cast<RawCode*>( |
61 object_pool_.ObjectAt(target_code_pool_index_)); | 56 object_pool_.ObjectAt(target_code_pool_index_)); |
62 } | 57 } |
63 | 58 |
64 | 59 |
65 void NativeCallPattern::set_target(const Code& target) const { | 60 void NativeCallPattern::set_target(const Code& target) const { |
66 object_pool_.SetObjectAt(target_code_pool_index_, target); | 61 object_pool_.SetObjectAt(target_code_pool_index_, target); |
67 // No need to flush the instruction cache, since the code is not modified. | 62 // No need to flush the instruction cache, since the code is not modified. |
68 } | 63 } |
69 | 64 |
70 | 65 |
71 NativeFunction NativeCallPattern::native_function() const { | 66 NativeFunction NativeCallPattern::native_function() const { |
72 return reinterpret_cast<NativeFunction>( | 67 return reinterpret_cast<NativeFunction>( |
73 object_pool_.RawValueAt(native_function_pool_index_)); | 68 object_pool_.RawValueAt(native_function_pool_index_)); |
74 } | 69 } |
75 | 70 |
76 | 71 |
77 void NativeCallPattern::set_native_function(NativeFunction func) const { | 72 void NativeCallPattern::set_native_function(NativeFunction func) const { |
78 object_pool_.SetRawValueAt(native_function_pool_index_, | 73 object_pool_.SetRawValueAt(native_function_pool_index_, |
79 reinterpret_cast<uword>(func)); | 74 reinterpret_cast<uword>(func)); |
80 } | 75 } |
81 | 76 |
82 | 77 |
83 intptr_t InstructionPattern::OffsetFromPPIndex(intptr_t index) { | 78 intptr_t InstructionPattern::OffsetFromPPIndex(intptr_t index) { |
84 return Array::element_offset(index); | 79 return Array::element_offset(index); |
85 } | 80 } |
86 | 81 |
87 | 82 |
88 // Decodes a load sequence ending at 'end' (the last instruction of the load | 83 // Decodes a load sequence ending at 'end' (the last instruction of the load |
89 // sequence is the instruction before the one at end). Returns a pointer to | 84 // sequence is the instruction before the one at end). Returns a pointer to |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 // or | 198 // or |
204 // 3. movz dst, low_offset, 0 | 199 // 3. movz dst, low_offset, 0 |
205 // movk dst, hi_offset, 1 (optional) | 200 // movk dst, hi_offset, 1 (optional) |
206 // ldr dst, [pp, dst] | 201 // ldr dst, [pp, dst] |
207 uword start = end - Instr::kInstrSize; | 202 uword start = end - Instr::kInstrSize; |
208 Instr* instr = Instr::At(start); | 203 Instr* instr = Instr::At(start); |
209 intptr_t offset = 0; | 204 intptr_t offset = 0; |
210 | 205 |
211 // Last instruction is always an ldr into a 64-bit X register. | 206 // Last instruction is always an ldr into a 64-bit X register. |
212 ASSERT(instr->IsLoadStoreRegOp() && (instr->Bit(22) == 1) && | 207 ASSERT(instr->IsLoadStoreRegOp() && (instr->Bit(22) == 1) && |
213 (instr->Bits(30, 2) == 3)); | 208 (instr->Bits(30, 2) == 3)); |
214 | 209 |
215 // Grab the destination register from the ldr instruction. | 210 // Grab the destination register from the ldr instruction. |
216 *reg = instr->RtField(); | 211 *reg = instr->RtField(); |
217 | 212 |
218 if (instr->Bit(24) == 1) { | 213 if (instr->Bit(24) == 1) { |
219 // base + scaled unsigned 12-bit immediate offset. | 214 // base + scaled unsigned 12-bit immediate offset. |
220 // Case 1. | 215 // Case 1. |
221 offset |= (instr->Imm12Field() << 3); | 216 offset |= (instr->Imm12Field() << 3); |
222 if (instr->RnField() == *reg) { | 217 if (instr->RnField() == *reg) { |
223 start -= Instr::kInstrSize; | 218 start -= Instr::kInstrSize; |
(...skipping 30 matching lines...) Expand all Loading... |
254 offset |= instr->Imm16Field(); | 249 offset |= instr->Imm16Field(); |
255 } | 250 } |
256 } | 251 } |
257 // PP is untagged on ARM64. | 252 // PP is untagged on ARM64. |
258 ASSERT(Utils::IsAligned(offset, 8)); | 253 ASSERT(Utils::IsAligned(offset, 8)); |
259 *index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag); | 254 *index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag); |
260 return start; | 255 return start; |
261 } | 256 } |
262 | 257 |
263 | 258 |
264 bool DecodeLoadObjectFromPoolOrThread(uword pc, | 259 bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code& code, Object* obj) { |
265 const Code& code, | |
266 Object* obj) { | |
267 ASSERT(code.ContainsInstructionAt(pc)); | 260 ASSERT(code.ContainsInstructionAt(pc)); |
268 | 261 |
269 Instr* instr = Instr::At(pc); | 262 Instr* instr = Instr::At(pc); |
270 if (instr->IsLoadStoreRegOp() && (instr->Bit(22) == 1) && | 263 if (instr->IsLoadStoreRegOp() && (instr->Bit(22) == 1) && |
271 (instr->Bits(30, 2) == 3) && instr->Bit(24) == 1) { | 264 (instr->Bits(30, 2) == 3) && instr->Bit(24) == 1) { |
272 intptr_t offset = (instr->Imm12Field() << 3); | 265 intptr_t offset = (instr->Imm12Field() << 3); |
273 if (instr->RnField() == PP) { | 266 if (instr->RnField() == PP) { |
274 // PP is untagged on ARM64. | 267 // PP is untagged on ARM64. |
275 ASSERT(Utils::IsAligned(offset, 8)); | 268 ASSERT(Utils::IsAligned(offset, 8)); |
276 intptr_t index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag); | 269 intptr_t index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag); |
(...skipping 15 matching lines...) Expand all Loading... |
292 // Encodes a load sequence ending at 'end'. Encodes a fixed length two | 285 // Encodes a load sequence ending at 'end'. Encodes a fixed length two |
293 // instruction load from the pool pointer in PP using the destination | 286 // instruction load from the pool pointer in PP using the destination |
294 // register reg as a temporary for the base address. | 287 // register reg as a temporary for the base address. |
295 // Assumes that the location has already been validated for patching. | 288 // Assumes that the location has already been validated for patching. |
296 void InstructionPattern::EncodeLoadWordFromPoolFixed(uword end, | 289 void InstructionPattern::EncodeLoadWordFromPoolFixed(uword end, |
297 int32_t offset) { | 290 int32_t offset) { |
298 uword start = end - Instr::kInstrSize; | 291 uword start = end - Instr::kInstrSize; |
299 Instr* instr = Instr::At(start); | 292 Instr* instr = Instr::At(start); |
300 const int32_t upper12 = offset & 0x00fff000; | 293 const int32_t upper12 = offset & 0x00fff000; |
301 const int32_t lower12 = offset & 0x00000fff; | 294 const int32_t lower12 = offset & 0x00000fff; |
302 ASSERT((offset & 0xff000000) == 0); // Can't encode > 24 bits. | 295 ASSERT((offset & 0xff000000) == 0); // Can't encode > 24 bits. |
303 ASSERT(((lower12 >> 3) << 3) == lower12); // 8-byte aligned. | 296 ASSERT(((lower12 >> 3) << 3) == lower12); // 8-byte aligned. |
304 instr->SetImm12Bits(instr->InstructionBits(), lower12 >> 3); | 297 instr->SetImm12Bits(instr->InstructionBits(), lower12 >> 3); |
305 | 298 |
306 start -= Instr::kInstrSize; | 299 start -= Instr::kInstrSize; |
307 instr = Instr::At(start); | 300 instr = Instr::At(start); |
308 instr->SetImm12Bits(instr->InstructionBits(), upper12 >> 12); | 301 instr->SetImm12Bits(instr->InstructionBits(), upper12 >> 12); |
309 instr->SetInstructionBits(instr->InstructionBits() | B22); | 302 instr->SetInstructionBits(instr->InstructionBits() | B22); |
310 } | 303 } |
311 | 304 |
312 | 305 |
313 RawICData* CallPattern::IcData() { | 306 RawICData* CallPattern::IcData() { |
314 if (ic_data_.IsNull()) { | 307 if (ic_data_.IsNull()) { |
315 Register reg; | 308 Register reg; |
316 InstructionPattern::DecodeLoadObject(ic_data_load_end_, | 309 InstructionPattern::DecodeLoadObject(ic_data_load_end_, object_pool_, ®, |
317 object_pool_, | |
318 ®, | |
319 &ic_data_); | 310 &ic_data_); |
320 ASSERT(reg == R5); | 311 ASSERT(reg == R5); |
321 } | 312 } |
322 return ic_data_.raw(); | 313 return ic_data_.raw(); |
323 } | 314 } |
324 | 315 |
325 | 316 |
326 RawCode* CallPattern::TargetCode() const { | 317 RawCode* CallPattern::TargetCode() const { |
327 return reinterpret_cast<RawCode*>( | 318 return reinterpret_cast<RawCode*>( |
328 object_pool_.ObjectAt(target_code_pool_index_)); | 319 object_pool_.ObjectAt(target_code_pool_index_)); |
329 } | 320 } |
330 | 321 |
331 | 322 |
332 void CallPattern::SetTargetCode(const Code& target) const { | 323 void CallPattern::SetTargetCode(const Code& target) const { |
333 object_pool_.SetObjectAt(target_code_pool_index_, target); | 324 object_pool_.SetObjectAt(target_code_pool_index_, target); |
334 // No need to flush the instruction cache, since the code is not modified. | 325 // No need to flush the instruction cache, since the code is not modified. |
335 } | 326 } |
336 | 327 |
337 | 328 |
338 SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code) | 329 SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code) |
339 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 330 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
340 data_pool_index_(-1), | 331 data_pool_index_(-1), |
341 target_pool_index_(-1) { | 332 target_pool_index_(-1) { |
342 ASSERT(code.ContainsInstructionAt(pc)); | 333 ASSERT(code.ContainsInstructionAt(pc)); |
343 // Last instruction: blr ip0. | 334 // Last instruction: blr ip0. |
344 ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f0200); | 335 ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f0200); |
345 | 336 |
346 Register reg; | 337 Register reg; |
347 uword data_load_end = | 338 uword data_load_end = InstructionPattern::DecodeLoadWordFromPool( |
348 InstructionPattern::DecodeLoadWordFromPool(pc - Instr::kInstrSize, | 339 pc - Instr::kInstrSize, ®, &data_pool_index_); |
349 ®, | |
350 &data_pool_index_); | |
351 ASSERT(reg == R5); | 340 ASSERT(reg == R5); |
352 InstructionPattern::DecodeLoadWordFromPool(data_load_end - Instr::kInstrSize, | 341 InstructionPattern::DecodeLoadWordFromPool(data_load_end - Instr::kInstrSize, |
353 ®, | 342 ®, &target_pool_index_); |
354 &target_pool_index_); | |
355 ASSERT(reg == CODE_REG); | 343 ASSERT(reg == CODE_REG); |
356 } | 344 } |
357 | 345 |
358 | 346 |
359 RawObject* SwitchableCallPattern::data() const { | 347 RawObject* SwitchableCallPattern::data() const { |
360 return object_pool_.ObjectAt(data_pool_index_); | 348 return object_pool_.ObjectAt(data_pool_index_); |
361 } | 349 } |
362 | 350 |
363 | 351 |
364 RawCode* SwitchableCallPattern::target() const { | 352 RawCode* SwitchableCallPattern::target() const { |
365 return reinterpret_cast<RawCode*>( | 353 return reinterpret_cast<RawCode*>(object_pool_.ObjectAt(target_pool_index_)); |
366 object_pool_.ObjectAt(target_pool_index_)); | |
367 } | 354 } |
368 | 355 |
369 | 356 |
370 void SwitchableCallPattern::SetData(const Object& data) const { | 357 void SwitchableCallPattern::SetData(const Object& data) const { |
371 ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode()); | 358 ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode()); |
372 object_pool_.SetObjectAt(data_pool_index_, data); | 359 object_pool_.SetObjectAt(data_pool_index_, data); |
373 } | 360 } |
374 | 361 |
375 | 362 |
376 void SwitchableCallPattern::SetTarget(const Code& target) const { | 363 void SwitchableCallPattern::SetTarget(const Code& target) const { |
377 ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode()); | 364 ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode()); |
378 object_pool_.SetObjectAt(target_pool_index_, target); | 365 object_pool_.SetObjectAt(target_pool_index_, target); |
379 } | 366 } |
380 | 367 |
381 | 368 |
382 ReturnPattern::ReturnPattern(uword pc) | 369 ReturnPattern::ReturnPattern(uword pc) : pc_(pc) {} |
383 : pc_(pc) { | |
384 } | |
385 | 370 |
386 | 371 |
387 bool ReturnPattern::IsValid() const { | 372 bool ReturnPattern::IsValid() const { |
388 Instr* bx_lr = Instr::At(pc_); | 373 Instr* bx_lr = Instr::At(pc_); |
389 const Register crn = ConcreteRegister(LR); | 374 const Register crn = ConcreteRegister(LR); |
390 const int32_t instruction = RET | (static_cast<int32_t>(crn) << kRnShift); | 375 const int32_t instruction = RET | (static_cast<int32_t>(crn) << kRnShift); |
391 return bx_lr->InstructionBits() == instruction; | 376 return bx_lr->InstructionBits() == instruction; |
392 } | 377 } |
393 | 378 |
394 } // namespace dart | 379 } // namespace dart |
395 | 380 |
396 #endif // defined TARGET_ARCH_ARM64 | 381 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |