1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #include "src/accessors.h"
8 #include "src/codegen.h"
9 #include "src/deoptimizer.h"
10 #include "src/disasm.h"
11 #include "src/full-codegen.h"
12 #include "src/global-handles.h"
13 #include "src/macro-assembler.h"
14 #include "src/prettyprinter.h"
15
16
17 namespace v8 {
18 namespace internal {
19
AllocateCodeChunk(MemoryAllocator * allocator)20 static MemoryChunk* AllocateCodeChunk(MemoryAllocator* allocator) {
21 return allocator->AllocateChunk(Deoptimizer::GetMaxDeoptTableSize(),
22 base::OS::CommitPageSize(),
23 #if defined(__native_client__)
24 // The Native Client port of V8 uses an interpreter,
25 // so code pages don't need PROT_EXEC.
26 NOT_EXECUTABLE,
27 #else
28 EXECUTABLE,
29 #endif
30 NULL);
31 }
32
33
DeoptimizerData(MemoryAllocator * allocator)34 DeoptimizerData::DeoptimizerData(MemoryAllocator* allocator)
35 : allocator_(allocator),
36 deoptimized_frame_info_(NULL),
37 current_(NULL) {
38 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
39 deopt_entry_code_entries_[i] = -1;
40 deopt_entry_code_[i] = AllocateCodeChunk(allocator);
41 }
42 }
43
44
~DeoptimizerData()45 DeoptimizerData::~DeoptimizerData() {
46 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
47 allocator_->Free(deopt_entry_code_[i]);
48 deopt_entry_code_[i] = NULL;
49 }
50 }
51
52
Iterate(ObjectVisitor * v)53 void DeoptimizerData::Iterate(ObjectVisitor* v) {
54 if (deoptimized_frame_info_ != NULL) {
55 deoptimized_frame_info_->Iterate(v);
56 }
57 }
58
59
FindDeoptimizingCode(Address addr)60 Code* Deoptimizer::FindDeoptimizingCode(Address addr) {
61 if (function_->IsHeapObject()) {
62 // Search all deoptimizing code in the native context of the function.
63 Context* native_context = function_->context()->native_context();
64 Object* element = native_context->DeoptimizedCodeListHead();
65 while (!element->IsUndefined()) {
66 Code* code = Code::cast(element);
67 CHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
68 if (code->contains(addr)) return code;
69 element = code->next_code_link();
70 }
71 }
72 return NULL;
73 }
74
75
76 // We rely on this function not causing a GC. It is called from generated code
77 // without having a real stack frame in place.
New(JSFunction * function,BailoutType type,unsigned bailout_id,Address from,int fp_to_sp_delta,Isolate * isolate)78 Deoptimizer* Deoptimizer::New(JSFunction* function,
79 BailoutType type,
80 unsigned bailout_id,
81 Address from,
82 int fp_to_sp_delta,
83 Isolate* isolate) {
84 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
85 function,
86 type,
87 bailout_id,
88 from,
89 fp_to_sp_delta,
90 NULL);
91 CHECK(isolate->deoptimizer_data()->current_ == NULL);
92 isolate->deoptimizer_data()->current_ = deoptimizer;
93 return deoptimizer;
94 }
95
96
97 // No larger than 2K on all platforms
98 static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB;
99
100
GetMaxDeoptTableSize()101 size_t Deoptimizer::GetMaxDeoptTableSize() {
102 int entries_size =
103 Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_;
104 int commit_page_size = static_cast<int>(base::OS::CommitPageSize());
105 int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) /
106 commit_page_size) + 1;
107 return static_cast<size_t>(commit_page_size * page_count);
108 }
109
110
Grab(Isolate * isolate)111 Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
112 Deoptimizer* result = isolate->deoptimizer_data()->current_;
113 CHECK_NE(result, NULL);
114 result->DeleteFrameDescriptions();
115 isolate->deoptimizer_data()->current_ = NULL;
116 return result;
117 }
118
119
ConvertJSFrameIndexToFrameIndex(int jsframe_index)120 int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) {
121 if (jsframe_index == 0) return 0;
122
123 int frame_index = 0;
124 while (jsframe_index >= 0) {
125 FrameDescription* frame = output_[frame_index];
126 if (frame->GetFrameType() == StackFrame::JAVA_SCRIPT) {
127 jsframe_index--;
128 }
129 frame_index++;
130 }
131
132 return frame_index - 1;
133 }
134
135
DebuggerInspectableFrame(JavaScriptFrame * frame,int jsframe_index,Isolate * isolate)136 DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
137 JavaScriptFrame* frame,
138 int jsframe_index,
139 Isolate* isolate) {
140 CHECK(frame->is_optimized());
141 CHECK(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
142
143 // Get the function and code from the frame.
144 JSFunction* function = frame->function();
145 Code* code = frame->LookupCode();
146
147 // Locate the deoptimization point in the code. As we are at a call the
148 // return address must be at a place in the code with deoptimization support.
149 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
150 int deoptimization_index = safepoint_entry.deoptimization_index();
151 CHECK_NE(deoptimization_index, Safepoint::kNoDeoptimizationIndex);
152
153 // Always use the actual stack slots when calculating the fp to sp
154 // delta adding two for the function and context.
155 unsigned stack_slots = code->stack_slots();
156 unsigned fp_to_sp_delta = (stack_slots * kPointerSize) +
157 StandardFrameConstants::kFixedFrameSizeFromFp;
158
159 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
160 function,
161 Deoptimizer::DEBUGGER,
162 deoptimization_index,
163 frame->pc(),
164 fp_to_sp_delta,
165 code);
166 Address tos = frame->fp() - fp_to_sp_delta;
167 deoptimizer->FillInputFrame(tos, frame);
168
169 // Calculate the output frames.
170 Deoptimizer::ComputeOutputFrames(deoptimizer);
171
172 // Create the GC safe output frame information and register it for GC
173 // handling.
174 CHECK_LT(jsframe_index, deoptimizer->jsframe_count());
175
176 // Convert JS frame index into frame index.
177 int frame_index = deoptimizer->ConvertJSFrameIndexToFrameIndex(jsframe_index);
178
179 bool has_arguments_adaptor =
180 frame_index > 0 &&
181 deoptimizer->output_[frame_index - 1]->GetFrameType() ==
182 StackFrame::ARGUMENTS_ADAPTOR;
183
184 int construct_offset = has_arguments_adaptor ? 2 : 1;
185 bool has_construct_stub =
186 frame_index >= construct_offset &&
187 deoptimizer->output_[frame_index - construct_offset]->GetFrameType() ==
188 StackFrame::CONSTRUCT;
189
190 DeoptimizedFrameInfo* info = new DeoptimizedFrameInfo(deoptimizer,
191 frame_index,
192 has_arguments_adaptor,
193 has_construct_stub);
194 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
195
196 // Get the "simulated" top and size for the requested frame.
197 FrameDescription* parameters_frame =
198 deoptimizer->output_[
199 has_arguments_adaptor ? (frame_index - 1) : frame_index];
200
201 uint32_t parameters_size = (info->parameters_count() + 1) * kPointerSize;
202 Address parameters_top = reinterpret_cast<Address>(
203 parameters_frame->GetTop() + (parameters_frame->GetFrameSize() -
204 parameters_size));
205
206 uint32_t expressions_size = info->expression_count() * kPointerSize;
207 Address expressions_top = reinterpret_cast<Address>(
208 deoptimizer->output_[frame_index]->GetTop());
209
210 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
211 deoptimizer->DeleteFrameDescriptions();
212
213 // Allocate a heap number for the doubles belonging to this frame.
214 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
215 parameters_top, parameters_size, expressions_top, expressions_size, info);
216
217 // Finished using the deoptimizer instance.
218 delete deoptimizer;
219
220 return info;
221 }
222
223
DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo * info,Isolate * isolate)224 void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
225 Isolate* isolate) {
226 CHECK_EQ(isolate->deoptimizer_data()->deoptimized_frame_info_, info);
227 delete info;
228 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
229 }
230
231
GenerateDeoptimizationEntries(MacroAssembler * masm,int count,BailoutType type)232 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
233 int count,
234 BailoutType type) {
235 TableEntryGenerator generator(masm, type, count);
236 generator.Generate();
237 }
238
239
VisitAllOptimizedFunctionsForContext(Context * context,OptimizedFunctionVisitor * visitor)240 void Deoptimizer::VisitAllOptimizedFunctionsForContext(
241 Context* context, OptimizedFunctionVisitor* visitor) {
242 DisallowHeapAllocation no_allocation;
243
244 CHECK(context->IsNativeContext());
245
246 visitor->EnterContext(context);
247
248 // Visit the list of optimized functions, removing elements that
249 // no longer refer to optimized code.
250 JSFunction* prev = NULL;
251 Object* element = context->OptimizedFunctionsListHead();
252 while (!element->IsUndefined()) {
253 JSFunction* function = JSFunction::cast(element);
254 Object* next = function->next_function_link();
255 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION ||
256 (visitor->VisitFunction(function),
257 function->code()->kind() != Code::OPTIMIZED_FUNCTION)) {
258 // The function no longer refers to optimized code, or the visitor
259 // changed the code to which it refers to no longer be optimized code.
260 // Remove the function from this list.
261 if (prev != NULL) {
262 prev->set_next_function_link(next);
263 } else {
264 context->SetOptimizedFunctionsListHead(next);
265 }
266 // The visitor should not alter the link directly.
267 CHECK_EQ(function->next_function_link(), next);
268 // Set the next function link to undefined to indicate it is no longer
269 // in the optimized functions list.
270 function->set_next_function_link(context->GetHeap()->undefined_value());
271 } else {
272 // The visitor should not alter the link directly.
273 CHECK_EQ(function->next_function_link(), next);
274 // preserve this element.
275 prev = function;
276 }
277 element = next;
278 }
279
280 visitor->LeaveContext(context);
281 }
282
283
VisitAllOptimizedFunctions(Isolate * isolate,OptimizedFunctionVisitor * visitor)284 void Deoptimizer::VisitAllOptimizedFunctions(
285 Isolate* isolate,
286 OptimizedFunctionVisitor* visitor) {
287 DisallowHeapAllocation no_allocation;
288
289 // Run through the list of all native contexts.
290 Object* context = isolate->heap()->native_contexts_list();
291 while (!context->IsUndefined()) {
292 VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor);
293 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
294 }
295 }
296
297
298 // Unlink functions referring to code marked for deoptimization, then move
299 // marked code from the optimized code list to the deoptimized code list,
300 // and patch code for lazy deopt.
DeoptimizeMarkedCodeForContext(Context * context)301 void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
302 DisallowHeapAllocation no_allocation;
303
304 // A "closure" that unlinks optimized code that is going to be
305 // deoptimized from the functions that refer to it.
306 class SelectedCodeUnlinker: public OptimizedFunctionVisitor {
307 public:
308 virtual void EnterContext(Context* context) { } // Don't care.
309 virtual void LeaveContext(Context* context) { } // Don't care.
310 virtual void VisitFunction(JSFunction* function) {
311 Code* code = function->code();
312 if (!code->marked_for_deoptimization()) return;
313
314 // Unlink this function and evict from optimized code map.
315 SharedFunctionInfo* shared = function->shared();
316 function->set_code(shared->code());
317
318 if (FLAG_trace_deopt) {
319 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
320 PrintF(scope.file(), "[deoptimizer unlinked: ");
321 function->PrintName(scope.file());
322 PrintF(scope.file(),
323 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
324 }
325 }
326 };
327
328 // Unlink all functions that refer to marked code.
329 SelectedCodeUnlinker unlinker;
330 VisitAllOptimizedFunctionsForContext(context, &unlinker);
331
332 Isolate* isolate = context->GetHeap()->isolate();
333 #ifdef DEBUG
334 Code* topmost_optimized_code = NULL;
335 bool safe_to_deopt_topmost_optimized_code = false;
336 // Make sure all activations of optimized code can deopt at their current PC.
337 // The topmost optimized code has special handling because it cannot be
338 // deoptimized due to weak object dependency.
339 for (StackFrameIterator it(isolate, isolate->thread_local_top());
340 !it.done(); it.Advance()) {
341 StackFrame::Type type = it.frame()->type();
342 if (type == StackFrame::OPTIMIZED) {
343 Code* code = it.frame()->LookupCode();
344 if (FLAG_trace_deopt) {
345 JSFunction* function =
346 static_cast<OptimizedFrame*>(it.frame())->function();
347 CodeTracer::Scope scope(isolate->GetCodeTracer());
348 PrintF(scope.file(), "[deoptimizer found activation of function: ");
349 function->PrintName(scope.file());
350 PrintF(scope.file(),
351 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
352 }
353 SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc());
354 int deopt_index = safepoint.deoptimization_index();
355 // Turbofan deopt is checked when we are patching addresses on stack.
356 bool turbofanned = code->is_turbofanned() && !FLAG_turbo_deoptimization;
357 bool safe_to_deopt =
358 deopt_index != Safepoint::kNoDeoptimizationIndex || turbofanned;
359 CHECK(topmost_optimized_code == NULL || safe_to_deopt || turbofanned);
360 if (topmost_optimized_code == NULL) {
361 topmost_optimized_code = code;
362 safe_to_deopt_topmost_optimized_code = safe_to_deopt;
363 }
364 }
365 }
366 #endif
367
368 // Move marked code from the optimized code list to the deoptimized
369 // code list, collecting them into a ZoneList.
370 Zone zone(isolate);
371 ZoneList<Code*> codes(10, &zone);
372
373 // Walk over all optimized code objects in this native context.
374 Code* prev = NULL;
375 Object* element = context->OptimizedCodeListHead();
376 while (!element->IsUndefined()) {
377 Code* code = Code::cast(element);
378 CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
379 Object* next = code->next_code_link();
380
381 if (code->marked_for_deoptimization() &&
382 (!code->is_turbofanned() || FLAG_turbo_deoptimization)) {
383 // Put the code into the list for later patching.
384 codes.Add(code, &zone);
385
386 if (prev != NULL) {
387 // Skip this code in the optimized code list.
388 prev->set_next_code_link(next);
389 } else {
390 // There was no previous node, the next node is the new head.
391 context->SetOptimizedCodeListHead(next);
392 }
393
394 // Move the code to the _deoptimized_ code list.
395 code->set_next_code_link(context->DeoptimizedCodeListHead());
396 context->SetDeoptimizedCodeListHead(code);
397 } else {
398 // Not marked; preserve this element.
399 prev = code;
400 }
401 element = next;
402 }
403
404 // TODO(titzer): we need a handle scope only because of the macro assembler,
405 // which is only used in EnsureCodeForDeoptimizationEntry.
406 HandleScope scope(isolate);
407
408 // Now patch all the codes for deoptimization.
409 for (int i = 0; i < codes.length(); i++) {
410 #ifdef DEBUG
411 if (codes[i] == topmost_optimized_code) {
412 DCHECK(safe_to_deopt_topmost_optimized_code);
413 }
414 #endif
415 // It is finally time to die, code object.
416
417 // Remove the code from optimized code map.
418 DeoptimizationInputData* deopt_data =
419 DeoptimizationInputData::cast(codes[i]->deoptimization_data());
420 SharedFunctionInfo* shared =
421 SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
422 shared->EvictFromOptimizedCodeMap(codes[i], "deoptimized code");
423
424 // Do platform-specific patching to force any activations to lazy deopt.
425 if (!codes[i]->is_turbofanned() || FLAG_turbo_deoptimization) {
426 PatchCodeForDeoptimization(isolate, codes[i]);
427
428 // We might be in the middle of incremental marking with compaction.
429 // Tell collector to treat this code object in a special way and
430 // ignore all slots that might have been recorded on it.
431 isolate->heap()->mark_compact_collector()->InvalidateCode(codes[i]);
432 }
433 }
434 }
435
436
DeoptimizeAll(Isolate * isolate)437 void Deoptimizer::DeoptimizeAll(Isolate* isolate) {
438 if (FLAG_trace_deopt) {
439 CodeTracer::Scope scope(isolate->GetCodeTracer());
440 PrintF(scope.file(), "[deoptimize all code in all contexts]\n");
441 }
442 DisallowHeapAllocation no_allocation;
443 // For all contexts, mark all code, then deoptimize.
444 Object* context = isolate->heap()->native_contexts_list();
445 while (!context->IsUndefined()) {
446 Context* native_context = Context::cast(context);
447 MarkAllCodeForContext(native_context);
448 DeoptimizeMarkedCodeForContext(native_context);
449 context = native_context->get(Context::NEXT_CONTEXT_LINK);
450 }
451 }
452
453
DeoptimizeMarkedCode(Isolate * isolate)454 void Deoptimizer::DeoptimizeMarkedCode(Isolate* isolate) {
455 if (FLAG_trace_deopt) {
456 CodeTracer::Scope scope(isolate->GetCodeTracer());
457 PrintF(scope.file(), "[deoptimize marked code in all contexts]\n");
458 }
459 DisallowHeapAllocation no_allocation;
460 // For all contexts, deoptimize code already marked.
461 Object* context = isolate->heap()->native_contexts_list();
462 while (!context->IsUndefined()) {
463 Context* native_context = Context::cast(context);
464 DeoptimizeMarkedCodeForContext(native_context);
465 context = native_context->get(Context::NEXT_CONTEXT_LINK);
466 }
467 }
468
469
DeoptimizeGlobalObject(JSObject * object)470 void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) {
471 if (FLAG_trace_deopt) {
472 CodeTracer::Scope scope(object->GetHeap()->isolate()->GetCodeTracer());
473 PrintF(scope.file(), "[deoptimize global object @ 0x%08" V8PRIxPTR "]\n",
474 reinterpret_cast<intptr_t>(object));
475 }
476 if (object->IsJSGlobalProxy()) {
477 PrototypeIterator iter(object->GetIsolate(), object);
478 // TODO(verwaest): This CHECK will be hit if the global proxy is detached.
479 CHECK(iter.GetCurrent()->IsJSGlobalObject());
480 Context* native_context =
481 GlobalObject::cast(iter.GetCurrent())->native_context();
482 MarkAllCodeForContext(native_context);
483 DeoptimizeMarkedCodeForContext(native_context);
484 } else if (object->IsGlobalObject()) {
485 Context* native_context = GlobalObject::cast(object)->native_context();
486 MarkAllCodeForContext(native_context);
487 DeoptimizeMarkedCodeForContext(native_context);
488 }
489 }
490
491
MarkAllCodeForContext(Context * context)492 void Deoptimizer::MarkAllCodeForContext(Context* context) {
493 Object* element = context->OptimizedCodeListHead();
494 while (!element->IsUndefined()) {
495 Code* code = Code::cast(element);
496 CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
497 code->set_marked_for_deoptimization(true);
498 element = code->next_code_link();
499 }
500 }
501
502
DeoptimizeFunction(JSFunction * function)503 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
504 Code* code = function->code();
505 if (code->kind() == Code::OPTIMIZED_FUNCTION) {
506 // Mark the code for deoptimization and unlink any functions that also
507 // refer to that code. The code cannot be shared across native contexts,
508 // so we only need to search one.
509 code->set_marked_for_deoptimization(true);
510 DeoptimizeMarkedCodeForContext(function->context()->native_context());
511 }
512 }
513
514
ComputeOutputFrames(Deoptimizer * deoptimizer)515 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
516 deoptimizer->DoComputeOutputFrames();
517 }
518
519
TraceEnabledFor(BailoutType deopt_type,StackFrame::Type frame_type)520 bool Deoptimizer::TraceEnabledFor(BailoutType deopt_type,
521 StackFrame::Type frame_type) {
522 switch (deopt_type) {
523 case EAGER:
524 case SOFT:
525 case LAZY:
526 case DEBUGGER:
527 return (frame_type == StackFrame::STUB)
528 ? FLAG_trace_stub_failures
529 : FLAG_trace_deopt;
530 }
531 FATAL("Unsupported deopt type");
532 return false;
533 }
534
535
MessageFor(BailoutType type)536 const char* Deoptimizer::MessageFor(BailoutType type) {
537 switch (type) {
538 case EAGER: return "eager";
539 case SOFT: return "soft";
540 case LAZY: return "lazy";
541 case DEBUGGER: return "debugger";
542 }
543 FATAL("Unsupported deopt type");
544 return NULL;
545 }
546
547
Deoptimizer(Isolate * isolate,JSFunction * function,BailoutType type,unsigned bailout_id,Address from,int fp_to_sp_delta,Code * optimized_code)548 Deoptimizer::Deoptimizer(Isolate* isolate,
549 JSFunction* function,
550 BailoutType type,
551 unsigned bailout_id,
552 Address from,
553 int fp_to_sp_delta,
554 Code* optimized_code)
555 : isolate_(isolate),
556 function_(function),
557 bailout_id_(bailout_id),
558 bailout_type_(type),
559 from_(from),
560 fp_to_sp_delta_(fp_to_sp_delta),
561 has_alignment_padding_(0),
562 input_(NULL),
563 output_count_(0),
564 jsframe_count_(0),
565 output_(NULL),
566 deferred_objects_tagged_values_(0),
567 deferred_objects_double_values_(0),
568 deferred_objects_(0),
569 deferred_heap_numbers_(0),
570 jsframe_functions_(0),
571 jsframe_has_adapted_arguments_(0),
572 materialized_values_(NULL),
573 materialized_objects_(NULL),
574 materialization_value_index_(0),
575 materialization_object_index_(0),
576 trace_scope_(NULL) {
577 // For COMPILED_STUBs called from builtins, the function pointer is a SMI
578 // indicating an internal frame.
579 if (function->IsSmi()) {
580 function = NULL;
581 }
582 DCHECK(from != NULL);
583 if (function != NULL && function->IsOptimized()) {
584 function->shared()->increment_deopt_count();
585 if (bailout_type_ == Deoptimizer::SOFT) {
586 isolate->counters()->soft_deopts_executed()->Increment();
587 // Soft deopts shouldn't count against the overall re-optimization count
588 // that can eventually lead to disabling optimization for a function.
589 int opt_count = function->shared()->opt_count();
590 if (opt_count > 0) opt_count--;
591 function->shared()->set_opt_count(opt_count);
592 }
593 }
594 compiled_code_ = FindOptimizedCode(function, optimized_code);
595
596 #if DEBUG
597 DCHECK(compiled_code_ != NULL);
598 if (type == EAGER || type == SOFT || type == LAZY) {
599 DCHECK(compiled_code_->kind() != Code::FUNCTION);
600 }
601 #endif
602
603 StackFrame::Type frame_type = function == NULL
604 ? StackFrame::STUB
605 : StackFrame::JAVA_SCRIPT;
606 trace_scope_ = TraceEnabledFor(type, frame_type) ?
607 new CodeTracer::Scope(isolate->GetCodeTracer()) : NULL;
608 #ifdef DEBUG
609 CHECK(AllowHeapAllocation::IsAllowed());
610 disallow_heap_allocation_ = new DisallowHeapAllocation();
611 #endif // DEBUG
612 unsigned size = ComputeInputFrameSize();
613 input_ = new(size) FrameDescription(size, function);
614 input_->SetFrameType(frame_type);
615 }
616
617
FindOptimizedCode(JSFunction * function,Code * optimized_code)618 Code* Deoptimizer::FindOptimizedCode(JSFunction* function,
619 Code* optimized_code) {
620 switch (bailout_type_) {
621 case Deoptimizer::SOFT:
622 case Deoptimizer::EAGER:
623 case Deoptimizer::LAZY: {
624 Code* compiled_code = FindDeoptimizingCode(from_);
625 return (compiled_code == NULL)
626 ? static_cast<Code*>(isolate_->FindCodeObject(from_))
627 : compiled_code;
628 }
629 case Deoptimizer::DEBUGGER:
630 DCHECK(optimized_code->contains(from_));
631 return optimized_code;
632 }
633 FATAL("Could not find code for optimized function");
634 return NULL;
635 }
636
637
PrintFunctionName()638 void Deoptimizer::PrintFunctionName() {
639 if (function_->IsJSFunction()) {
640 function_->PrintName(trace_scope_->file());
641 } else {
642 PrintF(trace_scope_->file(),
643 "%s", Code::Kind2String(compiled_code_->kind()));
644 }
645 }
646
647
~Deoptimizer()648 Deoptimizer::~Deoptimizer() {
649 DCHECK(input_ == NULL && output_ == NULL);
650 DCHECK(disallow_heap_allocation_ == NULL);
651 delete trace_scope_;
652 }
653
654
DeleteFrameDescriptions()655 void Deoptimizer::DeleteFrameDescriptions() {
656 delete input_;
657 for (int i = 0; i < output_count_; ++i) {
658 if (output_[i] != input_) delete output_[i];
659 }
660 delete[] output_;
661 input_ = NULL;
662 output_ = NULL;
663 #ifdef DEBUG
664 CHECK(!AllowHeapAllocation::IsAllowed());
665 CHECK(disallow_heap_allocation_ != NULL);
666 delete disallow_heap_allocation_;
667 disallow_heap_allocation_ = NULL;
668 #endif // DEBUG
669 }
670
671
GetDeoptimizationEntry(Isolate * isolate,int id,BailoutType type,GetEntryMode mode)672 Address Deoptimizer::GetDeoptimizationEntry(Isolate* isolate,
673 int id,
674 BailoutType type,
675 GetEntryMode mode) {
676 CHECK_GE(id, 0);
677 if (id >= kMaxNumberOfEntries) return NULL;
678 if (mode == ENSURE_ENTRY_CODE) {
679 EnsureCodeForDeoptimizationEntry(isolate, type, id);
680 } else {
681 CHECK_EQ(mode, CALCULATE_ENTRY_ADDRESS);
682 }
683 DeoptimizerData* data = isolate->deoptimizer_data();
684 CHECK_LT(type, kBailoutTypesWithCodeEntry);
685 MemoryChunk* base = data->deopt_entry_code_[type];
686 return base->area_start() + (id * table_entry_size_);
687 }
688
689
GetDeoptimizationId(Isolate * isolate,Address addr,BailoutType type)690 int Deoptimizer::GetDeoptimizationId(Isolate* isolate,
691 Address addr,
692 BailoutType type) {
693 DeoptimizerData* data = isolate->deoptimizer_data();
694 MemoryChunk* base = data->deopt_entry_code_[type];
695 Address start = base->area_start();
696 if (base == NULL ||
697 addr < start ||
698 addr >= start + (kMaxNumberOfEntries * table_entry_size_)) {
699 return kNotDeoptimizationEntry;
700 }
701 DCHECK_EQ(0,
702 static_cast<int>(addr - start) % table_entry_size_);
703 return static_cast<int>(addr - start) / table_entry_size_;
704 }
705
706
GetOutputInfo(DeoptimizationOutputData * data,BailoutId id,SharedFunctionInfo * shared)707 int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
708 BailoutId id,
709 SharedFunctionInfo* shared) {
710 // TODO(kasperl): For now, we do a simple linear search for the PC
711 // offset associated with the given node id. This should probably be
712 // changed to a binary search.
713 int length = data->DeoptPoints();
714 for (int i = 0; i < length; i++) {
715 if (data->AstId(i) == id) {
716 return data->PcAndState(i)->value();
717 }
718 }
719 OFStream os(stderr);
720 os << "[couldn't find pc offset for node=" << id.ToInt() << "]\n"
721 << "[method: " << shared->DebugName()->ToCString().get() << "]\n"
722 << "[source:\n" << SourceCodeOf(shared) << "\n]" << endl;
723
724 FATAL("unable to find pc offset during deoptimization");
725 return -1;
726 }
727
728
GetDeoptimizedCodeCount(Isolate * isolate)729 int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
730 int length = 0;
731 // Count all entries in the deoptimizing code list of every context.
732 Object* context = isolate->heap()->native_contexts_list();
733 while (!context->IsUndefined()) {
734 Context* native_context = Context::cast(context);
735 Object* element = native_context->DeoptimizedCodeListHead();
736 while (!element->IsUndefined()) {
737 Code* code = Code::cast(element);
738 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
739 length++;
740 element = code->next_code_link();
741 }
742 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
743 }
744 return length;
745 }
746
747
748 // We rely on this function not causing a GC. It is called from generated code
749 // without having a real stack frame in place.
DoComputeOutputFrames()750 void Deoptimizer::DoComputeOutputFrames() {
751 // Print some helpful diagnostic information.
752 if (FLAG_log_timer_events &&
753 compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
754 LOG(isolate(), CodeDeoptEvent(compiled_code_));
755 }
756 base::ElapsedTimer timer;
757
758 // Determine basic deoptimization information. The optimized frame is
759 // described by the input data.
760 DeoptimizationInputData* input_data =
761 DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
762
763 if (trace_scope_ != NULL) {
764 timer.Start();
765 PrintF(trace_scope_->file(),
766 "[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
767 MessageFor(bailout_type_),
768 reinterpret_cast<intptr_t>(function_));
769 PrintFunctionName();
770 PrintF(trace_scope_->file(),
771 " (opt #%d) @%d, FP to SP delta: %d]\n",
772 input_data->OptimizationId()->value(),
773 bailout_id_,
774 fp_to_sp_delta_);
775 if (bailout_type_ == EAGER || bailout_type_ == SOFT ||
776 (compiled_code_->is_hydrogen_stub())) {
777 compiled_code_->PrintDeoptLocation(trace_scope_->file(), bailout_id_);
778 }
779 }
780
781 BailoutId node_id = input_data->AstId(bailout_id_);
782 ByteArray* translations = input_data->TranslationByteArray();
783 unsigned translation_index =
784 input_data->TranslationIndex(bailout_id_)->value();
785
786 // Do the input frame to output frame(s) translation.
787 TranslationIterator iterator(translations, translation_index);
788 Translation::Opcode opcode =
789 static_cast<Translation::Opcode>(iterator.Next());
790 DCHECK(Translation::BEGIN == opcode);
791 USE(opcode);
792 // Read the number of output frames and allocate an array for their
793 // descriptions.
794 int count = iterator.Next();
795 iterator.Next(); // Drop JS frames count.
796 DCHECK(output_ == NULL);
797 output_ = new FrameDescription*[count];
798 for (int i = 0; i < count; ++i) {
799 output_[i] = NULL;
800 }
801 output_count_ = count;
802
803 Register fp_reg = JavaScriptFrame::fp_register();
804 stack_fp_ = reinterpret_cast<Address>(
805 input_->GetRegister(fp_reg.code()) +
806 has_alignment_padding_ * kPointerSize);
807
808 // Translate each output frame.
809 for (int i = 0; i < count; ++i) {
810 // Read the ast node id, function, and frame height for this output frame.
811 Translation::Opcode opcode =
812 static_cast<Translation::Opcode>(iterator.Next());
813 switch (opcode) {
814 case Translation::JS_FRAME:
815 DoComputeJSFrame(&iterator, i);
816 jsframe_count_++;
817 break;
818 case Translation::ARGUMENTS_ADAPTOR_FRAME:
819 DoComputeArgumentsAdaptorFrame(&iterator, i);
820 break;
821 case Translation::CONSTRUCT_STUB_FRAME:
822 DoComputeConstructStubFrame(&iterator, i);
823 break;
824 case Translation::GETTER_STUB_FRAME:
825 DoComputeAccessorStubFrame(&iterator, i, false);
826 break;
827 case Translation::SETTER_STUB_FRAME:
828 DoComputeAccessorStubFrame(&iterator, i, true);
829 break;
830 case Translation::COMPILED_STUB_FRAME:
831 DoComputeCompiledStubFrame(&iterator, i);
832 break;
833 case Translation::BEGIN:
834 case Translation::REGISTER:
835 case Translation::INT32_REGISTER:
836 case Translation::UINT32_REGISTER:
837 case Translation::DOUBLE_REGISTER:
838 case Translation::STACK_SLOT:
839 case Translation::INT32_STACK_SLOT:
840 case Translation::UINT32_STACK_SLOT:
841 case Translation::DOUBLE_STACK_SLOT:
842 case Translation::LITERAL:
843 case Translation::ARGUMENTS_OBJECT:
844 default:
845 FATAL("Unsupported translation");
846 break;
847 }
848 }
849
850 // Print some helpful diagnostic information.
851 if (trace_scope_ != NULL) {
852 double ms = timer.Elapsed().InMillisecondsF();
853 int index = output_count_ - 1; // Index of the topmost frame.
854 JSFunction* function = output_[index]->GetFunction();
855 PrintF(trace_scope_->file(),
856 "[deoptimizing (%s): end 0x%08" V8PRIxPTR " ",
857 MessageFor(bailout_type_),
858 reinterpret_cast<intptr_t>(function));
859 PrintFunctionName();
860 PrintF(trace_scope_->file(),
861 " @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
862 " took %0.3f ms]\n",
863 bailout_id_,
864 node_id.ToInt(),
865 output_[index]->GetPc(),
866 FullCodeGenerator::State2String(
867 static_cast<FullCodeGenerator::State>(
868 output_[index]->GetState()->value())),
869 has_alignment_padding_ ? "with padding" : "no padding",
870 ms);
871 }
872 }
873
874
DoComputeJSFrame(TranslationIterator * iterator,int frame_index)875 void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
876 int frame_index) {
877 BailoutId node_id = BailoutId(iterator->Next());
878 JSFunction* function;
879 if (frame_index != 0) {
880 function = JSFunction::cast(ComputeLiteral(iterator->Next()));
881 } else {
882 int closure_id = iterator->Next();
883 USE(closure_id);
884 CHECK_EQ(Translation::kSelfLiteralId, closure_id);
885 function = function_;
886 }
887 unsigned height = iterator->Next() - 1; // Do not count the context.
888 unsigned height_in_bytes = height * kPointerSize;
889 if (trace_scope_ != NULL) {
890 PrintF(trace_scope_->file(), " translating ");
891 function->PrintName(trace_scope_->file());
892 PrintF(trace_scope_->file(),
893 " => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
894 }
895
896 // The 'fixed' part of the frame consists of the incoming parameters and
897 // the part described by JavaScriptFrameConstants.
898 unsigned fixed_frame_size = ComputeFixedSize(function);
899 unsigned input_frame_size = input_->GetFrameSize();
900 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
901
902 // Allocate and store the output frame description.
903 FrameDescription* output_frame =
904 new(output_frame_size) FrameDescription(output_frame_size, function);
905 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
906
907 bool is_bottommost = (0 == frame_index);
908 bool is_topmost = (output_count_ - 1 == frame_index);
909 CHECK(frame_index >= 0 && frame_index < output_count_);
910 CHECK_EQ(output_[frame_index], NULL);
911 output_[frame_index] = output_frame;
912
913 // The top address for the bottommost output frame can be computed from
914 // the input frame pointer and the output frame's height. For all
915 // subsequent output frames, it can be computed from the previous one's
916 // top address and the current frame's size.
917 Register fp_reg = JavaScriptFrame::fp_register();
918 intptr_t top_address;
919 if (is_bottommost) {
920 // Determine whether the input frame contains alignment padding.
921 has_alignment_padding_ =
922 (!compiled_code_->is_turbofanned() && HasAlignmentPadding(function))
923 ? 1
924 : 0;
925 // 2 = context and function in the frame.
926 // If the optimized frame had alignment padding, adjust the frame pointer
927 // to point to the new position of the old frame pointer after padding
928 // is removed. Subtract 2 * kPointerSize for the context and function slots.
929 top_address = input_->GetRegister(fp_reg.code()) -
930 StandardFrameConstants::kFixedFrameSizeFromFp -
931 height_in_bytes + has_alignment_padding_ * kPointerSize;
932 } else {
933 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
934 }
935 output_frame->SetTop(top_address);
936
937 // Compute the incoming parameter translation.
938 int parameter_count = function->shared()->formal_parameter_count() + 1;
939 unsigned output_offset = output_frame_size;
940 unsigned input_offset = input_frame_size;
941 for (int i = 0; i < parameter_count; ++i) {
942 output_offset -= kPointerSize;
943 DoTranslateCommand(iterator, frame_index, output_offset);
944 }
945 input_offset -= (parameter_count * kPointerSize);
946
947 // There are no translation commands for the caller's pc and fp, the
948 // context, and the function. Synthesize their values and set them up
949 // explicitly.
950 //
951 // The caller's pc for the bottommost output frame is the same as in the
952 // input frame. For all subsequent output frames, it can be read from the
953 // previous one. This frame's pc can be computed from the non-optimized
954 // function code and AST id of the bailout.
955 output_offset -= kPCOnStackSize;
956 input_offset -= kPCOnStackSize;
957 intptr_t value;
958 if (is_bottommost) {
959 value = input_->GetFrameSlot(input_offset);
960 } else {
961 value = output_[frame_index - 1]->GetPc();
962 }
963 output_frame->SetCallerPc(output_offset, value);
964 if (trace_scope_ != NULL) {
965 PrintF(trace_scope_->file(),
966 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
967 V8PRIxPTR " ; caller's pc\n",
968 top_address + output_offset, output_offset, value);
969 }
970
971 // The caller's frame pointer for the bottommost output frame is the same
972 // as in the input frame. For all subsequent output frames, it can be
973 // read from the previous one. Also compute and set this frame's frame
974 // pointer.
975 output_offset -= kFPOnStackSize;
976 input_offset -= kFPOnStackSize;
977 if (is_bottommost) {
978 value = input_->GetFrameSlot(input_offset);
979 } else {
980 value = output_[frame_index - 1]->GetFp();
981 }
982 output_frame->SetCallerFp(output_offset, value);
983 intptr_t fp_value = top_address + output_offset;
984 DCHECK(!is_bottommost || (input_->GetRegister(fp_reg.code()) +
985 has_alignment_padding_ * kPointerSize) == fp_value);
986 output_frame->SetFp(fp_value);
987 if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
988 if (trace_scope_ != NULL) {
989 PrintF(trace_scope_->file(),
990 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
991 V8PRIxPTR " ; caller's fp\n",
992 fp_value, output_offset, value);
993 }
994 DCHECK(!is_bottommost || !has_alignment_padding_ ||
995 (fp_value & kPointerSize) != 0);
996
997 if (FLAG_enable_ool_constant_pool) {
998 // For the bottommost output frame the constant pool pointer can be gotten
999 // from the input frame. For subsequent output frames, it can be read from
1000 // the previous frame.
1001 output_offset -= kPointerSize;
1002 input_offset -= kPointerSize;
1003 if (is_bottommost) {
1004 value = input_->GetFrameSlot(input_offset);
1005 } else {
1006 value = output_[frame_index - 1]->GetConstantPool();
1007 }
1008 output_frame->SetCallerConstantPool(output_offset, value);
1009 if (trace_scope_) {
1010 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1011 V8PRIxPTR "; caller's constant_pool\n",
1012 top_address + output_offset, output_offset, value);
1013 }
1014 }
1015
1016 // For the bottommost output frame the context can be gotten from the input
1017 // frame. For all subsequent output frames it can be gotten from the function
1018 // so long as we don't inline functions that need local contexts.
1019 Register context_reg = JavaScriptFrame::context_register();
1020 output_offset -= kPointerSize;
1021 input_offset -= kPointerSize;
1022 // Read the context from the translations.
1023 DoTranslateCommand(iterator, frame_index, output_offset);
1024 value = output_frame->GetFrameSlot(output_offset);
1025 // The context should not be a placeholder for a materialized object.
1026 CHECK(value !=
1027 reinterpret_cast<intptr_t>(isolate_->heap()->arguments_marker()));
1028 if (value ==
1029 reinterpret_cast<intptr_t>(isolate_->heap()->undefined_value())) {
1030 // If the context was optimized away, just use the context from
1031 // the activation. This should only apply to Crankshaft code.
1032 CHECK(!compiled_code_->is_turbofanned());
1033 if (is_bottommost) {
1034 value = input_->GetFrameSlot(input_offset);
1035 } else {
1036 value = reinterpret_cast<intptr_t>(function->context());
1037 }
1038 output_frame->SetFrameSlot(output_offset, value);
1039 }
1040 output_frame->SetContext(value);
1041 if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
1042 if (trace_scope_ != NULL) {
1043 PrintF(trace_scope_->file(),
1044 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1045 V8PRIxPTR "; context\n",
1046 top_address + output_offset, output_offset, value);
1047 }
1048
1049 // The function was mentioned explicitly in the BEGIN_FRAME.
1050 output_offset -= kPointerSize;
1051 input_offset -= kPointerSize;
1052 value = reinterpret_cast<intptr_t>(function);
1053 // The function for the bottommost output frame should also agree with the
1054 // input frame.
1055 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
1056 output_frame->SetFrameSlot(output_offset, value);
1057 if (trace_scope_ != NULL) {
1058 PrintF(trace_scope_->file(),
1059 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1060 V8PRIxPTR "; function\n",
1061 top_address + output_offset, output_offset, value);
1062 }
1063
1064 // Translate the rest of the frame.
1065 for (unsigned i = 0; i < height; ++i) {
1066 output_offset -= kPointerSize;
1067 DoTranslateCommand(iterator, frame_index, output_offset);
1068 }
1069 CHECK_EQ(0, output_offset);
1070
1071 // Compute this frame's PC, state, and continuation.
1072 Code* non_optimized_code = function->shared()->code();
1073 FixedArray* raw_data = non_optimized_code->deoptimization_data();
1074 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
1075 Address start = non_optimized_code->instruction_start();
1076 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
1077 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
1078 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
1079 output_frame->SetPc(pc_value);
1080
1081 // Update constant pool.
1082 if (FLAG_enable_ool_constant_pool) {
1083 intptr_t constant_pool_value =
1084 reinterpret_cast<intptr_t>(non_optimized_code->constant_pool());
1085 output_frame->SetConstantPool(constant_pool_value);
1086 if (is_topmost) {
1087 Register constant_pool_reg =
1088 JavaScriptFrame::constant_pool_pointer_register();
1089 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1090 }
1091 }
1092
1093 FullCodeGenerator::State state =
1094 FullCodeGenerator::StateField::decode(pc_and_state);
1095 output_frame->SetState(Smi::FromInt(state));
1096
1097 // Set the continuation for the topmost frame.
1098 if (is_topmost && bailout_type_ != DEBUGGER) {
1099 Builtins* builtins = isolate_->builtins();
1100 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
1101 if (bailout_type_ == LAZY) {
1102 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
1103 } else if (bailout_type_ == SOFT) {
1104 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
1105 } else {
1106 CHECK_EQ(bailout_type_, EAGER);
1107 }
1108 output_frame->SetContinuation(
1109 reinterpret_cast<intptr_t>(continuation->entry()));
1110 }
1111 }
1112
1113
DoComputeArgumentsAdaptorFrame(TranslationIterator * iterator,int frame_index)1114 void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
1115 int frame_index) {
1116 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
1117 unsigned height = iterator->Next();
1118 unsigned height_in_bytes = height * kPointerSize;
1119 if (trace_scope_ != NULL) {
1120 PrintF(trace_scope_->file(),
1121 " translating arguments adaptor => height=%d\n", height_in_bytes);
1122 }
1123
1124 unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
1125 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1126
1127 // Allocate and store the output frame description.
1128 FrameDescription* output_frame =
1129 new(output_frame_size) FrameDescription(output_frame_size, function);
1130 output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
1131
1132 // Arguments adaptor can not be topmost or bottommost.
1133 CHECK(frame_index > 0 && frame_index < output_count_ - 1);
1134 CHECK(output_[frame_index] == NULL);
1135 output_[frame_index] = output_frame;
1136
1137 // The top address of the frame is computed from the previous
1138 // frame's top and this frame's size.
1139 intptr_t top_address;
1140 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1141 output_frame->SetTop(top_address);
1142
1143 // Compute the incoming parameter translation.
1144 int parameter_count = height;
1145 unsigned output_offset = output_frame_size;
1146 for (int i = 0; i < parameter_count; ++i) {
1147 output_offset -= kPointerSize;
1148 DoTranslateCommand(iterator, frame_index, output_offset);
1149 }
1150
1151 // Read caller's PC from the previous frame.
1152 output_offset -= kPCOnStackSize;
1153 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1154 output_frame->SetCallerPc(output_offset, callers_pc);
1155 if (trace_scope_ != NULL) {
1156 PrintF(trace_scope_->file(),
1157 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1158 V8PRIxPTR " ; caller's pc\n",
1159 top_address + output_offset, output_offset, callers_pc);
1160 }
1161
1162 // Read caller's FP from the previous frame, and set this frame's FP.
1163 output_offset -= kFPOnStackSize;
1164 intptr_t value = output_[frame_index - 1]->GetFp();
1165 output_frame->SetCallerFp(output_offset, value);
1166 intptr_t fp_value = top_address + output_offset;
1167 output_frame->SetFp(fp_value);
1168 if (trace_scope_ != NULL) {
1169 PrintF(trace_scope_->file(),
1170 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1171 V8PRIxPTR " ; caller's fp\n",
1172 fp_value, output_offset, value);
1173 }
1174
1175 if (FLAG_enable_ool_constant_pool) {
1176 // Read the caller's constant pool from the previous frame.
1177 output_offset -= kPointerSize;
1178 value = output_[frame_index - 1]->GetConstantPool();
1179 output_frame->SetCallerConstantPool(output_offset, value);
1180 if (trace_scope_) {
1181 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1182 V8PRIxPTR "; caller's constant_pool\n",
1183 top_address + output_offset, output_offset, value);
1184 }
1185 }
1186
1187 // A marker value is used in place of the context.
1188 output_offset -= kPointerSize;
1189 intptr_t context = reinterpret_cast<intptr_t>(
1190 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1191 output_frame->SetFrameSlot(output_offset, context);
1192 if (trace_scope_ != NULL) {
1193 PrintF(trace_scope_->file(),
1194 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1195 V8PRIxPTR " ; context (adaptor sentinel)\n",
1196 top_address + output_offset, output_offset, context);
1197 }
1198
1199 // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
1200 output_offset -= kPointerSize;
1201 value = reinterpret_cast<intptr_t>(function);
1202 output_frame->SetFrameSlot(output_offset, value);
1203 if (trace_scope_ != NULL) {
1204 PrintF(trace_scope_->file(),
1205 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1206 V8PRIxPTR " ; function\n",
1207 top_address + output_offset, output_offset, value);
1208 }
1209
1210 // Number of incoming arguments.
1211 output_offset -= kPointerSize;
1212 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1213 output_frame->SetFrameSlot(output_offset, value);
1214 if (trace_scope_ != NULL) {
1215 PrintF(trace_scope_->file(),
1216 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1217 V8PRIxPTR " ; argc (%d)\n",
1218 top_address + output_offset, output_offset, value, height - 1);
1219 }
1220
1221 DCHECK(0 == output_offset);
1222
1223 Builtins* builtins = isolate_->builtins();
1224 Code* adaptor_trampoline =
1225 builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
1226 intptr_t pc_value = reinterpret_cast<intptr_t>(
1227 adaptor_trampoline->instruction_start() +
1228 isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
1229 output_frame->SetPc(pc_value);
1230 if (FLAG_enable_ool_constant_pool) {
1231 intptr_t constant_pool_value =
1232 reinterpret_cast<intptr_t>(adaptor_trampoline->constant_pool());
1233 output_frame->SetConstantPool(constant_pool_value);
1234 }
1235 }
1236
1237
DoComputeConstructStubFrame(TranslationIterator * iterator,int frame_index)1238 void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
1239 int frame_index) {
1240 Builtins* builtins = isolate_->builtins();
1241 Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
1242 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
1243 unsigned height = iterator->Next();
1244 unsigned height_in_bytes = height * kPointerSize;
1245 if (trace_scope_ != NULL) {
1246 PrintF(trace_scope_->file(),
1247 " translating construct stub => height=%d\n", height_in_bytes);
1248 }
1249
1250 unsigned fixed_frame_size = ConstructFrameConstants::kFrameSize;
1251 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1252
1253 // Allocate and store the output frame description.
1254 FrameDescription* output_frame =
1255 new(output_frame_size) FrameDescription(output_frame_size, function);
1256 output_frame->SetFrameType(StackFrame::CONSTRUCT);
1257
1258 // Construct stub can not be topmost or bottommost.
1259 DCHECK(frame_index > 0 && frame_index < output_count_ - 1);
1260 DCHECK(output_[frame_index] == NULL);
1261 output_[frame_index] = output_frame;
1262
1263 // The top address of the frame is computed from the previous
1264 // frame's top and this frame's size.
1265 intptr_t top_address;
1266 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1267 output_frame->SetTop(top_address);
1268
1269 // Compute the incoming parameter translation.
1270 int parameter_count = height;
1271 unsigned output_offset = output_frame_size;
1272 for (int i = 0; i < parameter_count; ++i) {
1273 output_offset -= kPointerSize;
1274 int deferred_object_index = deferred_objects_.length();
1275 DoTranslateCommand(iterator, frame_index, output_offset);
1276 // The allocated receiver of a construct stub frame is passed as the
1277 // receiver parameter through the translation. It might be encoding
1278 // a captured object, patch the slot address for a captured object.
1279 if (i == 0 && deferred_objects_.length() > deferred_object_index) {
1280 CHECK(!deferred_objects_[deferred_object_index].is_arguments());
1281 deferred_objects_[deferred_object_index].patch_slot_address(top_address);
1282 }
1283 }
1284
1285 // Read caller's PC from the previous frame.
1286 output_offset -= kPCOnStackSize;
1287 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1288 output_frame->SetCallerPc(output_offset, callers_pc);
1289 if (trace_scope_ != NULL) {
1290 PrintF(trace_scope_->file(),
1291 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1292 V8PRIxPTR " ; caller's pc\n",
1293 top_address + output_offset, output_offset, callers_pc);
1294 }
1295
1296 // Read caller's FP from the previous frame, and set this frame's FP.
1297 output_offset -= kFPOnStackSize;
1298 intptr_t value = output_[frame_index - 1]->GetFp();
1299 output_frame->SetCallerFp(output_offset, value);
1300 intptr_t fp_value = top_address + output_offset;
1301 output_frame->SetFp(fp_value);
1302 if (trace_scope_ != NULL) {
1303 PrintF(trace_scope_->file(),
1304 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1305 V8PRIxPTR " ; caller's fp\n",
1306 fp_value, output_offset, value);
1307 }
1308
1309 if (FLAG_enable_ool_constant_pool) {
1310 // Read the caller's constant pool from the previous frame.
1311 output_offset -= kPointerSize;
1312 value = output_[frame_index - 1]->GetConstantPool();
1313 output_frame->SetCallerConstantPool(output_offset, value);
1314 if (trace_scope_) {
1315 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1316 V8PRIxPTR " ; caller's constant pool\n",
1317 top_address + output_offset, output_offset, value);
1318 }
1319 }
1320
1321 // The context can be gotten from the previous frame.
1322 output_offset -= kPointerSize;
1323 value = output_[frame_index - 1]->GetContext();
1324 output_frame->SetFrameSlot(output_offset, value);
1325 if (trace_scope_ != NULL) {
1326 PrintF(trace_scope_->file(),
1327 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1328 V8PRIxPTR " ; context\n",
1329 top_address + output_offset, output_offset, value);
1330 }
1331
1332 // A marker value is used in place of the function.
1333 output_offset -= kPointerSize;
1334 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT));
1335 output_frame->SetFrameSlot(output_offset, value);
1336 if (trace_scope_ != NULL) {
1337 PrintF(trace_scope_->file(),
1338 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1339 V8PRIxPTR " ; function (construct sentinel)\n",
1340 top_address + output_offset, output_offset, value);
1341 }
1342
1343 // The output frame reflects a JSConstructStubGeneric frame.
1344 output_offset -= kPointerSize;
1345 value = reinterpret_cast<intptr_t>(construct_stub);
1346 output_frame->SetFrameSlot(output_offset, value);
1347 if (trace_scope_ != NULL) {
1348 PrintF(trace_scope_->file(),
1349 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1350 V8PRIxPTR " ; code object\n",
1351 top_address + output_offset, output_offset, value);
1352 }
1353
1354 // Number of incoming arguments.
1355 output_offset -= kPointerSize;
1356 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1357 output_frame->SetFrameSlot(output_offset, value);
1358 if (trace_scope_ != NULL) {
1359 PrintF(trace_scope_->file(),
1360 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1361 V8PRIxPTR " ; argc (%d)\n",
1362 top_address + output_offset, output_offset, value, height - 1);
1363 }
1364
1365 // Constructor function being invoked by the stub (only present on some
1366 // architectures, indicated by kConstructorOffset).
1367 if (ConstructFrameConstants::kConstructorOffset != kMinInt) {
1368 output_offset -= kPointerSize;
1369 value = reinterpret_cast<intptr_t>(function);
1370 output_frame->SetFrameSlot(output_offset, value);
1371 if (trace_scope_ != NULL) {
1372 PrintF(trace_scope_->file(),
1373 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1374 V8PRIxPTR " ; constructor function\n",
1375 top_address + output_offset, output_offset, value);
1376 }
1377 }
1378
1379 // The newly allocated object was passed as receiver in the artificial
1380 // constructor stub environment created by HEnvironment::CopyForInlining().
1381 output_offset -= kPointerSize;
1382 value = output_frame->GetFrameSlot(output_frame_size - kPointerSize);
1383 output_frame->SetFrameSlot(output_offset, value);
1384 if (trace_scope_ != NULL) {
1385 PrintF(trace_scope_->file(),
1386 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1387 V8PRIxPTR " ; allocated receiver\n",
1388 top_address + output_offset, output_offset, value);
1389 }
1390
1391 CHECK_EQ(0, output_offset);
1392
1393 intptr_t pc = reinterpret_cast<intptr_t>(
1394 construct_stub->instruction_start() +
1395 isolate_->heap()->construct_stub_deopt_pc_offset()->value());
1396 output_frame->SetPc(pc);
1397 if (FLAG_enable_ool_constant_pool) {
1398 intptr_t constant_pool_value =
1399 reinterpret_cast<intptr_t>(construct_stub->constant_pool());
1400 output_frame->SetConstantPool(constant_pool_value);
1401 }
1402 }
1403
1404
DoComputeAccessorStubFrame(TranslationIterator * iterator,int frame_index,bool is_setter_stub_frame)1405 void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
1406 int frame_index,
1407 bool is_setter_stub_frame) {
1408 JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
1409 // The receiver (and the implicit return value, if any) are expected in
1410 // registers by the LoadIC/StoreIC, so they don't belong to the output stack
1411 // frame. This means that we have to use a height of 0.
1412 unsigned height = 0;
1413 unsigned height_in_bytes = height * kPointerSize;
1414 const char* kind = is_setter_stub_frame ? "setter" : "getter";
1415 if (trace_scope_ != NULL) {
1416 PrintF(trace_scope_->file(),
1417 " translating %s stub => height=%u\n", kind, height_in_bytes);
1418 }
1419
1420 // We need 1 stack entry for the return address and enough entries for the
1421 // StackFrame::INTERNAL (FP, context, frame type, code object and constant
1422 // pool (if FLAG_enable_ool_constant_pool)- see MacroAssembler::EnterFrame).
1423 // For a setter stub frame we need one additional entry for the implicit
1424 // return value, see StoreStubCompiler::CompileStoreViaSetter.
1425 unsigned fixed_frame_entries =
1426 (StandardFrameConstants::kFixedFrameSize / kPointerSize) + 1 +
1427 (is_setter_stub_frame ? 1 : 0);
1428 unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
1429 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1430
1431 // Allocate and store the output frame description.
1432 FrameDescription* output_frame =
1433 new(output_frame_size) FrameDescription(output_frame_size, accessor);
1434 output_frame->SetFrameType(StackFrame::INTERNAL);
1435
1436 // A frame for an accessor stub can not be the topmost or bottommost one.
1437 CHECK(frame_index > 0 && frame_index < output_count_ - 1);
1438 CHECK_EQ(output_[frame_index], NULL);
1439 output_[frame_index] = output_frame;
1440
1441 // The top address of the frame is computed from the previous frame's top and
1442 // this frame's size.
1443 intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1444 output_frame->SetTop(top_address);
1445
1446 unsigned output_offset = output_frame_size;
1447
1448 // Read caller's PC from the previous frame.
1449 output_offset -= kPCOnStackSize;
1450 intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1451 output_frame->SetCallerPc(output_offset, callers_pc);
1452 if (trace_scope_ != NULL) {
1453 PrintF(trace_scope_->file(),
1454 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1455 " ; caller's pc\n",
1456 top_address + output_offset, output_offset, callers_pc);
1457 }
1458
1459 // Read caller's FP from the previous frame, and set this frame's FP.
1460 output_offset -= kFPOnStackSize;
1461 intptr_t value = output_[frame_index - 1]->GetFp();
1462 output_frame->SetCallerFp(output_offset, value);
1463 intptr_t fp_value = top_address + output_offset;
1464 output_frame->SetFp(fp_value);
1465 if (trace_scope_ != NULL) {
1466 PrintF(trace_scope_->file(),
1467 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1468 " ; caller's fp\n",
1469 fp_value, output_offset, value);
1470 }
1471
1472 if (FLAG_enable_ool_constant_pool) {
1473 // Read the caller's constant pool from the previous frame.
1474 output_offset -= kPointerSize;
1475 value = output_[frame_index - 1]->GetConstantPool();
1476 output_frame->SetCallerConstantPool(output_offset, value);
1477 if (trace_scope_) {
1478 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1479 V8PRIxPTR " ; caller's constant pool\n",
1480 top_address + output_offset, output_offset, value);
1481 }
1482 }
1483
1484 // The context can be gotten from the previous frame.
1485 output_offset -= kPointerSize;
1486 value = output_[frame_index - 1]->GetContext();
1487 output_frame->SetFrameSlot(output_offset, value);
1488 if (trace_scope_ != NULL) {
1489 PrintF(trace_scope_->file(),
1490 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1491 " ; context\n",
1492 top_address + output_offset, output_offset, value);
1493 }
1494
1495 // A marker value is used in place of the function.
1496 output_offset -= kPointerSize;
1497 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
1498 output_frame->SetFrameSlot(output_offset, value);
1499 if (trace_scope_ != NULL) {
1500 PrintF(trace_scope_->file(),
1501 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1502 " ; function (%s sentinel)\n",
1503 top_address + output_offset, output_offset, value, kind);
1504 }
1505
1506 // Get Code object from accessor stub.
1507 output_offset -= kPointerSize;
1508 Builtins::Name name = is_setter_stub_frame ?
1509 Builtins::kStoreIC_Setter_ForDeopt :
1510 Builtins::kLoadIC_Getter_ForDeopt;
1511 Code* accessor_stub = isolate_->builtins()->builtin(name);
1512 value = reinterpret_cast<intptr_t>(accessor_stub);
1513 output_frame->SetFrameSlot(output_offset, value);
1514 if (trace_scope_ != NULL) {
1515 PrintF(trace_scope_->file(),
1516 " 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
1517 " ; code object\n",
1518 top_address + output_offset, output_offset, value);
1519 }
1520
1521 // Skip receiver.
1522 DoTranslateObjectAndSkip(iterator);
1523
1524 if (is_setter_stub_frame) {
1525 // The implicit return value was part of the artificial setter stub
1526 // environment.
1527 output_offset -= kPointerSize;
1528 DoTranslateCommand(iterator, frame_index, output_offset);
1529 }
1530
1531 CHECK_EQ(output_offset, 0);
1532
1533 Smi* offset = is_setter_stub_frame ?
1534 isolate_->heap()->setter_stub_deopt_pc_offset() :
1535 isolate_->heap()->getter_stub_deopt_pc_offset();
1536 intptr_t pc = reinterpret_cast<intptr_t>(
1537 accessor_stub->instruction_start() + offset->value());
1538 output_frame->SetPc(pc);
1539 if (FLAG_enable_ool_constant_pool) {
1540 intptr_t constant_pool_value =
1541 reinterpret_cast<intptr_t>(accessor_stub->constant_pool());
1542 output_frame->SetConstantPool(constant_pool_value);
1543 }
1544 }
1545
1546
DoComputeCompiledStubFrame(TranslationIterator * iterator,int frame_index)1547 void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
1548 int frame_index) {
1549 //
1550 // FROM TO
1551 // | .... | | .... |
1552 // +-------------------------+ +-------------------------+
1553 // | JSFunction continuation | | JSFunction continuation |
1554 // +-------------------------+ +-------------------------+
1555 // | | saved frame (FP) | | saved frame (FP) |
1556 // | +=========================+<-fpreg +=========================+<-fpreg
1557 // | |constant pool (if ool_cp)| |constant pool (if ool_cp)|
1558 // | +-------------------------+ +-------------------------|
1559 // | | JSFunction context | | JSFunction context |
1560 // v +-------------------------+ +-------------------------|
1561 // | COMPILED_STUB marker | | STUB_FAILURE marker |
1562 // +-------------------------+ +-------------------------+
1563 // | | | caller args.arguments_ |
1564 // | ... | +-------------------------+
1565 // | | | caller args.length_ |
1566 // |-------------------------|<-spreg +-------------------------+
1567 // | caller args pointer |
1568 // +-------------------------+
1569 // | caller stack param 1 |
1570 // parameters in registers +-------------------------+
1571 // and spilled to stack | .... |
1572 // +-------------------------+
1573 // | caller stack param n |
1574 // +-------------------------+<-spreg
1575 // reg = number of parameters
1576 // reg = failure handler address
1577 // reg = saved frame
1578 // reg = JSFunction context
1579 //
1580
1581 CHECK(compiled_code_->is_hydrogen_stub());
1582 int major_key = CodeStub::GetMajorKey(compiled_code_);
1583 CodeStubDescriptor descriptor(isolate_, compiled_code_->stub_key());
1584
1585 // The output frame must have room for all pushed register parameters
1586 // and the standard stack frame slots. Include space for an argument
1587 // object to the callee and optionally the space to pass the argument
1588 // object to the stub failure handler.
1589 int param_count = descriptor.GetEnvironmentParameterCount();
1590 CHECK_GE(param_count, 0);
1591
1592 int height_in_bytes = kPointerSize * param_count + sizeof(Arguments) +
1593 kPointerSize;
1594 int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
1595 int input_frame_size = input_->GetFrameSize();
1596 int output_frame_size = height_in_bytes + fixed_frame_size;
1597 if (trace_scope_ != NULL) {
1598 PrintF(trace_scope_->file(),
1599 " translating %s => StubFailureTrampolineStub, height=%d\n",
1600 CodeStub::MajorName(static_cast<CodeStub::Major>(major_key), false),
1601 height_in_bytes);
1602 }
1603
1604 // The stub failure trampoline is a single frame.
1605 FrameDescription* output_frame =
1606 new(output_frame_size) FrameDescription(output_frame_size, NULL);
1607 output_frame->SetFrameType(StackFrame::STUB_FAILURE_TRAMPOLINE);
1608 CHECK_EQ(frame_index, 0);
1609 output_[frame_index] = output_frame;
1610
1611 // The top address for the output frame can be computed from the input
1612 // frame pointer and the output frame's height. Subtract space for the
1613 // context and function slots.
1614 Register fp_reg = StubFailureTrampolineFrame::fp_register();
1615 intptr_t top_address = input_->GetRegister(fp_reg.code()) -
1616 StandardFrameConstants::kFixedFrameSizeFromFp - height_in_bytes;
1617 output_frame->SetTop(top_address);
1618
1619 // Read caller's PC (JSFunction continuation) from the input frame.
1620 unsigned input_frame_offset = input_frame_size - kPCOnStackSize;
1621 unsigned output_frame_offset = output_frame_size - kFPOnStackSize;
1622 intptr_t value = input_->GetFrameSlot(input_frame_offset);
1623 output_frame->SetCallerPc(output_frame_offset, value);
1624 if (trace_scope_ != NULL) {
1625 PrintF(trace_scope_->file(),
1626 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1627 V8PRIxPTR " ; caller's pc\n",
1628 top_address + output_frame_offset, output_frame_offset, value);
1629 }
1630
1631 // Read caller's FP from the input frame, and set this frame's FP.
1632 input_frame_offset -= kFPOnStackSize;
1633 value = input_->GetFrameSlot(input_frame_offset);
1634 output_frame_offset -= kFPOnStackSize;
1635 output_frame->SetCallerFp(output_frame_offset, value);
1636 intptr_t frame_ptr = input_->GetRegister(fp_reg.code());
1637 output_frame->SetRegister(fp_reg.code(), frame_ptr);
1638 output_frame->SetFp(frame_ptr);
1639 if (trace_scope_ != NULL) {
1640 PrintF(trace_scope_->file(),
1641 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1642 V8PRIxPTR " ; caller's fp\n",
1643 top_address + output_frame_offset, output_frame_offset, value);
1644 }
1645
1646 if (FLAG_enable_ool_constant_pool) {
1647 // Read the caller's constant pool from the input frame.
1648 input_frame_offset -= kPointerSize;
1649 value = input_->GetFrameSlot(input_frame_offset);
1650 output_frame_offset -= kPointerSize;
1651 output_frame->SetCallerConstantPool(output_frame_offset, value);
1652 if (trace_scope_) {
1653 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1654 V8PRIxPTR " ; caller's constant_pool\n",
1655 top_address + output_frame_offset, output_frame_offset, value);
1656 }
1657 }
1658
1659 // The context can be gotten from the input frame.
1660 Register context_reg = StubFailureTrampolineFrame::context_register();
1661 input_frame_offset -= kPointerSize;
1662 value = input_->GetFrameSlot(input_frame_offset);
1663 output_frame->SetRegister(context_reg.code(), value);
1664 output_frame_offset -= kPointerSize;
1665 output_frame->SetFrameSlot(output_frame_offset, value);
1666 CHECK(reinterpret_cast<Object*>(value)->IsContext());
1667 if (trace_scope_ != NULL) {
1668 PrintF(trace_scope_->file(),
1669 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1670 V8PRIxPTR " ; context\n",
1671 top_address + output_frame_offset, output_frame_offset, value);
1672 }
1673
1674 // A marker value is used in place of the function.
1675 output_frame_offset -= kPointerSize;
1676 value = reinterpret_cast<intptr_t>(
1677 Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
1678 output_frame->SetFrameSlot(output_frame_offset, value);
1679 if (trace_scope_ != NULL) {
1680 PrintF(trace_scope_->file(),
1681 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1682 V8PRIxPTR " ; function (stub failure sentinel)\n",
1683 top_address + output_frame_offset, output_frame_offset, value);
1684 }
1685
1686 intptr_t caller_arg_count = 0;
1687 bool arg_count_known = !descriptor.stack_parameter_count().is_valid();
1688
1689 // Build the Arguments object for the caller's parameters and a pointer to it.
1690 output_frame_offset -= kPointerSize;
1691 int args_arguments_offset = output_frame_offset;
1692 intptr_t the_hole = reinterpret_cast<intptr_t>(
1693 isolate_->heap()->the_hole_value());
1694 if (arg_count_known) {
1695 value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
1696 (caller_arg_count - 1) * kPointerSize;
1697 } else {
1698 value = the_hole;
1699 }
1700
1701 output_frame->SetFrameSlot(args_arguments_offset, value);
1702 if (trace_scope_ != NULL) {
1703 PrintF(trace_scope_->file(),
1704 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1705 V8PRIxPTR " ; args.arguments %s\n",
1706 top_address + args_arguments_offset, args_arguments_offset, value,
1707 arg_count_known ? "" : "(the hole)");
1708 }
1709
1710 output_frame_offset -= kPointerSize;
1711 int length_frame_offset = output_frame_offset;
1712 value = arg_count_known ? caller_arg_count : the_hole;
1713 output_frame->SetFrameSlot(length_frame_offset, value);
1714 if (trace_scope_ != NULL) {
1715 PrintF(trace_scope_->file(),
1716 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1717 V8PRIxPTR " ; args.length %s\n",
1718 top_address + length_frame_offset, length_frame_offset, value,
1719 arg_count_known ? "" : "(the hole)");
1720 }
1721
1722 output_frame_offset -= kPointerSize;
1723 value = frame_ptr + StandardFrameConstants::kCallerSPOffset -
1724 (output_frame_size - output_frame_offset) + kPointerSize;
1725 output_frame->SetFrameSlot(output_frame_offset, value);
1726 if (trace_scope_ != NULL) {
1727 PrintF(trace_scope_->file(),
1728 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1729 V8PRIxPTR " ; args*\n",
1730 top_address + output_frame_offset, output_frame_offset, value);
1731 }
1732
1733 // Copy the register parameters to the failure frame.
1734 int arguments_length_offset = -1;
1735 for (int i = 0; i < param_count; ++i) {
1736 output_frame_offset -= kPointerSize;
1737 DoTranslateCommand(iterator, 0, output_frame_offset);
1738
1739 if (!arg_count_known && descriptor.IsEnvironmentParameterCountRegister(i)) {
1740 arguments_length_offset = output_frame_offset;
1741 }
1742 }
1743
1744 CHECK_EQ(output_frame_offset, 0);
1745
1746 if (!arg_count_known) {
1747 CHECK_GE(arguments_length_offset, 0);
1748 // We know it's a smi because 1) the code stub guarantees the stack
1749 // parameter count is in smi range, and 2) the DoTranslateCommand in the
1750 // parameter loop above translated that to a tagged value.
1751 Smi* smi_caller_arg_count = reinterpret_cast<Smi*>(
1752 output_frame->GetFrameSlot(arguments_length_offset));
1753 caller_arg_count = smi_caller_arg_count->value();
1754 output_frame->SetFrameSlot(length_frame_offset, caller_arg_count);
1755 if (trace_scope_ != NULL) {
1756 PrintF(trace_scope_->file(),
1757 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1758 V8PRIxPTR " ; args.length\n",
1759 top_address + length_frame_offset, length_frame_offset,
1760 caller_arg_count);
1761 }
1762 value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
1763 (caller_arg_count - 1) * kPointerSize;
1764 output_frame->SetFrameSlot(args_arguments_offset, value);
1765 if (trace_scope_ != NULL) {
1766 PrintF(trace_scope_->file(),
1767 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1768 V8PRIxPTR " ; args.arguments\n",
1769 top_address + args_arguments_offset, args_arguments_offset,
1770 value);
1771 }
1772 }
1773
1774 // Copy the double registers from the input into the output frame.
1775 CopyDoubleRegisters(output_frame);
1776
1777 // Fill registers containing handler and number of parameters.
1778 SetPlatformCompiledStubRegisters(output_frame, &descriptor);
1779
1780 // Compute this frame's PC, state, and continuation.
1781 Code* trampoline = NULL;
1782 StubFunctionMode function_mode = descriptor.function_mode();
1783 StubFailureTrampolineStub(isolate_,
1784 function_mode).FindCodeInCache(&trampoline);
1785 DCHECK(trampoline != NULL);
1786 output_frame->SetPc(reinterpret_cast<intptr_t>(
1787 trampoline->instruction_start()));
1788 if (FLAG_enable_ool_constant_pool) {
1789 Register constant_pool_reg =
1790 StubFailureTrampolineFrame::constant_pool_pointer_register();
1791 intptr_t constant_pool_value =
1792 reinterpret_cast<intptr_t>(trampoline->constant_pool());
1793 output_frame->SetConstantPool(constant_pool_value);
1794 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1795 }
1796 output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
1797 Code* notify_failure =
1798 isolate_->builtins()->builtin(Builtins::kNotifyStubFailureSaveDoubles);
1799 output_frame->SetContinuation(
1800 reinterpret_cast<intptr_t>(notify_failure->entry()));
1801 }
1802
1803
MaterializeNextHeapObject()1804 Handle<Object> Deoptimizer::MaterializeNextHeapObject() {
1805 int object_index = materialization_object_index_++;
1806 ObjectMaterializationDescriptor desc = deferred_objects_[object_index];
1807 const int length = desc.object_length();
1808
1809 if (desc.duplicate_object() >= 0) {
1810 // Found a previously materialized object by de-duplication.
1811 object_index = desc.duplicate_object();
1812 materialized_objects_->Add(Handle<Object>());
1813 } else if (desc.is_arguments() && ArgumentsObjectIsAdapted(object_index)) {
1814 // Use the arguments adapter frame we just built to materialize the
1815 // arguments object. FunctionGetArguments can't throw an exception.
1816 Handle<JSFunction> function = ArgumentsObjectFunction(object_index);
1817 Handle<JSObject> arguments = Handle<JSObject>::cast(
1818 Accessors::FunctionGetArguments(function));
1819 materialized_objects_->Add(arguments);
1820 // To keep consistent object counters, we still materialize the
1821 // nested values (but we throw them away).
1822 for (int i = 0; i < length; ++i) {
1823 MaterializeNextValue();
1824 }
1825 } else if (desc.is_arguments()) {
1826 // Construct an arguments object and copy the parameters to a newly
1827 // allocated arguments object backing store.
1828 Handle<JSFunction> function = ArgumentsObjectFunction(object_index);
1829 Handle<JSObject> arguments =
1830 isolate_->factory()->NewArgumentsObject(function, length);
1831 Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length);
1832 DCHECK_EQ(array->length(), length);
1833 arguments->set_elements(*array);
1834 materialized_objects_->Add(arguments);
1835 for (int i = 0; i < length; ++i) {
1836 Handle<Object> value = MaterializeNextValue();
1837 array->set(i, *value);
1838 }
1839 } else {
1840 // Dispatch on the instance type of the object to be materialized.
1841 // We also need to make sure that the representation of all fields
1842 // in the given object are general enough to hold a tagged value.
1843 Handle<Map> map = Map::GeneralizeAllFieldRepresentations(
1844 Handle<Map>::cast(MaterializeNextValue()));
1845 switch (map->instance_type()) {
1846 case MUTABLE_HEAP_NUMBER_TYPE:
1847 case HEAP_NUMBER_TYPE: {
1848 // Reuse the HeapNumber value directly as it is already properly
1849 // tagged and skip materializing the HeapNumber explicitly. Turn mutable
1850 // heap numbers immutable.
1851 Handle<Object> object = MaterializeNextValue();
1852 if (object_index < prev_materialized_count_) {
1853 materialized_objects_->Add(Handle<Object>(
1854 previously_materialized_objects_->get(object_index), isolate_));
1855 } else {
1856 materialized_objects_->Add(object);
1857 }
1858 materialization_value_index_ += kDoubleSize / kPointerSize - 1;
1859 break;
1860 }
1861 case JS_OBJECT_TYPE: {
1862 Handle<JSObject> object =
1863 isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED, false);
1864 if (object_index < prev_materialized_count_) {
1865 materialized_objects_->Add(Handle<Object>(
1866 previously_materialized_objects_->get(object_index), isolate_));
1867 } else {
1868 materialized_objects_->Add(object);
1869 }
1870 Handle<Object> properties = MaterializeNextValue();
1871 Handle<Object> elements = MaterializeNextValue();
1872 object->set_properties(FixedArray::cast(*properties));
1873 object->set_elements(FixedArrayBase::cast(*elements));
1874 for (int i = 0; i < length - 3; ++i) {
1875 Handle<Object> value = MaterializeNextValue();
1876 FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i);
1877 object->FastPropertyAtPut(index, *value);
1878 }
1879 break;
1880 }
1881 case JS_ARRAY_TYPE: {
1882 Handle<JSArray> object =
1883 isolate_->factory()->NewJSArray(0, map->elements_kind());
1884 if (object_index < prev_materialized_count_) {
1885 materialized_objects_->Add(Handle<Object>(
1886 previously_materialized_objects_->get(object_index), isolate_));
1887 } else {
1888 materialized_objects_->Add(object);
1889 }
1890 Handle<Object> properties = MaterializeNextValue();
1891 Handle<Object> elements = MaterializeNextValue();
1892 Handle<Object> length = MaterializeNextValue();
1893 object->set_properties(FixedArray::cast(*properties));
1894 object->set_elements(FixedArrayBase::cast(*elements));
1895 object->set_length(*length);
1896 break;
1897 }
1898 default:
1899 PrintF(stderr,
1900 "[couldn't handle instance type %d]\n", map->instance_type());
1901 FATAL("Unsupported instance type");
1902 }
1903 }
1904
1905 return materialized_objects_->at(object_index);
1906 }
1907
1908
MaterializeNextValue()1909 Handle<Object> Deoptimizer::MaterializeNextValue() {
1910 int value_index = materialization_value_index_++;
1911 Handle<Object> value = materialized_values_->at(value_index);
1912 if (value->IsMutableHeapNumber()) {
1913 HeapNumber::cast(*value)->set_map(isolate_->heap()->heap_number_map());
1914 }
1915 if (*value == isolate_->heap()->arguments_marker()) {
1916 value = MaterializeNextHeapObject();
1917 }
1918 return value;
1919 }
1920
1921
MaterializeHeapObjects(JavaScriptFrameIterator * it)1922 void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
1923 DCHECK_NE(DEBUGGER, bailout_type_);
1924
1925 MaterializedObjectStore* materialized_store =
1926 isolate_->materialized_object_store();
1927 previously_materialized_objects_ = materialized_store->Get(stack_fp_);
1928 prev_materialized_count_ = previously_materialized_objects_.is_null() ?
1929 0 : previously_materialized_objects_->length();
1930
1931 // Walk all JavaScript output frames with the given frame iterator.
1932 for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
1933 if (frame_index != 0) it->Advance();
1934 JavaScriptFrame* frame = it->frame();
1935 jsframe_functions_.Add(handle(frame->function(), isolate_));
1936 jsframe_has_adapted_arguments_.Add(frame->has_adapted_arguments());
1937 }
1938
1939 // Handlify all tagged object values before triggering any allocation.
1940 List<Handle<Object> > values(deferred_objects_tagged_values_.length());
1941 for (int i = 0; i < deferred_objects_tagged_values_.length(); ++i) {
1942 values.Add(Handle<Object>(deferred_objects_tagged_values_[i], isolate_));
1943 }
1944
1945 // Play it safe and clear all unhandlified values before we continue.
1946 deferred_objects_tagged_values_.Clear();
1947
1948 // Materialize all heap numbers before looking at arguments because when the
1949 // output frames are used to materialize arguments objects later on they need
1950 // to already contain valid heap numbers.
1951 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
1952 HeapNumberMaterializationDescriptor<Address> d = deferred_heap_numbers_[i];
1953 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
1954 if (trace_scope_ != NULL) {
1955 PrintF(trace_scope_->file(),
1956 "Materialized a new heap number %p [%e] in slot %p\n",
1957 reinterpret_cast<void*>(*num),
1958 d.value(),
1959 d.destination());
1960 }
1961 Memory::Object_at(d.destination()) = *num;
1962 }
1963
1964 // Materialize all heap numbers required for arguments/captured objects.
1965 for (int i = 0; i < deferred_objects_double_values_.length(); i++) {
1966 HeapNumberMaterializationDescriptor<int> d =
1967 deferred_objects_double_values_[i];
1968 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
1969 if (trace_scope_ != NULL) {
1970 PrintF(trace_scope_->file(),
1971 "Materialized a new heap number %p [%e] for object at %d\n",
1972 reinterpret_cast<void*>(*num),
1973 d.value(),
1974 d.destination());
1975 }
1976 DCHECK(values.at(d.destination())->IsTheHole());
1977 values.Set(d.destination(), num);
1978 }
1979
1980 // Play it safe and clear all object double values before we continue.
1981 deferred_objects_double_values_.Clear();
1982
1983 // Materialize arguments/captured objects.
1984 if (!deferred_objects_.is_empty()) {
1985 List<Handle<Object> > materialized_objects(deferred_objects_.length());
1986 materialized_objects_ = &materialized_objects;
1987 materialized_values_ = &values;
1988
1989 while (materialization_object_index_ < deferred_objects_.length()) {
1990 int object_index = materialization_object_index_;
1991 ObjectMaterializationDescriptor descriptor =
1992 deferred_objects_.at(object_index);
1993
1994 // Find a previously materialized object by de-duplication or
1995 // materialize a new instance of the object if necessary. Store
1996 // the materialized object into the frame slot.
1997 Handle<Object> object = MaterializeNextHeapObject();
1998 if (descriptor.slot_address() != NULL) {
1999 Memory::Object_at(descriptor.slot_address()) = *object;
2000 }
2001 if (trace_scope_ != NULL) {
2002 if (descriptor.is_arguments()) {
2003 PrintF(trace_scope_->file(),
2004 "Materialized %sarguments object of length %d for %p: ",
2005 ArgumentsObjectIsAdapted(object_index) ? "(adapted) " : "",
2006 Handle<JSObject>::cast(object)->elements()->length(),
2007 reinterpret_cast<void*>(descriptor.slot_address()));
2008 } else {
2009 PrintF(trace_scope_->file(),
2010 "Materialized captured object of size %d for %p: ",
2011 Handle<HeapObject>::cast(object)->Size(),
2012 reinterpret_cast<void*>(descriptor.slot_address()));
2013 }
2014 object->ShortPrint(trace_scope_->file());
2015 PrintF(trace_scope_->file(), "\n");
2016 }
2017 }
2018
2019 CHECK_EQ(materialization_object_index_, materialized_objects_->length());
2020 CHECK_EQ(materialization_value_index_, materialized_values_->length());
2021 }
2022
2023 if (prev_materialized_count_ > 0) {
2024 materialized_store->Remove(stack_fp_);
2025 }
2026 }
2027
2028
MaterializeHeapNumbersForDebuggerInspectableFrame(Address parameters_top,uint32_t parameters_size,Address expressions_top,uint32_t expressions_size,DeoptimizedFrameInfo * info)2029 void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
2030 Address parameters_top,
2031 uint32_t parameters_size,
2032 Address expressions_top,
2033 uint32_t expressions_size,
2034 DeoptimizedFrameInfo* info) {
2035 CHECK_EQ(DEBUGGER, bailout_type_);
2036 Address parameters_bottom = parameters_top + parameters_size;
2037 Address expressions_bottom = expressions_top + expressions_size;
2038 for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
2039 HeapNumberMaterializationDescriptor<Address> d = deferred_heap_numbers_[i];
2040
2041 // Check of the heap number to materialize actually belong to the frame
2042 // being extracted.
2043 Address slot = d.destination();
2044 if (parameters_top <= slot && slot < parameters_bottom) {
2045 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
2046
2047 int index = (info->parameters_count() - 1) -
2048 static_cast<int>(slot - parameters_top) / kPointerSize;
2049
2050 if (trace_scope_ != NULL) {
2051 PrintF(trace_scope_->file(),
2052 "Materializing a new heap number %p [%e] in slot %p"
2053 "for parameter slot #%d\n",
2054 reinterpret_cast<void*>(*num),
2055 d.value(),
2056 d.destination(),
2057 index);
2058 }
2059
2060 info->SetParameter(index, *num);
2061 } else if (expressions_top <= slot && slot < expressions_bottom) {
2062 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
2063
2064 int index = info->expression_count() - 1 -
2065 static_cast<int>(slot - expressions_top) / kPointerSize;
2066
2067 if (trace_scope_ != NULL) {
2068 PrintF(trace_scope_->file(),
2069 "Materializing a new heap number %p [%e] in slot %p"
2070 "for expression slot #%d\n",
2071 reinterpret_cast<void*>(*num),
2072 d.value(),
2073 d.destination(),
2074 index);
2075 }
2076
2077 info->SetExpression(index, *num);
2078 }
2079 }
2080 }
2081
2082
TraceValueType(bool is_smi)2083 static const char* TraceValueType(bool is_smi) {
2084 if (is_smi) {
2085 return "smi";
2086 }
2087
2088 return "heap number";
2089 }
2090
2091
DoTranslateObjectAndSkip(TranslationIterator * iterator)2092 void Deoptimizer::DoTranslateObjectAndSkip(TranslationIterator* iterator) {
2093 Translation::Opcode opcode =
2094 static_cast<Translation::Opcode>(iterator->Next());
2095
2096 switch (opcode) {
2097 case Translation::BEGIN:
2098 case Translation::JS_FRAME:
2099 case Translation::ARGUMENTS_ADAPTOR_FRAME:
2100 case Translation::CONSTRUCT_STUB_FRAME:
2101 case Translation::GETTER_STUB_FRAME:
2102 case Translation::SETTER_STUB_FRAME:
2103 case Translation::COMPILED_STUB_FRAME: {
2104 FATAL("Unexpected frame start translation opcode");
2105 return;
2106 }
2107
2108 case Translation::REGISTER:
2109 case Translation::INT32_REGISTER:
2110 case Translation::UINT32_REGISTER:
2111 case Translation::DOUBLE_REGISTER:
2112 case Translation::STACK_SLOT:
2113 case Translation::INT32_STACK_SLOT:
2114 case Translation::UINT32_STACK_SLOT:
2115 case Translation::DOUBLE_STACK_SLOT:
2116 case Translation::LITERAL: {
2117 // The value is not part of any materialized object, so we can ignore it.
2118 iterator->Skip(Translation::NumberOfOperandsFor(opcode));
2119 return;
2120 }
2121
2122 case Translation::DUPLICATED_OBJECT: {
2123 int object_index = iterator->Next();
2124 if (trace_scope_ != NULL) {
2125 PrintF(trace_scope_->file(), " skipping object ");
2126 PrintF(trace_scope_->file(),
2127 " ; duplicate of object #%d\n", object_index);
2128 }
2129 AddObjectDuplication(0, object_index);
2130 return;
2131 }
2132
2133 case Translation::ARGUMENTS_OBJECT:
2134 case Translation::CAPTURED_OBJECT: {
2135 int length = iterator->Next();
2136 bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
2137 if (trace_scope_ != NULL) {
2138 PrintF(trace_scope_->file(), " skipping object ");
2139 PrintF(trace_scope_->file(),
2140 " ; object (length = %d, is_args = %d)\n", length, is_args);
2141 }
2142
2143 AddObjectStart(0, length, is_args);
2144
2145 // We save the object values on the side and materialize the actual
2146 // object after the deoptimized frame is built.
2147 int object_index = deferred_objects_.length() - 1;
2148 for (int i = 0; i < length; i++) {
2149 DoTranslateObject(iterator, object_index, i);
2150 }
2151 return;
2152 }
2153 }
2154
2155 FATAL("Unexpected translation opcode");
2156 }
2157
2158
DoTranslateObject(TranslationIterator * iterator,int object_index,int field_index)2159 void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
2160 int object_index,
2161 int field_index) {
2162 disasm::NameConverter converter;
2163 Address object_slot = deferred_objects_[object_index].slot_address();
2164
2165 Translation::Opcode opcode =
2166 static_cast<Translation::Opcode>(iterator->Next());
2167
2168 switch (opcode) {
2169 case Translation::BEGIN:
2170 case Translation::JS_FRAME:
2171 case Translation::ARGUMENTS_ADAPTOR_FRAME:
2172 case Translation::CONSTRUCT_STUB_FRAME:
2173 case Translation::GETTER_STUB_FRAME:
2174 case Translation::SETTER_STUB_FRAME:
2175 case Translation::COMPILED_STUB_FRAME:
2176 FATAL("Unexpected frame start translation opcode");
2177 return;
2178
2179 case Translation::REGISTER: {
2180 int input_reg = iterator->Next();
2181 intptr_t input_value = input_->GetRegister(input_reg);
2182 if (trace_scope_ != NULL) {
2183 PrintF(trace_scope_->file(),
2184 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2185 reinterpret_cast<intptr_t>(object_slot),
2186 field_index);
2187 PrintF(trace_scope_->file(),
2188 "0x%08" V8PRIxPTR " ; %s ", input_value,
2189 converter.NameOfCPURegister(input_reg));
2190 reinterpret_cast<Object*>(input_value)->ShortPrint(
2191 trace_scope_->file());
2192 PrintF(trace_scope_->file(),
2193 "\n");
2194 }
2195 AddObjectTaggedValue(input_value);
2196 return;
2197 }
2198
2199 case Translation::INT32_REGISTER: {
2200 int input_reg = iterator->Next();
2201 intptr_t value = input_->GetRegister(input_reg);
2202 bool is_smi = Smi::IsValid(value);
2203 if (trace_scope_ != NULL) {
2204 PrintF(trace_scope_->file(),
2205 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2206 reinterpret_cast<intptr_t>(object_slot),
2207 field_index);
2208 PrintF(trace_scope_->file(),
2209 "%" V8PRIdPTR " ; %s (%s)\n", value,
2210 converter.NameOfCPURegister(input_reg),
2211 TraceValueType(is_smi));
2212 }
2213 if (is_smi) {
2214 intptr_t tagged_value =
2215 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2216 AddObjectTaggedValue(tagged_value);
2217 } else {
2218 double double_value = static_cast<double>(static_cast<int32_t>(value));
2219 AddObjectDoubleValue(double_value);
2220 }
2221 return;
2222 }
2223
2224 case Translation::UINT32_REGISTER: {
2225 int input_reg = iterator->Next();
2226 uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
2227 bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
2228 if (trace_scope_ != NULL) {
2229 PrintF(trace_scope_->file(),
2230 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2231 reinterpret_cast<intptr_t>(object_slot),
2232 field_index);
2233 PrintF(trace_scope_->file(),
2234 "%" V8PRIdPTR " ; uint %s (%s)\n", value,
2235 converter.NameOfCPURegister(input_reg),
2236 TraceValueType(is_smi));
2237 }
2238 if (is_smi) {
2239 intptr_t tagged_value =
2240 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2241 AddObjectTaggedValue(tagged_value);
2242 } else {
2243 double double_value = static_cast<double>(static_cast<uint32_t>(value));
2244 AddObjectDoubleValue(double_value);
2245 }
2246 return;
2247 }
2248
2249 case Translation::DOUBLE_REGISTER: {
2250 int input_reg = iterator->Next();
2251 double value = input_->GetDoubleRegister(input_reg);
2252 if (trace_scope_ != NULL) {
2253 PrintF(trace_scope_->file(),
2254 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2255 reinterpret_cast<intptr_t>(object_slot),
2256 field_index);
2257 PrintF(trace_scope_->file(),
2258 "%e ; %s\n", value,
2259 DoubleRegister::AllocationIndexToString(input_reg));
2260 }
2261 AddObjectDoubleValue(value);
2262 return;
2263 }
2264
2265 case Translation::STACK_SLOT: {
2266 int input_slot_index = iterator->Next();
2267 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2268 intptr_t input_value = input_->GetFrameSlot(input_offset);
2269 if (trace_scope_ != NULL) {
2270 PrintF(trace_scope_->file(),
2271 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2272 reinterpret_cast<intptr_t>(object_slot),
2273 field_index);
2274 PrintF(trace_scope_->file(),
2275 "0x%08" V8PRIxPTR " ; [sp + %d] ", input_value, input_offset);
2276 reinterpret_cast<Object*>(input_value)->ShortPrint(
2277 trace_scope_->file());
2278 PrintF(trace_scope_->file(),
2279 "\n");
2280 }
2281 AddObjectTaggedValue(input_value);
2282 return;
2283 }
2284
2285 case Translation::INT32_STACK_SLOT: {
2286 int input_slot_index = iterator->Next();
2287 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2288 intptr_t value = input_->GetFrameSlot(input_offset);
2289 bool is_smi = Smi::IsValid(value);
2290 if (trace_scope_ != NULL) {
2291 PrintF(trace_scope_->file(),
2292 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2293 reinterpret_cast<intptr_t>(object_slot),
2294 field_index);
2295 PrintF(trace_scope_->file(),
2296 "%" V8PRIdPTR " ; [sp + %d] (%s)\n",
2297 value, input_offset, TraceValueType(is_smi));
2298 }
2299 if (is_smi) {
2300 intptr_t tagged_value =
2301 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2302 AddObjectTaggedValue(tagged_value);
2303 } else {
2304 double double_value = static_cast<double>(static_cast<int32_t>(value));
2305 AddObjectDoubleValue(double_value);
2306 }
2307 return;
2308 }
2309
2310 case Translation::UINT32_STACK_SLOT: {
2311 int input_slot_index = iterator->Next();
2312 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2313 uintptr_t value =
2314 static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
2315 bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
2316 if (trace_scope_ != NULL) {
2317 PrintF(trace_scope_->file(),
2318 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2319 reinterpret_cast<intptr_t>(object_slot),
2320 field_index);
2321 PrintF(trace_scope_->file(),
2322 "%" V8PRIdPTR " ; [sp + %d] (uint %s)\n",
2323 value, input_offset, TraceValueType(is_smi));
2324 }
2325 if (is_smi) {
2326 intptr_t tagged_value =
2327 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2328 AddObjectTaggedValue(tagged_value);
2329 } else {
2330 double double_value = static_cast<double>(static_cast<uint32_t>(value));
2331 AddObjectDoubleValue(double_value);
2332 }
2333 return;
2334 }
2335
2336 case Translation::DOUBLE_STACK_SLOT: {
2337 int input_slot_index = iterator->Next();
2338 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2339 double value = input_->GetDoubleFrameSlot(input_offset);
2340 if (trace_scope_ != NULL) {
2341 PrintF(trace_scope_->file(),
2342 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2343 reinterpret_cast<intptr_t>(object_slot),
2344 field_index);
2345 PrintF(trace_scope_->file(),
2346 "%e ; [sp + %d]\n", value, input_offset);
2347 }
2348 AddObjectDoubleValue(value);
2349 return;
2350 }
2351
2352 case Translation::LITERAL: {
2353 Object* literal = ComputeLiteral(iterator->Next());
2354 if (trace_scope_ != NULL) {
2355 PrintF(trace_scope_->file(),
2356 " object @0x%08" V8PRIxPTR ": [field #%d] <- ",
2357 reinterpret_cast<intptr_t>(object_slot),
2358 field_index);
2359 literal->ShortPrint(trace_scope_->file());
2360 PrintF(trace_scope_->file(),
2361 " ; literal\n");
2362 }
2363 intptr_t value = reinterpret_cast<intptr_t>(literal);
2364 AddObjectTaggedValue(value);
2365 return;
2366 }
2367
2368 case Translation::DUPLICATED_OBJECT: {
2369 int object_index = iterator->Next();
2370 if (trace_scope_ != NULL) {
2371 PrintF(trace_scope_->file(),
2372 " nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
2373 reinterpret_cast<intptr_t>(object_slot),
2374 field_index);
2375 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2376 PrintF(trace_scope_->file(),
2377 " ; duplicate of object #%d\n", object_index);
2378 }
2379 // Use the materialization marker value as a sentinel and fill in
2380 // the object after the deoptimized frame is built.
2381 intptr_t value = reinterpret_cast<intptr_t>(
2382 isolate_->heap()->arguments_marker());
2383 AddObjectDuplication(0, object_index);
2384 AddObjectTaggedValue(value);
2385 return;
2386 }
2387
2388 case Translation::ARGUMENTS_OBJECT:
2389 case Translation::CAPTURED_OBJECT: {
2390 int length = iterator->Next();
2391 bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
2392 if (trace_scope_ != NULL) {
2393 PrintF(trace_scope_->file(),
2394 " nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
2395 reinterpret_cast<intptr_t>(object_slot),
2396 field_index);
2397 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2398 PrintF(trace_scope_->file(),
2399 " ; object (length = %d, is_args = %d)\n", length, is_args);
2400 }
2401 // Use the materialization marker value as a sentinel and fill in
2402 // the object after the deoptimized frame is built.
2403 intptr_t value = reinterpret_cast<intptr_t>(
2404 isolate_->heap()->arguments_marker());
2405 AddObjectStart(0, length, is_args);
2406 AddObjectTaggedValue(value);
2407 // We save the object values on the side and materialize the actual
2408 // object after the deoptimized frame is built.
2409 int object_index = deferred_objects_.length() - 1;
2410 for (int i = 0; i < length; i++) {
2411 DoTranslateObject(iterator, object_index, i);
2412 }
2413 return;
2414 }
2415 }
2416
2417 FATAL("Unexpected translation opcode");
2418 }
2419
2420
DoTranslateCommand(TranslationIterator * iterator,int frame_index,unsigned output_offset)2421 void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
2422 int frame_index,
2423 unsigned output_offset) {
2424 disasm::NameConverter converter;
2425 // A GC-safe temporary placeholder that we can put in the output frame.
2426 const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
2427
2428 Translation::Opcode opcode =
2429 static_cast<Translation::Opcode>(iterator->Next());
2430
2431 switch (opcode) {
2432 case Translation::BEGIN:
2433 case Translation::JS_FRAME:
2434 case Translation::ARGUMENTS_ADAPTOR_FRAME:
2435 case Translation::CONSTRUCT_STUB_FRAME:
2436 case Translation::GETTER_STUB_FRAME:
2437 case Translation::SETTER_STUB_FRAME:
2438 case Translation::COMPILED_STUB_FRAME:
2439 FATAL("Unexpected translation opcode");
2440 return;
2441
2442 case Translation::REGISTER: {
2443 int input_reg = iterator->Next();
2444 intptr_t input_value = input_->GetRegister(input_reg);
2445 if (trace_scope_ != NULL) {
2446 PrintF(
2447 trace_scope_->file(),
2448 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
2449 output_[frame_index]->GetTop() + output_offset,
2450 output_offset,
2451 input_value,
2452 converter.NameOfCPURegister(input_reg));
2453 reinterpret_cast<Object*>(input_value)->ShortPrint(
2454 trace_scope_->file());
2455 PrintF(trace_scope_->file(), "\n");
2456 }
2457 output_[frame_index]->SetFrameSlot(output_offset, input_value);
2458 return;
2459 }
2460
2461 case Translation::INT32_REGISTER: {
2462 int input_reg = iterator->Next();
2463 intptr_t value = input_->GetRegister(input_reg);
2464 bool is_smi = Smi::IsValid(value);
2465 if (trace_scope_ != NULL) {
2466 PrintF(
2467 trace_scope_->file(),
2468 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
2469 output_[frame_index]->GetTop() + output_offset,
2470 output_offset,
2471 value,
2472 converter.NameOfCPURegister(input_reg),
2473 TraceValueType(is_smi));
2474 }
2475 if (is_smi) {
2476 intptr_t tagged_value =
2477 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2478 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
2479 } else {
2480 // We save the untagged value on the side and store a GC-safe
2481 // temporary placeholder in the frame.
2482 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2483 static_cast<double>(static_cast<int32_t>(value)));
2484 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2485 }
2486 return;
2487 }
2488
2489 case Translation::UINT32_REGISTER: {
2490 int input_reg = iterator->Next();
2491 uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
2492 bool is_smi = value <= static_cast<uintptr_t>(Smi::kMaxValue);
2493 if (trace_scope_ != NULL) {
2494 PrintF(
2495 trace_scope_->file(),
2496 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIuPTR
2497 " ; uint %s (%s)\n",
2498 output_[frame_index]->GetTop() + output_offset,
2499 output_offset,
2500 value,
2501 converter.NameOfCPURegister(input_reg),
2502 TraceValueType(is_smi));
2503 }
2504 if (is_smi) {
2505 intptr_t tagged_value =
2506 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2507 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
2508 } else {
2509 // We save the untagged value on the side and store a GC-safe
2510 // temporary placeholder in the frame.
2511 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2512 static_cast<double>(static_cast<uint32_t>(value)));
2513 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2514 }
2515 return;
2516 }
2517
2518 case Translation::DOUBLE_REGISTER: {
2519 int input_reg = iterator->Next();
2520 double value = input_->GetDoubleRegister(input_reg);
2521 if (trace_scope_ != NULL) {
2522 PrintF(trace_scope_->file(),
2523 " 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n",
2524 output_[frame_index]->GetTop() + output_offset,
2525 output_offset,
2526 value,
2527 DoubleRegister::AllocationIndexToString(input_reg));
2528 }
2529 // We save the untagged value on the side and store a GC-safe
2530 // temporary placeholder in the frame.
2531 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
2532 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2533 return;
2534 }
2535
2536 case Translation::STACK_SLOT: {
2537 int input_slot_index = iterator->Next();
2538 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2539 intptr_t input_value = input_->GetFrameSlot(input_offset);
2540 if (trace_scope_ != NULL) {
2541 PrintF(trace_scope_->file(),
2542 " 0x%08" V8PRIxPTR ": ",
2543 output_[frame_index]->GetTop() + output_offset);
2544 PrintF(trace_scope_->file(),
2545 "[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
2546 output_offset,
2547 input_value,
2548 input_offset);
2549 reinterpret_cast<Object*>(input_value)->ShortPrint(
2550 trace_scope_->file());
2551 PrintF(trace_scope_->file(), "\n");
2552 }
2553 output_[frame_index]->SetFrameSlot(output_offset, input_value);
2554 return;
2555 }
2556
2557 case Translation::INT32_STACK_SLOT: {
2558 int input_slot_index = iterator->Next();
2559 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2560 intptr_t value = input_->GetFrameSlot(input_offset);
2561 bool is_smi = Smi::IsValid(value);
2562 if (trace_scope_ != NULL) {
2563 PrintF(trace_scope_->file(),
2564 " 0x%08" V8PRIxPTR ": ",
2565 output_[frame_index]->GetTop() + output_offset);
2566 PrintF(trace_scope_->file(),
2567 "[top + %d] <- %" V8PRIdPTR " ; [sp + %d] (%s)\n",
2568 output_offset,
2569 value,
2570 input_offset,
2571 TraceValueType(is_smi));
2572 }
2573 if (is_smi) {
2574 intptr_t tagged_value =
2575 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2576 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
2577 } else {
2578 // We save the untagged value on the side and store a GC-safe
2579 // temporary placeholder in the frame.
2580 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2581 static_cast<double>(static_cast<int32_t>(value)));
2582 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2583 }
2584 return;
2585 }
2586
2587 case Translation::UINT32_STACK_SLOT: {
2588 int input_slot_index = iterator->Next();
2589 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2590 uintptr_t value =
2591 static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
2592 bool is_smi = value <= static_cast<uintptr_t>(Smi::kMaxValue);
2593 if (trace_scope_ != NULL) {
2594 PrintF(trace_scope_->file(),
2595 " 0x%08" V8PRIxPTR ": ",
2596 output_[frame_index]->GetTop() + output_offset);
2597 PrintF(trace_scope_->file(),
2598 "[top + %d] <- %" V8PRIuPTR " ; [sp + %d] (uint32 %s)\n",
2599 output_offset,
2600 value,
2601 input_offset,
2602 TraceValueType(is_smi));
2603 }
2604 if (is_smi) {
2605 intptr_t tagged_value =
2606 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2607 output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
2608 } else {
2609 // We save the untagged value on the side and store a GC-safe
2610 // temporary placeholder in the frame.
2611 AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
2612 static_cast<double>(static_cast<uint32_t>(value)));
2613 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2614 }
2615 return;
2616 }
2617
2618 case Translation::DOUBLE_STACK_SLOT: {
2619 int input_slot_index = iterator->Next();
2620 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
2621 double value = input_->GetDoubleFrameSlot(input_offset);
2622 if (trace_scope_ != NULL) {
2623 PrintF(trace_scope_->file(),
2624 " 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
2625 output_[frame_index]->GetTop() + output_offset,
2626 output_offset,
2627 value,
2628 input_offset);
2629 }
2630 // We save the untagged value on the side and store a GC-safe
2631 // temporary placeholder in the frame.
2632 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value);
2633 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
2634 return;
2635 }
2636
2637 case Translation::LITERAL: {
2638 Object* literal = ComputeLiteral(iterator->Next());
2639 if (trace_scope_ != NULL) {
2640 PrintF(trace_scope_->file(),
2641 " 0x%08" V8PRIxPTR ": [top + %d] <- ",
2642 output_[frame_index]->GetTop() + output_offset,
2643 output_offset);
2644 literal->ShortPrint(trace_scope_->file());
2645 PrintF(trace_scope_->file(), " ; literal\n");
2646 }
2647 intptr_t value = reinterpret_cast<intptr_t>(literal);
2648 output_[frame_index]->SetFrameSlot(output_offset, value);
2649 return;
2650 }
2651
2652 case Translation::DUPLICATED_OBJECT: {
2653 int object_index = iterator->Next();
2654 if (trace_scope_ != NULL) {
2655 PrintF(trace_scope_->file(),
2656 " 0x%08" V8PRIxPTR ": [top + %d] <- ",
2657 output_[frame_index]->GetTop() + output_offset,
2658 output_offset);
2659 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2660 PrintF(trace_scope_->file(),
2661 " ; duplicate of object #%d\n", object_index);
2662 }
2663 // Use the materialization marker value as a sentinel and fill in
2664 // the object after the deoptimized frame is built.
2665 intptr_t value = reinterpret_cast<intptr_t>(
2666 isolate_->heap()->arguments_marker());
2667 AddObjectDuplication(output_[frame_index]->GetTop() + output_offset,
2668 object_index);
2669 output_[frame_index]->SetFrameSlot(output_offset, value);
2670 return;
2671 }
2672
2673 case Translation::ARGUMENTS_OBJECT:
2674 case Translation::CAPTURED_OBJECT: {
2675 int length = iterator->Next();
2676 bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
2677 if (trace_scope_ != NULL) {
2678 PrintF(trace_scope_->file(),
2679 " 0x%08" V8PRIxPTR ": [top + %d] <- ",
2680 output_[frame_index]->GetTop() + output_offset,
2681 output_offset);
2682 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2683 PrintF(trace_scope_->file(),
2684 " ; object (length = %d, is_args = %d)\n", length, is_args);
2685 }
2686 // Use the materialization marker value as a sentinel and fill in
2687 // the object after the deoptimized frame is built.
2688 intptr_t value = reinterpret_cast<intptr_t>(
2689 isolate_->heap()->arguments_marker());
2690 AddObjectStart(output_[frame_index]->GetTop() + output_offset,
2691 length, is_args);
2692 output_[frame_index]->SetFrameSlot(output_offset, value);
2693 // We save the object values on the side and materialize the actual
2694 // object after the deoptimized frame is built.
2695 int object_index = deferred_objects_.length() - 1;
2696 for (int i = 0; i < length; i++) {
2697 DoTranslateObject(iterator, object_index, i);
2698 }
2699 return;
2700 }
2701 }
2702 }
2703
2704
ComputeInputFrameSize() const2705 unsigned Deoptimizer::ComputeInputFrameSize() const {
2706 unsigned fixed_size = ComputeFixedSize(function_);
2707 // The fp-to-sp delta already takes the context, constant pool pointer and the
2708 // function into account so we have to avoid double counting them.
2709 unsigned result = fixed_size + fp_to_sp_delta_ -
2710 StandardFrameConstants::kFixedFrameSizeFromFp;
2711 if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
2712 unsigned stack_slots = compiled_code_->stack_slots();
2713 unsigned outgoing_size = ComputeOutgoingArgumentSize();
2714 CHECK(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
2715 }
2716 return result;
2717 }
2718
2719
ComputeFixedSize(JSFunction * function) const2720 unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const {
2721 // The fixed part of the frame consists of the return address, frame
2722 // pointer, function, context, and all the incoming arguments.
2723 return ComputeIncomingArgumentSize(function) +
2724 StandardFrameConstants::kFixedFrameSize;
2725 }
2726
2727
ComputeIncomingArgumentSize(JSFunction * function) const2728 unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const {
2729 // The incoming arguments is the values for formal parameters and
2730 // the receiver. Every slot contains a pointer.
2731 if (function->IsSmi()) {
2732 CHECK_EQ(Smi::cast(function), Smi::FromInt(StackFrame::STUB));
2733 return 0;
2734 }
2735 unsigned arguments = function->shared()->formal_parameter_count() + 1;
2736 return arguments * kPointerSize;
2737 }
2738
2739
ComputeOutgoingArgumentSize() const2740 unsigned Deoptimizer::ComputeOutgoingArgumentSize() const {
2741 DeoptimizationInputData* data = DeoptimizationInputData::cast(
2742 compiled_code_->deoptimization_data());
2743 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value();
2744 return height * kPointerSize;
2745 }
2746
2747
ComputeLiteral(int index) const2748 Object* Deoptimizer::ComputeLiteral(int index) const {
2749 DeoptimizationInputData* data = DeoptimizationInputData::cast(
2750 compiled_code_->deoptimization_data());
2751 FixedArray* literals = data->LiteralArray();
2752 return literals->get(index);
2753 }
2754
2755
AddObjectStart(intptr_t slot,int length,bool is_args)2756 void Deoptimizer::AddObjectStart(intptr_t slot, int length, bool is_args) {
2757 ObjectMaterializationDescriptor object_desc(
2758 reinterpret_cast<Address>(slot), jsframe_count_, length, -1, is_args);
2759 deferred_objects_.Add(object_desc);
2760 }
2761
2762
AddObjectDuplication(intptr_t slot,int object_index)2763 void Deoptimizer::AddObjectDuplication(intptr_t slot, int object_index) {
2764 ObjectMaterializationDescriptor object_desc(
2765 reinterpret_cast<Address>(slot), jsframe_count_, -1, object_index, false);
2766 deferred_objects_.Add(object_desc);
2767 }
2768
2769
AddObjectTaggedValue(intptr_t value)2770 void Deoptimizer::AddObjectTaggedValue(intptr_t value) {
2771 deferred_objects_tagged_values_.Add(reinterpret_cast<Object*>(value));
2772 }
2773
2774
AddObjectDoubleValue(double value)2775 void Deoptimizer::AddObjectDoubleValue(double value) {
2776 deferred_objects_tagged_values_.Add(isolate()->heap()->the_hole_value());
2777 HeapNumberMaterializationDescriptor<int> value_desc(
2778 deferred_objects_tagged_values_.length() - 1, value);
2779 deferred_objects_double_values_.Add(value_desc);
2780 }
2781
2782
AddDoubleValue(intptr_t slot_address,double value)2783 void Deoptimizer::AddDoubleValue(intptr_t slot_address, double value) {
2784 HeapNumberMaterializationDescriptor<Address> value_desc(
2785 reinterpret_cast<Address>(slot_address), value);
2786 deferred_heap_numbers_.Add(value_desc);
2787 }
2788
2789
EnsureCodeForDeoptimizationEntry(Isolate * isolate,BailoutType type,int max_entry_id)2790 void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate,
2791 BailoutType type,
2792 int max_entry_id) {
2793 // We cannot run this if the serializer is enabled because this will
2794 // cause us to emit relocation information for the external
2795 // references. This is fine because the deoptimizer's code section
2796 // isn't meant to be serialized at all.
2797 CHECK(type == EAGER || type == SOFT || type == LAZY);
2798 DeoptimizerData* data = isolate->deoptimizer_data();
2799 int entry_count = data->deopt_entry_code_entries_[type];
2800 if (max_entry_id < entry_count) return;
2801 entry_count = Max(entry_count, Deoptimizer::kMinNumberOfEntries);
2802 while (max_entry_id >= entry_count) entry_count *= 2;
2803 CHECK(entry_count <= Deoptimizer::kMaxNumberOfEntries);
2804
2805 MacroAssembler masm(isolate, NULL, 16 * KB);
2806 masm.set_emit_debug_code(false);
2807 GenerateDeoptimizationEntries(&masm, entry_count, type);
2808 CodeDesc desc;
2809 masm.GetCode(&desc);
2810 DCHECK(!RelocInfo::RequiresRelocation(desc));
2811
2812 MemoryChunk* chunk = data->deopt_entry_code_[type];
2813 CHECK(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >=
2814 desc.instr_size);
2815 chunk->CommitArea(desc.instr_size);
2816 CopyBytes(chunk->area_start(), desc.buffer,
2817 static_cast<size_t>(desc.instr_size));
2818 CpuFeatures::FlushICache(chunk->area_start(), desc.instr_size);
2819
2820 data->deopt_entry_code_entries_[type] = entry_count;
2821 }
2822
2823
FrameDescription(uint32_t frame_size,JSFunction * function)2824 FrameDescription::FrameDescription(uint32_t frame_size,
2825 JSFunction* function)
2826 : frame_size_(frame_size),
2827 function_(function),
2828 top_(kZapUint32),
2829 pc_(kZapUint32),
2830 fp_(kZapUint32),
2831 context_(kZapUint32),
2832 constant_pool_(kZapUint32) {
2833 // Zap all the registers.
2834 for (int r = 0; r < Register::kNumRegisters; r++) {
2835 // TODO(jbramley): It isn't safe to use kZapUint32 here. If the register
2836 // isn't used before the next safepoint, the GC will try to scan it as a
2837 // tagged value. kZapUint32 looks like a valid tagged pointer, but it isn't.
2838 SetRegister(r, kZapUint32);
2839 }
2840
2841 // Zap all the slots.
2842 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
2843 SetFrameSlot(o, kZapUint32);
2844 }
2845 }
2846
2847
ComputeFixedSize()2848 int FrameDescription::ComputeFixedSize() {
2849 return StandardFrameConstants::kFixedFrameSize +
2850 (ComputeParametersCount() + 1) * kPointerSize;
2851 }
2852
2853
GetOffsetFromSlotIndex(int slot_index)2854 unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) {
2855 if (slot_index >= 0) {
2856 // Local or spill slots. Skip the fixed part of the frame
2857 // including all arguments.
2858 unsigned base = GetFrameSize() - ComputeFixedSize();
2859 return base - ((slot_index + 1) * kPointerSize);
2860 } else {
2861 // Incoming parameter.
2862 int arg_size = (ComputeParametersCount() + 1) * kPointerSize;
2863 unsigned base = GetFrameSize() - arg_size;
2864 return base - ((slot_index + 1) * kPointerSize);
2865 }
2866 }
2867
2868
ComputeParametersCount()2869 int FrameDescription::ComputeParametersCount() {
2870 switch (type_) {
2871 case StackFrame::JAVA_SCRIPT:
2872 return function_->shared()->formal_parameter_count();
2873 case StackFrame::ARGUMENTS_ADAPTOR: {
2874 // Last slot contains number of incomming arguments as a smi.
2875 // Can't use GetExpression(0) because it would cause infinite recursion.
2876 return reinterpret_cast<Smi*>(*GetFrameSlotPointer(0))->value();
2877 }
2878 case StackFrame::STUB:
2879 return -1; // Minus receiver.
2880 default:
2881 FATAL("Unexpected stack frame type");
2882 return 0;
2883 }
2884 }
2885
2886
GetParameter(int index)2887 Object* FrameDescription::GetParameter(int index) {
2888 CHECK_GE(index, 0);
2889 CHECK_LT(index, ComputeParametersCount());
2890 // The slot indexes for incoming arguments are negative.
2891 unsigned offset = GetOffsetFromSlotIndex(index - ComputeParametersCount());
2892 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
2893 }
2894
2895
GetExpressionCount()2896 unsigned FrameDescription::GetExpressionCount() {
2897 CHECK_EQ(StackFrame::JAVA_SCRIPT, type_);
2898 unsigned size = GetFrameSize() - ComputeFixedSize();
2899 return size / kPointerSize;
2900 }
2901
2902
GetExpression(int index)2903 Object* FrameDescription::GetExpression(int index) {
2904 DCHECK_EQ(StackFrame::JAVA_SCRIPT, type_);
2905 unsigned offset = GetOffsetFromSlotIndex(index);
2906 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
2907 }
2908
2909
Add(int32_t value,Zone * zone)2910 void TranslationBuffer::Add(int32_t value, Zone* zone) {
2911 // Encode the sign bit in the least significant bit.
2912 bool is_negative = (value < 0);
2913 uint32_t bits = ((is_negative ? -value : value) << 1) |
2914 static_cast<int32_t>(is_negative);
2915 // Encode the individual bytes using the least significant bit of
2916 // each byte to indicate whether or not more bytes follow.
2917 do {
2918 uint32_t next = bits >> 7;
2919 contents_.Add(((bits << 1) & 0xFF) | (next != 0), zone);
2920 bits = next;
2921 } while (bits != 0);
2922 }
2923
2924
Next()2925 int32_t TranslationIterator::Next() {
2926 // Run through the bytes until we reach one with a least significant
2927 // bit of zero (marks the end).
2928 uint32_t bits = 0;
2929 for (int i = 0; true; i += 7) {
2930 DCHECK(HasNext());
2931 uint8_t next = buffer_->get(index_++);
2932 bits |= (next >> 1) << i;
2933 if ((next & 1) == 0) break;
2934 }
2935 // The bits encode the sign in the least significant bit.
2936 bool is_negative = (bits & 1) == 1;
2937 int32_t result = bits >> 1;
2938 return is_negative ? -result : result;
2939 }
2940
2941
CreateByteArray(Factory * factory)2942 Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
2943 int length = contents_.length();
2944 Handle<ByteArray> result = factory->NewByteArray(length, TENURED);
2945 MemCopy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
2946 return result;
2947 }
2948
2949
BeginConstructStubFrame(int literal_id,unsigned height)2950 void Translation::BeginConstructStubFrame(int literal_id, unsigned height) {
2951 buffer_->Add(CONSTRUCT_STUB_FRAME, zone());
2952 buffer_->Add(literal_id, zone());
2953 buffer_->Add(height, zone());
2954 }
2955
2956
BeginGetterStubFrame(int literal_id)2957 void Translation::BeginGetterStubFrame(int literal_id) {
2958 buffer_->Add(GETTER_STUB_FRAME, zone());
2959 buffer_->Add(literal_id, zone());
2960 }
2961
2962
BeginSetterStubFrame(int literal_id)2963 void Translation::BeginSetterStubFrame(int literal_id) {
2964 buffer_->Add(SETTER_STUB_FRAME, zone());
2965 buffer_->Add(literal_id, zone());
2966 }
2967
2968
BeginArgumentsAdaptorFrame(int literal_id,unsigned height)2969 void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
2970 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone());
2971 buffer_->Add(literal_id, zone());
2972 buffer_->Add(height, zone());
2973 }
2974
2975
BeginJSFrame(BailoutId node_id,int literal_id,unsigned height)2976 void Translation::BeginJSFrame(BailoutId node_id,
2977 int literal_id,
2978 unsigned height) {
2979 buffer_->Add(JS_FRAME, zone());
2980 buffer_->Add(node_id.ToInt(), zone());
2981 buffer_->Add(literal_id, zone());
2982 buffer_->Add(height, zone());
2983 }
2984
2985
BeginCompiledStubFrame()2986 void Translation::BeginCompiledStubFrame() {
2987 buffer_->Add(COMPILED_STUB_FRAME, zone());
2988 }
2989
2990
BeginArgumentsObject(int args_length)2991 void Translation::BeginArgumentsObject(int args_length) {
2992 buffer_->Add(ARGUMENTS_OBJECT, zone());
2993 buffer_->Add(args_length, zone());
2994 }
2995
2996
BeginCapturedObject(int length)2997 void Translation::BeginCapturedObject(int length) {
2998 buffer_->Add(CAPTURED_OBJECT, zone());
2999 buffer_->Add(length, zone());
3000 }
3001
3002
DuplicateObject(int object_index)3003 void Translation::DuplicateObject(int object_index) {
3004 buffer_->Add(DUPLICATED_OBJECT, zone());
3005 buffer_->Add(object_index, zone());
3006 }
3007
3008
StoreRegister(Register reg)3009 void Translation::StoreRegister(Register reg) {
3010 buffer_->Add(REGISTER, zone());
3011 buffer_->Add(reg.code(), zone());
3012 }
3013
3014
StoreInt32Register(Register reg)3015 void Translation::StoreInt32Register(Register reg) {
3016 buffer_->Add(INT32_REGISTER, zone());
3017 buffer_->Add(reg.code(), zone());
3018 }
3019
3020
StoreUint32Register(Register reg)3021 void Translation::StoreUint32Register(Register reg) {
3022 buffer_->Add(UINT32_REGISTER, zone());
3023 buffer_->Add(reg.code(), zone());
3024 }
3025
3026
StoreDoubleRegister(DoubleRegister reg)3027 void Translation::StoreDoubleRegister(DoubleRegister reg) {
3028 buffer_->Add(DOUBLE_REGISTER, zone());
3029 buffer_->Add(DoubleRegister::ToAllocationIndex(reg), zone());
3030 }
3031
3032
StoreStackSlot(int index)3033 void Translation::StoreStackSlot(int index) {
3034 buffer_->Add(STACK_SLOT, zone());
3035 buffer_->Add(index, zone());
3036 }
3037
3038
StoreInt32StackSlot(int index)3039 void Translation::StoreInt32StackSlot(int index) {
3040 buffer_->Add(INT32_STACK_SLOT, zone());
3041 buffer_->Add(index, zone());
3042 }
3043
3044
StoreUint32StackSlot(int index)3045 void Translation::StoreUint32StackSlot(int index) {
3046 buffer_->Add(UINT32_STACK_SLOT, zone());
3047 buffer_->Add(index, zone());
3048 }
3049
3050
StoreDoubleStackSlot(int index)3051 void Translation::StoreDoubleStackSlot(int index) {
3052 buffer_->Add(DOUBLE_STACK_SLOT, zone());
3053 buffer_->Add(index, zone());
3054 }
3055
3056
StoreLiteral(int literal_id)3057 void Translation::StoreLiteral(int literal_id) {
3058 buffer_->Add(LITERAL, zone());
3059 buffer_->Add(literal_id, zone());
3060 }
3061
3062
StoreArgumentsObject(bool args_known,int args_index,int args_length)3063 void Translation::StoreArgumentsObject(bool args_known,
3064 int args_index,
3065 int args_length) {
3066 buffer_->Add(ARGUMENTS_OBJECT, zone());
3067 buffer_->Add(args_known, zone());
3068 buffer_->Add(args_index, zone());
3069 buffer_->Add(args_length, zone());
3070 }
3071
3072
NumberOfOperandsFor(Opcode opcode)3073 int Translation::NumberOfOperandsFor(Opcode opcode) {
3074 switch (opcode) {
3075 case GETTER_STUB_FRAME:
3076 case SETTER_STUB_FRAME:
3077 case DUPLICATED_OBJECT:
3078 case ARGUMENTS_OBJECT:
3079 case CAPTURED_OBJECT:
3080 case REGISTER:
3081 case INT32_REGISTER:
3082 case UINT32_REGISTER:
3083 case DOUBLE_REGISTER:
3084 case STACK_SLOT:
3085 case INT32_STACK_SLOT:
3086 case UINT32_STACK_SLOT:
3087 case DOUBLE_STACK_SLOT:
3088 case LITERAL:
3089 case COMPILED_STUB_FRAME:
3090 return 1;
3091 case BEGIN:
3092 case ARGUMENTS_ADAPTOR_FRAME:
3093 case CONSTRUCT_STUB_FRAME:
3094 return 2;
3095 case JS_FRAME:
3096 return 3;
3097 }
3098 FATAL("Unexpected translation type");
3099 return -1;
3100 }
3101
3102
3103 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
3104
StringFor(Opcode opcode)3105 const char* Translation::StringFor(Opcode opcode) {
3106 #define TRANSLATION_OPCODE_CASE(item) case item: return #item;
3107 switch (opcode) {
3108 TRANSLATION_OPCODE_LIST(TRANSLATION_OPCODE_CASE)
3109 }
3110 #undef TRANSLATION_OPCODE_CASE
3111 UNREACHABLE();
3112 return "";
3113 }
3114
3115 #endif
3116
3117
3118 // We can't intermix stack decoding and allocations because
3119 // deoptimization infrastracture is not GC safe.
3120 // Thus we build a temporary structure in malloced space.
ComputeSlotForNextArgument(Translation::Opcode opcode,TranslationIterator * iterator,DeoptimizationInputData * data,JavaScriptFrame * frame)3121 SlotRef SlotRefValueBuilder::ComputeSlotForNextArgument(
3122 Translation::Opcode opcode,
3123 TranslationIterator* iterator,
3124 DeoptimizationInputData* data,
3125 JavaScriptFrame* frame) {
3126 switch (opcode) {
3127 case Translation::BEGIN:
3128 case Translation::JS_FRAME:
3129 case Translation::ARGUMENTS_ADAPTOR_FRAME:
3130 case Translation::CONSTRUCT_STUB_FRAME:
3131 case Translation::GETTER_STUB_FRAME:
3132 case Translation::SETTER_STUB_FRAME:
3133 // Peeled off before getting here.
3134 break;
3135
3136 case Translation::DUPLICATED_OBJECT: {
3137 return SlotRef::NewDuplicateObject(iterator->Next());
3138 }
3139
3140 case Translation::ARGUMENTS_OBJECT:
3141 return SlotRef::NewArgumentsObject(iterator->Next());
3142
3143 case Translation::CAPTURED_OBJECT: {
3144 return SlotRef::NewDeferredObject(iterator->Next());
3145 }
3146
3147 case Translation::REGISTER:
3148 case Translation::INT32_REGISTER:
3149 case Translation::UINT32_REGISTER:
3150 case Translation::DOUBLE_REGISTER:
3151 // We are at safepoint which corresponds to call. All registers are
3152 // saved by caller so there would be no live registers at this
3153 // point. Thus these translation commands should not be used.
3154 break;
3155
3156 case Translation::STACK_SLOT: {
3157 int slot_index = iterator->Next();
3158 Address slot_addr = SlotAddress(frame, slot_index);
3159 return SlotRef(slot_addr, SlotRef::TAGGED);
3160 }
3161
3162 case Translation::INT32_STACK_SLOT: {
3163 int slot_index = iterator->Next();
3164 Address slot_addr = SlotAddress(frame, slot_index);
3165 return SlotRef(slot_addr, SlotRef::INT32);
3166 }
3167
3168 case Translation::UINT32_STACK_SLOT: {
3169 int slot_index = iterator->Next();
3170 Address slot_addr = SlotAddress(frame, slot_index);
3171 return SlotRef(slot_addr, SlotRef::UINT32);
3172 }
3173
3174 case Translation::DOUBLE_STACK_SLOT: {
3175 int slot_index = iterator->Next();
3176 Address slot_addr = SlotAddress(frame, slot_index);
3177 return SlotRef(slot_addr, SlotRef::DOUBLE);
3178 }
3179
3180 case Translation::LITERAL: {
3181 int literal_index = iterator->Next();
3182 return SlotRef(data->GetIsolate(),
3183 data->LiteralArray()->get(literal_index));
3184 }
3185
3186 case Translation::COMPILED_STUB_FRAME:
3187 UNREACHABLE();
3188 break;
3189 }
3190
3191 FATAL("We should never get here - unexpected deopt info.");
3192 return SlotRef();
3193 }
3194
3195
SlotRefValueBuilder(JavaScriptFrame * frame,int inlined_jsframe_index,int formal_parameter_count)3196 SlotRefValueBuilder::SlotRefValueBuilder(JavaScriptFrame* frame,
3197 int inlined_jsframe_index,
3198 int formal_parameter_count)
3199 : current_slot_(0), args_length_(-1), first_slot_index_(-1) {
3200 DisallowHeapAllocation no_gc;
3201
3202 int deopt_index = Safepoint::kNoDeoptimizationIndex;
3203 DeoptimizationInputData* data =
3204 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
3205 TranslationIterator it(data->TranslationByteArray(),
3206 data->TranslationIndex(deopt_index)->value());
3207 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
3208 CHECK_EQ(opcode, Translation::BEGIN);
3209 it.Next(); // Drop frame count.
3210
3211 stack_frame_id_ = frame->fp();
3212
3213 int jsframe_count = it.Next();
3214 CHECK_GT(jsframe_count, inlined_jsframe_index);
3215 int jsframes_to_skip = inlined_jsframe_index;
3216 int number_of_slots = -1; // Number of slots inside our frame (yet unknown)
3217 bool should_deopt = false;
3218 while (number_of_slots != 0) {
3219 opcode = static_cast<Translation::Opcode>(it.Next());
3220 bool processed = false;
3221 if (opcode == Translation::ARGUMENTS_ADAPTOR_FRAME) {
3222 if (jsframes_to_skip == 0) {
3223 CHECK_EQ(Translation::NumberOfOperandsFor(opcode), 2);
3224
3225 it.Skip(1); // literal id
3226 int height = it.Next();
3227
3228 // Skip the translation command for the receiver.
3229 it.Skip(Translation::NumberOfOperandsFor(
3230 static_cast<Translation::Opcode>(it.Next())));
3231
3232 // We reached the arguments adaptor frame corresponding to the
3233 // inlined function in question. Number of arguments is height - 1.
3234 first_slot_index_ = slot_refs_.length();
3235 args_length_ = height - 1;
3236 number_of_slots = height - 1;
3237 processed = true;
3238 }
3239 } else if (opcode == Translation::JS_FRAME) {
3240 if (jsframes_to_skip == 0) {
3241 // Skip over operands to advance to the next opcode.
3242 it.Skip(Translation::NumberOfOperandsFor(opcode));
3243
3244 // Skip the translation command for the receiver.
3245 it.Skip(Translation::NumberOfOperandsFor(
3246 static_cast<Translation::Opcode>(it.Next())));
3247
3248 // We reached the frame corresponding to the inlined function
3249 // in question. Process the translation commands for the
3250 // arguments. Number of arguments is equal to the number of
3251 // format parameter count.
3252 first_slot_index_ = slot_refs_.length();
3253 args_length_ = formal_parameter_count;
3254 number_of_slots = formal_parameter_count;
3255 processed = true;
3256 }
3257 jsframes_to_skip--;
3258 } else if (opcode != Translation::BEGIN &&
3259 opcode != Translation::CONSTRUCT_STUB_FRAME &&
3260 opcode != Translation::GETTER_STUB_FRAME &&
3261 opcode != Translation::SETTER_STUB_FRAME &&
3262 opcode != Translation::COMPILED_STUB_FRAME) {
3263 slot_refs_.Add(ComputeSlotForNextArgument(opcode, &it, data, frame));
3264
3265 if (first_slot_index_ >= 0) {
3266 // We have found the beginning of our frame -> make sure we count
3267 // the nested slots of captured objects
3268 number_of_slots--;
3269 SlotRef& slot = slot_refs_.last();
3270 CHECK_NE(slot.Representation(), SlotRef::ARGUMENTS_OBJECT);
3271 number_of_slots += slot.GetChildrenCount();
3272 if (slot.Representation() == SlotRef::DEFERRED_OBJECT ||
3273 slot.Representation() == SlotRef::DUPLICATE_OBJECT) {
3274 should_deopt = true;
3275 }
3276 }
3277
3278 processed = true;
3279 }
3280 if (!processed) {
3281 // Skip over operands to advance to the next opcode.
3282 it.Skip(Translation::NumberOfOperandsFor(opcode));
3283 }
3284 }
3285 if (should_deopt) {
3286 List<JSFunction*> functions(2);
3287 frame->GetFunctions(&functions);
3288 Deoptimizer::DeoptimizeFunction(functions[0]);
3289 }
3290 }
3291
3292
GetValue(Isolate * isolate)3293 Handle<Object> SlotRef::GetValue(Isolate* isolate) {
3294 switch (representation_) {
3295 case TAGGED:
3296 return Handle<Object>(Memory::Object_at(addr_), isolate);
3297
3298 case INT32: {
3299 #if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT
3300 int value = Memory::int32_at(addr_ + kIntSize);
3301 #else
3302 int value = Memory::int32_at(addr_);
3303 #endif
3304 if (Smi::IsValid(value)) {
3305 return Handle<Object>(Smi::FromInt(value), isolate);
3306 } else {
3307 return isolate->factory()->NewNumberFromInt(value);
3308 }
3309 }
3310
3311 case UINT32: {
3312 #if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT
3313 uint32_t value = Memory::uint32_at(addr_ + kIntSize);
3314 #else
3315 uint32_t value = Memory::uint32_at(addr_);
3316 #endif
3317 if (value <= static_cast<uint32_t>(Smi::kMaxValue)) {
3318 return Handle<Object>(Smi::FromInt(static_cast<int>(value)), isolate);
3319 } else {
3320 return isolate->factory()->NewNumber(static_cast<double>(value));
3321 }
3322 }
3323
3324 case DOUBLE: {
3325 double value = read_double_value(addr_);
3326 return isolate->factory()->NewNumber(value);
3327 }
3328
3329 case LITERAL:
3330 return literal_;
3331
3332 default:
3333 FATAL("We should never get here - unexpected deopt info.");
3334 return Handle<Object>::null();
3335 }
3336 }
3337
3338
Prepare(Isolate * isolate)3339 void SlotRefValueBuilder::Prepare(Isolate* isolate) {
3340 MaterializedObjectStore* materialized_store =
3341 isolate->materialized_object_store();
3342 previously_materialized_objects_ = materialized_store->Get(stack_frame_id_);
3343 prev_materialized_count_ = previously_materialized_objects_.is_null()
3344 ? 0 : previously_materialized_objects_->length();
3345
3346 // Skip any materialized objects of the inlined "parent" frames.
3347 // (Note that we still need to materialize them because they might be
3348 // referred to as duplicated objects.)
3349 while (current_slot_ < first_slot_index_) {
3350 GetNext(isolate, 0);
3351 }
3352 CHECK_EQ(current_slot_, first_slot_index_);
3353 }
3354
3355
GetPreviouslyMaterialized(Isolate * isolate,int length)3356 Handle<Object> SlotRefValueBuilder::GetPreviouslyMaterialized(
3357 Isolate* isolate, int length) {
3358 int object_index = materialized_objects_.length();
3359 Handle<Object> return_value = Handle<Object>(
3360 previously_materialized_objects_->get(object_index), isolate);
3361 materialized_objects_.Add(return_value);
3362
3363 // Now need to skip all the nested objects (and possibly read them from
3364 // the materialization store, too).
3365 for (int i = 0; i < length; i++) {
3366 SlotRef& slot = slot_refs_[current_slot_];
3367 current_slot_++;
3368
3369 // We need to read all the nested objects - add them to the
3370 // number of objects we need to process.
3371 length += slot.GetChildrenCount();
3372
3373 // Put the nested deferred/duplicate objects into our materialization
3374 // array.
3375 if (slot.Representation() == SlotRef::DEFERRED_OBJECT ||
3376 slot.Representation() == SlotRef::DUPLICATE_OBJECT) {
3377 int nested_object_index = materialized_objects_.length();
3378 Handle<Object> nested_object = Handle<Object>(
3379 previously_materialized_objects_->get(nested_object_index),
3380 isolate);
3381 materialized_objects_.Add(nested_object);
3382 }
3383 }
3384
3385 return return_value;
3386 }
3387
3388
GetNext(Isolate * isolate,int lvl)3389 Handle<Object> SlotRefValueBuilder::GetNext(Isolate* isolate, int lvl) {
3390 SlotRef& slot = slot_refs_[current_slot_];
3391 current_slot_++;
3392 switch (slot.Representation()) {
3393 case SlotRef::TAGGED:
3394 case SlotRef::INT32:
3395 case SlotRef::UINT32:
3396 case SlotRef::DOUBLE:
3397 case SlotRef::LITERAL: {
3398 return slot.GetValue(isolate);
3399 }
3400 case SlotRef::ARGUMENTS_OBJECT: {
3401 // We should never need to materialize an arguments object,
3402 // but we still need to put something into the array
3403 // so that the indexing is consistent.
3404 materialized_objects_.Add(isolate->factory()->undefined_value());
3405 int length = slot.GetChildrenCount();
3406 for (int i = 0; i < length; ++i) {
3407 // We don't need the argument, just ignore it
3408 GetNext(isolate, lvl + 1);
3409 }
3410 return isolate->factory()->undefined_value();
3411 }
3412 case SlotRef::DEFERRED_OBJECT: {
3413 int length = slot.GetChildrenCount();
3414 CHECK(slot_refs_[current_slot_].Representation() == SlotRef::LITERAL ||
3415 slot_refs_[current_slot_].Representation() == SlotRef::TAGGED);
3416
3417 int object_index = materialized_objects_.length();
3418 if (object_index < prev_materialized_count_) {
3419 return GetPreviouslyMaterialized(isolate, length);
3420 }
3421
3422 Handle<Object> map_object = slot_refs_[current_slot_].GetValue(isolate);
3423 Handle<Map> map = Map::GeneralizeAllFieldRepresentations(
3424 Handle<Map>::cast(map_object));
3425 current_slot_++;
3426 // TODO(jarin) this should be unified with the code in
3427 // Deoptimizer::MaterializeNextHeapObject()
3428 switch (map->instance_type()) {
3429 case MUTABLE_HEAP_NUMBER_TYPE:
3430 case HEAP_NUMBER_TYPE: {
3431 // Reuse the HeapNumber value directly as it is already properly
3432 // tagged and skip materializing the HeapNumber explicitly.
3433 Handle<Object> object = GetNext(isolate, lvl + 1);
3434 materialized_objects_.Add(object);
3435 // On 32-bit architectures, there is an extra slot there because
3436 // the escape analysis calculates the number of slots as
3437 // object-size/pointer-size. To account for this, we read out
3438 // any extra slots.
3439 for (int i = 0; i < length - 2; i++) {
3440 GetNext(isolate, lvl + 1);
3441 }
3442 return object;
3443 }
3444 case JS_OBJECT_TYPE: {
3445 Handle<JSObject> object =
3446 isolate->factory()->NewJSObjectFromMap(map, NOT_TENURED, false);
3447 materialized_objects_.Add(object);
3448 Handle<Object> properties = GetNext(isolate, lvl + 1);
3449 Handle<Object> elements = GetNext(isolate, lvl + 1);
3450 object->set_properties(FixedArray::cast(*properties));
3451 object->set_elements(FixedArrayBase::cast(*elements));
3452 for (int i = 0; i < length - 3; ++i) {
3453 Handle<Object> value = GetNext(isolate, lvl + 1);
3454 FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i);
3455 object->FastPropertyAtPut(index, *value);
3456 }
3457 return object;
3458 }
3459 case JS_ARRAY_TYPE: {
3460 Handle<JSArray> object =
3461 isolate->factory()->NewJSArray(0, map->elements_kind());
3462 materialized_objects_.Add(object);
3463 Handle<Object> properties = GetNext(isolate, lvl + 1);
3464 Handle<Object> elements = GetNext(isolate, lvl + 1);
3465 Handle<Object> length = GetNext(isolate, lvl + 1);
3466 object->set_properties(FixedArray::cast(*properties));
3467 object->set_elements(FixedArrayBase::cast(*elements));
3468 object->set_length(*length);
3469 return object;
3470 }
3471 default:
3472 PrintF(stderr,
3473 "[couldn't handle instance type %d]\n", map->instance_type());
3474 UNREACHABLE();
3475 break;
3476 }
3477 UNREACHABLE();
3478 break;
3479 }
3480
3481 case SlotRef::DUPLICATE_OBJECT: {
3482 int object_index = slot.DuplicateObjectId();
3483 Handle<Object> object = materialized_objects_[object_index];
3484 materialized_objects_.Add(object);
3485 return object;
3486 }
3487 default:
3488 UNREACHABLE();
3489 break;
3490 }
3491
3492 FATAL("We should never get here - unexpected deopt slot kind.");
3493 return Handle<Object>::null();
3494 }
3495
3496
Finish(Isolate * isolate)3497 void SlotRefValueBuilder::Finish(Isolate* isolate) {
3498 // We should have processed all the slots
3499 CHECK_EQ(slot_refs_.length(), current_slot_);
3500
3501 if (materialized_objects_.length() > prev_materialized_count_) {
3502 // We have materialized some new objects, so we have to store them
3503 // to prevent duplicate materialization
3504 Handle<FixedArray> array = isolate->factory()->NewFixedArray(
3505 materialized_objects_.length());
3506 for (int i = 0; i < materialized_objects_.length(); i++) {
3507 array->set(i, *(materialized_objects_.at(i)));
3508 }
3509 isolate->materialized_object_store()->Set(stack_frame_id_, array);
3510 }
3511 }
3512
3513
Get(Address fp)3514 Handle<FixedArray> MaterializedObjectStore::Get(Address fp) {
3515 int index = StackIdToIndex(fp);
3516 if (index == -1) {
3517 return Handle<FixedArray>::null();
3518 }
3519 Handle<FixedArray> array = GetStackEntries();
3520 CHECK_GT(array->length(), index);
3521 return Handle<FixedArray>::cast(Handle<Object>(array->get(index),
3522 isolate()));
3523 }
3524
3525
Set(Address fp,Handle<FixedArray> materialized_objects)3526 void MaterializedObjectStore::Set(Address fp,
3527 Handle<FixedArray> materialized_objects) {
3528 int index = StackIdToIndex(fp);
3529 if (index == -1) {
3530 index = frame_fps_.length();
3531 frame_fps_.Add(fp);
3532 }
3533
3534 Handle<FixedArray> array = EnsureStackEntries(index + 1);
3535 array->set(index, *materialized_objects);
3536 }
3537
3538
Remove(Address fp)3539 void MaterializedObjectStore::Remove(Address fp) {
3540 int index = StackIdToIndex(fp);
3541 CHECK_GE(index, 0);
3542
3543 frame_fps_.Remove(index);
3544 Handle<FixedArray> array = GetStackEntries();
3545 CHECK_LT(index, array->length());
3546 for (int i = index; i < frame_fps_.length(); i++) {
3547 array->set(i, array->get(i + 1));
3548 }
3549 array->set(frame_fps_.length(), isolate()->heap()->undefined_value());
3550 }
3551
3552
StackIdToIndex(Address fp)3553 int MaterializedObjectStore::StackIdToIndex(Address fp) {
3554 for (int i = 0; i < frame_fps_.length(); i++) {
3555 if (frame_fps_[i] == fp) {
3556 return i;
3557 }
3558 }
3559 return -1;
3560 }
3561
3562
GetStackEntries()3563 Handle<FixedArray> MaterializedObjectStore::GetStackEntries() {
3564 return Handle<FixedArray>(isolate()->heap()->materialized_objects());
3565 }
3566
3567
EnsureStackEntries(int length)3568 Handle<FixedArray> MaterializedObjectStore::EnsureStackEntries(int length) {
3569 Handle<FixedArray> array = GetStackEntries();
3570 if (array->length() >= length) {
3571 return array;
3572 }
3573
3574 int new_length = length > 10 ? length : 10;
3575 if (new_length < 2 * array->length()) {
3576 new_length = 2 * array->length();
3577 }
3578
3579 Handle<FixedArray> new_array =
3580 isolate()->factory()->NewFixedArray(new_length, TENURED);
3581 for (int i = 0; i < array->length(); i++) {
3582 new_array->set(i, array->get(i));
3583 }
3584 for (int i = array->length(); i < length; i++) {
3585 new_array->set(i, isolate()->heap()->undefined_value());
3586 }
3587 isolate()->heap()->public_set_materialized_objects(*new_array);
3588 return new_array;
3589 }
3590
3591
DeoptimizedFrameInfo(Deoptimizer * deoptimizer,int frame_index,bool has_arguments_adaptor,bool has_construct_stub)3592 DeoptimizedFrameInfo::DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
3593 int frame_index,
3594 bool has_arguments_adaptor,
3595 bool has_construct_stub) {
3596 FrameDescription* output_frame = deoptimizer->output_[frame_index];
3597 function_ = output_frame->GetFunction();
3598 context_ = reinterpret_cast<Object*>(output_frame->GetContext());
3599 has_construct_stub_ = has_construct_stub;
3600 expression_count_ = output_frame->GetExpressionCount();
3601 expression_stack_ = new Object*[expression_count_];
3602 // Get the source position using the unoptimized code.
3603 Address pc = reinterpret_cast<Address>(output_frame->GetPc());
3604 Code* code = Code::cast(deoptimizer->isolate()->FindCodeObject(pc));
3605 source_position_ = code->SourcePosition(pc);
3606
3607 for (int i = 0; i < expression_count_; i++) {
3608 SetExpression(i, output_frame->GetExpression(i));
3609 }
3610
3611 if (has_arguments_adaptor) {
3612 output_frame = deoptimizer->output_[frame_index - 1];
3613 CHECK_EQ(output_frame->GetFrameType(), StackFrame::ARGUMENTS_ADAPTOR);
3614 }
3615
3616 parameters_count_ = output_frame->ComputeParametersCount();
3617 parameters_ = new Object*[parameters_count_];
3618 for (int i = 0; i < parameters_count_; i++) {
3619 SetParameter(i, output_frame->GetParameter(i));
3620 }
3621 }
3622
3623
~DeoptimizedFrameInfo()3624 DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
3625 delete[] expression_stack_;
3626 delete[] parameters_;
3627 }
3628
3629
Iterate(ObjectVisitor * v)3630 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
3631 v->VisitPointer(bit_cast<Object**>(&function_));
3632 v->VisitPointer(&context_);
3633 v->VisitPointers(parameters_, parameters_ + parameters_count_);
3634 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
3635 }
3636
3637 } } // namespace v8::internal
3638