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

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
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 num_args_ =
srdjan 2013/10/07 21:36:53 Please add comment why it is 0 with optional param
turnidge 2013/10/08 17:29:12 Copied the old comment from code_generator.cc.
56 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters();
57
58 // The fixed size section of the (fake) Dart frame called via a stub by the
59 // optimized function contains FP, PP (ARM and MIPS only), PC-marker and
60 // return-address. This section is copied as well, so that its contained
61 // values can be updated before returning to the deoptimized function.
62 source_frame_size_ =
63 + kDartFrameFixedSize // For saved values below sp.
64 + ((frame->fp() - frame->sp()) / kWordSize) // For frame size incl. sp.
65 + 1 // For fp.
66 + kParamEndSlotFromFp // For saved values above fp.
67 + num_args_; // For arguments.
68 source_frame_ = reinterpret_cast<intptr_t*>(
69 frame->sp() - (kDartFrameFixedSize * kWordSize));
70
71 if (dest_options == kDestIsOriginalFrame) {
72 // Work from a copy of the source frame.
73 intptr_t* original_frame = source_frame_;
74 source_frame_ = new intptr_t[source_frame_size_];
75 ASSERT(source_frame_ != NULL);
76 for (intptr_t i = 0; i < source_frame_size_; i++) {
77 source_frame_[i] = original_frame[i];
78 }
79 source_frame_is_allocated_ = true;
80 }
81 caller_fp_ = GetSourceFp();
82
83 dest_frame_size_ = deopt_info.FrameSize();
84
85 if (dest_options == kDestIsAllocated) {
86 dest_frame_ = new intptr_t[dest_frame_size_];
87 ASSERT(source_frame_ != NULL);
88 for (intptr_t i = 0; i < source_frame_size_; i++) {
89 dest_frame_[i] = 0;
90 }
91 dest_frame_is_allocated_ = true;
92 }
93
94 if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
95 OS::PrintErr(
96 "Deoptimizing (reason %" Pd " '%s') at pc %#" Px " '%s' (count %d)\n",
97 deopt_reason,
98 DeoptReasonToText(deopt_reason_),
99 frame->pc(),
100 function.ToFullyQualifiedCString(),
101 function.deoptimization_counter());
102 }
39 } 103 }
40 104
41 105
42 DeoptContext::~DeoptContext() { 106 DeoptContext::~DeoptContext() {
43 // Delete memory for source frame and registers. 107 // Delete memory for source frame and registers.
44 if (source_frame_is_copy_) { 108 if (source_frame_is_allocated_) {
45 delete[] source_frame_; 109 delete[] source_frame_;
46 } 110 }
47 source_frame_ = NULL; 111 source_frame_ = NULL;
48 delete[] fpu_registers_; 112 delete[] fpu_registers_;
49 delete[] cpu_registers_; 113 delete[] cpu_registers_;
50 fpu_registers_ = NULL; 114 fpu_registers_ = NULL;
51 cpu_registers_ = NULL; 115 cpu_registers_ = NULL;
116 if (dest_frame_is_allocated_) {
117 delete[] dest_frame_;
118 }
119 dest_frame_ = NULL;
52 120
53 // Delete all deferred objects. 121 // Delete all deferred objects.
54 for (intptr_t i = 0; i < deferred_objects_count_; i++) { 122 for (intptr_t i = 0; i < deferred_objects_count_; i++) {
55 delete deferred_objects_[i]; 123 delete deferred_objects_[i];
56 } 124 }
57 delete[] deferred_objects_; 125 delete[] deferred_objects_;
58 deferred_objects_ = NULL; 126 deferred_objects_ = NULL;
59 deferred_objects_count_ = 0; 127 deferred_objects_count_ = 0;
60 } 128 }
61 129
62 130
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) { 131 void DeoptContext::VisitObjectPointers(ObjectPointerVisitor* visitor) {
92 visitor->VisitPointer(reinterpret_cast<RawObject**>(&object_table_)); 132 visitor->VisitPointer(reinterpret_cast<RawObject**>(&object_table_));
133 visitor->VisitPointer(reinterpret_cast<RawObject**>(&deopt_info_));
134
135 // Visit any object pointers on the destination stack.
136 if (dest_frame_is_allocated_) {
137 for (int i = 0; i < dest_frame_size_; i++) {
138 if (dest_frame_[i] != 0) {
139 visitor->VisitPointer(reinterpret_cast<RawObject**>(&dest_frame_[i]));
140 }
141 }
142 }
93 } 143 }
94 144
95 145
146 intptr_t DeoptContext::DestStackAdjustment() const {
147 return (dest_frame_size_
148 - kDartFrameFixedSize
149 - num_args_
150 - kParamEndSlotFromFp
151 - 1); // For fp.
152 }
153
154
96 intptr_t DeoptContext::GetSourceFp() const { 155 intptr_t DeoptContext::GetSourceFp() const {
97 return source_frame_[source_frame_size_ - 1 - num_args_ - 156 return source_frame_[source_frame_size_ - 1 - num_args_ -
98 kParamEndSlotFromFp]; 157 kParamEndSlotFromFp];
99 } 158 }
100 159
101 160
102 intptr_t DeoptContext::GetSourcePp() const { 161 intptr_t DeoptContext::GetSourcePp() const {
103 return source_frame_[source_frame_size_ - 1 - num_args_ - 162 return source_frame_[source_frame_size_ - 1 - num_args_ -
104 kParamEndSlotFromFp + 163 kParamEndSlotFromFp +
105 StackFrame::SavedCallerPpSlotFromFp()]; 164 StackFrame::SavedCallerPpSlotFromFp()];
106 } 165 }
107 166
108 167
109 intptr_t DeoptContext::GetSourcePc() const { 168 intptr_t DeoptContext::GetSourcePc() const {
110 return source_frame_[source_frame_size_ - num_args_ + kSavedPcSlotFromSp]; 169 return source_frame_[source_frame_size_ - num_args_ + kSavedPcSlotFromSp];
111 } 170 }
112 171
113 172
114 intptr_t DeoptContext::GetCallerFp() const { 173 intptr_t DeoptContext::GetCallerFp() const {
115 return caller_fp_; 174 return caller_fp_;
116 } 175 }
117 176
118 177
119 void DeoptContext::SetCallerFp(intptr_t caller_fp) { 178 void DeoptContext::SetCallerFp(intptr_t caller_fp) {
120 caller_fp_ = caller_fp; 179 caller_fp_ = caller_fp;
121 } 180 }
122 181
123 182
183 static bool IsObjectInstruction(DeoptInstr::Kind kind) {
184 switch (kind) {
185 case DeoptInstr::kConstant:
186 case DeoptInstr::kRegister:
187 case DeoptInstr::kFpuRegister:
188 case DeoptInstr::kInt64FpuRegister:
189 case DeoptInstr::kFloat32x4FpuRegister:
190 case DeoptInstr::kUint32x4FpuRegister:
191 case DeoptInstr::kStackSlot:
192 case DeoptInstr::kDoubleStackSlot:
193 case DeoptInstr::kInt64StackSlot:
194 case DeoptInstr::kFloat32x4StackSlot:
195 case DeoptInstr::kUint32x4StackSlot:
196 case DeoptInstr::kPp:
197 case DeoptInstr::kCallerPp:
198 case DeoptInstr::kMaterializedObjectRef:
199 return true;
200
201 case DeoptInstr::kRetAddress:
202 case DeoptInstr::kPcMarker:
203 case DeoptInstr::kCallerFp:
204 case DeoptInstr::kCallerPc:
205 return false;
206
207 case DeoptInstr::kSuffix:
208 case DeoptInstr::kMaterializeObject:
209 // We should not encounter these instructions when filling stack slots.
210 UNIMPLEMENTED();
211 return false;
212 }
213 }
214
215
216 void DeoptContext::FillDestFrame() {
217 const Code& code = Code::Handle(code_);
218 const DeoptInfo& deopt_info = DeoptInfo::Handle(deopt_info_);
219
220 const intptr_t len = deopt_info.TranslationLength();
221 GrowableArray<DeoptInstr*> deopt_instructions(len);
222 const Array& deopt_table = Array::Handle(code.deopt_info_array());
223 ASSERT(!deopt_table.IsNull());
224 deopt_info.ToInstructions(deopt_table, &deopt_instructions);
225
226 const intptr_t frame_size = deopt_info.FrameSize();
227
228 // For now, we never place non-objects in the deoptimized frame if
229 // the destination frame is a copy. This allows us to copy the
230 // deoptimized frame into an Array.
231 const bool objects_only = dest_frame_is_allocated_;
232
233 // All kMaterializeObject instructions are emitted before the instructions
234 // that describe stack frames. Skip them and defer materialization of
235 // objects until the frame is fully reconstructed and it is safe to perform
236 // GC.
237 // Arguments (class of the instance to allocate and field-value pairs) are
238 // described as part of the expression stack for the bottom-most deoptimized
239 // frame. They will be used during materialization and removed from the stack
240 // right before control switches to the unoptimized code.
241 const intptr_t num_materializations = len - frame_size;
242 PrepareForDeferredMaterialization(num_materializations);
243 for (intptr_t from_index = 0, to_index = kDartFrameFixedSize;
244 from_index < num_materializations;
245 from_index++) {
246 const intptr_t field_count =
247 DeoptInstr::GetFieldCount(deopt_instructions[from_index]);
248 intptr_t* args = GetDestFrameAddressAt(to_index);
249 DeferredObject* obj = new DeferredObject(field_count, args);
250 SetDeferredObjectAt(from_index, obj);
251 to_index += obj->ArgumentCount();
252 }
253
254 // Populate stack frames.
255 for (intptr_t to_index = frame_size - 1, from_index = len - 1;
256 to_index >= 0;
257 to_index--, from_index--) {
258 intptr_t* to_addr = GetDestFrameAddressAt(to_index);
259 DeoptInstr* instr = deopt_instructions[from_index];
260 if (!objects_only || IsObjectInstruction(instr->kind())) {
261 instr->Execute(this, to_addr);
262 } else {
263 *to_addr = 0;
264 }
265 }
266
267 if (FLAG_trace_deoptimization_verbose) {
268 intptr_t* start = dest_frame_;
269 for (intptr_t i = 0; i < frame_size; i++) {
270 // OS::PrintErr("*%" Pd ". [%" Px "] %#014" Px " [%s]\n",
271 OS::Print("*%" Pd ". [%" Px "] %#014" Px " [%s]\n",
272 i,
273 reinterpret_cast<uword>(&start[i]),
274 start[i],
275 deopt_instructions[i + (len - frame_size)]->ToCString());
276 }
277 }
278 }
279
280
124 static void FillDeferredSlots(DeferredSlot** slot_list) { 281 static void FillDeferredSlots(DeferredSlot** slot_list) {
125 DeferredSlot* slot = *slot_list; 282 DeferredSlot* slot = *slot_list;
126 *slot_list = NULL; 283 *slot_list = NULL;
127 284
128 while (slot != NULL) { 285 while (slot != NULL) {
129 DeferredSlot* current = slot; 286 DeferredSlot* current = slot;
130 slot = slot->next(); 287 slot = slot->next();
131 288
132 current->Materialize(); 289 current->Materialize();
133 290
134 delete current; 291 delete current;
135 } 292 }
136 } 293 }
137 294
138 295
139 // Materializes all deferred objects. Returns the total number of 296 // Materializes all deferred objects. Returns the total number of
140 // artificial arguments used during deoptimization. 297 // artificial arguments used during deoptimization.
141 intptr_t DeoptContext::MaterializeDeferredObjects() { 298 intptr_t DeoptContext::MaterializeDeferredObjects() {
142 // First materialize all unboxed "primitive" values (doubles, mints, simd) 299 // First materialize all unboxed "primitive" values (doubles, mints, simd)
143 // then materialize objects. The order is important: objects might be 300 // then materialize objects. The order is important: objects might be
144 // referencing boxes allocated on the first step. At the same time 301 // referencing boxes allocated on the first step. At the same time
145 // objects can't be referencing other deferred objects because storing 302 // objects can't be referencing other deferred objects because storing
146 // an object into a field is always conservatively treated as escaping by 303 // an object into a field is always conservatively treated as escaping by
147 // allocation sinking and load forwarding. 304 // allocation sinking and load forwarding.
148 FillDeferredSlots(&deferred_boxes_); 305 FillDeferredSlots(&deferred_boxes_);
149 FillDeferredSlots(&deferred_object_refs_); 306 FillDeferredSlots(&deferred_object_refs_);
150 307
151 // Compute total number of artificial arguments used during deoptimization. 308 // Compute total number of artificial arguments used during deoptimization.
152 intptr_t deopt_arguments = 0; 309 intptr_t deopt_arg_count = 0;
153 for (intptr_t i = 0; i < DeferredObjectsCount(); i++) { 310 for (intptr_t i = 0; i < DeferredObjectsCount(); i++) {
154 deopt_arguments += GetDeferredObject(i)->ArgumentCount(); 311 deopt_arg_count += GetDeferredObject(i)->ArgumentCount();
155 } 312 }
156 return deopt_arguments; 313
314 // Since this is the only step where GC can occur during deoptimization,
315 // use it to report the source line where deoptimization occured.
316 if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
317 DartFrameIterator iterator;
318 StackFrame* top_frame = iterator.NextFrame();
319 ASSERT(top_frame != NULL);
320 const Code& code = Code::Handle(top_frame->LookupDartCode());
321 const Function& top_function = Function::Handle(code.function());
322 const Script& script = Script::Handle(top_function.script());
323 const intptr_t token_pos = code.GetTokenIndexOfPC(top_frame->pc());
324 intptr_t line, column;
325 script.GetTokenLocation(token_pos, &line, &column);
326 String& line_string = String::Handle(script.GetLine(line));
327 OS::PrintErr(" Function: %s\n", top_function.ToFullyQualifiedCString());
328 OS::PrintErr(" Line %" Pd ": '%s'\n", line, line_string.ToCString());
329 OS::PrintErr(" Deopt args: %" Pd "\n", deopt_arg_count);
330 }
331
332 return deopt_arg_count;
333 }
334
335
336 RawArray* DeoptContext::DestFrameAsArray() {
337 ASSERT(dest_frame_ != NULL && dest_frame_is_allocated_);
338 const Array& dest_array =
339 Array::Handle(Array::New(dest_frame_size_));
340 Instance& obj = Instance::Handle();
341 for (intptr_t i = 0; i < dest_frame_size_; i++) {
342 obj ^= reinterpret_cast<RawObject*>(dest_frame_[i]);
343 dest_array.SetAt(i, obj);
344 }
345 return dest_array.raw();
157 } 346 }
158 347
159 348
160 // Deoptimization instruction moving value from optimized frame at 349 // Deoptimization instruction moving value from optimized frame at
161 // 'source_index' to specified slots in the unoptimized frame. 350 // 'source_index' to specified slots in the unoptimized frame.
162 // 'source_index' represents the slot index of the frame (0 being 351 // 'source_index' represents the slot index of the frame (0 being
163 // first argument) and accounts for saved return address, frame 352 // first argument) and accounts for saved return address, frame
164 // pointer, pool pointer and pc marker. 353 // pointer, pool pointer and pc marker.
165 class DeoptStackSlotInstr : public DeoptInstr { 354 class DeoptStackSlotInstr : public DeoptInstr {
166 public: 355 public:
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after
1194 Smi* offset, 1383 Smi* offset,
1195 DeoptInfo* info, 1384 DeoptInfo* info,
1196 Smi* reason) { 1385 Smi* reason) {
1197 intptr_t i = index * kEntrySize; 1386 intptr_t i = index * kEntrySize;
1198 *offset ^= table.At(i); 1387 *offset ^= table.At(i);
1199 *info ^= table.At(i + 1); 1388 *info ^= table.At(i + 1);
1200 *reason ^= table.At(i + 2); 1389 *reason ^= table.At(i + 2);
1201 } 1390 }
1202 1391
1203 } // namespace dart 1392 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698