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