| 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 |