OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
7 | 7 |
8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/code_patcher.h" | 9 #include "vm/code_patcher.h" |
10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
11 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
12 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
13 #include "vm/instructions.h" | 13 #include "vm/instructions.h" |
14 #include "vm/object.h" | 14 #include "vm/object.h" |
15 #include "vm/raw_object.h" | 15 #include "vm/raw_object.h" |
16 | 16 |
17 namespace dart { | 17 namespace dart { |
18 | 18 |
19 | 19 // The expected pattern of a Dart unoptimized call (static and instance): |
20 static bool MatchesPattern(uword addr, int16_t* pattern, intptr_t size) { | 20 // 0: 49 8b 9f imm32 mov RBX, [PP + off] |
21 uint8_t* bytes = reinterpret_cast<uint8_t*>(addr); | 21 // 7: 41 ff 97 imm32 call [PP + off] |
22 for (intptr_t i = 0; i < size; i++) { | 22 // 14 <- return address |
23 int16_t val = pattern[i]; | |
24 if ((val >= 0) && (val != bytes[i])) { | |
25 return false; | |
26 } | |
27 } | |
28 return true; | |
29 } | |
30 | |
31 | |
32 intptr_t IndexFromPPLoad(uword start) { | |
33 int32_t offset = *reinterpret_cast<int32_t*>(start); | |
34 return ObjectPool::IndexFromOffset(offset); | |
35 } | |
36 | |
37 | |
38 class UnoptimizedCall : public ValueObject { | 23 class UnoptimizedCall : public ValueObject { |
39 public: | 24 public: |
40 UnoptimizedCall(uword return_address, const Code& code) | 25 UnoptimizedCall(uword return_address, const Code& code) |
41 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), | 26 : object_pool_(ObjectPool::Handle(code.GetObjectPool())), |
42 start_(return_address - kCallPatternSize) { | 27 start_(return_address - kCallPatternSize) { |
| 28 ASSERT(IsValid(return_address)); |
43 ASSERT((kCallPatternSize - 7) == Assembler::kCallExternalLabelSize); | 29 ASSERT((kCallPatternSize - 7) == Assembler::kCallExternalLabelSize); |
44 ASSERT(IsValid()); | |
45 } | 30 } |
46 | 31 |
47 static const int kCallPatternSize = 22; | 32 static const int kCallPatternSize = 14; |
48 | 33 |
49 bool IsValid() const { | 34 static bool IsValid(uword return_address) { |
50 static int16_t pattern[kCallPatternSize] = { | 35 uint8_t* code_bytes = |
51 0x49, 0x8b, 0x9f, -1, -1, -1, -1, // movq RBX, [PP + offs] | 36 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
52 0x4d, 0x8b, 0xa7, -1, -1, -1, -1, // movq CR, [PP + offs] | 37 return (code_bytes[0] == 0x49) && (code_bytes[1] == 0x8B) && |
53 0x4d, 0x8b, 0x5c, 0x24, 0x07, // movq TMP, [CR + entry_point_offs] | 38 (code_bytes[2] == 0x9F) && |
54 0x41, 0xff, 0xd3 // callq TMP | 39 (code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) && |
55 }; | 40 (code_bytes[9] == 0x97); |
56 return MatchesPattern(start_, pattern, kCallPatternSize); | |
57 } | 41 } |
58 | 42 |
59 intptr_t argument_index() const { | 43 intptr_t argument_index() const { |
60 return IndexFromPPLoad(start_ + 3); | 44 return IndexFromPPLoad(start_ + 3); |
61 } | 45 } |
62 | 46 |
63 RawObject* ic_data() const { | 47 RawObject* ic_data() const { |
64 return object_pool_.ObjectAt(argument_index()); | 48 return object_pool_.ObjectAt(argument_index()); |
65 } | 49 } |
66 | 50 |
67 RawCode* target() const { | 51 uword target() const { |
68 intptr_t index = IndexFromPPLoad(start_ + 10); | 52 intptr_t index = IndexFromPPLoad(start_ + 10); |
69 Code& code = Code::Handle(); | 53 return object_pool_.RawValueAt(index); |
70 code ^= object_pool_.ObjectAt(index); | |
71 return code.raw(); | |
72 } | 54 } |
73 | 55 |
74 void set_target(const Code& target) const { | 56 void set_target(uword target) const { |
75 intptr_t index = IndexFromPPLoad(start_ + 10); | 57 intptr_t index = IndexFromPPLoad(start_ + 10); |
76 object_pool_.SetObjectAt(index, target); | 58 object_pool_.SetRawValueAt(index, target); |
77 // 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. |
78 } | 60 } |
79 | 61 |
80 protected: | 62 protected: |
81 const ObjectPool& object_pool_; | 63 const ObjectPool& object_pool_; |
82 | 64 |
83 private: | 65 private: |
84 uword start_; | 66 uword start_; |
85 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall); | 67 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall); |
86 }; | 68 }; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 ASSERT(test_ic_data.NumArgsTested() >= 0); | 115 ASSERT(test_ic_data.NumArgsTested() >= 0); |
134 #endif // DEBUG | 116 #endif // DEBUG |
135 } | 117 } |
136 | 118 |
137 private: | 119 private: |
138 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); | 120 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); |
139 }; | 121 }; |
140 | 122 |
141 | 123 |
142 // The expected pattern of a call where the target is loaded from | 124 // The expected pattern of a call where the target is loaded from |
143 // the object pool. | 125 // the object pool: |
| 126 // 0: 41 ff 97 imm32 call [PP + off] |
| 127 // 7: <- return address |
144 class PoolPointerCall : public ValueObject { | 128 class PoolPointerCall : public ValueObject { |
145 public: | 129 public: |
146 explicit PoolPointerCall(uword return_address, const Code& code) | 130 explicit PoolPointerCall(uword return_address, const Code& code) |
147 : start_(return_address - kCallPatternSize), | 131 : start_(return_address - kCallPatternSize), |
148 object_pool_(ObjectPool::Handle(code.GetObjectPool())) { | 132 object_pool_(ObjectPool::Handle(code.GetObjectPool())) { |
149 ASSERT(IsValid()); | 133 ASSERT(IsValid(return_address)); |
150 } | 134 } |
151 | 135 |
152 static const int kCallPatternSize = 15; | 136 static const int kCallPatternSize = 7; |
153 | 137 |
154 bool IsValid() const { | 138 static bool IsValid(uword return_address) { |
155 static int16_t pattern[kCallPatternSize] = { | 139 uint8_t* code_bytes = |
156 0x4d, 0x8b, 0xa7, -1, -1, -1, -1, // movq CR, [PP + offs] | 140 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
157 0x4d, 0x8b, 0x5c, 0x24, 0x07, // movq TMP, [CR + entry_point_off] | 141 return (code_bytes[0] == 0x41) && (code_bytes[1] == 0xFF) && |
158 0x41, 0xff, 0xd3 // callq TMP | 142 (code_bytes[2] == 0x97); |
159 }; | |
160 return MatchesPattern(start_, pattern, kCallPatternSize); | |
161 } | 143 } |
162 | 144 |
163 intptr_t pp_index() const { | 145 intptr_t pp_index() const { |
164 return IndexFromPPLoad(start_ + 3); | 146 return IndexFromPPLoad(start_ + 3); |
165 } | 147 } |
166 | 148 |
167 RawCode* Target() const { | 149 uword Target() const { |
168 Code& code = Code::Handle(); | 150 return object_pool_.RawValueAt(pp_index()); |
169 code ^= object_pool_.ObjectAt(pp_index()); | |
170 return code.raw(); | |
171 } | 151 } |
172 | 152 |
173 void SetTarget(const Code& target) const { | 153 void SetTarget(uword target) const { |
174 object_pool_.SetObjectAt(pp_index(), target); | 154 object_pool_.SetRawValueAt(pp_index(), target); |
175 // No need to flush the instruction cache, since the code is not modified. | 155 // No need to flush the instruction cache, since the code is not modified. |
176 } | 156 } |
177 | 157 |
178 protected: | 158 protected: |
179 uword start_; | 159 uword start_; |
180 const ObjectPool& object_pool_; | 160 const ObjectPool& object_pool_; |
181 | 161 |
182 private: | 162 private: |
183 DISALLOW_IMPLICIT_CONSTRUCTORS(PoolPointerCall); | 163 DISALLOW_IMPLICIT_CONSTRUCTORS(PoolPointerCall); |
184 }; | 164 }; |
185 | 165 |
186 | 166 |
187 RawCode* CodePatcher::GetStaticCallTargetAt(uword return_address, | 167 uword CodePatcher::GetStaticCallTargetAt(uword return_address, |
188 const Code& code) { | 168 const Code& code) { |
189 ASSERT(code.ContainsInstructionAt(return_address)); | 169 ASSERT(code.ContainsInstructionAt(return_address)); |
190 PoolPointerCall call(return_address, code); | 170 PoolPointerCall call(return_address, code); |
191 return call.Target(); | 171 return call.Target(); |
192 } | 172 } |
193 | 173 |
194 | 174 |
195 void CodePatcher::PatchStaticCallAt(uword return_address, | 175 void CodePatcher::PatchStaticCallAt(uword return_address, |
196 const Code& code, | 176 const Code& code, |
197 const Code& new_target) { | 177 uword new_target) { |
198 PatchPoolPointerCallAt(return_address, code, new_target); | 178 PatchPoolPointerCallAt(return_address, code, new_target); |
199 } | 179 } |
200 | 180 |
201 | 181 |
202 void CodePatcher::PatchPoolPointerCallAt(uword return_address, | 182 void CodePatcher::PatchPoolPointerCallAt(uword return_address, |
203 const Code& code, | 183 const Code& code, |
204 const Code& new_target) { | 184 uword new_target) { |
205 ASSERT(code.ContainsInstructionAt(return_address)); | 185 ASSERT(code.ContainsInstructionAt(return_address)); |
206 PoolPointerCall call(return_address, code); | 186 PoolPointerCall call(return_address, code); |
207 call.SetTarget(new_target); | 187 call.SetTarget(new_target); |
208 } | 188 } |
209 | 189 |
210 | 190 |
211 RawCode* CodePatcher::GetInstanceCallAt(uword return_address, | 191 void CodePatcher::PatchInstanceCallAt(uword return_address, |
212 const Code& code, | 192 const Code& code, |
213 ICData* ic_data) { | 193 uword new_target) { |
| 194 ASSERT(code.ContainsInstructionAt(return_address)); |
| 195 InstanceCall call(return_address, code); |
| 196 call.set_target(new_target); |
| 197 } |
| 198 |
| 199 |
| 200 uword CodePatcher::GetInstanceCallAt(uword return_address, |
| 201 const Code& code, |
| 202 ICData* ic_data) { |
214 ASSERT(code.ContainsInstructionAt(return_address)); | 203 ASSERT(code.ContainsInstructionAt(return_address)); |
215 InstanceCall call(return_address, code); | 204 InstanceCall call(return_address, code); |
216 if (ic_data != NULL) { | 205 if (ic_data != NULL) { |
217 *ic_data ^= call.ic_data(); | 206 *ic_data ^= call.ic_data(); |
218 } | 207 } |
219 return call.target(); | 208 return call.target(); |
220 } | 209 } |
221 | 210 |
222 | 211 |
223 intptr_t CodePatcher::InstanceCallSizeInBytes() { | 212 intptr_t CodePatcher::InstanceCallSizeInBytes() { |
224 return InstanceCall::kCallPatternSize; | 213 return InstanceCall::kCallPatternSize; |
225 } | 214 } |
226 | 215 |
227 | 216 |
228 void CodePatcher::InsertDeoptimizationCallAt(uword start, uword target) { | 217 void CodePatcher::InsertCallAt(uword start, uword target) { |
229 // The inserted call should not overlap the lazy deopt jump code. | 218 // The inserted call should not overlap the lazy deopt jump code. |
230 ASSERT(start + ShortCallPattern::pattern_length_in_bytes() <= target); | 219 ASSERT(start + ShortCallPattern::pattern_length_in_bytes() <= target); |
231 *reinterpret_cast<uint8_t*>(start) = 0xE8; | 220 *reinterpret_cast<uint8_t*>(start) = 0xE8; |
232 ShortCallPattern call(start); | 221 ShortCallPattern call(start); |
233 call.SetTargetAddress(target); | 222 call.SetTargetAddress(target); |
234 CPU::FlushICache(start, ShortCallPattern::pattern_length_in_bytes()); | 223 CPU::FlushICache(start, ShortCallPattern::pattern_length_in_bytes()); |
235 } | 224 } |
236 | 225 |
237 | 226 |
238 RawFunction* CodePatcher::GetUnoptimizedStaticCallAt( | 227 RawFunction* CodePatcher::GetUnoptimizedStaticCallAt( |
239 uword return_address, const Code& code, ICData* ic_data_result) { | 228 uword return_address, const Code& code, ICData* ic_data_result) { |
240 ASSERT(code.ContainsInstructionAt(return_address)); | 229 ASSERT(code.ContainsInstructionAt(return_address)); |
241 UnoptimizedStaticCall static_call(return_address, code); | 230 UnoptimizedStaticCall static_call(return_address, code); |
242 ICData& ic_data = ICData::Handle(); | 231 ICData& ic_data = ICData::Handle(); |
243 ic_data ^= static_call.ic_data(); | 232 ic_data ^= static_call.ic_data(); |
244 if (ic_data_result != NULL) { | 233 if (ic_data_result != NULL) { |
245 *ic_data_result = ic_data.raw(); | 234 *ic_data_result = ic_data.raw(); |
246 } | 235 } |
247 return ic_data.GetTargetAt(0); | 236 return ic_data.GetTargetAt(0); |
248 } | 237 } |
249 | 238 |
250 | 239 |
251 void CodePatcher::PatchNativeCallAt(uword return_address, | 240 void CodePatcher::PatchNativeCallAt(uword return_address, |
252 const Code& code, | 241 const Code& code, |
253 NativeFunction target, | 242 NativeFunction target, |
254 const Code& trampoline) { | 243 const Code& trampoline) { |
255 ASSERT(code.ContainsInstructionAt(return_address)); | 244 ASSERT(code.ContainsInstructionAt(return_address)); |
256 NativeCall call(return_address, code); | 245 NativeCall call(return_address, code); |
257 call.set_target(trampoline); | 246 call.set_target(trampoline.EntryPoint()); |
258 call.set_native_function(target); | 247 call.set_native_function(target); |
259 } | 248 } |
260 | 249 |
261 | 250 |
262 RawCode* CodePatcher::GetNativeCallAt(uword return_address, | 251 uword CodePatcher::GetNativeCallAt(uword return_address, |
263 const Code& code, | 252 const Code& code, |
264 NativeFunction* target) { | 253 NativeFunction* target) { |
265 ASSERT(code.ContainsInstructionAt(return_address)); | 254 ASSERT(code.ContainsInstructionAt(return_address)); |
266 NativeCall call(return_address, code); | 255 NativeCall call(return_address, code); |
267 *target = call.native_function(); | 256 *target = call.native_function(); |
268 return call.target(); | 257 return call.target(); |
269 } | 258 } |
270 | 259 |
271 | 260 |
272 // The expected code pattern of an edge counter in unoptimized code: | 261 // The expected code pattern of an edge counter in unoptimized code: |
273 // 49 8b 87 imm32 mov RAX, [PP + offset] | 262 // 49 8b 87 imm32 mov RAX, [PP + offset] |
274 class EdgeCounter : public ValueObject { | 263 class EdgeCounter : public ValueObject { |
(...skipping 21 matching lines...) Expand all Loading... |
296 | 285 |
297 RawObject* CodePatcher::GetEdgeCounterAt(uword pc, const Code& code) { | 286 RawObject* CodePatcher::GetEdgeCounterAt(uword pc, const Code& code) { |
298 ASSERT(code.ContainsInstructionAt(pc)); | 287 ASSERT(code.ContainsInstructionAt(pc)); |
299 EdgeCounter counter(pc, code); | 288 EdgeCounter counter(pc, code); |
300 return counter.edge_counter(); | 289 return counter.edge_counter(); |
301 } | 290 } |
302 | 291 |
303 } // namespace dart | 292 } // namespace dart |
304 | 293 |
305 #endif // defined TARGET_ARCH_X64 | 294 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |