• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/deoptimizer.h"
6 
7 #include <memory>
8 
9 #include "src/ast/prettyprinter.h"
10 #include "src/builtins/accessors.h"
11 #include "src/codegen/assembler-inl.h"
12 #include "src/codegen/callable.h"
13 #include "src/codegen/macro-assembler.h"
14 #include "src/codegen/register-configuration.h"
15 #include "src/common/assert-scope.h"
16 #include "src/diagnostics/disasm.h"
17 #include "src/execution/frames-inl.h"
18 #include "src/execution/pointer-authentication.h"
19 #include "src/execution/v8threads.h"
20 #include "src/handles/global-handles.h"
21 #include "src/heap/heap-inl.h"
22 #include "src/init/v8.h"
23 #include "src/interpreter/interpreter.h"
24 #include "src/logging/counters.h"
25 #include "src/logging/log.h"
26 #include "src/objects/arguments.h"
27 #include "src/objects/debug-objects-inl.h"
28 #include "src/objects/heap-number-inl.h"
29 #include "src/objects/smi.h"
30 #include "src/snapshot/embedded/embedded-data.h"
31 #include "src/tracing/trace-event.h"
32 
33 // Has to be the last include (doesn't have include guards)
34 #include "src/objects/object-macros.h"
35 
36 namespace v8 {
37 namespace internal {
38 
39 // {FrameWriter} offers a stack writer abstraction for writing
40 // FrameDescriptions. The main service the class provides is managing
41 // {top_offset_}, i.e. the offset of the next slot to write to.
42 class FrameWriter {
43  public:
44   static const int NO_INPUT_INDEX = -1;
FrameWriter(Deoptimizer * deoptimizer,FrameDescription * frame,CodeTracer::Scope * trace_scope)45   FrameWriter(Deoptimizer* deoptimizer, FrameDescription* frame,
46               CodeTracer::Scope* trace_scope)
47       : deoptimizer_(deoptimizer),
48         frame_(frame),
49         trace_scope_(trace_scope),
50         top_offset_(frame->GetFrameSize()) {}
51 
PushRawValue(intptr_t value,const char * debug_hint)52   void PushRawValue(intptr_t value, const char* debug_hint) {
53     PushValue(value);
54     if (trace_scope_ != nullptr) {
55       DebugPrintOutputValue(value, debug_hint);
56     }
57   }
58 
PushRawObject(Object obj,const char * debug_hint)59   void PushRawObject(Object obj, const char* debug_hint) {
60     intptr_t value = obj.ptr();
61     PushValue(value);
62     if (trace_scope_ != nullptr) {
63       DebugPrintOutputObject(obj, top_offset_, debug_hint);
64     }
65   }
66 
67   // There is no check against the allowed addresses for bottommost frames, as
68   // the caller's pc could be anything. The caller's pc pushed here should never
69   // be re-signed.
PushBottommostCallerPc(intptr_t pc)70   void PushBottommostCallerPc(intptr_t pc) {
71     top_offset_ -= kPCOnStackSize;
72     frame_->SetFrameSlot(top_offset_, pc);
73     DebugPrintOutputPc(pc, "bottommost caller's pc\n");
74   }
75 
PushApprovedCallerPc(intptr_t pc)76   void PushApprovedCallerPc(intptr_t pc) {
77     top_offset_ -= kPCOnStackSize;
78     frame_->SetCallerPc(top_offset_, pc);
79     DebugPrintOutputPc(pc, "caller's pc\n");
80   }
81 
PushCallerFp(intptr_t fp)82   void PushCallerFp(intptr_t fp) {
83     top_offset_ -= kFPOnStackSize;
84     frame_->SetCallerFp(top_offset_, fp);
85     DebugPrintOutputValue(fp, "caller's fp\n");
86   }
87 
PushCallerConstantPool(intptr_t cp)88   void PushCallerConstantPool(intptr_t cp) {
89     top_offset_ -= kSystemPointerSize;
90     frame_->SetCallerConstantPool(top_offset_, cp);
91     DebugPrintOutputValue(cp, "caller's constant_pool\n");
92   }
93 
PushTranslatedValue(const TranslatedFrame::iterator & iterator,const char * debug_hint="")94   void PushTranslatedValue(const TranslatedFrame::iterator& iterator,
95                            const char* debug_hint = "") {
96     Object obj = iterator->GetRawValue();
97     PushRawObject(obj, debug_hint);
98     if (trace_scope_) {
99       PrintF(trace_scope_->file(), " (input #%d)\n", iterator.input_index());
100     }
101     deoptimizer_->QueueValueForMaterialization(output_address(top_offset_), obj,
102                                                iterator);
103   }
104 
PushStackJSArguments(TranslatedFrame::iterator & iterator,int parameters_count)105   void PushStackJSArguments(TranslatedFrame::iterator& iterator,
106                             int parameters_count) {
107     std::vector<TranslatedFrame::iterator> parameters;
108     parameters.reserve(parameters_count);
109     for (int i = 0; i < parameters_count; ++i, ++iterator) {
110       parameters.push_back(iterator);
111     }
112     for (auto& parameter : base::Reversed(parameters)) {
113       PushTranslatedValue(parameter, "stack parameter");
114     }
115   }
116 
top_offset() const117   unsigned top_offset() const { return top_offset_; }
118 
frame()119   FrameDescription* frame() { return frame_; }
120 
121  private:
PushValue(intptr_t value)122   void PushValue(intptr_t value) {
123     CHECK_GE(top_offset_, 0);
124     top_offset_ -= kSystemPointerSize;
125     frame_->SetFrameSlot(top_offset_, value);
126   }
127 
output_address(unsigned output_offset)128   Address output_address(unsigned output_offset) {
129     Address output_address =
130         static_cast<Address>(frame_->GetTop()) + output_offset;
131     return output_address;
132   }
133 
DebugPrintOutputValue(intptr_t value,const char * debug_hint="")134   void DebugPrintOutputValue(intptr_t value, const char* debug_hint = "") {
135     if (trace_scope_ != nullptr) {
136       PrintF(trace_scope_->file(),
137              "    " V8PRIxPTR_FMT ": [top + %3d] <- " V8PRIxPTR_FMT " ;  %s",
138              output_address(top_offset_), top_offset_, value, debug_hint);
139     }
140   }
141 
DebugPrintOutputPc(intptr_t value,const char * debug_hint="")142   void DebugPrintOutputPc(intptr_t value, const char* debug_hint = "") {
143 #ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY
144     if (trace_scope_ != nullptr) {
145       PrintF(trace_scope_->file(),
146              "    " V8PRIxPTR_FMT ": [top + %3d] <- " V8PRIxPTR_FMT
147              " (signed) " V8PRIxPTR_FMT " (unsigned) ;  %s",
148              output_address(top_offset_), top_offset_, value,
149              PointerAuthentication::StripPAC(value), debug_hint);
150     }
151 #else
152     DebugPrintOutputValue(value, debug_hint);
153 #endif
154   }
155 
DebugPrintOutputObject(Object obj,unsigned output_offset,const char * debug_hint="")156   void DebugPrintOutputObject(Object obj, unsigned output_offset,
157                               const char* debug_hint = "") {
158     if (trace_scope_ != nullptr) {
159       PrintF(trace_scope_->file(), "    " V8PRIxPTR_FMT ": [top + %3d] <- ",
160              output_address(output_offset), output_offset);
161       if (obj.IsSmi()) {
162         PrintF(trace_scope_->file(), V8PRIxPTR_FMT " <Smi %d>", obj.ptr(),
163                Smi::cast(obj).value());
164       } else {
165         obj.ShortPrint(trace_scope_->file());
166       }
167       PrintF(trace_scope_->file(), " ;  %s", debug_hint);
168     }
169   }
170 
171   Deoptimizer* deoptimizer_;
172   FrameDescription* frame_;
173   CodeTracer::Scope* const trace_scope_;
174   unsigned top_offset_;
175 };
176 
FindDeoptimizingCode(Address addr)177 Code Deoptimizer::FindDeoptimizingCode(Address addr) {
178   if (function_.IsHeapObject()) {
179     // Search all deoptimizing code in the native context of the function.
180     Isolate* isolate = isolate_;
181     NativeContext native_context = function_.context().native_context();
182     Object element = native_context.DeoptimizedCodeListHead();
183     while (!element.IsUndefined(isolate)) {
184       Code code = Code::cast(element);
185       CHECK(CodeKindCanDeoptimize(code.kind()));
186       if (code.contains(addr)) return code;
187       element = code.next_code_link();
188     }
189   }
190   return Code();
191 }
192 
193 // We rely on this function not causing a GC. It is called from generated code
194 // without having a real stack frame in place.
New(Address raw_function,DeoptimizeKind kind,unsigned bailout_id,Address from,int fp_to_sp_delta,Isolate * isolate)195 Deoptimizer* Deoptimizer::New(Address raw_function, DeoptimizeKind kind,
196                               unsigned bailout_id, Address from,
197                               int fp_to_sp_delta, Isolate* isolate) {
198   JSFunction function = JSFunction::cast(Object(raw_function));
199   Deoptimizer* deoptimizer = new Deoptimizer(isolate, function, kind,
200                                              bailout_id, from, fp_to_sp_delta);
201   isolate->set_current_deoptimizer(deoptimizer);
202   return deoptimizer;
203 }
204 
Grab(Isolate * isolate)205 Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
206   Deoptimizer* result = isolate->GetAndClearCurrentDeoptimizer();
207   result->DeleteFrameDescriptions();
208   return result;
209 }
210 
DebuggerInspectableFrame(JavaScriptFrame * frame,int jsframe_index,Isolate * isolate)211 DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
212     JavaScriptFrame* frame, int jsframe_index, Isolate* isolate) {
213   CHECK(frame->is_optimized());
214 
215   TranslatedState translated_values(frame);
216   translated_values.Prepare(frame->fp());
217 
218   TranslatedState::iterator frame_it = translated_values.end();
219   int counter = jsframe_index;
220   for (auto it = translated_values.begin(); it != translated_values.end();
221        it++) {
222     if (it->kind() == TranslatedFrame::kInterpretedFunction ||
223         it->kind() == TranslatedFrame::kJavaScriptBuiltinContinuation ||
224         it->kind() ==
225             TranslatedFrame::kJavaScriptBuiltinContinuationWithCatch) {
226       if (counter == 0) {
227         frame_it = it;
228         break;
229       }
230       counter--;
231     }
232   }
233   CHECK(frame_it != translated_values.end());
234   // We only include kJavaScriptBuiltinContinuation frames above to get the
235   // counting right.
236   CHECK_EQ(frame_it->kind(), TranslatedFrame::kInterpretedFunction);
237 
238   DeoptimizedFrameInfo* info =
239       new DeoptimizedFrameInfo(&translated_values, frame_it, isolate);
240 
241   return info;
242 }
243 
244 namespace {
245 class ActivationsFinder : public ThreadVisitor {
246  public:
ActivationsFinder(std::set<Code> * codes,Code topmost_optimized_code,bool safe_to_deopt_topmost_optimized_code)247   explicit ActivationsFinder(std::set<Code>* codes, Code topmost_optimized_code,
248                              bool safe_to_deopt_topmost_optimized_code)
249       : codes_(codes) {
250 #ifdef DEBUG
251     topmost_ = topmost_optimized_code;
252     safe_to_deopt_ = safe_to_deopt_topmost_optimized_code;
253 #endif
254   }
255 
256   // Find the frames with activations of codes marked for deoptimization, search
257   // for the trampoline to the deoptimizer call respective to each code, and use
258   // it to replace the current pc on the stack.
VisitThread(Isolate * isolate,ThreadLocalTop * top)259   void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
260     for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
261       if (it.frame()->type() == StackFrame::OPTIMIZED) {
262         Code code = it.frame()->LookupCode();
263         if (CodeKindCanDeoptimize(code.kind()) &&
264             code.marked_for_deoptimization()) {
265           codes_->erase(code);
266           // Obtain the trampoline to the deoptimizer call.
267           SafepointEntry safepoint = code.GetSafepointEntry(it.frame()->pc());
268           int trampoline_pc = safepoint.trampoline_pc();
269           DCHECK_IMPLIES(code == topmost_, safe_to_deopt_);
270           CHECK_GE(trampoline_pc, 0);
271           // Replace the current pc on the stack with the trampoline.
272           // TODO(v8:10026): avoid replacing a signed pointer.
273           Address* pc_addr = it.frame()->pc_address();
274           Address new_pc = code.raw_instruction_start() + trampoline_pc;
275           PointerAuthentication::ReplacePC(pc_addr, new_pc, kSystemPointerSize);
276         }
277       }
278     }
279   }
280 
281  private:
282   std::set<Code>* codes_;
283 
284 #ifdef DEBUG
285   Code topmost_;
286   bool safe_to_deopt_;
287 #endif
288 };
289 }  // namespace
290 
291 // Move marked code from the optimized code list to the deoptimized code list,
292 // and replace pc on the stack for codes marked for deoptimization.
293 // static
DeoptimizeMarkedCodeForContext(NativeContext native_context)294 void Deoptimizer::DeoptimizeMarkedCodeForContext(NativeContext native_context) {
295   DisallowHeapAllocation no_allocation;
296 
297   Isolate* isolate = native_context.GetIsolate();
298   Code topmost_optimized_code;
299   bool safe_to_deopt_topmost_optimized_code = false;
300 #ifdef DEBUG
301   // Make sure all activations of optimized code can deopt at their current PC.
302   // The topmost optimized code has special handling because it cannot be
303   // deoptimized due to weak object dependency.
304   for (StackFrameIterator it(isolate, isolate->thread_local_top()); !it.done();
305        it.Advance()) {
306     StackFrame::Type type = it.frame()->type();
307     if (type == StackFrame::OPTIMIZED) {
308       Code code = it.frame()->LookupCode();
309       JSFunction function =
310           static_cast<OptimizedFrame*>(it.frame())->function();
311       TraceFoundActivation(isolate, function);
312       SafepointEntry safepoint = code.GetSafepointEntry(it.frame()->pc());
313 
314       // Turbofan deopt is checked when we are patching addresses on stack.
315       bool safe_if_deopt_triggered = safepoint.has_deoptimization_index();
316       bool is_builtin_code = code.kind() == CodeKind::BUILTIN;
317       DCHECK(topmost_optimized_code.is_null() || safe_if_deopt_triggered ||
318              is_builtin_code);
319       if (topmost_optimized_code.is_null()) {
320         topmost_optimized_code = code;
321         safe_to_deopt_topmost_optimized_code = safe_if_deopt_triggered;
322       }
323     }
324   }
325 #endif
326 
327   // We will use this set to mark those Code objects that are marked for
328   // deoptimization and have not been found in stack frames.
329   std::set<Code> codes;
330 
331   // Move marked code from the optimized code list to the deoptimized code list.
332   // Walk over all optimized code objects in this native context.
333   Code prev;
334   Object element = native_context.OptimizedCodeListHead();
335   while (!element.IsUndefined(isolate)) {
336     Code code = Code::cast(element);
337     CHECK(CodeKindCanDeoptimize(code.kind()));
338     Object next = code.next_code_link();
339 
340     if (code.marked_for_deoptimization()) {
341       codes.insert(code);
342 
343       if (!prev.is_null()) {
344         // Skip this code in the optimized code list.
345         prev.set_next_code_link(next);
346       } else {
347         // There was no previous node, the next node is the new head.
348         native_context.SetOptimizedCodeListHead(next);
349       }
350 
351       // Move the code to the _deoptimized_ code list.
352       code.set_next_code_link(native_context.DeoptimizedCodeListHead());
353       native_context.SetDeoptimizedCodeListHead(code);
354     } else {
355       // Not marked; preserve this element.
356       prev = code;
357     }
358     element = next;
359   }
360 
361   ActivationsFinder visitor(&codes, topmost_optimized_code,
362                             safe_to_deopt_topmost_optimized_code);
363   // Iterate over the stack of this thread.
364   visitor.VisitThread(isolate, isolate->thread_local_top());
365   // In addition to iterate over the stack of this thread, we also
366   // need to consider all the other threads as they may also use
367   // the code currently beings deoptimized.
368   isolate->thread_manager()->IterateArchivedThreads(&visitor);
369 
370   // If there's no activation of a code in any stack then we can remove its
371   // deoptimization data. We do this to ensure that code objects that are
372   // unlinked don't transitively keep objects alive unnecessarily.
373   for (Code code : codes) {
374     isolate->heap()->InvalidateCodeDeoptimizationData(code);
375   }
376 
377   native_context.GetOSROptimizedCodeCache().EvictMarkedCode(
378       native_context.GetIsolate());
379 }
380 
DeoptimizeAll(Isolate * isolate)381 void Deoptimizer::DeoptimizeAll(Isolate* isolate) {
382   RuntimeCallTimerScope runtimeTimer(isolate,
383                                      RuntimeCallCounterId::kDeoptimizeCode);
384   TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
385   TRACE_EVENT0("v8", "V8.DeoptimizeCode");
386   TraceDeoptAll(isolate);
387   isolate->AbortConcurrentOptimization(BlockingBehavior::kBlock);
388   DisallowHeapAllocation no_allocation;
389   // For all contexts, mark all code, then deoptimize.
390   Object context = isolate->heap()->native_contexts_list();
391   while (!context.IsUndefined(isolate)) {
392     NativeContext native_context = NativeContext::cast(context);
393     MarkAllCodeForContext(native_context);
394     OSROptimizedCodeCache::Clear(native_context);
395     DeoptimizeMarkedCodeForContext(native_context);
396     context = native_context.next_context_link();
397   }
398 }
399 
DeoptimizeMarkedCode(Isolate * isolate)400 void Deoptimizer::DeoptimizeMarkedCode(Isolate* isolate) {
401   RuntimeCallTimerScope runtimeTimer(isolate,
402                                      RuntimeCallCounterId::kDeoptimizeCode);
403   TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
404   TRACE_EVENT0("v8", "V8.DeoptimizeCode");
405   TraceDeoptMarked(isolate);
406   DisallowHeapAllocation no_allocation;
407   // For all contexts, deoptimize code already marked.
408   Object context = isolate->heap()->native_contexts_list();
409   while (!context.IsUndefined(isolate)) {
410     NativeContext native_context = NativeContext::cast(context);
411     DeoptimizeMarkedCodeForContext(native_context);
412     context = native_context.next_context_link();
413   }
414 }
415 
MarkAllCodeForContext(NativeContext native_context)416 void Deoptimizer::MarkAllCodeForContext(NativeContext native_context) {
417   Object element = native_context.OptimizedCodeListHead();
418   Isolate* isolate = native_context.GetIsolate();
419   while (!element.IsUndefined(isolate)) {
420     Code code = Code::cast(element);
421     CHECK(CodeKindCanDeoptimize(code.kind()));
422     code.set_marked_for_deoptimization(true);
423     element = code.next_code_link();
424   }
425 }
426 
DeoptimizeFunction(JSFunction function,Code code)427 void Deoptimizer::DeoptimizeFunction(JSFunction function, Code code) {
428   Isolate* isolate = function.GetIsolate();
429   RuntimeCallTimerScope runtimeTimer(isolate,
430                                      RuntimeCallCounterId::kDeoptimizeCode);
431   TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
432   TRACE_EVENT0("v8", "V8.DeoptimizeCode");
433   function.ResetIfBytecodeFlushed();
434   if (code.is_null()) code = function.code();
435 
436   if (CodeKindCanDeoptimize(code.kind())) {
437     // Mark the code for deoptimization and unlink any functions that also
438     // refer to that code. The code cannot be shared across native contexts,
439     // so we only need to search one.
440     code.set_marked_for_deoptimization(true);
441     // The code in the function's optimized code feedback vector slot might
442     // be different from the code on the function - evict it if necessary.
443     function.feedback_vector().EvictOptimizedCodeMarkedForDeoptimization(
444         function.shared(), "unlinking code marked for deopt");
445     if (!code.deopt_already_counted()) {
446       code.set_deopt_already_counted(true);
447     }
448     DeoptimizeMarkedCodeForContext(function.context().native_context());
449     // TODO(mythria): Ideally EvictMarkCode should compact the cache without
450     // having to explicitly call this. We don't do this currently because
451     // compacting causes GC and DeoptimizeMarkedCodeForContext uses raw
452     // pointers. Update DeoptimizeMarkedCodeForContext to use handles and remove
453     // this call from here.
454     OSROptimizedCodeCache::Compact(
455         Handle<NativeContext>(function.context().native_context(), isolate));
456   }
457 }
458 
ComputeOutputFrames(Deoptimizer * deoptimizer)459 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
460   deoptimizer->DoComputeOutputFrames();
461 }
462 
MessageFor(DeoptimizeKind kind,bool reuse_code)463 const char* Deoptimizer::MessageFor(DeoptimizeKind kind, bool reuse_code) {
464   DCHECK_IMPLIES(reuse_code, kind == DeoptimizeKind::kSoft);
465   switch (kind) {
466     case DeoptimizeKind::kEager:
467       return "deopt-eager";
468     case DeoptimizeKind::kSoft:
469       return reuse_code ? "bailout-soft" : "deopt-soft";
470     case DeoptimizeKind::kLazy:
471       return "deopt-lazy";
472     case DeoptimizeKind::kBailout:
473       return "bailout";
474   }
475 }
476 
477 namespace {
478 
InternalFormalParameterCountWithReceiver(SharedFunctionInfo sfi)479 uint16_t InternalFormalParameterCountWithReceiver(SharedFunctionInfo sfi) {
480   static constexpr int kTheReceiver = 1;
481   return sfi.internal_formal_parameter_count() + kTheReceiver;
482 }
483 
484 }  // namespace
485 
Deoptimizer(Isolate * isolate,JSFunction function,DeoptimizeKind kind,unsigned bailout_id,Address from,int fp_to_sp_delta)486 Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function,
487                          DeoptimizeKind kind, unsigned bailout_id, Address from,
488                          int fp_to_sp_delta)
489     : isolate_(isolate),
490       function_(function),
491       bailout_id_(bailout_id),
492       deopt_kind_(kind),
493       from_(from),
494       fp_to_sp_delta_(fp_to_sp_delta),
495       deoptimizing_throw_(false),
496       catch_handler_data_(-1),
497       catch_handler_pc_offset_(-1),
498       input_(nullptr),
499       output_count_(0),
500       jsframe_count_(0),
501       output_(nullptr),
502       caller_frame_top_(0),
503       caller_fp_(0),
504       caller_pc_(0),
505       caller_constant_pool_(0),
506       input_frame_context_(0),
507       actual_argument_count_(0),
508       stack_fp_(0),
509       trace_scope_(FLAG_trace_deopt
510                        ? new CodeTracer::Scope(isolate->GetCodeTracer())
511                        : nullptr) {
512   if (isolate->deoptimizer_lazy_throw()) {
513     isolate->set_deoptimizer_lazy_throw(false);
514     deoptimizing_throw_ = true;
515   }
516 
517   DCHECK(bailout_id_ == kFixedExitSizeMarker ||
518          bailout_id_ < kMaxNumberOfEntries);
519 
520   DCHECK_NE(from, kNullAddress);
521   compiled_code_ = FindOptimizedCode();
522   DCHECK(!compiled_code_.is_null());
523 
524   DCHECK(function.IsJSFunction());
525 #ifdef DEBUG
526   DCHECK(AllowHeapAllocation::IsAllowed());
527   DCHECK(AllowGarbageCollection::IsAllowed());
528   disallow_garbage_collection_ = new DisallowGarbageCollection();
529 #endif  // DEBUG
530   CHECK(CodeKindCanDeoptimize(compiled_code_.kind()));
531   if (!compiled_code_.deopt_already_counted() &&
532       deopt_kind_ == DeoptimizeKind::kSoft) {
533     isolate->counters()->soft_deopts_executed()->Increment();
534   }
535   compiled_code_.set_deopt_already_counted(true);
536   {
537     HandleScope scope(isolate_);
538     PROFILE(isolate_,
539             CodeDeoptEvent(handle(compiled_code_, isolate_), kind, from_,
540                            fp_to_sp_delta_, should_reuse_code()));
541   }
542   unsigned size = ComputeInputFrameSize();
543   const int parameter_count =
544       InternalFormalParameterCountWithReceiver(function.shared());
545   input_ = new (size) FrameDescription(size, parameter_count);
546 
547   if (kSupportsFixedDeoptExitSizes) {
548     DCHECK_EQ(bailout_id_, kFixedExitSizeMarker);
549     // Calculate bailout id from return address.
550     DCHECK_GT(kNonLazyDeoptExitSize, 0);
551     DCHECK_GT(kLazyDeoptExitSize, 0);
552     DeoptimizationData deopt_data =
553         DeoptimizationData::cast(compiled_code_.deoptimization_data());
554     Address deopt_start = compiled_code_.raw_instruction_start() +
555                           deopt_data.DeoptExitStart().value();
556     int non_lazy_deopt_count = deopt_data.NonLazyDeoptCount().value();
557     Address lazy_deopt_start =
558         deopt_start + non_lazy_deopt_count * kNonLazyDeoptExitSize;
559     // The deoptimization exits are sorted so that lazy deopt exits appear last.
560     static_assert(DeoptimizeKind::kLazy == kLastDeoptimizeKind,
561                   "lazy deopts are expected to be emitted last");
562     // from_ is the value of the link register after the call to the
563     // deoptimizer, so for the last lazy deopt, from_ points to the first
564     // non-lazy deopt, so we use <=.
565     if (from_ <= lazy_deopt_start) {
566       int offset =
567           static_cast<int>(from_ - kNonLazyDeoptExitSize - deopt_start);
568       DCHECK_EQ(0, offset % kNonLazyDeoptExitSize);
569       bailout_id_ = offset / kNonLazyDeoptExitSize;
570     } else {
571       int offset =
572           static_cast<int>(from_ - kLazyDeoptExitSize - lazy_deopt_start);
573       DCHECK_EQ(0, offset % kLazyDeoptExitSize);
574       bailout_id_ = non_lazy_deopt_count + (offset / kLazyDeoptExitSize);
575     }
576   }
577 }
578 
FindOptimizedCode()579 Code Deoptimizer::FindOptimizedCode() {
580   Code compiled_code = FindDeoptimizingCode(from_);
581   return !compiled_code.is_null() ? compiled_code
582                                   : isolate_->FindCodeObject(from_);
583 }
584 
function() const585 Handle<JSFunction> Deoptimizer::function() const {
586   return Handle<JSFunction>(function_, isolate());
587 }
compiled_code() const588 Handle<Code> Deoptimizer::compiled_code() const {
589   return Handle<Code>(compiled_code_, isolate());
590 }
591 
should_reuse_code() const592 bool Deoptimizer::should_reuse_code() const {
593   int count = compiled_code_.deoptimization_count();
594   return deopt_kind_ == DeoptimizeKind::kSoft &&
595          count < FLAG_reuse_opt_code_count;
596 }
597 
~Deoptimizer()598 Deoptimizer::~Deoptimizer() {
599   DCHECK(input_ == nullptr && output_ == nullptr);
600   DCHECK_NULL(disallow_garbage_collection_);
601 }
602 
DeleteFrameDescriptions()603 void Deoptimizer::DeleteFrameDescriptions() {
604   delete input_;
605   for (int i = 0; i < output_count_; ++i) {
606     if (output_[i] != input_) delete output_[i];
607   }
608   delete[] output_;
609   input_ = nullptr;
610   output_ = nullptr;
611 #ifdef DEBUG
612   DCHECK(!AllowGarbageCollection::IsAllowed());
613   DCHECK_NOT_NULL(disallow_garbage_collection_);
614   delete disallow_garbage_collection_;
615   disallow_garbage_collection_ = nullptr;
616 #endif  // DEBUG
617 }
618 
GetDeoptimizationEntry(Isolate * isolate,DeoptimizeKind kind)619 Builtins::Name Deoptimizer::GetDeoptimizationEntry(Isolate* isolate,
620                                                    DeoptimizeKind kind) {
621   switch (kind) {
622     case DeoptimizeKind::kEager:
623       return Builtins::kDeoptimizationEntry_Eager;
624     case DeoptimizeKind::kSoft:
625       return Builtins::kDeoptimizationEntry_Soft;
626     case DeoptimizeKind::kBailout:
627       return Builtins::kDeoptimizationEntry_Bailout;
628     case DeoptimizeKind::kLazy:
629       return Builtins::kDeoptimizationEntry_Lazy;
630   }
631 }
632 
IsDeoptimizationEntry(Isolate * isolate,Address addr,DeoptimizeKind * type_out)633 bool Deoptimizer::IsDeoptimizationEntry(Isolate* isolate, Address addr,
634                                         DeoptimizeKind* type_out) {
635   Code maybe_code = InstructionStream::TryLookupCode(isolate, addr);
636   if (maybe_code.is_null()) return false;
637 
638   Code code = maybe_code;
639   switch (code.builtin_index()) {
640     case Builtins::kDeoptimizationEntry_Eager:
641       *type_out = DeoptimizeKind::kEager;
642       return true;
643     case Builtins::kDeoptimizationEntry_Soft:
644       *type_out = DeoptimizeKind::kSoft;
645       return true;
646     case Builtins::kDeoptimizationEntry_Bailout:
647       *type_out = DeoptimizeKind::kBailout;
648       return true;
649     case Builtins::kDeoptimizationEntry_Lazy:
650       *type_out = DeoptimizeKind::kLazy;
651       return true;
652     default:
653       return false;
654   }
655 
656   UNREACHABLE();
657 }
658 
GetDeoptimizedCodeCount(Isolate * isolate)659 int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
660   int length = 0;
661   // Count all entries in the deoptimizing code list of every context.
662   Object context = isolate->heap()->native_contexts_list();
663   while (!context.IsUndefined(isolate)) {
664     NativeContext native_context = NativeContext::cast(context);
665     Object element = native_context.DeoptimizedCodeListHead();
666     while (!element.IsUndefined(isolate)) {
667       Code code = Code::cast(element);
668       DCHECK(CodeKindCanDeoptimize(code.kind()));
669       if (!code.marked_for_deoptimization()) {
670         length++;
671       }
672       element = code.next_code_link();
673     }
674     context = Context::cast(context).next_context_link();
675   }
676   return length;
677 }
678 
679 namespace {
680 
LookupCatchHandler(TranslatedFrame * translated_frame,int * data_out)681 int LookupCatchHandler(TranslatedFrame* translated_frame, int* data_out) {
682   switch (translated_frame->kind()) {
683     case TranslatedFrame::kInterpretedFunction: {
684       int bytecode_offset = translated_frame->node_id().ToInt();
685       HandlerTable table(
686           translated_frame->raw_shared_info().GetBytecodeArray());
687       return table.LookupRange(bytecode_offset, data_out, nullptr);
688     }
689     case TranslatedFrame::kJavaScriptBuiltinContinuationWithCatch: {
690       return 0;
691     }
692     default:
693       break;
694   }
695   return -1;
696 }
697 
698 }  // namespace
699 
TraceDeoptBegin(int optimization_id,int node_id)700 void Deoptimizer::TraceDeoptBegin(int optimization_id, int node_id) {
701   DCHECK(tracing_enabled());
702   FILE* file = trace_scope()->file();
703   Deoptimizer::DeoptInfo info =
704       Deoptimizer::GetDeoptInfo(compiled_code_, from_);
705   PrintF(file, "[bailout (kind: %s, reason: %s): begin. deoptimizing ",
706          MessageFor(deopt_kind_, should_reuse_code()),
707          DeoptimizeReasonToString(info.deopt_reason));
708   if (function_.IsJSFunction()) {
709     function_.ShortPrint(file);
710   } else {
711     PrintF(file, "%s", CodeKindToString(compiled_code_.kind()));
712   }
713   PrintF(file,
714          ", opt id %d, node id %d, bailout id %d, FP to SP delta %d, "
715          "caller SP " V8PRIxPTR_FMT ", pc " V8PRIxPTR_FMT "]\n",
716          optimization_id, node_id, bailout_id_, fp_to_sp_delta_,
717          caller_frame_top_, PointerAuthentication::StripPAC(from_));
718   if (verbose_tracing_enabled() && deopt_kind_ != DeoptimizeKind::kLazy) {
719     PrintF(file, "            ;;; deoptimize at ");
720     OFStream outstr(file);
721     info.position.Print(outstr, compiled_code_);
722     PrintF(file, "\n");
723   }
724 }
725 
TraceDeoptEnd(double deopt_duration)726 void Deoptimizer::TraceDeoptEnd(double deopt_duration) {
727   DCHECK(verbose_tracing_enabled());
728   PrintF(trace_scope()->file(), "[bailout end. took %0.3f ms]\n",
729          deopt_duration);
730 }
731 
732 // static
TraceMarkForDeoptimization(Code code,const char * reason)733 void Deoptimizer::TraceMarkForDeoptimization(Code code, const char* reason) {
734   if (!FLAG_trace_deopt_verbose) return;
735 
736   DisallowHeapAllocation no_gc;
737   Isolate* isolate = code.GetIsolate();
738   Object maybe_data = code.deoptimization_data();
739   if (maybe_data == ReadOnlyRoots(isolate).empty_fixed_array()) return;
740 
741   DeoptimizationData deopt_data = DeoptimizationData::cast(maybe_data);
742   CodeTracer::Scope scope(isolate->GetCodeTracer());
743   PrintF(scope.file(), "[marking dependent code " V8PRIxPTR_FMT " (",
744          code.ptr());
745   deopt_data.SharedFunctionInfo().ShortPrint(scope.file());
746   PrintF(") (opt id %d) for deoptimization, reason: %s]\n",
747          deopt_data.OptimizationId().value(), reason);
748   {
749     AllowHeapAllocation yes_gc;
750     HandleScope scope(isolate);
751     PROFILE(
752         isolate,
753         CodeDependencyChangeEvent(
754             handle(code, isolate),
755             handle(SharedFunctionInfo::cast(deopt_data.SharedFunctionInfo()),
756                    isolate),
757             reason));
758   }
759 }
760 
761 // static
TraceEvictFromOptimizedCodeCache(SharedFunctionInfo sfi,const char * reason)762 void Deoptimizer::TraceEvictFromOptimizedCodeCache(SharedFunctionInfo sfi,
763                                                    const char* reason) {
764   if (!FLAG_trace_deopt_verbose) return;
765 
766   DisallowHeapAllocation no_gc;
767   CodeTracer::Scope scope(sfi.GetIsolate()->GetCodeTracer());
768   PrintF(scope.file(),
769          "[evicting optimized code marked for deoptimization (%s) for ",
770          reason);
771   sfi.ShortPrint(scope.file());
772   PrintF(scope.file(), "]\n");
773 }
774 
775 #ifdef DEBUG
776 // static
TraceFoundActivation(Isolate * isolate,JSFunction function)777 void Deoptimizer::TraceFoundActivation(Isolate* isolate, JSFunction function) {
778   if (!FLAG_trace_deopt_verbose) return;
779   CodeTracer::Scope scope(isolate->GetCodeTracer());
780   PrintF(scope.file(), "[deoptimizer found activation of function: ");
781   function.PrintName(scope.file());
782   PrintF(scope.file(), " / %" V8PRIxPTR "]\n", function.ptr());
783 }
784 #endif  // DEBUG
785 
786 // static
TraceDeoptAll(Isolate * isolate)787 void Deoptimizer::TraceDeoptAll(Isolate* isolate) {
788   if (!FLAG_trace_deopt_verbose) return;
789   CodeTracer::Scope scope(isolate->GetCodeTracer());
790   PrintF(scope.file(), "[deoptimize all code in all contexts]\n");
791 }
792 
793 // static
TraceDeoptMarked(Isolate * isolate)794 void Deoptimizer::TraceDeoptMarked(Isolate* isolate) {
795   if (!FLAG_trace_deopt_verbose) return;
796   CodeTracer::Scope scope(isolate->GetCodeTracer());
797   PrintF(scope.file(), "[deoptimize marked code in all contexts]\n");
798 }
799 
800 // We rely on this function not causing a GC.  It is called from generated code
801 // without having a real stack frame in place.
DoComputeOutputFrames()802 void Deoptimizer::DoComputeOutputFrames() {
803   // When we call this function, the return address of the previous frame has
804   // been removed from the stack by the DeoptimizationEntry builtin, so the
805   // stack is not iterable by the SafeStackFrameIterator.
806 #if V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK
807   DCHECK_EQ(0, isolate()->isolate_data()->stack_is_iterable());
808 #endif
809   base::ElapsedTimer timer;
810 
811   // Determine basic deoptimization information.  The optimized frame is
812   // described by the input data.
813   DeoptimizationData input_data =
814       DeoptimizationData::cast(compiled_code_.deoptimization_data());
815 
816   {
817     // Read caller's PC, caller's FP and caller's constant pool values
818     // from input frame. Compute caller's frame top address.
819 
820     Register fp_reg = JavaScriptFrame::fp_register();
821     stack_fp_ = input_->GetRegister(fp_reg.code());
822 
823     caller_frame_top_ = stack_fp_ + ComputeInputFrameAboveFpFixedSize();
824 
825     Address fp_address = input_->GetFramePointerAddress();
826     caller_fp_ = Memory<intptr_t>(fp_address);
827     caller_pc_ =
828         Memory<intptr_t>(fp_address + CommonFrameConstants::kCallerPCOffset);
829     input_frame_context_ = Memory<intptr_t>(
830         fp_address + CommonFrameConstants::kContextOrFrameTypeOffset);
831     actual_argument_count_ = static_cast<int>(
832         Memory<intptr_t>(fp_address + StandardFrameConstants::kArgCOffset));
833 
834     if (FLAG_enable_embedded_constant_pool) {
835       caller_constant_pool_ = Memory<intptr_t>(
836           fp_address + CommonFrameConstants::kConstantPoolOffset);
837     }
838   }
839 
840   StackGuard* const stack_guard = isolate()->stack_guard();
841   CHECK_GT(static_cast<uintptr_t>(caller_frame_top_),
842            stack_guard->real_jslimit());
843 
844   BailoutId node_id = input_data.BytecodeOffset(bailout_id_);
845   ByteArray translations = input_data.TranslationByteArray();
846   unsigned translation_index = input_data.TranslationIndex(bailout_id_).value();
847 
848   if (tracing_enabled()) {
849     timer.Start();
850     TraceDeoptBegin(input_data.OptimizationId().value(), node_id.ToInt());
851   }
852 
853   FILE* trace_file =
854       verbose_tracing_enabled() ? trace_scope()->file() : nullptr;
855   TranslationIterator state_iterator(translations, translation_index);
856   translated_state_.Init(
857       isolate_, input_->GetFramePointerAddress(), stack_fp_, &state_iterator,
858       input_data.LiteralArray(), input_->GetRegisterValues(), trace_file,
859       function_.IsHeapObject()
860           ? function_.shared().internal_formal_parameter_count()
861           : 0,
862       actual_argument_count_);
863 
864   // Do the input frame to output frame(s) translation.
865   size_t count = translated_state_.frames().size();
866   // If we are supposed to go to the catch handler, find the catching frame
867   // for the catch and make sure we only deoptimize up to that frame.
868   if (deoptimizing_throw_) {
869     size_t catch_handler_frame_index = count;
870     for (size_t i = count; i-- > 0;) {
871       catch_handler_pc_offset_ = LookupCatchHandler(
872           &(translated_state_.frames()[i]), &catch_handler_data_);
873       if (catch_handler_pc_offset_ >= 0) {
874         catch_handler_frame_index = i;
875         break;
876       }
877     }
878     CHECK_LT(catch_handler_frame_index, count);
879     count = catch_handler_frame_index + 1;
880   }
881 
882   DCHECK_NULL(output_);
883   output_ = new FrameDescription*[count];
884   for (size_t i = 0; i < count; ++i) {
885     output_[i] = nullptr;
886   }
887   output_count_ = static_cast<int>(count);
888 
889   // Translate each output frame.
890   int frame_index = 0;  // output_frame_index
891   size_t total_output_frame_size = 0;
892   for (size_t i = 0; i < count; ++i, ++frame_index) {
893     // Read the ast node id, function, and frame height for this output frame.
894     TranslatedFrame* translated_frame = &(translated_state_.frames()[i]);
895     bool handle_exception = deoptimizing_throw_ && i == count - 1;
896     switch (translated_frame->kind()) {
897       case TranslatedFrame::kInterpretedFunction:
898         DoComputeInterpretedFrame(translated_frame, frame_index,
899                                   handle_exception);
900         jsframe_count_++;
901         break;
902       case TranslatedFrame::kArgumentsAdaptor:
903         DoComputeArgumentsAdaptorFrame(translated_frame, frame_index);
904         break;
905       case TranslatedFrame::kConstructStub:
906         DoComputeConstructStubFrame(translated_frame, frame_index);
907         break;
908       case TranslatedFrame::kBuiltinContinuation:
909         DoComputeBuiltinContinuation(translated_frame, frame_index,
910                                      BuiltinContinuationMode::STUB);
911         break;
912       case TranslatedFrame::kJavaScriptBuiltinContinuation:
913         DoComputeBuiltinContinuation(translated_frame, frame_index,
914                                      BuiltinContinuationMode::JAVASCRIPT);
915         break;
916       case TranslatedFrame::kJavaScriptBuiltinContinuationWithCatch:
917         DoComputeBuiltinContinuation(
918             translated_frame, frame_index,
919             handle_exception
920                 ? BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION
921                 : BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH);
922         break;
923       case TranslatedFrame::kInvalid:
924         FATAL("invalid frame");
925         break;
926     }
927     total_output_frame_size += output_[frame_index]->GetFrameSize();
928   }
929 
930   FrameDescription* topmost = output_[count - 1];
931   topmost->GetRegisterValues()->SetRegister(kRootRegister.code(),
932                                             isolate()->isolate_root());
933 
934   // Print some helpful diagnostic information.
935   if (verbose_tracing_enabled()) {
936     TraceDeoptEnd(timer.Elapsed().InMillisecondsF());
937   }
938 
939   // The following invariant is fairly tricky to guarantee, since the size of
940   // an optimized frame and its deoptimized counterparts usually differs. We
941   // thus need to consider the case in which deoptimized frames are larger than
942   // the optimized frame in stack checks in optimized code. We do this by
943   // applying an offset to stack checks (see kArchStackPointerGreaterThan in the
944   // code generator).
945   // Note that we explicitly allow deopts to exceed the limit by a certain
946   // number of slack bytes.
947   CHECK_GT(
948       static_cast<uintptr_t>(caller_frame_top_) - total_output_frame_size,
949       stack_guard->real_jslimit() - kStackLimitSlackForDeoptimizationInBytes);
950 }
951 
DoComputeInterpretedFrame(TranslatedFrame * translated_frame,int frame_index,bool goto_catch_handler)952 void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
953                                             int frame_index,
954                                             bool goto_catch_handler) {
955   SharedFunctionInfo shared = translated_frame->raw_shared_info();
956 
957   TranslatedFrame::iterator value_iterator = translated_frame->begin();
958   const bool is_bottommost = (0 == frame_index);
959   const bool is_topmost = (output_count_ - 1 == frame_index);
960 
961   const int real_bytecode_offset = translated_frame->node_id().ToInt();
962   const int bytecode_offset =
963       goto_catch_handler ? catch_handler_pc_offset_ : real_bytecode_offset;
964 
965   const int parameters_count = InternalFormalParameterCountWithReceiver(shared);
966 
967 #ifdef V8_NO_ARGUMENTS_ADAPTOR
968   // If this is the bottom most frame or the previous frame was the arguments
969   // adaptor fake frame, then we already have extra arguments in the stack
970   // (including any extra padding). Therefore we should not try to add any
971   // padding.
972   bool should_pad_arguments =
973       !is_bottommost && (translated_state_.frames()[frame_index - 1]).kind() !=
974                             TranslatedFrame::kArgumentsAdaptor;
975 #else
976   bool should_pad_arguments = true;
977 #endif
978 
979   const int locals_count = translated_frame->height();
980   InterpretedFrameInfo frame_info = InterpretedFrameInfo::Precise(
981       parameters_count, locals_count, is_topmost, should_pad_arguments);
982   const uint32_t output_frame_size = frame_info.frame_size_in_bytes();
983 
984   TranslatedFrame::iterator function_iterator = value_iterator++;
985   if (verbose_tracing_enabled()) {
986     PrintF(trace_scope()->file(), "  translating interpreted frame ");
987     std::unique_ptr<char[]> name = shared.DebugName().ToCString();
988     PrintF(trace_scope()->file(), "%s", name.get());
989     PrintF(trace_scope()->file(),
990            " => bytecode_offset=%d, variable_frame_size=%d, frame_size=%d%s\n",
991            real_bytecode_offset, frame_info.frame_size_in_bytes_without_fixed(),
992            output_frame_size, goto_catch_handler ? " (throw)" : "");
993   }
994 
995   // Allocate and store the output frame description.
996   FrameDescription* output_frame = new (output_frame_size)
997       FrameDescription(output_frame_size, parameters_count);
998   FrameWriter frame_writer(this, output_frame, verbose_trace_scope());
999 
1000   CHECK(frame_index >= 0 && frame_index < output_count_);
1001   CHECK_NULL(output_[frame_index]);
1002   output_[frame_index] = output_frame;
1003 
1004   // The top address of the frame is computed from the previous frame's top and
1005   // this frame's size.
1006   const intptr_t top_address =
1007       is_bottommost ? caller_frame_top_ - output_frame_size
1008                     : output_[frame_index - 1]->GetTop() - output_frame_size;
1009   output_frame->SetTop(top_address);
1010 
1011   // Compute the incoming parameter translation.
1012   ReadOnlyRoots roots(isolate());
1013   if (should_pad_arguments && ShouldPadArguments(parameters_count)) {
1014     frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1015   }
1016 
1017   // Note: parameters_count includes the receiver.
1018   if (verbose_tracing_enabled() && is_bottommost &&
1019       actual_argument_count_ > parameters_count - 1) {
1020     PrintF(trace_scope_->file(),
1021            "    -- %d extra argument(s) already in the stack --\n",
1022            actual_argument_count_ - parameters_count + 1);
1023   }
1024   frame_writer.PushStackJSArguments(value_iterator, parameters_count);
1025 
1026   DCHECK_EQ(output_frame->GetLastArgumentSlotOffset(should_pad_arguments),
1027             frame_writer.top_offset());
1028   if (verbose_tracing_enabled()) {
1029     PrintF(trace_scope()->file(), "    -------------------------\n");
1030   }
1031 
1032   // There are no translation commands for the caller's pc and fp, the
1033   // context, the function and the bytecode offset.  Synthesize
1034   // their values and set them up
1035   // explicitly.
1036   //
1037   // The caller's pc for the bottommost output frame is the same as in the
1038   // input frame.  For all subsequent output frames, it can be read from the
1039   // previous one.  This frame's pc can be computed from the non-optimized
1040   // function code and AST id of the bailout.
1041   if (is_bottommost) {
1042     frame_writer.PushBottommostCallerPc(caller_pc_);
1043   } else {
1044     frame_writer.PushApprovedCallerPc(output_[frame_index - 1]->GetPc());
1045   }
1046 
1047   // The caller's frame pointer for the bottommost output frame is the same
1048   // as in the input frame.  For all subsequent output frames, it can be
1049   // read from the previous one.  Also compute and set this frame's frame
1050   // pointer.
1051   const intptr_t caller_fp =
1052       is_bottommost ? caller_fp_ : output_[frame_index - 1]->GetFp();
1053   frame_writer.PushCallerFp(caller_fp);
1054 
1055   const intptr_t fp_value = top_address + frame_writer.top_offset();
1056   output_frame->SetFp(fp_value);
1057   if (is_topmost) {
1058     Register fp_reg = InterpretedFrame::fp_register();
1059     output_frame->SetRegister(fp_reg.code(), fp_value);
1060   }
1061 
1062   if (FLAG_enable_embedded_constant_pool) {
1063     // For the bottommost output frame the constant pool pointer can be gotten
1064     // from the input frame. For subsequent output frames, it can be read from
1065     // the previous frame.
1066     const intptr_t caller_cp =
1067         is_bottommost ? caller_constant_pool_
1068                       : output_[frame_index - 1]->GetConstantPool();
1069     frame_writer.PushCallerConstantPool(caller_cp);
1070   }
1071 
1072   // For the bottommost output frame the context can be gotten from the input
1073   // frame. For all subsequent output frames it can be gotten from the function
1074   // so long as we don't inline functions that need local contexts.
1075 
1076   // When deoptimizing into a catch block, we need to take the context
1077   // from a register that was specified in the handler table.
1078   TranslatedFrame::iterator context_pos = value_iterator++;
1079   if (goto_catch_handler) {
1080     // Skip to the translated value of the register specified
1081     // in the handler table.
1082     for (int i = 0; i < catch_handler_data_ + 1; ++i) {
1083       context_pos++;
1084     }
1085   }
1086   // Read the context from the translations.
1087   Object context = context_pos->GetRawValue();
1088   output_frame->SetContext(static_cast<intptr_t>(context.ptr()));
1089   frame_writer.PushTranslatedValue(context_pos, "context");
1090 
1091   // The function was mentioned explicitly in the BEGIN_FRAME.
1092   frame_writer.PushTranslatedValue(function_iterator, "function");
1093 
1094   // Actual argument count.
1095   int argc;
1096   if (is_bottommost) {
1097     argc = actual_argument_count_;
1098   } else {
1099     TranslatedFrame::Kind previous_frame_kind =
1100         (translated_state_.frames()[frame_index - 1]).kind();
1101     argc = previous_frame_kind == TranslatedFrame::kArgumentsAdaptor
1102                ? output_[frame_index - 1]->parameter_count()
1103                : parameters_count - 1;
1104   }
1105   frame_writer.PushRawValue(argc, "actual argument count\n");
1106 
1107   // Set the bytecode array pointer.
1108   Object bytecode_array = shared.HasBreakInfo()
1109                               ? shared.GetDebugInfo().DebugBytecodeArray()
1110                               : shared.GetBytecodeArray();
1111   frame_writer.PushRawObject(bytecode_array, "bytecode array\n");
1112 
1113   // The bytecode offset was mentioned explicitly in the BEGIN_FRAME.
1114   const int raw_bytecode_offset =
1115       BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset;
1116   Smi smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset);
1117   frame_writer.PushRawObject(smi_bytecode_offset, "bytecode offset\n");
1118 
1119   if (verbose_tracing_enabled()) {
1120     PrintF(trace_scope()->file(), "    -------------------------\n");
1121   }
1122 
1123   // Translate the rest of the interpreter registers in the frame.
1124   // The return_value_offset is counted from the top. Here, we compute the
1125   // register index (counted from the start).
1126   const int return_value_first_reg =
1127       locals_count - translated_frame->return_value_offset();
1128   const int return_value_count = translated_frame->return_value_count();
1129   for (int i = 0; i < locals_count; ++i, ++value_iterator) {
1130     // Ensure we write the return value if we have one and we are returning
1131     // normally to a lazy deopt point.
1132     if (is_topmost && !goto_catch_handler &&
1133         deopt_kind_ == DeoptimizeKind::kLazy && i >= return_value_first_reg &&
1134         i < return_value_first_reg + return_value_count) {
1135       const int return_index = i - return_value_first_reg;
1136       if (return_index == 0) {
1137         frame_writer.PushRawValue(input_->GetRegister(kReturnRegister0.code()),
1138                                   "return value 0\n");
1139         // We do not handle the situation when one return value should go into
1140         // the accumulator and another one into an ordinary register. Since
1141         // the interpreter should never create such situation, just assert
1142         // this does not happen.
1143         CHECK_LE(return_value_first_reg + return_value_count, locals_count);
1144       } else {
1145         CHECK_EQ(return_index, 1);
1146         frame_writer.PushRawValue(input_->GetRegister(kReturnRegister1.code()),
1147                                   "return value 1\n");
1148       }
1149     } else {
1150       // This is not return value, just write the value from the translations.
1151       frame_writer.PushTranslatedValue(value_iterator, "stack parameter");
1152     }
1153   }
1154 
1155   uint32_t register_slots_written = static_cast<uint32_t>(locals_count);
1156   DCHECK_LE(register_slots_written, frame_info.register_stack_slot_count());
1157   // Some architectures must pad the stack frame with extra stack slots
1158   // to ensure the stack frame is aligned. Do this now.
1159   while (register_slots_written < frame_info.register_stack_slot_count()) {
1160     register_slots_written++;
1161     frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1162   }
1163 
1164   // Translate the accumulator register (depending on frame position).
1165   if (is_topmost) {
1166     if (kPadArguments) {
1167       frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1168     }
1169     // For topmost frame, put the accumulator on the stack. The
1170     // {NotifyDeoptimized} builtin pops it off the topmost frame (possibly
1171     // after materialization).
1172     if (goto_catch_handler) {
1173       // If we are lazy deopting to a catch handler, we set the accumulator to
1174       // the exception (which lives in the result register).
1175       intptr_t accumulator_value =
1176           input_->GetRegister(kInterpreterAccumulatorRegister.code());
1177       frame_writer.PushRawObject(Object(accumulator_value), "accumulator\n");
1178     } else {
1179       // If we are lazily deoptimizing make sure we store the deopt
1180       // return value into the appropriate slot.
1181       if (deopt_kind_ == DeoptimizeKind::kLazy &&
1182           translated_frame->return_value_offset() == 0 &&
1183           translated_frame->return_value_count() > 0) {
1184         CHECK_EQ(translated_frame->return_value_count(), 1);
1185         frame_writer.PushRawValue(input_->GetRegister(kReturnRegister0.code()),
1186                                   "return value 0\n");
1187       } else {
1188         frame_writer.PushTranslatedValue(value_iterator, "accumulator");
1189       }
1190     }
1191     ++value_iterator;  // Move over the accumulator.
1192   } else {
1193     // For non-topmost frames, skip the accumulator translation. For those
1194     // frames, the return value from the callee will become the accumulator.
1195     ++value_iterator;
1196   }
1197   CHECK_EQ(translated_frame->end(), value_iterator);
1198   CHECK_EQ(0u, frame_writer.top_offset());
1199 
1200   // Compute this frame's PC and state. The PC will be a special builtin that
1201   // continues the bytecode dispatch. Note that non-topmost and lazy-style
1202   // bailout handlers also advance the bytecode offset before dispatch, hence
1203   // simulating what normal handlers do upon completion of the operation.
1204   Builtins* builtins = isolate_->builtins();
1205   Code dispatch_builtin =
1206       (!is_topmost || (deopt_kind_ == DeoptimizeKind::kLazy)) &&
1207               !goto_catch_handler
1208           ? builtins->builtin(Builtins::kInterpreterEnterBytecodeAdvance)
1209           : builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch);
1210   if (is_topmost) {
1211     // Only the pc of the topmost frame needs to be signed since it is
1212     // authenticated at the end of the DeoptimizationEntry builtin.
1213     const intptr_t top_most_pc = PointerAuthentication::SignAndCheckPC(
1214         static_cast<intptr_t>(dispatch_builtin.InstructionStart()),
1215         frame_writer.frame()->GetTop());
1216     output_frame->SetPc(top_most_pc);
1217   } else {
1218     output_frame->SetPc(
1219         static_cast<intptr_t>(dispatch_builtin.InstructionStart()));
1220   }
1221 
1222   // Update constant pool.
1223   if (FLAG_enable_embedded_constant_pool) {
1224     intptr_t constant_pool_value =
1225         static_cast<intptr_t>(dispatch_builtin.constant_pool());
1226     output_frame->SetConstantPool(constant_pool_value);
1227     if (is_topmost) {
1228       Register constant_pool_reg =
1229           InterpretedFrame::constant_pool_pointer_register();
1230       output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1231     }
1232   }
1233 
1234   // Clear the context register. The context might be a de-materialized object
1235   // and will be materialized by {Runtime_NotifyDeoptimized}. For additional
1236   // safety we use Smi(0) instead of the potential {arguments_marker} here.
1237   if (is_topmost) {
1238     intptr_t context_value = static_cast<intptr_t>(Smi::zero().ptr());
1239     Register context_reg = JavaScriptFrame::context_register();
1240     output_frame->SetRegister(context_reg.code(), context_value);
1241     // Set the continuation for the topmost frame.
1242     Code continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
1243     output_frame->SetContinuation(
1244         static_cast<intptr_t>(continuation.InstructionStart()));
1245   }
1246 }
1247 
DoComputeArgumentsAdaptorFrame(TranslatedFrame * translated_frame,int frame_index)1248 void Deoptimizer::DoComputeArgumentsAdaptorFrame(
1249     TranslatedFrame* translated_frame, int frame_index) {
1250   // Arguments adaptor can not be top most, nor the bottom most frames.
1251   CHECK(frame_index < output_count_ - 1);
1252   CHECK_GT(frame_index, 0);
1253   CHECK_NULL(output_[frame_index]);
1254 
1255 #ifdef V8_NO_ARGUMENTS_ADAPTOR
1256   // During execution, V8 does not understand arguments adaptor frames anymore,
1257   // so during deoptimization we only push the extra arguments (arguments with
1258   // index greater than the formal parameter count). Therefore we call this
1259   // TranslatedFrame the fake adaptor frame. For more info, see the design
1260   // document shorturl.at/fKT49.
1261 
1262   TranslatedFrame::iterator value_iterator = translated_frame->begin();
1263   const int argument_count_without_receiver = translated_frame->height() - 1;
1264   const int formal_parameter_count =
1265       translated_frame->raw_shared_info().internal_formal_parameter_count();
1266   const int extra_argument_count =
1267       argument_count_without_receiver - formal_parameter_count;
1268   // The number of pushed arguments is the maximum of the actual argument count
1269   // and the formal parameter count + the receiver.
1270   const bool should_pad_args = ShouldPadArguments(
1271       std::max(argument_count_without_receiver, formal_parameter_count) + 1);
1272   const int output_frame_size =
1273       std::max(0, extra_argument_count * kSystemPointerSize) +
1274       (should_pad_args ? kSystemPointerSize : 0);
1275   if (verbose_tracing_enabled()) {
1276     PrintF(trace_scope_->file(),
1277            "  translating arguments adaptor => variable_size=%d\n",
1278            output_frame_size);
1279   }
1280 
1281   // Allocate and store the output frame description.
1282   FrameDescription* output_frame = new (output_frame_size)
1283       FrameDescription(output_frame_size, argument_count_without_receiver);
1284   // The top address of the frame is computed from the previous frame's top and
1285   // this frame's size.
1286   const intptr_t top_address =
1287       output_[frame_index - 1]->GetTop() - output_frame_size;
1288   output_frame->SetTop(top_address);
1289   // This is not a real frame, we take PC and FP values from the parent frame.
1290   output_frame->SetPc(output_[frame_index - 1]->GetPc());
1291   output_frame->SetFp(output_[frame_index - 1]->GetFp());
1292   output_[frame_index] = output_frame;
1293 
1294   FrameWriter frame_writer(this, output_frame, verbose_trace_scope());
1295 
1296   ReadOnlyRoots roots(isolate());
1297   if (should_pad_args) {
1298     frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1299   }
1300 
1301   if (extra_argument_count > 0) {
1302     // The receiver and arguments with index below the formal parameter
1303     // count are in the fake adaptor frame, because they are used to create the
1304     // arguments object. We should however not push them, since the interpreter
1305     // frame with do that.
1306     value_iterator++;  // Skip function.
1307     value_iterator++;  // Skip receiver.
1308     for (int i = 0; i < formal_parameter_count; i++) value_iterator++;
1309     frame_writer.PushStackJSArguments(value_iterator, extra_argument_count);
1310   }
1311 #else
1312   TranslatedFrame::iterator value_iterator = translated_frame->begin();
1313   const bool is_bottommost = (0 == frame_index);
1314 
1315   const int parameters_count = translated_frame->height();
1316   ArgumentsAdaptorFrameInfo frame_info =
1317       ArgumentsAdaptorFrameInfo::Precise(parameters_count);
1318   const uint32_t output_frame_size = frame_info.frame_size_in_bytes();
1319 
1320   TranslatedFrame::iterator function_iterator = value_iterator++;
1321   if (verbose_tracing_enabled()) {
1322     PrintF(trace_scope()->file(),
1323            "  translating arguments adaptor => variable_frame_size=%d, "
1324            "frame_size=%d\n",
1325            frame_info.frame_size_in_bytes_without_fixed(), output_frame_size);
1326   }
1327 
1328   // Allocate and store the output frame description.
1329   FrameDescription* output_frame = new (output_frame_size)
1330       FrameDescription(output_frame_size, parameters_count);
1331   FrameWriter frame_writer(this, output_frame, verbose_trace_scope());
1332 
1333   // Arguments adaptor can not be topmost.
1334   CHECK(frame_index < output_count_ - 1);
1335   CHECK_NULL(output_[frame_index]);
1336   output_[frame_index] = output_frame;
1337 
1338   // The top address of the frame is computed from the previous frame's top and
1339   // this frame's size.
1340   const intptr_t top_address =
1341       is_bottommost ? caller_frame_top_ - output_frame_size
1342                     : output_[frame_index - 1]->GetTop() - output_frame_size;
1343   output_frame->SetTop(top_address);
1344 
1345   ReadOnlyRoots roots(isolate());
1346   if (ShouldPadArguments(parameters_count)) {
1347     frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1348   }
1349 
1350   // Compute the incoming parameter translation.
1351   frame_writer.PushStackJSArguments(value_iterator, parameters_count);
1352 
1353   DCHECK_EQ(output_frame->GetLastArgumentSlotOffset(),
1354             frame_writer.top_offset());
1355 
1356   // Read caller's PC from the previous frame.
1357   if (is_bottommost) {
1358     frame_writer.PushBottommostCallerPc(caller_pc_);
1359   } else {
1360     frame_writer.PushApprovedCallerPc(output_[frame_index - 1]->GetPc());
1361   }
1362 
1363   // Read caller's FP from the previous frame, and set this frame's FP.
1364   const intptr_t caller_fp =
1365       is_bottommost ? caller_fp_ : output_[frame_index - 1]->GetFp();
1366   frame_writer.PushCallerFp(caller_fp);
1367 
1368   intptr_t fp_value = top_address + frame_writer.top_offset();
1369   output_frame->SetFp(fp_value);
1370 
1371   if (FLAG_enable_embedded_constant_pool) {
1372     // Read the caller's constant pool from the previous frame.
1373     const intptr_t caller_cp =
1374         is_bottommost ? caller_constant_pool_
1375                       : output_[frame_index - 1]->GetConstantPool();
1376     frame_writer.PushCallerConstantPool(caller_cp);
1377   }
1378 
1379   // A marker value is used in place of the context.
1380   intptr_t marker = StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR);
1381   frame_writer.PushRawValue(marker, "context (adaptor sentinel)\n");
1382 
1383   // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
1384   frame_writer.PushTranslatedValue(function_iterator, "function\n");
1385 
1386   // Number of incoming arguments.
1387   const uint32_t parameters_count_without_receiver = parameters_count - 1;
1388   frame_writer.PushRawObject(Smi::FromInt(parameters_count_without_receiver),
1389                              "argc\n");
1390 
1391   frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1392 
1393   CHECK_EQ(translated_frame->end(), value_iterator);
1394   DCHECK_EQ(0, frame_writer.top_offset());
1395 
1396   Builtins* builtins = isolate_->builtins();
1397   Code adaptor_trampoline =
1398       builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
1399   intptr_t pc_value = static_cast<intptr_t>(
1400       adaptor_trampoline.InstructionStart() +
1401       isolate_->heap()->arguments_adaptor_deopt_pc_offset().value());
1402   output_frame->SetPc(pc_value);
1403   if (FLAG_enable_embedded_constant_pool) {
1404     intptr_t constant_pool_value =
1405         static_cast<intptr_t>(adaptor_trampoline.constant_pool());
1406     output_frame->SetConstantPool(constant_pool_value);
1407   }
1408 #endif
1409 }
1410 
DoComputeConstructStubFrame(TranslatedFrame * translated_frame,int frame_index)1411 void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
1412                                               int frame_index) {
1413   TranslatedFrame::iterator value_iterator = translated_frame->begin();
1414   const bool is_topmost = (output_count_ - 1 == frame_index);
1415   // The construct frame could become topmost only if we inlined a constructor
1416   // call which does a tail call (otherwise the tail callee's frame would be
1417   // the topmost one). So it could only be the DeoptimizeKind::kLazy case.
1418   CHECK(!is_topmost || deopt_kind_ == DeoptimizeKind::kLazy);
1419 
1420   Builtins* builtins = isolate_->builtins();
1421   Code construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
1422   BailoutId bailout_id = translated_frame->node_id();
1423 
1424   const int parameters_count = translated_frame->height();
1425   ConstructStubFrameInfo frame_info =
1426       ConstructStubFrameInfo::Precise(parameters_count, is_topmost);
1427   const uint32_t output_frame_size = frame_info.frame_size_in_bytes();
1428 
1429   TranslatedFrame::iterator function_iterator = value_iterator++;
1430   if (verbose_tracing_enabled()) {
1431     PrintF(trace_scope()->file(),
1432            "  translating construct stub => bailout_id=%d (%s), "
1433            "variable_frame_size=%d, frame_size=%d\n",
1434            bailout_id.ToInt(),
1435            bailout_id == BailoutId::ConstructStubCreate() ? "create" : "invoke",
1436            frame_info.frame_size_in_bytes_without_fixed(), output_frame_size);
1437   }
1438 
1439   // Allocate and store the output frame description.
1440   FrameDescription* output_frame = new (output_frame_size)
1441       FrameDescription(output_frame_size, parameters_count);
1442   FrameWriter frame_writer(this, output_frame, verbose_trace_scope());
1443 
1444   // Construct stub can not be topmost.
1445   DCHECK(frame_index > 0 && frame_index < output_count_);
1446   DCHECK_NULL(output_[frame_index]);
1447   output_[frame_index] = output_frame;
1448 
1449   // The top address of the frame is computed from the previous frame's top and
1450   // this frame's size.
1451   const intptr_t top_address =
1452       output_[frame_index - 1]->GetTop() - output_frame_size;
1453   output_frame->SetTop(top_address);
1454 
1455   ReadOnlyRoots roots(isolate());
1456   if (ShouldPadArguments(parameters_count)) {
1457     frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1458   }
1459 
1460   // The allocated receiver of a construct stub frame is passed as the
1461   // receiver parameter through the translation. It might be encoding
1462   // a captured object, so we need save it for later.
1463   TranslatedFrame::iterator receiver_iterator = value_iterator;
1464 
1465   // Compute the incoming parameter translation.
1466   frame_writer.PushStackJSArguments(value_iterator, parameters_count);
1467 
1468   DCHECK_EQ(output_frame->GetLastArgumentSlotOffset(),
1469             frame_writer.top_offset());
1470 
1471   // Read caller's PC from the previous frame.
1472   const intptr_t caller_pc = output_[frame_index - 1]->GetPc();
1473   frame_writer.PushApprovedCallerPc(caller_pc);
1474 
1475   // Read caller's FP from the previous frame, and set this frame's FP.
1476   const intptr_t caller_fp = output_[frame_index - 1]->GetFp();
1477   frame_writer.PushCallerFp(caller_fp);
1478 
1479   const intptr_t fp_value = top_address + frame_writer.top_offset();
1480   output_frame->SetFp(fp_value);
1481   if (is_topmost) {
1482     Register fp_reg = JavaScriptFrame::fp_register();
1483     output_frame->SetRegister(fp_reg.code(), fp_value);
1484   }
1485 
1486   if (FLAG_enable_embedded_constant_pool) {
1487     // Read the caller's constant pool from the previous frame.
1488     const intptr_t caller_cp = output_[frame_index - 1]->GetConstantPool();
1489     frame_writer.PushCallerConstantPool(caller_cp);
1490   }
1491 
1492   // A marker value is used to mark the frame.
1493   intptr_t marker = StackFrame::TypeToMarker(StackFrame::CONSTRUCT);
1494   frame_writer.PushRawValue(marker, "context (construct stub sentinel)\n");
1495 
1496   frame_writer.PushTranslatedValue(value_iterator++, "context");
1497 
1498   // Number of incoming arguments.
1499   const uint32_t parameters_count_without_receiver = parameters_count - 1;
1500   frame_writer.PushRawObject(Smi::FromInt(parameters_count_without_receiver),
1501                              "argc\n");
1502 
1503   // The constructor function was mentioned explicitly in the
1504   // CONSTRUCT_STUB_FRAME.
1505   frame_writer.PushTranslatedValue(function_iterator, "constructor function\n");
1506 
1507   // The deopt info contains the implicit receiver or the new target at the
1508   // position of the receiver. Copy it to the top of stack, with the hole value
1509   // as padding to maintain alignment.
1510 
1511   frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1512 
1513   CHECK(bailout_id == BailoutId::ConstructStubCreate() ||
1514         bailout_id == BailoutId::ConstructStubInvoke());
1515   const char* debug_hint = bailout_id == BailoutId::ConstructStubCreate()
1516                                ? "new target\n"
1517                                : "allocated receiver\n";
1518   frame_writer.PushTranslatedValue(receiver_iterator, debug_hint);
1519 
1520   if (is_topmost) {
1521     if (kPadArguments) {
1522       frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1523     }
1524     // Ensure the result is restored back when we return to the stub.
1525     Register result_reg = kReturnRegister0;
1526     intptr_t result = input_->GetRegister(result_reg.code());
1527     frame_writer.PushRawValue(result, "subcall result\n");
1528   }
1529 
1530   CHECK_EQ(translated_frame->end(), value_iterator);
1531   CHECK_EQ(0u, frame_writer.top_offset());
1532 
1533   // Compute this frame's PC.
1534   DCHECK(bailout_id.IsValidForConstructStub());
1535   Address start = construct_stub.InstructionStart();
1536   const int pc_offset =
1537       bailout_id == BailoutId::ConstructStubCreate()
1538           ? isolate_->heap()->construct_stub_create_deopt_pc_offset().value()
1539           : isolate_->heap()->construct_stub_invoke_deopt_pc_offset().value();
1540   intptr_t pc_value = static_cast<intptr_t>(start + pc_offset);
1541   if (is_topmost) {
1542     // Only the pc of the topmost frame needs to be signed since it is
1543     // authenticated at the end of the DeoptimizationEntry builtin.
1544     output_frame->SetPc(PointerAuthentication::SignAndCheckPC(
1545         pc_value, frame_writer.frame()->GetTop()));
1546   } else {
1547     output_frame->SetPc(pc_value);
1548   }
1549 
1550   // Update constant pool.
1551   if (FLAG_enable_embedded_constant_pool) {
1552     intptr_t constant_pool_value =
1553         static_cast<intptr_t>(construct_stub.constant_pool());
1554     output_frame->SetConstantPool(constant_pool_value);
1555     if (is_topmost) {
1556       Register constant_pool_reg =
1557           JavaScriptFrame::constant_pool_pointer_register();
1558       output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1559     }
1560   }
1561 
1562   // Clear the context register. The context might be a de-materialized object
1563   // and will be materialized by {Runtime_NotifyDeoptimized}. For additional
1564   // safety we use Smi(0) instead of the potential {arguments_marker} here.
1565   if (is_topmost) {
1566     intptr_t context_value = static_cast<intptr_t>(Smi::zero().ptr());
1567     Register context_reg = JavaScriptFrame::context_register();
1568     output_frame->SetRegister(context_reg.code(), context_value);
1569   }
1570 
1571   // Set the continuation for the topmost frame.
1572   if (is_topmost) {
1573     Builtins* builtins = isolate_->builtins();
1574     DCHECK_EQ(DeoptimizeKind::kLazy, deopt_kind_);
1575     Code continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
1576     output_frame->SetContinuation(
1577         static_cast<intptr_t>(continuation.InstructionStart()));
1578   }
1579 }
1580 
1581 namespace {
1582 
BuiltinContinuationModeIsJavaScript(BuiltinContinuationMode mode)1583 bool BuiltinContinuationModeIsJavaScript(BuiltinContinuationMode mode) {
1584   switch (mode) {
1585     case BuiltinContinuationMode::STUB:
1586       return false;
1587     case BuiltinContinuationMode::JAVASCRIPT:
1588     case BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH:
1589     case BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION:
1590       return true;
1591   }
1592   UNREACHABLE();
1593 }
1594 
BuiltinContinuationModeToFrameType(BuiltinContinuationMode mode)1595 StackFrame::Type BuiltinContinuationModeToFrameType(
1596     BuiltinContinuationMode mode) {
1597   switch (mode) {
1598     case BuiltinContinuationMode::STUB:
1599       return StackFrame::BUILTIN_CONTINUATION;
1600     case BuiltinContinuationMode::JAVASCRIPT:
1601       return StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION;
1602     case BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH:
1603       return StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH;
1604     case BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION:
1605       return StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH;
1606   }
1607   UNREACHABLE();
1608 }
1609 
1610 }  // namespace
1611 
TrampolineForBuiltinContinuation(BuiltinContinuationMode mode,bool must_handle_result)1612 Builtins::Name Deoptimizer::TrampolineForBuiltinContinuation(
1613     BuiltinContinuationMode mode, bool must_handle_result) {
1614   switch (mode) {
1615     case BuiltinContinuationMode::STUB:
1616       return must_handle_result ? Builtins::kContinueToCodeStubBuiltinWithResult
1617                                 : Builtins::kContinueToCodeStubBuiltin;
1618     case BuiltinContinuationMode::JAVASCRIPT:
1619     case BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH:
1620     case BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION:
1621       return must_handle_result
1622                  ? Builtins::kContinueToJavaScriptBuiltinWithResult
1623                  : Builtins::kContinueToJavaScriptBuiltin;
1624   }
1625   UNREACHABLE();
1626 }
1627 
1628 // BuiltinContinuationFrames capture the machine state that is expected as input
1629 // to a builtin, including both input register values and stack parameters. When
1630 // the frame is reactivated (i.e. the frame below it returns), a
1631 // ContinueToBuiltin stub restores the register state from the frame and tail
1632 // calls to the actual target builtin, making it appear that the stub had been
1633 // directly called by the frame above it. The input values to populate the frame
1634 // are taken from the deopt's FrameState.
1635 //
1636 // Frame translation happens in two modes, EAGER and LAZY. In EAGER mode, all of
1637 // the parameters to the Builtin are explicitly specified in the TurboFan
1638 // FrameState node. In LAZY mode, there is always one fewer parameters specified
1639 // in the FrameState than expected by the Builtin. In that case, construction of
1640 // BuiltinContinuationFrame adds the final missing parameter during
1641 // deoptimization, and that parameter is always on the stack and contains the
1642 // value returned from the callee of the call site triggering the LAZY deopt
1643 // (e.g. rax on x64). This requires that continuation Builtins for LAZY deopts
1644 // must have at least one stack parameter.
1645 //
1646 //                TO
1647 //    |          ....           |
1648 //    +-------------------------+
1649 //    | arg padding (arch dept) |<- at most 1*kSystemPointerSize
1650 //    +-------------------------+
1651 //    |     builtin param 0     |<- FrameState input value n becomes
1652 //    +-------------------------+
1653 //    |           ...           |
1654 //    +-------------------------+
1655 //    |     builtin param m     |<- FrameState input value n+m-1, or in
1656 //    +-----needs-alignment-----+   the LAZY case, return LAZY result value
1657 //    | ContinueToBuiltin entry |
1658 //    +-------------------------+
1659 // |  |    saved frame (FP)     |
1660 // |  +=====needs=alignment=====+<- fpreg
1661 // |  |constant pool (if ool_cp)|
1662 // v  +-------------------------+
1663 //    |BUILTIN_CONTINUATION mark|
1664 //    +-------------------------+
1665 //    |  JSFunction (or zero)   |<- only if JavaScript builtin
1666 //    +-------------------------+
1667 //    |  frame height above FP  |
1668 //    +-------------------------+
1669 //    |         context         |<- this non-standard context slot contains
1670 //    +-------------------------+   the context, even for non-JS builtins.
1671 //    |      builtin index      |
1672 //    +-------------------------+
1673 //    | builtin input GPR reg0  |<- populated from deopt FrameState using
1674 //    +-------------------------+   the builtin's CallInterfaceDescriptor
1675 //    |          ...            |   to map a FrameState's 0..n-1 inputs to
1676 //    +-------------------------+   the builtin's n input register params.
1677 //    | builtin input GPR regn  |
1678 //    +-------------------------+
1679 //    | reg padding (arch dept) |
1680 //    +-----needs--alignment----+
1681 //    | res padding (arch dept) |<- only if {is_topmost}; result is pop'd by
1682 //    +-------------------------+<- kNotifyDeopt ASM stub and moved to acc
1683 //    |      result  value      |<- reg, as ContinueToBuiltin stub expects.
1684 //    +-----needs-alignment-----+<- spreg
1685 //
DoComputeBuiltinContinuation(TranslatedFrame * translated_frame,int frame_index,BuiltinContinuationMode mode)1686 void Deoptimizer::DoComputeBuiltinContinuation(
1687     TranslatedFrame* translated_frame, int frame_index,
1688     BuiltinContinuationMode mode) {
1689   TranslatedFrame::iterator value_iterator = translated_frame->begin();
1690 
1691   const BailoutId bailout_id = translated_frame->node_id();
1692   Builtins::Name builtin_name = Builtins::GetBuiltinFromBailoutId(bailout_id);
1693   CallInterfaceDescriptor continuation_descriptor =
1694       Builtins::CallInterfaceDescriptorFor(builtin_name);
1695 
1696   const RegisterConfiguration* config = RegisterConfiguration::Default();
1697 
1698   const bool is_bottommost = (0 == frame_index);
1699   const bool is_topmost = (output_count_ - 1 == frame_index);
1700 
1701   const int parameters_count = translated_frame->height();
1702   BuiltinContinuationFrameInfo frame_info =
1703       BuiltinContinuationFrameInfo::Precise(parameters_count,
1704                                             continuation_descriptor, config,
1705                                             is_topmost, deopt_kind_, mode);
1706 
1707   const unsigned output_frame_size = frame_info.frame_size_in_bytes();
1708   const unsigned output_frame_size_above_fp =
1709       frame_info.frame_size_in_bytes_above_fp();
1710 
1711   // Validate types of parameters. They must all be tagged except for argc for
1712   // JS builtins.
1713   bool has_argc = false;
1714   const int register_parameter_count =
1715       continuation_descriptor.GetRegisterParameterCount();
1716   for (int i = 0; i < register_parameter_count; ++i) {
1717     MachineType type = continuation_descriptor.GetParameterType(i);
1718     int code = continuation_descriptor.GetRegisterParameter(i).code();
1719     // Only tagged and int32 arguments are supported, and int32 only for the
1720     // arguments count on JavaScript builtins.
1721     if (type == MachineType::Int32()) {
1722       CHECK_EQ(code, kJavaScriptCallArgCountRegister.code());
1723       has_argc = true;
1724     } else {
1725       // Any other argument must be a tagged value.
1726       CHECK(IsAnyTagged(type.representation()));
1727     }
1728   }
1729   CHECK_EQ(BuiltinContinuationModeIsJavaScript(mode), has_argc);
1730 
1731   if (verbose_tracing_enabled()) {
1732     PrintF(trace_scope()->file(),
1733            "  translating BuiltinContinuation to %s,"
1734            " => register_param_count=%d,"
1735            " stack_param_count=%d, frame_size=%d\n",
1736            Builtins::name(builtin_name), register_parameter_count,
1737            frame_info.stack_parameter_count(), output_frame_size);
1738   }
1739 
1740   FrameDescription* output_frame = new (output_frame_size)
1741       FrameDescription(output_frame_size, frame_info.stack_parameter_count());
1742   output_[frame_index] = output_frame;
1743   FrameWriter frame_writer(this, output_frame, verbose_trace_scope());
1744 
1745   // The top address of the frame is computed from the previous frame's top and
1746   // this frame's size.
1747   const intptr_t top_address =
1748       is_bottommost ? caller_frame_top_ - output_frame_size
1749                     : output_[frame_index - 1]->GetTop() - output_frame_size;
1750   output_frame->SetTop(top_address);
1751 
1752   // Get the possible JSFunction for the case that this is a
1753   // JavaScriptBuiltinContinuationFrame, which needs the JSFunction pointer
1754   // like a normal JavaScriptFrame.
1755   const intptr_t maybe_function = value_iterator->GetRawValue().ptr();
1756   ++value_iterator;
1757 
1758   ReadOnlyRoots roots(isolate());
1759   if (ShouldPadArguments(frame_info.stack_parameter_count())) {
1760     frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1761   }
1762 
1763   if (mode == BuiltinContinuationMode::STUB) {
1764     DCHECK_EQ(Builtins::CallInterfaceDescriptorFor(builtin_name)
1765                   .GetStackArgumentOrder(),
1766               StackArgumentOrder::kDefault);
1767     for (uint32_t i = 0; i < frame_info.translated_stack_parameter_count();
1768          ++i, ++value_iterator) {
1769       frame_writer.PushTranslatedValue(value_iterator, "stack parameter");
1770     }
1771     if (frame_info.frame_has_result_stack_slot()) {
1772       frame_writer.PushRawObject(
1773           roots.the_hole_value(),
1774           "placeholder for return result on lazy deopt\n");
1775     }
1776   } else {
1777     // JavaScript builtin.
1778     if (frame_info.frame_has_result_stack_slot()) {
1779       frame_writer.PushRawObject(
1780           roots.the_hole_value(),
1781           "placeholder for return result on lazy deopt\n");
1782     }
1783     switch (mode) {
1784       case BuiltinContinuationMode::STUB:
1785         UNREACHABLE();
1786       case BuiltinContinuationMode::JAVASCRIPT:
1787         break;
1788       case BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH: {
1789         frame_writer.PushRawObject(roots.the_hole_value(),
1790                                    "placeholder for exception on lazy deopt\n");
1791       } break;
1792       case BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION: {
1793         intptr_t accumulator_value =
1794             input_->GetRegister(kInterpreterAccumulatorRegister.code());
1795         frame_writer.PushRawObject(Object(accumulator_value),
1796                                    "exception (from accumulator)\n");
1797       } break;
1798     }
1799     frame_writer.PushStackJSArguments(
1800         value_iterator, frame_info.translated_stack_parameter_count());
1801   }
1802 
1803   DCHECK_EQ(output_frame->GetLastArgumentSlotOffset(),
1804             frame_writer.top_offset());
1805 
1806   std::vector<TranslatedFrame::iterator> register_values;
1807   int total_registers = config->num_general_registers();
1808   register_values.resize(total_registers, {value_iterator});
1809 
1810   for (int i = 0; i < register_parameter_count; ++i, ++value_iterator) {
1811     int code = continuation_descriptor.GetRegisterParameter(i).code();
1812     register_values[code] = value_iterator;
1813   }
1814 
1815   // The context register is always implicit in the CallInterfaceDescriptor but
1816   // its register must be explicitly set when continuing to the builtin. Make
1817   // sure that it's harvested from the translation and copied into the register
1818   // set (it was automatically added at the end of the FrameState by the
1819   // instruction selector).
1820   Object context = value_iterator->GetRawValue();
1821   const intptr_t value = context.ptr();
1822   TranslatedFrame::iterator context_register_value = value_iterator++;
1823   register_values[kContextRegister.code()] = context_register_value;
1824   output_frame->SetContext(value);
1825   output_frame->SetRegister(kContextRegister.code(), value);
1826 
1827   // Set caller's PC (JSFunction continuation).
1828   if (is_bottommost) {
1829     frame_writer.PushBottommostCallerPc(caller_pc_);
1830   } else {
1831     frame_writer.PushApprovedCallerPc(output_[frame_index - 1]->GetPc());
1832   }
1833 
1834   // Read caller's FP from the previous frame, and set this frame's FP.
1835   const intptr_t caller_fp =
1836       is_bottommost ? caller_fp_ : output_[frame_index - 1]->GetFp();
1837   frame_writer.PushCallerFp(caller_fp);
1838 
1839   const intptr_t fp_value = top_address + frame_writer.top_offset();
1840   output_frame->SetFp(fp_value);
1841 
1842   DCHECK_EQ(output_frame_size_above_fp, frame_writer.top_offset());
1843 
1844   if (FLAG_enable_embedded_constant_pool) {
1845     // Read the caller's constant pool from the previous frame.
1846     const intptr_t caller_cp =
1847         is_bottommost ? caller_constant_pool_
1848                       : output_[frame_index - 1]->GetConstantPool();
1849     frame_writer.PushCallerConstantPool(caller_cp);
1850   }
1851 
1852   // A marker value is used in place of the context.
1853   const intptr_t marker =
1854       StackFrame::TypeToMarker(BuiltinContinuationModeToFrameType(mode));
1855   frame_writer.PushRawValue(marker,
1856                             "context (builtin continuation sentinel)\n");
1857 
1858   if (BuiltinContinuationModeIsJavaScript(mode)) {
1859     frame_writer.PushRawValue(maybe_function, "JSFunction\n");
1860   } else {
1861     frame_writer.PushRawValue(0, "unused\n");
1862   }
1863 
1864   // The delta from the SP to the FP; used to reconstruct SP in
1865   // Isolate::UnwindAndFindHandler.
1866   frame_writer.PushRawObject(Smi::FromInt(output_frame_size_above_fp),
1867                              "frame height at deoptimization\n");
1868 
1869   // The context even if this is a stub contininuation frame. We can't use the
1870   // usual context slot, because we must store the frame marker there.
1871   frame_writer.PushTranslatedValue(context_register_value,
1872                                    "builtin JavaScript context\n");
1873 
1874   // The builtin to continue to.
1875   frame_writer.PushRawObject(Smi::FromInt(builtin_name), "builtin index\n");
1876 
1877   const int allocatable_register_count =
1878       config->num_allocatable_general_registers();
1879   for (int i = 0; i < allocatable_register_count; ++i) {
1880     int code = config->GetAllocatableGeneralCode(i);
1881     ScopedVector<char> str(128);
1882     if (verbose_tracing_enabled()) {
1883       if (BuiltinContinuationModeIsJavaScript(mode) &&
1884           code == kJavaScriptCallArgCountRegister.code()) {
1885         SNPrintF(
1886             str,
1887             "tagged argument count %s (will be untagged by continuation)\n",
1888             RegisterName(Register::from_code(code)));
1889       } else {
1890         SNPrintF(str, "builtin register argument %s\n",
1891                  RegisterName(Register::from_code(code)));
1892       }
1893     }
1894     frame_writer.PushTranslatedValue(
1895         register_values[code], verbose_tracing_enabled() ? str.begin() : "");
1896   }
1897 
1898   // Some architectures must pad the stack frame with extra stack slots
1899   // to ensure the stack frame is aligned.
1900   const int padding_slot_count =
1901       BuiltinContinuationFrameConstants::PaddingSlotCount(
1902           allocatable_register_count);
1903   for (int i = 0; i < padding_slot_count; ++i) {
1904     frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1905   }
1906 
1907   if (is_topmost) {
1908     if (kPadArguments) {
1909       frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
1910     }
1911 
1912     // Ensure the result is restored back when we return to the stub.
1913     if (frame_info.frame_has_result_stack_slot()) {
1914       Register result_reg = kReturnRegister0;
1915       frame_writer.PushRawValue(input_->GetRegister(result_reg.code()),
1916                                 "callback result\n");
1917     } else {
1918       frame_writer.PushRawObject(roots.undefined_value(), "callback result\n");
1919     }
1920   }
1921 
1922   CHECK_EQ(translated_frame->end(), value_iterator);
1923   CHECK_EQ(0u, frame_writer.top_offset());
1924 
1925   // Clear the context register. The context might be a de-materialized object
1926   // and will be materialized by {Runtime_NotifyDeoptimized}. For additional
1927   // safety we use Smi(0) instead of the potential {arguments_marker} here.
1928   if (is_topmost) {
1929     intptr_t context_value = static_cast<intptr_t>(Smi::zero().ptr());
1930     Register context_reg = JavaScriptFrame::context_register();
1931     output_frame->SetRegister(context_reg.code(), context_value);
1932   }
1933 
1934   // Ensure the frame pointer register points to the callee's frame. The builtin
1935   // will build its own frame once we continue to it.
1936   Register fp_reg = JavaScriptFrame::fp_register();
1937   output_frame->SetRegister(fp_reg.code(), fp_value);
1938 
1939   Code continue_to_builtin =
1940       isolate()->builtins()->builtin(TrampolineForBuiltinContinuation(
1941           mode, frame_info.frame_has_result_stack_slot()));
1942   if (is_topmost) {
1943     // Only the pc of the topmost frame needs to be signed since it is
1944     // authenticated at the end of the DeoptimizationEntry builtin.
1945     const intptr_t top_most_pc = PointerAuthentication::SignAndCheckPC(
1946         static_cast<intptr_t>(continue_to_builtin.InstructionStart()),
1947         frame_writer.frame()->GetTop());
1948     output_frame->SetPc(top_most_pc);
1949   } else {
1950     output_frame->SetPc(
1951         static_cast<intptr_t>(continue_to_builtin.InstructionStart()));
1952   }
1953 
1954   Code continuation =
1955       isolate()->builtins()->builtin(Builtins::kNotifyDeoptimized);
1956   output_frame->SetContinuation(
1957       static_cast<intptr_t>(continuation.InstructionStart()));
1958 }
1959 
MaterializeHeapObjects()1960 void Deoptimizer::MaterializeHeapObjects() {
1961   translated_state_.Prepare(static_cast<Address>(stack_fp_));
1962   if (FLAG_deopt_every_n_times > 0) {
1963     // Doing a GC here will find problems with the deoptimized frames.
1964     isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags,
1965                                         GarbageCollectionReason::kTesting);
1966   }
1967 
1968   for (auto& materialization : values_to_materialize_) {
1969     Handle<Object> value = materialization.value_->GetValue();
1970 
1971     if (verbose_tracing_enabled()) {
1972       PrintF(trace_scope()->file(),
1973              "Materialization [" V8PRIxPTR_FMT "] <- " V8PRIxPTR_FMT " ;  ",
1974              static_cast<intptr_t>(materialization.output_slot_address_),
1975              value->ptr());
1976       value->ShortPrint(trace_scope()->file());
1977       PrintF(trace_scope()->file(), "\n");
1978     }
1979 
1980     *(reinterpret_cast<Address*>(materialization.output_slot_address_)) =
1981         value->ptr();
1982   }
1983 
1984   translated_state_.VerifyMaterializedObjects();
1985 
1986   bool feedback_updated = translated_state_.DoUpdateFeedback();
1987   if (verbose_tracing_enabled() && feedback_updated) {
1988     FILE* file = trace_scope()->file();
1989     Deoptimizer::DeoptInfo info =
1990         Deoptimizer::GetDeoptInfo(compiled_code_, from_);
1991     PrintF(file, "Feedback updated from deoptimization at ");
1992     OFStream outstr(file);
1993     info.position.Print(outstr, compiled_code_);
1994     PrintF(file, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
1995   }
1996 
1997   isolate_->materialized_object_store()->Remove(
1998       static_cast<Address>(stack_fp_));
1999 }
2000 
QueueValueForMaterialization(Address output_address,Object obj,const TranslatedFrame::iterator & iterator)2001 void Deoptimizer::QueueValueForMaterialization(
2002     Address output_address, Object obj,
2003     const TranslatedFrame::iterator& iterator) {
2004   if (obj == ReadOnlyRoots(isolate_).arguments_marker()) {
2005     values_to_materialize_.push_back({output_address, iterator});
2006   }
2007 }
2008 
ComputeInputFrameAboveFpFixedSize() const2009 unsigned Deoptimizer::ComputeInputFrameAboveFpFixedSize() const {
2010   unsigned fixed_size = CommonFrameConstants::kFixedFrameSizeAboveFp;
2011   // TODO(jkummerow): If {function_->IsSmi()} can indeed be true, then
2012   // {function_} should not have type {JSFunction}.
2013   if (!function_.IsSmi()) {
2014     fixed_size += ComputeIncomingArgumentSize(function_.shared());
2015   }
2016   return fixed_size;
2017 }
2018 
ComputeInputFrameSize() const2019 unsigned Deoptimizer::ComputeInputFrameSize() const {
2020   // The fp-to-sp delta already takes the context, constant pool pointer and the
2021   // function into account so we have to avoid double counting them.
2022   unsigned fixed_size_above_fp = ComputeInputFrameAboveFpFixedSize();
2023   unsigned result = fixed_size_above_fp + fp_to_sp_delta_;
2024   DCHECK(CodeKindCanDeoptimize(compiled_code_.kind()));
2025   unsigned stack_slots = compiled_code_.stack_slots();
2026   unsigned outgoing_size = 0;
2027   //        ComputeOutgoingArgumentSize(compiled_code_, bailout_id_);
2028   CHECK_EQ(fixed_size_above_fp + (stack_slots * kSystemPointerSize) -
2029                CommonFrameConstants::kFixedFrameSizeAboveFp + outgoing_size,
2030            result);
2031   return result;
2032 }
2033 
2034 // static
ComputeIncomingArgumentSize(SharedFunctionInfo shared)2035 unsigned Deoptimizer::ComputeIncomingArgumentSize(SharedFunctionInfo shared) {
2036   int parameter_slots = InternalFormalParameterCountWithReceiver(shared);
2037 #ifndef V8_NO_ARGUMENTS_ADAPTOR
2038   if (ShouldPadArguments(parameter_slots)) parameter_slots++;
2039 #endif
2040   return parameter_slots * kSystemPointerSize;
2041 }
2042 
FrameDescription(uint32_t frame_size,int parameter_count)2043 FrameDescription::FrameDescription(uint32_t frame_size, int parameter_count)
2044     : frame_size_(frame_size),
2045       parameter_count_(parameter_count),
2046       top_(kZapUint32),
2047       pc_(kZapUint32),
2048       fp_(kZapUint32),
2049       context_(kZapUint32),
2050       constant_pool_(kZapUint32) {
2051   // Zap all the registers.
2052   for (int r = 0; r < Register::kNumRegisters; r++) {
2053     // TODO(jbramley): It isn't safe to use kZapUint32 here. If the register
2054     // isn't used before the next safepoint, the GC will try to scan it as a
2055     // tagged value. kZapUint32 looks like a valid tagged pointer, but it isn't.
2056 #if defined(V8_OS_WIN) && defined(V8_TARGET_ARCH_ARM64)
2057     // x18 is reserved as platform register on Windows arm64 platform
2058     const int kPlatformRegister = 18;
2059     if (r != kPlatformRegister) {
2060       SetRegister(r, kZapUint32);
2061     }
2062 #else
2063     SetRegister(r, kZapUint32);
2064 #endif
2065   }
2066 
2067   // Zap all the slots.
2068   for (unsigned o = 0; o < frame_size; o += kSystemPointerSize) {
2069     SetFrameSlot(o, kZapUint32);
2070   }
2071 }
2072 
Add(int32_t value)2073 void TranslationBuffer::Add(int32_t value) {
2074   // This wouldn't handle kMinInt correctly if it ever encountered it.
2075   DCHECK_NE(value, kMinInt);
2076   // Encode the sign bit in the least significant bit.
2077   bool is_negative = (value < 0);
2078   uint32_t bits = (static_cast<uint32_t>(is_negative ? -value : value) << 1) |
2079                   static_cast<uint32_t>(is_negative);
2080   // Encode the individual bytes using the least significant bit of
2081   // each byte to indicate whether or not more bytes follow.
2082   do {
2083     uint32_t next = bits >> 7;
2084     contents_.push_back(((bits << 1) & 0xFF) | (next != 0));
2085     bits = next;
2086   } while (bits != 0);
2087 }
2088 
TranslationIterator(ByteArray buffer,int index)2089 TranslationIterator::TranslationIterator(ByteArray buffer, int index)
2090     : buffer_(buffer), index_(index) {
2091   DCHECK(index >= 0 && index < buffer.length());
2092 }
2093 
Next()2094 int32_t TranslationIterator::Next() {
2095   // Run through the bytes until we reach one with a least significant
2096   // bit of zero (marks the end).
2097   uint32_t bits = 0;
2098   for (int i = 0; true; i += 7) {
2099     DCHECK(HasNext());
2100     uint8_t next = buffer_.get(index_++);
2101     bits |= (next >> 1) << i;
2102     if ((next & 1) == 0) break;
2103   }
2104   // The bits encode the sign in the least significant bit.
2105   bool is_negative = (bits & 1) == 1;
2106   int32_t result = bits >> 1;
2107   return is_negative ? -result : result;
2108 }
2109 
HasNext() const2110 bool TranslationIterator::HasNext() const { return index_ < buffer_.length(); }
2111 
CreateByteArray(Factory * factory)2112 Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
2113   Handle<ByteArray> result =
2114       factory->NewByteArray(CurrentIndex(), AllocationType::kOld);
2115   contents_.CopyTo(result->GetDataStartAddress());
2116   return result;
2117 }
2118 
BeginBuiltinContinuationFrame(BailoutId bailout_id,int literal_id,unsigned height)2119 void Translation::BeginBuiltinContinuationFrame(BailoutId bailout_id,
2120                                                 int literal_id,
2121                                                 unsigned height) {
2122   buffer_->Add(BUILTIN_CONTINUATION_FRAME);
2123   buffer_->Add(bailout_id.ToInt());
2124   buffer_->Add(literal_id);
2125   buffer_->Add(height);
2126 }
2127 
BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,int literal_id,unsigned height)2128 void Translation::BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,
2129                                                           int literal_id,
2130                                                           unsigned height) {
2131   buffer_->Add(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME);
2132   buffer_->Add(bailout_id.ToInt());
2133   buffer_->Add(literal_id);
2134   buffer_->Add(height);
2135 }
2136 
BeginJavaScriptBuiltinContinuationWithCatchFrame(BailoutId bailout_id,int literal_id,unsigned height)2137 void Translation::BeginJavaScriptBuiltinContinuationWithCatchFrame(
2138     BailoutId bailout_id, int literal_id, unsigned height) {
2139   buffer_->Add(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME);
2140   buffer_->Add(bailout_id.ToInt());
2141   buffer_->Add(literal_id);
2142   buffer_->Add(height);
2143 }
2144 
BeginConstructStubFrame(BailoutId bailout_id,int literal_id,unsigned height)2145 void Translation::BeginConstructStubFrame(BailoutId bailout_id, int literal_id,
2146                                           unsigned height) {
2147   buffer_->Add(CONSTRUCT_STUB_FRAME);
2148   buffer_->Add(bailout_id.ToInt());
2149   buffer_->Add(literal_id);
2150   buffer_->Add(height);
2151 }
2152 
BeginArgumentsAdaptorFrame(int literal_id,unsigned height)2153 void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
2154   buffer_->Add(ARGUMENTS_ADAPTOR_FRAME);
2155   buffer_->Add(literal_id);
2156   buffer_->Add(height);
2157 }
2158 
BeginInterpretedFrame(BailoutId bytecode_offset,int literal_id,unsigned height,int return_value_offset,int return_value_count)2159 void Translation::BeginInterpretedFrame(BailoutId bytecode_offset,
2160                                         int literal_id, unsigned height,
2161                                         int return_value_offset,
2162                                         int return_value_count) {
2163   buffer_->Add(INTERPRETED_FRAME);
2164   buffer_->Add(bytecode_offset.ToInt());
2165   buffer_->Add(literal_id);
2166   buffer_->Add(height);
2167   buffer_->Add(return_value_offset);
2168   buffer_->Add(return_value_count);
2169 }
2170 
ArgumentsElements(CreateArgumentsType type)2171 void Translation::ArgumentsElements(CreateArgumentsType type) {
2172   buffer_->Add(ARGUMENTS_ELEMENTS);
2173   buffer_->Add(static_cast<uint8_t>(type));
2174 }
2175 
ArgumentsLength()2176 void Translation::ArgumentsLength() { buffer_->Add(ARGUMENTS_LENGTH); }
2177 
BeginCapturedObject(int length)2178 void Translation::BeginCapturedObject(int length) {
2179   buffer_->Add(CAPTURED_OBJECT);
2180   buffer_->Add(length);
2181 }
2182 
DuplicateObject(int object_index)2183 void Translation::DuplicateObject(int object_index) {
2184   buffer_->Add(DUPLICATED_OBJECT);
2185   buffer_->Add(object_index);
2186 }
2187 
StoreRegister(Register reg)2188 void Translation::StoreRegister(Register reg) {
2189   buffer_->Add(REGISTER);
2190   buffer_->Add(reg.code());
2191 }
2192 
StoreInt32Register(Register reg)2193 void Translation::StoreInt32Register(Register reg) {
2194   buffer_->Add(INT32_REGISTER);
2195   buffer_->Add(reg.code());
2196 }
2197 
StoreInt64Register(Register reg)2198 void Translation::StoreInt64Register(Register reg) {
2199   buffer_->Add(INT64_REGISTER);
2200   buffer_->Add(reg.code());
2201 }
2202 
StoreUint32Register(Register reg)2203 void Translation::StoreUint32Register(Register reg) {
2204   buffer_->Add(UINT32_REGISTER);
2205   buffer_->Add(reg.code());
2206 }
2207 
StoreBoolRegister(Register reg)2208 void Translation::StoreBoolRegister(Register reg) {
2209   buffer_->Add(BOOL_REGISTER);
2210   buffer_->Add(reg.code());
2211 }
2212 
StoreFloatRegister(FloatRegister reg)2213 void Translation::StoreFloatRegister(FloatRegister reg) {
2214   buffer_->Add(FLOAT_REGISTER);
2215   buffer_->Add(reg.code());
2216 }
2217 
StoreDoubleRegister(DoubleRegister reg)2218 void Translation::StoreDoubleRegister(DoubleRegister reg) {
2219   buffer_->Add(DOUBLE_REGISTER);
2220   buffer_->Add(reg.code());
2221 }
2222 
StoreStackSlot(int index)2223 void Translation::StoreStackSlot(int index) {
2224   buffer_->Add(STACK_SLOT);
2225   buffer_->Add(index);
2226 }
2227 
StoreInt32StackSlot(int index)2228 void Translation::StoreInt32StackSlot(int index) {
2229   buffer_->Add(INT32_STACK_SLOT);
2230   buffer_->Add(index);
2231 }
2232 
StoreInt64StackSlot(int index)2233 void Translation::StoreInt64StackSlot(int index) {
2234   buffer_->Add(INT64_STACK_SLOT);
2235   buffer_->Add(index);
2236 }
2237 
StoreUint32StackSlot(int index)2238 void Translation::StoreUint32StackSlot(int index) {
2239   buffer_->Add(UINT32_STACK_SLOT);
2240   buffer_->Add(index);
2241 }
2242 
StoreBoolStackSlot(int index)2243 void Translation::StoreBoolStackSlot(int index) {
2244   buffer_->Add(BOOL_STACK_SLOT);
2245   buffer_->Add(index);
2246 }
2247 
StoreFloatStackSlot(int index)2248 void Translation::StoreFloatStackSlot(int index) {
2249   buffer_->Add(FLOAT_STACK_SLOT);
2250   buffer_->Add(index);
2251 }
2252 
StoreDoubleStackSlot(int index)2253 void Translation::StoreDoubleStackSlot(int index) {
2254   buffer_->Add(DOUBLE_STACK_SLOT);
2255   buffer_->Add(index);
2256 }
2257 
StoreLiteral(int literal_id)2258 void Translation::StoreLiteral(int literal_id) {
2259   buffer_->Add(LITERAL);
2260   buffer_->Add(literal_id);
2261 }
2262 
AddUpdateFeedback(int vector_literal,int slot)2263 void Translation::AddUpdateFeedback(int vector_literal, int slot) {
2264   buffer_->Add(UPDATE_FEEDBACK);
2265   buffer_->Add(vector_literal);
2266   buffer_->Add(slot);
2267 }
2268 
StoreJSFrameFunction()2269 void Translation::StoreJSFrameFunction() {
2270   StoreStackSlot((StandardFrameConstants::kCallerPCOffset -
2271                   StandardFrameConstants::kFunctionOffset) /
2272                  kSystemPointerSize);
2273 }
2274 
NumberOfOperandsFor(Opcode opcode)2275 int Translation::NumberOfOperandsFor(Opcode opcode) {
2276   switch (opcode) {
2277     case ARGUMENTS_LENGTH:
2278       return 0;
2279     case DUPLICATED_OBJECT:
2280     case ARGUMENTS_ELEMENTS:
2281     case CAPTURED_OBJECT:
2282     case REGISTER:
2283     case INT32_REGISTER:
2284     case INT64_REGISTER:
2285     case UINT32_REGISTER:
2286     case BOOL_REGISTER:
2287     case FLOAT_REGISTER:
2288     case DOUBLE_REGISTER:
2289     case STACK_SLOT:
2290     case INT32_STACK_SLOT:
2291     case INT64_STACK_SLOT:
2292     case UINT32_STACK_SLOT:
2293     case BOOL_STACK_SLOT:
2294     case FLOAT_STACK_SLOT:
2295     case DOUBLE_STACK_SLOT:
2296     case LITERAL:
2297       return 1;
2298     case ARGUMENTS_ADAPTOR_FRAME:
2299     case UPDATE_FEEDBACK:
2300       return 2;
2301     case BEGIN:
2302     case CONSTRUCT_STUB_FRAME:
2303     case BUILTIN_CONTINUATION_FRAME:
2304     case JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
2305     case JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME:
2306       return 3;
2307     case INTERPRETED_FRAME:
2308       return 5;
2309   }
2310   FATAL("Unexpected translation type");
2311   return -1;
2312 }
2313 
2314 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
2315 
StringFor(Opcode opcode)2316 const char* Translation::StringFor(Opcode opcode) {
2317 #define TRANSLATION_OPCODE_CASE(item) \
2318   case item:                          \
2319     return #item;
2320   switch (opcode) { TRANSLATION_OPCODE_LIST(TRANSLATION_OPCODE_CASE) }
2321 #undef TRANSLATION_OPCODE_CASE
2322   UNREACHABLE();
2323 }
2324 
2325 #endif
2326 
Get(Address fp)2327 Handle<FixedArray> MaterializedObjectStore::Get(Address fp) {
2328   int index = StackIdToIndex(fp);
2329   if (index == -1) {
2330     return Handle<FixedArray>::null();
2331   }
2332   Handle<FixedArray> array = GetStackEntries();
2333   CHECK_GT(array->length(), index);
2334   return Handle<FixedArray>::cast(Handle<Object>(array->get(index), isolate()));
2335 }
2336 
Set(Address fp,Handle<FixedArray> materialized_objects)2337 void MaterializedObjectStore::Set(Address fp,
2338                                   Handle<FixedArray> materialized_objects) {
2339   int index = StackIdToIndex(fp);
2340   if (index == -1) {
2341     index = static_cast<int>(frame_fps_.size());
2342     frame_fps_.push_back(fp);
2343   }
2344 
2345   Handle<FixedArray> array = EnsureStackEntries(index + 1);
2346   array->set(index, *materialized_objects);
2347 }
2348 
Remove(Address fp)2349 bool MaterializedObjectStore::Remove(Address fp) {
2350   auto it = std::find(frame_fps_.begin(), frame_fps_.end(), fp);
2351   if (it == frame_fps_.end()) return false;
2352   int index = static_cast<int>(std::distance(frame_fps_.begin(), it));
2353 
2354   frame_fps_.erase(it);
2355   FixedArray array = isolate()->heap()->materialized_objects();
2356 
2357   CHECK_LT(index, array.length());
2358   int fps_size = static_cast<int>(frame_fps_.size());
2359   for (int i = index; i < fps_size; i++) {
2360     array.set(i, array.get(i + 1));
2361   }
2362   array.set(fps_size, ReadOnlyRoots(isolate()).undefined_value());
2363   return true;
2364 }
2365 
StackIdToIndex(Address fp)2366 int MaterializedObjectStore::StackIdToIndex(Address fp) {
2367   auto it = std::find(frame_fps_.begin(), frame_fps_.end(), fp);
2368   return it == frame_fps_.end()
2369              ? -1
2370              : static_cast<int>(std::distance(frame_fps_.begin(), it));
2371 }
2372 
GetStackEntries()2373 Handle<FixedArray> MaterializedObjectStore::GetStackEntries() {
2374   return Handle<FixedArray>(isolate()->heap()->materialized_objects(),
2375                             isolate());
2376 }
2377 
EnsureStackEntries(int length)2378 Handle<FixedArray> MaterializedObjectStore::EnsureStackEntries(int length) {
2379   Handle<FixedArray> array = GetStackEntries();
2380   if (array->length() >= length) {
2381     return array;
2382   }
2383 
2384   int new_length = length > 10 ? length : 10;
2385   if (new_length < 2 * array->length()) {
2386     new_length = 2 * array->length();
2387   }
2388 
2389   Handle<FixedArray> new_array =
2390       isolate()->factory()->NewFixedArray(new_length, AllocationType::kOld);
2391   for (int i = 0; i < array->length(); i++) {
2392     new_array->set(i, array->get(i));
2393   }
2394   HeapObject undefined_value = ReadOnlyRoots(isolate()).undefined_value();
2395   for (int i = array->length(); i < length; i++) {
2396     new_array->set(i, undefined_value);
2397   }
2398   isolate()->heap()->SetRootMaterializedObjects(*new_array);
2399   return new_array;
2400 }
2401 
2402 namespace {
2403 
GetValueForDebugger(TranslatedFrame::iterator it,Isolate * isolate)2404 Handle<Object> GetValueForDebugger(TranslatedFrame::iterator it,
2405                                    Isolate* isolate) {
2406   if (it->GetRawValue() == ReadOnlyRoots(isolate).arguments_marker()) {
2407     if (!it->IsMaterializableByDebugger()) {
2408       return isolate->factory()->optimized_out();
2409     }
2410   }
2411   return it->GetValue();
2412 }
2413 
2414 }  // namespace
2415 
DeoptimizedFrameInfo(TranslatedState * state,TranslatedState::iterator frame_it,Isolate * isolate)2416 DeoptimizedFrameInfo::DeoptimizedFrameInfo(TranslatedState* state,
2417                                            TranslatedState::iterator frame_it,
2418                                            Isolate* isolate) {
2419   int parameter_count =
2420       frame_it->shared_info()->internal_formal_parameter_count();
2421   TranslatedFrame::iterator stack_it = frame_it->begin();
2422 
2423   // Get the function. Note that this might materialize the function.
2424   // In case the debugger mutates this value, we should deoptimize
2425   // the function and remember the value in the materialized value store.
2426   function_ = Handle<JSFunction>::cast(stack_it->GetValue());
2427   stack_it++;  // Skip the function.
2428   stack_it++;  // Skip the receiver.
2429 
2430   DCHECK_EQ(TranslatedFrame::kInterpretedFunction, frame_it->kind());
2431   source_position_ = Deoptimizer::ComputeSourcePositionFromBytecodeArray(
2432       *frame_it->shared_info(), frame_it->node_id());
2433 
2434   DCHECK_EQ(parameter_count,
2435             function_->shared().internal_formal_parameter_count());
2436 
2437   parameters_.resize(static_cast<size_t>(parameter_count));
2438   for (int i = 0; i < parameter_count; i++) {
2439     Handle<Object> parameter = GetValueForDebugger(stack_it, isolate);
2440     SetParameter(i, parameter);
2441     stack_it++;
2442   }
2443 
2444   // Get the context.
2445   context_ = GetValueForDebugger(stack_it, isolate);
2446   stack_it++;
2447 
2448   // Get the expression stack.
2449   DCHECK_EQ(TranslatedFrame::kInterpretedFunction, frame_it->kind());
2450   const int stack_height = frame_it->height();  // Accumulator *not* included.
2451 
2452   expression_stack_.resize(static_cast<size_t>(stack_height));
2453   for (int i = 0; i < stack_height; i++) {
2454     Handle<Object> expression = GetValueForDebugger(stack_it, isolate);
2455     SetExpression(i, expression);
2456     stack_it++;
2457   }
2458 
2459   DCHECK_EQ(TranslatedFrame::kInterpretedFunction, frame_it->kind());
2460   stack_it++;  // Skip the accumulator.
2461 
2462   CHECK(stack_it == frame_it->end());
2463 }
2464 
GetDeoptInfo(Code code,Address pc)2465 Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code code, Address pc) {
2466   CHECK(code.InstructionStart() <= pc && pc <= code.InstructionEnd());
2467   SourcePosition last_position = SourcePosition::Unknown();
2468   DeoptimizeReason last_reason = DeoptimizeReason::kUnknown;
2469   int last_deopt_id = kNoDeoptimizationId;
2470   int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_REASON) |
2471              RelocInfo::ModeMask(RelocInfo::DEOPT_ID) |
2472              RelocInfo::ModeMask(RelocInfo::DEOPT_SCRIPT_OFFSET) |
2473              RelocInfo::ModeMask(RelocInfo::DEOPT_INLINING_ID);
2474   for (RelocIterator it(code, mask); !it.done(); it.next()) {
2475     RelocInfo* info = it.rinfo();
2476     if (info->pc() >= pc) break;
2477     if (info->rmode() == RelocInfo::DEOPT_SCRIPT_OFFSET) {
2478       int script_offset = static_cast<int>(info->data());
2479       it.next();
2480       DCHECK(it.rinfo()->rmode() == RelocInfo::DEOPT_INLINING_ID);
2481       int inlining_id = static_cast<int>(it.rinfo()->data());
2482       last_position = SourcePosition(script_offset, inlining_id);
2483     } else if (info->rmode() == RelocInfo::DEOPT_ID) {
2484       last_deopt_id = static_cast<int>(info->data());
2485     } else if (info->rmode() == RelocInfo::DEOPT_REASON) {
2486       last_reason = static_cast<DeoptimizeReason>(info->data());
2487     }
2488   }
2489   return DeoptInfo(last_position, last_reason, last_deopt_id);
2490 }
2491 
2492 // static
ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo shared,BailoutId node_id)2493 int Deoptimizer::ComputeSourcePositionFromBytecodeArray(
2494     SharedFunctionInfo shared, BailoutId node_id) {
2495   DCHECK(shared.HasBytecodeArray());
2496   return AbstractCode::cast(shared.GetBytecodeArray())
2497       .SourcePosition(node_id.ToInt());
2498 }
2499 
2500 // static
NewDeferredObject(TranslatedState * container,int length,int object_index)2501 TranslatedValue TranslatedValue::NewDeferredObject(TranslatedState* container,
2502                                                    int length,
2503                                                    int object_index) {
2504   TranslatedValue slot(container, kCapturedObject);
2505   slot.materialization_info_ = {object_index, length};
2506   return slot;
2507 }
2508 
2509 // static
NewDuplicateObject(TranslatedState * container,int id)2510 TranslatedValue TranslatedValue::NewDuplicateObject(TranslatedState* container,
2511                                                     int id) {
2512   TranslatedValue slot(container, kDuplicatedObject);
2513   slot.materialization_info_ = {id, -1};
2514   return slot;
2515 }
2516 
2517 // static
NewFloat(TranslatedState * container,Float32 value)2518 TranslatedValue TranslatedValue::NewFloat(TranslatedState* container,
2519                                           Float32 value) {
2520   TranslatedValue slot(container, kFloat);
2521   slot.float_value_ = value;
2522   return slot;
2523 }
2524 
2525 // static
NewDouble(TranslatedState * container,Float64 value)2526 TranslatedValue TranslatedValue::NewDouble(TranslatedState* container,
2527                                            Float64 value) {
2528   TranslatedValue slot(container, kDouble);
2529   slot.double_value_ = value;
2530   return slot;
2531 }
2532 
2533 // static
NewInt32(TranslatedState * container,int32_t value)2534 TranslatedValue TranslatedValue::NewInt32(TranslatedState* container,
2535                                           int32_t value) {
2536   TranslatedValue slot(container, kInt32);
2537   slot.int32_value_ = value;
2538   return slot;
2539 }
2540 
2541 // static
NewInt64(TranslatedState * container,int64_t value)2542 TranslatedValue TranslatedValue::NewInt64(TranslatedState* container,
2543                                           int64_t value) {
2544   TranslatedValue slot(container, kInt64);
2545   slot.int64_value_ = value;
2546   return slot;
2547 }
2548 
2549 // static
NewUInt32(TranslatedState * container,uint32_t value)2550 TranslatedValue TranslatedValue::NewUInt32(TranslatedState* container,
2551                                            uint32_t value) {
2552   TranslatedValue slot(container, kUInt32);
2553   slot.uint32_value_ = value;
2554   return slot;
2555 }
2556 
2557 // static
NewBool(TranslatedState * container,uint32_t value)2558 TranslatedValue TranslatedValue::NewBool(TranslatedState* container,
2559                                          uint32_t value) {
2560   TranslatedValue slot(container, kBoolBit);
2561   slot.uint32_value_ = value;
2562   return slot;
2563 }
2564 
2565 // static
NewTagged(TranslatedState * container,Object literal)2566 TranslatedValue TranslatedValue::NewTagged(TranslatedState* container,
2567                                            Object literal) {
2568   TranslatedValue slot(container, kTagged);
2569   slot.raw_literal_ = literal;
2570   return slot;
2571 }
2572 
2573 // static
NewInvalid(TranslatedState * container)2574 TranslatedValue TranslatedValue::NewInvalid(TranslatedState* container) {
2575   return TranslatedValue(container, kInvalid);
2576 }
2577 
isolate() const2578 Isolate* TranslatedValue::isolate() const { return container_->isolate(); }
2579 
raw_literal() const2580 Object TranslatedValue::raw_literal() const {
2581   DCHECK_EQ(kTagged, kind());
2582   return raw_literal_;
2583 }
2584 
int32_value() const2585 int32_t TranslatedValue::int32_value() const {
2586   DCHECK_EQ(kInt32, kind());
2587   return int32_value_;
2588 }
2589 
int64_value() const2590 int64_t TranslatedValue::int64_value() const {
2591   DCHECK_EQ(kInt64, kind());
2592   return int64_value_;
2593 }
2594 
uint32_value() const2595 uint32_t TranslatedValue::uint32_value() const {
2596   DCHECK(kind() == kUInt32 || kind() == kBoolBit);
2597   return uint32_value_;
2598 }
2599 
float_value() const2600 Float32 TranslatedValue::float_value() const {
2601   DCHECK_EQ(kFloat, kind());
2602   return float_value_;
2603 }
2604 
double_value() const2605 Float64 TranslatedValue::double_value() const {
2606   DCHECK_EQ(kDouble, kind());
2607   return double_value_;
2608 }
2609 
object_length() const2610 int TranslatedValue::object_length() const {
2611   DCHECK_EQ(kind(), kCapturedObject);
2612   return materialization_info_.length_;
2613 }
2614 
object_index() const2615 int TranslatedValue::object_index() const {
2616   DCHECK(kind() == kCapturedObject || kind() == kDuplicatedObject);
2617   return materialization_info_.id_;
2618 }
2619 
GetRawValue() const2620 Object TranslatedValue::GetRawValue() const {
2621   // If we have a value, return it.
2622   if (materialization_state() == kFinished) {
2623     int smi;
2624     if (storage_->IsHeapNumber() &&
2625         DoubleToSmiInteger(storage_->Number(), &smi)) {
2626       return Smi::FromInt(smi);
2627     }
2628     return *storage_;
2629   }
2630 
2631   // Otherwise, do a best effort to get the value without allocation.
2632   switch (kind()) {
2633     case kTagged:
2634       return raw_literal();
2635 
2636     case kInt32: {
2637       bool is_smi = Smi::IsValid(int32_value());
2638       if (is_smi) {
2639         return Smi::FromInt(int32_value());
2640       }
2641       break;
2642     }
2643 
2644     case kInt64: {
2645       bool is_smi = (int64_value() >= static_cast<int64_t>(Smi::kMinValue) &&
2646                      int64_value() <= static_cast<int64_t>(Smi::kMaxValue));
2647       if (is_smi) {
2648         return Smi::FromIntptr(static_cast<intptr_t>(int64_value()));
2649       }
2650       break;
2651     }
2652 
2653     case kUInt32: {
2654       bool is_smi = (uint32_value() <= static_cast<uintptr_t>(Smi::kMaxValue));
2655       if (is_smi) {
2656         return Smi::FromInt(static_cast<int32_t>(uint32_value()));
2657       }
2658       break;
2659     }
2660 
2661     case kBoolBit: {
2662       if (uint32_value() == 0) {
2663         return ReadOnlyRoots(isolate()).false_value();
2664       } else {
2665         CHECK_EQ(1U, uint32_value());
2666         return ReadOnlyRoots(isolate()).true_value();
2667       }
2668     }
2669 
2670     case kFloat: {
2671       int smi;
2672       if (DoubleToSmiInteger(float_value().get_scalar(), &smi)) {
2673         return Smi::FromInt(smi);
2674       }
2675       break;
2676     }
2677 
2678     case kDouble: {
2679       int smi;
2680       if (DoubleToSmiInteger(double_value().get_scalar(), &smi)) {
2681         return Smi::FromInt(smi);
2682       }
2683       break;
2684     }
2685 
2686     default:
2687       break;
2688   }
2689 
2690   // If we could not get the value without allocation, return the arguments
2691   // marker.
2692   return ReadOnlyRoots(isolate()).arguments_marker();
2693 }
2694 
set_initialized_storage(Handle<HeapObject> storage)2695 void TranslatedValue::set_initialized_storage(Handle<HeapObject> storage) {
2696   DCHECK_EQ(kUninitialized, materialization_state());
2697   storage_ = storage;
2698   materialization_state_ = kFinished;
2699 }
2700 
GetValue()2701 Handle<Object> TranslatedValue::GetValue() {
2702   Handle<Object> value(GetRawValue(), isolate());
2703   if (materialization_state() == kFinished) return value;
2704 
2705   if (value->IsSmi()) {
2706     // Even though stored as a Smi, this number might instead be needed as a
2707     // HeapNumber when materializing a JSObject with a field of HeapObject
2708     // representation. Since we don't have this information available here, we
2709     // just always allocate a HeapNumber and later extract the Smi again if we
2710     // don't need a HeapObject.
2711     set_initialized_storage(
2712         isolate()->factory()->NewHeapNumber(value->Number()));
2713     return value;
2714   }
2715 
2716   if (*value != ReadOnlyRoots(isolate()).arguments_marker()) {
2717     set_initialized_storage(Handle<HeapObject>::cast(value));
2718     return storage_;
2719   }
2720 
2721   // Otherwise we have to materialize.
2722 
2723   if (kind() == TranslatedValue::kCapturedObject ||
2724       kind() == TranslatedValue::kDuplicatedObject) {
2725     // We need to materialize the object (or possibly even object graphs).
2726     // To make the object verifier happy, we materialize in two steps.
2727 
2728     // 1. Allocate storage for reachable objects. This makes sure that for
2729     //    each object we have allocated space on heap. The space will be
2730     //    a byte array that will be later initialized, or a fully
2731     //    initialized object if it is safe to allocate one that will
2732     //    pass the verifier.
2733     container_->EnsureObjectAllocatedAt(this);
2734 
2735     // 2. Initialize the objects. If we have allocated only byte arrays
2736     //    for some objects, we now overwrite the byte arrays with the
2737     //    correct object fields. Note that this phase does not allocate
2738     //    any new objects, so it does not trigger the object verifier.
2739     return container_->InitializeObjectAt(this);
2740   }
2741 
2742   double number;
2743   switch (kind()) {
2744     case TranslatedValue::kInt32:
2745       number = int32_value();
2746       break;
2747     case TranslatedValue::kInt64:
2748       number = int64_value();
2749       break;
2750     case TranslatedValue::kUInt32:
2751       number = uint32_value();
2752       break;
2753     case TranslatedValue::kFloat:
2754       number = float_value().get_scalar();
2755       break;
2756     case TranslatedValue::kDouble:
2757       number = double_value().get_scalar();
2758       break;
2759     default:
2760       UNREACHABLE();
2761   }
2762   DCHECK(!IsSmiDouble(number));
2763   set_initialized_storage(isolate()->factory()->NewHeapNumber(number));
2764   return storage_;
2765 }
2766 
IsMaterializedObject() const2767 bool TranslatedValue::IsMaterializedObject() const {
2768   switch (kind()) {
2769     case kCapturedObject:
2770     case kDuplicatedObject:
2771       return true;
2772     default:
2773       return false;
2774   }
2775 }
2776 
IsMaterializableByDebugger() const2777 bool TranslatedValue::IsMaterializableByDebugger() const {
2778   // At the moment, we only allow materialization of doubles.
2779   return (kind() == kDouble);
2780 }
2781 
GetChildrenCount() const2782 int TranslatedValue::GetChildrenCount() const {
2783   if (kind() == kCapturedObject) {
2784     return object_length();
2785   } else {
2786     return 0;
2787   }
2788 }
2789 
GetUInt64Slot(Address fp,int slot_offset)2790 uint64_t TranslatedState::GetUInt64Slot(Address fp, int slot_offset) {
2791 #if V8_TARGET_ARCH_32_BIT
2792   return ReadUnalignedValue<uint64_t>(fp + slot_offset);
2793 #else
2794   return Memory<uint64_t>(fp + slot_offset);
2795 #endif
2796 }
2797 
GetUInt32Slot(Address fp,int slot_offset)2798 uint32_t TranslatedState::GetUInt32Slot(Address fp, int slot_offset) {
2799   Address address = fp + slot_offset;
2800 #if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT
2801   return Memory<uint32_t>(address + kIntSize);
2802 #else
2803   return Memory<uint32_t>(address);
2804 #endif
2805 }
2806 
GetFloatSlot(Address fp,int slot_offset)2807 Float32 TranslatedState::GetFloatSlot(Address fp, int slot_offset) {
2808 #if !V8_TARGET_ARCH_S390X && !V8_TARGET_ARCH_PPC64
2809   return Float32::FromBits(GetUInt32Slot(fp, slot_offset));
2810 #else
2811   return Float32::FromBits(Memory<uint32_t>(fp + slot_offset));
2812 #endif
2813 }
2814 
GetDoubleSlot(Address fp,int slot_offset)2815 Float64 TranslatedState::GetDoubleSlot(Address fp, int slot_offset) {
2816   return Float64::FromBits(GetUInt64Slot(fp, slot_offset));
2817 }
2818 
Handlify()2819 void TranslatedValue::Handlify() {
2820   if (kind() == kTagged && raw_literal().IsHeapObject()) {
2821     set_initialized_storage(
2822         Handle<HeapObject>(HeapObject::cast(raw_literal()), isolate()));
2823     raw_literal_ = Object();
2824   }
2825 }
2826 
InterpretedFrame(BailoutId bytecode_offset,SharedFunctionInfo shared_info,int height,int return_value_offset,int return_value_count)2827 TranslatedFrame TranslatedFrame::InterpretedFrame(
2828     BailoutId bytecode_offset, SharedFunctionInfo shared_info, int height,
2829     int return_value_offset, int return_value_count) {
2830   TranslatedFrame frame(kInterpretedFunction, shared_info, height,
2831                         return_value_offset, return_value_count);
2832   frame.node_id_ = bytecode_offset;
2833   return frame;
2834 }
2835 
ArgumentsAdaptorFrame(SharedFunctionInfo shared_info,int height)2836 TranslatedFrame TranslatedFrame::ArgumentsAdaptorFrame(
2837     SharedFunctionInfo shared_info, int height) {
2838   return TranslatedFrame(kArgumentsAdaptor, shared_info, height);
2839 }
2840 
ConstructStubFrame(BailoutId bailout_id,SharedFunctionInfo shared_info,int height)2841 TranslatedFrame TranslatedFrame::ConstructStubFrame(
2842     BailoutId bailout_id, SharedFunctionInfo shared_info, int height) {
2843   TranslatedFrame frame(kConstructStub, shared_info, height);
2844   frame.node_id_ = bailout_id;
2845   return frame;
2846 }
2847 
BuiltinContinuationFrame(BailoutId bailout_id,SharedFunctionInfo shared_info,int height)2848 TranslatedFrame TranslatedFrame::BuiltinContinuationFrame(
2849     BailoutId bailout_id, SharedFunctionInfo shared_info, int height) {
2850   TranslatedFrame frame(kBuiltinContinuation, shared_info, height);
2851   frame.node_id_ = bailout_id;
2852   return frame;
2853 }
2854 
JavaScriptBuiltinContinuationFrame(BailoutId bailout_id,SharedFunctionInfo shared_info,int height)2855 TranslatedFrame TranslatedFrame::JavaScriptBuiltinContinuationFrame(
2856     BailoutId bailout_id, SharedFunctionInfo shared_info, int height) {
2857   TranslatedFrame frame(kJavaScriptBuiltinContinuation, shared_info, height);
2858   frame.node_id_ = bailout_id;
2859   return frame;
2860 }
2861 
JavaScriptBuiltinContinuationWithCatchFrame(BailoutId bailout_id,SharedFunctionInfo shared_info,int height)2862 TranslatedFrame TranslatedFrame::JavaScriptBuiltinContinuationWithCatchFrame(
2863     BailoutId bailout_id, SharedFunctionInfo shared_info, int height) {
2864   TranslatedFrame frame(kJavaScriptBuiltinContinuationWithCatch, shared_info,
2865                         height);
2866   frame.node_id_ = bailout_id;
2867   return frame;
2868 }
2869 
GetValueCount()2870 int TranslatedFrame::GetValueCount() {
2871   // The function is added to all frame state descriptors in
2872   // InstructionSelector::AddInputsToFrameStateDescriptor.
2873   static constexpr int kTheFunction = 1;
2874 
2875   switch (kind()) {
2876     case kInterpretedFunction: {
2877       int parameter_count =
2878           InternalFormalParameterCountWithReceiver(raw_shared_info_);
2879       static constexpr int kTheContext = 1;
2880       static constexpr int kTheAccumulator = 1;
2881       return height() + parameter_count + kTheContext + kTheFunction +
2882              kTheAccumulator;
2883     }
2884 
2885     case kArgumentsAdaptor:
2886       return height() + kTheFunction;
2887 
2888     case kConstructStub:
2889     case kBuiltinContinuation:
2890     case kJavaScriptBuiltinContinuation:
2891     case kJavaScriptBuiltinContinuationWithCatch: {
2892       static constexpr int kTheContext = 1;
2893       return height() + kTheContext + kTheFunction;
2894     }
2895 
2896     case kInvalid:
2897       UNREACHABLE();
2898   }
2899   UNREACHABLE();
2900 }
2901 
Handlify()2902 void TranslatedFrame::Handlify() {
2903   if (!raw_shared_info_.is_null()) {
2904     shared_info_ = Handle<SharedFunctionInfo>(raw_shared_info_,
2905                                               raw_shared_info_.GetIsolate());
2906     raw_shared_info_ = SharedFunctionInfo();
2907   }
2908   for (auto& value : values_) {
2909     value.Handlify();
2910   }
2911 }
2912 
CreateNextTranslatedFrame(TranslationIterator * iterator,FixedArray literal_array,Address fp,FILE * trace_file)2913 TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
2914     TranslationIterator* iterator, FixedArray literal_array, Address fp,
2915     FILE* trace_file) {
2916   Translation::Opcode opcode =
2917       static_cast<Translation::Opcode>(iterator->Next());
2918   switch (opcode) {
2919     case Translation::INTERPRETED_FRAME: {
2920       BailoutId bytecode_offset = BailoutId(iterator->Next());
2921       SharedFunctionInfo shared_info =
2922           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
2923       int height = iterator->Next();
2924       int return_value_offset = iterator->Next();
2925       int return_value_count = iterator->Next();
2926       if (trace_file != nullptr) {
2927         std::unique_ptr<char[]> name = shared_info.DebugName().ToCString();
2928         PrintF(trace_file, "  reading input frame %s", name.get());
2929         int arg_count = InternalFormalParameterCountWithReceiver(shared_info);
2930         PrintF(trace_file,
2931                " => bytecode_offset=%d, args=%d, height=%d, retval=%i(#%i); "
2932                "inputs:\n",
2933                bytecode_offset.ToInt(), arg_count, height, return_value_offset,
2934                return_value_count);
2935       }
2936       return TranslatedFrame::InterpretedFrame(bytecode_offset, shared_info,
2937                                                height, return_value_offset,
2938                                                return_value_count);
2939     }
2940 
2941     case Translation::ARGUMENTS_ADAPTOR_FRAME: {
2942       SharedFunctionInfo shared_info =
2943           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
2944       int height = iterator->Next();
2945       if (trace_file != nullptr) {
2946         std::unique_ptr<char[]> name = shared_info.DebugName().ToCString();
2947         PrintF(trace_file, "  reading arguments adaptor frame %s", name.get());
2948         PrintF(trace_file, " => height=%d; inputs:\n", height);
2949       }
2950       return TranslatedFrame::ArgumentsAdaptorFrame(shared_info, height);
2951     }
2952 
2953     case Translation::CONSTRUCT_STUB_FRAME: {
2954       BailoutId bailout_id = BailoutId(iterator->Next());
2955       SharedFunctionInfo shared_info =
2956           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
2957       int height = iterator->Next();
2958       if (trace_file != nullptr) {
2959         std::unique_ptr<char[]> name = shared_info.DebugName().ToCString();
2960         PrintF(trace_file, "  reading construct stub frame %s", name.get());
2961         PrintF(trace_file, " => bailout_id=%d, height=%d; inputs:\n",
2962                bailout_id.ToInt(), height);
2963       }
2964       return TranslatedFrame::ConstructStubFrame(bailout_id, shared_info,
2965                                                  height);
2966     }
2967 
2968     case Translation::BUILTIN_CONTINUATION_FRAME: {
2969       BailoutId bailout_id = BailoutId(iterator->Next());
2970       SharedFunctionInfo shared_info =
2971           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
2972       int height = iterator->Next();
2973       if (trace_file != nullptr) {
2974         std::unique_ptr<char[]> name = shared_info.DebugName().ToCString();
2975         PrintF(trace_file, "  reading builtin continuation frame %s",
2976                name.get());
2977         PrintF(trace_file, " => bailout_id=%d, height=%d; inputs:\n",
2978                bailout_id.ToInt(), height);
2979       }
2980       return TranslatedFrame::BuiltinContinuationFrame(bailout_id, shared_info,
2981                                                        height);
2982     }
2983 
2984     case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME: {
2985       BailoutId bailout_id = BailoutId(iterator->Next());
2986       SharedFunctionInfo shared_info =
2987           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
2988       int height = iterator->Next();
2989       if (trace_file != nullptr) {
2990         std::unique_ptr<char[]> name = shared_info.DebugName().ToCString();
2991         PrintF(trace_file, "  reading JavaScript builtin continuation frame %s",
2992                name.get());
2993         PrintF(trace_file, " => bailout_id=%d, height=%d; inputs:\n",
2994                bailout_id.ToInt(), height);
2995       }
2996       return TranslatedFrame::JavaScriptBuiltinContinuationFrame(
2997           bailout_id, shared_info, height);
2998     }
2999     case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
3000       BailoutId bailout_id = BailoutId(iterator->Next());
3001       SharedFunctionInfo shared_info =
3002           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
3003       int height = iterator->Next();
3004       if (trace_file != nullptr) {
3005         std::unique_ptr<char[]> name = shared_info.DebugName().ToCString();
3006         PrintF(trace_file,
3007                "  reading JavaScript builtin continuation frame with catch %s",
3008                name.get());
3009         PrintF(trace_file, " => bailout_id=%d, height=%d; inputs:\n",
3010                bailout_id.ToInt(), height);
3011       }
3012       return TranslatedFrame::JavaScriptBuiltinContinuationWithCatchFrame(
3013           bailout_id, shared_info, height);
3014     }
3015     case Translation::UPDATE_FEEDBACK:
3016     case Translation::BEGIN:
3017     case Translation::DUPLICATED_OBJECT:
3018     case Translation::ARGUMENTS_ELEMENTS:
3019     case Translation::ARGUMENTS_LENGTH:
3020     case Translation::CAPTURED_OBJECT:
3021     case Translation::REGISTER:
3022     case Translation::INT32_REGISTER:
3023     case Translation::INT64_REGISTER:
3024     case Translation::UINT32_REGISTER:
3025     case Translation::BOOL_REGISTER:
3026     case Translation::FLOAT_REGISTER:
3027     case Translation::DOUBLE_REGISTER:
3028     case Translation::STACK_SLOT:
3029     case Translation::INT32_STACK_SLOT:
3030     case Translation::INT64_STACK_SLOT:
3031     case Translation::UINT32_STACK_SLOT:
3032     case Translation::BOOL_STACK_SLOT:
3033     case Translation::FLOAT_STACK_SLOT:
3034     case Translation::DOUBLE_STACK_SLOT:
3035     case Translation::LITERAL:
3036       break;
3037   }
3038   FATAL("We should never get here - unexpected deopt info.");
3039   return TranslatedFrame::InvalidFrame();
3040 }
3041 
3042 // static
AdvanceIterator(std::deque<TranslatedValue>::iterator * iter)3043 void TranslatedFrame::AdvanceIterator(
3044     std::deque<TranslatedValue>::iterator* iter) {
3045   int values_to_skip = 1;
3046   while (values_to_skip > 0) {
3047     // Consume the current element.
3048     values_to_skip--;
3049     // Add all the children.
3050     values_to_skip += (*iter)->GetChildrenCount();
3051 
3052     (*iter)++;
3053   }
3054 }
3055 
ComputeArgumentsPosition(Address input_frame_pointer,int * length)3056 Address TranslatedState::ComputeArgumentsPosition(Address input_frame_pointer,
3057                                                   int* length) {
3058   Address parent_frame_pointer = *reinterpret_cast<Address*>(
3059       input_frame_pointer + StandardFrameConstants::kCallerFPOffset);
3060   intptr_t parent_frame_type = Memory<intptr_t>(
3061       parent_frame_pointer + CommonFrameConstants::kContextOrFrameTypeOffset);
3062 
3063   Address arguments_frame;
3064   if (parent_frame_type ==
3065       StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)) {
3066     if (length)
3067       *length = Smi::cast(*FullObjectSlot(
3068                               parent_frame_pointer +
3069                               ArgumentsAdaptorFrameConstants::kLengthOffset))
3070                     .value();
3071     arguments_frame = parent_frame_pointer;
3072   } else {
3073     if (length) *length = formal_parameter_count_;
3074     arguments_frame = input_frame_pointer;
3075   }
3076 
3077   return arguments_frame;
3078 }
3079 
3080 // Creates translated values for an arguments backing store, or the backing
3081 // store for rest parameters depending on the given {type}. The TranslatedValue
3082 // objects for the fields are not read from the TranslationIterator, but instead
3083 // created on-the-fly based on dynamic information in the optimized frame.
CreateArgumentsElementsTranslatedValues(int frame_index,Address input_frame_pointer,CreateArgumentsType type,FILE * trace_file)3084 void TranslatedState::CreateArgumentsElementsTranslatedValues(
3085     int frame_index, Address input_frame_pointer, CreateArgumentsType type,
3086     FILE* trace_file) {
3087   TranslatedFrame& frame = frames_[frame_index];
3088 
3089 #ifdef V8_NO_ARGUMENTS_ADAPTOR
3090   int arguments_length = actual_argument_count_;
3091 #else
3092   int arguments_length;
3093   Address arguments_frame =
3094       ComputeArgumentsPosition(input_frame_pointer, &arguments_length);
3095 #endif
3096 
3097   int length = type == CreateArgumentsType::kRestParameter
3098                    ? std::max(0, arguments_length - formal_parameter_count_)
3099                    : arguments_length;
3100 
3101   int object_index = static_cast<int>(object_positions_.size());
3102   int value_index = static_cast<int>(frame.values_.size());
3103   if (trace_file != nullptr) {
3104     PrintF(trace_file, "arguments elements object #%d (type = %d, length = %d)",
3105            object_index, static_cast<uint8_t>(type), length);
3106   }
3107 
3108   object_positions_.push_back({frame_index, value_index});
3109   frame.Add(TranslatedValue::NewDeferredObject(
3110       this, length + FixedArray::kHeaderSize / kTaggedSize, object_index));
3111 
3112   ReadOnlyRoots roots(isolate_);
3113   frame.Add(TranslatedValue::NewTagged(this, roots.fixed_array_map()));
3114   frame.Add(TranslatedValue::NewInt32(this, length));
3115 
3116   int number_of_holes = 0;
3117   if (type == CreateArgumentsType::kMappedArguments) {
3118     // If the actual number of arguments is less than the number of formal
3119     // parameters, we have fewer holes to fill to not overshoot the length.
3120     number_of_holes = std::min(formal_parameter_count_, length);
3121   }
3122   for (int i = 0; i < number_of_holes; ++i) {
3123     frame.Add(TranslatedValue::NewTagged(this, roots.the_hole_value()));
3124   }
3125   int argc = length - number_of_holes;
3126   int start_index = number_of_holes;
3127   if (type == CreateArgumentsType::kRestParameter) {
3128     start_index = std::max(0, formal_parameter_count_);
3129   }
3130   for (int i = 0; i < argc; i++) {
3131     // Skip the receiver.
3132     int offset = i + start_index + 1;
3133 #ifdef V8_NO_ARGUMENTS_ADAPTOR
3134     Address arguments_frame = offset > formal_parameter_count_
3135                                   ? stack_frame_pointer_
3136                                   : input_frame_pointer;
3137 #endif
3138     Address argument_slot = arguments_frame +
3139                             CommonFrameConstants::kFixedFrameSizeAboveFp +
3140                             offset * kSystemPointerSize;
3141 
3142     frame.Add(TranslatedValue::NewTagged(this, *FullObjectSlot(argument_slot)));
3143   }
3144 }
3145 
3146 // We can't intermix stack decoding and allocations because the deoptimization
3147 // infrastracture is not GC safe.
3148 // Thus we build a temporary structure in malloced space.
3149 // The TranslatedValue objects created correspond to the static translation
3150 // instructions from the TranslationIterator, except for
3151 // Translation::ARGUMENTS_ELEMENTS, where the number and values of the
3152 // FixedArray elements depend on dynamic information from the optimized frame.
3153 // Returns the number of expected nested translations from the
3154 // TranslationIterator.
CreateNextTranslatedValue(int frame_index,TranslationIterator * iterator,FixedArray literal_array,Address fp,RegisterValues * registers,FILE * trace_file)3155 int TranslatedState::CreateNextTranslatedValue(
3156     int frame_index, TranslationIterator* iterator, FixedArray literal_array,
3157     Address fp, RegisterValues* registers, FILE* trace_file) {
3158   disasm::NameConverter converter;
3159 
3160   TranslatedFrame& frame = frames_[frame_index];
3161   int value_index = static_cast<int>(frame.values_.size());
3162 
3163   Translation::Opcode opcode =
3164       static_cast<Translation::Opcode>(iterator->Next());
3165   switch (opcode) {
3166     case Translation::BEGIN:
3167     case Translation::INTERPRETED_FRAME:
3168     case Translation::ARGUMENTS_ADAPTOR_FRAME:
3169     case Translation::CONSTRUCT_STUB_FRAME:
3170     case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
3171     case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME:
3172     case Translation::BUILTIN_CONTINUATION_FRAME:
3173     case Translation::UPDATE_FEEDBACK:
3174       // Peeled off before getting here.
3175       break;
3176 
3177     case Translation::DUPLICATED_OBJECT: {
3178       int object_id = iterator->Next();
3179       if (trace_file != nullptr) {
3180         PrintF(trace_file, "duplicated object #%d", object_id);
3181       }
3182       object_positions_.push_back(object_positions_[object_id]);
3183       TranslatedValue translated_value =
3184           TranslatedValue::NewDuplicateObject(this, object_id);
3185       frame.Add(translated_value);
3186       return translated_value.GetChildrenCount();
3187     }
3188 
3189     case Translation::ARGUMENTS_ELEMENTS: {
3190       CreateArgumentsType arguments_type =
3191           static_cast<CreateArgumentsType>(iterator->Next());
3192       CreateArgumentsElementsTranslatedValues(frame_index, fp, arguments_type,
3193                                               trace_file);
3194       return 0;
3195     }
3196 
3197     case Translation::ARGUMENTS_LENGTH: {
3198 #ifdef V8_NO_ARGUMENTS_ADAPTOR
3199       int arguments_length = actual_argument_count_;
3200 #else
3201       int arguments_length;
3202       ComputeArgumentsPosition(fp, &arguments_length);
3203 #endif
3204       if (trace_file != nullptr) {
3205         PrintF(trace_file, "arguments length field (length = %d)",
3206                arguments_length);
3207       }
3208       frame.Add(TranslatedValue::NewInt32(this, arguments_length));
3209       return 0;
3210     }
3211 
3212     case Translation::CAPTURED_OBJECT: {
3213       int field_count = iterator->Next();
3214       int object_index = static_cast<int>(object_positions_.size());
3215       if (trace_file != nullptr) {
3216         PrintF(trace_file, "captured object #%d (length = %d)", object_index,
3217                field_count);
3218       }
3219       object_positions_.push_back({frame_index, value_index});
3220       TranslatedValue translated_value =
3221           TranslatedValue::NewDeferredObject(this, field_count, object_index);
3222       frame.Add(translated_value);
3223       return translated_value.GetChildrenCount();
3224     }
3225 
3226     case Translation::REGISTER: {
3227       int input_reg = iterator->Next();
3228       if (registers == nullptr) {
3229         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
3230         frame.Add(translated_value);
3231         return translated_value.GetChildrenCount();
3232       }
3233       intptr_t value = registers->GetRegister(input_reg);
3234       Address uncompressed_value = DecompressIfNeeded(value);
3235       if (trace_file != nullptr) {
3236         PrintF(trace_file, V8PRIxPTR_FMT " ; %s ", uncompressed_value,
3237                converter.NameOfCPURegister(input_reg));
3238         Object(uncompressed_value).ShortPrint(trace_file);
3239       }
3240       TranslatedValue translated_value =
3241           TranslatedValue::NewTagged(this, Object(uncompressed_value));
3242       frame.Add(translated_value);
3243       return translated_value.GetChildrenCount();
3244     }
3245 
3246     case Translation::INT32_REGISTER: {
3247       int input_reg = iterator->Next();
3248       if (registers == nullptr) {
3249         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
3250         frame.Add(translated_value);
3251         return translated_value.GetChildrenCount();
3252       }
3253       intptr_t value = registers->GetRegister(input_reg);
3254       if (trace_file != nullptr) {
3255         PrintF(trace_file, "%" V8PRIdPTR " ; %s (int32)", value,
3256                converter.NameOfCPURegister(input_reg));
3257       }
3258       TranslatedValue translated_value =
3259           TranslatedValue::NewInt32(this, static_cast<int32_t>(value));
3260       frame.Add(translated_value);
3261       return translated_value.GetChildrenCount();
3262     }
3263 
3264     case Translation::INT64_REGISTER: {
3265       int input_reg = iterator->Next();
3266       if (registers == nullptr) {
3267         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
3268         frame.Add(translated_value);
3269         return translated_value.GetChildrenCount();
3270       }
3271       intptr_t value = registers->GetRegister(input_reg);
3272       if (trace_file != nullptr) {
3273         PrintF(trace_file, "%" V8PRIdPTR " ; %s (int64)", value,
3274                converter.NameOfCPURegister(input_reg));
3275       }
3276       TranslatedValue translated_value =
3277           TranslatedValue::NewInt64(this, static_cast<int64_t>(value));
3278       frame.Add(translated_value);
3279       return translated_value.GetChildrenCount();
3280     }
3281 
3282     case Translation::UINT32_REGISTER: {
3283       int input_reg = iterator->Next();
3284       if (registers == nullptr) {
3285         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
3286         frame.Add(translated_value);
3287         return translated_value.GetChildrenCount();
3288       }
3289       intptr_t value = registers->GetRegister(input_reg);
3290       if (trace_file != nullptr) {
3291         PrintF(trace_file, "%" V8PRIuPTR " ; %s (uint32)", value,
3292                converter.NameOfCPURegister(input_reg));
3293       }
3294       TranslatedValue translated_value =
3295           TranslatedValue::NewUInt32(this, static_cast<uint32_t>(value));
3296       frame.Add(translated_value);
3297       return translated_value.GetChildrenCount();
3298     }
3299 
3300     case Translation::BOOL_REGISTER: {
3301       int input_reg = iterator->Next();
3302       if (registers == nullptr) {
3303         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
3304         frame.Add(translated_value);
3305         return translated_value.GetChildrenCount();
3306       }
3307       intptr_t value = registers->GetRegister(input_reg);
3308       if (trace_file != nullptr) {
3309         PrintF(trace_file, "%" V8PRIdPTR " ; %s (bool)", value,
3310                converter.NameOfCPURegister(input_reg));
3311       }
3312       TranslatedValue translated_value =
3313           TranslatedValue::NewBool(this, static_cast<uint32_t>(value));
3314       frame.Add(translated_value);
3315       return translated_value.GetChildrenCount();
3316     }
3317 
3318     case Translation::FLOAT_REGISTER: {
3319       int input_reg = iterator->Next();
3320       if (registers == nullptr) {
3321         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
3322         frame.Add(translated_value);
3323         return translated_value.GetChildrenCount();
3324       }
3325       Float32 value = registers->GetFloatRegister(input_reg);
3326       if (trace_file != nullptr) {
3327         PrintF(trace_file, "%e ; %s (float)", value.get_scalar(),
3328                RegisterName(FloatRegister::from_code(input_reg)));
3329       }
3330       TranslatedValue translated_value = TranslatedValue::NewFloat(this, value);
3331       frame.Add(translated_value);
3332       return translated_value.GetChildrenCount();
3333     }
3334 
3335     case Translation::DOUBLE_REGISTER: {
3336       int input_reg = iterator->Next();
3337       if (registers == nullptr) {
3338         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
3339         frame.Add(translated_value);
3340         return translated_value.GetChildrenCount();
3341       }
3342       Float64 value = registers->GetDoubleRegister(input_reg);
3343       if (trace_file != nullptr) {
3344         PrintF(trace_file, "%e ; %s (double)", value.get_scalar(),
3345                RegisterName(DoubleRegister::from_code(input_reg)));
3346       }
3347       TranslatedValue translated_value =
3348           TranslatedValue::NewDouble(this, value);
3349       frame.Add(translated_value);
3350       return translated_value.GetChildrenCount();
3351     }
3352 
3353     case Translation::STACK_SLOT: {
3354       int slot_offset =
3355           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3356       intptr_t value = *(reinterpret_cast<intptr_t*>(fp + slot_offset));
3357       Address uncompressed_value = DecompressIfNeeded(value);
3358       if (trace_file != nullptr) {
3359         PrintF(trace_file, V8PRIxPTR_FMT " ;  [fp %c %3d]  ",
3360                uncompressed_value, slot_offset < 0 ? '-' : '+',
3361                std::abs(slot_offset));
3362         Object(uncompressed_value).ShortPrint(trace_file);
3363       }
3364       TranslatedValue translated_value =
3365           TranslatedValue::NewTagged(this, Object(uncompressed_value));
3366       frame.Add(translated_value);
3367       return translated_value.GetChildrenCount();
3368     }
3369 
3370     case Translation::INT32_STACK_SLOT: {
3371       int slot_offset =
3372           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3373       uint32_t value = GetUInt32Slot(fp, slot_offset);
3374       if (trace_file != nullptr) {
3375         PrintF(trace_file, "%d ; (int32) [fp %c %3d] ",
3376                static_cast<int32_t>(value), slot_offset < 0 ? '-' : '+',
3377                std::abs(slot_offset));
3378       }
3379       TranslatedValue translated_value = TranslatedValue::NewInt32(this, value);
3380       frame.Add(translated_value);
3381       return translated_value.GetChildrenCount();
3382     }
3383 
3384     case Translation::INT64_STACK_SLOT: {
3385       int slot_offset =
3386           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3387       uint64_t value = GetUInt64Slot(fp, slot_offset);
3388       if (trace_file != nullptr) {
3389         PrintF(trace_file, "%" V8PRIdPTR " ; (int64) [fp %c %3d] ",
3390                static_cast<intptr_t>(value), slot_offset < 0 ? '-' : '+',
3391                std::abs(slot_offset));
3392       }
3393       TranslatedValue translated_value = TranslatedValue::NewInt64(this, value);
3394       frame.Add(translated_value);
3395       return translated_value.GetChildrenCount();
3396     }
3397 
3398     case Translation::UINT32_STACK_SLOT: {
3399       int slot_offset =
3400           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3401       uint32_t value = GetUInt32Slot(fp, slot_offset);
3402       if (trace_file != nullptr) {
3403         PrintF(trace_file, "%u ; (uint32) [fp %c %3d] ", value,
3404                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3405       }
3406       TranslatedValue translated_value =
3407           TranslatedValue::NewUInt32(this, value);
3408       frame.Add(translated_value);
3409       return translated_value.GetChildrenCount();
3410     }
3411 
3412     case Translation::BOOL_STACK_SLOT: {
3413       int slot_offset =
3414           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3415       uint32_t value = GetUInt32Slot(fp, slot_offset);
3416       if (trace_file != nullptr) {
3417         PrintF(trace_file, "%u ; (bool) [fp %c %3d] ", value,
3418                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3419       }
3420       TranslatedValue translated_value = TranslatedValue::NewBool(this, value);
3421       frame.Add(translated_value);
3422       return translated_value.GetChildrenCount();
3423     }
3424 
3425     case Translation::FLOAT_STACK_SLOT: {
3426       int slot_offset =
3427           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3428       Float32 value = GetFloatSlot(fp, slot_offset);
3429       if (trace_file != nullptr) {
3430         PrintF(trace_file, "%e ; (float) [fp %c %3d] ", value.get_scalar(),
3431                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3432       }
3433       TranslatedValue translated_value = TranslatedValue::NewFloat(this, value);
3434       frame.Add(translated_value);
3435       return translated_value.GetChildrenCount();
3436     }
3437 
3438     case Translation::DOUBLE_STACK_SLOT: {
3439       int slot_offset =
3440           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
3441       Float64 value = GetDoubleSlot(fp, slot_offset);
3442       if (trace_file != nullptr) {
3443         PrintF(trace_file, "%e ; (double) [fp %c %d] ", value.get_scalar(),
3444                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
3445       }
3446       TranslatedValue translated_value =
3447           TranslatedValue::NewDouble(this, value);
3448       frame.Add(translated_value);
3449       return translated_value.GetChildrenCount();
3450     }
3451 
3452     case Translation::LITERAL: {
3453       int literal_index = iterator->Next();
3454       Object value = literal_array.get(literal_index);
3455       if (trace_file != nullptr) {
3456         PrintF(trace_file, V8PRIxPTR_FMT " ; (literal %2d) ", value.ptr(),
3457                literal_index);
3458         value.ShortPrint(trace_file);
3459       }
3460 
3461       TranslatedValue translated_value =
3462           TranslatedValue::NewTagged(this, value);
3463       frame.Add(translated_value);
3464       return translated_value.GetChildrenCount();
3465     }
3466   }
3467 
3468   FATAL("We should never get here - unexpected deopt info.");
3469 }
3470 
DecompressIfNeeded(intptr_t value)3471 Address TranslatedState::DecompressIfNeeded(intptr_t value) {
3472   if (COMPRESS_POINTERS_BOOL) {
3473     return DecompressTaggedAny(isolate()->isolate_root(),
3474                                static_cast<uint32_t>(value));
3475   } else {
3476     return value;
3477   }
3478 }
3479 
TranslatedState(const JavaScriptFrame * frame)3480 TranslatedState::TranslatedState(const JavaScriptFrame* frame) {
3481   int deopt_index = Safepoint::kNoDeoptimizationIndex;
3482   DeoptimizationData data =
3483       static_cast<const OptimizedFrame*>(frame)->GetDeoptimizationData(
3484           &deopt_index);
3485   DCHECK(!data.is_null() && deopt_index != Safepoint::kNoDeoptimizationIndex);
3486   TranslationIterator it(data.TranslationByteArray(),
3487                          data.TranslationIndex(deopt_index).value());
3488 #ifdef V8_NO_ARGUMENTS_ADAPTOR
3489   int actual_argc = frame->GetActualArgumentCount();
3490 #else
3491   int actual_argc = 0;
3492 #endif
3493   Init(frame->isolate(), frame->fp(), frame->fp(), &it, data.LiteralArray(),
3494        nullptr /* registers */, nullptr /* trace file */,
3495        frame->function().shared().internal_formal_parameter_count(),
3496        actual_argc);
3497 }
3498 
Init(Isolate * isolate,Address input_frame_pointer,Address stack_frame_pointer,TranslationIterator * iterator,FixedArray literal_array,RegisterValues * registers,FILE * trace_file,int formal_parameter_count,int actual_argument_count)3499 void TranslatedState::Init(Isolate* isolate, Address input_frame_pointer,
3500                            Address stack_frame_pointer,
3501                            TranslationIterator* iterator,
3502                            FixedArray literal_array, RegisterValues* registers,
3503                            FILE* trace_file, int formal_parameter_count,
3504                            int actual_argument_count) {
3505   DCHECK(frames_.empty());
3506 
3507   stack_frame_pointer_ = stack_frame_pointer;
3508   formal_parameter_count_ = formal_parameter_count;
3509   actual_argument_count_ = actual_argument_count;
3510   isolate_ = isolate;
3511 
3512   // Read out the 'header' translation.
3513   Translation::Opcode opcode =
3514       static_cast<Translation::Opcode>(iterator->Next());
3515   CHECK(opcode == Translation::BEGIN);
3516 
3517   int count = iterator->Next();
3518   frames_.reserve(count);
3519   iterator->Next();  // Drop JS frames count.
3520   int update_feedback_count = iterator->Next();
3521   CHECK_GE(update_feedback_count, 0);
3522   CHECK_LE(update_feedback_count, 1);
3523 
3524   if (update_feedback_count == 1) {
3525     ReadUpdateFeedback(iterator, literal_array, trace_file);
3526   }
3527 
3528   std::stack<int> nested_counts;
3529 
3530   // Read the frames
3531   for (int frame_index = 0; frame_index < count; frame_index++) {
3532     // Read the frame descriptor.
3533     frames_.push_back(CreateNextTranslatedFrame(
3534         iterator, literal_array, input_frame_pointer, trace_file));
3535     TranslatedFrame& frame = frames_.back();
3536 
3537     // Read the values.
3538     int values_to_process = frame.GetValueCount();
3539     while (values_to_process > 0 || !nested_counts.empty()) {
3540       if (trace_file != nullptr) {
3541         if (nested_counts.empty()) {
3542           // For top level values, print the value number.
3543           PrintF(trace_file,
3544                  "    %3i: ", frame.GetValueCount() - values_to_process);
3545         } else {
3546           // Take care of indenting for nested values.
3547           PrintF(trace_file, "         ");
3548           for (size_t j = 0; j < nested_counts.size(); j++) {
3549             PrintF(trace_file, "  ");
3550           }
3551         }
3552       }
3553 
3554       int nested_count =
3555           CreateNextTranslatedValue(frame_index, iterator, literal_array,
3556                                     input_frame_pointer, registers, trace_file);
3557 
3558       if (trace_file != nullptr) {
3559         PrintF(trace_file, "\n");
3560       }
3561 
3562       // Update the value count and resolve the nesting.
3563       values_to_process--;
3564       if (nested_count > 0) {
3565         nested_counts.push(values_to_process);
3566         values_to_process = nested_count;
3567       } else {
3568         while (values_to_process == 0 && !nested_counts.empty()) {
3569           values_to_process = nested_counts.top();
3570           nested_counts.pop();
3571         }
3572       }
3573     }
3574   }
3575 
3576   CHECK(!iterator->HasNext() || static_cast<Translation::Opcode>(
3577                                     iterator->Next()) == Translation::BEGIN);
3578 }
3579 
Prepare(Address stack_frame_pointer)3580 void TranslatedState::Prepare(Address stack_frame_pointer) {
3581   for (auto& frame : frames_) frame.Handlify();
3582 
3583   if (!feedback_vector_.is_null()) {
3584     feedback_vector_handle_ =
3585         Handle<FeedbackVector>(feedback_vector_, isolate());
3586     feedback_vector_ = FeedbackVector();
3587   }
3588   stack_frame_pointer_ = stack_frame_pointer;
3589 
3590   UpdateFromPreviouslyMaterializedObjects();
3591 }
3592 
GetValueByObjectIndex(int object_index)3593 TranslatedValue* TranslatedState::GetValueByObjectIndex(int object_index) {
3594   CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
3595   TranslatedState::ObjectPosition pos = object_positions_[object_index];
3596   return &(frames_[pos.frame_index_].values_[pos.value_index_]);
3597 }
3598 
InitializeObjectAt(TranslatedValue * slot)3599 Handle<HeapObject> TranslatedState::InitializeObjectAt(TranslatedValue* slot) {
3600   slot = ResolveCapturedObject(slot);
3601 
3602   DisallowHeapAllocation no_allocation;
3603   if (slot->materialization_state() != TranslatedValue::kFinished) {
3604     std::stack<int> worklist;
3605     worklist.push(slot->object_index());
3606     slot->mark_finished();
3607 
3608     while (!worklist.empty()) {
3609       int index = worklist.top();
3610       worklist.pop();
3611       InitializeCapturedObjectAt(index, &worklist, no_allocation);
3612     }
3613   }
3614   return slot->storage();
3615 }
3616 
InitializeCapturedObjectAt(int object_index,std::stack<int> * worklist,const DisallowHeapAllocation & no_allocation)3617 void TranslatedState::InitializeCapturedObjectAt(
3618     int object_index, std::stack<int>* worklist,
3619     const DisallowHeapAllocation& no_allocation) {
3620   CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
3621   TranslatedState::ObjectPosition pos = object_positions_[object_index];
3622   int value_index = pos.value_index_;
3623 
3624   TranslatedFrame* frame = &(frames_[pos.frame_index_]);
3625   TranslatedValue* slot = &(frame->values_[value_index]);
3626   value_index++;
3627 
3628   CHECK_EQ(TranslatedValue::kFinished, slot->materialization_state());
3629   CHECK_EQ(TranslatedValue::kCapturedObject, slot->kind());
3630 
3631   // Ensure all fields are initialized.
3632   int children_init_index = value_index;
3633   for (int i = 0; i < slot->GetChildrenCount(); i++) {
3634     // If the field is an object that has not been initialized yet, queue it
3635     // for initialization (and mark it as such).
3636     TranslatedValue* child_slot = frame->ValueAt(children_init_index);
3637     if (child_slot->kind() == TranslatedValue::kCapturedObject ||
3638         child_slot->kind() == TranslatedValue::kDuplicatedObject) {
3639       child_slot = ResolveCapturedObject(child_slot);
3640       if (child_slot->materialization_state() != TranslatedValue::kFinished) {
3641         DCHECK_EQ(TranslatedValue::kAllocated,
3642                   child_slot->materialization_state());
3643         worklist->push(child_slot->object_index());
3644         child_slot->mark_finished();
3645       }
3646     }
3647     SkipSlots(1, frame, &children_init_index);
3648   }
3649 
3650   // Read the map.
3651   // The map should never be materialized, so let us check we already have
3652   // an existing object here.
3653   CHECK_EQ(frame->values_[value_index].kind(), TranslatedValue::kTagged);
3654   Handle<Map> map = Handle<Map>::cast(frame->values_[value_index].GetValue());
3655   CHECK(map->IsMap());
3656   value_index++;
3657 
3658   // Handle the special cases.
3659   switch (map->instance_type()) {
3660     case HEAP_NUMBER_TYPE:
3661     case FIXED_DOUBLE_ARRAY_TYPE:
3662       return;
3663 
3664     case FIXED_ARRAY_TYPE:
3665     case AWAIT_CONTEXT_TYPE:
3666     case BLOCK_CONTEXT_TYPE:
3667     case CATCH_CONTEXT_TYPE:
3668     case DEBUG_EVALUATE_CONTEXT_TYPE:
3669     case EVAL_CONTEXT_TYPE:
3670     case FUNCTION_CONTEXT_TYPE:
3671     case MODULE_CONTEXT_TYPE:
3672     case NATIVE_CONTEXT_TYPE:
3673     case SCRIPT_CONTEXT_TYPE:
3674     case WITH_CONTEXT_TYPE:
3675     case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
3676     case HASH_TABLE_TYPE:
3677     case ORDERED_HASH_MAP_TYPE:
3678     case ORDERED_HASH_SET_TYPE:
3679     case NAME_DICTIONARY_TYPE:
3680     case GLOBAL_DICTIONARY_TYPE:
3681     case NUMBER_DICTIONARY_TYPE:
3682     case SIMPLE_NUMBER_DICTIONARY_TYPE:
3683     case PROPERTY_ARRAY_TYPE:
3684     case SCRIPT_CONTEXT_TABLE_TYPE:
3685     case SLOPPY_ARGUMENTS_ELEMENTS_TYPE:
3686       InitializeObjectWithTaggedFieldsAt(frame, &value_index, slot, map,
3687                                          no_allocation);
3688       break;
3689 
3690     default:
3691       CHECK(map->IsJSObjectMap());
3692       InitializeJSObjectAt(frame, &value_index, slot, map, no_allocation);
3693       break;
3694   }
3695   CHECK_EQ(value_index, children_init_index);
3696 }
3697 
EnsureObjectAllocatedAt(TranslatedValue * slot)3698 void TranslatedState::EnsureObjectAllocatedAt(TranslatedValue* slot) {
3699   slot = ResolveCapturedObject(slot);
3700 
3701   if (slot->materialization_state() == TranslatedValue::kUninitialized) {
3702     std::stack<int> worklist;
3703     worklist.push(slot->object_index());
3704     slot->mark_allocated();
3705 
3706     while (!worklist.empty()) {
3707       int index = worklist.top();
3708       worklist.pop();
3709       EnsureCapturedObjectAllocatedAt(index, &worklist);
3710     }
3711   }
3712 }
3713 
GetSmiValue() const3714 int TranslatedValue::GetSmiValue() const {
3715   Object value = GetRawValue();
3716   CHECK(value.IsSmi());
3717   return Smi::cast(value).value();
3718 }
3719 
MaterializeFixedDoubleArray(TranslatedFrame * frame,int * value_index,TranslatedValue * slot,Handle<Map> map)3720 void TranslatedState::MaterializeFixedDoubleArray(TranslatedFrame* frame,
3721                                                   int* value_index,
3722                                                   TranslatedValue* slot,
3723                                                   Handle<Map> map) {
3724   int length = frame->values_[*value_index].GetSmiValue();
3725   (*value_index)++;
3726   Handle<FixedDoubleArray> array = Handle<FixedDoubleArray>::cast(
3727       isolate()->factory()->NewFixedDoubleArray(length));
3728   CHECK_GT(length, 0);
3729   for (int i = 0; i < length; i++) {
3730     CHECK_NE(TranslatedValue::kCapturedObject,
3731              frame->values_[*value_index].kind());
3732     Handle<Object> value = frame->values_[*value_index].GetValue();
3733     if (value->IsNumber()) {
3734       array->set(i, value->Number());
3735     } else {
3736       CHECK(value.is_identical_to(isolate()->factory()->the_hole_value()));
3737       array->set_the_hole(isolate(), i);
3738     }
3739     (*value_index)++;
3740   }
3741   slot->set_storage(array);
3742 }
3743 
MaterializeHeapNumber(TranslatedFrame * frame,int * value_index,TranslatedValue * slot)3744 void TranslatedState::MaterializeHeapNumber(TranslatedFrame* frame,
3745                                             int* value_index,
3746                                             TranslatedValue* slot) {
3747   CHECK_NE(TranslatedValue::kCapturedObject,
3748            frame->values_[*value_index].kind());
3749   Handle<Object> value = frame->values_[*value_index].GetValue();
3750   CHECK(value->IsNumber());
3751   Handle<HeapNumber> box = isolate()->factory()->NewHeapNumber(value->Number());
3752   (*value_index)++;
3753   slot->set_storage(box);
3754 }
3755 
3756 namespace {
3757 
3758 enum StorageKind : uint8_t {
3759   kStoreTagged,
3760   kStoreUnboxedDouble,
3761   kStoreHeapObject
3762 };
3763 
3764 }  // namespace
3765 
SkipSlots(int slots_to_skip,TranslatedFrame * frame,int * value_index)3766 void TranslatedState::SkipSlots(int slots_to_skip, TranslatedFrame* frame,
3767                                 int* value_index) {
3768   while (slots_to_skip > 0) {
3769     TranslatedValue* slot = &(frame->values_[*value_index]);
3770     (*value_index)++;
3771     slots_to_skip--;
3772 
3773     if (slot->kind() == TranslatedValue::kCapturedObject) {
3774       slots_to_skip += slot->GetChildrenCount();
3775     }
3776   }
3777 }
3778 
EnsureCapturedObjectAllocatedAt(int object_index,std::stack<int> * worklist)3779 void TranslatedState::EnsureCapturedObjectAllocatedAt(
3780     int object_index, std::stack<int>* worklist) {
3781   CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
3782   TranslatedState::ObjectPosition pos = object_positions_[object_index];
3783   int value_index = pos.value_index_;
3784 
3785   TranslatedFrame* frame = &(frames_[pos.frame_index_]);
3786   TranslatedValue* slot = &(frame->values_[value_index]);
3787   value_index++;
3788 
3789   CHECK_EQ(TranslatedValue::kAllocated, slot->materialization_state());
3790   CHECK_EQ(TranslatedValue::kCapturedObject, slot->kind());
3791 
3792   // Read the map.
3793   // The map should never be materialized, so let us check we already have
3794   // an existing object here.
3795   CHECK_EQ(frame->values_[value_index].kind(), TranslatedValue::kTagged);
3796   Handle<Map> map = Handle<Map>::cast(frame->values_[value_index].GetValue());
3797   CHECK(map->IsMap());
3798   value_index++;
3799 
3800   // Handle the special cases.
3801   switch (map->instance_type()) {
3802     case FIXED_DOUBLE_ARRAY_TYPE:
3803       // Materialize (i.e. allocate&initialize) the array and return since
3804       // there is no need to process the children.
3805       return MaterializeFixedDoubleArray(frame, &value_index, slot, map);
3806 
3807     case HEAP_NUMBER_TYPE:
3808       // Materialize (i.e. allocate&initialize) the heap number and return.
3809       // There is no need to process the children.
3810       return MaterializeHeapNumber(frame, &value_index, slot);
3811 
3812     case FIXED_ARRAY_TYPE:
3813     case SCRIPT_CONTEXT_TABLE_TYPE:
3814     case AWAIT_CONTEXT_TYPE:
3815     case BLOCK_CONTEXT_TYPE:
3816     case CATCH_CONTEXT_TYPE:
3817     case DEBUG_EVALUATE_CONTEXT_TYPE:
3818     case EVAL_CONTEXT_TYPE:
3819     case FUNCTION_CONTEXT_TYPE:
3820     case MODULE_CONTEXT_TYPE:
3821     case NATIVE_CONTEXT_TYPE:
3822     case SCRIPT_CONTEXT_TYPE:
3823     case WITH_CONTEXT_TYPE:
3824     case HASH_TABLE_TYPE:
3825     case ORDERED_HASH_MAP_TYPE:
3826     case ORDERED_HASH_SET_TYPE:
3827     case NAME_DICTIONARY_TYPE:
3828     case GLOBAL_DICTIONARY_TYPE:
3829     case NUMBER_DICTIONARY_TYPE:
3830     case SIMPLE_NUMBER_DICTIONARY_TYPE: {
3831       // Check we have the right size.
3832       int array_length = frame->values_[value_index].GetSmiValue();
3833       int instance_size = FixedArray::SizeFor(array_length);
3834       CHECK_EQ(instance_size, slot->GetChildrenCount() * kTaggedSize);
3835 
3836       // Canonicalize empty fixed array.
3837       if (*map == ReadOnlyRoots(isolate()).empty_fixed_array().map() &&
3838           array_length == 0) {
3839         slot->set_storage(isolate()->factory()->empty_fixed_array());
3840       } else {
3841         slot->set_storage(AllocateStorageFor(slot));
3842       }
3843 
3844       // Make sure all the remaining children (after the map) are allocated.
3845       return EnsureChildrenAllocated(slot->GetChildrenCount() - 1, frame,
3846                                      &value_index, worklist);
3847     }
3848 
3849     case SLOPPY_ARGUMENTS_ELEMENTS_TYPE: {
3850       // Verify that the arguments size is correct.
3851       int args_length = frame->values_[value_index].GetSmiValue();
3852       int args_size = SloppyArgumentsElements::SizeFor(args_length);
3853       CHECK_EQ(args_size, slot->GetChildrenCount() * kTaggedSize);
3854 
3855       slot->set_storage(AllocateStorageFor(slot));
3856 
3857       // Make sure all the remaining children (after the map) are allocated.
3858       return EnsureChildrenAllocated(slot->GetChildrenCount() - 1, frame,
3859                                      &value_index, worklist);
3860     }
3861 
3862     case PROPERTY_ARRAY_TYPE: {
3863       // Check we have the right size.
3864       int length_or_hash = frame->values_[value_index].GetSmiValue();
3865       int array_length = PropertyArray::LengthField::decode(length_or_hash);
3866       int instance_size = PropertyArray::SizeFor(array_length);
3867       CHECK_EQ(instance_size, slot->GetChildrenCount() * kTaggedSize);
3868 
3869       slot->set_storage(AllocateStorageFor(slot));
3870 
3871       // Make sure all the remaining children (after the map) are allocated.
3872       return EnsureChildrenAllocated(slot->GetChildrenCount() - 1, frame,
3873                                      &value_index, worklist);
3874     }
3875 
3876     default:
3877       CHECK(map->IsJSObjectMap());
3878       EnsureJSObjectAllocated(slot, map);
3879       TranslatedValue* properties_slot = &(frame->values_[value_index]);
3880       value_index++;
3881       if (properties_slot->kind() == TranslatedValue::kCapturedObject) {
3882         // If we are materializing the property array, make sure we put
3883         // the mutable heap numbers at the right places.
3884         EnsurePropertiesAllocatedAndMarked(properties_slot, map);
3885         EnsureChildrenAllocated(properties_slot->GetChildrenCount(), frame,
3886                                 &value_index, worklist);
3887       }
3888       // Make sure all the remaining children (after the map and properties) are
3889       // allocated.
3890       return EnsureChildrenAllocated(slot->GetChildrenCount() - 2, frame,
3891                                      &value_index, worklist);
3892   }
3893   UNREACHABLE();
3894 }
3895 
EnsureChildrenAllocated(int count,TranslatedFrame * frame,int * value_index,std::stack<int> * worklist)3896 void TranslatedState::EnsureChildrenAllocated(int count, TranslatedFrame* frame,
3897                                               int* value_index,
3898                                               std::stack<int>* worklist) {
3899   // Ensure all children are allocated.
3900   for (int i = 0; i < count; i++) {
3901     // If the field is an object that has not been allocated yet, queue it
3902     // for initialization (and mark it as such).
3903     TranslatedValue* child_slot = frame->ValueAt(*value_index);
3904     if (child_slot->kind() == TranslatedValue::kCapturedObject ||
3905         child_slot->kind() == TranslatedValue::kDuplicatedObject) {
3906       child_slot = ResolveCapturedObject(child_slot);
3907       if (child_slot->materialization_state() ==
3908           TranslatedValue::kUninitialized) {
3909         worklist->push(child_slot->object_index());
3910         child_slot->mark_allocated();
3911       }
3912     } else {
3913       // Make sure the simple values (heap numbers, etc.) are properly
3914       // initialized.
3915       child_slot->GetValue();
3916     }
3917     SkipSlots(1, frame, value_index);
3918   }
3919 }
3920 
EnsurePropertiesAllocatedAndMarked(TranslatedValue * properties_slot,Handle<Map> map)3921 void TranslatedState::EnsurePropertiesAllocatedAndMarked(
3922     TranslatedValue* properties_slot, Handle<Map> map) {
3923   CHECK_EQ(TranslatedValue::kUninitialized,
3924            properties_slot->materialization_state());
3925 
3926   Handle<ByteArray> object_storage = AllocateStorageFor(properties_slot);
3927   properties_slot->mark_allocated();
3928   properties_slot->set_storage(object_storage);
3929 
3930   // Set markers for out-of-object properties.
3931   Handle<DescriptorArray> descriptors(map->instance_descriptors(kRelaxedLoad),
3932                                       isolate());
3933   for (InternalIndex i : map->IterateOwnDescriptors()) {
3934     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3935     Representation representation = descriptors->GetDetails(i).representation();
3936     if (!index.is_inobject() &&
3937         (representation.IsDouble() || representation.IsHeapObject())) {
3938       CHECK(!map->IsUnboxedDoubleField(index));
3939       int outobject_index = index.outobject_array_index();
3940       int array_index = outobject_index * kTaggedSize;
3941       object_storage->set(array_index, kStoreHeapObject);
3942     }
3943   }
3944 }
3945 
AllocateStorageFor(TranslatedValue * slot)3946 Handle<ByteArray> TranslatedState::AllocateStorageFor(TranslatedValue* slot) {
3947   int allocate_size =
3948       ByteArray::LengthFor(slot->GetChildrenCount() * kTaggedSize);
3949   // It is important to allocate all the objects tenured so that the marker
3950   // does not visit them.
3951   Handle<ByteArray> object_storage =
3952       isolate()->factory()->NewByteArray(allocate_size, AllocationType::kOld);
3953   for (int i = 0; i < object_storage->length(); i++) {
3954     object_storage->set(i, kStoreTagged);
3955   }
3956   return object_storage;
3957 }
3958 
EnsureJSObjectAllocated(TranslatedValue * slot,Handle<Map> map)3959 void TranslatedState::EnsureJSObjectAllocated(TranslatedValue* slot,
3960                                               Handle<Map> map) {
3961   CHECK_EQ(map->instance_size(), slot->GetChildrenCount() * kTaggedSize);
3962 
3963   Handle<ByteArray> object_storage = AllocateStorageFor(slot);
3964   // Now we handle the interesting (JSObject) case.
3965   Handle<DescriptorArray> descriptors(map->instance_descriptors(kRelaxedLoad),
3966                                       isolate());
3967 
3968   // Set markers for in-object properties.
3969   for (InternalIndex i : map->IterateOwnDescriptors()) {
3970     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
3971     Representation representation = descriptors->GetDetails(i).representation();
3972     if (index.is_inobject() &&
3973         (representation.IsDouble() || representation.IsHeapObject())) {
3974       CHECK_GE(index.index(), FixedArray::kHeaderSize / kTaggedSize);
3975       int array_index = index.index() * kTaggedSize - FixedArray::kHeaderSize;
3976       uint8_t marker = map->IsUnboxedDoubleField(index) ? kStoreUnboxedDouble
3977                                                         : kStoreHeapObject;
3978       object_storage->set(array_index, marker);
3979     }
3980   }
3981   slot->set_storage(object_storage);
3982 }
3983 
GetResolvedSlot(TranslatedFrame * frame,int value_index)3984 TranslatedValue* TranslatedState::GetResolvedSlot(TranslatedFrame* frame,
3985                                                   int value_index) {
3986   TranslatedValue* slot = frame->ValueAt(value_index);
3987   if (slot->kind() == TranslatedValue::kDuplicatedObject) {
3988     slot = ResolveCapturedObject(slot);
3989   }
3990   CHECK_NE(slot->materialization_state(), TranslatedValue::kUninitialized);
3991   return slot;
3992 }
3993 
GetResolvedSlotAndAdvance(TranslatedFrame * frame,int * value_index)3994 TranslatedValue* TranslatedState::GetResolvedSlotAndAdvance(
3995     TranslatedFrame* frame, int* value_index) {
3996   TranslatedValue* slot = GetResolvedSlot(frame, *value_index);
3997   SkipSlots(1, frame, value_index);
3998   return slot;
3999 }
4000 
GetValueAndAdvance(TranslatedFrame * frame,int * value_index)4001 Handle<Object> TranslatedState::GetValueAndAdvance(TranslatedFrame* frame,
4002                                                    int* value_index) {
4003   TranslatedValue* slot = GetResolvedSlot(frame, *value_index);
4004   SkipSlots(1, frame, value_index);
4005   return slot->GetValue();
4006 }
4007 
InitializeJSObjectAt(TranslatedFrame * frame,int * value_index,TranslatedValue * slot,Handle<Map> map,const DisallowHeapAllocation & no_allocation)4008 void TranslatedState::InitializeJSObjectAt(
4009     TranslatedFrame* frame, int* value_index, TranslatedValue* slot,
4010     Handle<Map> map, const DisallowHeapAllocation& no_allocation) {
4011   Handle<HeapObject> object_storage = Handle<HeapObject>::cast(slot->storage_);
4012   DCHECK_EQ(TranslatedValue::kCapturedObject, slot->kind());
4013 
4014   // The object should have at least a map and some payload.
4015   CHECK_GE(slot->GetChildrenCount(), 2);
4016 
4017   // Notify the concurrent marker about the layout change.
4018   isolate()->heap()->NotifyObjectLayoutChange(*object_storage, no_allocation);
4019 
4020   // Fill the property array field.
4021   {
4022     Handle<Object> properties = GetValueAndAdvance(frame, value_index);
4023     WRITE_FIELD(*object_storage, JSObject::kPropertiesOrHashOffset,
4024                 *properties);
4025     WRITE_BARRIER(*object_storage, JSObject::kPropertiesOrHashOffset,
4026                   *properties);
4027   }
4028 
4029   // For all the other fields we first look at the fixed array and check the
4030   // marker to see if we store an unboxed double.
4031   DCHECK_EQ(kTaggedSize, JSObject::kPropertiesOrHashOffset);
4032   for (int i = 2; i < slot->GetChildrenCount(); i++) {
4033     TranslatedValue* slot = GetResolvedSlotAndAdvance(frame, value_index);
4034     // Read out the marker and ensure the field is consistent with
4035     // what the markers in the storage say (note that all heap numbers
4036     // should be fully initialized by now).
4037     int offset = i * kTaggedSize;
4038     uint8_t marker = object_storage->ReadField<uint8_t>(offset);
4039     if (marker == kStoreUnboxedDouble) {
4040       Handle<HeapObject> field_value = slot->storage();
4041       CHECK(field_value->IsHeapNumber());
4042       object_storage->WriteField<double>(offset, field_value->Number());
4043     } else if (marker == kStoreHeapObject) {
4044       Handle<HeapObject> field_value = slot->storage();
4045       WRITE_FIELD(*object_storage, offset, *field_value);
4046       WRITE_BARRIER(*object_storage, offset, *field_value);
4047     } else {
4048       CHECK_EQ(kStoreTagged, marker);
4049       Handle<Object> field_value = slot->GetValue();
4050       DCHECK_IMPLIES(field_value->IsHeapNumber(),
4051                      !IsSmiDouble(field_value->Number()));
4052       WRITE_FIELD(*object_storage, offset, *field_value);
4053       WRITE_BARRIER(*object_storage, offset, *field_value);
4054     }
4055   }
4056   object_storage->synchronized_set_map(*map);
4057 }
4058 
InitializeObjectWithTaggedFieldsAt(TranslatedFrame * frame,int * value_index,TranslatedValue * slot,Handle<Map> map,const DisallowHeapAllocation & no_allocation)4059 void TranslatedState::InitializeObjectWithTaggedFieldsAt(
4060     TranslatedFrame* frame, int* value_index, TranslatedValue* slot,
4061     Handle<Map> map, const DisallowHeapAllocation& no_allocation) {
4062   Handle<HeapObject> object_storage = Handle<HeapObject>::cast(slot->storage_);
4063 
4064   // Skip the writes if we already have the canonical empty fixed array.
4065   if (*object_storage == ReadOnlyRoots(isolate()).empty_fixed_array()) {
4066     CHECK_EQ(2, slot->GetChildrenCount());
4067     Handle<Object> length_value = GetValueAndAdvance(frame, value_index);
4068     CHECK_EQ(*length_value, Smi::FromInt(0));
4069     return;
4070   }
4071 
4072   // Notify the concurrent marker about the layout change.
4073   isolate()->heap()->NotifyObjectLayoutChange(*object_storage, no_allocation);
4074 
4075   // Write the fields to the object.
4076   for (int i = 1; i < slot->GetChildrenCount(); i++) {
4077     TranslatedValue* slot = GetResolvedSlotAndAdvance(frame, value_index);
4078     int offset = i * kTaggedSize;
4079     uint8_t marker = object_storage->ReadField<uint8_t>(offset);
4080     Handle<Object> field_value;
4081     if (i > 1 && marker == kStoreHeapObject) {
4082       field_value = slot->storage();
4083     } else {
4084       CHECK(marker == kStoreTagged || i == 1);
4085       field_value = slot->GetValue();
4086       DCHECK_IMPLIES(field_value->IsHeapNumber(),
4087                      !IsSmiDouble(field_value->Number()));
4088     }
4089     WRITE_FIELD(*object_storage, offset, *field_value);
4090     WRITE_BARRIER(*object_storage, offset, *field_value);
4091   }
4092 
4093   object_storage->synchronized_set_map(*map);
4094 }
4095 
ResolveCapturedObject(TranslatedValue * slot)4096 TranslatedValue* TranslatedState::ResolveCapturedObject(TranslatedValue* slot) {
4097   while (slot->kind() == TranslatedValue::kDuplicatedObject) {
4098     slot = GetValueByObjectIndex(slot->object_index());
4099   }
4100   CHECK_EQ(TranslatedValue::kCapturedObject, slot->kind());
4101   return slot;
4102 }
4103 
GetFrameFromJSFrameIndex(int jsframe_index)4104 TranslatedFrame* TranslatedState::GetFrameFromJSFrameIndex(int jsframe_index) {
4105   for (size_t i = 0; i < frames_.size(); i++) {
4106     if (frames_[i].kind() == TranslatedFrame::kInterpretedFunction ||
4107         frames_[i].kind() == TranslatedFrame::kJavaScriptBuiltinContinuation ||
4108         frames_[i].kind() ==
4109             TranslatedFrame::kJavaScriptBuiltinContinuationWithCatch) {
4110       if (jsframe_index > 0) {
4111         jsframe_index--;
4112       } else {
4113         return &(frames_[i]);
4114       }
4115     }
4116   }
4117   return nullptr;
4118 }
4119 
GetArgumentsInfoFromJSFrameIndex(int jsframe_index,int * args_count)4120 TranslatedFrame* TranslatedState::GetArgumentsInfoFromJSFrameIndex(
4121     int jsframe_index, int* args_count) {
4122   for (size_t i = 0; i < frames_.size(); i++) {
4123     if (frames_[i].kind() == TranslatedFrame::kInterpretedFunction ||
4124         frames_[i].kind() == TranslatedFrame::kJavaScriptBuiltinContinuation ||
4125         frames_[i].kind() ==
4126             TranslatedFrame::kJavaScriptBuiltinContinuationWithCatch) {
4127       if (jsframe_index > 0) {
4128         jsframe_index--;
4129       } else {
4130         // We have the JS function frame, now check if it has arguments
4131         // adaptor.
4132         if (i > 0 &&
4133             frames_[i - 1].kind() == TranslatedFrame::kArgumentsAdaptor) {
4134           *args_count = frames_[i - 1].height();
4135           return &(frames_[i - 1]);
4136         }
4137 
4138         // JavaScriptBuiltinContinuation frames that are not preceeded by
4139         // a arguments adapter frame are currently only used by C++ API calls
4140         // from TurboFan. Calls to C++ API functions from TurboFan need
4141         // a special marker frame state, otherwise the API call wouldn't
4142         // be shown in a stack trace.
4143         if (frames_[i].kind() ==
4144                 TranslatedFrame::kJavaScriptBuiltinContinuation &&
4145             frames_[i].shared_info()->internal_formal_parameter_count() ==
4146                 kDontAdaptArgumentsSentinel) {
4147           DCHECK(frames_[i].shared_info()->IsApiFunction());
4148 
4149           // The argument count for this special case is always the second
4150           // to last value in the TranslatedFrame. It should also always be
4151           // {1}, as the GenericLazyDeoptContinuation builtin only has one
4152           // argument (the receiver).
4153           static constexpr int kTheContext = 1;
4154           const int height = frames_[i].height() + kTheContext;
4155           *args_count = frames_[i].ValueAt(height - 1)->GetSmiValue();
4156           DCHECK_EQ(*args_count, 1);
4157         } else {
4158           *args_count = InternalFormalParameterCountWithReceiver(
4159               *frames_[i].shared_info());
4160         }
4161         return &(frames_[i]);
4162       }
4163     }
4164   }
4165   return nullptr;
4166 }
4167 
StoreMaterializedValuesAndDeopt(JavaScriptFrame * frame)4168 void TranslatedState::StoreMaterializedValuesAndDeopt(JavaScriptFrame* frame) {
4169   MaterializedObjectStore* materialized_store =
4170       isolate_->materialized_object_store();
4171   Handle<FixedArray> previously_materialized_objects =
4172       materialized_store->Get(stack_frame_pointer_);
4173 
4174   Handle<Object> marker = isolate_->factory()->arguments_marker();
4175 
4176   int length = static_cast<int>(object_positions_.size());
4177   bool new_store = false;
4178   if (previously_materialized_objects.is_null()) {
4179     previously_materialized_objects =
4180         isolate_->factory()->NewFixedArray(length, AllocationType::kOld);
4181     for (int i = 0; i < length; i++) {
4182       previously_materialized_objects->set(i, *marker);
4183     }
4184     new_store = true;
4185   }
4186 
4187   CHECK_EQ(length, previously_materialized_objects->length());
4188 
4189   bool value_changed = false;
4190   for (int i = 0; i < length; i++) {
4191     TranslatedState::ObjectPosition pos = object_positions_[i];
4192     TranslatedValue* value_info =
4193         &(frames_[pos.frame_index_].values_[pos.value_index_]);
4194 
4195     CHECK(value_info->IsMaterializedObject());
4196 
4197     // Skip duplicate objects (i.e., those that point to some other object id).
4198     if (value_info->object_index() != i) continue;
4199 
4200     Handle<Object> previous_value(previously_materialized_objects->get(i),
4201                                   isolate_);
4202     Handle<Object> value(value_info->GetRawValue(), isolate_);
4203 
4204     if (value.is_identical_to(marker)) {
4205       DCHECK_EQ(*previous_value, *marker);
4206     } else {
4207       if (*previous_value == *marker) {
4208         if (value->IsSmi()) {
4209           value = isolate()->factory()->NewHeapNumber(value->Number());
4210         }
4211         previously_materialized_objects->set(i, *value);
4212         value_changed = true;
4213       } else {
4214         CHECK(*previous_value == *value ||
4215               (previous_value->IsHeapNumber() && value->IsSmi() &&
4216                previous_value->Number() == value->Number()));
4217       }
4218     }
4219   }
4220 
4221   if (new_store && value_changed) {
4222     materialized_store->Set(stack_frame_pointer_,
4223                             previously_materialized_objects);
4224     CHECK_EQ(frames_[0].kind(), TranslatedFrame::kInterpretedFunction);
4225     CHECK_EQ(frame->function(), frames_[0].front().GetRawValue());
4226     Deoptimizer::DeoptimizeFunction(frame->function(), frame->LookupCode());
4227   }
4228 }
4229 
UpdateFromPreviouslyMaterializedObjects()4230 void TranslatedState::UpdateFromPreviouslyMaterializedObjects() {
4231   MaterializedObjectStore* materialized_store =
4232       isolate_->materialized_object_store();
4233   Handle<FixedArray> previously_materialized_objects =
4234       materialized_store->Get(stack_frame_pointer_);
4235 
4236   // If we have no previously materialized objects, there is nothing to do.
4237   if (previously_materialized_objects.is_null()) return;
4238 
4239   Handle<Object> marker = isolate_->factory()->arguments_marker();
4240 
4241   int length = static_cast<int>(object_positions_.size());
4242   CHECK_EQ(length, previously_materialized_objects->length());
4243 
4244   for (int i = 0; i < length; i++) {
4245     // For a previously materialized objects, inject their value into the
4246     // translated values.
4247     if (previously_materialized_objects->get(i) != *marker) {
4248       TranslatedState::ObjectPosition pos = object_positions_[i];
4249       TranslatedValue* value_info =
4250           &(frames_[pos.frame_index_].values_[pos.value_index_]);
4251       CHECK(value_info->IsMaterializedObject());
4252 
4253       if (value_info->kind() == TranslatedValue::kCapturedObject) {
4254         Handle<Object> object(previously_materialized_objects->get(i),
4255                               isolate_);
4256         CHECK(object->IsHeapObject());
4257         value_info->set_initialized_storage(Handle<HeapObject>::cast(object));
4258       }
4259     }
4260   }
4261 }
4262 
VerifyMaterializedObjects()4263 void TranslatedState::VerifyMaterializedObjects() {
4264 #if VERIFY_HEAP
4265   int length = static_cast<int>(object_positions_.size());
4266   for (int i = 0; i < length; i++) {
4267     TranslatedValue* slot = GetValueByObjectIndex(i);
4268     if (slot->kind() == TranslatedValue::kCapturedObject) {
4269       CHECK_EQ(slot, GetValueByObjectIndex(slot->object_index()));
4270       if (slot->materialization_state() == TranslatedValue::kFinished) {
4271         slot->storage()->ObjectVerify(isolate());
4272       } else {
4273         CHECK_EQ(slot->materialization_state(),
4274                  TranslatedValue::kUninitialized);
4275       }
4276     }
4277   }
4278 #endif
4279 }
4280 
DoUpdateFeedback()4281 bool TranslatedState::DoUpdateFeedback() {
4282   if (!feedback_vector_handle_.is_null()) {
4283     CHECK(!feedback_slot_.IsInvalid());
4284     isolate()->CountUsage(v8::Isolate::kDeoptimizerDisableSpeculation);
4285     FeedbackNexus nexus(feedback_vector_handle_, feedback_slot_);
4286     nexus.SetSpeculationMode(SpeculationMode::kDisallowSpeculation);
4287     return true;
4288   }
4289   return false;
4290 }
4291 
ReadUpdateFeedback(TranslationIterator * iterator,FixedArray literal_array,FILE * trace_file)4292 void TranslatedState::ReadUpdateFeedback(TranslationIterator* iterator,
4293                                          FixedArray literal_array,
4294                                          FILE* trace_file) {
4295   CHECK_EQ(Translation::UPDATE_FEEDBACK, iterator->Next());
4296   feedback_vector_ = FeedbackVector::cast(literal_array.get(iterator->Next()));
4297   feedback_slot_ = FeedbackSlot(iterator->Next());
4298   if (trace_file != nullptr) {
4299     PrintF(trace_file, "  reading FeedbackVector (slot %d)\n",
4300            feedback_slot_.ToInt());
4301   }
4302 }
4303 
4304 }  // namespace internal
4305 }  // namespace v8
4306 
4307 // Undefine the heap manipulation macros.
4308 #include "src/objects/object-macros-undef.h"
4309