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