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