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