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/deopt_instructions.h" | 5 #include "vm/deopt_instructions.h" |
6 | 6 |
7 #include "vm/assembler_macros.h" | 7 #include "vm/assembler_macros.h" |
8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
9 #include "vm/locations.h" | 9 #include "vm/locations.h" |
10 #include "vm/parser.h" | 10 #include "vm/parser.h" |
11 | 11 |
12 namespace dart { | 12 namespace dart { |
13 | 13 |
| 14 DEFINE_FLAG(bool, compress_deopt_info, true, |
| 15 "Compress the size of the deoptimization info for optimized code."); |
| 16 |
14 DeoptimizationContext::DeoptimizationContext(intptr_t* to_frame_start, | 17 DeoptimizationContext::DeoptimizationContext(intptr_t* to_frame_start, |
15 intptr_t to_frame_size, | 18 intptr_t to_frame_size, |
16 const Array& object_table, | 19 const Array& object_table, |
17 intptr_t num_args) | 20 intptr_t num_args) |
18 : object_table_(object_table), | 21 : object_table_(object_table), |
19 to_frame_(to_frame_start), | 22 to_frame_(to_frame_start), |
20 to_frame_size_(to_frame_size), | 23 to_frame_size_(to_frame_size), |
21 from_frame_(NULL), | 24 from_frame_(NULL), |
22 from_frame_size_(0), | 25 from_frame_size_(0), |
23 registers_copy_(NULL), | 26 registers_copy_(NULL), |
(...skipping 30 matching lines...) Expand all Loading... |
54 // 'from_index' represents the slot index of the frame (0 being first argument) | 57 // 'from_index' represents the slot index of the frame (0 being first argument) |
55 // and accounts for saved return address, frame pointer and pc marker. | 58 // and accounts for saved return address, frame pointer and pc marker. |
56 class DeoptStackSlotInstr : public DeoptInstr { | 59 class DeoptStackSlotInstr : public DeoptInstr { |
57 public: | 60 public: |
58 explicit DeoptStackSlotInstr(intptr_t from_index) | 61 explicit DeoptStackSlotInstr(intptr_t from_index) |
59 : stack_slot_index_(from_index) { | 62 : stack_slot_index_(from_index) { |
60 ASSERT(stack_slot_index_ >= 0); | 63 ASSERT(stack_slot_index_ >= 0); |
61 } | 64 } |
62 | 65 |
63 virtual intptr_t from_index() const { return stack_slot_index_; } | 66 virtual intptr_t from_index() const { return stack_slot_index_; } |
64 virtual DeoptInstr::Kind kind() const { return kCopyStackSlot; } | 67 virtual DeoptInstr::Kind kind() const { return kStackSlot; } |
65 | 68 |
66 virtual const char* ToCString() const { | 69 virtual const char* ToCString() const { |
67 const char* format = "s%"Pd""; | 70 const char* format = "s%"Pd""; |
68 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); | 71 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); |
69 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 72 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
70 OS::SNPrint(chars, len + 1, format, stack_slot_index_); | 73 OS::SNPrint(chars, len + 1, format, stack_slot_index_); |
71 return chars; | 74 return chars; |
72 } | 75 } |
73 | 76 |
74 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 77 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
(...skipping 12 matching lines...) Expand all Loading... |
87 | 90 |
88 | 91 |
89 class DeoptDoubleStackSlotInstr : public DeoptInstr { | 92 class DeoptDoubleStackSlotInstr : public DeoptInstr { |
90 public: | 93 public: |
91 explicit DeoptDoubleStackSlotInstr(intptr_t from_index) | 94 explicit DeoptDoubleStackSlotInstr(intptr_t from_index) |
92 : stack_slot_index_(from_index) { | 95 : stack_slot_index_(from_index) { |
93 ASSERT(stack_slot_index_ >= 0); | 96 ASSERT(stack_slot_index_ >= 0); |
94 } | 97 } |
95 | 98 |
96 virtual intptr_t from_index() const { return stack_slot_index_; } | 99 virtual intptr_t from_index() const { return stack_slot_index_; } |
97 virtual DeoptInstr::Kind kind() const { return kCopyDoubleStackSlot; } | 100 virtual DeoptInstr::Kind kind() const { return kDoubleStackSlot; } |
98 | 101 |
99 virtual const char* ToCString() const { | 102 virtual const char* ToCString() const { |
100 const char* format = "ds%"Pd""; | 103 const char* format = "ds%"Pd""; |
101 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); | 104 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); |
102 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 105 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
103 OS::SNPrint(chars, len + 1, format, stack_slot_index_); | 106 OS::SNPrint(chars, len + 1, format, stack_slot_index_); |
104 return chars; | 107 return chars; |
105 } | 108 } |
106 | 109 |
107 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 110 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
(...skipping 15 matching lines...) Expand all Loading... |
123 | 126 |
124 | 127 |
125 class DeoptInt64StackSlotInstr : public DeoptInstr { | 128 class DeoptInt64StackSlotInstr : public DeoptInstr { |
126 public: | 129 public: |
127 explicit DeoptInt64StackSlotInstr(intptr_t from_index) | 130 explicit DeoptInt64StackSlotInstr(intptr_t from_index) |
128 : stack_slot_index_(from_index) { | 131 : stack_slot_index_(from_index) { |
129 ASSERT(stack_slot_index_ >= 0); | 132 ASSERT(stack_slot_index_ >= 0); |
130 } | 133 } |
131 | 134 |
132 virtual intptr_t from_index() const { return stack_slot_index_; } | 135 virtual intptr_t from_index() const { return stack_slot_index_; } |
133 virtual DeoptInstr::Kind kind() const { return kCopyInt64StackSlot; } | 136 virtual DeoptInstr::Kind kind() const { return kInt64StackSlot; } |
134 | 137 |
135 virtual const char* ToCString() const { | 138 virtual const char* ToCString() const { |
136 const char* format = "ms%"Pd""; | 139 const char* format = "ms%"Pd""; |
137 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); | 140 intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_); |
138 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 141 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
139 OS::SNPrint(chars, len + 1, format, stack_slot_index_); | 142 OS::SNPrint(chars, len + 1, format, stack_slot_index_); |
140 return chars; | 143 return chars; |
141 } | 144 } |
142 | 145 |
143 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 146 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
(...skipping 15 matching lines...) Expand all Loading... |
159 private: | 162 private: |
160 const intptr_t stack_slot_index_; // First argument is 0, always >= 0. | 163 const intptr_t stack_slot_index_; // First argument is 0, always >= 0. |
161 | 164 |
162 DISALLOW_COPY_AND_ASSIGN(DeoptInt64StackSlotInstr); | 165 DISALLOW_COPY_AND_ASSIGN(DeoptInt64StackSlotInstr); |
163 }; | 166 }; |
164 | 167 |
165 | 168 |
166 // Deoptimization instruction creating return address using function and | 169 // Deoptimization instruction creating return address using function and |
167 // deopt-id stored at 'object_table_index'. Uses the deopt-after | 170 // deopt-id stored at 'object_table_index'. Uses the deopt-after |
168 // continuation point. | 171 // continuation point. |
169 class DeoptRetAddrAfterInstr : public DeoptInstr { | 172 class DeoptRetAfterAddressInstr : public DeoptInstr { |
170 public: | 173 public: |
171 DeoptRetAddrAfterInstr(intptr_t object_table_index, intptr_t deopt_id) | 174 DeoptRetAfterAddressInstr(intptr_t object_table_index, intptr_t deopt_id) |
172 : object_table_index_(object_table_index), deopt_id_(deopt_id) { | 175 : object_table_index_(object_table_index), deopt_id_(deopt_id) { |
173 ASSERT(object_table_index >= 0); | 176 ASSERT(object_table_index >= 0); |
174 ASSERT(deopt_id >= 0); | 177 ASSERT(deopt_id >= 0); |
175 } | 178 } |
176 | 179 |
177 explicit DeoptRetAddrAfterInstr(intptr_t from_index) | 180 explicit DeoptRetAfterAddressInstr(intptr_t from_index) |
178 : object_table_index_(ObjectTableIndex::decode(from_index)), | 181 : object_table_index_(ObjectTableIndex::decode(from_index)), |
179 deopt_id_(DeoptId::decode(from_index)) { | 182 deopt_id_(DeoptId::decode(from_index)) { |
180 } | 183 } |
181 | 184 |
182 virtual intptr_t from_index() const { | 185 virtual intptr_t from_index() const { |
183 return ObjectTableIndex::encode(object_table_index_) | | 186 return ObjectTableIndex::encode(object_table_index_) | |
184 DeoptId::encode(deopt_id_); | 187 DeoptId::encode(deopt_id_); |
185 } | 188 } |
186 virtual DeoptInstr::Kind kind() const { return kSetRetAfterAddress; } | 189 virtual DeoptInstr::Kind kind() const { return kRetAfterAddress; } |
187 | 190 |
188 virtual const char* ToCString() const { | 191 virtual const char* ToCString() const { |
189 const char* format = "ret aft oti:%"Pd"(%"Pd")"; | 192 const char* format = "ret aft oti:%"Pd"(%"Pd")"; |
190 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); | 193 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); |
191 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 194 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
192 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); | 195 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); |
193 return chars; | 196 return chars; |
194 } | 197 } |
195 | 198 |
196 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 199 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
197 Function& function = Function::Handle(deopt_context->isolate()); | 200 Function& function = Function::Handle(deopt_context->isolate()); |
198 function ^= deopt_context->ObjectAt(object_table_index_); | 201 function ^= deopt_context->ObjectAt(object_table_index_); |
199 const Code& code = | 202 const Code& code = |
200 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); | 203 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); |
201 uword continue_at_pc = code.GetDeoptAfterPcAtDeoptId(deopt_id_); | 204 uword continue_at_pc = code.GetDeoptAfterPcAtDeoptId(deopt_id_); |
202 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 205 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
203 *to_addr = continue_at_pc; | 206 *to_addr = continue_at_pc; |
204 } | 207 } |
205 | 208 |
206 private: | 209 private: |
207 static const intptr_t kFieldWidth = kBitsPerWord / 2; | 210 static const intptr_t kFieldWidth = kBitsPerWord / 2; |
208 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; | 211 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; |
209 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; | 212 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; |
210 | 213 |
211 const intptr_t object_table_index_; | 214 const intptr_t object_table_index_; |
212 const intptr_t deopt_id_; | 215 const intptr_t deopt_id_; |
213 | 216 |
214 DISALLOW_COPY_AND_ASSIGN(DeoptRetAddrAfterInstr); | 217 DISALLOW_COPY_AND_ASSIGN(DeoptRetAfterAddressInstr); |
215 }; | 218 }; |
216 | 219 |
217 | 220 |
218 // Deoptimization instruction creating return address using function and | 221 // Deoptimization instruction creating return address using function and |
219 // deopt-id stored at 'object_table_index'. Uses the deopt-before | 222 // deopt-id stored at 'object_table_index'. Uses the deopt-before |
220 // continuation point. | 223 // continuation point. |
221 class DeoptRetAddrBeforeInstr : public DeoptInstr { | 224 class DeoptRetBeforeAddressInstr : public DeoptInstr { |
222 public: | 225 public: |
223 DeoptRetAddrBeforeInstr(intptr_t object_table_index, intptr_t deopt_id) | 226 DeoptRetBeforeAddressInstr(intptr_t object_table_index, intptr_t deopt_id) |
224 : object_table_index_(object_table_index), deopt_id_(deopt_id) { | 227 : object_table_index_(object_table_index), deopt_id_(deopt_id) { |
225 ASSERT(object_table_index >= 0); | 228 ASSERT(object_table_index >= 0); |
226 ASSERT(deopt_id_ >= 0); | 229 ASSERT(deopt_id >= 0); |
227 } | 230 } |
228 | 231 |
229 explicit DeoptRetAddrBeforeInstr(intptr_t from_index) | 232 explicit DeoptRetBeforeAddressInstr(intptr_t from_index) |
230 : object_table_index_(ObjectTableIndex::decode(from_index)), | 233 : object_table_index_(ObjectTableIndex::decode(from_index)), |
231 deopt_id_(DeoptId::decode(from_index)) { | 234 deopt_id_(DeoptId::decode(from_index)) { |
232 } | 235 } |
233 | 236 |
234 virtual intptr_t from_index() const { | 237 virtual intptr_t from_index() const { |
235 return ObjectTableIndex::encode(object_table_index_) | | 238 return ObjectTableIndex::encode(object_table_index_) | |
236 DeoptId::encode(deopt_id_); | 239 DeoptId::encode(deopt_id_); |
237 } | 240 } |
238 virtual DeoptInstr::Kind kind() const { return kSetRetBeforeAddress; } | 241 virtual DeoptInstr::Kind kind() const { return kRetBeforeAddress; } |
239 | 242 |
240 virtual const char* ToCString() const { | 243 virtual const char* ToCString() const { |
241 const char* format = "ret bef oti:%"Pd"(%"Pd")"; | 244 const char* format = "ret bef oti:%"Pd"(%"Pd")"; |
242 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); | 245 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); |
243 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 246 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
244 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); | 247 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); |
245 return chars; | 248 return chars; |
246 } | 249 } |
247 | 250 |
248 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 251 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
249 Function& function = Function::Handle(deopt_context->isolate()); | 252 Function& function = Function::Handle(deopt_context->isolate()); |
250 function ^= deopt_context->ObjectAt(object_table_index_); | 253 function ^= deopt_context->ObjectAt(object_table_index_); |
251 const Code& code = | 254 const Code& code = |
252 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); | 255 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); |
253 uword continue_at_pc = code.GetDeoptBeforePcAtDeoptId(deopt_id_); | 256 uword continue_at_pc = code.GetDeoptBeforePcAtDeoptId(deopt_id_); |
254 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 257 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
255 *to_addr = continue_at_pc; | 258 *to_addr = continue_at_pc; |
256 } | 259 } |
257 | 260 |
258 private: | 261 private: |
259 static const intptr_t kFieldWidth = kBitsPerWord / 2; | 262 static const intptr_t kFieldWidth = kBitsPerWord / 2; |
260 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; | 263 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; |
261 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; | 264 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; |
262 | 265 |
263 const intptr_t object_table_index_; | 266 const intptr_t object_table_index_; |
264 const intptr_t deopt_id_; | 267 const intptr_t deopt_id_; |
265 | 268 |
266 DISALLOW_COPY_AND_ASSIGN(DeoptRetAddrBeforeInstr); | 269 DISALLOW_COPY_AND_ASSIGN(DeoptRetBeforeAddressInstr); |
267 }; | 270 }; |
268 | 271 |
269 | 272 |
270 // Deoptimization instruction moving a constant stored at 'object_table_index'. | 273 // Deoptimization instruction moving a constant stored at 'object_table_index'. |
271 class DeoptConstantInstr : public DeoptInstr { | 274 class DeoptConstantInstr : public DeoptInstr { |
272 public: | 275 public: |
273 explicit DeoptConstantInstr(intptr_t object_table_index) | 276 explicit DeoptConstantInstr(intptr_t object_table_index) |
274 : object_table_index_(object_table_index) { | 277 : object_table_index_(object_table_index) { |
275 ASSERT(object_table_index >= 0); | 278 ASSERT(object_table_index >= 0); |
276 } | 279 } |
277 | 280 |
278 virtual intptr_t from_index() const { return object_table_index_; } | 281 virtual intptr_t from_index() const { return object_table_index_; } |
279 virtual DeoptInstr::Kind kind() const { return kCopyConstant; } | 282 virtual DeoptInstr::Kind kind() const { return kConstant; } |
280 | 283 |
281 virtual const char* ToCString() const { | 284 virtual const char* ToCString() const { |
282 const char* format = "const oti:%"Pd""; | 285 const char* format = "const oti:%"Pd""; |
283 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_); | 286 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_); |
284 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 287 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
285 OS::SNPrint(chars, len + 1, format, object_table_index_); | 288 OS::SNPrint(chars, len + 1, format, object_table_index_); |
286 return chars; | 289 return chars; |
287 } | 290 } |
288 | 291 |
289 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 292 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
(...skipping 11 matching lines...) Expand all Loading... |
301 }; | 304 }; |
302 | 305 |
303 | 306 |
304 // Deoptimization instruction moving a CPU register. | 307 // Deoptimization instruction moving a CPU register. |
305 class DeoptRegisterInstr: public DeoptInstr { | 308 class DeoptRegisterInstr: public DeoptInstr { |
306 public: | 309 public: |
307 explicit DeoptRegisterInstr(intptr_t reg_as_int) | 310 explicit DeoptRegisterInstr(intptr_t reg_as_int) |
308 : reg_(static_cast<Register>(reg_as_int)) {} | 311 : reg_(static_cast<Register>(reg_as_int)) {} |
309 | 312 |
310 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } | 313 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } |
311 virtual DeoptInstr::Kind kind() const { return kCopyRegister; } | 314 virtual DeoptInstr::Kind kind() const { return kRegister; } |
312 | 315 |
313 virtual const char* ToCString() const { | 316 virtual const char* ToCString() const { |
314 return Assembler::RegisterName(reg_); | 317 return Assembler::RegisterName(reg_); |
315 } | 318 } |
316 | 319 |
317 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 320 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
318 intptr_t value = deopt_context->RegisterValue(reg_); | 321 intptr_t value = deopt_context->RegisterValue(reg_); |
319 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 322 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
320 *to_addr = value; | 323 *to_addr = value; |
321 } | 324 } |
322 | 325 |
323 private: | 326 private: |
324 const Register reg_; | 327 const Register reg_; |
325 | 328 |
326 DISALLOW_COPY_AND_ASSIGN(DeoptRegisterInstr); | 329 DISALLOW_COPY_AND_ASSIGN(DeoptRegisterInstr); |
327 }; | 330 }; |
328 | 331 |
329 | 332 |
330 // Deoptimization instruction moving an XMM register. | 333 // Deoptimization instruction moving an XMM register. |
331 class DeoptXmmRegisterInstr: public DeoptInstr { | 334 class DeoptXmmRegisterInstr: public DeoptInstr { |
332 public: | 335 public: |
333 explicit DeoptXmmRegisterInstr(intptr_t reg_as_int) | 336 explicit DeoptXmmRegisterInstr(intptr_t reg_as_int) |
334 : reg_(static_cast<XmmRegister>(reg_as_int)) {} | 337 : reg_(static_cast<XmmRegister>(reg_as_int)) {} |
335 | 338 |
336 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } | 339 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } |
337 virtual DeoptInstr::Kind kind() const { return kCopyXmmRegister; } | 340 virtual DeoptInstr::Kind kind() const { return kXmmRegister; } |
338 | 341 |
339 virtual const char* ToCString() const { | 342 virtual const char* ToCString() const { |
340 return Assembler::XmmRegisterName(reg_); | 343 return Assembler::XmmRegisterName(reg_); |
341 } | 344 } |
342 | 345 |
343 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 346 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
344 double value = deopt_context->XmmRegisterValue(reg_); | 347 double value = deopt_context->XmmRegisterValue(reg_); |
345 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 348 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
346 *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0); | 349 *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0); |
347 Isolate::Current()->DeferDoubleMaterialization( | 350 Isolate::Current()->DeferDoubleMaterialization( |
348 value, reinterpret_cast<RawDouble**>(to_addr)); | 351 value, reinterpret_cast<RawDouble**>(to_addr)); |
349 } | 352 } |
350 | 353 |
351 private: | 354 private: |
352 const XmmRegister reg_; | 355 const XmmRegister reg_; |
353 | 356 |
354 DISALLOW_COPY_AND_ASSIGN(DeoptXmmRegisterInstr); | 357 DISALLOW_COPY_AND_ASSIGN(DeoptXmmRegisterInstr); |
355 }; | 358 }; |
356 | 359 |
357 | 360 |
358 class DeoptInt64XmmRegisterInstr: public DeoptInstr { | 361 class DeoptInt64XmmRegisterInstr: public DeoptInstr { |
359 public: | 362 public: |
360 explicit DeoptInt64XmmRegisterInstr(intptr_t reg_as_int) | 363 explicit DeoptInt64XmmRegisterInstr(intptr_t reg_as_int) |
361 : reg_(static_cast<XmmRegister>(reg_as_int)) {} | 364 : reg_(static_cast<XmmRegister>(reg_as_int)) {} |
362 | 365 |
363 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } | 366 virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); } |
364 virtual DeoptInstr::Kind kind() const { return kCopyInt64XmmRegister; } | 367 virtual DeoptInstr::Kind kind() const { return kInt64XmmRegister; } |
365 | 368 |
366 virtual const char* ToCString() const { | 369 virtual const char* ToCString() const { |
367 const char* format = "%s(m)"; | 370 const char* format = "%s(m)"; |
368 intptr_t len = | 371 intptr_t len = |
369 OS::SNPrint(NULL, 0, format, Assembler::XmmRegisterName(reg_)); | 372 OS::SNPrint(NULL, 0, format, Assembler::XmmRegisterName(reg_)); |
370 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 373 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
371 OS::SNPrint(chars, len + 1, format, Assembler::XmmRegisterName(reg_)); | 374 OS::SNPrint(chars, len + 1, format, Assembler::XmmRegisterName(reg_)); |
372 return chars; | 375 return chars; |
373 } | 376 } |
374 | 377 |
(...skipping 20 matching lines...) Expand all Loading... |
395 // Deoptimization instruction creating a PC marker for the code of | 398 // Deoptimization instruction creating a PC marker for the code of |
396 // function at 'object_table_index'. | 399 // function at 'object_table_index'. |
397 class DeoptPcMarkerInstr : public DeoptInstr { | 400 class DeoptPcMarkerInstr : public DeoptInstr { |
398 public: | 401 public: |
399 explicit DeoptPcMarkerInstr(intptr_t object_table_index) | 402 explicit DeoptPcMarkerInstr(intptr_t object_table_index) |
400 : object_table_index_(object_table_index) { | 403 : object_table_index_(object_table_index) { |
401 ASSERT(object_table_index >= 0); | 404 ASSERT(object_table_index >= 0); |
402 } | 405 } |
403 | 406 |
404 virtual intptr_t from_index() const { return object_table_index_; } | 407 virtual intptr_t from_index() const { return object_table_index_; } |
405 virtual DeoptInstr::Kind kind() const { return kSetPcMarker; } | 408 virtual DeoptInstr::Kind kind() const { return kPcMarker; } |
406 | 409 |
407 virtual const char* ToCString() const { | 410 virtual const char* ToCString() const { |
408 const char* format = "pcmark oti:%"Pd""; | 411 const char* format = "pcmark oti:%"Pd""; |
409 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_); | 412 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_); |
410 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 413 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
411 OS::SNPrint(chars, len + 1, format, object_table_index_); | 414 OS::SNPrint(chars, len + 1, format, object_table_index_); |
412 return chars; | 415 return chars; |
413 } | 416 } |
414 | 417 |
415 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 418 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
(...skipping 20 matching lines...) Expand all Loading... |
436 DISALLOW_COPY_AND_ASSIGN(DeoptPcMarkerInstr); | 439 DISALLOW_COPY_AND_ASSIGN(DeoptPcMarkerInstr); |
437 }; | 440 }; |
438 | 441 |
439 | 442 |
440 // Deoptimization instruction copying the caller saved FP from optimized frame. | 443 // Deoptimization instruction copying the caller saved FP from optimized frame. |
441 class DeoptCallerFpInstr : public DeoptInstr { | 444 class DeoptCallerFpInstr : public DeoptInstr { |
442 public: | 445 public: |
443 DeoptCallerFpInstr() {} | 446 DeoptCallerFpInstr() {} |
444 | 447 |
445 virtual intptr_t from_index() const { return 0; } | 448 virtual intptr_t from_index() const { return 0; } |
446 virtual DeoptInstr::Kind kind() const { return kSetCallerFp; } | 449 virtual DeoptInstr::Kind kind() const { return kCallerFp; } |
447 | 450 |
448 virtual const char* ToCString() const { | 451 virtual const char* ToCString() const { |
449 return "callerfp"; | 452 return "callerfp"; |
450 } | 453 } |
451 | 454 |
452 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 455 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
453 intptr_t from = deopt_context->GetCallerFp(); | 456 intptr_t from = deopt_context->GetCallerFp(); |
454 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 457 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
455 *to_addr = from; | 458 *to_addr = from; |
456 deopt_context->SetCallerFp(reinterpret_cast<intptr_t>(to_addr)); | 459 deopt_context->SetCallerFp(reinterpret_cast<intptr_t>(to_addr)); |
457 } | 460 } |
458 | 461 |
459 private: | 462 private: |
460 DISALLOW_COPY_AND_ASSIGN(DeoptCallerFpInstr); | 463 DISALLOW_COPY_AND_ASSIGN(DeoptCallerFpInstr); |
461 }; | 464 }; |
462 | 465 |
463 | 466 |
464 // Deoptimization instruction copying the caller return address from optimized | 467 // Deoptimization instruction copying the caller return address from optimized |
465 // frame. | 468 // frame. |
466 class DeoptCallerPcInstr : public DeoptInstr { | 469 class DeoptCallerPcInstr : public DeoptInstr { |
467 public: | 470 public: |
468 DeoptCallerPcInstr() {} | 471 DeoptCallerPcInstr() {} |
469 | 472 |
470 virtual intptr_t from_index() const { return 0; } | 473 virtual intptr_t from_index() const { return 0; } |
471 virtual DeoptInstr::Kind kind() const { return kSetCallerPc; } | 474 virtual DeoptInstr::Kind kind() const { return kCallerPc; } |
472 | 475 |
473 virtual const char* ToCString() const { | 476 virtual const char* ToCString() const { |
474 return "callerpc"; | 477 return "callerpc"; |
475 } | 478 } |
476 | 479 |
477 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 480 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
478 intptr_t from = deopt_context->GetFromPc(); | 481 intptr_t from = deopt_context->GetFromPc(); |
479 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 482 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
480 *to_addr = from; | 483 *to_addr = from; |
481 } | 484 } |
482 | 485 |
483 private: | 486 private: |
484 DISALLOW_COPY_AND_ASSIGN(DeoptCallerPcInstr); | 487 DISALLOW_COPY_AND_ASSIGN(DeoptCallerPcInstr); |
485 }; | 488 }; |
486 | 489 |
487 | 490 |
| 491 // Deoptimization instruction that indicates the rest of this DeoptInfo is a |
| 492 // suffix of another one. The suffix contains the info number (0 based |
| 493 // index in the deopt table of the DeoptInfo to share) and the length of the |
| 494 // suffix. |
| 495 class DeoptSuffixInstr : public DeoptInstr { |
| 496 public: |
| 497 DeoptSuffixInstr(intptr_t info_number, intptr_t suffix_length) |
| 498 : info_number_(info_number), suffix_length_(suffix_length) { |
| 499 ASSERT(info_number >= 0); |
| 500 ASSERT(suffix_length >= 0); |
| 501 } |
| 502 |
| 503 explicit DeoptSuffixInstr(intptr_t from_index) |
| 504 : info_number_(InfoNumber::decode(from_index)), |
| 505 suffix_length_(SuffixLength::decode(from_index)) { |
| 506 } |
| 507 |
| 508 virtual intptr_t from_index() const { |
| 509 return InfoNumber::encode(info_number_) | |
| 510 SuffixLength::encode(suffix_length_); |
| 511 } |
| 512 virtual DeoptInstr::Kind kind() const { return kSuffix; } |
| 513 |
| 514 virtual const char* ToCString() const { |
| 515 const char* format = "suffix %"Pd":%"Pd; |
| 516 intptr_t len = OS::SNPrint(NULL, 0, format, info_number_, suffix_length_); |
| 517 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 518 OS::SNPrint(chars, len + 1, format, info_number_, suffix_length_); |
| 519 return chars; |
| 520 } |
| 521 |
| 522 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| 523 // The deoptimization info is uncompresses by translating away suffixes |
| 524 // before executing the instructions. |
| 525 UNREACHABLE(); |
| 526 } |
| 527 |
| 528 private: |
| 529 // Static decoder functions in DeoptInstr have access to the bitfield |
| 530 // definitions. |
| 531 friend class DeoptInstr; |
| 532 |
| 533 static const intptr_t kFieldWidth = kBitsPerWord / 2; |
| 534 class InfoNumber : public BitField<intptr_t, 0, kFieldWidth> { }; |
| 535 class SuffixLength : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; |
| 536 |
| 537 const intptr_t info_number_; |
| 538 const intptr_t suffix_length_; |
| 539 |
| 540 DISALLOW_COPY_AND_ASSIGN(DeoptSuffixInstr); |
| 541 }; |
| 542 |
| 543 |
| 544 intptr_t DeoptInstr::DecodeSuffix(intptr_t from_index, intptr_t* info_number) { |
| 545 *info_number = DeoptSuffixInstr::InfoNumber::decode(from_index); |
| 546 return DeoptSuffixInstr::SuffixLength::decode(from_index); |
| 547 } |
| 548 |
| 549 |
488 DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t from_index) { | 550 DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t from_index) { |
489 Kind kind = static_cast<Kind>(kind_as_int); | 551 Kind kind = static_cast<Kind>(kind_as_int); |
490 switch (kind) { | 552 switch (kind) { |
491 case kCopyStackSlot: return new DeoptStackSlotInstr(from_index); | 553 case kStackSlot: return new DeoptStackSlotInstr(from_index); |
492 case kCopyDoubleStackSlot: return new DeoptDoubleStackSlotInstr(from_index); | 554 case kDoubleStackSlot: return new DeoptDoubleStackSlotInstr(from_index); |
493 case kCopyInt64StackSlot: return new DeoptInt64StackSlotInstr(from_index); | 555 case kInt64StackSlot: return new DeoptInt64StackSlotInstr(from_index); |
494 case kSetRetAfterAddress: return new DeoptRetAddrAfterInstr(from_index); | 556 case kRetAfterAddress: return new DeoptRetAfterAddressInstr(from_index); |
495 case kSetRetBeforeAddress: return new DeoptRetAddrBeforeInstr(from_index); | 557 case kRetBeforeAddress: return new DeoptRetBeforeAddressInstr(from_index); |
496 case kCopyConstant: return new DeoptConstantInstr(from_index); | 558 case kConstant: return new DeoptConstantInstr(from_index); |
497 case kCopyRegister: return new DeoptRegisterInstr(from_index); | 559 case kRegister: return new DeoptRegisterInstr(from_index); |
498 case kCopyXmmRegister: return new DeoptXmmRegisterInstr(from_index); | 560 case kXmmRegister: return new DeoptXmmRegisterInstr(from_index); |
499 case kCopyInt64XmmRegister: | 561 case kInt64XmmRegister: return new DeoptInt64XmmRegisterInstr(from_index); |
500 return new DeoptInt64XmmRegisterInstr(from_index); | 562 case kPcMarker: return new DeoptPcMarkerInstr(from_index); |
501 case kSetPcMarker: return new DeoptPcMarkerInstr(from_index); | 563 case kCallerFp: return new DeoptCallerFpInstr(); |
502 case kSetCallerFp: return new DeoptCallerFpInstr(); | 564 case kCallerPc: return new DeoptCallerPcInstr(); |
503 case kSetCallerPc: return new DeoptCallerPcInstr(); | 565 case kSuffix: return new DeoptSuffixInstr(from_index); |
504 } | 566 } |
505 UNREACHABLE(); | 567 UNREACHABLE(); |
506 return NULL; | 568 return NULL; |
507 } | 569 } |
508 | 570 |
509 | 571 |
| 572 class DeoptInfoBuilder::TrieNode : public ZoneAllocated { |
| 573 public: |
| 574 // Construct the root node representing the implicit "shared" terminator |
| 575 // at the end of each deopt info. |
| 576 TrieNode() : instruction_(NULL), info_number_(-1), children_(16) { } |
| 577 |
| 578 // Construct a node representing a written instruction. |
| 579 TrieNode(DeoptInstr* instruction, intptr_t info_number) |
| 580 : instruction_(instruction), info_number_(info_number), children_(4) { } |
| 581 |
| 582 intptr_t info_number() const { return info_number_; } |
| 583 |
| 584 void AddChild(TrieNode* child) { |
| 585 if (child != NULL) children_.Add(child); |
| 586 } |
| 587 |
| 588 TrieNode* FindChild(const DeoptInstr& instruction) { |
| 589 for (intptr_t i = 0; i < children_.length(); ++i) { |
| 590 TrieNode* child = children_[i]; |
| 591 if (child->instruction_->Equals(instruction)) return child; |
| 592 } |
| 593 return NULL; |
| 594 } |
| 595 |
| 596 private: |
| 597 const DeoptInstr* instruction_; // Instruction that was written. |
| 598 const intptr_t info_number_; // Index of the deopt info it was written to. |
| 599 |
| 600 GrowableArray<TrieNode*> children_; |
| 601 }; |
| 602 |
| 603 |
| 604 DeoptInfoBuilder::DeoptInfoBuilder(const intptr_t num_args) |
| 605 : instructions_(), |
| 606 object_table_(GrowableObjectArray::Handle(GrowableObjectArray::New())), |
| 607 num_args_(num_args), |
| 608 trie_root_(new TrieNode()), |
| 609 current_info_number_(0) { |
| 610 } |
| 611 |
| 612 |
510 intptr_t DeoptInfoBuilder::FindOrAddObjectInTable(const Object& obj) const { | 613 intptr_t DeoptInfoBuilder::FindOrAddObjectInTable(const Object& obj) const { |
511 for (intptr_t i = 0; i < object_table_.Length(); i++) { | 614 for (intptr_t i = 0; i < object_table_.Length(); i++) { |
512 if (object_table_.At(i) == obj.raw()) { | 615 if (object_table_.At(i) == obj.raw()) { |
513 return i; | 616 return i; |
514 } | 617 } |
515 } | 618 } |
516 // Add object. | 619 // Add object. |
517 const intptr_t result = object_table_.Length(); | 620 const intptr_t result = object_table_.Length(); |
518 object_table_.Add(obj); | 621 object_table_.Add(obj); |
519 return result; | 622 return result; |
520 } | 623 } |
521 | 624 |
522 | 625 |
523 void DeoptInfoBuilder::AddReturnAddressBefore(const Function& function, | 626 void DeoptInfoBuilder::AddReturnAddressBefore(const Function& function, |
524 intptr_t deopt_id, | 627 intptr_t deopt_id, |
525 intptr_t to_index) { | 628 intptr_t to_index) { |
526 const intptr_t object_table_index = FindOrAddObjectInTable(function); | 629 const intptr_t object_table_index = FindOrAddObjectInTable(function); |
527 ASSERT(to_index == instructions_.length()); | 630 ASSERT(to_index == instructions_.length()); |
528 instructions_.Add(new DeoptRetAddrBeforeInstr(object_table_index, deopt_id)); | 631 instructions_.Add(new DeoptRetBeforeAddressInstr(object_table_index, |
| 632 deopt_id)); |
529 } | 633 } |
530 | 634 |
531 | 635 |
532 void DeoptInfoBuilder::AddReturnAddressAfter(const Function& function, | 636 void DeoptInfoBuilder::AddReturnAddressAfter(const Function& function, |
533 intptr_t deopt_id, | 637 intptr_t deopt_id, |
534 intptr_t to_index) { | 638 intptr_t to_index) { |
535 const intptr_t object_table_index = FindOrAddObjectInTable(function); | 639 const intptr_t object_table_index = FindOrAddObjectInTable(function); |
536 ASSERT(to_index == instructions_.length()); | 640 ASSERT(to_index == instructions_.length()); |
537 instructions_.Add(new DeoptRetAddrAfterInstr(object_table_index, deopt_id)); | 641 instructions_.Add(new DeoptRetAfterAddressInstr(object_table_index, |
| 642 deopt_id)); |
538 } | 643 } |
539 | 644 |
540 | 645 |
541 void DeoptInfoBuilder::AddPcMarker(const Function& function, | 646 void DeoptInfoBuilder::AddPcMarker(const Function& function, |
542 intptr_t to_index) { | 647 intptr_t to_index) { |
543 // Function object was already added by AddReturnAddress, find it. | 648 // Function object was already added by AddReturnAddress, find it. |
544 intptr_t from_index = FindOrAddObjectInTable(function); | 649 intptr_t from_index = FindOrAddObjectInTable(function); |
545 ASSERT(to_index == instructions_.length()); | 650 ASSERT(to_index == instructions_.length()); |
546 instructions_.Add(new DeoptPcMarkerInstr(from_index)); | 651 instructions_.Add(new DeoptPcMarkerInstr(from_index)); |
547 } | 652 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 instructions_.Add(new DeoptCallerFpInstr()); | 698 instructions_.Add(new DeoptCallerFpInstr()); |
594 } | 699 } |
595 | 700 |
596 | 701 |
597 void DeoptInfoBuilder::AddCallerPc(intptr_t to_index) { | 702 void DeoptInfoBuilder::AddCallerPc(intptr_t to_index) { |
598 ASSERT(to_index == instructions_.length()); | 703 ASSERT(to_index == instructions_.length()); |
599 instructions_.Add(new DeoptCallerPcInstr()); | 704 instructions_.Add(new DeoptCallerPcInstr()); |
600 } | 705 } |
601 | 706 |
602 | 707 |
603 RawDeoptInfo* DeoptInfoBuilder::CreateDeoptInfo() const { | 708 RawDeoptInfo* DeoptInfoBuilder::CreateDeoptInfo() { |
604 const intptr_t len = instructions_.length(); | 709 intptr_t length = instructions_.length(); |
605 const DeoptInfo& deopt_info = DeoptInfo::Handle(DeoptInfo::New(len)); | 710 |
606 for (intptr_t i = 0; i < len; i++) { | 711 // Count the number of instructions that are a shared suffix of some deopt |
| 712 // info already written. |
| 713 TrieNode* suffix = trie_root_; |
| 714 intptr_t suffix_length = 0; |
| 715 if (FLAG_compress_deopt_info) { |
| 716 for (intptr_t i = length - 1; i >= 0; --i) { |
| 717 TrieNode* node = suffix->FindChild(*instructions_[i]); |
| 718 if (node == NULL) break; |
| 719 suffix = node; |
| 720 ++suffix_length; |
| 721 } |
| 722 } |
| 723 |
| 724 // Allocate space for the translation. If the shared suffix is longer |
| 725 // than one instruction, we replace it with a single suffix instruction. |
| 726 if (suffix_length > 1) length -= (suffix_length - 1); |
| 727 const DeoptInfo& deopt_info = DeoptInfo::Handle(DeoptInfo::New(length)); |
| 728 |
| 729 // Write the unshared instructions and build their sub-tree. |
| 730 TrieNode* node = NULL; |
| 731 intptr_t write_count = (suffix_length > 1) ? length - 1 : length; |
| 732 for (intptr_t i = 0; i < write_count; ++i) { |
607 DeoptInstr* instr = instructions_[i]; | 733 DeoptInstr* instr = instructions_[i]; |
608 deopt_info.SetAt(i, instr->kind(), instr->from_index()); | 734 deopt_info.SetAt(i, instr->kind(), instr->from_index()); |
| 735 TrieNode* child = node; |
| 736 node = new TrieNode(instr, current_info_number_); |
| 737 node->AddChild(child); |
609 } | 738 } |
| 739 suffix->AddChild(node); |
| 740 |
| 741 if (suffix_length > 1) { |
| 742 DeoptInstr* instr = |
| 743 new DeoptSuffixInstr(suffix->info_number(), suffix_length); |
| 744 deopt_info.SetAt(length - 1, instr->kind(), instr->from_index()); |
| 745 } |
| 746 |
| 747 instructions_.Clear(); |
| 748 ++current_info_number_; |
610 return deopt_info.raw(); | 749 return deopt_info.raw(); |
611 } | 750 } |
612 | 751 |
613 | 752 |
614 intptr_t DeoptTable::SizeFor(intptr_t length) { | 753 intptr_t DeoptTable::SizeFor(intptr_t length) { |
615 return length * kEntrySize; | 754 return length * kEntrySize; |
616 } | 755 } |
617 | 756 |
618 void DeoptTable::SetEntry(const Array& table, | 757 void DeoptTable::SetEntry(const Array& table, |
619 intptr_t index, | 758 intptr_t index, |
(...skipping 19 matching lines...) Expand all Loading... |
639 Smi* offset, | 778 Smi* offset, |
640 DeoptInfo* info, | 779 DeoptInfo* info, |
641 Smi* reason) { | 780 Smi* reason) { |
642 intptr_t i = index * kEntrySize; | 781 intptr_t i = index * kEntrySize; |
643 *offset ^= table.At(i); | 782 *offset ^= table.At(i); |
644 *info ^= table.At(i + 1); | 783 *info ^= table.At(i + 1); |
645 *reason ^= table.At(i + 2); | 784 *reason ^= table.At(i + 2); |
646 } | 785 } |
647 | 786 |
648 } // namespace dart | 787 } // namespace dart |
OLD | NEW |