1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/deoptimizer.h"
6 
7 #include <memory>
8 
9 #include "src/accessors.h"
10 #include "src/ast/prettyprinter.h"
11 #include "src/codegen.h"
12 #include "src/disasm.h"
13 #include "src/frames-inl.h"
14 #include "src/full-codegen/full-codegen.h"
15 #include "src/global-handles.h"
16 #include "src/interpreter/interpreter.h"
17 #include "src/macro-assembler.h"
18 #include "src/tracing/trace-event.h"
19 #include "src/v8.h"
20 
21 
22 namespace v8 {
23 namespace internal {
24 
AllocateCodeChunk(MemoryAllocator * allocator)25 static MemoryChunk* AllocateCodeChunk(MemoryAllocator* allocator) {
26   return allocator->AllocateChunk(Deoptimizer::GetMaxDeoptTableSize(),
27                                   MemoryAllocator::GetCommitPageSize(),
28                                   EXECUTABLE, NULL);
29 }
30 
31 
DeoptimizerData(MemoryAllocator * allocator)32 DeoptimizerData::DeoptimizerData(MemoryAllocator* allocator)
33     : allocator_(allocator),
34       current_(NULL) {
35   for (int i = 0; i <= Deoptimizer::kLastBailoutType; ++i) {
36     deopt_entry_code_entries_[i] = -1;
37     deopt_entry_code_[i] = AllocateCodeChunk(allocator);
38   }
39 }
40 
41 
~DeoptimizerData()42 DeoptimizerData::~DeoptimizerData() {
43   for (int i = 0; i <= Deoptimizer::kLastBailoutType; ++i) {
44     allocator_->Free<MemoryAllocator::kFull>(deopt_entry_code_[i]);
45     deopt_entry_code_[i] = NULL;
46   }
47 }
48 
49 
FindDeoptimizingCode(Address addr)50 Code* Deoptimizer::FindDeoptimizingCode(Address addr) {
51   if (function_->IsHeapObject()) {
52     // Search all deoptimizing code in the native context of the function.
53     Isolate* isolate = function_->GetIsolate();
54     Context* native_context = function_->context()->native_context();
55     Object* element = native_context->DeoptimizedCodeListHead();
56     while (!element->IsUndefined(isolate)) {
57       Code* code = Code::cast(element);
58       CHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
59       if (code->contains(addr)) return code;
60       element = code->next_code_link();
61     }
62   }
63   return NULL;
64 }
65 
66 
67 // We rely on this function not causing a GC.  It is called from generated code
68 // 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)69 Deoptimizer* Deoptimizer::New(JSFunction* function,
70                               BailoutType type,
71                               unsigned bailout_id,
72                               Address from,
73                               int fp_to_sp_delta,
74                               Isolate* isolate) {
75   Deoptimizer* deoptimizer = new Deoptimizer(isolate, function, type,
76                                              bailout_id, from, fp_to_sp_delta);
77   CHECK(isolate->deoptimizer_data()->current_ == NULL);
78   isolate->deoptimizer_data()->current_ = deoptimizer;
79   return deoptimizer;
80 }
81 
82 
83 // No larger than 2K on all platforms
84 static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB;
85 
86 
GetMaxDeoptTableSize()87 size_t Deoptimizer::GetMaxDeoptTableSize() {
88   int entries_size =
89       Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_;
90   int commit_page_size = static_cast<int>(MemoryAllocator::GetCommitPageSize());
91   int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) /
92                     commit_page_size) + 1;
93   return static_cast<size_t>(commit_page_size * page_count);
94 }
95 
96 
Grab(Isolate * isolate)97 Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
98   Deoptimizer* result = isolate->deoptimizer_data()->current_;
99   CHECK_NOT_NULL(result);
100   result->DeleteFrameDescriptions();
101   isolate->deoptimizer_data()->current_ = NULL;
102   return result;
103 }
104 
DebuggerInspectableFrame(JavaScriptFrame * frame,int jsframe_index,Isolate * isolate)105 DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
106     JavaScriptFrame* frame,
107     int jsframe_index,
108     Isolate* isolate) {
109   CHECK(frame->is_optimized());
110 
111   TranslatedState translated_values(frame);
112   translated_values.Prepare(false, frame->fp());
113 
114   TranslatedState::iterator frame_it = translated_values.end();
115   int counter = jsframe_index;
116   for (auto it = translated_values.begin(); it != translated_values.end();
117        it++) {
118     if (it->kind() == TranslatedFrame::kFunction ||
119         it->kind() == TranslatedFrame::kInterpretedFunction) {
120       if (counter == 0) {
121         frame_it = it;
122         break;
123       }
124       counter--;
125     }
126   }
127   CHECK(frame_it != translated_values.end());
128 
129   DeoptimizedFrameInfo* info =
130       new DeoptimizedFrameInfo(&translated_values, frame_it, isolate);
131 
132   return info;
133 }
134 
GenerateDeoptimizationEntries(MacroAssembler * masm,int count,BailoutType type)135 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
136                                                 int count,
137                                                 BailoutType type) {
138   TableEntryGenerator generator(masm, type, count);
139   generator.Generate();
140 }
141 
VisitAllOptimizedFunctionsForContext(Context * context,OptimizedFunctionVisitor * visitor)142 void Deoptimizer::VisitAllOptimizedFunctionsForContext(
143     Context* context, OptimizedFunctionVisitor* visitor) {
144   DisallowHeapAllocation no_allocation;
145 
146   CHECK(context->IsNativeContext());
147 
148   visitor->EnterContext(context);
149 
150   // Visit the list of optimized functions, removing elements that
151   // no longer refer to optimized code.
152   JSFunction* prev = NULL;
153   Object* element = context->OptimizedFunctionsListHead();
154   Isolate* isolate = context->GetIsolate();
155   while (!element->IsUndefined(isolate)) {
156     JSFunction* function = JSFunction::cast(element);
157     Object* next = function->next_function_link();
158     if (function->code()->kind() != Code::OPTIMIZED_FUNCTION ||
159         (visitor->VisitFunction(function),
160          function->code()->kind() != Code::OPTIMIZED_FUNCTION)) {
161       // The function no longer refers to optimized code, or the visitor
162       // changed the code to which it refers to no longer be optimized code.
163       // Remove the function from this list.
164       if (prev != NULL) {
165         prev->set_next_function_link(next, UPDATE_WEAK_WRITE_BARRIER);
166       } else {
167         context->SetOptimizedFunctionsListHead(next);
168       }
169       // The visitor should not alter the link directly.
170       CHECK_EQ(function->next_function_link(), next);
171       // Set the next function link to undefined to indicate it is no longer
172       // in the optimized functions list.
173       function->set_next_function_link(context->GetHeap()->undefined_value(),
174                                        SKIP_WRITE_BARRIER);
175     } else {
176       // The visitor should not alter the link directly.
177       CHECK_EQ(function->next_function_link(), next);
178       // preserve this element.
179       prev = function;
180     }
181     element = next;
182   }
183 
184   visitor->LeaveContext(context);
185 }
186 
187 
VisitAllOptimizedFunctions(Isolate * isolate,OptimizedFunctionVisitor * visitor)188 void Deoptimizer::VisitAllOptimizedFunctions(
189     Isolate* isolate,
190     OptimizedFunctionVisitor* visitor) {
191   DisallowHeapAllocation no_allocation;
192 
193   // Run through the list of all native contexts.
194   Object* context = isolate->heap()->native_contexts_list();
195   while (!context->IsUndefined(isolate)) {
196     VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor);
197     context = Context::cast(context)->next_context_link();
198   }
199 }
200 
201 
202 // Unlink functions referring to code marked for deoptimization, then move
203 // marked code from the optimized code list to the deoptimized code list,
204 // and patch code for lazy deopt.
DeoptimizeMarkedCodeForContext(Context * context)205 void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
206   DisallowHeapAllocation no_allocation;
207 
208   // A "closure" that unlinks optimized code that is going to be
209   // deoptimized from the functions that refer to it.
210   class SelectedCodeUnlinker: public OptimizedFunctionVisitor {
211    public:
212     virtual void EnterContext(Context* context) { }  // Don't care.
213     virtual void LeaveContext(Context* context)  { }  // Don't care.
214     virtual void VisitFunction(JSFunction* function) {
215       Code* code = function->code();
216       if (!code->marked_for_deoptimization()) return;
217 
218       // Unlink this function and evict from optimized code map.
219       SharedFunctionInfo* shared = function->shared();
220       function->set_code(shared->code());
221 
222       if (FLAG_trace_deopt) {
223         CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
224         PrintF(scope.file(), "[deoptimizer unlinked: ");
225         function->PrintName(scope.file());
226         PrintF(scope.file(),
227                " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
228       }
229     }
230   };
231 
232   // Unlink all functions that refer to marked code.
233   SelectedCodeUnlinker unlinker;
234   VisitAllOptimizedFunctionsForContext(context, &unlinker);
235 
236   Isolate* isolate = context->GetHeap()->isolate();
237 #ifdef DEBUG
238   Code* topmost_optimized_code = NULL;
239   bool safe_to_deopt_topmost_optimized_code = false;
240   // Make sure all activations of optimized code can deopt at their current PC.
241   // The topmost optimized code has special handling because it cannot be
242   // deoptimized due to weak object dependency.
243   for (StackFrameIterator it(isolate, isolate->thread_local_top());
244        !it.done(); it.Advance()) {
245     StackFrame::Type type = it.frame()->type();
246     if (type == StackFrame::OPTIMIZED) {
247       Code* code = it.frame()->LookupCode();
248       JSFunction* function =
249           static_cast<OptimizedFrame*>(it.frame())->function();
250       if (FLAG_trace_deopt) {
251         CodeTracer::Scope scope(isolate->GetCodeTracer());
252         PrintF(scope.file(), "[deoptimizer found activation of function: ");
253         function->PrintName(scope.file());
254         PrintF(scope.file(),
255                " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
256       }
257       SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc());
258       int deopt_index = safepoint.deoptimization_index();
259       // Turbofan deopt is checked when we are patching addresses on stack.
260       bool turbofanned = code->is_turbofanned() &&
261                          function->shared()->asm_function() &&
262                          !FLAG_turbo_asm_deoptimization;
263       bool safe_to_deopt =
264           deopt_index != Safepoint::kNoDeoptimizationIndex || turbofanned;
265       bool builtin = code->kind() == Code::BUILTIN;
266       CHECK(topmost_optimized_code == NULL || safe_to_deopt || turbofanned ||
267             builtin);
268       if (topmost_optimized_code == NULL) {
269         topmost_optimized_code = code;
270         safe_to_deopt_topmost_optimized_code = safe_to_deopt;
271       }
272     }
273   }
274 #endif
275 
276   // Move marked code from the optimized code list to the deoptimized
277   // code list, collecting them into a ZoneList.
278   Zone zone(isolate->allocator(), ZONE_NAME);
279   ZoneList<Code*> codes(10, &zone);
280 
281   // Walk over all optimized code objects in this native context.
282   Code* prev = NULL;
283   Object* element = context->OptimizedCodeListHead();
284   while (!element->IsUndefined(isolate)) {
285     Code* code = Code::cast(element);
286     CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
287     Object* next = code->next_code_link();
288 
289     if (code->marked_for_deoptimization()) {
290       // Put the code into the list for later patching.
291       codes.Add(code, &zone);
292 
293       if (prev != NULL) {
294         // Skip this code in the optimized code list.
295         prev->set_next_code_link(next);
296       } else {
297         // There was no previous node, the next node is the new head.
298         context->SetOptimizedCodeListHead(next);
299       }
300 
301       // Move the code to the _deoptimized_ code list.
302       code->set_next_code_link(context->DeoptimizedCodeListHead());
303       context->SetDeoptimizedCodeListHead(code);
304     } else {
305       // Not marked; preserve this element.
306       prev = code;
307     }
308     element = next;
309   }
310 
311   // We need a handle scope only because of the macro assembler,
312   // which is used in code patching in EnsureCodeForDeoptimizationEntry.
313   HandleScope scope(isolate);
314 
315   // Now patch all the codes for deoptimization.
316   for (int i = 0; i < codes.length(); i++) {
317 #ifdef DEBUG
318     if (codes[i] == topmost_optimized_code) {
319       DCHECK(safe_to_deopt_topmost_optimized_code);
320     }
321 #endif
322     // It is finally time to die, code object.
323 
324     // Remove the code from optimized code map.
325     DeoptimizationInputData* deopt_data =
326         DeoptimizationInputData::cast(codes[i]->deoptimization_data());
327     SharedFunctionInfo* shared =
328         SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
329     shared->EvictFromOptimizedCodeMap(codes[i], "deoptimized code");
330 
331     // Do platform-specific patching to force any activations to lazy deopt.
332     PatchCodeForDeoptimization(isolate, codes[i]);
333 
334     // We might be in the middle of incremental marking with compaction.
335     // Tell collector to treat this code object in a special way and
336     // ignore all slots that might have been recorded on it.
337     isolate->heap()->mark_compact_collector()->InvalidateCode(codes[i]);
338   }
339 }
340 
341 
DeoptimizeAll(Isolate * isolate)342 void Deoptimizer::DeoptimizeAll(Isolate* isolate) {
343   RuntimeCallTimerScope runtimeTimer(isolate,
344                                      &RuntimeCallStats::DeoptimizeCode);
345   TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
346   TRACE_EVENT0("v8", "V8.DeoptimizeCode");
347   if (FLAG_trace_deopt) {
348     CodeTracer::Scope scope(isolate->GetCodeTracer());
349     PrintF(scope.file(), "[deoptimize all code in all contexts]\n");
350   }
351   DisallowHeapAllocation no_allocation;
352   // For all contexts, mark all code, then deoptimize.
353   Object* context = isolate->heap()->native_contexts_list();
354   while (!context->IsUndefined(isolate)) {
355     Context* native_context = Context::cast(context);
356     MarkAllCodeForContext(native_context);
357     DeoptimizeMarkedCodeForContext(native_context);
358     context = native_context->next_context_link();
359   }
360 }
361 
362 
DeoptimizeMarkedCode(Isolate * isolate)363 void Deoptimizer::DeoptimizeMarkedCode(Isolate* isolate) {
364   RuntimeCallTimerScope runtimeTimer(isolate,
365                                      &RuntimeCallStats::DeoptimizeCode);
366   TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
367   TRACE_EVENT0("v8", "V8.DeoptimizeCode");
368   if (FLAG_trace_deopt) {
369     CodeTracer::Scope scope(isolate->GetCodeTracer());
370     PrintF(scope.file(), "[deoptimize marked code in all contexts]\n");
371   }
372   DisallowHeapAllocation no_allocation;
373   // For all contexts, deoptimize code already marked.
374   Object* context = isolate->heap()->native_contexts_list();
375   while (!context->IsUndefined(isolate)) {
376     Context* native_context = Context::cast(context);
377     DeoptimizeMarkedCodeForContext(native_context);
378     context = native_context->next_context_link();
379   }
380 }
381 
382 
MarkAllCodeForContext(Context * context)383 void Deoptimizer::MarkAllCodeForContext(Context* context) {
384   Object* element = context->OptimizedCodeListHead();
385   Isolate* isolate = context->GetIsolate();
386   while (!element->IsUndefined(isolate)) {
387     Code* code = Code::cast(element);
388     CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
389     code->set_marked_for_deoptimization(true);
390     element = code->next_code_link();
391   }
392 }
393 
394 
DeoptimizeFunction(JSFunction * function)395 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
396   Isolate* isolate = function->GetIsolate();
397   RuntimeCallTimerScope runtimeTimer(isolate,
398                                      &RuntimeCallStats::DeoptimizeCode);
399   TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
400   TRACE_EVENT0("v8", "V8.DeoptimizeCode");
401   Code* code = function->code();
402   if (code->kind() == Code::OPTIMIZED_FUNCTION) {
403     // Mark the code for deoptimization and unlink any functions that also
404     // refer to that code. The code cannot be shared across native contexts,
405     // so we only need to search one.
406     code->set_marked_for_deoptimization(true);
407     DeoptimizeMarkedCodeForContext(function->context()->native_context());
408   }
409 }
410 
411 
ComputeOutputFrames(Deoptimizer * deoptimizer)412 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
413   deoptimizer->DoComputeOutputFrames();
414 }
415 
TraceEnabledFor(StackFrame::Type frame_type)416 bool Deoptimizer::TraceEnabledFor(StackFrame::Type frame_type) {
417   return (frame_type == StackFrame::STUB) ? FLAG_trace_stub_failures
418                                           : FLAG_trace_deopt;
419 }
420 
421 
MessageFor(BailoutType type)422 const char* Deoptimizer::MessageFor(BailoutType type) {
423   switch (type) {
424     case EAGER: return "eager";
425     case SOFT: return "soft";
426     case LAZY: return "lazy";
427   }
428   FATAL("Unsupported deopt type");
429   return NULL;
430 }
431 
Deoptimizer(Isolate * isolate,JSFunction * function,BailoutType type,unsigned bailout_id,Address from,int fp_to_sp_delta)432 Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function,
433                          BailoutType type, unsigned bailout_id, Address from,
434                          int fp_to_sp_delta)
435     : isolate_(isolate),
436       function_(function),
437       bailout_id_(bailout_id),
438       bailout_type_(type),
439       from_(from),
440       fp_to_sp_delta_(fp_to_sp_delta),
441       deoptimizing_throw_(false),
442       catch_handler_data_(-1),
443       catch_handler_pc_offset_(-1),
444       input_(nullptr),
445       output_count_(0),
446       jsframe_count_(0),
447       output_(nullptr),
448       caller_frame_top_(0),
449       caller_fp_(0),
450       caller_pc_(0),
451       caller_constant_pool_(0),
452       input_frame_context_(0),
453       stack_fp_(0),
454       trace_scope_(nullptr) {
455   if (isolate->deoptimizer_lazy_throw()) {
456     isolate->set_deoptimizer_lazy_throw(false);
457     deoptimizing_throw_ = true;
458   }
459 
460   // For COMPILED_STUBs called from builtins, the function pointer is a SMI
461   // indicating an internal frame.
462   if (function->IsSmi()) {
463     function = nullptr;
464   }
465   DCHECK(from != nullptr);
466   if (function != nullptr && function->IsOptimized()) {
467     function->shared()->increment_deopt_count();
468     if (bailout_type_ == Deoptimizer::SOFT) {
469       isolate->counters()->soft_deopts_executed()->Increment();
470       // Soft deopts shouldn't count against the overall re-optimization count
471       // that can eventually lead to disabling optimization for a function.
472       int opt_count = function->shared()->opt_count();
473       if (opt_count > 0) opt_count--;
474       function->shared()->set_opt_count(opt_count);
475     }
476   }
477   compiled_code_ = FindOptimizedCode(function);
478 #if DEBUG
479   DCHECK(compiled_code_ != NULL);
480   if (type == EAGER || type == SOFT || type == LAZY) {
481     DCHECK(compiled_code_->kind() != Code::FUNCTION);
482   }
483 #endif
484 
485   StackFrame::Type frame_type = function == NULL
486       ? StackFrame::STUB
487       : StackFrame::JAVA_SCRIPT;
488   trace_scope_ = TraceEnabledFor(frame_type)
489                      ? new CodeTracer::Scope(isolate->GetCodeTracer())
490                      : NULL;
491 #ifdef DEBUG
492   CHECK(AllowHeapAllocation::IsAllowed());
493   disallow_heap_allocation_ = new DisallowHeapAllocation();
494 #endif  // DEBUG
495   if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
496     PROFILE(isolate_, CodeDeoptEvent(compiled_code_, from_, fp_to_sp_delta_));
497   }
498   unsigned size = ComputeInputFrameSize();
499   int parameter_count =
500       function == nullptr
501           ? 0
502           : (function->shared()->internal_formal_parameter_count() + 1);
503   input_ = new (size) FrameDescription(size, parameter_count);
504   input_->SetFrameType(frame_type);
505 }
506 
FindOptimizedCode(JSFunction * function)507 Code* Deoptimizer::FindOptimizedCode(JSFunction* function) {
508   Code* compiled_code = FindDeoptimizingCode(from_);
509   return (compiled_code == NULL)
510              ? static_cast<Code*>(isolate_->FindCodeObject(from_))
511              : compiled_code;
512 }
513 
514 
PrintFunctionName()515 void Deoptimizer::PrintFunctionName() {
516   if (function_ != nullptr && function_->IsJSFunction()) {
517     function_->ShortPrint(trace_scope_->file());
518   } else {
519     PrintF(trace_scope_->file(),
520            "%s", Code::Kind2String(compiled_code_->kind()));
521   }
522 }
523 
524 
~Deoptimizer()525 Deoptimizer::~Deoptimizer() {
526   DCHECK(input_ == NULL && output_ == NULL);
527   DCHECK(disallow_heap_allocation_ == NULL);
528   delete trace_scope_;
529 }
530 
531 
DeleteFrameDescriptions()532 void Deoptimizer::DeleteFrameDescriptions() {
533   delete input_;
534   for (int i = 0; i < output_count_; ++i) {
535     if (output_[i] != input_) delete output_[i];
536   }
537   delete[] output_;
538   input_ = NULL;
539   output_ = NULL;
540 #ifdef DEBUG
541   CHECK(!AllowHeapAllocation::IsAllowed());
542   CHECK(disallow_heap_allocation_ != NULL);
543   delete disallow_heap_allocation_;
544   disallow_heap_allocation_ = NULL;
545 #endif  // DEBUG
546 }
547 
548 
GetDeoptimizationEntry(Isolate * isolate,int id,BailoutType type,GetEntryMode mode)549 Address Deoptimizer::GetDeoptimizationEntry(Isolate* isolate,
550                                             int id,
551                                             BailoutType type,
552                                             GetEntryMode mode) {
553   CHECK_GE(id, 0);
554   if (id >= kMaxNumberOfEntries) return NULL;
555   if (mode == ENSURE_ENTRY_CODE) {
556     EnsureCodeForDeoptimizationEntry(isolate, type, id);
557   } else {
558     CHECK_EQ(mode, CALCULATE_ENTRY_ADDRESS);
559   }
560   DeoptimizerData* data = isolate->deoptimizer_data();
561   CHECK_LE(type, kLastBailoutType);
562   MemoryChunk* base = data->deopt_entry_code_[type];
563   return base->area_start() + (id * table_entry_size_);
564 }
565 
566 
GetDeoptimizationId(Isolate * isolate,Address addr,BailoutType type)567 int Deoptimizer::GetDeoptimizationId(Isolate* isolate,
568                                      Address addr,
569                                      BailoutType type) {
570   DeoptimizerData* data = isolate->deoptimizer_data();
571   MemoryChunk* base = data->deopt_entry_code_[type];
572   Address start = base->area_start();
573   if (addr < start ||
574       addr >= start + (kMaxNumberOfEntries * table_entry_size_)) {
575     return kNotDeoptimizationEntry;
576   }
577   DCHECK_EQ(0,
578             static_cast<int>(addr - start) % table_entry_size_);
579   return static_cast<int>(addr - start) / table_entry_size_;
580 }
581 
582 
GetOutputInfo(DeoptimizationOutputData * data,BailoutId id,SharedFunctionInfo * shared)583 int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
584                                BailoutId id,
585                                SharedFunctionInfo* shared) {
586   // TODO(kasperl): For now, we do a simple linear search for the PC
587   // offset associated with the given node id. This should probably be
588   // changed to a binary search.
589   int length = data->DeoptPoints();
590   for (int i = 0; i < length; i++) {
591     if (data->AstId(i) == id) {
592       return data->PcAndState(i)->value();
593     }
594   }
595   OFStream os(stderr);
596   os << "[couldn't find pc offset for node=" << id.ToInt() << "]\n"
597      << "[method: " << shared->DebugName()->ToCString().get() << "]\n"
598      << "[source:\n" << SourceCodeOf(shared) << "\n]" << std::endl;
599 
600   shared->GetHeap()->isolate()->PushStackTraceAndDie(0xfefefefe, data, shared,
601                                                      0xfefefeff);
602   FATAL("unable to find pc offset during deoptimization");
603   return -1;
604 }
605 
606 
GetDeoptimizedCodeCount(Isolate * isolate)607 int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
608   int length = 0;
609   // Count all entries in the deoptimizing code list of every context.
610   Object* context = isolate->heap()->native_contexts_list();
611   while (!context->IsUndefined(isolate)) {
612     Context* native_context = Context::cast(context);
613     Object* element = native_context->DeoptimizedCodeListHead();
614     while (!element->IsUndefined(isolate)) {
615       Code* code = Code::cast(element);
616       DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
617       length++;
618       element = code->next_code_link();
619     }
620     context = Context::cast(context)->next_context_link();
621   }
622   return length;
623 }
624 
625 namespace {
626 
LookupCatchHandler(TranslatedFrame * translated_frame,int * data_out)627 int LookupCatchHandler(TranslatedFrame* translated_frame, int* data_out) {
628   switch (translated_frame->kind()) {
629     case TranslatedFrame::kFunction: {
630       BailoutId node_id = translated_frame->node_id();
631       JSFunction* function =
632           JSFunction::cast(translated_frame->begin()->GetRawValue());
633       Code* non_optimized_code = function->shared()->code();
634       FixedArray* raw_data = non_optimized_code->deoptimization_data();
635       DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
636       unsigned pc_and_state =
637           Deoptimizer::GetOutputInfo(data, node_id, function->shared());
638       unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
639       HandlerTable* table =
640           HandlerTable::cast(non_optimized_code->handler_table());
641       HandlerTable::CatchPrediction prediction;
642       return table->LookupRange(pc_offset, data_out, &prediction);
643     }
644     case TranslatedFrame::kInterpretedFunction: {
645       int bytecode_offset = translated_frame->node_id().ToInt();
646       JSFunction* function =
647           JSFunction::cast(translated_frame->begin()->GetRawValue());
648       BytecodeArray* bytecode = function->shared()->bytecode_array();
649       HandlerTable* table = HandlerTable::cast(bytecode->handler_table());
650       HandlerTable::CatchPrediction prediction;
651       return table->LookupRange(bytecode_offset, data_out, &prediction);
652     }
653     default:
654       break;
655   }
656   return -1;
657 }
658 
659 }  // namespace
660 
661 // We rely on this function not causing a GC.  It is called from generated code
662 // without having a real stack frame in place.
DoComputeOutputFrames()663 void Deoptimizer::DoComputeOutputFrames() {
664   base::ElapsedTimer timer;
665 
666   // Determine basic deoptimization information.  The optimized frame is
667   // described by the input data.
668   DeoptimizationInputData* input_data =
669       DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
670 
671   {
672     // Read caller's PC, caller's FP and caller's constant pool values
673     // from input frame. Compute caller's frame top address.
674 
675     Register fp_reg = JavaScriptFrame::fp_register();
676     stack_fp_ = input_->GetRegister(fp_reg.code());
677 
678     caller_frame_top_ = stack_fp_ + ComputeInputFrameAboveFpFixedSize();
679 
680     Address fp_address = input_->GetFramePointerAddress();
681     caller_fp_ = Memory::intptr_at(fp_address);
682     caller_pc_ =
683         Memory::intptr_at(fp_address + CommonFrameConstants::kCallerPCOffset);
684     input_frame_context_ = Memory::intptr_at(
685         fp_address + CommonFrameConstants::kContextOrFrameTypeOffset);
686 
687     if (FLAG_enable_embedded_constant_pool) {
688       caller_constant_pool_ = Memory::intptr_at(
689           fp_address + CommonFrameConstants::kConstantPoolOffset);
690     }
691   }
692 
693   if (trace_scope_ != NULL) {
694     timer.Start();
695     PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ",
696            MessageFor(bailout_type_));
697     PrintFunctionName();
698     PrintF(trace_scope_->file(),
699            " (opt #%d) @%d, FP to SP delta: %d, caller sp: 0x%08" V8PRIxPTR
700            "]\n",
701            input_data->OptimizationId()->value(), bailout_id_, fp_to_sp_delta_,
702            caller_frame_top_);
703     if (bailout_type_ == EAGER || bailout_type_ == SOFT ||
704         (compiled_code_->is_hydrogen_stub())) {
705       compiled_code_->PrintDeoptLocation(trace_scope_->file(), from_);
706     }
707   }
708 
709   BailoutId node_id = input_data->AstId(bailout_id_);
710   ByteArray* translations = input_data->TranslationByteArray();
711   unsigned translation_index =
712       input_data->TranslationIndex(bailout_id_)->value();
713 
714   TranslationIterator state_iterator(translations, translation_index);
715   translated_state_.Init(
716       input_->GetFramePointerAddress(), &state_iterator,
717       input_data->LiteralArray(), input_->GetRegisterValues(),
718       trace_scope_ == nullptr ? nullptr : trace_scope_->file());
719 
720   // Do the input frame to output frame(s) translation.
721   size_t count = translated_state_.frames().size();
722   // If we are supposed to go to the catch handler, find the catching frame
723   // for the catch and make sure we only deoptimize upto that frame.
724   if (deoptimizing_throw_) {
725     size_t catch_handler_frame_index = count;
726     for (size_t i = count; i-- > 0;) {
727       catch_handler_pc_offset_ = LookupCatchHandler(
728           &(translated_state_.frames()[i]), &catch_handler_data_);
729       if (catch_handler_pc_offset_ >= 0) {
730         catch_handler_frame_index = i;
731         break;
732       }
733     }
734     CHECK_LT(catch_handler_frame_index, count);
735     count = catch_handler_frame_index + 1;
736   }
737 
738   DCHECK(output_ == NULL);
739   output_ = new FrameDescription*[count];
740   for (size_t i = 0; i < count; ++i) {
741     output_[i] = NULL;
742   }
743   output_count_ = static_cast<int>(count);
744 
745   // Translate each output frame.
746   int frame_index = 0;  // output_frame_index
747   for (size_t i = 0; i < count; ++i, ++frame_index) {
748     // Read the ast node id, function, and frame height for this output frame.
749     TranslatedFrame* translated_frame = &(translated_state_.frames()[i]);
750     switch (translated_frame->kind()) {
751       case TranslatedFrame::kFunction:
752         DoComputeJSFrame(translated_frame, frame_index,
753                          deoptimizing_throw_ && i == count - 1);
754         jsframe_count_++;
755         break;
756       case TranslatedFrame::kInterpretedFunction:
757         DoComputeInterpretedFrame(translated_frame, frame_index,
758                                   deoptimizing_throw_ && i == count - 1);
759         jsframe_count_++;
760         break;
761       case TranslatedFrame::kArgumentsAdaptor:
762         DoComputeArgumentsAdaptorFrame(translated_frame, frame_index);
763         break;
764       case TranslatedFrame::kTailCallerFunction:
765         DoComputeTailCallerFrame(translated_frame, frame_index);
766         // Tail caller frame translations do not produce output frames.
767         frame_index--;
768         output_count_--;
769         break;
770       case TranslatedFrame::kConstructStub:
771         DoComputeConstructStubFrame(translated_frame, frame_index);
772         break;
773       case TranslatedFrame::kGetter:
774         DoComputeAccessorStubFrame(translated_frame, frame_index, false);
775         break;
776       case TranslatedFrame::kSetter:
777         DoComputeAccessorStubFrame(translated_frame, frame_index, true);
778         break;
779       case TranslatedFrame::kCompiledStub:
780         DoComputeCompiledStubFrame(translated_frame, frame_index);
781         break;
782       case TranslatedFrame::kInvalid:
783         FATAL("invalid frame");
784         break;
785     }
786   }
787 
788   // Print some helpful diagnostic information.
789   if (trace_scope_ != NULL) {
790     double ms = timer.Elapsed().InMillisecondsF();
791     int index = output_count_ - 1;  // Index of the topmost frame.
792     PrintF(trace_scope_->file(), "[deoptimizing (%s): end ",
793            MessageFor(bailout_type_));
794     PrintFunctionName();
795     PrintF(trace_scope_->file(),
796            " @%d => node=%d, pc=0x%08" V8PRIxPTR ", caller sp=0x%08" V8PRIxPTR
797            ", state=%s, took %0.3f ms]\n",
798            bailout_id_, node_id.ToInt(), output_[index]->GetPc(),
799            caller_frame_top_, BailoutStateToString(static_cast<BailoutState>(
800                                   output_[index]->GetState()->value())),
801            ms);
802   }
803 }
804 
DoComputeJSFrame(TranslatedFrame * translated_frame,int frame_index,bool goto_catch_handler)805 void Deoptimizer::DoComputeJSFrame(TranslatedFrame* translated_frame,
806                                    int frame_index, bool goto_catch_handler) {
807   SharedFunctionInfo* shared = translated_frame->raw_shared_info();
808 
809   TranslatedFrame::iterator value_iterator = translated_frame->begin();
810   bool is_bottommost = (0 == frame_index);
811   bool is_topmost = (output_count_ - 1 == frame_index);
812   int input_index = 0;
813 
814   BailoutId node_id = translated_frame->node_id();
815   unsigned height =
816       translated_frame->height() - 1;  // Do not count the context.
817   unsigned height_in_bytes = height * kPointerSize;
818   if (goto_catch_handler) {
819     // Take the stack height from the handler table.
820     height = catch_handler_data_;
821     // We also make space for the exception itself.
822     height_in_bytes = (height + 1) * kPointerSize;
823     CHECK(is_topmost);
824   }
825 
826   JSFunction* function = JSFunction::cast(value_iterator->GetRawValue());
827   value_iterator++;
828   input_index++;
829   if (trace_scope_ != NULL) {
830     PrintF(trace_scope_->file(), "  translating frame ");
831     std::unique_ptr<char[]> name = shared->DebugName()->ToCString();
832     PrintF(trace_scope_->file(), "%s", name.get());
833     PrintF(trace_scope_->file(), " => node=%d, height=%d%s\n", node_id.ToInt(),
834            height_in_bytes, goto_catch_handler ? " (throw)" : "");
835   }
836 
837   // The 'fixed' part of the frame consists of the incoming parameters and
838   // the part described by JavaScriptFrameConstants.
839   unsigned fixed_frame_size = ComputeJavascriptFixedSize(shared);
840   unsigned output_frame_size = height_in_bytes + fixed_frame_size;
841 
842   // Allocate and store the output frame description.
843   int parameter_count = shared->internal_formal_parameter_count() + 1;
844   FrameDescription* output_frame = new (output_frame_size)
845       FrameDescription(output_frame_size, parameter_count);
846   output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
847 
848   CHECK(frame_index >= 0 && frame_index < output_count_);
849   CHECK_NULL(output_[frame_index]);
850   output_[frame_index] = output_frame;
851 
852   // The top address of the frame is computed from the previous frame's top and
853   // this frame's size.
854   intptr_t top_address;
855   if (is_bottommost) {
856     top_address = caller_frame_top_ - output_frame_size;
857   } else {
858     top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
859   }
860   output_frame->SetTop(top_address);
861 
862   // Compute the incoming parameter translation.
863   unsigned output_offset = output_frame_size;
864   for (int i = 0; i < parameter_count; ++i) {
865     output_offset -= kPointerSize;
866     WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
867                                  output_offset);
868   }
869 
870   if (trace_scope_ != nullptr) {
871     PrintF(trace_scope_->file(), "    -------------------------\n");
872   }
873 
874   // There are no translation commands for the caller's pc and fp, the
875   // context, and the function.  Synthesize their values and set them up
876   // explicitly.
877   //
878   // The caller's pc for the bottommost output frame is the same as in the
879   // input frame.  For all subsequent output frames, it can be read from the
880   // previous one.  This frame's pc can be computed from the non-optimized
881   // function code and AST id of the bailout.
882   output_offset -= kPCOnStackSize;
883   intptr_t value;
884   if (is_bottommost) {
885     value = caller_pc_;
886   } else {
887     value = output_[frame_index - 1]->GetPc();
888   }
889   output_frame->SetCallerPc(output_offset, value);
890   DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n");
891 
892   // The caller's frame pointer for the bottommost output frame is the same
893   // as in the input frame.  For all subsequent output frames, it can be
894   // read from the previous one.  Also compute and set this frame's frame
895   // pointer.
896   output_offset -= kFPOnStackSize;
897   if (is_bottommost) {
898     value = caller_fp_;
899   } else {
900     value = output_[frame_index - 1]->GetFp();
901   }
902   output_frame->SetCallerFp(output_offset, value);
903   intptr_t fp_value = top_address + output_offset;
904   output_frame->SetFp(fp_value);
905   if (is_topmost) {
906     Register fp_reg = JavaScriptFrame::fp_register();
907     output_frame->SetRegister(fp_reg.code(), fp_value);
908   }
909   DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
910 
911   if (FLAG_enable_embedded_constant_pool) {
912     // For the bottommost output frame the constant pool pointer can be gotten
913     // from the input frame. For subsequent output frames, it can be read from
914     // the previous frame.
915     output_offset -= kPointerSize;
916     if (is_bottommost) {
917       value = caller_constant_pool_;
918     } else {
919       value = output_[frame_index - 1]->GetConstantPool();
920     }
921     output_frame->SetCallerConstantPool(output_offset, value);
922     DebugPrintOutputSlot(value, frame_index, output_offset,
923                          "caller's constant_pool\n");
924   }
925 
926   // For the bottommost output frame the context can be gotten from the input
927   // frame. For all subsequent output frames it can be gotten from the function
928   // so long as we don't inline functions that need local contexts.
929   output_offset -= kPointerSize;
930 
931   // When deoptimizing into a catch block, we need to take the context
932   // from just above the top of the operand stack (we push the context
933   // at the entry of the try block).
934   TranslatedFrame::iterator context_pos = value_iterator;
935   int context_input_index = input_index;
936   if (goto_catch_handler) {
937     for (unsigned i = 0; i < height + 1; ++i) {
938       context_pos++;
939       context_input_index++;
940     }
941   }
942   // Read the context from the translations.
943   Object* context = context_pos->GetRawValue();
944   if (context->IsUndefined(isolate_)) {
945     // If the context was optimized away, just use the context from
946     // the activation. This should only apply to Crankshaft code.
947     CHECK(!compiled_code_->is_turbofanned());
948     context = is_bottommost ? reinterpret_cast<Object*>(input_frame_context_)
949                             : function->context();
950   }
951   value = reinterpret_cast<intptr_t>(context);
952   output_frame->SetContext(value);
953   WriteValueToOutput(context, context_input_index, frame_index, output_offset,
954                      "context    ");
955   if (context == isolate_->heap()->arguments_marker()) {
956     Address output_address =
957         reinterpret_cast<Address>(output_[frame_index]->GetTop()) +
958         output_offset;
959     values_to_materialize_.push_back({output_address, context_pos});
960   }
961   value_iterator++;
962   input_index++;
963 
964   // The function was mentioned explicitly in the BEGIN_FRAME.
965   output_offset -= kPointerSize;
966   value = reinterpret_cast<intptr_t>(function);
967   WriteValueToOutput(function, 0, frame_index, output_offset, "function    ");
968 
969   if (trace_scope_ != nullptr) {
970     PrintF(trace_scope_->file(), "    -------------------------\n");
971   }
972 
973   // Translate the rest of the frame.
974   for (unsigned i = 0; i < height; ++i) {
975     output_offset -= kPointerSize;
976     WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
977                                  output_offset);
978   }
979   if (goto_catch_handler) {
980     // Write out the exception for the catch handler.
981     output_offset -= kPointerSize;
982     Object* exception_obj = reinterpret_cast<Object*>(
983         input_->GetRegister(FullCodeGenerator::result_register().code()));
984     WriteValueToOutput(exception_obj, input_index, frame_index, output_offset,
985                        "exception   ");
986     input_index++;
987   }
988   CHECK_EQ(0u, output_offset);
989 
990   // Update constant pool.
991   Code* non_optimized_code = shared->code();
992   if (FLAG_enable_embedded_constant_pool) {
993     intptr_t constant_pool_value =
994         reinterpret_cast<intptr_t>(non_optimized_code->constant_pool());
995     output_frame->SetConstantPool(constant_pool_value);
996     if (is_topmost) {
997       Register constant_pool_reg =
998           JavaScriptFrame::constant_pool_pointer_register();
999       output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1000     }
1001   }
1002 
1003   // Compute this frame's PC and state.
1004   FixedArray* raw_data = non_optimized_code->deoptimization_data();
1005   DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
1006   Address start = non_optimized_code->instruction_start();
1007   unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
1008   unsigned pc_offset = goto_catch_handler
1009                            ? catch_handler_pc_offset_
1010                            : FullCodeGenerator::PcField::decode(pc_and_state);
1011   intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
1012   output_frame->SetPc(pc_value);
1013 
1014   // If we are going to the catch handler, then the exception lives in
1015   // the accumulator.
1016   BailoutState state =
1017       goto_catch_handler
1018           ? BailoutState::TOS_REGISTER
1019           : FullCodeGenerator::BailoutStateField::decode(pc_and_state);
1020   output_frame->SetState(Smi::FromInt(static_cast<int>(state)));
1021 
1022   // Clear the context register. The context might be a de-materialized object
1023   // and will be materialized by {Runtime_NotifyDeoptimized}. For additional
1024   // safety we use Smi(0) instead of the potential {arguments_marker} here.
1025   if (is_topmost) {
1026     intptr_t context_value = reinterpret_cast<intptr_t>(Smi::kZero);
1027     Register context_reg = JavaScriptFrame::context_register();
1028     output_frame->SetRegister(context_reg.code(), context_value);
1029   }
1030 
1031   // Set the continuation for the topmost frame.
1032   if (is_topmost) {
1033     Builtins* builtins = isolate_->builtins();
1034     Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
1035     if (bailout_type_ == LAZY) {
1036       continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
1037     } else if (bailout_type_ == SOFT) {
1038       continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
1039     } else {
1040       CHECK_EQ(bailout_type_, EAGER);
1041     }
1042     output_frame->SetContinuation(
1043         reinterpret_cast<intptr_t>(continuation->entry()));
1044   }
1045 }
1046 
DoComputeInterpretedFrame(TranslatedFrame * translated_frame,int frame_index,bool goto_catch_handler)1047 void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
1048                                             int frame_index,
1049                                             bool goto_catch_handler) {
1050   SharedFunctionInfo* shared = translated_frame->raw_shared_info();
1051 
1052   TranslatedFrame::iterator value_iterator = translated_frame->begin();
1053   bool is_bottommost = (0 == frame_index);
1054   bool is_topmost = (output_count_ - 1 == frame_index);
1055   int input_index = 0;
1056 
1057   int bytecode_offset = translated_frame->node_id().ToInt();
1058   unsigned height = translated_frame->height();
1059   unsigned height_in_bytes = height * kPointerSize;
1060 
1061   // All tranlations for interpreted frames contain the accumulator and hence
1062   // are assumed to be in bailout state {BailoutState::TOS_REGISTER}. However
1063   // such a state is only supported for the topmost frame. We need to skip
1064   // pushing the accumulator for any non-topmost frame.
1065   if (!is_topmost) height_in_bytes -= kPointerSize;
1066 
1067   JSFunction* function = JSFunction::cast(value_iterator->GetRawValue());
1068   value_iterator++;
1069   input_index++;
1070   if (trace_scope_ != NULL) {
1071     PrintF(trace_scope_->file(), "  translating interpreted frame ");
1072     std::unique_ptr<char[]> name = shared->DebugName()->ToCString();
1073     PrintF(trace_scope_->file(), "%s", name.get());
1074     PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d%s\n",
1075            bytecode_offset, height_in_bytes,
1076            goto_catch_handler ? " (throw)" : "");
1077   }
1078   if (goto_catch_handler) {
1079     bytecode_offset = catch_handler_pc_offset_;
1080   }
1081 
1082   // The 'fixed' part of the frame consists of the incoming parameters and
1083   // the part described by InterpreterFrameConstants.
1084   unsigned fixed_frame_size = ComputeInterpretedFixedSize(shared);
1085   unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1086 
1087   // Allocate and store the output frame description.
1088   int parameter_count = shared->internal_formal_parameter_count() + 1;
1089   FrameDescription* output_frame = new (output_frame_size)
1090       FrameDescription(output_frame_size, parameter_count);
1091   output_frame->SetFrameType(StackFrame::INTERPRETED);
1092 
1093   CHECK(frame_index >= 0 && frame_index < output_count_);
1094   CHECK_NULL(output_[frame_index]);
1095   output_[frame_index] = output_frame;
1096 
1097   // The top address of the frame is computed from the previous frame's top and
1098   // this frame's size.
1099   intptr_t top_address;
1100   if (is_bottommost) {
1101     top_address = caller_frame_top_ - output_frame_size;
1102   } else {
1103     top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1104   }
1105   output_frame->SetTop(top_address);
1106 
1107   // Compute the incoming parameter translation.
1108   unsigned output_offset = output_frame_size;
1109   for (int i = 0; i < parameter_count; ++i) {
1110     output_offset -= kPointerSize;
1111     WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1112                                  output_offset);
1113   }
1114 
1115   if (trace_scope_ != nullptr) {
1116     PrintF(trace_scope_->file(), "    -------------------------\n");
1117   }
1118 
1119   // There are no translation commands for the caller's pc and fp, the
1120   // context, the function, new.target and the bytecode offset.  Synthesize
1121   // their values and set them up
1122   // explicitly.
1123   //
1124   // The caller's pc for the bottommost output frame is the same as in the
1125   // input frame.  For all subsequent output frames, it can be read from the
1126   // previous one.  This frame's pc can be computed from the non-optimized
1127   // function code and AST id of the bailout.
1128   output_offset -= kPCOnStackSize;
1129   intptr_t value;
1130   if (is_bottommost) {
1131     value = caller_pc_;
1132   } else {
1133     value = output_[frame_index - 1]->GetPc();
1134   }
1135   output_frame->SetCallerPc(output_offset, value);
1136   DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n");
1137 
1138   // The caller's frame pointer for the bottommost output frame is the same
1139   // as in the input frame.  For all subsequent output frames, it can be
1140   // read from the previous one.  Also compute and set this frame's frame
1141   // pointer.
1142   output_offset -= kFPOnStackSize;
1143   if (is_bottommost) {
1144     value = caller_fp_;
1145   } else {
1146     value = output_[frame_index - 1]->GetFp();
1147   }
1148   output_frame->SetCallerFp(output_offset, value);
1149   intptr_t fp_value = top_address + output_offset;
1150   output_frame->SetFp(fp_value);
1151   if (is_topmost) {
1152     Register fp_reg = InterpretedFrame::fp_register();
1153     output_frame->SetRegister(fp_reg.code(), fp_value);
1154   }
1155   DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
1156 
1157   if (FLAG_enable_embedded_constant_pool) {
1158     // For the bottommost output frame the constant pool pointer can be gotten
1159     // from the input frame. For subsequent output frames, it can be read from
1160     // the previous frame.
1161     output_offset -= kPointerSize;
1162     if (is_bottommost) {
1163       value = caller_constant_pool_;
1164     } else {
1165       value = output_[frame_index - 1]->GetConstantPool();
1166     }
1167     output_frame->SetCallerConstantPool(output_offset, value);
1168     DebugPrintOutputSlot(value, frame_index, output_offset,
1169                          "caller's constant_pool\n");
1170   }
1171 
1172   // For the bottommost output frame the context can be gotten from the input
1173   // frame. For all subsequent output frames it can be gotten from the function
1174   // so long as we don't inline functions that need local contexts.
1175   output_offset -= kPointerSize;
1176 
1177   // When deoptimizing into a catch block, we need to take the context
1178   // from a register that was specified in the handler table.
1179   TranslatedFrame::iterator context_pos = value_iterator;
1180   int context_input_index = input_index;
1181   if (goto_catch_handler) {
1182     // Skip to the translated value of the register specified
1183     // in the handler table.
1184     for (int i = 0; i < catch_handler_data_ + 1; ++i) {
1185       context_pos++;
1186       context_input_index++;
1187     }
1188   }
1189   // Read the context from the translations.
1190   Object* context = context_pos->GetRawValue();
1191   value = reinterpret_cast<intptr_t>(context);
1192   output_frame->SetContext(value);
1193   WriteValueToOutput(context, context_input_index, frame_index, output_offset,
1194                      "context    ");
1195   if (context == isolate_->heap()->arguments_marker()) {
1196     Address output_address =
1197         reinterpret_cast<Address>(output_[frame_index]->GetTop()) +
1198         output_offset;
1199     values_to_materialize_.push_back({output_address, context_pos});
1200   }
1201   value_iterator++;
1202   input_index++;
1203 
1204   // The function was mentioned explicitly in the BEGIN_FRAME.
1205   output_offset -= kPointerSize;
1206   value = reinterpret_cast<intptr_t>(function);
1207   WriteValueToOutput(function, 0, frame_index, output_offset, "function    ");
1208 
1209   // The new.target slot is only used during function activiation which is
1210   // before the first deopt point, so should never be needed. Just set it to
1211   // undefined.
1212   output_offset -= kPointerSize;
1213   Object* new_target = isolate_->heap()->undefined_value();
1214   WriteValueToOutput(new_target, 0, frame_index, output_offset, "new_target  ");
1215 
1216   // Set the bytecode array pointer.
1217   output_offset -= kPointerSize;
1218   Object* bytecode_array = shared->HasDebugInfo()
1219                                ? shared->GetDebugInfo()->DebugBytecodeArray()
1220                                : shared->bytecode_array();
1221   WriteValueToOutput(bytecode_array, 0, frame_index, output_offset,
1222                      "bytecode array ");
1223 
1224   // The bytecode offset was mentioned explicitly in the BEGIN_FRAME.
1225   output_offset -= kPointerSize;
1226   int raw_bytecode_offset =
1227       BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset;
1228   Smi* smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset);
1229   WriteValueToOutput(smi_bytecode_offset, 0, frame_index, output_offset,
1230                      "bytecode offset ");
1231 
1232   if (trace_scope_ != nullptr) {
1233     PrintF(trace_scope_->file(), "    -------------------------\n");
1234   }
1235 
1236   // Translate the rest of the interpreter registers in the frame.
1237   for (unsigned i = 0; i < height - 1; ++i) {
1238     output_offset -= kPointerSize;
1239     WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1240                                  output_offset);
1241   }
1242 
1243   // Translate the accumulator register (depending on frame position).
1244   if (is_topmost) {
1245     // For topmost frame, put the accumulator on the stack. The bailout state
1246     // for interpreted frames is always set to {BailoutState::TOS_REGISTER} and
1247     // the {NotifyDeoptimized} builtin pops it off the topmost frame (possibly
1248     // after materialization).
1249     output_offset -= kPointerSize;
1250     if (goto_catch_handler) {
1251       // If we are lazy deopting to a catch handler, we set the accumulator to
1252       // the exception (which lives in the result register).
1253       intptr_t accumulator_value =
1254           input_->GetRegister(FullCodeGenerator::result_register().code());
1255       WriteValueToOutput(reinterpret_cast<Object*>(accumulator_value), 0,
1256                          frame_index, output_offset, "accumulator ");
1257       value_iterator++;
1258     } else {
1259       WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1260                                    output_offset, "accumulator ");
1261     }
1262   } else {
1263     // For non-topmost frames, skip the accumulator translation. For those
1264     // frames, the return value from the callee will become the accumulator.
1265     value_iterator++;
1266     input_index++;
1267   }
1268   CHECK_EQ(0u, output_offset);
1269 
1270   // Compute this frame's PC and state. The PC will be a special builtin that
1271   // continues the bytecode dispatch. Note that non-topmost and lazy-style
1272   // bailout handlers also advance the bytecode offset before dispatch, hence
1273   // simulating what normal handlers do upon completion of the operation.
1274   Builtins* builtins = isolate_->builtins();
1275   Code* dispatch_builtin =
1276       (!is_topmost || (bailout_type_ == LAZY)) && !goto_catch_handler
1277           ? builtins->builtin(Builtins::kInterpreterEnterBytecodeAdvance)
1278           : builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch);
1279   output_frame->SetPc(reinterpret_cast<intptr_t>(dispatch_builtin->entry()));
1280   // Restore accumulator (TOS) register.
1281   output_frame->SetState(
1282       Smi::FromInt(static_cast<int>(BailoutState::TOS_REGISTER)));
1283 
1284   // Update constant pool.
1285   if (FLAG_enable_embedded_constant_pool) {
1286     intptr_t constant_pool_value =
1287         reinterpret_cast<intptr_t>(dispatch_builtin->constant_pool());
1288     output_frame->SetConstantPool(constant_pool_value);
1289     if (is_topmost) {
1290       Register constant_pool_reg =
1291           InterpretedFrame::constant_pool_pointer_register();
1292       output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1293     }
1294   }
1295 
1296   // Clear the context register. The context might be a de-materialized object
1297   // and will be materialized by {Runtime_NotifyDeoptimized}. For additional
1298   // safety we use Smi(0) instead of the potential {arguments_marker} here.
1299   if (is_topmost) {
1300     intptr_t context_value = reinterpret_cast<intptr_t>(Smi::kZero);
1301     Register context_reg = JavaScriptFrame::context_register();
1302     output_frame->SetRegister(context_reg.code(), context_value);
1303   }
1304 
1305   // Set the continuation for the topmost frame.
1306   if (is_topmost) {
1307     Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
1308     if (bailout_type_ == LAZY) {
1309       continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
1310     } else if (bailout_type_ == SOFT) {
1311       continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
1312     } else {
1313       CHECK_EQ(bailout_type_, EAGER);
1314     }
1315     output_frame->SetContinuation(
1316         reinterpret_cast<intptr_t>(continuation->entry()));
1317   }
1318 }
1319 
DoComputeArgumentsAdaptorFrame(TranslatedFrame * translated_frame,int frame_index)1320 void Deoptimizer::DoComputeArgumentsAdaptorFrame(
1321     TranslatedFrame* translated_frame, int frame_index) {
1322   TranslatedFrame::iterator value_iterator = translated_frame->begin();
1323   bool is_bottommost = (0 == frame_index);
1324   int input_index = 0;
1325 
1326   unsigned height = translated_frame->height();
1327   unsigned height_in_bytes = height * kPointerSize;
1328   JSFunction* function = JSFunction::cast(value_iterator->GetRawValue());
1329   value_iterator++;
1330   input_index++;
1331   if (trace_scope_ != NULL) {
1332     PrintF(trace_scope_->file(),
1333            "  translating arguments adaptor => height=%d\n", height_in_bytes);
1334   }
1335 
1336   unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFixedFrameSize;
1337   unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1338 
1339   // Allocate and store the output frame description.
1340   int parameter_count = height;
1341   FrameDescription* output_frame = new (output_frame_size)
1342       FrameDescription(output_frame_size, parameter_count);
1343   output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
1344 
1345   // Arguments adaptor can not be topmost.
1346   CHECK(frame_index < output_count_ - 1);
1347   CHECK(output_[frame_index] == NULL);
1348   output_[frame_index] = output_frame;
1349 
1350   // The top address of the frame is computed from the previous frame's top and
1351   // this frame's size.
1352   intptr_t top_address;
1353   if (is_bottommost) {
1354     top_address = caller_frame_top_ - output_frame_size;
1355   } else {
1356     top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1357   }
1358   output_frame->SetTop(top_address);
1359 
1360   // Compute the incoming parameter translation.
1361   unsigned output_offset = output_frame_size;
1362   for (int i = 0; i < parameter_count; ++i) {
1363     output_offset -= kPointerSize;
1364     WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1365                                  output_offset);
1366   }
1367 
1368   // Read caller's PC from the previous frame.
1369   output_offset -= kPCOnStackSize;
1370   intptr_t value;
1371   if (is_bottommost) {
1372     value = caller_pc_;
1373   } else {
1374     value = output_[frame_index - 1]->GetPc();
1375   }
1376   output_frame->SetCallerPc(output_offset, value);
1377   DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n");
1378 
1379   // Read caller's FP from the previous frame, and set this frame's FP.
1380   output_offset -= kFPOnStackSize;
1381   if (is_bottommost) {
1382     value = caller_fp_;
1383   } else {
1384     value = output_[frame_index - 1]->GetFp();
1385   }
1386   output_frame->SetCallerFp(output_offset, value);
1387   intptr_t fp_value = top_address + output_offset;
1388   output_frame->SetFp(fp_value);
1389   DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
1390 
1391   if (FLAG_enable_embedded_constant_pool) {
1392     // Read the caller's constant pool from the previous frame.
1393     output_offset -= kPointerSize;
1394     if (is_bottommost) {
1395       value = caller_constant_pool_;
1396     } else {
1397       value = output_[frame_index - 1]->GetConstantPool();
1398     }
1399     output_frame->SetCallerConstantPool(output_offset, value);
1400     DebugPrintOutputSlot(value, frame_index, output_offset,
1401                          "caller's constant_pool\n");
1402   }
1403 
1404   // A marker value is used in place of the context.
1405   output_offset -= kPointerSize;
1406   intptr_t context = reinterpret_cast<intptr_t>(
1407       Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1408   output_frame->SetFrameSlot(output_offset, context);
1409   DebugPrintOutputSlot(context, frame_index, output_offset,
1410                        "context (adaptor sentinel)\n");
1411 
1412   // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
1413   output_offset -= kPointerSize;
1414   value = reinterpret_cast<intptr_t>(function);
1415   WriteValueToOutput(function, 0, frame_index, output_offset, "function    ");
1416 
1417   // Number of incoming arguments.
1418   output_offset -= kPointerSize;
1419   value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1420   output_frame->SetFrameSlot(output_offset, value);
1421   DebugPrintOutputSlot(value, frame_index, output_offset, "argc ");
1422   if (trace_scope_ != nullptr) {
1423     PrintF(trace_scope_->file(), "(%d)\n", height - 1);
1424   }
1425 
1426   DCHECK(0 == output_offset);
1427 
1428   Builtins* builtins = isolate_->builtins();
1429   Code* adaptor_trampoline =
1430       builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
1431   intptr_t pc_value = reinterpret_cast<intptr_t>(
1432       adaptor_trampoline->instruction_start() +
1433       isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
1434   output_frame->SetPc(pc_value);
1435   if (FLAG_enable_embedded_constant_pool) {
1436     intptr_t constant_pool_value =
1437         reinterpret_cast<intptr_t>(adaptor_trampoline->constant_pool());
1438     output_frame->SetConstantPool(constant_pool_value);
1439   }
1440 }
1441 
DoComputeTailCallerFrame(TranslatedFrame * translated_frame,int frame_index)1442 void Deoptimizer::DoComputeTailCallerFrame(TranslatedFrame* translated_frame,
1443                                            int frame_index) {
1444   SharedFunctionInfo* shared = translated_frame->raw_shared_info();
1445 
1446   bool is_bottommost = (0 == frame_index);
1447   // Tail caller frame can't be topmost.
1448   CHECK_NE(output_count_ - 1, frame_index);
1449 
1450   if (trace_scope_ != NULL) {
1451     PrintF(trace_scope_->file(), "  translating tail caller frame ");
1452     std::unique_ptr<char[]> name = shared->DebugName()->ToCString();
1453     PrintF(trace_scope_->file(), "%s\n", name.get());
1454   }
1455 
1456   if (!is_bottommost) return;
1457 
1458   // Drop arguments adaptor frame below current frame if it exsits.
1459   Address fp_address = input_->GetFramePointerAddress();
1460   Address adaptor_fp_address =
1461       Memory::Address_at(fp_address + CommonFrameConstants::kCallerFPOffset);
1462 
1463   if (Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR) !=
1464       Memory::Object_at(adaptor_fp_address +
1465                         CommonFrameConstants::kContextOrFrameTypeOffset)) {
1466     return;
1467   }
1468 
1469   int caller_params_count =
1470       Smi::cast(
1471           Memory::Object_at(adaptor_fp_address +
1472                             ArgumentsAdaptorFrameConstants::kLengthOffset))
1473           ->value();
1474 
1475   int callee_params_count =
1476       function_->shared()->internal_formal_parameter_count();
1477 
1478   // Both caller and callee parameters count do not include receiver.
1479   int offset = (caller_params_count - callee_params_count) * kPointerSize;
1480   intptr_t new_stack_fp =
1481       reinterpret_cast<intptr_t>(adaptor_fp_address) + offset;
1482 
1483   intptr_t new_caller_frame_top = new_stack_fp +
1484                                   (callee_params_count + 1) * kPointerSize +
1485                                   CommonFrameConstants::kFixedFrameSizeAboveFp;
1486 
1487   intptr_t adaptor_caller_pc = Memory::intptr_at(
1488       adaptor_fp_address + CommonFrameConstants::kCallerPCOffset);
1489   intptr_t adaptor_caller_fp = Memory::intptr_at(
1490       adaptor_fp_address + CommonFrameConstants::kCallerFPOffset);
1491 
1492   if (trace_scope_ != NULL) {
1493     PrintF(trace_scope_->file(),
1494            "    dropping caller arguments adaptor frame: offset=%d, "
1495            "fp: 0x%08" V8PRIxPTR " -> 0x%08" V8PRIxPTR
1496            ", "
1497            "caller sp: 0x%08" V8PRIxPTR " -> 0x%08" V8PRIxPTR "\n",
1498            offset, stack_fp_, new_stack_fp, caller_frame_top_,
1499            new_caller_frame_top);
1500   }
1501   caller_frame_top_ = new_caller_frame_top;
1502   caller_fp_ = adaptor_caller_fp;
1503   caller_pc_ = adaptor_caller_pc;
1504 }
1505 
DoComputeConstructStubFrame(TranslatedFrame * translated_frame,int frame_index)1506 void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
1507                                               int frame_index) {
1508   TranslatedFrame::iterator value_iterator = translated_frame->begin();
1509   bool is_topmost = (output_count_ - 1 == frame_index);
1510   // The construct frame could become topmost only if we inlined a constructor
1511   // call which does a tail call (otherwise the tail callee's frame would be
1512   // the topmost one). So it could only be the LAZY case.
1513   CHECK(!is_topmost || bailout_type_ == LAZY);
1514   int input_index = 0;
1515 
1516   Builtins* builtins = isolate_->builtins();
1517   Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
1518   unsigned height = translated_frame->height();
1519   unsigned height_in_bytes = height * kPointerSize;
1520 
1521   // If the construct frame appears to be topmost we should ensure that the
1522   // value of result register is preserved during continuation execution.
1523   // We do this here by "pushing" the result of the constructor function to the
1524   // top of the reconstructed stack and then using the
1525   // BailoutState::TOS_REGISTER machinery.
1526   if (is_topmost) {
1527     height_in_bytes += kPointerSize;
1528   }
1529 
1530   // Skip function.
1531   value_iterator++;
1532   input_index++;
1533   if (trace_scope_ != NULL) {
1534     PrintF(trace_scope_->file(),
1535            "  translating construct stub => height=%d\n", height_in_bytes);
1536   }
1537 
1538   unsigned fixed_frame_size = ConstructFrameConstants::kFixedFrameSize;
1539   unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1540 
1541   // Allocate and store the output frame description.
1542   FrameDescription* output_frame =
1543       new (output_frame_size) FrameDescription(output_frame_size);
1544   output_frame->SetFrameType(StackFrame::CONSTRUCT);
1545 
1546   // Construct stub can not be topmost.
1547   DCHECK(frame_index > 0 && frame_index < output_count_);
1548   DCHECK(output_[frame_index] == NULL);
1549   output_[frame_index] = output_frame;
1550 
1551   // The top address of the frame is computed from the previous frame's top and
1552   // this frame's size.
1553   intptr_t top_address;
1554   top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1555   output_frame->SetTop(top_address);
1556 
1557   // Compute the incoming parameter translation.
1558   int parameter_count = height;
1559   unsigned output_offset = output_frame_size;
1560   for (int i = 0; i < parameter_count; ++i) {
1561     output_offset -= kPointerSize;
1562     // The allocated receiver of a construct stub frame is passed as the
1563     // receiver parameter through the translation. It might be encoding
1564     // a captured object, override the slot address for a captured object.
1565     WriteTranslatedValueToOutput(
1566         &value_iterator, &input_index, frame_index, output_offset, nullptr,
1567         (i == 0) ? reinterpret_cast<Address>(top_address) : nullptr);
1568   }
1569 
1570   // Read caller's PC from the previous frame.
1571   output_offset -= kPCOnStackSize;
1572   intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1573   output_frame->SetCallerPc(output_offset, callers_pc);
1574   DebugPrintOutputSlot(callers_pc, frame_index, output_offset, "caller's pc\n");
1575 
1576   // Read caller's FP from the previous frame, and set this frame's FP.
1577   output_offset -= kFPOnStackSize;
1578   intptr_t value = output_[frame_index - 1]->GetFp();
1579   output_frame->SetCallerFp(output_offset, value);
1580   intptr_t fp_value = top_address + output_offset;
1581   output_frame->SetFp(fp_value);
1582   if (is_topmost) {
1583     Register fp_reg = JavaScriptFrame::fp_register();
1584     output_frame->SetRegister(fp_reg.code(), fp_value);
1585   }
1586   DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
1587 
1588   if (FLAG_enable_embedded_constant_pool) {
1589     // Read the caller's constant pool from the previous frame.
1590     output_offset -= kPointerSize;
1591     value = output_[frame_index - 1]->GetConstantPool();
1592     output_frame->SetCallerConstantPool(output_offset, value);
1593     DebugPrintOutputSlot(value, frame_index, output_offset,
1594                          "caller's constant_pool\n");
1595   }
1596 
1597   // A marker value is used to mark the frame.
1598   output_offset -= kPointerSize;
1599   value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT));
1600   output_frame->SetFrameSlot(output_offset, value);
1601   DebugPrintOutputSlot(value, frame_index, output_offset,
1602                        "typed frame marker\n");
1603 
1604   // The context can be gotten from the previous frame.
1605   output_offset -= kPointerSize;
1606   value = output_[frame_index - 1]->GetContext();
1607   output_frame->SetFrameSlot(output_offset, value);
1608   DebugPrintOutputSlot(value, frame_index, output_offset, "context\n");
1609 
1610   // Number of incoming arguments.
1611   output_offset -= kPointerSize;
1612   value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
1613   output_frame->SetFrameSlot(output_offset, value);
1614   DebugPrintOutputSlot(value, frame_index, output_offset, "argc ");
1615   if (trace_scope_ != nullptr) {
1616     PrintF(trace_scope_->file(), "(%d)\n", height - 1);
1617   }
1618 
1619   // The newly allocated object was passed as receiver in the artificial
1620   // constructor stub environment created by HEnvironment::CopyForInlining().
1621   output_offset -= kPointerSize;
1622   value = output_frame->GetFrameSlot(output_frame_size - kPointerSize);
1623   output_frame->SetFrameSlot(output_offset, value);
1624   DebugPrintOutputSlot(value, frame_index, output_offset,
1625                        "allocated receiver\n");
1626 
1627   if (is_topmost) {
1628     // Ensure the result is restored back when we return to the stub.
1629     output_offset -= kPointerSize;
1630     Register result_reg = FullCodeGenerator::result_register();
1631     value = input_->GetRegister(result_reg.code());
1632     output_frame->SetFrameSlot(output_offset, value);
1633     DebugPrintOutputSlot(value, frame_index, output_offset,
1634                          "constructor result\n");
1635 
1636     output_frame->SetState(
1637         Smi::FromInt(static_cast<int>(BailoutState::TOS_REGISTER)));
1638   }
1639 
1640   CHECK_EQ(0u, output_offset);
1641 
1642   intptr_t pc = reinterpret_cast<intptr_t>(
1643       construct_stub->instruction_start() +
1644       isolate_->heap()->construct_stub_deopt_pc_offset()->value());
1645   output_frame->SetPc(pc);
1646   if (FLAG_enable_embedded_constant_pool) {
1647     intptr_t constant_pool_value =
1648         reinterpret_cast<intptr_t>(construct_stub->constant_pool());
1649     output_frame->SetConstantPool(constant_pool_value);
1650     if (is_topmost) {
1651       Register constant_pool_reg =
1652           JavaScriptFrame::constant_pool_pointer_register();
1653       output_frame->SetRegister(constant_pool_reg.code(), fp_value);
1654     }
1655   }
1656 
1657   // Clear the context register. The context might be a de-materialized object
1658   // and will be materialized by {Runtime_NotifyDeoptimized}. For additional
1659   // safety we use Smi(0) instead of the potential {arguments_marker} here.
1660   if (is_topmost) {
1661     intptr_t context_value = reinterpret_cast<intptr_t>(Smi::kZero);
1662     Register context_reg = JavaScriptFrame::context_register();
1663     output_frame->SetRegister(context_reg.code(), context_value);
1664   }
1665 
1666   // Set the continuation for the topmost frame.
1667   if (is_topmost) {
1668     Builtins* builtins = isolate_->builtins();
1669     DCHECK_EQ(LAZY, bailout_type_);
1670     Code* continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
1671     output_frame->SetContinuation(
1672         reinterpret_cast<intptr_t>(continuation->entry()));
1673   }
1674 }
1675 
DoComputeAccessorStubFrame(TranslatedFrame * translated_frame,int frame_index,bool is_setter_stub_frame)1676 void Deoptimizer::DoComputeAccessorStubFrame(TranslatedFrame* translated_frame,
1677                                              int frame_index,
1678                                              bool is_setter_stub_frame) {
1679   TranslatedFrame::iterator value_iterator = translated_frame->begin();
1680   bool is_topmost = (output_count_ - 1 == frame_index);
1681   // The accessor frame could become topmost only if we inlined an accessor
1682   // call which does a tail call (otherwise the tail callee's frame would be
1683   // the topmost one). So it could only be the LAZY case.
1684   CHECK(!is_topmost || bailout_type_ == LAZY);
1685   int input_index = 0;
1686 
1687   // Skip accessor.
1688   value_iterator++;
1689   input_index++;
1690   // The receiver (and the implicit return value, if any) are expected in
1691   // registers by the LoadIC/StoreIC, so they don't belong to the output stack
1692   // frame. This means that we have to use a height of 0.
1693   unsigned height = 0;
1694   unsigned height_in_bytes = height * kPointerSize;
1695 
1696   // If the accessor frame appears to be topmost we should ensure that the
1697   // value of result register is preserved during continuation execution.
1698   // We do this here by "pushing" the result of the accessor function to the
1699   // top of the reconstructed stack and then using the
1700   // BailoutState::TOS_REGISTER machinery.
1701   // We don't need to restore the result in case of a setter call because we
1702   // have to return the stored value but not the result of the setter function.
1703   bool should_preserve_result = is_topmost && !is_setter_stub_frame;
1704   if (should_preserve_result) {
1705     height_in_bytes += kPointerSize;
1706   }
1707 
1708   const char* kind = is_setter_stub_frame ? "setter" : "getter";
1709   if (trace_scope_ != NULL) {
1710     PrintF(trace_scope_->file(),
1711            "  translating %s stub => height=%u\n", kind, height_in_bytes);
1712   }
1713 
1714   // We need 1 stack entry for the return address and enough entries for the
1715   // StackFrame::INTERNAL (FP, frame type, context, code object and constant
1716   // pool (if enabled)- see MacroAssembler::EnterFrame).
1717   // For a setter stub frame we need one additional entry for the implicit
1718   // return value, see StoreStubCompiler::CompileStoreViaSetter.
1719   unsigned fixed_frame_entries =
1720       (StandardFrameConstants::kFixedFrameSize / kPointerSize) + 1 +
1721       (is_setter_stub_frame ? 1 : 0);
1722   unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
1723   unsigned output_frame_size = height_in_bytes + fixed_frame_size;
1724 
1725   // Allocate and store the output frame description.
1726   FrameDescription* output_frame =
1727       new (output_frame_size) FrameDescription(output_frame_size);
1728   output_frame->SetFrameType(StackFrame::INTERNAL);
1729 
1730   // A frame for an accessor stub can not be bottommost.
1731   CHECK(frame_index > 0 && frame_index < output_count_);
1732   CHECK_NULL(output_[frame_index]);
1733   output_[frame_index] = output_frame;
1734 
1735   // The top address of the frame is computed from the previous frame's top and
1736   // this frame's size.
1737   intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
1738   output_frame->SetTop(top_address);
1739 
1740   unsigned output_offset = output_frame_size;
1741 
1742   // Read caller's PC from the previous frame.
1743   output_offset -= kPCOnStackSize;
1744   intptr_t callers_pc = output_[frame_index - 1]->GetPc();
1745   output_frame->SetCallerPc(output_offset, callers_pc);
1746   DebugPrintOutputSlot(callers_pc, frame_index, output_offset, "caller's pc\n");
1747 
1748   // Read caller's FP from the previous frame, and set this frame's FP.
1749   output_offset -= kFPOnStackSize;
1750   intptr_t value = output_[frame_index - 1]->GetFp();
1751   output_frame->SetCallerFp(output_offset, value);
1752   intptr_t fp_value = top_address + output_offset;
1753   output_frame->SetFp(fp_value);
1754   if (is_topmost) {
1755     Register fp_reg = JavaScriptFrame::fp_register();
1756     output_frame->SetRegister(fp_reg.code(), fp_value);
1757   }
1758   DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
1759 
1760   if (FLAG_enable_embedded_constant_pool) {
1761     // Read the caller's constant pool from the previous frame.
1762     output_offset -= kPointerSize;
1763     value = output_[frame_index - 1]->GetConstantPool();
1764     output_frame->SetCallerConstantPool(output_offset, value);
1765     DebugPrintOutputSlot(value, frame_index, output_offset,
1766                          "caller's constant_pool\n");
1767   }
1768 
1769   // Set the frame type.
1770   output_offset -= kPointerSize;
1771   value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
1772   output_frame->SetFrameSlot(output_offset, value);
1773   DebugPrintOutputSlot(value, frame_index, output_offset, "frame type ");
1774   if (trace_scope_ != nullptr) {
1775     PrintF(trace_scope_->file(), "(%s sentinel)\n", kind);
1776   }
1777 
1778   // Get Code object from accessor stub.
1779   output_offset -= kPointerSize;
1780   Builtins::Name name = is_setter_stub_frame ?
1781       Builtins::kStoreIC_Setter_ForDeopt :
1782       Builtins::kLoadIC_Getter_ForDeopt;
1783   Code* accessor_stub = isolate_->builtins()->builtin(name);
1784   value = reinterpret_cast<intptr_t>(accessor_stub);
1785   output_frame->SetFrameSlot(output_offset, value);
1786   DebugPrintOutputSlot(value, frame_index, output_offset, "code object\n");
1787 
1788   // The context can be gotten from the previous frame.
1789   output_offset -= kPointerSize;
1790   value = output_[frame_index - 1]->GetContext();
1791   output_frame->SetFrameSlot(output_offset, value);
1792   DebugPrintOutputSlot(value, frame_index, output_offset, "context\n");
1793 
1794   // Skip receiver.
1795   value_iterator++;
1796   input_index++;
1797 
1798   if (is_setter_stub_frame) {
1799     // The implicit return value was part of the artificial setter stub
1800     // environment.
1801     output_offset -= kPointerSize;
1802     WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
1803                                  output_offset);
1804   }
1805 
1806   if (should_preserve_result) {
1807     // Ensure the result is restored back when we return to the stub.
1808     output_offset -= kPointerSize;
1809     Register result_reg = FullCodeGenerator::result_register();
1810     value = input_->GetRegister(result_reg.code());
1811     output_frame->SetFrameSlot(output_offset, value);
1812     DebugPrintOutputSlot(value, frame_index, output_offset,
1813                          "accessor result\n");
1814 
1815     output_frame->SetState(
1816         Smi::FromInt(static_cast<int>(BailoutState::TOS_REGISTER)));
1817   } else {
1818     output_frame->SetState(
1819         Smi::FromInt(static_cast<int>(BailoutState::NO_REGISTERS)));
1820   }
1821 
1822   CHECK_EQ(0u, output_offset);
1823 
1824   Smi* offset = is_setter_stub_frame ?
1825       isolate_->heap()->setter_stub_deopt_pc_offset() :
1826       isolate_->heap()->getter_stub_deopt_pc_offset();
1827   intptr_t pc = reinterpret_cast<intptr_t>(
1828       accessor_stub->instruction_start() + offset->value());
1829   output_frame->SetPc(pc);
1830   if (FLAG_enable_embedded_constant_pool) {
1831     intptr_t constant_pool_value =
1832         reinterpret_cast<intptr_t>(accessor_stub->constant_pool());
1833     output_frame->SetConstantPool(constant_pool_value);
1834     if (is_topmost) {
1835       Register constant_pool_reg =
1836           JavaScriptFrame::constant_pool_pointer_register();
1837       output_frame->SetRegister(constant_pool_reg.code(), fp_value);
1838     }
1839   }
1840 
1841   // Clear the context register. The context might be a de-materialized object
1842   // and will be materialized by {Runtime_NotifyDeoptimized}. For additional
1843   // safety we use Smi(0) instead of the potential {arguments_marker} here.
1844   if (is_topmost) {
1845     intptr_t context_value = reinterpret_cast<intptr_t>(Smi::kZero);
1846     Register context_reg = JavaScriptFrame::context_register();
1847     output_frame->SetRegister(context_reg.code(), context_value);
1848   }
1849 
1850   // Set the continuation for the topmost frame.
1851   if (is_topmost) {
1852     Builtins* builtins = isolate_->builtins();
1853     DCHECK_EQ(LAZY, bailout_type_);
1854     Code* continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
1855     output_frame->SetContinuation(
1856         reinterpret_cast<intptr_t>(continuation->entry()));
1857   }
1858 }
1859 
DoComputeCompiledStubFrame(TranslatedFrame * translated_frame,int frame_index)1860 void Deoptimizer::DoComputeCompiledStubFrame(TranslatedFrame* translated_frame,
1861                                              int frame_index) {
1862   //
1863   //               FROM                                  TO
1864   //    |          ....           |          |          ....           |
1865   //    +-------------------------+          +-------------------------+
1866   //    | JSFunction continuation |          | JSFunction continuation |
1867   //    +-------------------------+          +-------------------------+
1868   // |  |    saved frame (FP)     |          |    saved frame (FP)     |
1869   // |  +=========================+<-fpreg   +=========================+<-fpreg
1870   // |  |constant pool (if ool_cp)|          |constant pool (if ool_cp)|
1871   // |  +-------------------------+          +-------------------------|
1872   // |  |   JSFunction context    |          |   JSFunction context    |
1873   // v  +-------------------------+          +-------------------------|
1874   //    |   COMPILED_STUB marker  |          |   STUB_FAILURE marker   |
1875   //    +-------------------------+          +-------------------------+
1876   //    |                         |          |  caller args.arguments_ |
1877   //    | ...                     |          +-------------------------+
1878   //    |                         |          |  caller args.length_    |
1879   //    |-------------------------|<-spreg   +-------------------------+
1880   //                                         |  caller args pointer    |
1881   //                                         +-------------------------+
1882   //                                         |  caller stack param 1   |
1883   //      parameters in registers            +-------------------------+
1884   //       and spilled to stack              |           ....          |
1885   //                                         +-------------------------+
1886   //                                         |  caller stack param n   |
1887   //                                         +-------------------------+<-spreg
1888   //                                         reg = number of parameters
1889   //                                         reg = failure handler address
1890   //                                         reg = saved frame
1891   //                                         reg = JSFunction context
1892   //
1893   // Caller stack params contain the register parameters to the stub first,
1894   // and then, if the descriptor specifies a constant number of stack
1895   // parameters, the stack parameters as well.
1896 
1897   TranslatedFrame::iterator value_iterator = translated_frame->begin();
1898   int input_index = 0;
1899 
1900   CHECK(compiled_code_->is_hydrogen_stub());
1901   int major_key = CodeStub::GetMajorKey(compiled_code_);
1902   CodeStubDescriptor descriptor(isolate_, compiled_code_->stub_key());
1903 
1904   // The output frame must have room for all pushed register parameters
1905   // and the standard stack frame slots.  Include space for an argument
1906   // object to the callee and optionally the space to pass the argument
1907   // object to the stub failure handler.
1908   int param_count = descriptor.GetRegisterParameterCount();
1909   int stack_param_count = descriptor.GetStackParameterCount();
1910   // The translated frame contains all of the register parameters
1911   // plus the context.
1912   CHECK_EQ(translated_frame->height(), param_count + 1);
1913   CHECK_GE(param_count, 0);
1914 
1915   int height_in_bytes = kPointerSize * (param_count + stack_param_count);
1916   int fixed_frame_size = StubFailureTrampolineFrameConstants::kFixedFrameSize;
1917   int output_frame_size = height_in_bytes + fixed_frame_size;
1918   if (trace_scope_ != NULL) {
1919     PrintF(trace_scope_->file(),
1920            "  translating %s => StubFailureTrampolineStub, height=%d\n",
1921            CodeStub::MajorName(static_cast<CodeStub::Major>(major_key)),
1922            height_in_bytes);
1923   }
1924 
1925   // The stub failure trampoline is a single frame.
1926   FrameDescription* output_frame =
1927       new (output_frame_size) FrameDescription(output_frame_size);
1928   output_frame->SetFrameType(StackFrame::STUB_FAILURE_TRAMPOLINE);
1929   CHECK_EQ(frame_index, 0);
1930   output_[frame_index] = output_frame;
1931 
1932   // The top address of the frame is computed from the previous frame's top and
1933   // this frame's size.
1934   intptr_t top_address = caller_frame_top_ - output_frame_size;
1935   output_frame->SetTop(top_address);
1936 
1937   // Set caller's PC (JSFunction continuation).
1938   unsigned output_frame_offset = output_frame_size - kFPOnStackSize;
1939   intptr_t value = caller_pc_;
1940   output_frame->SetCallerPc(output_frame_offset, value);
1941   DebugPrintOutputSlot(value, frame_index, output_frame_offset,
1942                        "caller's pc\n");
1943 
1944   // Read caller's FP from the input frame, and set this frame's FP.
1945   value = caller_fp_;
1946   output_frame_offset -= kFPOnStackSize;
1947   output_frame->SetCallerFp(output_frame_offset, value);
1948   intptr_t frame_ptr = top_address + output_frame_offset;
1949   Register fp_reg = StubFailureTrampolineFrame::fp_register();
1950   output_frame->SetRegister(fp_reg.code(), frame_ptr);
1951   output_frame->SetFp(frame_ptr);
1952   DebugPrintOutputSlot(value, frame_index, output_frame_offset,
1953                        "caller's fp\n");
1954 
1955   if (FLAG_enable_embedded_constant_pool) {
1956     // Read the caller's constant pool from the input frame.
1957     value = caller_constant_pool_;
1958     output_frame_offset -= kPointerSize;
1959     output_frame->SetCallerConstantPool(output_frame_offset, value);
1960     DebugPrintOutputSlot(value, frame_index, output_frame_offset,
1961                          "caller's constant_pool\n");
1962   }
1963 
1964   // The marker for the typed stack frame
1965   output_frame_offset -= kPointerSize;
1966   value = reinterpret_cast<intptr_t>(
1967       Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
1968   output_frame->SetFrameSlot(output_frame_offset, value);
1969   DebugPrintOutputSlot(value, frame_index, output_frame_offset,
1970                        "function (stub failure sentinel)\n");
1971 
1972   intptr_t caller_arg_count = stack_param_count;
1973   bool arg_count_known = !descriptor.stack_parameter_count().is_valid();
1974 
1975   // Build the Arguments object for the caller's parameters and a pointer to it.
1976   output_frame_offset -= kPointerSize;
1977   int args_arguments_offset = output_frame_offset;
1978   intptr_t the_hole = reinterpret_cast<intptr_t>(
1979       isolate_->heap()->the_hole_value());
1980   if (arg_count_known) {
1981     value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
1982         (caller_arg_count - 1) * kPointerSize;
1983   } else {
1984     value = the_hole;
1985   }
1986 
1987   output_frame->SetFrameSlot(args_arguments_offset, value);
1988   DebugPrintOutputSlot(
1989       value, frame_index, args_arguments_offset,
1990       arg_count_known ? "args.arguments\n" : "args.arguments (the hole)\n");
1991 
1992   output_frame_offset -= kPointerSize;
1993   int length_frame_offset = output_frame_offset;
1994   value = arg_count_known ? caller_arg_count : the_hole;
1995   output_frame->SetFrameSlot(length_frame_offset, value);
1996   DebugPrintOutputSlot(
1997       value, frame_index, length_frame_offset,
1998       arg_count_known ? "args.length\n" : "args.length (the hole)\n");
1999 
2000   output_frame_offset -= kPointerSize;
2001   value = frame_ptr + StandardFrameConstants::kCallerSPOffset -
2002       (output_frame_size - output_frame_offset) + kPointerSize;
2003   output_frame->SetFrameSlot(output_frame_offset, value);
2004   DebugPrintOutputSlot(value, frame_index, output_frame_offset, "args*\n");
2005 
2006   // Copy the register parameters to the failure frame.
2007   int arguments_length_offset = -1;
2008   for (int i = 0; i < param_count; ++i) {
2009     output_frame_offset -= kPointerSize;
2010     WriteTranslatedValueToOutput(&value_iterator, &input_index, 0,
2011                                  output_frame_offset);
2012 
2013     if (!arg_count_known &&
2014         descriptor.GetRegisterParameter(i)
2015             .is(descriptor.stack_parameter_count())) {
2016       arguments_length_offset = output_frame_offset;
2017     }
2018   }
2019 
2020   Object* maybe_context = value_iterator->GetRawValue();
2021   CHECK(maybe_context->IsContext());
2022   Register context_reg = StubFailureTrampolineFrame::context_register();
2023   value = reinterpret_cast<intptr_t>(maybe_context);
2024   output_frame->SetRegister(context_reg.code(), value);
2025   ++value_iterator;
2026 
2027   // Copy constant stack parameters to the failure frame. If the number of stack
2028   // parameters is not known in the descriptor, the arguments object is the way
2029   // to access them.
2030   for (int i = 0; i < stack_param_count; i++) {
2031     output_frame_offset -= kPointerSize;
2032     Object** stack_parameter = reinterpret_cast<Object**>(
2033         frame_ptr + StandardFrameConstants::kCallerSPOffset +
2034         (stack_param_count - i - 1) * kPointerSize);
2035     value = reinterpret_cast<intptr_t>(*stack_parameter);
2036     output_frame->SetFrameSlot(output_frame_offset, value);
2037     DebugPrintOutputSlot(value, frame_index, output_frame_offset,
2038                          "stack parameter\n");
2039   }
2040 
2041   CHECK_EQ(0u, output_frame_offset);
2042 
2043   if (!arg_count_known) {
2044     CHECK_GE(arguments_length_offset, 0);
2045     // We know it's a smi because 1) the code stub guarantees the stack
2046     // parameter count is in smi range, and 2) the DoTranslateCommand in the
2047     // parameter loop above translated that to a tagged value.
2048     Smi* smi_caller_arg_count = reinterpret_cast<Smi*>(
2049         output_frame->GetFrameSlot(arguments_length_offset));
2050     caller_arg_count = smi_caller_arg_count->value();
2051     output_frame->SetFrameSlot(length_frame_offset, caller_arg_count);
2052     DebugPrintOutputSlot(caller_arg_count, frame_index, length_frame_offset,
2053                          "args.length\n");
2054     value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
2055         (caller_arg_count - 1) * kPointerSize;
2056     output_frame->SetFrameSlot(args_arguments_offset, value);
2057     DebugPrintOutputSlot(value, frame_index, args_arguments_offset,
2058                          "args.arguments");
2059   }
2060 
2061   // Copy the double registers from the input into the output frame.
2062   CopyDoubleRegisters(output_frame);
2063 
2064   // Fill registers containing handler and number of parameters.
2065   SetPlatformCompiledStubRegisters(output_frame, &descriptor);
2066 
2067   // Compute this frame's PC, state, and continuation.
2068   Code* trampoline = NULL;
2069   StubFunctionMode function_mode = descriptor.function_mode();
2070   StubFailureTrampolineStub(isolate_, function_mode)
2071       .FindCodeInCache(&trampoline);
2072   DCHECK(trampoline != NULL);
2073   output_frame->SetPc(reinterpret_cast<intptr_t>(
2074       trampoline->instruction_start()));
2075   if (FLAG_enable_embedded_constant_pool) {
2076     Register constant_pool_reg =
2077         StubFailureTrampolineFrame::constant_pool_pointer_register();
2078     intptr_t constant_pool_value =
2079         reinterpret_cast<intptr_t>(trampoline->constant_pool());
2080     output_frame->SetConstantPool(constant_pool_value);
2081     output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
2082   }
2083   output_frame->SetState(
2084       Smi::FromInt(static_cast<int>(BailoutState::NO_REGISTERS)));
2085   Code* notify_failure =
2086       isolate_->builtins()->builtin(Builtins::kNotifyStubFailureSaveDoubles);
2087   output_frame->SetContinuation(
2088       reinterpret_cast<intptr_t>(notify_failure->entry()));
2089 }
2090 
2091 
MaterializeHeapObjects(JavaScriptFrameIterator * it)2092 void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
2093   // Walk to the last JavaScript output frame to find out if it has
2094   // adapted arguments.
2095   for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
2096     if (frame_index != 0) it->Advance();
2097   }
2098   translated_state_.Prepare(it->frame()->has_adapted_arguments(),
2099                             reinterpret_cast<Address>(stack_fp_));
2100 
2101   for (auto& materialization : values_to_materialize_) {
2102     Handle<Object> value = materialization.value_->GetValue();
2103 
2104     if (trace_scope_ != nullptr) {
2105       PrintF("Materialization [0x%08" V8PRIxPTR "] <- 0x%08" V8PRIxPTR " ;  ",
2106              reinterpret_cast<intptr_t>(materialization.output_slot_address_),
2107              reinterpret_cast<intptr_t>(*value));
2108       value->ShortPrint(trace_scope_->file());
2109       PrintF(trace_scope_->file(), "\n");
2110     }
2111 
2112     *(reinterpret_cast<intptr_t*>(materialization.output_slot_address_)) =
2113         reinterpret_cast<intptr_t>(*value);
2114   }
2115 
2116   isolate_->materialized_object_store()->Remove(
2117       reinterpret_cast<Address>(stack_fp_));
2118 }
2119 
2120 
WriteTranslatedValueToOutput(TranslatedFrame::iterator * iterator,int * input_index,int frame_index,unsigned output_offset,const char * debug_hint_string,Address output_address_for_materialization)2121 void Deoptimizer::WriteTranslatedValueToOutput(
2122     TranslatedFrame::iterator* iterator, int* input_index, int frame_index,
2123     unsigned output_offset, const char* debug_hint_string,
2124     Address output_address_for_materialization) {
2125   Object* value = (*iterator)->GetRawValue();
2126 
2127   WriteValueToOutput(value, *input_index, frame_index, output_offset,
2128                      debug_hint_string);
2129 
2130   if (value == isolate_->heap()->arguments_marker()) {
2131     Address output_address =
2132         reinterpret_cast<Address>(output_[frame_index]->GetTop()) +
2133         output_offset;
2134     if (output_address_for_materialization == nullptr) {
2135       output_address_for_materialization = output_address;
2136     }
2137     values_to_materialize_.push_back(
2138         {output_address_for_materialization, *iterator});
2139   }
2140 
2141   (*iterator)++;
2142   (*input_index)++;
2143 }
2144 
2145 
WriteValueToOutput(Object * value,int input_index,int frame_index,unsigned output_offset,const char * debug_hint_string)2146 void Deoptimizer::WriteValueToOutput(Object* value, int input_index,
2147                                      int frame_index, unsigned output_offset,
2148                                      const char* debug_hint_string) {
2149   output_[frame_index]->SetFrameSlot(output_offset,
2150                                      reinterpret_cast<intptr_t>(value));
2151 
2152   if (trace_scope_ != nullptr) {
2153     DebugPrintOutputSlot(reinterpret_cast<intptr_t>(value), frame_index,
2154                          output_offset, debug_hint_string);
2155     value->ShortPrint(trace_scope_->file());
2156     PrintF(trace_scope_->file(), "  (input #%d)\n", input_index);
2157   }
2158 }
2159 
2160 
DebugPrintOutputSlot(intptr_t value,int frame_index,unsigned output_offset,const char * debug_hint_string)2161 void Deoptimizer::DebugPrintOutputSlot(intptr_t value, int frame_index,
2162                                        unsigned output_offset,
2163                                        const char* debug_hint_string) {
2164   if (trace_scope_ != nullptr) {
2165     Address output_address =
2166         reinterpret_cast<Address>(output_[frame_index]->GetTop()) +
2167         output_offset;
2168     PrintF(trace_scope_->file(),
2169            "    0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ;  %s",
2170            reinterpret_cast<intptr_t>(output_address), output_offset, value,
2171            debug_hint_string == nullptr ? "" : debug_hint_string);
2172   }
2173 }
2174 
ComputeInputFrameAboveFpFixedSize() const2175 unsigned Deoptimizer::ComputeInputFrameAboveFpFixedSize() const {
2176   unsigned fixed_size = CommonFrameConstants::kFixedFrameSizeAboveFp;
2177   if (!function_->IsSmi()) {
2178     fixed_size += ComputeIncomingArgumentSize(function_->shared());
2179   }
2180   return fixed_size;
2181 }
2182 
ComputeInputFrameSize() const2183 unsigned Deoptimizer::ComputeInputFrameSize() const {
2184   // The fp-to-sp delta already takes the context, constant pool pointer and the
2185   // function into account so we have to avoid double counting them.
2186   unsigned fixed_size_above_fp = ComputeInputFrameAboveFpFixedSize();
2187   unsigned result = fixed_size_above_fp + fp_to_sp_delta_;
2188   if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
2189     unsigned stack_slots = compiled_code_->stack_slots();
2190     unsigned outgoing_size =
2191         ComputeOutgoingArgumentSize(compiled_code_, bailout_id_);
2192     CHECK_EQ(fixed_size_above_fp + (stack_slots * kPointerSize) -
2193                  CommonFrameConstants::kFixedFrameSizeAboveFp + outgoing_size,
2194              result);
2195   }
2196   return result;
2197 }
2198 
2199 // static
ComputeJavascriptFixedSize(SharedFunctionInfo * shared)2200 unsigned Deoptimizer::ComputeJavascriptFixedSize(SharedFunctionInfo* shared) {
2201   // The fixed part of the frame consists of the return address, frame
2202   // pointer, function, context, and all the incoming arguments.
2203   return ComputeIncomingArgumentSize(shared) +
2204          StandardFrameConstants::kFixedFrameSize;
2205 }
2206 
2207 // static
ComputeInterpretedFixedSize(SharedFunctionInfo * shared)2208 unsigned Deoptimizer::ComputeInterpretedFixedSize(SharedFunctionInfo* shared) {
2209   // The fixed part of the frame consists of the return address, frame
2210   // pointer, function, context, new.target, bytecode offset and all the
2211   // incoming arguments.
2212   return ComputeIncomingArgumentSize(shared) +
2213          InterpreterFrameConstants::kFixedFrameSize;
2214 }
2215 
2216 // static
ComputeIncomingArgumentSize(SharedFunctionInfo * shared)2217 unsigned Deoptimizer::ComputeIncomingArgumentSize(SharedFunctionInfo* shared) {
2218   return (shared->internal_formal_parameter_count() + 1) * kPointerSize;
2219 }
2220 
2221 
2222 // static
ComputeOutgoingArgumentSize(Code * code,unsigned bailout_id)2223 unsigned Deoptimizer::ComputeOutgoingArgumentSize(Code* code,
2224                                                   unsigned bailout_id) {
2225   DeoptimizationInputData* data =
2226       DeoptimizationInputData::cast(code->deoptimization_data());
2227   unsigned height = data->ArgumentsStackHeight(bailout_id)->value();
2228   return height * kPointerSize;
2229 }
2230 
EnsureCodeForDeoptimizationEntry(Isolate * isolate,BailoutType type,int max_entry_id)2231 void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate,
2232                                                    BailoutType type,
2233                                                    int max_entry_id) {
2234   // We cannot run this if the serializer is enabled because this will
2235   // cause us to emit relocation information for the external
2236   // references. This is fine because the deoptimizer's code section
2237   // isn't meant to be serialized at all.
2238   CHECK(type == EAGER || type == SOFT || type == LAZY);
2239   DeoptimizerData* data = isolate->deoptimizer_data();
2240   int entry_count = data->deopt_entry_code_entries_[type];
2241   if (max_entry_id < entry_count) return;
2242   entry_count = Max(entry_count, Deoptimizer::kMinNumberOfEntries);
2243   while (max_entry_id >= entry_count) entry_count *= 2;
2244   CHECK(entry_count <= Deoptimizer::kMaxNumberOfEntries);
2245 
2246   MacroAssembler masm(isolate, NULL, 16 * KB, CodeObjectRequired::kYes);
2247   masm.set_emit_debug_code(false);
2248   GenerateDeoptimizationEntries(&masm, entry_count, type);
2249   CodeDesc desc;
2250   masm.GetCode(&desc);
2251   DCHECK(!RelocInfo::RequiresRelocation(desc));
2252 
2253   MemoryChunk* chunk = data->deopt_entry_code_[type];
2254   CHECK(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >=
2255         desc.instr_size);
2256   if (!chunk->CommitArea(desc.instr_size)) {
2257     V8::FatalProcessOutOfMemory(
2258         "Deoptimizer::EnsureCodeForDeoptimizationEntry");
2259   }
2260   CopyBytes(chunk->area_start(), desc.buffer,
2261             static_cast<size_t>(desc.instr_size));
2262   Assembler::FlushICache(isolate, chunk->area_start(), desc.instr_size);
2263 
2264   data->deopt_entry_code_entries_[type] = entry_count;
2265 }
2266 
FrameDescription(uint32_t frame_size,int parameter_count)2267 FrameDescription::FrameDescription(uint32_t frame_size, int parameter_count)
2268     : frame_size_(frame_size),
2269       parameter_count_(parameter_count),
2270       top_(kZapUint32),
2271       pc_(kZapUint32),
2272       fp_(kZapUint32),
2273       context_(kZapUint32),
2274       constant_pool_(kZapUint32) {
2275   // Zap all the registers.
2276   for (int r = 0; r < Register::kNumRegisters; r++) {
2277     // TODO(jbramley): It isn't safe to use kZapUint32 here. If the register
2278     // isn't used before the next safepoint, the GC will try to scan it as a
2279     // tagged value. kZapUint32 looks like a valid tagged pointer, but it isn't.
2280     SetRegister(r, kZapUint32);
2281   }
2282 
2283   // Zap all the slots.
2284   for (unsigned o = 0; o < frame_size; o += kPointerSize) {
2285     SetFrameSlot(o, kZapUint32);
2286   }
2287 }
2288 
Add(int32_t value)2289 void TranslationBuffer::Add(int32_t value) {
2290   // This wouldn't handle kMinInt correctly if it ever encountered it.
2291   DCHECK(value != kMinInt);
2292   // Encode the sign bit in the least significant bit.
2293   bool is_negative = (value < 0);
2294   uint32_t bits = ((is_negative ? -value : value) << 1) |
2295       static_cast<int32_t>(is_negative);
2296   // Encode the individual bytes using the least significant bit of
2297   // each byte to indicate whether or not more bytes follow.
2298   do {
2299     uint32_t next = bits >> 7;
2300     contents_.push_back(((bits << 1) & 0xFF) | (next != 0));
2301     bits = next;
2302   } while (bits != 0);
2303 }
2304 
2305 
Next()2306 int32_t TranslationIterator::Next() {
2307   // Run through the bytes until we reach one with a least significant
2308   // bit of zero (marks the end).
2309   uint32_t bits = 0;
2310   for (int i = 0; true; i += 7) {
2311     DCHECK(HasNext());
2312     uint8_t next = buffer_->get(index_++);
2313     bits |= (next >> 1) << i;
2314     if ((next & 1) == 0) break;
2315   }
2316   // The bits encode the sign in the least significant bit.
2317   bool is_negative = (bits & 1) == 1;
2318   int32_t result = bits >> 1;
2319   return is_negative ? -result : result;
2320 }
2321 
2322 
CreateByteArray(Factory * factory)2323 Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
2324   Handle<ByteArray> result = factory->NewByteArray(CurrentIndex(), TENURED);
2325   contents_.CopyTo(result->GetDataStartAddress());
2326   return result;
2327 }
2328 
2329 
BeginConstructStubFrame(int literal_id,unsigned height)2330 void Translation::BeginConstructStubFrame(int literal_id, unsigned height) {
2331   buffer_->Add(CONSTRUCT_STUB_FRAME);
2332   buffer_->Add(literal_id);
2333   buffer_->Add(height);
2334 }
2335 
2336 
BeginGetterStubFrame(int literal_id)2337 void Translation::BeginGetterStubFrame(int literal_id) {
2338   buffer_->Add(GETTER_STUB_FRAME);
2339   buffer_->Add(literal_id);
2340 }
2341 
2342 
BeginSetterStubFrame(int literal_id)2343 void Translation::BeginSetterStubFrame(int literal_id) {
2344   buffer_->Add(SETTER_STUB_FRAME);
2345   buffer_->Add(literal_id);
2346 }
2347 
2348 
BeginArgumentsAdaptorFrame(int literal_id,unsigned height)2349 void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
2350   buffer_->Add(ARGUMENTS_ADAPTOR_FRAME);
2351   buffer_->Add(literal_id);
2352   buffer_->Add(height);
2353 }
2354 
BeginTailCallerFrame(int literal_id)2355 void Translation::BeginTailCallerFrame(int literal_id) {
2356   buffer_->Add(TAIL_CALLER_FRAME);
2357   buffer_->Add(literal_id);
2358 }
2359 
BeginJSFrame(BailoutId node_id,int literal_id,unsigned height)2360 void Translation::BeginJSFrame(BailoutId node_id,
2361                                int literal_id,
2362                                unsigned height) {
2363   buffer_->Add(JS_FRAME);
2364   buffer_->Add(node_id.ToInt());
2365   buffer_->Add(literal_id);
2366   buffer_->Add(height);
2367 }
2368 
2369 
BeginInterpretedFrame(BailoutId bytecode_offset,int literal_id,unsigned height)2370 void Translation::BeginInterpretedFrame(BailoutId bytecode_offset,
2371                                         int literal_id, unsigned height) {
2372   buffer_->Add(INTERPRETED_FRAME);
2373   buffer_->Add(bytecode_offset.ToInt());
2374   buffer_->Add(literal_id);
2375   buffer_->Add(height);
2376 }
2377 
2378 
BeginCompiledStubFrame(int height)2379 void Translation::BeginCompiledStubFrame(int height) {
2380   buffer_->Add(COMPILED_STUB_FRAME);
2381   buffer_->Add(height);
2382 }
2383 
2384 
BeginArgumentsObject(int args_length)2385 void Translation::BeginArgumentsObject(int args_length) {
2386   buffer_->Add(ARGUMENTS_OBJECT);
2387   buffer_->Add(args_length);
2388 }
2389 
2390 
BeginCapturedObject(int length)2391 void Translation::BeginCapturedObject(int length) {
2392   buffer_->Add(CAPTURED_OBJECT);
2393   buffer_->Add(length);
2394 }
2395 
2396 
DuplicateObject(int object_index)2397 void Translation::DuplicateObject(int object_index) {
2398   buffer_->Add(DUPLICATED_OBJECT);
2399   buffer_->Add(object_index);
2400 }
2401 
2402 
StoreRegister(Register reg)2403 void Translation::StoreRegister(Register reg) {
2404   buffer_->Add(REGISTER);
2405   buffer_->Add(reg.code());
2406 }
2407 
2408 
StoreInt32Register(Register reg)2409 void Translation::StoreInt32Register(Register reg) {
2410   buffer_->Add(INT32_REGISTER);
2411   buffer_->Add(reg.code());
2412 }
2413 
2414 
StoreUint32Register(Register reg)2415 void Translation::StoreUint32Register(Register reg) {
2416   buffer_->Add(UINT32_REGISTER);
2417   buffer_->Add(reg.code());
2418 }
2419 
2420 
StoreBoolRegister(Register reg)2421 void Translation::StoreBoolRegister(Register reg) {
2422   buffer_->Add(BOOL_REGISTER);
2423   buffer_->Add(reg.code());
2424 }
2425 
StoreFloatRegister(FloatRegister reg)2426 void Translation::StoreFloatRegister(FloatRegister reg) {
2427   buffer_->Add(FLOAT_REGISTER);
2428   buffer_->Add(reg.code());
2429 }
2430 
StoreDoubleRegister(DoubleRegister reg)2431 void Translation::StoreDoubleRegister(DoubleRegister reg) {
2432   buffer_->Add(DOUBLE_REGISTER);
2433   buffer_->Add(reg.code());
2434 }
2435 
2436 
StoreStackSlot(int index)2437 void Translation::StoreStackSlot(int index) {
2438   buffer_->Add(STACK_SLOT);
2439   buffer_->Add(index);
2440 }
2441 
2442 
StoreInt32StackSlot(int index)2443 void Translation::StoreInt32StackSlot(int index) {
2444   buffer_->Add(INT32_STACK_SLOT);
2445   buffer_->Add(index);
2446 }
2447 
2448 
StoreUint32StackSlot(int index)2449 void Translation::StoreUint32StackSlot(int index) {
2450   buffer_->Add(UINT32_STACK_SLOT);
2451   buffer_->Add(index);
2452 }
2453 
2454 
StoreBoolStackSlot(int index)2455 void Translation::StoreBoolStackSlot(int index) {
2456   buffer_->Add(BOOL_STACK_SLOT);
2457   buffer_->Add(index);
2458 }
2459 
StoreFloatStackSlot(int index)2460 void Translation::StoreFloatStackSlot(int index) {
2461   buffer_->Add(FLOAT_STACK_SLOT);
2462   buffer_->Add(index);
2463 }
2464 
StoreDoubleStackSlot(int index)2465 void Translation::StoreDoubleStackSlot(int index) {
2466   buffer_->Add(DOUBLE_STACK_SLOT);
2467   buffer_->Add(index);
2468 }
2469 
2470 
StoreLiteral(int literal_id)2471 void Translation::StoreLiteral(int literal_id) {
2472   buffer_->Add(LITERAL);
2473   buffer_->Add(literal_id);
2474 }
2475 
2476 
StoreArgumentsObject(bool args_known,int args_index,int args_length)2477 void Translation::StoreArgumentsObject(bool args_known,
2478                                        int args_index,
2479                                        int args_length) {
2480   buffer_->Add(ARGUMENTS_OBJECT);
2481   buffer_->Add(args_known);
2482   buffer_->Add(args_index);
2483   buffer_->Add(args_length);
2484 }
2485 
2486 
StoreJSFrameFunction()2487 void Translation::StoreJSFrameFunction() {
2488   StoreStackSlot((StandardFrameConstants::kCallerPCOffset -
2489                   StandardFrameConstants::kFunctionOffset) /
2490                  kPointerSize);
2491 }
2492 
NumberOfOperandsFor(Opcode opcode)2493 int Translation::NumberOfOperandsFor(Opcode opcode) {
2494   switch (opcode) {
2495     case GETTER_STUB_FRAME:
2496     case SETTER_STUB_FRAME:
2497     case DUPLICATED_OBJECT:
2498     case ARGUMENTS_OBJECT:
2499     case CAPTURED_OBJECT:
2500     case REGISTER:
2501     case INT32_REGISTER:
2502     case UINT32_REGISTER:
2503     case BOOL_REGISTER:
2504     case FLOAT_REGISTER:
2505     case DOUBLE_REGISTER:
2506     case STACK_SLOT:
2507     case INT32_STACK_SLOT:
2508     case UINT32_STACK_SLOT:
2509     case BOOL_STACK_SLOT:
2510     case FLOAT_STACK_SLOT:
2511     case DOUBLE_STACK_SLOT:
2512     case LITERAL:
2513     case COMPILED_STUB_FRAME:
2514     case TAIL_CALLER_FRAME:
2515       return 1;
2516     case BEGIN:
2517     case ARGUMENTS_ADAPTOR_FRAME:
2518     case CONSTRUCT_STUB_FRAME:
2519       return 2;
2520     case JS_FRAME:
2521     case INTERPRETED_FRAME:
2522       return 3;
2523   }
2524   FATAL("Unexpected translation type");
2525   return -1;
2526 }
2527 
2528 
2529 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
2530 
StringFor(Opcode opcode)2531 const char* Translation::StringFor(Opcode opcode) {
2532 #define TRANSLATION_OPCODE_CASE(item)   case item: return #item;
2533   switch (opcode) {
2534     TRANSLATION_OPCODE_LIST(TRANSLATION_OPCODE_CASE)
2535   }
2536 #undef TRANSLATION_OPCODE_CASE
2537   UNREACHABLE();
2538   return "";
2539 }
2540 
2541 #endif
2542 
2543 
Get(Address fp)2544 Handle<FixedArray> MaterializedObjectStore::Get(Address fp) {
2545   int index = StackIdToIndex(fp);
2546   if (index == -1) {
2547     return Handle<FixedArray>::null();
2548   }
2549   Handle<FixedArray> array = GetStackEntries();
2550   CHECK_GT(array->length(), index);
2551   return Handle<FixedArray>::cast(Handle<Object>(array->get(index), isolate()));
2552 }
2553 
2554 
Set(Address fp,Handle<FixedArray> materialized_objects)2555 void MaterializedObjectStore::Set(Address fp,
2556                                   Handle<FixedArray> materialized_objects) {
2557   int index = StackIdToIndex(fp);
2558   if (index == -1) {
2559     index = frame_fps_.length();
2560     frame_fps_.Add(fp);
2561   }
2562 
2563   Handle<FixedArray> array = EnsureStackEntries(index + 1);
2564   array->set(index, *materialized_objects);
2565 }
2566 
2567 
Remove(Address fp)2568 bool MaterializedObjectStore::Remove(Address fp) {
2569   int index = StackIdToIndex(fp);
2570   if (index == -1) {
2571     return false;
2572   }
2573   CHECK_GE(index, 0);
2574 
2575   frame_fps_.Remove(index);
2576   FixedArray* array = isolate()->heap()->materialized_objects();
2577   CHECK_LT(index, array->length());
2578   for (int i = index; i < frame_fps_.length(); i++) {
2579     array->set(i, array->get(i + 1));
2580   }
2581   array->set(frame_fps_.length(), isolate()->heap()->undefined_value());
2582   return true;
2583 }
2584 
2585 
StackIdToIndex(Address fp)2586 int MaterializedObjectStore::StackIdToIndex(Address fp) {
2587   for (int i = 0; i < frame_fps_.length(); i++) {
2588     if (frame_fps_[i] == fp) {
2589       return i;
2590     }
2591   }
2592   return -1;
2593 }
2594 
2595 
GetStackEntries()2596 Handle<FixedArray> MaterializedObjectStore::GetStackEntries() {
2597   return Handle<FixedArray>(isolate()->heap()->materialized_objects());
2598 }
2599 
2600 
EnsureStackEntries(int length)2601 Handle<FixedArray> MaterializedObjectStore::EnsureStackEntries(int length) {
2602   Handle<FixedArray> array = GetStackEntries();
2603   if (array->length() >= length) {
2604     return array;
2605   }
2606 
2607   int new_length = length > 10 ? length : 10;
2608   if (new_length < 2 * array->length()) {
2609     new_length = 2 * array->length();
2610   }
2611 
2612   Handle<FixedArray> new_array =
2613       isolate()->factory()->NewFixedArray(new_length, TENURED);
2614   for (int i = 0; i < array->length(); i++) {
2615     new_array->set(i, array->get(i));
2616   }
2617   for (int i = array->length(); i < length; i++) {
2618     new_array->set(i, isolate()->heap()->undefined_value());
2619   }
2620   isolate()->heap()->SetRootMaterializedObjects(*new_array);
2621   return new_array;
2622 }
2623 
2624 namespace {
2625 
GetValueForDebugger(TranslatedFrame::iterator it,Isolate * isolate)2626 Handle<Object> GetValueForDebugger(TranslatedFrame::iterator it,
2627                                    Isolate* isolate) {
2628   if (it->GetRawValue() == isolate->heap()->arguments_marker()) {
2629     if (!it->IsMaterializableByDebugger()) {
2630       return isolate->factory()->undefined_value();
2631     }
2632   }
2633   return it->GetValue();
2634 }
2635 
2636 }  // namespace
2637 
DeoptimizedFrameInfo(TranslatedState * state,TranslatedState::iterator frame_it,Isolate * isolate)2638 DeoptimizedFrameInfo::DeoptimizedFrameInfo(TranslatedState* state,
2639                                            TranslatedState::iterator frame_it,
2640                                            Isolate* isolate) {
2641   // If the previous frame is an adaptor frame, we will take the parameters
2642   // from there.
2643   TranslatedState::iterator parameter_frame = frame_it;
2644   if (parameter_frame != state->begin()) {
2645     parameter_frame--;
2646   }
2647   int parameter_count;
2648   if (parameter_frame->kind() == TranslatedFrame::kArgumentsAdaptor) {
2649     parameter_count = parameter_frame->height() - 1;  // Ignore the receiver.
2650   } else {
2651     parameter_frame = frame_it;
2652     parameter_count =
2653         frame_it->shared_info()->internal_formal_parameter_count();
2654   }
2655   TranslatedFrame::iterator parameter_it = parameter_frame->begin();
2656   parameter_it++;  // Skip the function.
2657   parameter_it++;  // Skip the receiver.
2658 
2659   // Figure out whether there is a construct stub frame on top of
2660   // the parameter frame.
2661   has_construct_stub_ =
2662       parameter_frame != state->begin() &&
2663       (parameter_frame - 1)->kind() == TranslatedFrame::kConstructStub;
2664 
2665   if (frame_it->kind() == TranslatedFrame::kInterpretedFunction) {
2666     source_position_ = Deoptimizer::ComputeSourcePositionFromBytecodeArray(
2667         *frame_it->shared_info(), frame_it->node_id());
2668   } else {
2669     DCHECK_EQ(TranslatedFrame::kFunction, frame_it->kind());
2670     source_position_ = Deoptimizer::ComputeSourcePositionFromBaselineCode(
2671         *frame_it->shared_info(), frame_it->node_id());
2672   }
2673 
2674   TranslatedFrame::iterator value_it = frame_it->begin();
2675   // Get the function. Note that this might materialize the function.
2676   // In case the debugger mutates this value, we should deoptimize
2677   // the function and remember the value in the materialized value store.
2678   function_ = Handle<JSFunction>::cast(value_it->GetValue());
2679 
2680   parameters_.resize(static_cast<size_t>(parameter_count));
2681   for (int i = 0; i < parameter_count; i++) {
2682     Handle<Object> parameter = GetValueForDebugger(parameter_it, isolate);
2683     SetParameter(i, parameter);
2684     parameter_it++;
2685   }
2686 
2687   // Skip the function, the receiver and the arguments.
2688   int skip_count =
2689       frame_it->shared_info()->internal_formal_parameter_count() + 2;
2690   TranslatedFrame::iterator stack_it = frame_it->begin();
2691   for (int i = 0; i < skip_count; i++) {
2692     stack_it++;
2693   }
2694 
2695   // Get the context.
2696   context_ = GetValueForDebugger(stack_it, isolate);
2697   stack_it++;
2698 
2699   // Get the expression stack.
2700   int stack_height = frame_it->height();
2701   if (frame_it->kind() == TranslatedFrame::kFunction ||
2702       frame_it->kind() == TranslatedFrame::kInterpretedFunction) {
2703     // For full-code frames, we should not count the context.
2704     // For interpreter frames, we should not count the accumulator.
2705     // TODO(jarin): Clean up the indexing in translated frames.
2706     stack_height--;
2707   }
2708   expression_stack_.resize(static_cast<size_t>(stack_height));
2709   for (int i = 0; i < stack_height; i++) {
2710     Handle<Object> expression = GetValueForDebugger(stack_it, isolate);
2711     SetExpression(i, expression);
2712     stack_it++;
2713   }
2714 
2715   // For interpreter frame, skip the accumulator.
2716   if (frame_it->kind() == TranslatedFrame::kInterpretedFunction) {
2717     stack_it++;
2718   }
2719   CHECK(stack_it == frame_it->end());
2720 }
2721 
2722 
GetDeoptInfo(Code * code,Address pc)2723 Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code* code, Address pc) {
2724   SourcePosition last_position = SourcePosition::Unknown();
2725   DeoptimizeReason last_reason = DeoptimizeReason::kNoReason;
2726   int last_deopt_id = kNoDeoptimizationId;
2727   int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_REASON) |
2728              RelocInfo::ModeMask(RelocInfo::DEOPT_ID) |
2729              RelocInfo::ModeMask(RelocInfo::DEOPT_SCRIPT_OFFSET) |
2730              RelocInfo::ModeMask(RelocInfo::DEOPT_INLINING_ID);
2731   for (RelocIterator it(code, mask); !it.done(); it.next()) {
2732     RelocInfo* info = it.rinfo();
2733     if (info->pc() >= pc) {
2734       return DeoptInfo(last_position, last_reason, last_deopt_id);
2735     }
2736     if (info->rmode() == RelocInfo::DEOPT_SCRIPT_OFFSET) {
2737       int script_offset = static_cast<int>(info->data());
2738       it.next();
2739       DCHECK(it.rinfo()->rmode() == RelocInfo::DEOPT_INLINING_ID);
2740       int inlining_id = static_cast<int>(it.rinfo()->data());
2741       last_position = SourcePosition(script_offset, inlining_id);
2742     } else if (info->rmode() == RelocInfo::DEOPT_ID) {
2743       last_deopt_id = static_cast<int>(info->data());
2744     } else if (info->rmode() == RelocInfo::DEOPT_REASON) {
2745       last_reason = static_cast<DeoptimizeReason>(info->data());
2746     }
2747   }
2748   return DeoptInfo(SourcePosition::Unknown(), DeoptimizeReason::kNoReason, -1);
2749 }
2750 
2751 
2752 // static
ComputeSourcePositionFromBaselineCode(SharedFunctionInfo * shared,BailoutId node_id)2753 int Deoptimizer::ComputeSourcePositionFromBaselineCode(
2754     SharedFunctionInfo* shared, BailoutId node_id) {
2755   DCHECK(shared->HasBaselineCode());
2756   Code* code = shared->code();
2757   FixedArray* raw_data = code->deoptimization_data();
2758   DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
2759   unsigned pc_and_state = Deoptimizer::GetOutputInfo(data, node_id, shared);
2760   int code_offset =
2761       static_cast<int>(FullCodeGenerator::PcField::decode(pc_and_state));
2762   return AbstractCode::cast(code)->SourcePosition(code_offset);
2763 }
2764 
2765 // static
ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo * shared,BailoutId node_id)2766 int Deoptimizer::ComputeSourcePositionFromBytecodeArray(
2767     SharedFunctionInfo* shared, BailoutId node_id) {
2768   DCHECK(shared->HasBytecodeArray());
2769   return AbstractCode::cast(shared->bytecode_array())
2770       ->SourcePosition(node_id.ToInt());
2771 }
2772 
2773 // static
NewArgumentsObject(TranslatedState * container,int length,int object_index)2774 TranslatedValue TranslatedValue::NewArgumentsObject(TranslatedState* container,
2775                                                     int length,
2776                                                     int object_index) {
2777   TranslatedValue slot(container, kArgumentsObject);
2778   slot.materialization_info_ = {object_index, length};
2779   return slot;
2780 }
2781 
2782 
2783 // static
NewDeferredObject(TranslatedState * container,int length,int object_index)2784 TranslatedValue TranslatedValue::NewDeferredObject(TranslatedState* container,
2785                                                    int length,
2786                                                    int object_index) {
2787   TranslatedValue slot(container, kCapturedObject);
2788   slot.materialization_info_ = {object_index, length};
2789   return slot;
2790 }
2791 
2792 
2793 // static
NewDuplicateObject(TranslatedState * container,int id)2794 TranslatedValue TranslatedValue::NewDuplicateObject(TranslatedState* container,
2795                                                     int id) {
2796   TranslatedValue slot(container, kDuplicatedObject);
2797   slot.materialization_info_ = {id, -1};
2798   return slot;
2799 }
2800 
2801 
2802 // static
NewFloat(TranslatedState * container,float value)2803 TranslatedValue TranslatedValue::NewFloat(TranslatedState* container,
2804                                           float value) {
2805   TranslatedValue slot(container, kFloat);
2806   slot.float_value_ = value;
2807   return slot;
2808 }
2809 
2810 // static
NewDouble(TranslatedState * container,double value)2811 TranslatedValue TranslatedValue::NewDouble(TranslatedState* container,
2812                                            double value) {
2813   TranslatedValue slot(container, kDouble);
2814   slot.double_value_ = value;
2815   return slot;
2816 }
2817 
2818 
2819 // static
NewInt32(TranslatedState * container,int32_t value)2820 TranslatedValue TranslatedValue::NewInt32(TranslatedState* container,
2821                                           int32_t value) {
2822   TranslatedValue slot(container, kInt32);
2823   slot.int32_value_ = value;
2824   return slot;
2825 }
2826 
2827 
2828 // static
NewUInt32(TranslatedState * container,uint32_t value)2829 TranslatedValue TranslatedValue::NewUInt32(TranslatedState* container,
2830                                            uint32_t value) {
2831   TranslatedValue slot(container, kUInt32);
2832   slot.uint32_value_ = value;
2833   return slot;
2834 }
2835 
2836 
2837 // static
NewBool(TranslatedState * container,uint32_t value)2838 TranslatedValue TranslatedValue::NewBool(TranslatedState* container,
2839                                          uint32_t value) {
2840   TranslatedValue slot(container, kBoolBit);
2841   slot.uint32_value_ = value;
2842   return slot;
2843 }
2844 
2845 
2846 // static
NewTagged(TranslatedState * container,Object * literal)2847 TranslatedValue TranslatedValue::NewTagged(TranslatedState* container,
2848                                            Object* literal) {
2849   TranslatedValue slot(container, kTagged);
2850   slot.raw_literal_ = literal;
2851   return slot;
2852 }
2853 
2854 
2855 // static
NewInvalid(TranslatedState * container)2856 TranslatedValue TranslatedValue::NewInvalid(TranslatedState* container) {
2857   return TranslatedValue(container, kInvalid);
2858 }
2859 
2860 
isolate() const2861 Isolate* TranslatedValue::isolate() const { return container_->isolate(); }
2862 
2863 
raw_literal() const2864 Object* TranslatedValue::raw_literal() const {
2865   DCHECK_EQ(kTagged, kind());
2866   return raw_literal_;
2867 }
2868 
2869 
int32_value() const2870 int32_t TranslatedValue::int32_value() const {
2871   DCHECK_EQ(kInt32, kind());
2872   return int32_value_;
2873 }
2874 
2875 
uint32_value() const2876 uint32_t TranslatedValue::uint32_value() const {
2877   DCHECK(kind() == kUInt32 || kind() == kBoolBit);
2878   return uint32_value_;
2879 }
2880 
float_value() const2881 float TranslatedValue::float_value() const {
2882   DCHECK_EQ(kFloat, kind());
2883   return float_value_;
2884 }
2885 
double_value() const2886 double TranslatedValue::double_value() const {
2887   DCHECK_EQ(kDouble, kind());
2888   return double_value_;
2889 }
2890 
2891 
object_length() const2892 int TranslatedValue::object_length() const {
2893   DCHECK(kind() == kArgumentsObject || kind() == kCapturedObject);
2894   return materialization_info_.length_;
2895 }
2896 
2897 
object_index() const2898 int TranslatedValue::object_index() const {
2899   DCHECK(kind() == kArgumentsObject || kind() == kCapturedObject ||
2900          kind() == kDuplicatedObject);
2901   return materialization_info_.id_;
2902 }
2903 
2904 
GetRawValue() const2905 Object* TranslatedValue::GetRawValue() const {
2906   // If we have a value, return it.
2907   Handle<Object> result_handle;
2908   if (value_.ToHandle(&result_handle)) {
2909     return *result_handle;
2910   }
2911 
2912   // Otherwise, do a best effort to get the value without allocation.
2913   switch (kind()) {
2914     case kTagged:
2915       return raw_literal();
2916 
2917     case kInt32: {
2918       bool is_smi = Smi::IsValid(int32_value());
2919       if (is_smi) {
2920         return Smi::FromInt(int32_value());
2921       }
2922       break;
2923     }
2924 
2925     case kUInt32: {
2926       bool is_smi = (uint32_value() <= static_cast<uintptr_t>(Smi::kMaxValue));
2927       if (is_smi) {
2928         return Smi::FromInt(static_cast<int32_t>(uint32_value()));
2929       }
2930       break;
2931     }
2932 
2933     case kBoolBit: {
2934       if (uint32_value() == 0) {
2935         return isolate()->heap()->false_value();
2936       } else {
2937         CHECK_EQ(1U, uint32_value());
2938         return isolate()->heap()->true_value();
2939       }
2940     }
2941 
2942     default:
2943       break;
2944   }
2945 
2946   // If we could not get the value without allocation, return the arguments
2947   // marker.
2948   return isolate()->heap()->arguments_marker();
2949 }
2950 
2951 
GetValue()2952 Handle<Object> TranslatedValue::GetValue() {
2953   Handle<Object> result;
2954   // If we already have a value, then get it.
2955   if (value_.ToHandle(&result)) return result;
2956 
2957   // Otherwise we have to materialize.
2958   switch (kind()) {
2959     case TranslatedValue::kTagged:
2960     case TranslatedValue::kInt32:
2961     case TranslatedValue::kUInt32:
2962     case TranslatedValue::kBoolBit:
2963     case TranslatedValue::kFloat:
2964     case TranslatedValue::kDouble: {
2965       MaterializeSimple();
2966       return value_.ToHandleChecked();
2967     }
2968 
2969     case TranslatedValue::kArgumentsObject:
2970     case TranslatedValue::kCapturedObject:
2971     case TranslatedValue::kDuplicatedObject:
2972       return container_->MaterializeObjectAt(object_index());
2973 
2974     case TranslatedValue::kInvalid:
2975       FATAL("unexpected case");
2976       return Handle<Object>::null();
2977   }
2978 
2979   FATAL("internal error: value missing");
2980   return Handle<Object>::null();
2981 }
2982 
2983 
MaterializeSimple()2984 void TranslatedValue::MaterializeSimple() {
2985   // If we already have materialized, return.
2986   if (!value_.is_null()) return;
2987 
2988   Object* raw_value = GetRawValue();
2989   if (raw_value != isolate()->heap()->arguments_marker()) {
2990     // We can get the value without allocation, just return it here.
2991     value_ = Handle<Object>(raw_value, isolate());
2992     return;
2993   }
2994 
2995   switch (kind()) {
2996     case kInt32: {
2997       value_ = Handle<Object>(isolate()->factory()->NewNumber(int32_value()));
2998       return;
2999     }
3000 
3001     case kUInt32:
3002       value_ = Handle<Object>(isolate()->factory()->NewNumber(uint32_value()));
3003       return;
3004 
3005     case kFloat:
3006       value_ = Handle<Object>(isolate()->factory()->NewNumber(float_value()));
3007       return;
3008 
3009     case kDouble:
3010       value_ = Handle<Object>(isolate()->factory()->NewNumber(double_value()));
3011       return;
3012 
3013     case kCapturedObject:
3014     case kDuplicatedObject:
3015     case kArgumentsObject:
3016     case kInvalid:
3017     case kTagged:
3018     case kBoolBit:
3019       FATAL("internal error: unexpected materialization.");
3020       break;
3021   }
3022 }
3023 
3024 
IsMaterializedObject() const3025 bool TranslatedValue::IsMaterializedObject() const {
3026   switch (kind()) {
3027     case kCapturedObject:
3028     case kDuplicatedObject:
3029     case kArgumentsObject:
3030       return true;
3031     default:
3032       return false;
3033   }
3034 }
3035 
IsMaterializableByDebugger() const3036 bool TranslatedValue::IsMaterializableByDebugger() const {
3037   // At the moment, we only allow materialization of doubles.
3038   return (kind() == kDouble);
3039 }
3040 
GetChildrenCount() const3041 int TranslatedValue::GetChildrenCount() const {
3042   if (kind() == kCapturedObject || kind() == kArgumentsObject) {
3043     return object_length();
3044   } else {
3045     return 0;
3046   }
3047 }
3048 
3049 
GetUInt32Slot(Address fp,int slot_offset)3050 uint32_t TranslatedState::GetUInt32Slot(Address fp, int slot_offset) {
3051   Address address = fp + slot_offset;
3052 #if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT
3053   return Memory::uint32_at(address + kIntSize);
3054 #else
3055   return Memory::uint32_at(address);
3056 #endif
3057 }
3058 
3059 
Handlify()3060 void TranslatedValue::Handlify() {
3061   if (kind() == kTagged) {
3062     value_ = Handle<Object>(raw_literal(), isolate());
3063     raw_literal_ = nullptr;
3064   }
3065 }
3066 
3067 
JSFrame(BailoutId node_id,SharedFunctionInfo * shared_info,int height)3068 TranslatedFrame TranslatedFrame::JSFrame(BailoutId node_id,
3069                                          SharedFunctionInfo* shared_info,
3070                                          int height) {
3071   TranslatedFrame frame(kFunction, shared_info->GetIsolate(), shared_info,
3072                         height);
3073   frame.node_id_ = node_id;
3074   return frame;
3075 }
3076 
3077 
InterpretedFrame(BailoutId bytecode_offset,SharedFunctionInfo * shared_info,int height)3078 TranslatedFrame TranslatedFrame::InterpretedFrame(
3079     BailoutId bytecode_offset, SharedFunctionInfo* shared_info, int height) {
3080   TranslatedFrame frame(kInterpretedFunction, shared_info->GetIsolate(),
3081                         shared_info, height);
3082   frame.node_id_ = bytecode_offset;
3083   return frame;
3084 }
3085 
3086 
AccessorFrame(Kind kind,SharedFunctionInfo * shared_info)3087 TranslatedFrame TranslatedFrame::AccessorFrame(
3088     Kind kind, SharedFunctionInfo* shared_info) {
3089   DCHECK(kind == kSetter || kind == kGetter);
3090   return TranslatedFrame(kind, shared_info->GetIsolate(), shared_info);
3091 }
3092 
3093 
ArgumentsAdaptorFrame(SharedFunctionInfo * shared_info,int height)3094 TranslatedFrame TranslatedFrame::ArgumentsAdaptorFrame(
3095     SharedFunctionInfo* shared_info, int height) {
3096   return TranslatedFrame(kArgumentsAdaptor, shared_info->GetIsolate(),
3097                          shared_info, height);
3098 }
3099 
TailCallerFrame(SharedFunctionInfo * shared_info)3100 TranslatedFrame TranslatedFrame::TailCallerFrame(
3101     SharedFunctionInfo* shared_info) {
3102   return TranslatedFrame(kTailCallerFunction, shared_info->GetIsolate(),
3103                          shared_info, 0);
3104 }
3105 
ConstructStubFrame(SharedFunctionInfo * shared_info,int height)3106 TranslatedFrame TranslatedFrame::ConstructStubFrame(
3107     SharedFunctionInfo* shared_info, int height) {
3108   return TranslatedFrame(kConstructStub, shared_info->GetIsolate(), shared_info,
3109                          height);
3110 }
3111 
3112 
GetValueCount()3113 int TranslatedFrame::GetValueCount() {
3114   switch (kind()) {
3115     case kFunction: {
3116       int parameter_count =
3117           raw_shared_info_->internal_formal_parameter_count() + 1;
3118       // + 1 for function.
3119       return height_ + parameter_count + 1;
3120     }
3121 
3122     case kInterpretedFunction: {
3123       int parameter_count =
3124           raw_shared_info_->internal_formal_parameter_count() + 1;
3125       // + 2 for function and context.
3126       return height_ + parameter_count + 2;
3127     }
3128 
3129     case kGetter:
3130       return 2;  // Function and receiver.
3131 
3132     case kSetter:
3133       return 3;  // Function, receiver and the value to set.
3134 
3135     case kArgumentsAdaptor:
3136     case kConstructStub:
3137       return 1 + height_;
3138 
3139     case kTailCallerFunction:
3140       return 1;  // Function.
3141 
3142     case kCompiledStub:
3143       return height_;
3144 
3145     case kInvalid:
3146       UNREACHABLE();
3147       break;
3148   }
3149   UNREACHABLE();
3150   return -1;
3151 }
3152 
3153 
Handlify()3154 void TranslatedFrame::Handlify() {
3155   if (raw_shared_info_ != nullptr) {
3156     shared_info_ = Handle<SharedFunctionInfo>(raw_shared_info_);
3157     raw_shared_info_ = nullptr;
3158   }
3159   for (auto& value : values_) {
3160     value.Handlify();
3161   }
3162 }
3163 
3164 
CreateNextTranslatedFrame(TranslationIterator * iterator,FixedArray * literal_array,Address fp,FILE * trace_file)3165 TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
3166     TranslationIterator* iterator, FixedArray* literal_array, Address fp,
3167     FILE* trace_file) {
3168   Translation::Opcode opcode =
3169       static_cast<Translation::Opcode>(iterator->Next());
3170   switch (opcode) {
3171     case Translation::JS_FRAME: {
3172       BailoutId node_id = BailoutId(iterator->Next());
3173       SharedFunctionInfo* shared_info =
3174           SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3175       int height = iterator->Next();
3176       if (trace_file != nullptr) {
3177         std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
3178         PrintF(trace_file, "  reading input frame %s", name.get());
3179         int arg_count = shared_info->internal_formal_parameter_count() + 1;
3180         PrintF(trace_file, " => node=%d, args=%d, height=%d; inputs:\n",
3181                node_id.ToInt(), arg_count, height);
3182       }
3183       return TranslatedFrame::JSFrame(node_id, shared_info, height);
3184     }
3185 
3186     case Translation::INTERPRETED_FRAME: {
3187       BailoutId bytecode_offset = BailoutId(iterator->Next());
3188       SharedFunctionInfo* shared_info =
3189           SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3190       int height = iterator->Next();
3191       if (trace_file != nullptr) {
3192         std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
3193         PrintF(trace_file, "  reading input frame %s", name.get());
3194         int arg_count = shared_info->internal_formal_parameter_count() + 1;
3195         PrintF(trace_file,
3196                " => bytecode_offset=%d, args=%d, height=%d; inputs:\n",
3197                bytecode_offset.ToInt(), arg_count, height);
3198       }
3199       return TranslatedFrame::InterpretedFrame(bytecode_offset, shared_info,
3200                                                height);
3201     }
3202 
3203     case Translation::ARGUMENTS_ADAPTOR_FRAME: {
3204       SharedFunctionInfo* shared_info =
3205           SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3206       int height = iterator->Next();
3207       if (trace_file != nullptr) {
3208         std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
3209         PrintF(trace_file, "  reading arguments adaptor frame %s", name.get());
3210         PrintF(trace_file, " => height=%d; inputs:\n", height);
3211       }
3212       return TranslatedFrame::ArgumentsAdaptorFrame(shared_info, height);
3213     }
3214 
3215     case Translation::TAIL_CALLER_FRAME: {
3216       SharedFunctionInfo* shared_info =
3217           SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3218       if (trace_file != nullptr) {
3219         std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
3220         PrintF(trace_file, "  reading tail caller frame marker %s\n",
3221                name.get());
3222       }
3223       return TranslatedFrame::TailCallerFrame(shared_info);
3224     }
3225 
3226     case Translation::CONSTRUCT_STUB_FRAME: {
3227       SharedFunctionInfo* shared_info =
3228           SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3229       int height = iterator->Next();
3230       if (trace_file != nullptr) {
3231         std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
3232         PrintF(trace_file, "  reading construct stub frame %s", name.get());
3233         PrintF(trace_file, " => height=%d; inputs:\n", height);
3234       }
3235       return TranslatedFrame::ConstructStubFrame(shared_info, height);
3236     }
3237 
3238     case Translation::GETTER_STUB_FRAME: {
3239       SharedFunctionInfo* shared_info =
3240           SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3241       if (trace_file != nullptr) {
3242         std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
3243         PrintF(trace_file, "  reading getter frame %s; inputs:\n", name.get());
3244       }
3245       return TranslatedFrame::AccessorFrame(TranslatedFrame::kGetter,
3246                                             shared_info);
3247     }
3248 
3249     case Translation::SETTER_STUB_FRAME: {
3250       SharedFunctionInfo* shared_info =
3251           SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
3252       if (trace_file != nullptr) {
3253         std::unique_ptr<char[]> name = shared_info->DebugName()->ToCString();
3254         PrintF(trace_file, "  reading setter frame %s; inputs:\n", name.get());
3255       }
3256       return TranslatedFrame::AccessorFrame(TranslatedFrame::kSetter,
3257                                             shared_info);
3258     }
3259 
3260     case Translation::COMPILED_STUB_FRAME: {
3261       int height = iterator->Next();
3262       if (trace_file != nullptr) {
3263         PrintF(trace_file,
3264                "  reading compiler stub frame => height=%d; inputs:\n", height);
3265       }
3266       return TranslatedFrame::CompiledStubFrame(height,
3267                                                 literal_array->GetIsolate());
3268     }
3269 
3270     case Translation::BEGIN:
3271     case Translation::DUPLICATED_OBJECT:
3272     case Translation::ARGUMENTS_OBJECT:
3273     case Translation::CAPTURED_OBJECT:
3274     case Translation::REGISTER:
3275     case Translation::INT32_REGISTER:
3276     case Translation::UINT32_REGISTER:
3277     case Translation::BOOL_REGISTER:
3278     case Translation::FLOAT_REGISTER:
3279     case Translation::DOUBLE_REGISTER:
3280     case Translation::STACK_SLOT:
3281     case Translation::INT32_STACK_SLOT:
3282     case Translation::UINT32_STACK_SLOT:
3283     case Translation::BOOL_STACK_SLOT:
3284     case Translation::FLOAT_STACK_SLOT:
3285     case Translation::DOUBLE_STACK_SLOT:
3286     case Translation::LITERAL:
3287       break;
3288   }
3289   FATAL("We should never get here - unexpected deopt info.");
3290   return TranslatedFrame::InvalidFrame();
3291 }
3292 
3293 
3294 // static
AdvanceIterator(std::deque<TranslatedValue>::iterator * iter)3295 void TranslatedFrame::AdvanceIterator(
3296     std::deque<TranslatedValue>::iterator* iter) {
3297   int values_to_skip = 1;
3298   while (values_to_skip > 0) {
3299     // Consume the current element.
3300     values_to_skip--;
3301     // Add all the children.
3302     values_to_skip += (*iter)->GetChildrenCount();
3303 
3304     (*iter)++;
3305   }
3306 }
3307 
3308 
3309 // We can't intermix stack decoding and allocations because
3310 // deoptimization infrastracture is not GC safe.
3311 // Thus we build a temporary structure in malloced space.
CreateNextTranslatedValue(int frame_index,int value_index,TranslationIterator * iterator,FixedArray * literal_array,Address fp,RegisterValues * registers,FILE * trace_file)3312 TranslatedValue TranslatedState::CreateNextTranslatedValue(
3313     int frame_index, int value_index, TranslationIterator* iterator,
3314     FixedArray* literal_array, Address fp, RegisterValues* registers,
3315     FILE* trace_file) {
3316   disasm::NameConverter converter;
3317 
3318   Translation::Opcode opcode =
3319       static_cast<Translation::Opcode>(iterator->Next());
3320   switch (opcode) {
3321     case Translation::BEGIN:
3322     case Translation::JS_FRAME:
3323     case Translation::INTERPRETED_FRAME:
3324     case Translation::ARGUMENTS_ADAPTOR_FRAME:
3325     case Translation::TAIL_CALLER_FRAME:
3326     case Translation::CONSTRUCT_STUB_FRAME:
3327     case Translation::GETTER_STUB_FRAME:
3328     case Translation::SETTER_STUB_FRAME:
3329     case Translation::COMPILED_STUB_FRAME:
3330       // Peeled off before getting here.
3331       break;
3332 
3333     case Translation::DUPLICATED_OBJECT: {
3334       int object_id = iterator->Next();
3335       if (trace_file != nullptr) {
3336         PrintF(trace_file, "duplicated object #%d", object_id);
3337       }
3338       object_positions_.push_back(object_positions_[object_id]);
3339       return TranslatedValue::NewDuplicateObject(this, object_id);
3340     }
3341 
3342     case Translation::ARGUMENTS_OBJECT: {
3343       int arg_count = iterator->Next();
3344       int object_index = static_cast<int>(object_positions_.size());
3345       if (trace_file != nullptr) {
3346         PrintF(trace_file, "argumets object #%d (length = %d)", object_index,
3347                arg_count);
3348       }
3349       object_positions_.push_back({frame_index, value_index});
3350       return TranslatedValue::NewArgumentsObject(this, arg_count, object_index);
3351     }
3352 
3353     case Translation::CAPTURED_OBJECT: {
3354       int field_count = iterator->Next();
3355       int object_index = static_cast<int>(object_positions_.size());
3356       if (trace_file != nullptr) {
3357         PrintF(trace_file, "captured object #%d (length = %d)", object_index,
3358                field_count);
3359       }
3360       object_positions_.push_back({frame_index, value_index});
3361       return TranslatedValue::NewDeferredObject(this, field_count,
3362                                                 object_index);
3363     }
3364 
3365     case Translation::REGISTER: {
3366       int input_reg = iterator->Next();
3367       if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3368       intptr_t value = registers->GetRegister(input_reg);
3369       if (trace_file != nullptr) {
3370         PrintF(trace_file, "0x%08" V8PRIxPTR " ; %s ", value,
3371                converter.NameOfCPURegister(input_reg));
3372         reinterpret_cast<Object*>(value)->ShortPrint(trace_file);
3373       }
3374       return TranslatedValue::NewTagged(this, reinterpret_cast<Object*>(value));
3375     }
3376 
3377     case Translation::INT32_REGISTER: {
3378       int input_reg = iterator->Next();
3379       if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3380       intptr_t value = registers->GetRegister(input_reg);
3381       if (trace_file != nullptr) {
3382         PrintF(trace_file, "%" V8PRIdPTR " ; %s ", value,
3383                converter.NameOfCPURegister(input_reg));
3384       }
3385       return TranslatedValue::NewInt32(this, static_cast<int32_t>(value));
3386     }
3387 
3388     case Translation::UINT32_REGISTER: {
3389       int input_reg = iterator->Next();
3390       if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3391       intptr_t value = registers->GetRegister(input_reg);
3392       if (trace_file != nullptr) {
3393         PrintF(trace_file, "%" V8PRIuPTR " ; %s (uint)", value,
3394                converter.NameOfCPURegister(input_reg));
3395         reinterpret_cast<Object*>(value)->ShortPrint(trace_file);
3396       }
3397       return TranslatedValue::NewUInt32(this, static_cast<uint32_t>(value));
3398     }
3399 
3400     case Translation::BOOL_REGISTER: {
3401       int input_reg = iterator->Next();
3402       if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3403       intptr_t value = registers->GetRegister(input_reg);
3404       if (trace_file != nullptr) {
3405         PrintF(trace_file, "%" V8PRIdPTR " ; %s (bool)", value,
3406                converter.NameOfCPURegister(input_reg));
3407       }
3408       return TranslatedValue::NewBool(this, static_cast<uint32_t>(value));
3409     }
3410 
3411     case Translation::FLOAT_REGISTER: {
3412       int input_reg = iterator->Next();
3413       if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3414       float value = registers->GetFloatRegister(input_reg);
3415       if (trace_file != nullptr) {
3416         PrintF(trace_file, "%e ; %s (float)", value,
3417                RegisterConfiguration::Crankshaft()->GetFloatRegisterName(
3418                    input_reg));
3419       }
3420       return TranslatedValue::NewFloat(this, value);
3421     }
3422 
3423     case Translation::DOUBLE_REGISTER: {
3424       int input_reg = iterator->Next();
3425       if (registers == nullptr) return TranslatedValue::NewInvalid(this);
3426       double value = registers->GetDoubleRegister(input_reg);
3427       if (trace_file != nullptr) {
3428         PrintF(trace_file, "%e ; %s (double)", value,
3429                RegisterConfiguration::Crankshaft()->GetDoubleRegisterName(
3430                    input_reg));
3431       }
3432       return TranslatedValue::NewDouble(this, value);
3433     }
3434 
3435     case Translation::STACK_SLOT: {
3436       int slot_offset =
3437           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3438       intptr_t value = *(reinterpret_cast<intptr_t*>(fp + slot_offset));
3439       if (trace_file != nullptr) {
3440         PrintF(trace_file, "0x%08" V8PRIxPTR " ; [fp %c %d] ", value,
3441                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3442         reinterpret_cast<Object*>(value)->ShortPrint(trace_file);
3443       }
3444       return TranslatedValue::NewTagged(this, reinterpret_cast<Object*>(value));
3445     }
3446 
3447     case Translation::INT32_STACK_SLOT: {
3448       int slot_offset =
3449           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3450       uint32_t value = GetUInt32Slot(fp, slot_offset);
3451       if (trace_file != nullptr) {
3452         PrintF(trace_file, "%d ; (int) [fp %c %d] ",
3453                static_cast<int32_t>(value), slot_offset < 0 ? '-' : '+',
3454                std::abs(slot_offset));
3455       }
3456       return TranslatedValue::NewInt32(this, value);
3457     }
3458 
3459     case Translation::UINT32_STACK_SLOT: {
3460       int slot_offset =
3461           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3462       uint32_t value = GetUInt32Slot(fp, slot_offset);
3463       if (trace_file != nullptr) {
3464         PrintF(trace_file, "%u ; (uint) [fp %c %d] ", value,
3465                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3466       }
3467       return TranslatedValue::NewUInt32(this, value);
3468     }
3469 
3470     case Translation::BOOL_STACK_SLOT: {
3471       int slot_offset =
3472           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3473       uint32_t value = GetUInt32Slot(fp, slot_offset);
3474       if (trace_file != nullptr) {
3475         PrintF(trace_file, "%u ; (bool) [fp %c %d] ", value,
3476                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3477       }
3478       return TranslatedValue::NewBool(this, value);
3479     }
3480 
3481     case Translation::FLOAT_STACK_SLOT: {
3482       int slot_offset =
3483           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3484       float value = ReadFloatValue(fp + slot_offset);
3485       if (trace_file != nullptr) {
3486         PrintF(trace_file, "%e ; (float) [fp %c %d] ", value,
3487                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3488       }
3489       return TranslatedValue::NewFloat(this, value);
3490     }
3491 
3492     case Translation::DOUBLE_STACK_SLOT: {
3493       int slot_offset =
3494           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3495       double value = ReadDoubleValue(fp + slot_offset);
3496       if (trace_file != nullptr) {
3497         PrintF(trace_file, "%e ; (double) [fp %c %d] ", value,
3498                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3499       }
3500       return TranslatedValue::NewDouble(this, value);
3501     }
3502 
3503     case Translation::LITERAL: {
3504       int literal_index = iterator->Next();
3505       Object* value = literal_array->get(literal_index);
3506       if (trace_file != nullptr) {
3507         PrintF(trace_file, "0x%08" V8PRIxPTR " ; (literal %d) ",
3508                reinterpret_cast<intptr_t>(value), literal_index);
3509         reinterpret_cast<Object*>(value)->ShortPrint(trace_file);
3510       }
3511 
3512       return TranslatedValue::NewTagged(this, value);
3513     }
3514   }
3515 
3516   FATAL("We should never get here - unexpected deopt info.");
3517   return TranslatedValue(nullptr, TranslatedValue::kInvalid);
3518 }
3519 
3520 
TranslatedState(JavaScriptFrame * frame)3521 TranslatedState::TranslatedState(JavaScriptFrame* frame)
3522     : isolate_(nullptr),
3523       stack_frame_pointer_(nullptr),
3524       has_adapted_arguments_(false) {
3525   int deopt_index = Safepoint::kNoDeoptimizationIndex;
3526   DeoptimizationInputData* data =
3527       static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
3528   DCHECK(data != nullptr && deopt_index != Safepoint::kNoDeoptimizationIndex);
3529   TranslationIterator it(data->TranslationByteArray(),
3530                          data->TranslationIndex(deopt_index)->value());
3531   Init(frame->fp(), &it, data->LiteralArray(), nullptr /* registers */,
3532        nullptr /* trace file */);
3533 }
3534 
3535 
TranslatedState()3536 TranslatedState::TranslatedState()
3537     : isolate_(nullptr),
3538       stack_frame_pointer_(nullptr),
3539       has_adapted_arguments_(false) {}
3540 
3541 
Init(Address input_frame_pointer,TranslationIterator * iterator,FixedArray * literal_array,RegisterValues * registers,FILE * trace_file)3542 void TranslatedState::Init(Address input_frame_pointer,
3543                            TranslationIterator* iterator,
3544                            FixedArray* literal_array, RegisterValues* registers,
3545                            FILE* trace_file) {
3546   DCHECK(frames_.empty());
3547 
3548   isolate_ = literal_array->GetIsolate();
3549   // Read out the 'header' translation.
3550   Translation::Opcode opcode =
3551       static_cast<Translation::Opcode>(iterator->Next());
3552   CHECK(opcode == Translation::BEGIN);
3553 
3554   int count = iterator->Next();
3555   iterator->Next();  // Drop JS frames count.
3556 
3557   frames_.reserve(count);
3558 
3559   std::stack<int> nested_counts;
3560 
3561   // Read the frames
3562   for (int i = 0; i < count; i++) {
3563     // Read the frame descriptor.
3564     frames_.push_back(CreateNextTranslatedFrame(
3565         iterator, literal_array, input_frame_pointer, trace_file));
3566     TranslatedFrame& frame = frames_.back();
3567 
3568     // Read the values.
3569     int values_to_process = frame.GetValueCount();
3570     while (values_to_process > 0 || !nested_counts.empty()) {
3571       if (trace_file != nullptr) {
3572         if (nested_counts.empty()) {
3573           // For top level values, print the value number.
3574           PrintF(trace_file, "    %3i: ",
3575                  frame.GetValueCount() - values_to_process);
3576         } else {
3577           // Take care of indenting for nested values.
3578           PrintF(trace_file, "         ");
3579           for (size_t j = 0; j < nested_counts.size(); j++) {
3580             PrintF(trace_file, "  ");
3581           }
3582         }
3583       }
3584 
3585       TranslatedValue value = CreateNextTranslatedValue(
3586           i, static_cast<int>(frame.values_.size()), iterator, literal_array,
3587           input_frame_pointer, registers, trace_file);
3588       frame.Add(value);
3589 
3590       if (trace_file != nullptr) {
3591         PrintF(trace_file, "\n");
3592       }
3593 
3594       // Update the value count and resolve the nesting.
3595       values_to_process--;
3596       int children_count = value.GetChildrenCount();
3597       if (children_count > 0) {
3598         nested_counts.push(values_to_process);
3599         values_to_process = children_count;
3600       } else {
3601         while (values_to_process == 0 && !nested_counts.empty()) {
3602           values_to_process = nested_counts.top();
3603           nested_counts.pop();
3604         }
3605       }
3606     }
3607   }
3608 
3609   CHECK(!iterator->HasNext() ||
3610         static_cast<Translation::Opcode>(iterator->Next()) ==
3611             Translation::BEGIN);
3612 }
3613 
3614 
Prepare(bool has_adapted_arguments,Address stack_frame_pointer)3615 void TranslatedState::Prepare(bool has_adapted_arguments,
3616                               Address stack_frame_pointer) {
3617   for (auto& frame : frames_) frame.Handlify();
3618 
3619   stack_frame_pointer_ = stack_frame_pointer;
3620   has_adapted_arguments_ = has_adapted_arguments;
3621 
3622   UpdateFromPreviouslyMaterializedObjects();
3623 }
3624 
3625 
MaterializeAt(int frame_index,int * value_index)3626 Handle<Object> TranslatedState::MaterializeAt(int frame_index,
3627                                               int* value_index) {
3628   TranslatedFrame* frame = &(frames_[frame_index]);
3629   CHECK(static_cast<size_t>(*value_index) < frame->values_.size());
3630 
3631   TranslatedValue* slot = &(frame->values_[*value_index]);
3632   (*value_index)++;
3633 
3634   switch (slot->kind()) {
3635     case TranslatedValue::kTagged:
3636     case TranslatedValue::kInt32:
3637     case TranslatedValue::kUInt32:
3638     case TranslatedValue::kBoolBit:
3639     case TranslatedValue::kFloat:
3640     case TranslatedValue::kDouble: {
3641       slot->MaterializeSimple();
3642       Handle<Object> value = slot->GetValue();
3643       if (value->IsMutableHeapNumber()) {
3644         HeapNumber::cast(*value)->set_map(isolate()->heap()->heap_number_map());
3645       }
3646       return value;
3647     }
3648 
3649     case TranslatedValue::kArgumentsObject: {
3650       int length = slot->GetChildrenCount();
3651       Handle<JSObject> arguments;
3652       if (GetAdaptedArguments(&arguments, frame_index)) {
3653         // Store the materialized object and consume the nested values.
3654         for (int i = 0; i < length; ++i) {
3655           MaterializeAt(frame_index, value_index);
3656         }
3657       } else {
3658         Handle<JSFunction> function =
3659             Handle<JSFunction>::cast(frame->front().GetValue());
3660         arguments = isolate_->factory()->NewArgumentsObject(function, length);
3661         Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length);
3662         DCHECK_EQ(array->length(), length);
3663         arguments->set_elements(*array);
3664         for (int i = 0; i < length; ++i) {
3665           Handle<Object> value = MaterializeAt(frame_index, value_index);
3666           array->set(i, *value);
3667         }
3668       }
3669       slot->value_ = arguments;
3670       return arguments;
3671     }
3672     case TranslatedValue::kCapturedObject: {
3673       int length = slot->GetChildrenCount();
3674 
3675       // The map must be a tagged object.
3676       CHECK(frame->values_[*value_index].kind() == TranslatedValue::kTagged);
3677 
3678       Handle<Object> result;
3679       if (slot->value_.ToHandle(&result)) {
3680         // This has been previously materialized, return the previous value.
3681         // We still need to skip all the nested objects.
3682         for (int i = 0; i < length; i++) {
3683           MaterializeAt(frame_index, value_index);
3684         }
3685 
3686         return result;
3687       }
3688 
3689       Handle<Object> map_object = MaterializeAt(frame_index, value_index);
3690       Handle<Map> map =
3691           Map::GeneralizeAllFieldRepresentations(Handle<Map>::cast(map_object));
3692       switch (map->instance_type()) {
3693         case MUTABLE_HEAP_NUMBER_TYPE:
3694         case HEAP_NUMBER_TYPE: {
3695           // Reuse the HeapNumber value directly as it is already properly
3696           // tagged and skip materializing the HeapNumber explicitly.
3697           Handle<Object> object = MaterializeAt(frame_index, value_index);
3698           slot->value_ = object;
3699           // On 32-bit architectures, there is an extra slot there because
3700           // the escape analysis calculates the number of slots as
3701           // object-size/pointer-size. To account for this, we read out
3702           // any extra slots.
3703           for (int i = 0; i < length - 2; i++) {
3704             MaterializeAt(frame_index, value_index);
3705           }
3706           return object;
3707         }
3708         case JS_OBJECT_TYPE:
3709         case JS_ERROR_TYPE:
3710         case JS_ARGUMENTS_TYPE: {
3711           Handle<JSObject> object =
3712               isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED);
3713           slot->value_ = object;
3714           Handle<Object> properties = MaterializeAt(frame_index, value_index);
3715           Handle<Object> elements = MaterializeAt(frame_index, value_index);
3716           object->set_properties(FixedArray::cast(*properties));
3717           object->set_elements(FixedArrayBase::cast(*elements));
3718           for (int i = 0; i < length - 3; ++i) {
3719             Handle<Object> value = MaterializeAt(frame_index, value_index);
3720             FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i);
3721             object->FastPropertyAtPut(index, *value);
3722           }
3723           return object;
3724         }
3725         case JS_ARRAY_TYPE: {
3726           Handle<JSArray> object = Handle<JSArray>::cast(
3727               isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED));
3728           slot->value_ = object;
3729           Handle<Object> properties = MaterializeAt(frame_index, value_index);
3730           Handle<Object> elements = MaterializeAt(frame_index, value_index);
3731           Handle<Object> length = MaterializeAt(frame_index, value_index);
3732           object->set_properties(FixedArray::cast(*properties));
3733           object->set_elements(FixedArrayBase::cast(*elements));
3734           object->set_length(*length);
3735           return object;
3736         }
3737         case JS_FUNCTION_TYPE: {
3738           Handle<SharedFunctionInfo> temporary_shared =
3739               isolate_->factory()->NewSharedFunctionInfo(
3740                   isolate_->factory()->empty_string(), MaybeHandle<Code>(),
3741                   false);
3742           Handle<JSFunction> object =
3743               isolate_->factory()->NewFunctionFromSharedFunctionInfo(
3744                   map, temporary_shared, isolate_->factory()->undefined_value(),
3745                   NOT_TENURED);
3746           slot->value_ = object;
3747           Handle<Object> properties = MaterializeAt(frame_index, value_index);
3748           Handle<Object> elements = MaterializeAt(frame_index, value_index);
3749           Handle<Object> prototype = MaterializeAt(frame_index, value_index);
3750           Handle<Object> shared = MaterializeAt(frame_index, value_index);
3751           Handle<Object> context = MaterializeAt(frame_index, value_index);
3752           Handle<Object> literals = MaterializeAt(frame_index, value_index);
3753           Handle<Object> entry = MaterializeAt(frame_index, value_index);
3754           Handle<Object> next_link = MaterializeAt(frame_index, value_index);
3755           object->ReplaceCode(*isolate_->builtins()->CompileLazy());
3756           object->set_map(*map);
3757           object->set_properties(FixedArray::cast(*properties));
3758           object->set_elements(FixedArrayBase::cast(*elements));
3759           object->set_prototype_or_initial_map(*prototype);
3760           object->set_shared(SharedFunctionInfo::cast(*shared));
3761           object->set_context(Context::cast(*context));
3762           object->set_literals(LiteralsArray::cast(*literals));
3763           CHECK(entry->IsNumber());  // Entry to compile lazy stub.
3764           CHECK(next_link->IsUndefined(isolate_));
3765           return object;
3766         }
3767         case CONS_STRING_TYPE: {
3768           Handle<ConsString> object = Handle<ConsString>::cast(
3769               isolate_->factory()
3770                   ->NewConsString(isolate_->factory()->undefined_string(),
3771                                   isolate_->factory()->undefined_string())
3772                   .ToHandleChecked());
3773           slot->value_ = object;
3774           Handle<Object> hash = MaterializeAt(frame_index, value_index);
3775           Handle<Object> length = MaterializeAt(frame_index, value_index);
3776           Handle<Object> first = MaterializeAt(frame_index, value_index);
3777           Handle<Object> second = MaterializeAt(frame_index, value_index);
3778           object->set_map(*map);
3779           object->set_length(Smi::cast(*length)->value());
3780           object->set_first(String::cast(*first));
3781           object->set_second(String::cast(*second));
3782           CHECK(hash->IsNumber());  // The {Name::kEmptyHashField} value.
3783           return object;
3784         }
3785         case CONTEXT_EXTENSION_TYPE: {
3786           Handle<ContextExtension> object =
3787               isolate_->factory()->NewContextExtension(
3788                   isolate_->factory()->NewScopeInfo(1),
3789                   isolate_->factory()->undefined_value());
3790           slot->value_ = object;
3791           Handle<Object> scope_info = MaterializeAt(frame_index, value_index);
3792           Handle<Object> extension = MaterializeAt(frame_index, value_index);
3793           object->set_scope_info(ScopeInfo::cast(*scope_info));
3794           object->set_extension(*extension);
3795           return object;
3796         }
3797         case FIXED_ARRAY_TYPE: {
3798           Handle<Object> lengthObject = MaterializeAt(frame_index, value_index);
3799           int32_t length = 0;
3800           CHECK(lengthObject->ToInt32(&length));
3801           Handle<FixedArray> object =
3802               isolate_->factory()->NewFixedArray(length);
3803           // We need to set the map, because the fixed array we are
3804           // materializing could be a context or an arguments object,
3805           // in which case we must retain that information.
3806           object->set_map(*map);
3807           slot->value_ = object;
3808           for (int i = 0; i < length; ++i) {
3809             Handle<Object> value = MaterializeAt(frame_index, value_index);
3810             object->set(i, *value);
3811           }
3812           return object;
3813         }
3814         case FIXED_DOUBLE_ARRAY_TYPE: {
3815           DCHECK_EQ(*map, isolate_->heap()->fixed_double_array_map());
3816           Handle<Object> lengthObject = MaterializeAt(frame_index, value_index);
3817           int32_t length = 0;
3818           CHECK(lengthObject->ToInt32(&length));
3819           Handle<FixedArrayBase> object =
3820               isolate_->factory()->NewFixedDoubleArray(length);
3821           slot->value_ = object;
3822           if (length > 0) {
3823             Handle<FixedDoubleArray> double_array =
3824                 Handle<FixedDoubleArray>::cast(object);
3825             for (int i = 0; i < length; ++i) {
3826               Handle<Object> value = MaterializeAt(frame_index, value_index);
3827               CHECK(value->IsNumber());
3828               double_array->set(i, value->Number());
3829             }
3830           }
3831           return object;
3832         }
3833         default:
3834           PrintF(stderr, "[couldn't handle instance type %d]\n",
3835                  map->instance_type());
3836           FATAL("unreachable");
3837           return Handle<Object>::null();
3838       }
3839       UNREACHABLE();
3840       break;
3841     }
3842 
3843     case TranslatedValue::kDuplicatedObject: {
3844       int object_index = slot->object_index();
3845       TranslatedState::ObjectPosition pos = object_positions_[object_index];
3846 
3847       // Make sure the duplicate is refering to a previous object.
3848       CHECK(pos.frame_index_ < frame_index ||
3849             (pos.frame_index_ == frame_index &&
3850              pos.value_index_ < *value_index - 1));
3851 
3852       Handle<Object> object =
3853           frames_[pos.frame_index_].values_[pos.value_index_].GetValue();
3854 
3855       // The object should have a (non-sentinel) value.
3856       CHECK(!object.is_null() &&
3857             !object.is_identical_to(isolate_->factory()->arguments_marker()));
3858 
3859       slot->value_ = object;
3860       return object;
3861     }
3862 
3863     case TranslatedValue::kInvalid:
3864       UNREACHABLE();
3865       break;
3866   }
3867 
3868   FATAL("We should never get here - unexpected deopt slot kind.");
3869   return Handle<Object>::null();
3870 }
3871 
3872 
MaterializeObjectAt(int object_index)3873 Handle<Object> TranslatedState::MaterializeObjectAt(int object_index) {
3874   TranslatedState::ObjectPosition pos = object_positions_[object_index];
3875   return MaterializeAt(pos.frame_index_, &(pos.value_index_));
3876 }
3877 
3878 
GetAdaptedArguments(Handle<JSObject> * result,int frame_index)3879 bool TranslatedState::GetAdaptedArguments(Handle<JSObject>* result,
3880                                           int frame_index) {
3881   if (frame_index == 0) {
3882     // Top level frame -> we need to go to the parent frame on the stack.
3883     if (!has_adapted_arguments_) return false;
3884 
3885     // This is top level frame, so we need to go to the stack to get
3886     // this function's argument. (Note that this relies on not inlining
3887     // recursive functions!)
3888     Handle<JSFunction> function =
3889         Handle<JSFunction>::cast(frames_[frame_index].front().GetValue());
3890     *result = Accessors::FunctionGetArguments(function);
3891     return true;
3892   } else {
3893     TranslatedFrame* previous_frame = &(frames_[frame_index]);
3894     if (previous_frame->kind() != TranslatedFrame::kArgumentsAdaptor) {
3895       return false;
3896     }
3897     // We get the adapted arguments from the parent translation.
3898     int length = previous_frame->height();
3899     Handle<JSFunction> function =
3900         Handle<JSFunction>::cast(previous_frame->front().GetValue());
3901     Handle<JSObject> arguments =
3902         isolate_->factory()->NewArgumentsObject(function, length);
3903     Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length);
3904     arguments->set_elements(*array);
3905     TranslatedFrame::iterator arg_iterator = previous_frame->begin();
3906     arg_iterator++;  // Skip function.
3907     for (int i = 0; i < length; ++i) {
3908       Handle<Object> value = arg_iterator->GetValue();
3909       array->set(i, *value);
3910       arg_iterator++;
3911     }
3912     CHECK(arg_iterator == previous_frame->end());
3913     *result = arguments;
3914     return true;
3915   }
3916 }
3917 
3918 
GetArgumentsInfoFromJSFrameIndex(int jsframe_index,int * args_count)3919 TranslatedFrame* TranslatedState::GetArgumentsInfoFromJSFrameIndex(
3920     int jsframe_index, int* args_count) {
3921   for (size_t i = 0; i < frames_.size(); i++) {
3922     if (frames_[i].kind() == TranslatedFrame::kFunction ||
3923         frames_[i].kind() == TranslatedFrame::kInterpretedFunction) {
3924       if (jsframe_index > 0) {
3925         jsframe_index--;
3926       } else {
3927         // We have the JS function frame, now check if it has arguments adaptor.
3928         if (i > 0 &&
3929             frames_[i - 1].kind() == TranslatedFrame::kArgumentsAdaptor) {
3930           *args_count = frames_[i - 1].height();
3931           return &(frames_[i - 1]);
3932         }
3933         *args_count =
3934             frames_[i].shared_info()->internal_formal_parameter_count() + 1;
3935         return &(frames_[i]);
3936       }
3937     }
3938   }
3939   return nullptr;
3940 }
3941 
3942 
StoreMaterializedValuesAndDeopt()3943 void TranslatedState::StoreMaterializedValuesAndDeopt() {
3944   MaterializedObjectStore* materialized_store =
3945       isolate_->materialized_object_store();
3946   Handle<FixedArray> previously_materialized_objects =
3947       materialized_store->Get(stack_frame_pointer_);
3948 
3949   Handle<Object> marker = isolate_->factory()->arguments_marker();
3950 
3951   int length = static_cast<int>(object_positions_.size());
3952   bool new_store = false;
3953   if (previously_materialized_objects.is_null()) {
3954     previously_materialized_objects =
3955         isolate_->factory()->NewFixedArray(length);
3956     for (int i = 0; i < length; i++) {
3957       previously_materialized_objects->set(i, *marker);
3958     }
3959     new_store = true;
3960   }
3961 
3962   CHECK_EQ(length, previously_materialized_objects->length());
3963 
3964   bool value_changed = false;
3965   for (int i = 0; i < length; i++) {
3966     TranslatedState::ObjectPosition pos = object_positions_[i];
3967     TranslatedValue* value_info =
3968         &(frames_[pos.frame_index_].values_[pos.value_index_]);
3969 
3970     CHECK(value_info->IsMaterializedObject());
3971 
3972     Handle<Object> value(value_info->GetRawValue(), isolate_);
3973 
3974     if (!value.is_identical_to(marker)) {
3975       if (previously_materialized_objects->get(i) == *marker) {
3976         previously_materialized_objects->set(i, *value);
3977         value_changed = true;
3978       } else {
3979         CHECK(previously_materialized_objects->get(i) == *value);
3980       }
3981     }
3982   }
3983   if (new_store && value_changed) {
3984     materialized_store->Set(stack_frame_pointer_,
3985                             previously_materialized_objects);
3986     CHECK(frames_[0].kind() == TranslatedFrame::kFunction ||
3987           frames_[0].kind() == TranslatedFrame::kInterpretedFunction ||
3988           frames_[0].kind() == TranslatedFrame::kTailCallerFunction);
3989     Object* const function = frames_[0].front().GetRawValue();
3990     Deoptimizer::DeoptimizeFunction(JSFunction::cast(function));
3991   }
3992 }
3993 
3994 
UpdateFromPreviouslyMaterializedObjects()3995 void TranslatedState::UpdateFromPreviouslyMaterializedObjects() {
3996   MaterializedObjectStore* materialized_store =
3997       isolate_->materialized_object_store();
3998   Handle<FixedArray> previously_materialized_objects =
3999       materialized_store->Get(stack_frame_pointer_);
4000 
4001   // If we have no previously materialized objects, there is nothing to do.
4002   if (previously_materialized_objects.is_null()) return;
4003 
4004   Handle<Object> marker = isolate_->factory()->arguments_marker();
4005 
4006   int length = static_cast<int>(object_positions_.size());
4007   CHECK_EQ(length, previously_materialized_objects->length());
4008 
4009   for (int i = 0; i < length; i++) {
4010     // For a previously materialized objects, inject their value into the
4011     // translated values.
4012     if (previously_materialized_objects->get(i) != *marker) {
4013       TranslatedState::ObjectPosition pos = object_positions_[i];
4014       TranslatedValue* value_info =
4015           &(frames_[pos.frame_index_].values_[pos.value_index_]);
4016       CHECK(value_info->IsMaterializedObject());
4017 
4018       value_info->value_ =
4019           Handle<Object>(previously_materialized_objects->get(i), isolate_);
4020     }
4021   }
4022 }
4023 
4024 }  // namespace internal
4025 }  // namespace v8
4026