OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
7 | 7 |
| 8 #include "vm/assembler.h" |
8 #include "vm/constants_arm.h" | 9 #include "vm/constants_arm.h" |
9 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
10 #include "vm/instructions.h" | 11 #include "vm/instructions.h" |
11 #include "vm/object.h" | 12 #include "vm/object.h" |
12 | 13 |
13 namespace dart { | 14 namespace dart { |
14 | 15 |
15 CallPattern::CallPattern(uword pc, const Code& code) | 16 CallPattern::CallPattern(uword pc, const Code& code) |
16 : object_pool_(Array::Handle(code.ObjectPool())), | 17 : object_pool_(Array::Handle(code.ObjectPool())), |
17 end_(pc), | 18 end_(pc), |
18 args_desc_load_end_(0), | 19 args_desc_load_end_(0), |
19 ic_data_load_end_(0), | 20 ic_data_load_end_(0), |
20 target_address_pool_index_(-1), | 21 target_address_pool_index_(-1), |
21 args_desc_(Array::Handle()), | 22 args_desc_(Array::Handle()), |
22 ic_data_(ICData::Handle()) { | 23 ic_data_(ICData::Handle()) { |
23 ASSERT(code.ContainsInstructionAt(pc)); | 24 ASSERT(code.ContainsInstructionAt(pc)); |
24 // Last instruction: blx lr. | 25 // Last instruction: blx lr. |
25 ASSERT(*(reinterpret_cast<uword*>(end_) - 1) == 0xe12fff3e); | 26 ASSERT(*(reinterpret_cast<uword*>(end_) - 1) == 0xe12fff3e); |
26 | 27 |
27 Register reg; | 28 Register reg; |
28 ic_data_load_end_ = | 29 ic_data_load_end_ = |
29 InstructionPattern::DecodeLoadWordFromPool(end_ - Instr::kInstrSize, | 30 InstructionPattern::DecodeLoadWordFromPool(end_ - Instr::kInstrSize, |
30 ®, | 31 ®, |
31 &target_address_pool_index_); | 32 &target_address_pool_index_); |
32 ASSERT(reg == LR); | 33 ASSERT(reg == LR); |
33 } | 34 } |
34 | 35 |
35 | 36 |
| 37 int CallPattern::LengthInBytes() { |
| 38 if (TargetCPUFeatures::arm_version() == ARMv6) { |
| 39 return 5 * Instr::kInstrSize; |
| 40 } else { |
| 41 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); |
| 42 return 3 * Instr::kInstrSize; |
| 43 } |
| 44 } |
| 45 |
| 46 |
36 // Decodes a load sequence ending at 'end' (the last instruction of the load | 47 // Decodes a load sequence ending at 'end' (the last instruction of the load |
37 // sequence is the instruction before the one at end). Returns a pointer to | 48 // sequence is the instruction before the one at end). Returns a pointer to |
38 // the first instruction in the sequence. Returns the register being loaded | 49 // the first instruction in the sequence. Returns the register being loaded |
39 // and the loaded object in the output parameters 'reg' and 'obj' | 50 // and the loaded object in the output parameters 'reg' and 'obj' |
40 // respectively. | 51 // respectively. |
41 uword InstructionPattern::DecodeLoadObject(uword end, | 52 uword InstructionPattern::DecodeLoadObject(uword end, |
42 const Array& object_pool, | 53 const Array& object_pool, |
43 Register* reg, | 54 Register* reg, |
44 Object* obj) { | 55 Object* obj) { |
45 uword start = 0; | 56 uword start = 0; |
(...skipping 16 matching lines...) Expand all Loading... |
62 // sequence is the instruction before the one at end). Returns a pointer to | 73 // 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 | 74 // the first instruction in the sequence. Returns the register being loaded |
64 // and the loaded immediate value in the output parameters 'reg' and 'value' | 75 // and the loaded immediate value in the output parameters 'reg' and 'value' |
65 // respectively. | 76 // respectively. |
66 uword InstructionPattern::DecodeLoadWordImmediate(uword end, | 77 uword InstructionPattern::DecodeLoadWordImmediate(uword end, |
67 Register* reg, | 78 Register* reg, |
68 intptr_t* value) { | 79 intptr_t* value) { |
69 uword start = end - Instr::kInstrSize; | 80 uword start = end - Instr::kInstrSize; |
70 int32_t instr = Instr::At(start)->InstructionBits(); | 81 int32_t instr = Instr::At(start)->InstructionBits(); |
71 intptr_t imm = 0; | 82 intptr_t imm = 0; |
72 if ((instr & 0xfff00000) == 0xe3400000) { // movt reg, #imm_hi | 83 if (TargetCPUFeatures::arm_version() == ARMv6) { |
73 imm |= (instr & 0xf0000) << 12; | 84 ASSERT((instr & 0xfff00000) == 0xe3800000); // orr rd, rd, byte0 |
74 imm |= (instr & 0xfff) << 16; | 85 imm |= (instr & 0x000000ff); |
| 86 |
75 start -= Instr::kInstrSize; | 87 start -= Instr::kInstrSize; |
76 instr = Instr::At(start)->InstructionBits(); | 88 instr = Instr::At(start)->InstructionBits(); |
| 89 ASSERT((instr & 0xfff00000) == 0xe3800c00); // orr rd, rd, (byte1 rot 12) |
| 90 imm |= (instr & 0x000000ff); |
| 91 |
| 92 start -= Instr::kInstrSize; |
| 93 instr = Instr::At(start)->InstructionBits(); |
| 94 ASSERT((instr & 0xfff00f00) == 0xe3800800); // orr rd, rd, (byte2 rot 8) |
| 95 imm |= (instr & 0x000000ff); |
| 96 |
| 97 start -= Instr::kInstrSize; |
| 98 instr = Instr::At(start)->InstructionBits(); |
| 99 ASSERT((instr & 0xffff0f00) == 0xe3a00400); // mov rd, (byte3 rot 4) |
| 100 imm |= (instr & 0x000000ff); |
| 101 |
| 102 *reg = static_cast<Register>((instr & 0x0000f000) >> 12); |
| 103 *value = imm; |
| 104 } else { |
| 105 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); |
| 106 if ((instr & 0xfff00000) == 0xe3400000) { // movt reg, #imm_hi |
| 107 imm |= (instr & 0xf0000) << 12; |
| 108 imm |= (instr & 0xfff) << 16; |
| 109 start -= Instr::kInstrSize; |
| 110 instr = Instr::At(start)->InstructionBits(); |
| 111 } |
| 112 ASSERT((instr & 0xfff00000) == 0xe3000000); // movw reg, #imm_lo |
| 113 imm |= (instr & 0xf0000) >> 4; |
| 114 imm |= instr & 0xfff; |
| 115 *reg = static_cast<Register>((instr & 0xf000) >> 12); |
| 116 *value = imm; |
77 } | 117 } |
78 ASSERT((instr & 0xfff00000) == 0xe3000000); // movw reg, #imm_lo | |
79 imm |= (instr & 0xf0000) >> 4; | |
80 imm |= instr & 0xfff; | |
81 *reg = static_cast<Register>((instr & 0xf000) >> 12); | |
82 *value = imm; | |
83 return start; | 118 return start; |
84 } | 119 } |
85 | 120 |
86 | 121 |
87 // Decodes a load sequence ending at 'end' (the last instruction of the load | 122 // Decodes a load sequence ending at 'end' (the last instruction of the load |
88 // sequence is the instruction before the one at end). Returns a pointer to | 123 // sequence is the instruction before the one at end). Returns a pointer to |
89 // the first instruction in the sequence. Returns the register being loaded | 124 // the first instruction in the sequence. Returns the register being loaded |
90 // and the index in the pool being read from in the output parameters 'reg' | 125 // and the index in the pool being read from in the output parameters 'reg' |
91 // and 'index' respectively. | 126 // and 'index' respectively. |
92 uword InstructionPattern::DecodeLoadWordFromPool(uword end, | 127 uword InstructionPattern::DecodeLoadWordFromPool(uword end, |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 void CallPattern::SetTargetAddress(uword target_address) const { | 196 void CallPattern::SetTargetAddress(uword target_address) const { |
162 ASSERT(Utils::IsAligned(target_address, 4)); | 197 ASSERT(Utils::IsAligned(target_address, 4)); |
163 // The address is stored in the object array as a RawSmi. | 198 // The address is stored in the object array as a RawSmi. |
164 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target_address)); | 199 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target_address)); |
165 object_pool_.SetAt(target_address_pool_index_, smi); | 200 object_pool_.SetAt(target_address_pool_index_, smi); |
166 // No need to flush the instruction cache, since the code is not modified. | 201 // No need to flush the instruction cache, since the code is not modified. |
167 } | 202 } |
168 | 203 |
169 | 204 |
170 void CallPattern::InsertAt(uword pc, uword target_address) { | 205 void CallPattern::InsertAt(uword pc, uword target_address) { |
171 uint16_t target_lo = target_address & 0xffff; | 206 if (TargetCPUFeatures::arm_version() == ARMv6) { |
172 uint16_t target_hi = target_address >> 16; | 207 const uint32_t byte0 = (target_address & 0x000000ff); |
173 uword movw_ip = 0xe300c000 | ((target_lo >> 12) << 16) | (target_lo & 0xfff); | 208 const uint32_t byte1 = (target_address & 0x0000ff00) >> 8; |
174 uword movt_ip = 0xe340c000 | ((target_hi >> 12) << 16) | (target_hi & 0xfff); | 209 const uint32_t byte2 = (target_address & 0x00ff0000) >> 16; |
175 uword blx_ip = 0xe12fff3c; | 210 const uint32_t byte3 = (target_address & 0xff000000) >> 24; |
176 *reinterpret_cast<uword*>(pc + (0 * Instr::kInstrSize)) = movw_ip; | 211 |
177 *reinterpret_cast<uword*>(pc + (1 * Instr::kInstrSize)) = movt_ip; | 212 const uword mov_ip = 0xe3a0c400 | byte3; // mov ip, (byte3 rot 4) |
178 *reinterpret_cast<uword*>(pc + (2 * Instr::kInstrSize)) = blx_ip; | 213 const uword or1_ip = 0xe38cc800 | byte2; // orr ip, ip, (byte2 rot 8) |
179 ASSERT(kFixedLengthInBytes == 3 * Instr::kInstrSize); | 214 const uword or2_ip = 0xe38ccc00 | byte1; // orr ip, ip, (byte1 rot 12) |
180 CPU::FlushICache(pc, kFixedLengthInBytes); | 215 const uword or3_ip = 0xe38cc000 | byte0; // orr ip, ip, byte0 |
| 216 const uword blx_ip = 0xe12fff3c; |
| 217 |
| 218 *reinterpret_cast<uword*>(pc + (0 * Instr::kInstrSize)) = mov_ip; |
| 219 *reinterpret_cast<uword*>(pc + (1 * Instr::kInstrSize)) = or1_ip; |
| 220 *reinterpret_cast<uword*>(pc + (2 * Instr::kInstrSize)) = or2_ip; |
| 221 *reinterpret_cast<uword*>(pc + (3 * Instr::kInstrSize)) = or3_ip; |
| 222 *reinterpret_cast<uword*>(pc + (4 * Instr::kInstrSize)) = blx_ip; |
| 223 |
| 224 ASSERT(LengthInBytes() == 5 * Instr::kInstrSize); |
| 225 CPU::FlushICache(pc, LengthInBytes()); |
| 226 } else { |
| 227 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); |
| 228 const uint16_t target_lo = target_address & 0xffff; |
| 229 const uint16_t target_hi = target_address >> 16; |
| 230 |
| 231 const uword movw_ip = |
| 232 0xe300c000 | ((target_lo >> 12) << 16) | (target_lo & 0xfff); |
| 233 const uword movt_ip = |
| 234 0xe340c000 | ((target_hi >> 12) << 16) | (target_hi & 0xfff); |
| 235 const uword blx_ip = 0xe12fff3c; |
| 236 |
| 237 *reinterpret_cast<uword*>(pc + (0 * Instr::kInstrSize)) = movw_ip; |
| 238 *reinterpret_cast<uword*>(pc + (1 * Instr::kInstrSize)) = movt_ip; |
| 239 *reinterpret_cast<uword*>(pc + (2 * Instr::kInstrSize)) = blx_ip; |
| 240 |
| 241 ASSERT(LengthInBytes() == 3 * Instr::kInstrSize); |
| 242 CPU::FlushICache(pc, LengthInBytes()); |
| 243 } |
181 } | 244 } |
182 | 245 |
183 | 246 |
184 JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { } | 247 JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { } |
185 | 248 |
186 | 249 |
| 250 int JumpPattern::pattern_length_in_bytes() { |
| 251 if (TargetCPUFeatures::arm_version() == ARMv6) { |
| 252 return 5 * Instr::kInstrSize; |
| 253 } else { |
| 254 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); |
| 255 return 3 * Instr::kInstrSize; |
| 256 } |
| 257 } |
| 258 |
| 259 |
187 bool JumpPattern::IsValid() const { | 260 bool JumpPattern::IsValid() const { |
188 Instr* movw_ip = Instr::At(pc_ + (0 * Instr::kInstrSize)); // target_lo | 261 if (TargetCPUFeatures::arm_version() == ARMv6) { |
189 Instr* movt_ip = Instr::At(pc_ + (1 * Instr::kInstrSize)); // target_hi | 262 Instr* mov_ip = Instr::At(pc_ + (0 * Instr::kInstrSize)); |
190 Instr* bx_ip = Instr::At(pc_ + (2 * Instr::kInstrSize)); | 263 Instr* or1_ip = Instr::At(pc_ + (1 * Instr::kInstrSize)); |
191 return (movw_ip->InstructionBits() & 0xfff0f000) == 0xe300c000 && | 264 Instr* or2_ip = Instr::At(pc_ + (2 * Instr::kInstrSize)); |
192 (movt_ip->InstructionBits() & 0xfff0f000) == 0xe340c000 && | 265 Instr* or3_ip = Instr::At(pc_ + (3 * Instr::kInstrSize)); |
193 (bx_ip->InstructionBits() & 0xffffffff) == 0xe12fff1c; | 266 Instr* bx_ip = Instr::At(pc_ + (4 * Instr::kInstrSize)); |
| 267 return ((mov_ip->InstructionBits() & 0xffffff00) == 0xe3a0c400) && |
| 268 ((or1_ip->InstructionBits() & 0xffffff00) == 0xe38cc800) && |
| 269 ((or2_ip->InstructionBits() & 0xffffff00) == 0xe38ccc00) && |
| 270 ((or3_ip->InstructionBits() & 0xffffff00) == 0xe38cc000) && |
| 271 ((bx_ip->InstructionBits() & 0xffffffff) == 0xe12fff1c); |
| 272 } else { |
| 273 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); |
| 274 Instr* movw_ip = Instr::At(pc_ + (0 * Instr::kInstrSize)); // target_lo |
| 275 Instr* movt_ip = Instr::At(pc_ + (1 * Instr::kInstrSize)); // target_hi |
| 276 Instr* bx_ip = Instr::At(pc_ + (2 * Instr::kInstrSize)); |
| 277 return (movw_ip->InstructionBits() & 0xfff0f000) == 0xe300c000 && |
| 278 (movt_ip->InstructionBits() & 0xfff0f000) == 0xe340c000 && |
| 279 (bx_ip->InstructionBits() & 0xffffffff) == 0xe12fff1c; |
| 280 } |
194 } | 281 } |
195 | 282 |
196 | 283 |
197 uword JumpPattern::TargetAddress() const { | 284 uword JumpPattern::TargetAddress() const { |
198 Instr* movw_ip = Instr::At(pc_ + (0 * Instr::kInstrSize)); // target_lo | 285 if (TargetCPUFeatures::arm_version() == ARMv6) { |
199 Instr* movt_ip = Instr::At(pc_ + (1 * Instr::kInstrSize)); // target_hi | 286 Instr* mov_ip = Instr::At(pc_ + (0 * Instr::kInstrSize)); |
200 uint16_t target_lo = movw_ip->MovwField(); | 287 Instr* or1_ip = Instr::At(pc_ + (1 * Instr::kInstrSize)); |
201 uint16_t target_hi = movt_ip->MovwField(); | 288 Instr* or2_ip = Instr::At(pc_ + (2 * Instr::kInstrSize)); |
202 return (target_hi << 16) | target_lo; | 289 Instr* or3_ip = Instr::At(pc_ + (3 * Instr::kInstrSize)); |
| 290 uword imm = 0; |
| 291 imm |= or3_ip->Immed8Field(); |
| 292 imm |= or2_ip->Immed8Field() << 8; |
| 293 imm |= or1_ip->Immed8Field() << 16; |
| 294 imm |= mov_ip->Immed8Field() << 24; |
| 295 return imm; |
| 296 } else { |
| 297 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); |
| 298 Instr* movw_ip = Instr::At(pc_ + (0 * Instr::kInstrSize)); // target_lo |
| 299 Instr* movt_ip = Instr::At(pc_ + (1 * Instr::kInstrSize)); // target_hi |
| 300 uint16_t target_lo = movw_ip->MovwField(); |
| 301 uint16_t target_hi = movt_ip->MovwField(); |
| 302 return (target_hi << 16) | target_lo; |
| 303 } |
203 } | 304 } |
204 | 305 |
205 | 306 |
206 void JumpPattern::SetTargetAddress(uword target_address) const { | 307 void JumpPattern::SetTargetAddress(uword target_address) const { |
207 uint16_t target_lo = target_address & 0xffff; | 308 if (TargetCPUFeatures::arm_version() == ARMv6) { |
208 uint16_t target_hi = target_address >> 16; | 309 const uint32_t byte0 = (target_address & 0x000000ff); |
209 uword movw_ip = 0xe300c000 | ((target_lo >> 12) << 16) | (target_lo & 0xfff); | 310 const uint32_t byte1 = (target_address & 0x0000ff00) >> 8; |
210 uword movt_ip = 0xe340c000 | ((target_hi >> 12) << 16) | (target_hi & 0xfff); | 311 const uint32_t byte2 = (target_address & 0x00ff0000) >> 16; |
211 *reinterpret_cast<uword*>(pc_ + (0 * Instr::kInstrSize)) = movw_ip; | 312 const uint32_t byte3 = (target_address & 0xff000000) >> 24; |
212 *reinterpret_cast<uword*>(pc_ + (1 * Instr::kInstrSize)) = movt_ip; | 313 |
213 CPU::FlushICache(pc_, 2 * Instr::kInstrSize); | 314 const uword mov_ip = 0xe3a0c400 | byte3; // mov ip, (byte3 rot 4) |
| 315 const uword or1_ip = 0xe38cc800 | byte2; // orr ip, ip, (byte2 rot 8) |
| 316 const uword or2_ip = 0xe38ccc00 | byte1; // orr ip, ip, (byte1 rot 12) |
| 317 const uword or3_ip = 0xe38cc000 | byte0; // orr ip, ip, byte0 |
| 318 |
| 319 *reinterpret_cast<uword*>(pc_ + (0 * Instr::kInstrSize)) = mov_ip; |
| 320 *reinterpret_cast<uword*>(pc_ + (1 * Instr::kInstrSize)) = or1_ip; |
| 321 *reinterpret_cast<uword*>(pc_ + (2 * Instr::kInstrSize)) = or2_ip; |
| 322 *reinterpret_cast<uword*>(pc_ + (3 * Instr::kInstrSize)) = or3_ip; |
| 323 CPU::FlushICache(pc_, 4 * Instr::kInstrSize); |
| 324 } else { |
| 325 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); |
| 326 const uint16_t target_lo = target_address & 0xffff; |
| 327 const uint16_t target_hi = target_address >> 16; |
| 328 |
| 329 const uword movw_ip = |
| 330 0xe300c000 | ((target_lo >> 12) << 16) | (target_lo & 0xfff); |
| 331 const uword movt_ip = |
| 332 0xe340c000 | ((target_hi >> 12) << 16) | (target_hi & 0xfff); |
| 333 |
| 334 *reinterpret_cast<uword*>(pc_ + (0 * Instr::kInstrSize)) = movw_ip; |
| 335 *reinterpret_cast<uword*>(pc_ + (1 * Instr::kInstrSize)) = movt_ip; |
| 336 CPU::FlushICache(pc_, 2 * Instr::kInstrSize); |
| 337 } |
214 } | 338 } |
215 | 339 |
216 } // namespace dart | 340 } // namespace dart |
217 | 341 |
218 #endif // defined TARGET_ARCH_ARM | 342 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |