• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 #ifndef V8_DEOPTIMIZER_DEOPTIMIZER_H_
6 #define V8_DEOPTIMIZER_DEOPTIMIZER_H_
7 
8 #include <stack>
9 #include <vector>
10 
11 #include "src/base/macros.h"
12 #include "src/codegen/label.h"
13 #include "src/codegen/register-arch.h"
14 #include "src/codegen/source-position.h"
15 #include "src/common/assert-scope.h"
16 #include "src/common/globals.h"
17 #include "src/deoptimizer/deoptimize-reason.h"
18 #include "src/diagnostics/code-tracer.h"
19 #include "src/execution/frame-constants.h"
20 #include "src/execution/isolate.h"
21 #include "src/heap/heap.h"
22 #include "src/objects/feedback-vector.h"
23 #include "src/objects/js-function.h"
24 #include "src/objects/shared-function-info.h"
25 #include "src/utils/allocation.h"
26 #include "src/utils/boxed-float.h"
27 #include "src/zone/zone-chunk-list.h"
28 
29 namespace v8 {
30 namespace internal {
31 
32 class FrameDescription;
33 class JavaScriptFrame;
34 class TranslationIterator;
35 class DeoptimizedFrameInfo;
36 class TranslatedFrame;
37 class TranslatedState;
38 class RegisterValues;
39 class MacroAssembler;
40 class StrongRootsEntry;
41 
42 enum class BuiltinContinuationMode;
43 
44 class TranslatedValue {
45  public:
46   // Allocation-free getter of the value.
47   // Returns ReadOnlyRoots::arguments_marker() if allocation would be necessary
48   // to get the value. In the case of numbers, returns a Smi if possible.
49   Object GetRawValue() const;
50 
51   // Convenience wrapper around GetRawValue (checked).
52   int GetSmiValue() const;
53 
54   // Returns the value, possibly materializing it first (and the whole subgraph
55   // reachable from this value). In the case of numbers, returns a Smi if
56   // possible.
57   Handle<Object> GetValue();
58 
59   bool IsMaterializedObject() const;
60   bool IsMaterializableByDebugger() const;
61 
62  private:
63   friend class TranslatedState;
64   friend class TranslatedFrame;
65 
66   enum Kind : uint8_t {
67     kInvalid,
68     kTagged,
69     kInt32,
70     kInt64,
71     kUInt32,
72     kBoolBit,
73     kFloat,
74     kDouble,
75     kCapturedObject,   // Object captured by the escape analysis.
76                        // The number of nested objects can be obtained
77                        // with the DeferredObjectLength() method
78                        // (the values of the nested objects follow
79                        // this value in the depth-first order.)
80     kDuplicatedObject  // Duplicated object of a deferred object.
81   };
82 
83   enum MaterializationState : uint8_t {
84     kUninitialized,
85     kAllocated,  // Storage for the object has been allocated (or
86                  // enqueued for allocation).
87     kFinished,   // The object has been initialized (or enqueued for
88                  // initialization).
89   };
90 
TranslatedValue(TranslatedState * container,Kind kind)91   TranslatedValue(TranslatedState* container, Kind kind)
92       : kind_(kind), container_(container) {}
kind()93   Kind kind() const { return kind_; }
materialization_state()94   MaterializationState materialization_state() const {
95     return materialization_state_;
96   }
97   void Handlify();
98   int GetChildrenCount() const;
99 
100   static TranslatedValue NewDeferredObject(TranslatedState* container,
101                                            int length, int object_index);
102   static TranslatedValue NewDuplicateObject(TranslatedState* container, int id);
103   static TranslatedValue NewFloat(TranslatedState* container, Float32 value);
104   static TranslatedValue NewDouble(TranslatedState* container, Float64 value);
105   static TranslatedValue NewInt32(TranslatedState* container, int32_t value);
106   static TranslatedValue NewInt64(TranslatedState* container, int64_t value);
107   static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value);
108   static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
109   static TranslatedValue NewTagged(TranslatedState* container, Object literal);
110   static TranslatedValue NewInvalid(TranslatedState* container);
111 
112   Isolate* isolate() const;
113 
set_storage(Handle<HeapObject> storage)114   void set_storage(Handle<HeapObject> storage) { storage_ = storage; }
115   void set_initialized_storage(Handle<HeapObject> storage);
mark_finished()116   void mark_finished() { materialization_state_ = kFinished; }
mark_allocated()117   void mark_allocated() { materialization_state_ = kAllocated; }
118 
storage()119   Handle<HeapObject> storage() {
120     DCHECK_NE(materialization_state(), kUninitialized);
121     return storage_;
122   }
123 
124   Kind kind_;
125   MaterializationState materialization_state_ = kUninitialized;
126   TranslatedState* container_;  // This is only needed for materialization of
127                                 // objects and constructing handles (to get
128                                 // to the isolate).
129 
130   Handle<HeapObject> storage_;  // Contains the materialized value or the
131                                 // byte-array that will be later morphed into
132                                 // the materialized object.
133 
134   struct MaterializedObjectInfo {
135     int id_;
136     int length_;  // Applies only to kCapturedObject kinds.
137   };
138 
139   union {
140     // kind kTagged. After handlification it is always nullptr.
141     Object raw_literal_;
142     // kind is kUInt32 or kBoolBit.
143     uint32_t uint32_value_;
144     // kind is kInt32.
145     int32_t int32_value_;
146     // kind is kInt64.
147     int64_t int64_value_;
148     // kind is kFloat
149     Float32 float_value_;
150     // kind is kDouble
151     Float64 double_value_;
152     // kind is kDuplicatedObject or kCapturedObject.
153     MaterializedObjectInfo materialization_info_;
154   };
155 
156   // Checked accessors for the union members.
157   Object raw_literal() const;
158   int32_t int32_value() const;
159   int64_t int64_value() const;
160   uint32_t uint32_value() const;
161   Float32 float_value() const;
162   Float64 double_value() const;
163   int object_length() const;
164   int object_index() const;
165 };
166 
167 class TranslatedFrame {
168  public:
169   enum Kind {
170     kInterpretedFunction,
171     kArgumentsAdaptor,
172     kConstructStub,
173     kBuiltinContinuation,
174     kJavaScriptBuiltinContinuation,
175     kJavaScriptBuiltinContinuationWithCatch,
176     kInvalid
177   };
178 
179   int GetValueCount();
180 
kind()181   Kind kind() const { return kind_; }
node_id()182   BailoutId node_id() const { return node_id_; }
shared_info()183   Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
184 
185   // TODO(jgruber): Simplify/clarify the semantics of this field. The name
186   // `height` is slightly misleading. Yes, this value is related to stack frame
187   // height, but must undergo additional mutations to arrive at the real stack
188   // frame height (e.g.: addition/subtraction of context, accumulator, fixed
189   // frame sizes, padding).
height()190   int height() const { return height_; }
191 
return_value_offset()192   int return_value_offset() const { return return_value_offset_; }
return_value_count()193   int return_value_count() const { return return_value_count_; }
194 
raw_shared_info()195   SharedFunctionInfo raw_shared_info() const {
196     CHECK(!raw_shared_info_.is_null());
197     return raw_shared_info_;
198   }
199 
200   class iterator {
201    public:
202     iterator& operator++() {
203       ++input_index_;
204       AdvanceIterator(&position_);
205       return *this;
206     }
207 
208     iterator operator++(int) {
209       iterator original(position_, input_index_);
210       ++input_index_;
211       AdvanceIterator(&position_);
212       return original;
213     }
214 
215     bool operator==(const iterator& other) const {
216       // Ignore {input_index_} for equality.
217       return position_ == other.position_;
218     }
219     bool operator!=(const iterator& other) const { return !(*this == other); }
220 
221     TranslatedValue& operator*() { return (*position_); }
222     TranslatedValue* operator->() { return &(*position_); }
223     const TranslatedValue& operator*() const { return (*position_); }
224     const TranslatedValue* operator->() const { return &(*position_); }
225 
input_index()226     int input_index() const { return input_index_; }
227 
228    private:
229     friend TranslatedFrame;
230 
231     explicit iterator(std::deque<TranslatedValue>::iterator position,
232                       int input_index = 0)
position_(position)233         : position_(position), input_index_(input_index) {}
234 
235     std::deque<TranslatedValue>::iterator position_;
236     int input_index_;
237   };
238 
239   using reference = TranslatedValue&;
240   using const_reference = TranslatedValue const&;
241 
begin()242   iterator begin() { return iterator(values_.begin()); }
end()243   iterator end() { return iterator(values_.end()); }
244 
front()245   reference front() { return values_.front(); }
front()246   const_reference front() const { return values_.front(); }
247 
248  private:
249   friend class TranslatedState;
250 
251   // Constructor static methods.
252   static TranslatedFrame InterpretedFrame(BailoutId bytecode_offset,
253                                           SharedFunctionInfo shared_info,
254                                           int height, int return_value_offset,
255                                           int return_value_count);
256   static TranslatedFrame AccessorFrame(Kind kind,
257                                        SharedFunctionInfo shared_info);
258   static TranslatedFrame ArgumentsAdaptorFrame(SharedFunctionInfo shared_info,
259                                                int height);
260   static TranslatedFrame ConstructStubFrame(BailoutId bailout_id,
261                                             SharedFunctionInfo shared_info,
262                                             int height);
263   static TranslatedFrame BuiltinContinuationFrame(
264       BailoutId bailout_id, SharedFunctionInfo shared_info, int height);
265   static TranslatedFrame JavaScriptBuiltinContinuationFrame(
266       BailoutId bailout_id, SharedFunctionInfo shared_info, int height);
267   static TranslatedFrame JavaScriptBuiltinContinuationWithCatchFrame(
268       BailoutId bailout_id, SharedFunctionInfo shared_info, int height);
InvalidFrame()269   static TranslatedFrame InvalidFrame() {
270     return TranslatedFrame(kInvalid, SharedFunctionInfo());
271   }
272 
273   static void AdvanceIterator(std::deque<TranslatedValue>::iterator* iter);
274 
275   TranslatedFrame(Kind kind,
276                   SharedFunctionInfo shared_info = SharedFunctionInfo(),
277                   int height = 0, int return_value_offset = 0,
278                   int return_value_count = 0)
kind_(kind)279       : kind_(kind),
280         node_id_(BailoutId::None()),
281         raw_shared_info_(shared_info),
282         height_(height),
283         return_value_offset_(return_value_offset),
284         return_value_count_(return_value_count) {}
285 
Add(const TranslatedValue & value)286   void Add(const TranslatedValue& value) { values_.push_back(value); }
ValueAt(int index)287   TranslatedValue* ValueAt(int index) { return &(values_[index]); }
288   void Handlify();
289 
290   Kind kind_;
291   BailoutId node_id_;
292   SharedFunctionInfo raw_shared_info_;
293   Handle<SharedFunctionInfo> shared_info_;
294   int height_;
295   int return_value_offset_;
296   int return_value_count_;
297 
298   using ValuesContainer = std::deque<TranslatedValue>;
299 
300   ValuesContainer values_;
301 };
302 
303 // Auxiliary class for translating deoptimization values.
304 // Typical usage sequence:
305 //
306 // 1. Construct the instance. This will involve reading out the translations
307 //    and resolving them to values using the supplied frame pointer and
308 //    machine state (registers). This phase is guaranteed not to allocate
309 //    and not to use any HandleScope. Any object pointers will be stored raw.
310 //
311 // 2. Handlify pointers. This will convert all the raw pointers to handles.
312 //
313 // 3. Reading out the frame values.
314 //
315 // Note: After the instance is constructed, it is possible to iterate over
316 // the values eagerly.
317 
318 class TranslatedState {
319  public:
320   TranslatedState() = default;
321   explicit TranslatedState(const JavaScriptFrame* frame);
322 
323   void Prepare(Address stack_frame_pointer);
324 
325   // Store newly materialized values into the isolate.
326   void StoreMaterializedValuesAndDeopt(JavaScriptFrame* frame);
327 
328   using iterator = std::vector<TranslatedFrame>::iterator;
begin()329   iterator begin() { return frames_.begin(); }
end()330   iterator end() { return frames_.end(); }
331 
332   using const_iterator = std::vector<TranslatedFrame>::const_iterator;
begin()333   const_iterator begin() const { return frames_.begin(); }
end()334   const_iterator end() const { return frames_.end(); }
335 
frames()336   std::vector<TranslatedFrame>& frames() { return frames_; }
337 
338   TranslatedFrame* GetFrameFromJSFrameIndex(int jsframe_index);
339   TranslatedFrame* GetArgumentsInfoFromJSFrameIndex(int jsframe_index,
340                                                     int* arguments_count);
341 
isolate()342   Isolate* isolate() { return isolate_; }
343 
344   void Init(Isolate* isolate, Address input_frame_pointer,
345             Address stack_frame_pointer, TranslationIterator* iterator,
346             FixedArray literal_array, RegisterValues* registers,
347             FILE* trace_file, int parameter_count, int actual_argument_count);
348 
349   void VerifyMaterializedObjects();
350   bool DoUpdateFeedback();
351 
352  private:
353   friend TranslatedValue;
354 
355   TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator,
356                                             FixedArray literal_array,
357                                             Address fp, FILE* trace_file);
358   int CreateNextTranslatedValue(int frame_index, TranslationIterator* iterator,
359                                 FixedArray literal_array, Address fp,
360                                 RegisterValues* registers, FILE* trace_file);
361   Address DecompressIfNeeded(intptr_t value);
362   Address ComputeArgumentsPosition(Address input_frame_pointer, int* length);
363   void CreateArgumentsElementsTranslatedValues(int frame_index,
364                                                Address input_frame_pointer,
365                                                CreateArgumentsType type,
366                                                FILE* trace_file);
367 
368   void UpdateFromPreviouslyMaterializedObjects();
369   void MaterializeFixedDoubleArray(TranslatedFrame* frame, int* value_index,
370                                    TranslatedValue* slot, Handle<Map> map);
371   void MaterializeHeapNumber(TranslatedFrame* frame, int* value_index,
372                              TranslatedValue* slot);
373 
374   void EnsureObjectAllocatedAt(TranslatedValue* slot);
375 
376   void SkipSlots(int slots_to_skip, TranslatedFrame* frame, int* value_index);
377 
378   Handle<ByteArray> AllocateStorageFor(TranslatedValue* slot);
379   void EnsureJSObjectAllocated(TranslatedValue* slot, Handle<Map> map);
380   void EnsurePropertiesAllocatedAndMarked(TranslatedValue* properties_slot,
381                                           Handle<Map> map);
382   void EnsureChildrenAllocated(int count, TranslatedFrame* frame,
383                                int* value_index, std::stack<int>* worklist);
384   void EnsureCapturedObjectAllocatedAt(int object_index,
385                                        std::stack<int>* worklist);
386   Handle<HeapObject> InitializeObjectAt(TranslatedValue* slot);
387   void InitializeCapturedObjectAt(int object_index, std::stack<int>* worklist,
388                                   const DisallowHeapAllocation& no_allocation);
389   void InitializeJSObjectAt(TranslatedFrame* frame, int* value_index,
390                             TranslatedValue* slot, Handle<Map> map,
391                             const DisallowHeapAllocation& no_allocation);
392   void InitializeObjectWithTaggedFieldsAt(
393       TranslatedFrame* frame, int* value_index, TranslatedValue* slot,
394       Handle<Map> map, const DisallowHeapAllocation& no_allocation);
395 
396   void ReadUpdateFeedback(TranslationIterator* iterator,
397                           FixedArray literal_array, FILE* trace_file);
398 
399   TranslatedValue* ResolveCapturedObject(TranslatedValue* slot);
400   TranslatedValue* GetValueByObjectIndex(int object_index);
401   Handle<Object> GetValueAndAdvance(TranslatedFrame* frame, int* value_index);
402   TranslatedValue* GetResolvedSlot(TranslatedFrame* frame, int value_index);
403   TranslatedValue* GetResolvedSlotAndAdvance(TranslatedFrame* frame,
404                                              int* value_index);
405 
406   static uint32_t GetUInt32Slot(Address fp, int slot_index);
407   static uint64_t GetUInt64Slot(Address fp, int slot_index);
408   static Float32 GetFloatSlot(Address fp, int slot_index);
409   static Float64 GetDoubleSlot(Address fp, int slot_index);
410 
411   std::vector<TranslatedFrame> frames_;
412   Isolate* isolate_ = nullptr;
413   Address stack_frame_pointer_ = kNullAddress;
414   int formal_parameter_count_;
415   int actual_argument_count_;
416 
417   struct ObjectPosition {
418     int frame_index_;
419     int value_index_;
420   };
421   std::deque<ObjectPosition> object_positions_;
422   Handle<FeedbackVector> feedback_vector_handle_;
423   FeedbackVector feedback_vector_;
424   FeedbackSlot feedback_slot_;
425 };
426 
427 class OptimizedFunctionVisitor {
428  public:
429   virtual ~OptimizedFunctionVisitor() = default;
430   virtual void VisitFunction(JSFunction function) = 0;
431 };
432 
433 class Deoptimizer : public Malloced {
434  public:
435   struct DeoptInfo {
DeoptInfoDeoptInfo436     DeoptInfo(SourcePosition position, DeoptimizeReason deopt_reason,
437               int deopt_id)
438         : position(position), deopt_reason(deopt_reason), deopt_id(deopt_id) {}
439 
440     SourcePosition position;
441     DeoptimizeReason deopt_reason;
442     int deopt_id;
443 
444     static const int kNoDeoptId = -1;
445   };
446 
447   static DeoptInfo GetDeoptInfo(Code code, Address from);
448 
449   static int ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo shared,
450                                                     BailoutId node_id);
451 
452   static const char* MessageFor(DeoptimizeKind kind, bool reuse_code);
453 
output_count()454   int output_count() const { return output_count_; }
455 
456   Handle<JSFunction> function() const;
457   Handle<Code> compiled_code() const;
deopt_kind()458   DeoptimizeKind deopt_kind() const { return deopt_kind_; }
459 
460   // Number of created JS frames. Not all created frames are necessarily JS.
jsframe_count()461   int jsframe_count() const { return jsframe_count_; }
462 
463   bool should_reuse_code() const;
464 
465   static Deoptimizer* New(Address raw_function, DeoptimizeKind kind,
466                           unsigned bailout_id, Address from, int fp_to_sp_delta,
467                           Isolate* isolate);
468   static Deoptimizer* Grab(Isolate* isolate);
469 
470   // The returned object with information on the optimized frame needs to be
471   // freed before another one can be generated.
472   static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
473                                                         int jsframe_index,
474                                                         Isolate* isolate);
475 
476   // Deoptimize the function now. Its current optimized code will never be run
477   // again and any activations of the optimized code will get deoptimized when
478   // execution returns. If {code} is specified then the given code is targeted
479   // instead of the function code (e.g. OSR code not installed on function).
480   static void DeoptimizeFunction(JSFunction function, Code code = Code());
481 
482   // Deoptimize all code in the given isolate.
483   V8_EXPORT_PRIVATE static void DeoptimizeAll(Isolate* isolate);
484 
485   // Deoptimizes all optimized code that has been previously marked
486   // (via code->set_marked_for_deoptimization) and unlinks all functions that
487   // refer to that code.
488   static void DeoptimizeMarkedCode(Isolate* isolate);
489 
490   // Check the given address against a list of allowed addresses, to prevent a
491   // potential attacker from using the frame creation process in the
492   // deoptimizer, in particular the signing process, to gain control over the
493   // program.
494   // When building mksnapshot, always return false.
495   static bool IsValidReturnAddress(Address address);
496 
497   ~Deoptimizer();
498 
499   void MaterializeHeapObjects();
500 
501   static void ComputeOutputFrames(Deoptimizer* deoptimizer);
502 
503   V8_EXPORT_PRIVATE static Builtins::Name GetDeoptimizationEntry(
504       Isolate* isolate, DeoptimizeKind kind);
505 
506   // Returns true if {addr} is a deoptimization entry and stores its type in
507   // {type_out}. Returns false if {addr} is not a deoptimization entry.
508   static bool IsDeoptimizationEntry(Isolate* isolate, Address addr,
509                                     DeoptimizeKind* type_out);
510 
511   // Code generation support.
input_offset()512   static int input_offset() { return offsetof(Deoptimizer, input_); }
output_count_offset()513   static int output_count_offset() {
514     return offsetof(Deoptimizer, output_count_);
515   }
output_offset()516   static int output_offset() { return offsetof(Deoptimizer, output_); }
517 
caller_frame_top_offset()518   static int caller_frame_top_offset() {
519     return offsetof(Deoptimizer, caller_frame_top_);
520   }
521 
522   V8_EXPORT_PRIVATE static int GetDeoptimizedCodeCount(Isolate* isolate);
523 
isolate()524   Isolate* isolate() const { return isolate_; }
525 
526   static constexpr int kMaxNumberOfEntries = 16384;
527 
528   // This marker is passed to Deoptimizer::New as {bailout_id} on platforms
529   // that have fixed deopt sizes (see also kSupportsFixedDeoptExitSizes). The
530   // actual deoptimization id is then calculated from the return address.
531   static constexpr unsigned kFixedExitSizeMarker = kMaxUInt32;
532 
533   // Set to true when the architecture supports deoptimization exit sequences
534   // of a fixed size, that can be sorted so that the deoptimization index is
535   // deduced from the address of the deoptimization exit.
536   // TODO(jgruber): Remove this, and support for variable deopt exit sizes,
537   // once all architectures use fixed exit sizes.
538   V8_EXPORT_PRIVATE static const bool kSupportsFixedDeoptExitSizes;
539 
540   // Size of deoptimization exit sequence. This is only meaningful when
541   // kSupportsFixedDeoptExitSizes is true.
542   V8_EXPORT_PRIVATE static const int kNonLazyDeoptExitSize;
543   V8_EXPORT_PRIVATE static const int kLazyDeoptExitSize;
544 
545   // Tracing.
546   static void TraceMarkForDeoptimization(Code code, const char* reason);
547   static void TraceEvictFromOptimizedCodeCache(SharedFunctionInfo sfi,
548                                                const char* reason);
549 
550  private:
551   friend class FrameWriter;
552   void QueueValueForMaterialization(Address output_address, Object obj,
553                                     const TranslatedFrame::iterator& iterator);
554 
555   Deoptimizer(Isolate* isolate, JSFunction function, DeoptimizeKind kind,
556               unsigned bailout_id, Address from, int fp_to_sp_delta);
557   Code FindOptimizedCode();
558   void DeleteFrameDescriptions();
559 
560   void DoComputeOutputFrames();
561   void DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
562                                  int frame_index, bool goto_catch_handler);
563   void DoComputeArgumentsAdaptorFrame(TranslatedFrame* translated_frame,
564                                       int frame_index);
565   void DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
566                                    int frame_index);
567 
568   static Builtins::Name TrampolineForBuiltinContinuation(
569       BuiltinContinuationMode mode, bool must_handle_result);
570 
571   void DoComputeBuiltinContinuation(TranslatedFrame* translated_frame,
572                                     int frame_index,
573                                     BuiltinContinuationMode mode);
574 
575   unsigned ComputeInputFrameAboveFpFixedSize() const;
576   unsigned ComputeInputFrameSize() const;
577 
578   static unsigned ComputeIncomingArgumentSize(SharedFunctionInfo shared);
579   static unsigned ComputeOutgoingArgumentSize(Code code, unsigned bailout_id);
580 
581   static void MarkAllCodeForContext(NativeContext native_context);
582   static void DeoptimizeMarkedCodeForContext(NativeContext native_context);
583   // Searches the list of known deoptimizing code for a Code object
584   // containing the given address (which is supposedly faster than
585   // searching all code objects).
586   Code FindDeoptimizingCode(Address addr);
587 
588   // Tracing.
tracing_enabled()589   bool tracing_enabled() const { return static_cast<bool>(trace_scope_); }
verbose_tracing_enabled()590   bool verbose_tracing_enabled() const {
591     return FLAG_trace_deopt_verbose && trace_scope_;
592   }
trace_scope()593   CodeTracer::Scope* trace_scope() const { return trace_scope_.get(); }
verbose_trace_scope()594   CodeTracer::Scope* verbose_trace_scope() const {
595     return FLAG_trace_deopt_verbose ? trace_scope() : nullptr;
596   }
597   void TraceDeoptBegin(int optimization_id, int node_id);
598   void TraceDeoptEnd(double deopt_duration);
599 #ifdef DEBUG
600   static void TraceFoundActivation(Isolate* isolate, JSFunction function);
601 #endif
602   static void TraceDeoptAll(Isolate* isolate);
603   static void TraceDeoptMarked(Isolate* isolate);
604 
605   Isolate* isolate_;
606   JSFunction function_;
607   Code compiled_code_;
608   unsigned bailout_id_;
609   DeoptimizeKind deopt_kind_;
610   Address from_;
611   int fp_to_sp_delta_;
612   bool deoptimizing_throw_;
613   int catch_handler_data_;
614   int catch_handler_pc_offset_;
615 
616   // Input frame description.
617   FrameDescription* input_;
618   // Number of output frames.
619   int output_count_;
620   // Number of output js frames.
621   int jsframe_count_;
622   // Array of output frame descriptions.
623   FrameDescription** output_;
624 
625   // Caller frame details computed from input frame.
626   intptr_t caller_frame_top_;
627   intptr_t caller_fp_;
628   intptr_t caller_pc_;
629   intptr_t caller_constant_pool_;
630   intptr_t input_frame_context_;
631 
632   // The argument count of the bottom most frame.
633   int actual_argument_count_;
634 
635   // Key for lookup of previously materialized objects
636   intptr_t stack_fp_;
637 
638   TranslatedState translated_state_;
639   struct ValueToMaterialize {
640     Address output_slot_address_;
641     TranslatedFrame::iterator value_;
642   };
643   std::vector<ValueToMaterialize> values_to_materialize_;
644 
645 #ifdef DEBUG
646   DisallowGarbageCollection* disallow_garbage_collection_;
647 #endif  // DEBUG
648 
649   std::unique_ptr<CodeTracer::Scope> trace_scope_;
650 
651   static const int table_entry_size_;
652 
653   friend class FrameDescription;
654   friend class DeoptimizedFrameInfo;
655 };
656 
657 class RegisterValues {
658  public:
GetRegister(unsigned n)659   intptr_t GetRegister(unsigned n) const {
660 #if DEBUG
661     // This convoluted DCHECK is needed to work around a gcc problem that
662     // improperly detects an array bounds overflow in optimized debug builds
663     // when using a plain DCHECK.
664     if (n >= arraysize(registers_)) {
665       DCHECK(false);
666       return 0;
667     }
668 #endif
669     return registers_[n];
670   }
671 
672   Float32 GetFloatRegister(unsigned n) const;
673 
GetDoubleRegister(unsigned n)674   Float64 GetDoubleRegister(unsigned n) const {
675     DCHECK(n < arraysize(double_registers_));
676     return double_registers_[n];
677   }
678 
SetRegister(unsigned n,intptr_t value)679   void SetRegister(unsigned n, intptr_t value) {
680     DCHECK(n < arraysize(registers_));
681     registers_[n] = value;
682   }
683 
684   intptr_t registers_[Register::kNumRegisters];
685   // Generated code writes directly into the following array, make sure the
686   // element size matches what the machine instructions expect.
687   static_assert(sizeof(Float64) == kDoubleSize, "size mismatch");
688   Float64 double_registers_[DoubleRegister::kNumRegisters];
689 };
690 
691 class FrameDescription {
692  public:
693   explicit FrameDescription(uint32_t frame_size, int parameter_count = 0);
694 
new(size_t size,uint32_t frame_size)695   void* operator new(size_t size, uint32_t frame_size) {
696     // Subtracts kSystemPointerSize, as the member frame_content_ already
697     // supplies the first element of the area to store the frame.
698     return malloc(size + frame_size - kSystemPointerSize);
699   }
700 
delete(void * pointer,uint32_t frame_size)701   void operator delete(void* pointer, uint32_t frame_size) { free(pointer); }
702 
delete(void * description)703   void operator delete(void* description) { free(description); }
704 
GetFrameSize()705   uint32_t GetFrameSize() const {
706     USE(frame_content_);
707     DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
708     return static_cast<uint32_t>(frame_size_);
709   }
710 
GetFrameSlot(unsigned offset)711   intptr_t GetFrameSlot(unsigned offset) {
712     return *GetFrameSlotPointer(offset);
713   }
714 
715   unsigned GetLastArgumentSlotOffset(bool pad_arguments = true) {
716     int parameter_slots = parameter_count();
717     if (pad_arguments && ShouldPadArguments(parameter_slots)) parameter_slots++;
718     return GetFrameSize() - parameter_slots * kSystemPointerSize;
719   }
720 
GetFramePointerAddress()721   Address GetFramePointerAddress() {
722 #ifdef V8_NO_ARGUMENTS_ADAPTOR
723     // We should not pad arguments in the bottom frame, since this
724     // already contain a padding if necessary and it might contain
725     // extra arguments (actual argument count > parameter count).
726     const bool pad_arguments_bottom_frame = false;
727 #else
728     const bool pad_arguments_bottom_frame = true;
729 #endif
730     int fp_offset = GetLastArgumentSlotOffset(pad_arguments_bottom_frame) -
731                     StandardFrameConstants::kCallerSPOffset;
732     return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset));
733   }
734 
GetRegisterValues()735   RegisterValues* GetRegisterValues() { return &register_values_; }
736 
SetFrameSlot(unsigned offset,intptr_t value)737   void SetFrameSlot(unsigned offset, intptr_t value) {
738     *GetFrameSlotPointer(offset) = value;
739   }
740 
741   void SetCallerPc(unsigned offset, intptr_t value);
742 
743   void SetCallerFp(unsigned offset, intptr_t value);
744 
745   void SetCallerConstantPool(unsigned offset, intptr_t value);
746 
GetRegister(unsigned n)747   intptr_t GetRegister(unsigned n) const {
748     return register_values_.GetRegister(n);
749   }
750 
GetDoubleRegister(unsigned n)751   Float64 GetDoubleRegister(unsigned n) const {
752     return register_values_.GetDoubleRegister(n);
753   }
754 
SetRegister(unsigned n,intptr_t value)755   void SetRegister(unsigned n, intptr_t value) {
756     register_values_.SetRegister(n, value);
757   }
758 
GetTop()759   intptr_t GetTop() const { return top_; }
SetTop(intptr_t top)760   void SetTop(intptr_t top) { top_ = top; }
761 
GetPc()762   intptr_t GetPc() const { return pc_; }
763   void SetPc(intptr_t pc);
764 
GetFp()765   intptr_t GetFp() const { return fp_; }
SetFp(intptr_t fp)766   void SetFp(intptr_t fp) { fp_ = fp; }
767 
GetContext()768   intptr_t GetContext() const { return context_; }
SetContext(intptr_t context)769   void SetContext(intptr_t context) { context_ = context; }
770 
GetConstantPool()771   intptr_t GetConstantPool() const { return constant_pool_; }
SetConstantPool(intptr_t constant_pool)772   void SetConstantPool(intptr_t constant_pool) {
773     constant_pool_ = constant_pool;
774   }
775 
SetContinuation(intptr_t pc)776   void SetContinuation(intptr_t pc) { continuation_ = pc; }
777 
778   // Argument count, including receiver.
parameter_count()779   int parameter_count() { return parameter_count_; }
780 
registers_offset()781   static int registers_offset() {
782     return offsetof(FrameDescription, register_values_.registers_);
783   }
784 
double_registers_offset()785   static constexpr int double_registers_offset() {
786     return offsetof(FrameDescription, register_values_.double_registers_);
787   }
788 
frame_size_offset()789   static int frame_size_offset() {
790     return offsetof(FrameDescription, frame_size_);
791   }
792 
pc_offset()793   static int pc_offset() { return offsetof(FrameDescription, pc_); }
794 
continuation_offset()795   static int continuation_offset() {
796     return offsetof(FrameDescription, continuation_);
797   }
798 
frame_content_offset()799   static int frame_content_offset() {
800     return offsetof(FrameDescription, frame_content_);
801   }
802 
803  private:
804   static const uint32_t kZapUint32 = 0xbeeddead;
805 
806   // Frame_size_ must hold a uint32_t value.  It is only a uintptr_t to
807   // keep the variable-size array frame_content_ of type intptr_t at
808   // the end of the structure aligned.
809   uintptr_t frame_size_;  // Number of bytes.
810   int parameter_count_;
811   RegisterValues register_values_;
812   intptr_t top_;
813   intptr_t pc_;
814   intptr_t fp_;
815   intptr_t context_;
816   intptr_t constant_pool_;
817 
818   // Continuation is the PC where the execution continues after
819   // deoptimizing.
820   intptr_t continuation_;
821 
822   // This must be at the end of the object as the object is allocated larger
823   // than its definition indicates to extend this array.
824   intptr_t frame_content_[1];
825 
GetFrameSlotPointer(unsigned offset)826   intptr_t* GetFrameSlotPointer(unsigned offset) {
827     DCHECK(offset < frame_size_);
828     return reinterpret_cast<intptr_t*>(reinterpret_cast<Address>(this) +
829                                        frame_content_offset() + offset);
830   }
831 };
832 
833 class TranslationBuffer {
834  public:
TranslationBuffer(Zone * zone)835   explicit TranslationBuffer(Zone* zone) : contents_(zone) {}
836 
CurrentIndex()837   int CurrentIndex() const { return static_cast<int>(contents_.size()); }
838   void Add(int32_t value);
839 
840   Handle<ByteArray> CreateByteArray(Factory* factory);
841 
842  private:
843   ZoneChunkList<uint8_t> contents_;
844 };
845 
846 class TranslationIterator {
847  public:
848   TranslationIterator(ByteArray buffer, int index);
849 
850   int32_t Next();
851 
852   bool HasNext() const;
853 
Skip(int n)854   void Skip(int n) {
855     for (int i = 0; i < n; i++) Next();
856   }
857 
858  private:
859   ByteArray buffer_;
860   int index_;
861 };
862 
863 #define TRANSLATION_OPCODE_LIST(V)                     \
864   V(BEGIN)                                             \
865   V(INTERPRETED_FRAME)                                 \
866   V(BUILTIN_CONTINUATION_FRAME)                        \
867   V(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME)            \
868   V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME) \
869   V(CONSTRUCT_STUB_FRAME)                              \
870   V(ARGUMENTS_ADAPTOR_FRAME)                           \
871   V(DUPLICATED_OBJECT)                                 \
872   V(ARGUMENTS_ELEMENTS)                                \
873   V(ARGUMENTS_LENGTH)                                  \
874   V(CAPTURED_OBJECT)                                   \
875   V(REGISTER)                                          \
876   V(INT32_REGISTER)                                    \
877   V(INT64_REGISTER)                                    \
878   V(UINT32_REGISTER)                                   \
879   V(BOOL_REGISTER)                                     \
880   V(FLOAT_REGISTER)                                    \
881   V(DOUBLE_REGISTER)                                   \
882   V(STACK_SLOT)                                        \
883   V(INT32_STACK_SLOT)                                  \
884   V(INT64_STACK_SLOT)                                  \
885   V(UINT32_STACK_SLOT)                                 \
886   V(BOOL_STACK_SLOT)                                   \
887   V(FLOAT_STACK_SLOT)                                  \
888   V(DOUBLE_STACK_SLOT)                                 \
889   V(LITERAL)                                           \
890   V(UPDATE_FEEDBACK)
891 
892 class Translation {
893  public:
894 #define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
895   enum Opcode {
896     TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM) LAST = LITERAL
897   };
898 #undef DECLARE_TRANSLATION_OPCODE_ENUM
899 
Translation(TranslationBuffer * buffer,int frame_count,int jsframe_count,int update_feedback_count,Zone * zone)900   Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
901               int update_feedback_count, Zone* zone)
902       : buffer_(buffer), index_(buffer->CurrentIndex()), zone_(zone) {
903     buffer_->Add(BEGIN);
904     buffer_->Add(frame_count);
905     buffer_->Add(jsframe_count);
906     buffer_->Add(update_feedback_count);
907   }
908 
index()909   int index() const { return index_; }
910 
911   // Commands.
912   void BeginInterpretedFrame(BailoutId bytecode_offset, int literal_id,
913                              unsigned height, int return_value_offset,
914                              int return_value_count);
915   void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
916   void BeginConstructStubFrame(BailoutId bailout_id, int literal_id,
917                                unsigned height);
918   void BeginBuiltinContinuationFrame(BailoutId bailout_id, int literal_id,
919                                      unsigned height);
920   void BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,
921                                                int literal_id, unsigned height);
922   void BeginJavaScriptBuiltinContinuationWithCatchFrame(BailoutId bailout_id,
923                                                         int literal_id,
924                                                         unsigned height);
925   void ArgumentsElements(CreateArgumentsType type);
926   void ArgumentsLength();
927   void BeginCapturedObject(int length);
928   void AddUpdateFeedback(int vector_literal, int slot);
929   void DuplicateObject(int object_index);
930   void StoreRegister(Register reg);
931   void StoreInt32Register(Register reg);
932   void StoreInt64Register(Register reg);
933   void StoreUint32Register(Register reg);
934   void StoreBoolRegister(Register reg);
935   void StoreFloatRegister(FloatRegister reg);
936   void StoreDoubleRegister(DoubleRegister reg);
937   void StoreStackSlot(int index);
938   void StoreInt32StackSlot(int index);
939   void StoreInt64StackSlot(int index);
940   void StoreUint32StackSlot(int index);
941   void StoreBoolStackSlot(int index);
942   void StoreFloatStackSlot(int index);
943   void StoreDoubleStackSlot(int index);
944   void StoreLiteral(int literal_id);
945   void StoreJSFrameFunction();
946 
zone()947   Zone* zone() const { return zone_; }
948 
949   static int NumberOfOperandsFor(Opcode opcode);
950 
951 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
952   static const char* StringFor(Opcode opcode);
953 #endif
954 
955  private:
956   TranslationBuffer* buffer_;
957   int index_;
958   Zone* zone_;
959 };
960 
961 class MaterializedObjectStore {
962  public:
MaterializedObjectStore(Isolate * isolate)963   explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {}
964 
965   Handle<FixedArray> Get(Address fp);
966   void Set(Address fp, Handle<FixedArray> materialized_objects);
967   bool Remove(Address fp);
968 
969  private:
isolate()970   Isolate* isolate() const { return isolate_; }
971   Handle<FixedArray> GetStackEntries();
972   Handle<FixedArray> EnsureStackEntries(int size);
973 
974   int StackIdToIndex(Address fp);
975 
976   Isolate* isolate_;
977   std::vector<Address> frame_fps_;
978 };
979 
980 // Class used to represent an unoptimized frame when the debugger
981 // needs to inspect a frame that is part of an optimized frame. The
982 // internally used FrameDescription objects are not GC safe so for use
983 // by the debugger frame information is copied to an object of this type.
984 // Represents parameters in unadapted form so their number might mismatch
985 // formal parameter count.
986 class DeoptimizedFrameInfo : public Malloced {
987  public:
988   DeoptimizedFrameInfo(TranslatedState* state,
989                        TranslatedState::iterator frame_it, Isolate* isolate);
990 
991   // Return the number of incoming arguments.
parameters_count()992   int parameters_count() { return static_cast<int>(parameters_.size()); }
993 
994   // Return the height of the expression stack.
expression_count()995   int expression_count() { return static_cast<int>(expression_stack_.size()); }
996 
997   // Get the frame function.
GetFunction()998   Handle<JSFunction> GetFunction() { return function_; }
999 
1000   // Get the frame context.
GetContext()1001   Handle<Object> GetContext() { return context_; }
1002 
1003   // Get an incoming argument.
GetParameter(int index)1004   Handle<Object> GetParameter(int index) {
1005     DCHECK(0 <= index && index < parameters_count());
1006     return parameters_[index];
1007   }
1008 
1009   // Get an expression from the expression stack.
GetExpression(int index)1010   Handle<Object> GetExpression(int index) {
1011     DCHECK(0 <= index && index < expression_count());
1012     return expression_stack_[index];
1013   }
1014 
GetSourcePosition()1015   int GetSourcePosition() { return source_position_; }
1016 
1017  private:
1018   // Set an incoming argument.
SetParameter(int index,Handle<Object> obj)1019   void SetParameter(int index, Handle<Object> obj) {
1020     DCHECK(0 <= index && index < parameters_count());
1021     parameters_[index] = obj;
1022   }
1023 
1024   // Set an expression on the expression stack.
SetExpression(int index,Handle<Object> obj)1025   void SetExpression(int index, Handle<Object> obj) {
1026     DCHECK(0 <= index && index < expression_count());
1027     expression_stack_[index] = obj;
1028   }
1029 
1030   Handle<JSFunction> function_;
1031   Handle<Object> context_;
1032   std::vector<Handle<Object> > parameters_;
1033   std::vector<Handle<Object> > expression_stack_;
1034   int source_position_;
1035 
1036   friend class Deoptimizer;
1037 };
1038 
1039 }  // namespace internal
1040 }  // namespace v8
1041 
1042 #endif  // V8_DEOPTIMIZER_DEOPTIMIZER_H_
1043