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