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/instructions.h" | 8 #include "vm/instructions.h" |
9 #include "vm/instructions_arm.h" | 9 #include "vm/instructions_arm.h" |
10 | 10 |
(...skipping 13 matching lines...) Expand all Loading... |
24 ASSERT(code.ContainsInstructionAt(pc)); | 24 ASSERT(code.ContainsInstructionAt(pc)); |
25 // Last instruction: blx lr. | 25 // Last instruction: blx lr. |
26 ASSERT(*(reinterpret_cast<uword*>(end_) - 1) == 0xe12fff3e); | 26 ASSERT(*(reinterpret_cast<uword*>(end_) - 1) == 0xe12fff3e); |
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: blx lr. | 40 // Last instruction: blx lr. |
42 ASSERT(*(reinterpret_cast<uword*>(end_) - 1) == 0xe12fff3e); | 41 ASSERT(*(reinterpret_cast<uword*>(end_) - 1) == 0xe12fff3e); |
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 == R9); | 49 ASSERT(reg == R9); |
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& new_target) const { | 57 void NativeCallPattern::set_target(const Code& new_target) const { |
61 object_pool_.SetObjectAt(target_code_pool_index_, new_target); | 58 object_pool_.SetObjectAt(target_code_pool_index_, new_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 // Decodes a load sequence ending at 'end' (the last instruction of the load | 72 // Decodes a load sequence ending at 'end' (the last instruction of the load |
79 // 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 |
80 // the first instruction in the sequence. Returns the register being loaded | 74 // the first instruction in the sequence. Returns the register being loaded |
81 // and the loaded object in the output parameters 'reg' and 'obj' | 75 // and the loaded object in the output parameters 'reg' and 'obj' |
82 // respectively. | 76 // respectively. |
83 uword InstructionPattern::DecodeLoadObject(uword end, | 77 uword InstructionPattern::DecodeLoadObject(uword end, |
84 const ObjectPool& object_pool, | 78 const ObjectPool& object_pool, |
85 Register* reg, | 79 Register* reg, |
86 Object* obj) { | 80 Object* obj) { |
87 uword start = 0; | 81 uword start = 0; |
88 Instr* instr = Instr::At(end - Instr::kInstrSize); | 82 Instr* instr = Instr::At(end - Instr::kInstrSize); |
89 if ((instr->InstructionBits() & 0xfff00000) == 0xe5900000) { | 83 if ((instr->InstructionBits() & 0xfff00000) == 0xe5900000) { |
90 // ldr reg, [reg, #+offset] | 84 // ldr reg, [reg, #+offset] |
91 intptr_t index = 0; | 85 intptr_t index = 0; |
92 start = DecodeLoadWordFromPool(end, reg, &index); | 86 start = DecodeLoadWordFromPool(end, reg, &index); |
93 *obj = object_pool.ObjectAt(index); | 87 *obj = object_pool.ObjectAt(index); |
94 } else { | 88 } else { |
95 intptr_t value = 0; | 89 intptr_t value = 0; |
96 start = DecodeLoadWordImmediate(end, reg, &value); | 90 start = DecodeLoadWordImmediate(end, reg, &value); |
97 *obj = reinterpret_cast<RawObject*>(value); | 91 *obj = reinterpret_cast<RawObject*>(value); |
98 } | 92 } |
99 return start; | 93 return start; |
100 } | 94 } |
101 | 95 |
102 | |
103 // Decodes a load sequence ending at 'end' (the last instruction of the load | 96 // Decodes a load sequence ending at 'end' (the last instruction of the load |
104 // sequence is the instruction before the one at end). Returns a pointer to | 97 // sequence is the instruction before the one at end). Returns a pointer to |
105 // the first instruction in the sequence. Returns the register being loaded | 98 // the first instruction in the sequence. Returns the register being loaded |
106 // and the loaded immediate value in the output parameters 'reg' and 'value' | 99 // and the loaded immediate value in the output parameters 'reg' and 'value' |
107 // respectively. | 100 // respectively. |
108 uword InstructionPattern::DecodeLoadWordImmediate(uword end, | 101 uword InstructionPattern::DecodeLoadWordImmediate(uword end, |
109 Register* reg, | 102 Register* reg, |
110 intptr_t* value) { | 103 intptr_t* value) { |
111 uword start = end - Instr::kInstrSize; | 104 uword start = end - Instr::kInstrSize; |
112 int32_t instr = Instr::At(start)->InstructionBits(); | 105 int32_t instr = Instr::At(start)->InstructionBits(); |
(...skipping 30 matching lines...) Expand all Loading... |
143 } | 136 } |
144 ASSERT((instr & 0xfff00000) == 0xe3000000); // movw reg, #imm_lo | 137 ASSERT((instr & 0xfff00000) == 0xe3000000); // movw reg, #imm_lo |
145 imm |= (instr & 0xf0000) >> 4; | 138 imm |= (instr & 0xf0000) >> 4; |
146 imm |= instr & 0xfff; | 139 imm |= instr & 0xfff; |
147 *reg = static_cast<Register>((instr & 0xf000) >> 12); | 140 *reg = static_cast<Register>((instr & 0xf000) >> 12); |
148 *value = imm; | 141 *value = imm; |
149 } | 142 } |
150 return start; | 143 return start; |
151 } | 144 } |
152 | 145 |
153 | |
154 static bool IsLoadWithOffset(int32_t instr, | 146 static bool IsLoadWithOffset(int32_t instr, |
155 Register base, | 147 Register base, |
156 intptr_t* offset, | 148 intptr_t* offset, |
157 Register* dst) { | 149 Register* dst) { |
158 if ((instr & 0xffff0000) == (0xe5900000 | (base << 16))) { | 150 if ((instr & 0xffff0000) == (0xe5900000 | (base << 16))) { |
159 // ldr reg, [base, #+offset] | 151 // ldr reg, [base, #+offset] |
160 *offset = instr & 0xfff; | 152 *offset = instr & 0xfff; |
161 *dst = static_cast<Register>((instr & 0xf000) >> 12); | 153 *dst = static_cast<Register>((instr & 0xf000) >> 12); |
162 return true; | 154 return true; |
163 } | 155 } |
164 return false; | 156 return false; |
165 } | 157 } |
166 | 158 |
167 | |
168 // Decodes a load sequence ending at 'end' (the last instruction of the load | 159 // Decodes a load sequence ending at 'end' (the last instruction of the load |
169 // sequence is the instruction before the one at end). Returns a pointer to | 160 // sequence is the instruction before the one at end). Returns a pointer to |
170 // the first instruction in the sequence. Returns the register being loaded | 161 // the first instruction in the sequence. Returns the register being loaded |
171 // and the index in the pool being read from in the output parameters 'reg' | 162 // and the index in the pool being read from in the output parameters 'reg' |
172 // and 'index' respectively. | 163 // and 'index' respectively. |
173 uword InstructionPattern::DecodeLoadWordFromPool(uword end, | 164 uword InstructionPattern::DecodeLoadWordFromPool(uword end, |
174 Register* reg, | 165 Register* reg, |
175 intptr_t* index) { | 166 intptr_t* index) { |
176 uword start = end - Instr::kInstrSize; | 167 uword start = end - Instr::kInstrSize; |
177 int32_t instr = Instr::At(start)->InstructionBits(); | 168 int32_t instr = Instr::At(start)->InstructionBits(); |
(...skipping 14 matching lines...) Expand all Loading... |
192 } else { | 183 } else { |
193 ASSERT((instr & 0xffff0000) == (0xe0800000 | (PP << 16))); | 184 ASSERT((instr & 0xffff0000) == (0xe0800000 | (PP << 16))); |
194 // add reg, pp, reg | 185 // add reg, pp, reg |
195 end = DecodeLoadWordImmediate(end, reg, &offset); | 186 end = DecodeLoadWordImmediate(end, reg, &offset); |
196 } | 187 } |
197 } | 188 } |
198 *index = ObjectPool::IndexFromOffset(offset); | 189 *index = ObjectPool::IndexFromOffset(offset); |
199 return start; | 190 return start; |
200 } | 191 } |
201 | 192 |
202 | |
203 bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code& code, Object* obj) { | 193 bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code& code, Object* obj) { |
204 ASSERT(code.ContainsInstructionAt(pc)); | 194 ASSERT(code.ContainsInstructionAt(pc)); |
205 | 195 |
206 int32_t instr = Instr::At(pc)->InstructionBits(); | 196 int32_t instr = Instr::At(pc)->InstructionBits(); |
207 intptr_t offset; | 197 intptr_t offset; |
208 Register dst; | 198 Register dst; |
209 if (IsLoadWithOffset(instr, PP, &offset, &dst)) { | 199 if (IsLoadWithOffset(instr, PP, &offset, &dst)) { |
210 intptr_t index = ObjectPool::IndexFromOffset(offset); | 200 intptr_t index = ObjectPool::IndexFromOffset(offset); |
211 const ObjectPool& pool = ObjectPool::Handle(code.object_pool()); | 201 const ObjectPool& pool = ObjectPool::Handle(code.object_pool()); |
212 if (pool.InfoAt(index) == ObjectPool::kTaggedObject) { | 202 if (pool.InfoAt(index) == ObjectPool::kTaggedObject) { |
213 *obj = pool.ObjectAt(index); | 203 *obj = pool.ObjectAt(index); |
214 return true; | 204 return true; |
215 } | 205 } |
216 } else if (IsLoadWithOffset(instr, THR, &offset, &dst)) { | 206 } else if (IsLoadWithOffset(instr, THR, &offset, &dst)) { |
217 return Thread::ObjectAtOffset(offset, obj); | 207 return Thread::ObjectAtOffset(offset, obj); |
218 } | 208 } |
219 // TODO(rmacnak): Sequence for loads beyond 12 bits. | 209 // TODO(rmacnak): Sequence for loads beyond 12 bits. |
220 | 210 |
221 return false; | 211 return false; |
222 } | 212 } |
223 | 213 |
224 | |
225 RawICData* CallPattern::IcData() { | 214 RawICData* CallPattern::IcData() { |
226 if (ic_data_.IsNull()) { | 215 if (ic_data_.IsNull()) { |
227 Register reg; | 216 Register reg; |
228 InstructionPattern::DecodeLoadObject(ic_data_load_end_, object_pool_, ®, | 217 InstructionPattern::DecodeLoadObject(ic_data_load_end_, object_pool_, ®, |
229 &ic_data_); | 218 &ic_data_); |
230 ASSERT(reg == R9); | 219 ASSERT(reg == R9); |
231 } | 220 } |
232 return ic_data_.raw(); | 221 return ic_data_.raw(); |
233 } | 222 } |
234 | 223 |
235 | |
236 RawCode* CallPattern::TargetCode() const { | 224 RawCode* CallPattern::TargetCode() const { |
237 return reinterpret_cast<RawCode*>( | 225 return reinterpret_cast<RawCode*>( |
238 object_pool_.ObjectAt(target_code_pool_index_)); | 226 object_pool_.ObjectAt(target_code_pool_index_)); |
239 } | 227 } |
240 | 228 |
241 | |
242 void CallPattern::SetTargetCode(const Code& target_code) const { | 229 void CallPattern::SetTargetCode(const Code& target_code) const { |
243 object_pool_.SetObjectAt(target_code_pool_index_, target_code); | 230 object_pool_.SetObjectAt(target_code_pool_index_, target_code); |
244 } | 231 } |
245 | 232 |
246 | |
247 SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code) | 233 SwitchableCallPattern::SwitchableCallPattern(uword pc, const Code& code) |
248 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 234 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
249 data_pool_index_(-1), | 235 data_pool_index_(-1), |
250 target_pool_index_(-1) { | 236 target_pool_index_(-1) { |
251 ASSERT(code.ContainsInstructionAt(pc)); | 237 ASSERT(code.ContainsInstructionAt(pc)); |
252 // Last instruction: blx lr. | 238 // Last instruction: blx lr. |
253 ASSERT(*(reinterpret_cast<uword*>(pc) - 1) == 0xe12fff3e); | 239 ASSERT(*(reinterpret_cast<uword*>(pc) - 1) == 0xe12fff3e); |
254 | 240 |
255 Register reg; | 241 Register reg; |
256 uword data_load_end = InstructionPattern::DecodeLoadWordFromPool( | 242 uword data_load_end = InstructionPattern::DecodeLoadWordFromPool( |
257 pc - Instr::kInstrSize, ®, &data_pool_index_); | 243 pc - Instr::kInstrSize, ®, &data_pool_index_); |
258 ASSERT(reg == R9); | 244 ASSERT(reg == R9); |
259 InstructionPattern::DecodeLoadWordFromPool(data_load_end - Instr::kInstrSize, | 245 InstructionPattern::DecodeLoadWordFromPool(data_load_end - Instr::kInstrSize, |
260 ®, &target_pool_index_); | 246 ®, &target_pool_index_); |
261 ASSERT(reg == CODE_REG); | 247 ASSERT(reg == CODE_REG); |
262 } | 248 } |
263 | 249 |
264 | |
265 RawObject* SwitchableCallPattern::data() const { | 250 RawObject* SwitchableCallPattern::data() const { |
266 return object_pool_.ObjectAt(data_pool_index_); | 251 return object_pool_.ObjectAt(data_pool_index_); |
267 } | 252 } |
268 | 253 |
269 | |
270 RawCode* SwitchableCallPattern::target() const { | 254 RawCode* SwitchableCallPattern::target() const { |
271 return reinterpret_cast<RawCode*>(object_pool_.ObjectAt(target_pool_index_)); | 255 return reinterpret_cast<RawCode*>(object_pool_.ObjectAt(target_pool_index_)); |
272 } | 256 } |
273 | 257 |
274 | |
275 void SwitchableCallPattern::SetData(const Object& data) const { | 258 void SwitchableCallPattern::SetData(const Object& data) const { |
276 ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode()); | 259 ASSERT(!Object::Handle(object_pool_.ObjectAt(data_pool_index_)).IsCode()); |
277 object_pool_.SetObjectAt(data_pool_index_, data); | 260 object_pool_.SetObjectAt(data_pool_index_, data); |
278 } | 261 } |
279 | 262 |
280 | |
281 void SwitchableCallPattern::SetTarget(const Code& target) const { | 263 void SwitchableCallPattern::SetTarget(const Code& target) const { |
282 ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode()); | 264 ASSERT(Object::Handle(object_pool_.ObjectAt(target_pool_index_)).IsCode()); |
283 object_pool_.SetObjectAt(target_pool_index_, target); | 265 object_pool_.SetObjectAt(target_pool_index_, target); |
284 } | 266 } |
285 | 267 |
286 | |
287 ReturnPattern::ReturnPattern(uword pc) : pc_(pc) {} | 268 ReturnPattern::ReturnPattern(uword pc) : pc_(pc) {} |
288 | 269 |
289 | |
290 bool ReturnPattern::IsValid() const { | 270 bool ReturnPattern::IsValid() const { |
291 Instr* bx_lr = Instr::At(pc_); | 271 Instr* bx_lr = Instr::At(pc_); |
292 const int32_t B4 = 1 << 4; | 272 const int32_t B4 = 1 << 4; |
293 const int32_t B21 = 1 << 21; | 273 const int32_t B21 = 1 << 21; |
294 const int32_t B24 = 1 << 24; | 274 const int32_t B24 = 1 << 24; |
295 int32_t instruction = (static_cast<int32_t>(AL) << kConditionShift) | B24 | | 275 int32_t instruction = (static_cast<int32_t>(AL) << kConditionShift) | B24 | |
296 B21 | (0xfff << 8) | B4 | | 276 B21 | (0xfff << 8) | B4 | |
297 (static_cast<int32_t>(LR) << kRmShift); | 277 (static_cast<int32_t>(LR) << kRmShift); |
298 const ARMVersion version = TargetCPUFeatures::arm_version(); | 278 const ARMVersion version = TargetCPUFeatures::arm_version(); |
299 if ((version == ARMv5TE) || (version == ARMv6)) { | 279 if ((version == ARMv5TE) || (version == ARMv6)) { |
300 return bx_lr->InstructionBits() == instruction; | 280 return bx_lr->InstructionBits() == instruction; |
301 } else { | 281 } else { |
302 ASSERT(version == ARMv7); | 282 ASSERT(version == ARMv7); |
303 return bx_lr->InstructionBits() == instruction; | 283 return bx_lr->InstructionBits() == instruction; |
304 } | 284 } |
305 return false; | 285 return false; |
306 } | 286 } |
307 | 287 |
308 } // namespace dart | 288 } // namespace dart |
309 | 289 |
310 #endif // defined TARGET_ARCH_ARM | 290 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |