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/instructions.h" | 12 #include "vm/instructions.h" |
13 #include "vm/object.h" | 13 #include "vm/object.h" |
14 #include "vm/raw_object.h" | 14 #include "vm/raw_object.h" |
15 | 15 |
16 namespace dart { | 16 namespace dart { |
17 | 17 |
| 18 static int IndexFromPPLoad(uword start) { |
| 19 uint8_t which = *reinterpret_cast<uint8_t*>(start); |
| 20 if (which == 0x9F) { |
| 21 int32_t offset = *reinterpret_cast<int32_t*>(start + 1); |
| 22 offset += kHeapObjectTag; |
| 23 return (offset - Array::data_offset())/kWordSize; |
| 24 } else { |
| 25 ASSERT(which == 0x5F); |
| 26 int32_t offset = *reinterpret_cast<int8_t*>(start + 1); |
| 27 offset += kHeapObjectTag; |
| 28 return (offset - Array::data_offset())/kWordSize; |
| 29 } |
| 30 } |
| 31 |
18 // The expected pattern of a Dart unoptimized call (static and instance): | 32 // The expected pattern of a Dart unoptimized call (static and instance): |
19 // 00: 48 bb imm64 mov RBX, ic-data | 33 // 00: 49 8b 9f imm32 mov RBX, [PP + off] |
20 // 10: 49 bb imm64 mov R11, target_address | 34 // OR: |
21 // 20: 41 ff d3 call R11 | 35 // 00: 49 8b 5f imm8 mov RBX, [PP + off] |
22 // 23 <- return address | 36 // 04: 0f 1f 00 nop |
| 37 // Then: |
| 38 // 07: 4d 8b 9f imm32 mov R11, [PP + off] |
| 39 // OR: |
| 40 // 07: 4d 8b 5f imm8 mov R11, [PP + off] |
| 41 // 11: 0f 1f 00 nop |
| 42 // Then: |
| 43 // 14: 41 ff d3 call R11 |
| 44 // 17 <- return address |
23 class UnoptimizedCall : public ValueObject { | 45 class UnoptimizedCall : public ValueObject { |
24 public: | 46 public: |
25 explicit UnoptimizedCall(uword return_address) | 47 UnoptimizedCall(uword return_address, const Code& code) |
26 : start_(return_address - kCallPatternSize) { | 48 : start_(return_address - kCallPatternSize), |
| 49 object_pool_(Array::Handle(code.ObjectPool())) { |
27 ASSERT(IsValid(return_address)); | 50 ASSERT(IsValid(return_address)); |
28 ASSERT((kCallPatternSize - 10) == Assembler::kCallExternalLabelSize); | 51 ASSERT((kCallPatternSize - 7) == Assembler::kCallExternalLabelSize); |
29 } | 52 } |
30 | 53 |
31 static const int kCallPatternSize = 23; | 54 static const int kCallPatternSize = 17; |
32 | 55 |
33 static bool IsValid(uword return_address) { | 56 static bool IsValid(uword return_address) { |
34 uint8_t* code_bytes = | 57 uint8_t* code_bytes = |
35 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | 58 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
36 return (code_bytes[00] == 0x48) && (code_bytes[01] == 0xBB) && | 59 return (code_bytes[0] == 0x49) && (code_bytes[1] == 0x8B) && |
37 (code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) && | 60 ((code_bytes[2] == 0x5F) || (code_bytes[2] == 0x9F)) && |
38 (code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) && | 61 (code_bytes[7] == 0x4D) && (code_bytes[8] == 0x8B) && |
39 (code_bytes[22] == 0xD3); | 62 ((code_bytes[9] == 0x5F) || (code_bytes[9] == 0x9F)) && |
| 63 (code_bytes[14] == 0x41) && (code_bytes[15] == 0xFF) && |
| 64 (code_bytes[16] == 0xD3); |
40 } | 65 } |
41 | 66 |
42 RawObject* ic_data() const { | 67 RawObject* ic_data() const { |
43 return *reinterpret_cast<RawObject**>(start_ + 0 + 2); | 68 int index = IndexFromPPLoad(start_ + 2); |
| 69 return object_pool_.At(index); |
44 } | 70 } |
45 | 71 |
46 uword target() const { | 72 uword target() const { |
47 return *reinterpret_cast<uword*>(start_ + 10 + 2); | 73 int index = IndexFromPPLoad(start_ + 9); |
| 74 return reinterpret_cast<uword>(object_pool_.At(index)); |
48 } | 75 } |
49 | 76 |
50 void set_target(uword target) const { | 77 void set_target(uword target) const { |
51 uword* target_addr = reinterpret_cast<uword*>(start_ + 10 + 2); | 78 int index = IndexFromPPLoad(start_ + 9); |
52 *target_addr = target; | 79 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target)); |
53 CPU::FlushICache(start_ + 10, 2 + 8); | 80 object_pool_.SetAt(index, smi); |
| 81 // No need to flush the instruction cache, since the code is not modified. |
54 } | 82 } |
55 | 83 |
56 private: | 84 private: |
57 uword start_; | 85 uword start_; |
| 86 const Array& object_pool_; |
58 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall); | 87 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall); |
59 }; | 88 }; |
60 | 89 |
61 | 90 |
62 class InstanceCall : public UnoptimizedCall { | 91 class InstanceCall : public UnoptimizedCall { |
63 public: | 92 public: |
64 explicit InstanceCall(uword return_address) | 93 InstanceCall(uword return_address, const Code& code) |
65 : UnoptimizedCall(return_address) { | 94 : UnoptimizedCall(return_address, code) { |
66 #if defined(DEBUG) | 95 #if defined(DEBUG) |
67 ICData& test_ic_data = ICData::Handle(); | 96 ICData& test_ic_data = ICData::Handle(); |
68 test_ic_data ^= ic_data(); | 97 test_ic_data ^= ic_data(); |
69 ASSERT(test_ic_data.num_args_tested() > 0); | 98 ASSERT(test_ic_data.num_args_tested() > 0); |
70 #endif // DEBUG | 99 #endif // DEBUG |
71 } | 100 } |
72 | 101 |
73 private: | 102 private: |
74 DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceCall); | 103 DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceCall); |
75 }; | 104 }; |
76 | 105 |
77 | 106 |
78 class UnoptimizedStaticCall : public UnoptimizedCall { | 107 class UnoptimizedStaticCall : public UnoptimizedCall { |
79 public: | 108 public: |
80 explicit UnoptimizedStaticCall(uword return_address) | 109 UnoptimizedStaticCall(uword return_address, const Code& code) |
81 : UnoptimizedCall(return_address) { | 110 : UnoptimizedCall(return_address, code) { |
82 #if defined(DEBUG) | 111 #if defined(DEBUG) |
83 ICData& test_ic_data = ICData::Handle(); | 112 ICData& test_ic_data = ICData::Handle(); |
84 test_ic_data ^= ic_data(); | 113 test_ic_data ^= ic_data(); |
85 ASSERT(test_ic_data.num_args_tested() >= 0); | 114 ASSERT(test_ic_data.num_args_tested() >= 0); |
86 #endif // DEBUG | 115 #endif // DEBUG |
87 } | 116 } |
88 | 117 |
89 private: | 118 private: |
90 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); | 119 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall); |
91 }; | 120 }; |
92 | 121 |
93 | 122 |
94 // The expected pattern of a dart static call: | 123 // The expected pattern of a dart static call: |
95 // mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls) | 124 // 00 mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls) |
96 // mov R11, target_address (10 bytes) | 125 // 11: 4d 8b 9f imm32 mov R11, [PP + off] |
97 // call R11 (3 bytes) | 126 // OR: |
| 127 // 11: 4d 8b 5f imm8 mov R11, [PP + off] |
| 128 // 15: 0f 1f 00 nop |
| 129 // Then: |
| 130 // 16: call R11 (3 bytes) |
98 // <- return address | 131 // <- return address |
99 class StaticCall : public ValueObject { | 132 class StaticCall : public ValueObject { |
100 public: | 133 public: |
101 explicit StaticCall(uword return_address) | 134 explicit StaticCall(uword return_address, const Code& code) |
102 : start_(return_address - kCallPatternSize) { | 135 : start_(return_address - kCallPatternSize), |
| 136 object_pool_(Array::Handle(code.ObjectPool())) { |
103 ASSERT(IsValid(return_address)); | 137 ASSERT(IsValid(return_address)); |
104 ASSERT(kCallPatternSize == Assembler::kCallExternalLabelSize); | 138 ASSERT(kCallPatternSize == Assembler::kCallExternalLabelSize); |
105 } | 139 } |
106 | 140 |
107 static const int kCallPatternSize = 13; | 141 static const int kCallPatternSize = 10; |
108 | 142 |
109 static bool IsValid(uword return_address) { | 143 static bool IsValid(uword return_address) { |
110 uint8_t* code_bytes = | 144 uint8_t* code_bytes = |
111 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | 145 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
112 return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBB) && | 146 return (code_bytes[0] == 0x4D) && (code_bytes[1] == 0x8B) && |
113 (code_bytes[10] == 0x41) && (code_bytes[11] == 0xFF) && | 147 ((code_bytes[2] == 0x5F) || (code_bytes[2] == 0x9F)) && |
114 (code_bytes[12] == 0xD3); | 148 (code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) && |
| 149 (code_bytes[9] == 0xD3); |
115 } | 150 } |
116 | 151 |
117 uword target() const { | 152 uword target() const { |
118 return *reinterpret_cast<uword*>(start_ + 2); | 153 int index = IndexFromPPLoad(start_ + 2); |
| 154 return reinterpret_cast<uword>(object_pool_.At(index)); |
119 } | 155 } |
120 | 156 |
121 void set_target(uword target) const { | 157 void set_target(uword target) const { |
122 uword* target_addr = reinterpret_cast<uword*>(start_ + 2); | 158 int index = IndexFromPPLoad(start_ + 2); |
123 *target_addr = target; | 159 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target)); |
124 CPU::FlushICache(start_, 2 + 8); | 160 object_pool_.SetAt(index, smi); |
| 161 // No need to flush the instruction cache, since the code is not modified. |
125 } | 162 } |
126 | 163 |
127 private: | 164 private: |
128 uword start_; | 165 uword start_; |
129 | 166 const Array& object_pool_; |
130 DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall); | 167 DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall); |
131 }; | 168 }; |
132 | 169 |
133 | 170 |
134 // The expected code pattern of a dart closure call: | 171 // The expected code pattern of a dart closure call: |
135 // 00: 49 ba imm64 mov R10, immediate 2 ; 10 bytes | 172 // 00: 49 ba imm64 mov R10, immediate 2 ; 10 bytes |
136 // 10: 49 bb imm64 mov R11, target_address ; 10 bytes | 173 // 10: 4d 8b 9f imm32 mov R11, [PP + off] |
137 // 20: 41 ff d3 call R11 ; 3 bytes | 174 // OR: |
138 // 23: <- return_address | 175 // 10: 4d 8b 5f imm8 mov R11, [PP + off] |
| 176 // 14: 0f 1f 00 nop |
| 177 // Then: |
| 178 // 17: 41 ff d3 call R11 ; 3 bytes |
| 179 // 20: <- return_address |
139 class ClosureCall : public ValueObject { | 180 class ClosureCall : public ValueObject { |
140 public: | 181 public: |
141 explicit ClosureCall(uword return_address) | 182 explicit ClosureCall(uword return_address) |
142 : start_(return_address - kCallPatternSize) { | 183 : start_(return_address - kCallPatternSize) { |
143 ASSERT(IsValid(return_address)); | 184 ASSERT(IsValid(return_address)); |
144 } | 185 } |
145 | 186 |
146 static bool IsValid(uword return_address) { | 187 static bool IsValid(uword return_address) { |
147 uint8_t* code_bytes = | 188 uint8_t* code_bytes = |
148 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); | 189 reinterpret_cast<uint8_t*>(return_address - kCallPatternSize); |
149 return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBA) && | 190 return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBA) && |
150 (code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) && | 191 (code_bytes[10] == 0x4D) && (code_bytes[11] == 0x8B) && |
151 (code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) && | 192 ((code_bytes[12] == 0x5F) || (code_bytes[12] == 0x9F)) && |
152 (code_bytes[22] == 0xD3); | 193 (code_bytes[17] == 0x41) && (code_bytes[18] == 0xFF) && |
| 194 (code_bytes[19] == 0xD3); |
153 } | 195 } |
154 | 196 |
155 RawArray* arguments_descriptor() const { | 197 RawArray* arguments_descriptor() const { |
156 return *reinterpret_cast<RawArray**>(start_ + 2); | 198 return *reinterpret_cast<RawArray**>(start_ + 2); |
157 } | 199 } |
158 | 200 |
159 private: | 201 private: |
160 static const int kCallPatternSize = 10 + 10 + 3; | 202 static const int kCallPatternSize = 10 + 7 + 3; |
161 uword start_; | 203 uword start_; |
162 DISALLOW_IMPLICIT_CONSTRUCTORS(ClosureCall); | 204 DISALLOW_IMPLICIT_CONSTRUCTORS(ClosureCall); |
163 }; | 205 }; |
164 | 206 |
165 | 207 |
166 RawArray* CodePatcher::GetClosureArgDescAt(uword return_address, | 208 RawArray* CodePatcher::GetClosureArgDescAt(uword return_address, |
167 const Code& code) { | 209 const Code& code) { |
168 ASSERT(code.ContainsInstructionAt(return_address)); | 210 ASSERT(code.ContainsInstructionAt(return_address)); |
169 ClosureCall call(return_address); | 211 ClosureCall call(return_address); |
170 return call.arguments_descriptor(); | 212 return call.arguments_descriptor(); |
171 } | 213 } |
172 | 214 |
173 | 215 |
174 uword CodePatcher::GetStaticCallTargetAt(uword return_address, | 216 uword CodePatcher::GetStaticCallTargetAt(uword return_address, |
175 const Code& code) { | 217 const Code& code) { |
176 ASSERT(code.ContainsInstructionAt(return_address)); | 218 ASSERT(code.ContainsInstructionAt(return_address)); |
177 StaticCall call(return_address); | 219 StaticCall call(return_address, code); |
178 return call.target(); | 220 return call.target(); |
179 } | 221 } |
180 | 222 |
181 | 223 |
182 void CodePatcher::PatchStaticCallAt(uword return_address, | 224 void CodePatcher::PatchStaticCallAt(uword return_address, |
183 const Code& code, | 225 const Code& code, |
184 uword new_target) { | 226 uword new_target) { |
185 ASSERT(code.ContainsInstructionAt(return_address)); | 227 ASSERT(code.ContainsInstructionAt(return_address)); |
186 StaticCall call(return_address); | 228 StaticCall call(return_address, code); |
187 call.set_target(new_target); | 229 call.set_target(new_target); |
188 } | 230 } |
189 | 231 |
190 | 232 |
191 void CodePatcher::PatchInstanceCallAt(uword return_address, | 233 void CodePatcher::PatchInstanceCallAt(uword return_address, |
192 const Code& code, | 234 const Code& code, |
193 uword new_target) { | 235 uword new_target) { |
194 ASSERT(code.ContainsInstructionAt(return_address)); | 236 ASSERT(code.ContainsInstructionAt(return_address)); |
195 InstanceCall call(return_address); | 237 InstanceCall call(return_address, code); |
196 call.set_target(new_target); | 238 call.set_target(new_target); |
197 } | 239 } |
198 | 240 |
199 | 241 |
200 uword CodePatcher::GetInstanceCallAt(uword return_address, | 242 uword CodePatcher::GetInstanceCallAt(uword return_address, |
201 const Code& code, | 243 const Code& code, |
202 ICData* ic_data) { | 244 ICData* ic_data) { |
203 ASSERT(code.ContainsInstructionAt(return_address)); | 245 ASSERT(code.ContainsInstructionAt(return_address)); |
204 InstanceCall call(return_address); | 246 InstanceCall call(return_address, code); |
205 if (ic_data != NULL) { | 247 if (ic_data != NULL) { |
206 *ic_data ^= call.ic_data(); | 248 *ic_data ^= call.ic_data(); |
207 } | 249 } |
208 return call.target(); | 250 return call.target(); |
209 } | 251 } |
210 | 252 |
211 | 253 |
212 intptr_t CodePatcher::InstanceCallSizeInBytes() { | 254 intptr_t CodePatcher::InstanceCallSizeInBytes() { |
213 return InstanceCall::kCallPatternSize; | 255 return InstanceCall::kCallPatternSize; |
214 } | 256 } |
215 | 257 |
216 | 258 |
217 void CodePatcher::InsertCallAt(uword start, uword target) { | 259 void CodePatcher::InsertCallAt(uword start, uword target) { |
218 // The inserted call should not overlap the lazy deopt jump code. | 260 // The inserted call should not overlap the lazy deopt jump code. |
219 ASSERT(start + ShortCallPattern::InstructionLength() <= target); | 261 ASSERT(start + ShortCallPattern::InstructionLength() <= target); |
220 *reinterpret_cast<uint8_t*>(start) = 0xE8; | 262 *reinterpret_cast<uint8_t*>(start) = 0xE8; |
221 ShortCallPattern call(start); | 263 ShortCallPattern call(start); |
222 call.SetTargetAddress(target); | 264 call.SetTargetAddress(target); |
223 CPU::FlushICache(start, ShortCallPattern::InstructionLength()); | 265 CPU::FlushICache(start, ShortCallPattern::InstructionLength()); |
224 } | 266 } |
225 | 267 |
226 | 268 |
227 RawFunction* CodePatcher::GetUnoptimizedStaticCallAt( | 269 RawFunction* CodePatcher::GetUnoptimizedStaticCallAt( |
228 uword return_address, const Code& code, ICData* ic_data_result) { | 270 uword return_address, const Code& code, ICData* ic_data_result) { |
229 ASSERT(code.ContainsInstructionAt(return_address)); | 271 ASSERT(code.ContainsInstructionAt(return_address)); |
230 UnoptimizedStaticCall static_call(return_address); | 272 UnoptimizedStaticCall static_call(return_address, code); |
231 ICData& ic_data = ICData::Handle(); | 273 ICData& ic_data = ICData::Handle(); |
232 ic_data ^= static_call.ic_data(); | 274 ic_data ^= static_call.ic_data(); |
233 if (ic_data_result != NULL) { | 275 if (ic_data_result != NULL) { |
234 *ic_data_result = ic_data.raw(); | 276 *ic_data_result = ic_data.raw(); |
235 } | 277 } |
236 return ic_data.GetTargetAt(0); | 278 return ic_data.GetTargetAt(0); |
237 } | 279 } |
238 | 280 |
239 } // namespace dart | 281 } // namespace dart |
240 | 282 |
241 #endif // defined TARGET_ARCH_X64 | 283 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |