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

Side by Side Diff: src/deoptimizer.cc

Issue 7230045: Support debugger inspection of locals in optimized frames (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rebase Created 9 years, 5 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 | « src/deoptimizer.h ('k') | src/frames.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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 26 matching lines...) Expand all
37 37
38 38
39 namespace v8 { 39 namespace v8 {
40 namespace internal { 40 namespace internal {
41 41
42 DeoptimizerData::DeoptimizerData() { 42 DeoptimizerData::DeoptimizerData() {
43 eager_deoptimization_entry_code_ = NULL; 43 eager_deoptimization_entry_code_ = NULL;
44 lazy_deoptimization_entry_code_ = NULL; 44 lazy_deoptimization_entry_code_ = NULL;
45 current_ = NULL; 45 current_ = NULL;
46 deoptimizing_code_list_ = NULL; 46 deoptimizing_code_list_ = NULL;
47 #ifdef ENABLE_DEBUGGER_SUPPORT
48 deoptimized_frame_info_ = NULL;
49 #endif
47 } 50 }
48 51
49 52
50 DeoptimizerData::~DeoptimizerData() { 53 DeoptimizerData::~DeoptimizerData() {
51 if (eager_deoptimization_entry_code_ != NULL) { 54 if (eager_deoptimization_entry_code_ != NULL) {
52 eager_deoptimization_entry_code_->Free(EXECUTABLE); 55 eager_deoptimization_entry_code_->Free(EXECUTABLE);
53 eager_deoptimization_entry_code_ = NULL; 56 eager_deoptimization_entry_code_ = NULL;
54 } 57 }
55 if (lazy_deoptimization_entry_code_ != NULL) { 58 if (lazy_deoptimization_entry_code_ != NULL) {
56 lazy_deoptimization_entry_code_->Free(EXECUTABLE); 59 lazy_deoptimization_entry_code_->Free(EXECUTABLE);
57 lazy_deoptimization_entry_code_ = NULL; 60 lazy_deoptimization_entry_code_ = NULL;
58 } 61 }
59 } 62 }
60 63
64
65 #ifdef ENABLE_DEBUGGER_SUPPORT
66 void DeoptimizerData::Iterate(ObjectVisitor* v) {
67 if (deoptimized_frame_info_ != NULL) {
68 deoptimized_frame_info_->Iterate(v);
69 }
70 }
71 #endif
72
73
61 Deoptimizer* Deoptimizer::New(JSFunction* function, 74 Deoptimizer* Deoptimizer::New(JSFunction* function,
62 BailoutType type, 75 BailoutType type,
63 unsigned bailout_id, 76 unsigned bailout_id,
64 Address from, 77 Address from,
65 int fp_to_sp_delta, 78 int fp_to_sp_delta,
66 Isolate* isolate) { 79 Isolate* isolate) {
67 ASSERT(isolate == Isolate::Current()); 80 ASSERT(isolate == Isolate::Current());
68 Deoptimizer* deoptimizer = new Deoptimizer(isolate, 81 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
69 function, 82 function,
70 type, 83 type,
71 bailout_id, 84 bailout_id,
72 from, 85 from,
73 fp_to_sp_delta); 86 fp_to_sp_delta,
87 NULL);
74 ASSERT(isolate->deoptimizer_data()->current_ == NULL); 88 ASSERT(isolate->deoptimizer_data()->current_ == NULL);
75 isolate->deoptimizer_data()->current_ = deoptimizer; 89 isolate->deoptimizer_data()->current_ = deoptimizer;
76 return deoptimizer; 90 return deoptimizer;
77 } 91 }
78 92
79 93
80 Deoptimizer* Deoptimizer::Grab(Isolate* isolate) { 94 Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
81 ASSERT(isolate == Isolate::Current()); 95 ASSERT(isolate == Isolate::Current());
82 Deoptimizer* result = isolate->deoptimizer_data()->current_; 96 Deoptimizer* result = isolate->deoptimizer_data()->current_;
83 ASSERT(result != NULL); 97 ASSERT(result != NULL);
84 result->DeleteFrameDescriptions(); 98 result->DeleteFrameDescriptions();
85 isolate->deoptimizer_data()->current_ = NULL; 99 isolate->deoptimizer_data()->current_ = NULL;
86 return result; 100 return result;
87 } 101 }
88 102
103 #ifdef ENABLE_DEBUGGER_SUPPORT
104 DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
105 JavaScriptFrame* frame,
106 int frame_index,
107 Isolate* isolate) {
108 ASSERT(isolate == Isolate::Current());
109 ASSERT(frame->is_optimized());
110 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
111
112 // Get the function and code from the frame.
113 JSFunction* function = JSFunction::cast(frame->function());
114 Code* code = frame->LookupCode();
115 Address code_start_address = code->instruction_start();
116
117 // Locate the deoptimization point in the code. As we are at a call the
118 // return address must be at a place in the code with deoptimization support.
119 int deoptimization_index = Safepoint::kNoDeoptimizationIndex;
120 // Scope this as the safe point constructor will disallow allocation.
121 {
122 SafepointTable table(code);
123 for (unsigned i = 0; i < table.length(); ++i) {
124 Address address = code_start_address + table.GetPcOffset(i);
125 if (address == frame->pc()) {
126 SafepointEntry safepoint_entry = table.GetEntry(i);
127 ASSERT(safepoint_entry.deoptimization_index() !=
128 Safepoint::kNoDeoptimizationIndex);
129 deoptimization_index = safepoint_entry.deoptimization_index();
130 break;
131 }
132 }
133 }
134 ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
135
136 // Always use the actual stack slots when calculating the fp to sp
137 // delta adding two for the function and context.
138 unsigned stack_slots = code->stack_slots();
139 unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize);
140
141 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
142 function,
143 Deoptimizer::DEBUGGER,
144 deoptimization_index,
145 frame->pc(),
146 fp_to_sp_delta,
147 code);
148 Address tos = frame->fp() - fp_to_sp_delta;
149 deoptimizer->FillInputFrame(tos, frame);
150
151 // Calculate the output frames.
152 Deoptimizer::ComputeOutputFrames(deoptimizer);
153
154 // Create the GC safe output frame information and register it for GC
155 // handling.
156 ASSERT_LT(frame_index, deoptimizer->output_count());
157 DeoptimizedFrameInfo* info =
158 new DeoptimizedFrameInfo(deoptimizer, frame_index);
159 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
160
161 // Get the "simulated" top and size for the requested frame.
162 Address top =
163 reinterpret_cast<Address>(deoptimizer->output_[frame_index]->GetTop());
164 intptr_t size =
165 deoptimizer->output_[frame_index]->GetFrameSize() / kPointerSize;
166
167 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
168 deoptimizer->DeleteFrameDescriptions();
169
170 // Allocate a heap number for the doubles belonging to this frame.
171 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
172 top, size, info);
173
174 // Finished using the deoptimizer instance.
175 delete deoptimizer;
176
177 return info;
178 }
179
180
181 void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
182 Isolate* isolate) {
183 ASSERT(isolate == Isolate::Current());
184 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info);
185 delete info;
186 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
187 }
188 #endif
89 189
90 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, 190 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
91 int count, 191 int count,
92 BailoutType type) { 192 BailoutType type) {
93 TableEntryGenerator generator(masm, type, count); 193 TableEntryGenerator generator(masm, type, count);
94 generator.Generate(); 194 generator.Generate();
95 } 195 }
96 196
97 197
98 class DeoptimizingVisitor : public OptimizedFunctionVisitor { 198 class DeoptimizingVisitor : public OptimizedFunctionVisitor {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) { 302 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
203 deoptimizer->DoComputeOutputFrames(); 303 deoptimizer->DoComputeOutputFrames();
204 } 304 }
205 305
206 306
207 Deoptimizer::Deoptimizer(Isolate* isolate, 307 Deoptimizer::Deoptimizer(Isolate* isolate,
208 JSFunction* function, 308 JSFunction* function,
209 BailoutType type, 309 BailoutType type,
210 unsigned bailout_id, 310 unsigned bailout_id,
211 Address from, 311 Address from,
212 int fp_to_sp_delta) 312 int fp_to_sp_delta,
313 Code* optimized_code)
213 : isolate_(isolate), 314 : isolate_(isolate),
214 function_(function), 315 function_(function),
215 bailout_id_(bailout_id), 316 bailout_id_(bailout_id),
216 bailout_type_(type), 317 bailout_type_(type),
217 from_(from), 318 from_(from),
218 fp_to_sp_delta_(fp_to_sp_delta), 319 fp_to_sp_delta_(fp_to_sp_delta),
320 input_(NULL),
219 output_count_(0), 321 output_count_(0),
220 output_(NULL), 322 output_(NULL),
221 deferred_heap_numbers_(0) { 323 deferred_heap_numbers_(0) {
222 if (FLAG_trace_deopt && type != OSR) { 324 if (FLAG_trace_deopt && type != OSR) {
223 PrintF("**** DEOPT: "); 325 if (type == DEBUGGER) {
326 PrintF("**** DEOPT FOR DEBUGGER: ");
327 } else {
328 PrintF("**** DEOPT: ");
329 }
224 function->PrintName(); 330 function->PrintName();
225 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n", 331 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
226 bailout_id, 332 bailout_id,
227 reinterpret_cast<intptr_t>(from), 333 reinterpret_cast<intptr_t>(from),
228 fp_to_sp_delta - (2 * kPointerSize)); 334 fp_to_sp_delta - (2 * kPointerSize));
229 } else if (FLAG_trace_osr && type == OSR) { 335 } else if (FLAG_trace_osr && type == OSR) {
230 PrintF("**** OSR: "); 336 PrintF("**** OSR: ");
231 function->PrintName(); 337 function->PrintName();
232 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n", 338 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
233 bailout_id, 339 bailout_id,
234 reinterpret_cast<intptr_t>(from), 340 reinterpret_cast<intptr_t>(from),
235 fp_to_sp_delta - (2 * kPointerSize)); 341 fp_to_sp_delta - (2 * kPointerSize));
236 } 342 }
237 // Find the optimized code. 343 // Find the optimized code.
238 if (type == EAGER) { 344 if (type == EAGER) {
239 ASSERT(from == NULL); 345 ASSERT(from == NULL);
240 optimized_code_ = function_->code(); 346 optimized_code_ = function_->code();
241 } else if (type == LAZY) { 347 } else if (type == LAZY) {
242 optimized_code_ = FindDeoptimizingCodeFromAddress(from); 348 optimized_code_ = FindDeoptimizingCodeFromAddress(from);
243 ASSERT(optimized_code_ != NULL); 349 ASSERT(optimized_code_ != NULL);
244 } else if (type == OSR) { 350 } else if (type == OSR) {
245 // The function has already been optimized and we're transitioning 351 // The function has already been optimized and we're transitioning
246 // from the unoptimized shared version to the optimized one in the 352 // from the unoptimized shared version to the optimized one in the
247 // function. The return address (from) points to unoptimized code. 353 // function. The return address (from) points to unoptimized code.
248 optimized_code_ = function_->code(); 354 optimized_code_ = function_->code();
249 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION); 355 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
250 ASSERT(!optimized_code_->contains(from)); 356 ASSERT(!optimized_code_->contains(from));
357 } else if (type == DEBUGGER) {
358 optimized_code_ = optimized_code;
359 ASSERT(optimized_code_->contains(from));
251 } 360 }
252 ASSERT(HEAP->allow_allocation(false)); 361 ASSERT(HEAP->allow_allocation(false));
253 unsigned size = ComputeInputFrameSize(); 362 unsigned size = ComputeInputFrameSize();
254 input_ = new(size) FrameDescription(size, function); 363 input_ = new(size) FrameDescription(size, function);
364 #ifdef DEBUG
365 input_->SetKind(Code::OPTIMIZED_FUNCTION);
366 #endif
255 } 367 }
256 368
257 369
258 Deoptimizer::~Deoptimizer() { 370 Deoptimizer::~Deoptimizer() {
259 ASSERT(input_ == NULL && output_ == NULL); 371 ASSERT(input_ == NULL && output_ == NULL);
260 } 372 }
261 373
262 374
263 void Deoptimizer::DeleteFrameDescriptions() { 375 void Deoptimizer::DeleteFrameDescriptions() {
264 delete input_; 376 delete input_;
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 output_[index]->GetPc(), 522 output_[index]->GetPc(),
411 FullCodeGenerator::State2String( 523 FullCodeGenerator::State2String(
412 static_cast<FullCodeGenerator::State>( 524 static_cast<FullCodeGenerator::State>(
413 output_[index]->GetState()->value())), 525 output_[index]->GetState()->value())),
414 ms); 526 ms);
415 } 527 }
416 } 528 }
417 529
418 530
419 void Deoptimizer::MaterializeHeapNumbers() { 531 void Deoptimizer::MaterializeHeapNumbers() {
532 ASSERT_NE(DEBUGGER, bailout_type_);
420 for (int i = 0; i < deferred_heap_numbers_.length(); i++) { 533 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
421 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i]; 534 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
422 Handle<Object> num = isolate_->factory()->NewNumber(d.value()); 535 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
423 if (FLAG_trace_deopt) { 536 if (FLAG_trace_deopt) {
424 PrintF("Materializing a new heap number %p [%e] in slot %p\n", 537 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
425 reinterpret_cast<void*>(*num), 538 reinterpret_cast<void*>(*num),
426 d.value(), 539 d.value(),
427 d.slot_address()); 540 d.slot_address());
428 } 541 }
429 542
430 Memory::Object_at(d.slot_address()) = *num; 543 Memory::Object_at(d.slot_address()) = *num;
431 } 544 }
432 } 545 }
433 546
434 547
548 #ifdef ENABLE_DEBUGGER_SUPPORT
549 void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
550 Address top, intptr_t size, DeoptimizedFrameInfo* info) {
551 ASSERT_EQ(DEBUGGER, bailout_type_);
552 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
553 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
554
555 // Check of the heap number to materialize actually belong to the frame
556 // being extracted.
557 Address slot = d.slot_address();
558 if (top <= slot && slot < top + size) {
559 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
560 int expression_index =
561 info->expression_count_ - (slot - top) / kPointerSize - 1;
562 if (FLAG_trace_deopt) {
563 PrintF("Materializing a new heap number %p [%e] in slot %p"
564 "for expression stack index %d\n",
565 reinterpret_cast<void*>(*num),
566 d.value(),
567 d.slot_address(),
568 expression_index);
569 }
570 info->SetExpression(expression_index, *num);
571 }
572 }
573 }
574 #endif
575
576
435 void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, 577 void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
436 int frame_index, 578 int frame_index,
437 unsigned output_offset) { 579 unsigned output_offset) {
438 disasm::NameConverter converter; 580 disasm::NameConverter converter;
439 // A GC-safe temporary placeholder that we can put in the output frame. 581 // A GC-safe temporary placeholder that we can put in the output frame.
440 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0)); 582 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
441 583
442 // Ignore commands marked as duplicate and act on the first non-duplicate. 584 // Ignore commands marked as duplicate and act on the first non-duplicate.
443 Translation::Opcode opcode = 585 Translation::Opcode opcode =
444 static_cast<Translation::Opcode>(iterator->Next()); 586 static_cast<Translation::Opcode>(iterator->Next());
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after
977 return base - ((slot_index + 1) * kPointerSize); 1119 return base - ((slot_index + 1) * kPointerSize);
978 } else { 1120 } else {
979 // Incoming parameter. 1121 // Incoming parameter.
980 unsigned base = static_cast<unsigned>(GetFrameSize() - 1122 unsigned base = static_cast<unsigned>(GetFrameSize() -
981 deoptimizer->ComputeIncomingArgumentSize(GetFunction())); 1123 deoptimizer->ComputeIncomingArgumentSize(GetFunction()));
982 return base - ((slot_index + 1) * kPointerSize); 1124 return base - ((slot_index + 1) * kPointerSize);
983 } 1125 }
984 } 1126 }
985 1127
986 1128
1129 unsigned FrameDescription::GetExpressionCount(Deoptimizer* deoptimizer) {
1130 ASSERT_EQ(Code::FUNCTION, kind_);
1131 return (GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction()))
1132 / kPointerSize;
1133 }
1134
1135
1136 Object* FrameDescription::GetExpression(Deoptimizer* deoptimizer, int index) {
1137 ASSERT_EQ(Code::FUNCTION, kind_);
1138 unsigned offset = GetOffsetFromSlotIndex(deoptimizer, index);
1139 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1140 }
1141
1142
987 void TranslationBuffer::Add(int32_t value) { 1143 void TranslationBuffer::Add(int32_t value) {
988 // Encode the sign bit in the least significant bit. 1144 // Encode the sign bit in the least significant bit.
989 bool is_negative = (value < 0); 1145 bool is_negative = (value < 0);
990 uint32_t bits = ((is_negative ? -value : value) << 1) | 1146 uint32_t bits = ((is_negative ? -value : value) << 1) |
991 static_cast<int32_t>(is_negative); 1147 static_cast<int32_t>(is_negative);
992 // Encode the individual bytes using the least significant bit of 1148 // Encode the individual bytes using the least significant bit of
993 // each byte to indicate whether or not more bytes follow. 1149 // each byte to indicate whether or not more bytes follow.
994 do { 1150 do {
995 uint32_t next = bits >> 7; 1151 uint32_t next = bits >> 7;
996 contents_.Add(((bits << 1) & 0xFF) | (next != 0)); 1152 contents_.Add(((bits << 1) & 0xFF) | (next != 0));
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
1249 return; 1405 return;
1250 } 1406 }
1251 frames_to_skip--; 1407 frames_to_skip--;
1252 } 1408 }
1253 } 1409 }
1254 1410
1255 UNREACHABLE(); 1411 UNREACHABLE();
1256 } 1412 }
1257 1413
1258 1414
1415 DeoptimizedFrameInfo::DeoptimizedFrameInfo(
1416 Deoptimizer* deoptimizer, int frame_index) {
1417 FrameDescription* output_frame = deoptimizer->output_[frame_index];
1418 expression_count_ = output_frame->GetExpressionCount(deoptimizer);
1419 expression_stack_ = new Object*[expression_count_];
1420 for (int i = 0; i < expression_count_; i++) {
1421 SetExpression(i, output_frame->GetExpression(deoptimizer, i));
1422 }
1423 }
1424
1425
1426 DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
1427 delete expression_stack_;
1428 }
1429
1430 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
1431 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
1432 }
1433
1434
1259 } } // namespace v8::internal 1435 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/deoptimizer.h ('k') | src/frames.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698