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/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/constants_arm64.h" | 9 #include "vm/constants_arm64.h" |
10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
11 #include "vm/instructions.h" | 11 #include "vm/instructions.h" |
12 #include "vm/object.h" | 12 #include "vm/object.h" |
13 | 13 |
14 namespace dart { | 14 namespace dart { |
15 | 15 |
16 CallPattern::CallPattern(uword pc, const Code& code) | 16 CallPattern::CallPattern(uword pc, const Code& code) |
17 : object_pool_(Array::Handle(code.ObjectPool())), | 17 : object_pool_(Array::Handle(code.ObjectPool())), |
18 end_(pc), | 18 end_(pc), |
19 args_desc_load_end_(0), | 19 args_desc_load_end_(0), |
20 ic_data_load_end_(0), | 20 ic_data_load_end_(0), |
21 target_address_pool_index_(-1), | 21 target_address_pool_index_(-1), |
22 args_desc_(Array::Handle()), | 22 args_desc_(Array::Handle()), |
23 ic_data_(ICData::Handle()) { | 23 ic_data_(ICData::Handle()) { |
24 UNIMPLEMENTED(); | 24 ASSERT(code.ContainsInstructionAt(pc)); |
| 25 // Last instruction: blr ip0. |
| 26 ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200); |
| 27 |
| 28 Register reg; |
| 29 ic_data_load_end_ = |
| 30 InstructionPattern::DecodeLoadWordFromPool(end_ - Instr::kInstrSize, |
| 31 ®, |
| 32 &target_address_pool_index_); |
| 33 ASSERT(reg == IP0); |
25 } | 34 } |
26 | 35 |
27 | 36 |
28 int CallPattern::LengthInBytes() { | |
29 UNIMPLEMENTED(); | |
30 return 0; | |
31 } | |
32 | |
33 | |
34 // Decodes a load sequence ending at 'end' (the last instruction of the load | 37 // Decodes a load sequence ending at 'end' (the last instruction of the load |
35 // sequence is the instruction before the one at end). Returns a pointer to | 38 // sequence is the instruction before the one at end). Returns a pointer to |
36 // the first instruction in the sequence. Returns the register being loaded | 39 // the first instruction in the sequence. Returns the register being loaded |
37 // and the loaded object in the output parameters 'reg' and 'obj' | 40 // and the loaded object in the output parameters 'reg' and 'obj' |
38 // respectively. | 41 // respectively. |
39 uword InstructionPattern::DecodeLoadObject(uword end, | 42 uword InstructionPattern::DecodeLoadObject(uword end, |
40 const Array& object_pool, | 43 const Array& object_pool, |
41 Register* reg, | 44 Register* reg, |
42 Object* obj) { | 45 Object* obj) { |
43 UNIMPLEMENTED(); | 46 // 1. LoadWordFromPool |
44 return 0; | 47 // or |
| 48 // 2. LoadDecodableImmediate |
| 49 uword start = 0; |
| 50 Instr* instr = Instr::At(end - Instr::kInstrSize); |
| 51 if (instr->IsLoadStoreRegOp()) { |
| 52 // Case 1. |
| 53 intptr_t index = 0; |
| 54 start = DecodeLoadWordFromPool(end, reg, &index); |
| 55 *obj = object_pool.At(index); |
| 56 } else { |
| 57 // Case 2. |
| 58 intptr_t value = 0; |
| 59 start = DecodeLoadWordImmediate(end, reg, &value); |
| 60 *obj = reinterpret_cast<RawObject*>(value); |
| 61 } |
| 62 return start; |
45 } | 63 } |
46 | 64 |
47 | 65 |
48 // Decodes a load sequence ending at 'end' (the last instruction of the load | 66 // Decodes a load sequence ending at 'end' (the last instruction of the load |
49 // sequence is the instruction before the one at end). Returns a pointer to | 67 // sequence is the instruction before the one at end). Returns a pointer to |
50 // the first instruction in the sequence. Returns the register being loaded | 68 // the first instruction in the sequence. Returns the register being loaded |
51 // and the loaded immediate value in the output parameters 'reg' and 'value' | 69 // and the loaded immediate value in the output parameters 'reg' and 'value' |
52 // respectively. | 70 // respectively. |
53 uword InstructionPattern::DecodeLoadWordImmediate(uword end, | 71 uword InstructionPattern::DecodeLoadWordImmediate(uword end, |
54 Register* reg, | 72 Register* reg, |
55 intptr_t* value) { | 73 intptr_t* value) { |
56 UNIMPLEMENTED(); | 74 // 1. LoadWordFromPool |
57 return 0; | 75 // or |
| 76 // 2. LoadWordFromPool |
| 77 // orri |
| 78 // or |
| 79 // 3. LoadPatchableImmediate |
| 80 uword start = end - Instr::kInstrSize; |
| 81 Instr* instr = Instr::At(start); |
| 82 bool odd = false; |
| 83 |
| 84 // Case 2. |
| 85 if (instr->IsLogicalImmOp()) { |
| 86 ASSERT(instr->Bit(29) == 1); |
| 87 odd = true; |
| 88 // end points at orri so that we can pass it to DecodeLoadWordFromPool. |
| 89 end = start; |
| 90 start -= Instr::kInstrSize; |
| 91 instr = Instr::At(start); |
| 92 // Case 2 falls through to case 1. |
| 93 } |
| 94 |
| 95 // Case 1. |
| 96 if (instr->IsLoadStoreRegOp()) { |
| 97 start = DecodeLoadWordFromPool(end, reg, value); |
| 98 if (odd) { |
| 99 *value |= 1; |
| 100 } |
| 101 return start; |
| 102 } |
| 103 |
| 104 // Case 3. |
| 105 // movk dst, imm3, 3; movk dst, imm2, 2; movk dst, imm1, 1; movz dst, imm0, 0 |
| 106 ASSERT(instr->IsMoveWideOp()); |
| 107 ASSERT(instr->Bits(29, 2) == 3); |
| 108 ASSERT(instr->HWField() == 3); // movk dst, imm3, 3 |
| 109 *reg = instr->RdField(); |
| 110 *value = static_cast<int64_t>(instr->Imm16Field()) << 48; |
| 111 |
| 112 start -= Instr::kInstrSize; |
| 113 instr = Instr::At(start); |
| 114 ASSERT(instr->IsMoveWideOp()); |
| 115 ASSERT(instr->Bits(29, 2) == 3); |
| 116 ASSERT(instr->HWField() == 2); // movk dst, imm2, 2 |
| 117 ASSERT(instr->RdField() == *reg); |
| 118 *value |= static_cast<int64_t>(instr->Imm16Field()) << 32; |
| 119 |
| 120 start -= Instr::kInstrSize; |
| 121 instr = Instr::At(start); |
| 122 ASSERT(instr->IsMoveWideOp()); |
| 123 ASSERT(instr->Bits(29, 2) == 3); |
| 124 ASSERT(instr->HWField() == 1); // movk dst, imm1, 1 |
| 125 ASSERT(instr->RdField() == *reg); |
| 126 *value |= static_cast<int64_t>(instr->Imm16Field()) << 16; |
| 127 |
| 128 start -= Instr::kInstrSize; |
| 129 instr = Instr::At(start); |
| 130 ASSERT(instr->IsMoveWideOp()); |
| 131 ASSERT(instr->Bits(29, 2) == 2); |
| 132 ASSERT(instr->HWField() == 0); // movz dst, imm0, 0 |
| 133 ASSERT(instr->RdField() == *reg); |
| 134 *value |= static_cast<int64_t>(instr->Imm16Field()); |
| 135 |
| 136 return start; |
58 } | 137 } |
59 | 138 |
60 | 139 |
61 // Decodes a load sequence ending at 'end' (the last instruction of the load | 140 // Decodes a load sequence ending at 'end' (the last instruction of the load |
62 // sequence is the instruction before the one at end). Returns a pointer to | 141 // sequence is the instruction before the one at end). Returns a pointer to |
63 // the first instruction in the sequence. Returns the register being loaded | 142 // the first instruction in the sequence. Returns the register being loaded |
64 // and the index in the pool being read from in the output parameters 'reg' | 143 // and the index in the pool being read from in the output parameters 'reg' |
65 // and 'index' respectively. | 144 // and 'index' respectively. |
66 uword InstructionPattern::DecodeLoadWordFromPool(uword end, | 145 uword InstructionPattern::DecodeLoadWordFromPool(uword end, |
67 Register* reg, | 146 Register* reg, |
68 intptr_t* index) { | 147 intptr_t* index) { |
69 UNIMPLEMENTED(); | 148 // 1. ldr dst, [pp, offset] |
70 return 0; | 149 // or |
| 150 // 2. movz dst, low_offset, 0 |
| 151 // movk dst, hi_offset, 1 (optional) |
| 152 // ldr dst, [pp, dst] |
| 153 uword start = end - Instr::kInstrSize; |
| 154 Instr* instr = Instr::At(start); |
| 155 intptr_t offset = 0; |
| 156 |
| 157 // Last instruction is always an ldr into a 64-bit X register. |
| 158 ASSERT(instr->IsLoadStoreRegOp() && (instr->Bit(22) == 1) && |
| 159 (instr->Bits(30, 2) == 3)); |
| 160 |
| 161 // Grab the destination register from the ldr instruction. |
| 162 *reg = instr->RtField(); |
| 163 |
| 164 if (instr->Bit(24) == 1) { |
| 165 // pp + scaled unsigned 12-bit immediate offset. |
| 166 // Case 1. |
| 167 offset = instr->Imm12Field() << 3; |
| 168 } else { |
| 169 ASSERT(instr->Bits(10, 2) == 2); |
| 170 // We have to look at the preceding one or two instructions to find the |
| 171 // offset. |
| 172 |
| 173 start -= Instr::kInstrSize; |
| 174 instr = Instr::At(start); |
| 175 ASSERT(instr->IsMoveWideOp()); |
| 176 ASSERT(instr->RdField() == *reg); |
| 177 if (instr->Bits(29, 2) == 2) { // movz dst, low_offset, 0 |
| 178 ASSERT(instr->HWField() == 0); |
| 179 offset = instr->Imm16Field(); |
| 180 // no high offset. |
| 181 } else { |
| 182 ASSERT(instr->Bits(29, 2) == 3); // movk dst, high_offset, 1 |
| 183 ASSERT(instr->HWField() == 1); |
| 184 offset = instr->Imm16Field() << 16; |
| 185 |
| 186 start -= Instr::kInstrSize; |
| 187 instr = Instr::At(start); |
| 188 ASSERT(instr->IsMoveWideOp()); |
| 189 ASSERT(instr->RdField() == *reg); |
| 190 ASSERT(instr->Bits(29, 2) == 2); // movz dst, low_offset, 0 |
| 191 ASSERT(instr->HWField() == 0); |
| 192 offset |= instr->Imm16Field(); |
| 193 } |
| 194 } |
| 195 ASSERT(Utils::IsAligned(offset, 8)); |
| 196 *index = (offset - Array::data_offset()) / 8; |
| 197 return start; |
71 } | 198 } |
72 | 199 |
73 | 200 |
74 RawICData* CallPattern::IcData() { | 201 RawICData* CallPattern::IcData() { |
75 UNIMPLEMENTED(); | 202 if (ic_data_.IsNull()) { |
76 return NULL; | 203 Register reg; |
| 204 args_desc_load_end_ = |
| 205 InstructionPattern::DecodeLoadObject(ic_data_load_end_, |
| 206 object_pool_, |
| 207 ®, |
| 208 &ic_data_); |
| 209 ASSERT(reg == R5); |
| 210 } |
| 211 return ic_data_.raw(); |
77 } | 212 } |
78 | 213 |
79 | 214 |
80 RawArray* CallPattern::ClosureArgumentsDescriptor() { | 215 RawArray* CallPattern::ClosureArgumentsDescriptor() { |
81 UNIMPLEMENTED(); | 216 if (args_desc_.IsNull()) { |
82 return NULL; | 217 IcData(); // Loading of the ic_data must be decoded first, if not already. |
| 218 Register reg; |
| 219 InstructionPattern::DecodeLoadObject(args_desc_load_end_, |
| 220 object_pool_, |
| 221 ®, |
| 222 &args_desc_); |
| 223 ASSERT(reg == R4); |
| 224 } |
| 225 return args_desc_.raw(); |
83 } | 226 } |
84 | 227 |
85 | 228 |
86 uword CallPattern::TargetAddress() const { | 229 uword CallPattern::TargetAddress() const { |
87 UNIMPLEMENTED(); | 230 ASSERT(target_address_pool_index_ >= 0); |
88 return 0; | 231 const Object& target_address = |
| 232 Object::Handle(object_pool_.At(target_address_pool_index_)); |
| 233 ASSERT(target_address.IsSmi()); |
| 234 // The address is stored in the object array as a RawSmi. |
| 235 return reinterpret_cast<uword>(target_address.raw()); |
89 } | 236 } |
90 | 237 |
91 | 238 |
92 void CallPattern::SetTargetAddress(uword target_address) const { | 239 void CallPattern::SetTargetAddress(uword target_address) const { |
93 UNIMPLEMENTED(); | 240 ASSERT(Utils::IsAligned(target_address, 4)); |
| 241 // The address is stored in the object array as a RawSmi. |
| 242 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target_address)); |
| 243 object_pool_.SetAt(target_address_pool_index_, smi); |
| 244 // No need to flush the instruction cache, since the code is not modified. |
94 } | 245 } |
95 | 246 |
96 | 247 |
97 void CallPattern::InsertAt(uword pc, uword target_address) { | 248 void CallPattern::InsertAt(uword pc, uword target_address) { |
98 UNIMPLEMENTED(); | 249 Instr* movz0 = Instr::At(pc + (0 * Instr::kInstrSize)); |
| 250 Instr* movk1 = Instr::At(pc + (1 * Instr::kInstrSize)); |
| 251 Instr* movk2 = Instr::At(pc + (2 * Instr::kInstrSize)); |
| 252 Instr* movk3 = Instr::At(pc + (3 * Instr::kInstrSize)); |
| 253 Instr* blr = Instr::At(pc + (4 * Instr::kInstrSize)); |
| 254 const uint32_t w0 = Utils::Low32Bits(target_address); |
| 255 const uint32_t w1 = Utils::High32Bits(target_address); |
| 256 const uint16_t h0 = Utils::Low16Bits(w0); |
| 257 const uint16_t h1 = Utils::High16Bits(w0); |
| 258 const uint16_t h2 = Utils::Low16Bits(w1); |
| 259 const uint16_t h3 = Utils::High16Bits(w1); |
| 260 |
| 261 movz0->SetMoveWideBits(MOVZ, IP0, h0, 0, kDoubleWord); |
| 262 movk1->SetMoveWideBits(MOVK, IP0, h1, 1, kDoubleWord); |
| 263 movk2->SetMoveWideBits(MOVK, IP0, h2, 2, kDoubleWord); |
| 264 movk3->SetMoveWideBits(MOVK, IP0, h3, 3, kDoubleWord); |
| 265 blr->SetUnconditionalBranchRegBits(BLR, IP0); |
| 266 |
| 267 ASSERT(kLengthInBytes == 5 * Instr::kInstrSize); |
| 268 CPU::FlushICache(pc, kLengthInBytes); |
99 } | 269 } |
100 | 270 |
101 | 271 |
102 JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { } | 272 JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { } |
103 | 273 |
104 | 274 |
105 int JumpPattern::pattern_length_in_bytes() { | |
106 UNIMPLEMENTED(); | |
107 return 0; | |
108 } | |
109 | |
110 | |
111 bool JumpPattern::IsValid() const { | 275 bool JumpPattern::IsValid() const { |
112 UNIMPLEMENTED(); | 276 Instr* movz0 = Instr::At(pc_ + (0 * Instr::kInstrSize)); |
113 return false; | 277 Instr* movk1 = Instr::At(pc_ + (1 * Instr::kInstrSize)); |
| 278 Instr* movk2 = Instr::At(pc_ + (2 * Instr::kInstrSize)); |
| 279 Instr* movk3 = Instr::At(pc_ + (3 * Instr::kInstrSize)); |
| 280 Instr* br = Instr::At(pc_ + (4 * Instr::kInstrSize)); |
| 281 return (movz0->IsMoveWideOp()) && (movz0->Bits(29, 2) == 2) && |
| 282 (movk1->IsMoveWideOp()) && (movk1->Bits(29, 2) == 3) && |
| 283 (movk2->IsMoveWideOp()) && (movk2->Bits(29, 2) == 3) && |
| 284 (movk3->IsMoveWideOp()) && (movk3->Bits(29, 2) == 3) && |
| 285 (br->IsUnconditionalBranchRegOp()) && (br->Bits(16, 5) == 31); |
114 } | 286 } |
115 | 287 |
116 | 288 |
117 uword JumpPattern::TargetAddress() const { | 289 uword JumpPattern::TargetAddress() const { |
118 UNIMPLEMENTED(); | 290 Instr* movz0 = Instr::At(pc_ + (0 * Instr::kInstrSize)); |
119 return 0; | 291 Instr* movk1 = Instr::At(pc_ + (1 * Instr::kInstrSize)); |
| 292 Instr* movk2 = Instr::At(pc_ + (2 * Instr::kInstrSize)); |
| 293 Instr* movk3 = Instr::At(pc_ + (3 * Instr::kInstrSize)); |
| 294 const uint16_t imm0 = movz0->Imm16Field(); |
| 295 const uint16_t imm1 = movk1->Imm16Field(); |
| 296 const uint16_t imm2 = movk2->Imm16Field(); |
| 297 const uint16_t imm3 = movk3->Imm16Field(); |
| 298 const int64_t target = |
| 299 (static_cast<int64_t>(imm0)) | |
| 300 (static_cast<int64_t>(imm1) << 16) | |
| 301 (static_cast<int64_t>(imm2) << 32) | |
| 302 (static_cast<int64_t>(imm3) << 48); |
| 303 return target; |
120 } | 304 } |
121 | 305 |
122 | 306 |
123 void JumpPattern::SetTargetAddress(uword target_address) const { | 307 void JumpPattern::SetTargetAddress(uword target_address) const { |
124 UNIMPLEMENTED(); | 308 Instr* movz0 = Instr::At(pc_ + (0 * Instr::kInstrSize)); |
| 309 Instr* movk1 = Instr::At(pc_ + (1 * Instr::kInstrSize)); |
| 310 Instr* movk2 = Instr::At(pc_ + (2 * Instr::kInstrSize)); |
| 311 Instr* movk3 = Instr::At(pc_ + (3 * Instr::kInstrSize)); |
| 312 const int32_t movz0_bits = movz0->InstructionBits(); |
| 313 const int32_t movk1_bits = movk1->InstructionBits(); |
| 314 const int32_t movk2_bits = movk2->InstructionBits(); |
| 315 const int32_t movk3_bits = movk3->InstructionBits(); |
| 316 |
| 317 const uint32_t w0 = Utils::Low32Bits(target_address); |
| 318 const uint32_t w1 = Utils::High32Bits(target_address); |
| 319 const uint16_t h0 = Utils::Low16Bits(w0); |
| 320 const uint16_t h1 = Utils::High16Bits(w0); |
| 321 const uint16_t h2 = Utils::Low16Bits(w1); |
| 322 const uint16_t h3 = Utils::High16Bits(w1); |
| 323 |
| 324 movz0->SetInstructionBits((movz0_bits & ~kImm16Mask) | (h0 << kImm16Shift)); |
| 325 movk1->SetInstructionBits((movk1_bits & ~kImm16Mask) | (h1 << kImm16Shift)); |
| 326 movk2->SetInstructionBits((movk2_bits & ~kImm16Mask) | (h2 << kImm16Shift)); |
| 327 movk3->SetInstructionBits((movk3_bits & ~kImm16Mask) | (h3 << kImm16Shift)); |
| 328 CPU::FlushICache(pc_, 4 * Instr::kInstrSize); |
125 } | 329 } |
126 | 330 |
127 } // namespace dart | 331 } // namespace dart |
128 | 332 |
129 #endif // defined TARGET_ARCH_ARM64 | 333 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |