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

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: Removed test code 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
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
fschneider 2011/06/29 10:47:35 Maybe put the GC-unsafe part inside an AssertNoAll
Søren Thygesen Gjesse 2011/06/29 12:42:10 The already happens due to the Deoptimizer constru
170 // Allocate a heap number for the doubles belonging to this frame.
171 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
172 top, size, info);
173
fschneider 2011/06/29 10:47:35 Don't you have to de-allocate the deoptimizer? Or
Søren Thygesen Gjesse 2011/06/29 12:42:10 Good catch! Of cause.
174 return info;
175 }
176
177
178 void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
179 Isolate* isolate) {
180 ASSERT(isolate == Isolate::Current());
181 ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info);
182 delete info;
183 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
184 }
185 #endif
89 186
90 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, 187 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
91 int count, 188 int count,
92 BailoutType type) { 189 BailoutType type) {
93 TableEntryGenerator generator(masm, type, count); 190 TableEntryGenerator generator(masm, type, count);
94 generator.Generate(); 191 generator.Generate();
95 } 192 }
96 193
97 194
98 class DeoptimizingVisitor : public OptimizedFunctionVisitor { 195 class DeoptimizingVisitor : public OptimizedFunctionVisitor {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) { 299 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
203 deoptimizer->DoComputeOutputFrames(); 300 deoptimizer->DoComputeOutputFrames();
204 } 301 }
205 302
206 303
207 Deoptimizer::Deoptimizer(Isolate* isolate, 304 Deoptimizer::Deoptimizer(Isolate* isolate,
208 JSFunction* function, 305 JSFunction* function,
209 BailoutType type, 306 BailoutType type,
210 unsigned bailout_id, 307 unsigned bailout_id,
211 Address from, 308 Address from,
212 int fp_to_sp_delta) 309 int fp_to_sp_delta,
310 Code* optimized_code)
213 : isolate_(isolate), 311 : isolate_(isolate),
214 function_(function), 312 function_(function),
215 bailout_id_(bailout_id), 313 bailout_id_(bailout_id),
216 bailout_type_(type), 314 bailout_type_(type),
217 from_(from), 315 from_(from),
218 fp_to_sp_delta_(fp_to_sp_delta), 316 fp_to_sp_delta_(fp_to_sp_delta),
317 input_(NULL),
219 output_count_(0), 318 output_count_(0),
220 output_(NULL), 319 output_(NULL),
221 deferred_heap_numbers_(0) { 320 deferred_heap_numbers_(0) {
222 if (FLAG_trace_deopt && type != OSR) { 321 if (FLAG_trace_deopt && type != OSR) {
223 PrintF("**** DEOPT: "); 322 if (type == DEBUGGER) {
323 PrintF("**** DEOPT FOR DEBUGGER: ");
324 } else {
325 PrintF("**** DEOPT: ");
326 }
224 function->PrintName(); 327 function->PrintName();
225 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n", 328 PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
226 bailout_id, 329 bailout_id,
227 reinterpret_cast<intptr_t>(from), 330 reinterpret_cast<intptr_t>(from),
228 fp_to_sp_delta - (2 * kPointerSize)); 331 fp_to_sp_delta - (2 * kPointerSize));
229 } else if (FLAG_trace_osr && type == OSR) { 332 } else if (FLAG_trace_osr && type == OSR) {
230 PrintF("**** OSR: "); 333 PrintF("**** OSR: ");
231 function->PrintName(); 334 function->PrintName();
232 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n", 335 PrintF(" at ast id #%u, address 0x%" V8PRIxPTR ", frame size %d\n",
233 bailout_id, 336 bailout_id,
234 reinterpret_cast<intptr_t>(from), 337 reinterpret_cast<intptr_t>(from),
235 fp_to_sp_delta - (2 * kPointerSize)); 338 fp_to_sp_delta - (2 * kPointerSize));
236 } 339 }
237 // Find the optimized code. 340 // Find the optimized code.
238 if (type == EAGER) { 341 if (type == EAGER) {
239 ASSERT(from == NULL); 342 ASSERT(from == NULL);
240 optimized_code_ = function_->code(); 343 optimized_code_ = function_->code();
241 } else if (type == LAZY) { 344 } else if (type == LAZY) {
242 optimized_code_ = FindDeoptimizingCodeFromAddress(from); 345 optimized_code_ = FindDeoptimizingCodeFromAddress(from);
243 ASSERT(optimized_code_ != NULL); 346 ASSERT(optimized_code_ != NULL);
244 } else if (type == OSR) { 347 } else if (type == OSR) {
245 // The function has already been optimized and we're transitioning 348 // The function has already been optimized and we're transitioning
246 // from the unoptimized shared version to the optimized one in the 349 // from the unoptimized shared version to the optimized one in the
247 // function. The return address (from) points to unoptimized code. 350 // function. The return address (from) points to unoptimized code.
248 optimized_code_ = function_->code(); 351 optimized_code_ = function_->code();
249 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION); 352 ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION);
250 ASSERT(!optimized_code_->contains(from)); 353 ASSERT(!optimized_code_->contains(from));
354 } else if (type == DEBUGGER) {
355 optimized_code_ = optimized_code;
356 ASSERT(optimized_code_->contains(from));
251 } 357 }
252 ASSERT(HEAP->allow_allocation(false)); 358 ASSERT(HEAP->allow_allocation(false));
253 unsigned size = ComputeInputFrameSize(); 359 unsigned size = ComputeInputFrameSize();
254 input_ = new(size) FrameDescription(size, function); 360 input_ = new(size) FrameDescription(size, function);
361 #ifdef DEBUG
362 input_->SetKind(Code::OPTIMIZED_FUNCTION);
363 #endif
255 } 364 }
256 365
257 366
258 Deoptimizer::~Deoptimizer() { 367 Deoptimizer::~Deoptimizer() {
259 ASSERT(input_ == NULL && output_ == NULL); 368 ASSERT(input_ == NULL && output_ == NULL);
260 } 369 }
261 370
262 371
263 void Deoptimizer::DeleteFrameDescriptions() { 372 void Deoptimizer::DeleteFrameDescriptions() {
264 delete input_; 373 delete input_;
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 output_[index]->GetPc(), 519 output_[index]->GetPc(),
411 FullCodeGenerator::State2String( 520 FullCodeGenerator::State2String(
412 static_cast<FullCodeGenerator::State>( 521 static_cast<FullCodeGenerator::State>(
413 output_[index]->GetState()->value())), 522 output_[index]->GetState()->value())),
414 ms); 523 ms);
415 } 524 }
416 } 525 }
417 526
418 527
419 void Deoptimizer::MaterializeHeapNumbers() { 528 void Deoptimizer::MaterializeHeapNumbers() {
529 ASSERT_NE(DEBUGGER, bailout_type_);
420 for (int i = 0; i < deferred_heap_numbers_.length(); i++) { 530 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
421 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i]; 531 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
422 Handle<Object> num = isolate_->factory()->NewNumber(d.value()); 532 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
423 if (FLAG_trace_deopt) { 533 if (FLAG_trace_deopt) {
424 PrintF("Materializing a new heap number %p [%e] in slot %p\n", 534 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
425 reinterpret_cast<void*>(*num), 535 reinterpret_cast<void*>(*num),
426 d.value(), 536 d.value(),
427 d.slot_address()); 537 d.slot_address());
428 } 538 }
429 539
430 Memory::Object_at(d.slot_address()) = *num; 540 Memory::Object_at(d.slot_address()) = *num;
431 } 541 }
432 } 542 }
433 543
434 544
545 void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
546 Address top, intptr_t size, DeoptimizedFrameInfo* info) {
547 ASSERT_EQ(DEBUGGER, bailout_type_);
548 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
549 HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
550
551 // Check of the heap number to materialize actually belongd to the frame
fschneider 2011/06/29 10:47:35 Check that the heap number to materialize actually
Søren Thygesen Gjesse 2011/06/29 12:42:10 Done.
552 // being extracted.
553 Address slot = d.slot_address();
554 if (top <= slot && slot < top + size) {
555 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
556 if (FLAG_trace_deopt) {
557 PrintF("Materializing a new heap number %p [%e] in slot %p\n",
558 reinterpret_cast<void*>(*num),
559 d.value(),
560 d.slot_address());
561 }
562 int expression_index =
563 info->expression_count_ - (slot - top) / kPointerSize - 1;
564 PrintF("Materializing a new heap number %p [%e] in index %d\n",
fschneider 2011/06/29 10:47:35 Remove duplicate PrintF, maybe add the expression
Søren Thygesen Gjesse 2011/06/29 12:42:10 Done.
565 reinterpret_cast<void*>(*num),
566 d.value(),
567 expression_index);
568 info->SetExpression(expression_index, *num);
569 }
570 }
571 }
572
573
435 void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, 574 void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
436 int frame_index, 575 int frame_index,
437 unsigned output_offset) { 576 unsigned output_offset) {
438 disasm::NameConverter converter; 577 disasm::NameConverter converter;
439 // A GC-safe temporary placeholder that we can put in the output frame. 578 // 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)); 579 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
441 580
442 // Ignore commands marked as duplicate and act on the first non-duplicate. 581 // Ignore commands marked as duplicate and act on the first non-duplicate.
443 Translation::Opcode opcode = 582 Translation::Opcode opcode =
444 static_cast<Translation::Opcode>(iterator->Next()); 583 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); 1116 return base - ((slot_index + 1) * kPointerSize);
978 } else { 1117 } else {
979 // Incoming parameter. 1118 // Incoming parameter.
980 unsigned base = static_cast<unsigned>(GetFrameSize() - 1119 unsigned base = static_cast<unsigned>(GetFrameSize() -
981 deoptimizer->ComputeIncomingArgumentSize(GetFunction())); 1120 deoptimizer->ComputeIncomingArgumentSize(GetFunction()));
982 return base - ((slot_index + 1) * kPointerSize); 1121 return base - ((slot_index + 1) * kPointerSize);
983 } 1122 }
984 } 1123 }
985 1124
986 1125
1126 unsigned FrameDescription::GetExpressionCount(Deoptimizer* deoptimizer) {
1127 ASSERT_EQ(Code::FUNCTION, kind_);
1128 return (GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction()))
1129 / kPointerSize;
1130 }
1131
1132
1133 Object* FrameDescription::GetExpression(Deoptimizer* deoptimizer, int index) {
1134 ASSERT_EQ(Code::FUNCTION, kind_);
1135 unsigned offset = GetOffsetFromSlotIndex(deoptimizer, index);
1136 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
1137 }
1138
1139
987 void TranslationBuffer::Add(int32_t value) { 1140 void TranslationBuffer::Add(int32_t value) {
988 // Encode the sign bit in the least significant bit. 1141 // Encode the sign bit in the least significant bit.
989 bool is_negative = (value < 0); 1142 bool is_negative = (value < 0);
990 uint32_t bits = ((is_negative ? -value : value) << 1) | 1143 uint32_t bits = ((is_negative ? -value : value) << 1) |
991 static_cast<int32_t>(is_negative); 1144 static_cast<int32_t>(is_negative);
992 // Encode the individual bytes using the least significant bit of 1145 // Encode the individual bytes using the least significant bit of
993 // each byte to indicate whether or not more bytes follow. 1146 // each byte to indicate whether or not more bytes follow.
994 do { 1147 do {
995 uint32_t next = bits >> 7; 1148 uint32_t next = bits >> 7;
996 contents_.Add(((bits << 1) & 0xFF) | (next != 0)); 1149 contents_.Add(((bits << 1) & 0xFF) | (next != 0));
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
1249 return; 1402 return;
1250 } 1403 }
1251 frames_to_skip--; 1404 frames_to_skip--;
1252 } 1405 }
1253 } 1406 }
1254 1407
1255 UNREACHABLE(); 1408 UNREACHABLE();
1256 } 1409 }
1257 1410
1258 1411
1412 DeoptimizedFrameInfo::DeoptimizedFrameInfo(
1413 Deoptimizer* deoptimizer, int frame_index) {
1414 FrameDescription* output_frame = deoptimizer->output_[frame_index];
1415 expression_count_ = output_frame->GetExpressionCount(deoptimizer);
1416 expression_stack_ = new Object*[expression_count_];
1417 for (int i = 0; i < expression_count_; i++) {
1418 SetExpression(i, output_frame->GetExpression(deoptimizer, i));
1419 }
1420 }
1421
1422
1423 DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
1424 delete expression_stack_;
1425 }
1426
1427 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
1428 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
1429 }
1430
1431
1259 } } // namespace v8::internal 1432 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698