Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Side by Side Diff: runtime/vm/deopt_instructions.cc

Issue 26255004: Allow the debugger to inspect local variables from optimized and (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/deopt_instructions.h ('k') | runtime/vm/stack_frame.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/deopt_instructions.h" 5 #include "vm/deopt_instructions.h"
6 6
7 #include "vm/assembler.h" 7 #include "vm/assembler.h"
8 #include "vm/code_patcher.h" 8 #include "vm/code_patcher.h"
9 #include "vm/intermediate_language.h" 9 #include "vm/intermediate_language.h"
10 #include "vm/locations.h" 10 #include "vm/locations.h"
11 #include "vm/parser.h" 11 #include "vm/parser.h"
12 #include "vm/stack_frame.h" 12 #include "vm/stack_frame.h"
13 13
14 namespace dart { 14 namespace dart {
15 15
16 DEFINE_FLAG(bool, compress_deopt_info, true, 16 DEFINE_FLAG(bool, compress_deopt_info, true,
17 "Compress the size of the deoptimization info for optimized code."); 17 "Compress the size of the deoptimization info for optimized code.");
18 DECLARE_FLAG(bool, trace_deoptimization); 18 DECLARE_FLAG(bool, trace_deoptimization);
19 DECLARE_FLAG(bool, trace_deoptimization_verbose); 19 DECLARE_FLAG(bool, trace_deoptimization_verbose);
20 20
21 DeoptContext::DeoptContext(const Array& object_table, 21
22 intptr_t num_args, 22 DeoptContext::DeoptContext(const StackFrame* frame,
23 DeoptReasonId deopt_reason) 23 const Code& code,
24 : object_table_(object_table.raw()), 24 DestFrameOptions dest_options,
25 fpu_register_t* fpu_registers,
26 intptr_t* cpu_registers)
27 : code_(code.raw()),
28 object_table_(Array::null()),
29 deopt_info_(DeoptInfo::null()),
30 dest_frame_is_allocated_(false),
25 dest_frame_(NULL), 31 dest_frame_(NULL),
26 dest_frame_size_(0), 32 dest_frame_size_(0),
27 source_frame_is_copy_(false), 33 source_frame_is_allocated_(false),
28 source_frame_(NULL), 34 source_frame_(NULL),
29 source_frame_size_(0), 35 source_frame_size_(0),
30 cpu_registers_(NULL), 36 cpu_registers_(cpu_registers),
31 fpu_registers_(NULL), 37 fpu_registers_(fpu_registers),
32 num_args_(num_args), 38 num_args_(0),
33 deopt_reason_(deopt_reason), 39 deopt_reason_(kDeoptUnknown),
34 isolate_(Isolate::Current()), 40 isolate_(Isolate::Current()),
35 deferred_boxes_(NULL), 41 deferred_boxes_(NULL),
36 deferred_object_refs_(NULL), 42 deferred_object_refs_(NULL),
37 deferred_objects_count_(0), 43 deferred_objects_count_(0),
38 deferred_objects_(NULL) { 44 deferred_objects_(NULL) {
45 object_table_ = code.object_table();
46
47 intptr_t deopt_reason = kDeoptUnknown;
48 const DeoptInfo& deopt_info =
49 DeoptInfo::Handle(code.GetDeoptInfoAtPc(frame->pc(), &deopt_reason));
50 ASSERT(!deopt_info.IsNull());
51 deopt_info_ = deopt_info.raw();
52 deopt_reason_ = static_cast<DeoptReasonId>(deopt_reason);
53
54 const Function& function = Function::Handle(code.function());
55
56 // Do not include incoming arguments if there are optional arguments
57 // (they are copied into local space at method entry).
58 num_args_ =
59 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters();
60
61 // The fixed size section of the (fake) Dart frame called via a stub by the
62 // optimized function contains FP, PP (ARM and MIPS only), PC-marker and
63 // return-address. This section is copied as well, so that its contained
64 // values can be updated before returning to the deoptimized function.
65 source_frame_size_ =
66 + kDartFrameFixedSize // For saved values below sp.
67 + ((frame->fp() - frame->sp()) / kWordSize) // For frame size incl. sp.
68 + 1 // For fp.
69 + kParamEndSlotFromFp // For saved values above fp.
70 + num_args_; // For arguments.
71 source_frame_ = reinterpret_cast<intptr_t*>(
72 frame->sp() - (kDartFrameFixedSize * kWordSize));
73
74 if (dest_options == kDestIsOriginalFrame) {
75 // Work from a copy of the source frame.
76 intptr_t* original_frame = source_frame_;
77 source_frame_ = new intptr_t[source_frame_size_];
78 ASSERT(source_frame_ != NULL);
79 for (intptr_t i = 0; i < source_frame_size_; i++) {
80 source_frame_[i] = original_frame[i];
81 }
82 source_frame_is_allocated_ = true;
83 }
84 caller_fp_ = GetSourceFp();
85
86 dest_frame_size_ = deopt_info.FrameSize();
87
88 if (dest_options == kDestIsAllocated) {
89 dest_frame_ = new intptr_t[dest_frame_size_];
90 ASSERT(source_frame_ != NULL);
91 for (intptr_t i = 0; i < dest_frame_size_; i++) {
92 dest_frame_[i] = 0;
93 }
94 dest_frame_is_allocated_ = true;
95 }
96
97 if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
98 OS::PrintErr(
99 "Deoptimizing (reason %" Pd " '%s') at pc %#" Px " '%s' (count %d)\n",
100 deopt_reason,
101 DeoptReasonToText(deopt_reason_),
102 frame->pc(),
103 function.ToFullyQualifiedCString(),
104 function.deoptimization_counter());
105 }
39 } 106 }
40 107
41 108
42 DeoptContext::~DeoptContext() { 109 DeoptContext::~DeoptContext() {
43 // Delete memory for source frame and registers. 110 // Delete memory for source frame and registers.
44 if (source_frame_is_copy_) { 111 if (source_frame_is_allocated_) {
45 delete[] source_frame_; 112 delete[] source_frame_;
46 } 113 }
47 source_frame_ = NULL; 114 source_frame_ = NULL;
48 delete[] fpu_registers_; 115 delete[] fpu_registers_;
49 delete[] cpu_registers_; 116 delete[] cpu_registers_;
50 fpu_registers_ = NULL; 117 fpu_registers_ = NULL;
51 cpu_registers_ = NULL; 118 cpu_registers_ = NULL;
119 if (dest_frame_is_allocated_) {
120 delete[] dest_frame_;
121 }
122 dest_frame_ = NULL;
52 123
53 // Delete all deferred objects. 124 // Delete all deferred objects.
54 for (intptr_t i = 0; i < deferred_objects_count_; i++) { 125 for (intptr_t i = 0; i < deferred_objects_count_; i++) {
55 delete deferred_objects_[i]; 126 delete deferred_objects_[i];
56 } 127 }
57 delete[] deferred_objects_; 128 delete[] deferred_objects_;
58 deferred_objects_ = NULL; 129 deferred_objects_ = NULL;
59 deferred_objects_count_ = 0; 130 deferred_objects_count_ = 0;
60 } 131 }
61 132
62 133
63 void DeoptContext::SetSourceArgs(intptr_t* frame_start,
64 intptr_t frame_size,
65 fpu_register_t* fpu_registers,
66 intptr_t* cpu_registers,
67 bool source_frame_is_copy) {
68 ASSERT(frame_start != NULL);
69 ASSERT(frame_size >= 0);
70 ASSERT(source_frame_ == NULL);
71 ASSERT(cpu_registers_ == NULL && fpu_registers_ == NULL);
72 source_frame_ = frame_start;
73 source_frame_size_ = frame_size;
74 caller_fp_ = GetSourceFp();
75 cpu_registers_ = cpu_registers;
76 fpu_registers_ = fpu_registers;
77 source_frame_is_copy_ = source_frame_is_copy;
78 }
79
80
81 void DeoptContext::SetDestArgs(intptr_t* frame_start,
82 intptr_t frame_size) {
83 ASSERT(frame_start != NULL);
84 ASSERT(frame_size >= 0);
85 ASSERT(dest_frame_ == NULL);
86 dest_frame_ = frame_start;
87 dest_frame_size_ = frame_size;
88 }
89
90
91 void DeoptContext::VisitObjectPointers(ObjectPointerVisitor* visitor) { 134 void DeoptContext::VisitObjectPointers(ObjectPointerVisitor* visitor) {
92 visitor->VisitPointer(reinterpret_cast<RawObject**>(&object_table_)); 135 visitor->VisitPointer(reinterpret_cast<RawObject**>(&object_table_));
136 visitor->VisitPointer(reinterpret_cast<RawObject**>(&deopt_info_));
137
138 // Visit any object pointers on the destination stack.
139 if (dest_frame_is_allocated_) {
140 for (intptr_t i = 0; i < dest_frame_size_; i++) {
141 if (dest_frame_[i] != 0) {
142 visitor->VisitPointer(reinterpret_cast<RawObject**>(&dest_frame_[i]));
143 }
144 }
145 }
93 } 146 }
94 147
95 148
149 intptr_t DeoptContext::DestStackAdjustment() const {
150 return (dest_frame_size_
151 - kDartFrameFixedSize
152 - num_args_
153 - kParamEndSlotFromFp
154 - 1); // For fp.
155 }
156
157
96 intptr_t DeoptContext::GetSourceFp() const { 158 intptr_t DeoptContext::GetSourceFp() const {
97 return source_frame_[source_frame_size_ - 1 - num_args_ - 159 return source_frame_[source_frame_size_ - 1 - num_args_ -
98 kParamEndSlotFromFp]; 160 kParamEndSlotFromFp];
99 } 161 }
100 162
101 163
102 intptr_t DeoptContext::GetSourcePp() const { 164 intptr_t DeoptContext::GetSourcePp() const {
103 return source_frame_[source_frame_size_ - 1 - num_args_ - 165 return source_frame_[source_frame_size_ - 1 - num_args_ -
104 kParamEndSlotFromFp + 166 kParamEndSlotFromFp +
105 StackFrame::SavedCallerPpSlotFromFp()]; 167 StackFrame::SavedCallerPpSlotFromFp()];
106 } 168 }
107 169
108 170
109 intptr_t DeoptContext::GetSourcePc() const { 171 intptr_t DeoptContext::GetSourcePc() const {
110 return source_frame_[source_frame_size_ - num_args_ + kSavedPcSlotFromSp]; 172 return source_frame_[source_frame_size_ - num_args_ + kSavedPcSlotFromSp];
111 } 173 }
112 174
113 175
114 intptr_t DeoptContext::GetCallerFp() const { 176 intptr_t DeoptContext::GetCallerFp() const {
115 return caller_fp_; 177 return caller_fp_;
116 } 178 }
117 179
118 180
119 void DeoptContext::SetCallerFp(intptr_t caller_fp) { 181 void DeoptContext::SetCallerFp(intptr_t caller_fp) {
120 caller_fp_ = caller_fp; 182 caller_fp_ = caller_fp;
121 } 183 }
122 184
123 185
186 static bool IsObjectInstruction(DeoptInstr::Kind kind) {
187 switch (kind) {
188 case DeoptInstr::kConstant:
189 case DeoptInstr::kStackSlot:
190 case DeoptInstr::kDoubleStackSlot:
191 case DeoptInstr::kInt64StackSlot:
192 case DeoptInstr::kFloat32x4StackSlot:
193 case DeoptInstr::kUint32x4StackSlot:
194 case DeoptInstr::kPp:
195 case DeoptInstr::kCallerPp:
196 case DeoptInstr::kMaterializedObjectRef:
197 return true;
198
199 case DeoptInstr::kRegister:
200 case DeoptInstr::kFpuRegister:
201 case DeoptInstr::kInt64FpuRegister:
202 case DeoptInstr::kFloat32x4FpuRegister:
203 case DeoptInstr::kUint32x4FpuRegister:
204 // TODO(turnidge): Sometimes we encounter a deopt instruction
205 // with a register source while deoptimizing frames during
206 // debugging but we haven't saved our register set. This
207 // happens specifically when using the VMService to inspect the
208 // stack. In that case, the register values will have been
209 // saved before the StackOverflow runtime call but we do not
210 // actually keep track of which registers were saved and
211 // restored.
212 //
213 // It is possible to save this information at the point of the
214 // StackOverflow runtime call but would require a bit of magic
215 // to either make sure that the registers are pushed on the
216 // stack in a predictable fashion or that we save enough
217 // information to recover them after the fact.
218 //
219 // For now, we punt on these instructions.
220 return false;
221
222 case DeoptInstr::kRetAddress:
223 case DeoptInstr::kPcMarker:
224 case DeoptInstr::kCallerFp:
225 case DeoptInstr::kCallerPc:
226 return false;
227
228 case DeoptInstr::kSuffix:
229 case DeoptInstr::kMaterializeObject:
230 // We should not encounter these instructions when filling stack slots.
231 UNIMPLEMENTED();
232 return false;
233 }
234 }
235
236
237 void DeoptContext::FillDestFrame() {
238 const Code& code = Code::Handle(code_);
239 const DeoptInfo& deopt_info = DeoptInfo::Handle(deopt_info_);
240
241 const intptr_t len = deopt_info.TranslationLength();
242 GrowableArray<DeoptInstr*> deopt_instructions(len);
243 const Array& deopt_table = Array::Handle(code.deopt_info_array());
244 ASSERT(!deopt_table.IsNull());
245 deopt_info.ToInstructions(deopt_table, &deopt_instructions);
246
247 const intptr_t frame_size = deopt_info.FrameSize();
248
249 // For now, we never place non-objects in the deoptimized frame if
250 // the destination frame is a copy. This allows us to copy the
251 // deoptimized frame into an Array.
252 const bool objects_only = dest_frame_is_allocated_;
253
254 // All kMaterializeObject instructions are emitted before the instructions
255 // that describe stack frames. Skip them and defer materialization of
256 // objects until the frame is fully reconstructed and it is safe to perform
257 // GC.
258 // Arguments (class of the instance to allocate and field-value pairs) are
259 // described as part of the expression stack for the bottom-most deoptimized
260 // frame. They will be used during materialization and removed from the stack
261 // right before control switches to the unoptimized code.
262 const intptr_t num_materializations = len - frame_size;
263 PrepareForDeferredMaterialization(num_materializations);
264 for (intptr_t from_index = 0, to_index = kDartFrameFixedSize;
265 from_index < num_materializations;
266 from_index++) {
267 const intptr_t field_count =
268 DeoptInstr::GetFieldCount(deopt_instructions[from_index]);
269 intptr_t* args = GetDestFrameAddressAt(to_index);
270 DeferredObject* obj = new DeferredObject(field_count, args);
271 SetDeferredObjectAt(from_index, obj);
272 to_index += obj->ArgumentCount();
273 }
274
275 // Populate stack frames.
276 for (intptr_t to_index = frame_size - 1, from_index = len - 1;
277 to_index >= 0;
278 to_index--, from_index--) {
279 intptr_t* to_addr = GetDestFrameAddressAt(to_index);
280 DeoptInstr* instr = deopt_instructions[from_index];
281 if (!objects_only || IsObjectInstruction(instr->kind())) {
282 instr->Execute(this, to_addr);
283 } else {
284 *reinterpret_cast<RawObject**>(to_addr) = Object::null();
285 }
286 }
287
288 if (FLAG_trace_deoptimization_verbose) {
289 intptr_t* start = dest_frame_;
290 for (intptr_t i = 0; i < frame_size; i++) {
291 OS::PrintErr("*%" Pd ". [%" Px "] %#014" Px " [%s]\n",
292 i,
293 reinterpret_cast<uword>(&start[i]),
294 start[i],
295 deopt_instructions[i + (len - frame_size)]->ToCString());
296 }
297 }
298 }
299
300
124 static void FillDeferredSlots(DeferredSlot** slot_list) { 301 static void FillDeferredSlots(DeferredSlot** slot_list) {
125 DeferredSlot* slot = *slot_list; 302 DeferredSlot* slot = *slot_list;
126 *slot_list = NULL; 303 *slot_list = NULL;
127 304
128 while (slot != NULL) { 305 while (slot != NULL) {
129 DeferredSlot* current = slot; 306 DeferredSlot* current = slot;
130 slot = slot->next(); 307 slot = slot->next();
131 308
132 current->Materialize(); 309 current->Materialize();
133 310
134 delete current; 311 delete current;
135 } 312 }
136 } 313 }
137 314
138 315
139 // Materializes all deferred objects. Returns the total number of 316 // Materializes all deferred objects. Returns the total number of
140 // artificial arguments used during deoptimization. 317 // artificial arguments used during deoptimization.
141 intptr_t DeoptContext::MaterializeDeferredObjects() { 318 intptr_t DeoptContext::MaterializeDeferredObjects() {
142 // First materialize all unboxed "primitive" values (doubles, mints, simd) 319 // First materialize all unboxed "primitive" values (doubles, mints, simd)
143 // then materialize objects. The order is important: objects might be 320 // then materialize objects. The order is important: objects might be
144 // referencing boxes allocated on the first step. At the same time 321 // referencing boxes allocated on the first step. At the same time
145 // objects can't be referencing other deferred objects because storing 322 // objects can't be referencing other deferred objects because storing
146 // an object into a field is always conservatively treated as escaping by 323 // an object into a field is always conservatively treated as escaping by
147 // allocation sinking and load forwarding. 324 // allocation sinking and load forwarding.
148 FillDeferredSlots(&deferred_boxes_); 325 FillDeferredSlots(&deferred_boxes_);
149 FillDeferredSlots(&deferred_object_refs_); 326 FillDeferredSlots(&deferred_object_refs_);
150 327
151 // Compute total number of artificial arguments used during deoptimization. 328 // Compute total number of artificial arguments used during deoptimization.
152 intptr_t deopt_arguments = 0; 329 intptr_t deopt_arg_count = 0;
153 for (intptr_t i = 0; i < DeferredObjectsCount(); i++) { 330 for (intptr_t i = 0; i < DeferredObjectsCount(); i++) {
154 deopt_arguments += GetDeferredObject(i)->ArgumentCount(); 331 deopt_arg_count += GetDeferredObject(i)->ArgumentCount();
155 } 332 }
156 return deopt_arguments; 333
334 // Since this is the only step where GC can occur during deoptimization,
335 // use it to report the source line where deoptimization occured.
336 if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
337 DartFrameIterator iterator;
338 StackFrame* top_frame = iterator.NextFrame();
339 ASSERT(top_frame != NULL);
340 const Code& code = Code::Handle(top_frame->LookupDartCode());
341 const Function& top_function = Function::Handle(code.function());
342 const Script& script = Script::Handle(top_function.script());
343 const intptr_t token_pos = code.GetTokenIndexOfPC(top_frame->pc());
344 intptr_t line, column;
345 script.GetTokenLocation(token_pos, &line, &column);
346 String& line_string = String::Handle(script.GetLine(line));
347 OS::PrintErr(" Function: %s\n", top_function.ToFullyQualifiedCString());
348 OS::PrintErr(" Line %" Pd ": '%s'\n", line, line_string.ToCString());
349 OS::PrintErr(" Deopt args: %" Pd "\n", deopt_arg_count);
350 }
351
352 return deopt_arg_count;
353 }
354
355
356 RawArray* DeoptContext::DestFrameAsArray() {
357 ASSERT(dest_frame_ != NULL && dest_frame_is_allocated_);
358 const Array& dest_array =
359 Array::Handle(Array::New(dest_frame_size_));
360 Instance& obj = Instance::Handle();
361 for (intptr_t i = 0; i < dest_frame_size_; i++) {
362 obj ^= reinterpret_cast<RawObject*>(dest_frame_[i]);
363 dest_array.SetAt(i, obj);
364 }
365 return dest_array.raw();
157 } 366 }
158 367
159 368
160 // Deoptimization instruction moving value from optimized frame at 369 // Deoptimization instruction moving value from optimized frame at
161 // 'source_index' to specified slots in the unoptimized frame. 370 // 'source_index' to specified slots in the unoptimized frame.
162 // 'source_index' represents the slot index of the frame (0 being 371 // 'source_index' represents the slot index of the frame (0 being
163 // first argument) and accounts for saved return address, frame 372 // first argument) and accounts for saved return address, frame
164 // pointer, pool pointer and pc marker. 373 // pointer, pool pointer and pc marker.
165 class DeoptStackSlotInstr : public DeoptInstr { 374 class DeoptStackSlotInstr : public DeoptInstr {
166 public: 375 public:
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after
1194 Smi* offset, 1403 Smi* offset,
1195 DeoptInfo* info, 1404 DeoptInfo* info,
1196 Smi* reason) { 1405 Smi* reason) {
1197 intptr_t i = index * kEntrySize; 1406 intptr_t i = index * kEntrySize;
1198 *offset ^= table.At(i); 1407 *offset ^= table.At(i);
1199 *info ^= table.At(i + 1); 1408 *info ^= table.At(i + 1);
1200 *reason ^= table.At(i + 2); 1409 *reason ^= table.At(i + 2);
1201 } 1410 }
1202 1411
1203 } // namespace dart 1412 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/deopt_instructions.h ('k') | runtime/vm/stack_frame.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698