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/v8.h"
      9 
     10 #include "src/allocation.h"
     11 #include "src/macro-assembler.h"
     12 #include "src/zone-inl.h"
     13 
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 
     19 static inline double read_double_value(Address p) {
     20   double d;
     21   memcpy(&d, p, sizeof(d));
     22   return d;
     23 }
     24 
     25 
     26 class FrameDescription;
     27 class TranslationIterator;
     28 class DeoptimizedFrameInfo;
     29 
     30 template<typename T>
     31 class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
     32  public:
     33   HeapNumberMaterializationDescriptor(T destination, double value)
     34       : destination_(destination), value_(value) { }
     35 
     36   T destination() const { return destination_; }
     37   double value() const { return value_; }
     38 
     39  private:
     40   T destination_;
     41   double value_;
     42 };
     43 
     44 
     45 class ObjectMaterializationDescriptor BASE_EMBEDDED {
     46  public:
     47   ObjectMaterializationDescriptor(
     48       Address slot_address, int frame, int length, int duplicate, bool is_args)
     49       : slot_address_(slot_address),
     50         jsframe_index_(frame),
     51         object_length_(length),
     52         duplicate_object_(duplicate),
     53         is_arguments_(is_args) { }
     54 
     55   Address slot_address() const { return slot_address_; }
     56   int jsframe_index() const { return jsframe_index_; }
     57   int object_length() const { return object_length_; }
     58   int duplicate_object() const { return duplicate_object_; }
     59   bool is_arguments() const { return is_arguments_; }
     60 
     61   // Only used for allocated receivers in DoComputeConstructStubFrame.
     62   void patch_slot_address(intptr_t slot) {
     63     slot_address_ = reinterpret_cast<Address>(slot);
     64   }
     65 
     66  private:
     67   Address slot_address_;
     68   int jsframe_index_;
     69   int object_length_;
     70   int duplicate_object_;
     71   bool is_arguments_;
     72 };
     73 
     74 
     75 class OptimizedFunctionVisitor BASE_EMBEDDED {
     76  public:
     77   virtual ~OptimizedFunctionVisitor() {}
     78 
     79   // Function which is called before iteration of any optimized functions
     80   // from given native context.
     81   virtual void EnterContext(Context* context) = 0;
     82 
     83   virtual void VisitFunction(JSFunction* function) = 0;
     84 
     85   // Function which is called after iteration of all optimized functions
     86   // from given native context.
     87   virtual void LeaveContext(Context* context) = 0;
     88 };
     89 
     90 
     91 class Deoptimizer : public Malloced {
     92  public:
     93   enum BailoutType {
     94     EAGER,
     95     LAZY,
     96     SOFT,
     97     // This last bailout type is not really a bailout, but used by the
     98     // debugger to deoptimize stack frames to allow inspection.
     99     DEBUGGER
    100   };
    101 
    102   static const int kBailoutTypesWithCodeEntry = SOFT + 1;
    103 
    104   struct Reason {
    105     Reason(int r, const char* m, const char* d)
    106         : raw_position(r), mnemonic(m), detail(d) {}
    107 
    108     bool operator==(const Reason& other) const {
    109       return raw_position == other.raw_position &&
    110              CStringEquals(mnemonic, other.mnemonic) &&
    111              CStringEquals(detail, other.detail);
    112     }
    113 
    114     bool operator!=(const Reason& other) const { return !(*this == other); }
    115 
    116     int raw_position;
    117     const char* mnemonic;
    118     const char* detail;
    119   };
    120 
    121   struct JumpTableEntry : public ZoneObject {
    122     inline JumpTableEntry(Address entry, const Reason& the_reason,
    123                           Deoptimizer::BailoutType type, bool frame)
    124         : label(),
    125           address(entry),
    126           reason(the_reason),
    127           bailout_type(type),
    128           needs_frame(frame) {}
    129 
    130     bool IsEquivalentTo(const JumpTableEntry& other) const {
    131       return address == other.address && bailout_type == other.bailout_type &&
    132              needs_frame == other.needs_frame &&
    133              (!FLAG_trace_deopt || reason == other.reason);
    134     }
    135 
    136     Label label;
    137     Address address;
    138     Reason reason;
    139     Deoptimizer::BailoutType bailout_type;
    140     bool needs_frame;
    141   };
    142 
    143   static bool TraceEnabledFor(BailoutType deopt_type,
    144                               StackFrame::Type frame_type);
    145   static const char* MessageFor(BailoutType type);
    146 
    147   int output_count() const { return output_count_; }
    148 
    149   Handle<JSFunction> function() const { return Handle<JSFunction>(function_); }
    150   Handle<Code> compiled_code() const { return Handle<Code>(compiled_code_); }
    151   BailoutType bailout_type() const { return bailout_type_; }
    152 
    153   // Number of created JS frames. Not all created frames are necessarily JS.
    154   int jsframe_count() const { return jsframe_count_; }
    155 
    156   static Deoptimizer* New(JSFunction* function,
    157                           BailoutType type,
    158                           unsigned bailout_id,
    159                           Address from,
    160                           int fp_to_sp_delta,
    161                           Isolate* isolate);
    162   static Deoptimizer* Grab(Isolate* isolate);
    163 
    164   // The returned object with information on the optimized frame needs to be
    165   // freed before another one can be generated.
    166   static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
    167                                                         int jsframe_index,
    168                                                         Isolate* isolate);
    169   static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
    170                                              Isolate* isolate);
    171 
    172   // Makes sure that there is enough room in the relocation
    173   // information of a code object to perform lazy deoptimization
    174   // patching. If there is not enough room a new relocation
    175   // information object is allocated and comments are added until it
    176   // is big enough.
    177   static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code);
    178 
    179   // Deoptimize the function now. Its current optimized code will never be run
    180   // again and any activations of the optimized code will get deoptimized when
    181   // execution returns.
    182   static void DeoptimizeFunction(JSFunction* function);
    183 
    184   // Deoptimize all code in the given isolate.
    185   static void DeoptimizeAll(Isolate* isolate);
    186 
    187   // Deoptimize code associated with the given global object.
    188   static void DeoptimizeGlobalObject(JSObject* object);
    189 
    190   // Deoptimizes all optimized code that has been previously marked
    191   // (via code->set_marked_for_deoptimization) and unlinks all functions that
    192   // refer to that code.
    193   static void DeoptimizeMarkedCode(Isolate* isolate);
    194 
    195   // Visit all the known optimized functions in a given isolate.
    196   static void VisitAllOptimizedFunctions(
    197       Isolate* isolate, OptimizedFunctionVisitor* visitor);
    198 
    199   // The size in bytes of the code required at a lazy deopt patch site.
    200   static int patch_size();
    201 
    202   ~Deoptimizer();
    203 
    204   void MaterializeHeapObjects(JavaScriptFrameIterator* it);
    205 
    206   void MaterializeHeapNumbersForDebuggerInspectableFrame(
    207       Address parameters_top,
    208       uint32_t parameters_size,
    209       Address expressions_top,
    210       uint32_t expressions_size,
    211       DeoptimizedFrameInfo* info);
    212 
    213   static void ComputeOutputFrames(Deoptimizer* deoptimizer);
    214 
    215 
    216   enum GetEntryMode {
    217     CALCULATE_ENTRY_ADDRESS,
    218     ENSURE_ENTRY_CODE
    219   };
    220 
    221 
    222   static Address GetDeoptimizationEntry(
    223       Isolate* isolate,
    224       int id,
    225       BailoutType type,
    226       GetEntryMode mode = ENSURE_ENTRY_CODE);
    227   static int GetDeoptimizationId(Isolate* isolate,
    228                                  Address addr,
    229                                  BailoutType type);
    230   static int GetOutputInfo(DeoptimizationOutputData* data,
    231                            BailoutId node_id,
    232                            SharedFunctionInfo* shared);
    233 
    234   // Code generation support.
    235   static int input_offset() { return OFFSET_OF(Deoptimizer, input_); }
    236   static int output_count_offset() {
    237     return OFFSET_OF(Deoptimizer, output_count_);
    238   }
    239   static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
    240 
    241   static int has_alignment_padding_offset() {
    242     return OFFSET_OF(Deoptimizer, has_alignment_padding_);
    243   }
    244 
    245   static int GetDeoptimizedCodeCount(Isolate* isolate);
    246 
    247   static const int kNotDeoptimizationEntry = -1;
    248 
    249   // Generators for the deoptimization entry code.
    250   class EntryGenerator BASE_EMBEDDED {
    251    public:
    252     EntryGenerator(MacroAssembler* masm, BailoutType type)
    253         : masm_(masm), type_(type) { }
    254     virtual ~EntryGenerator() { }
    255 
    256     void Generate();
    257 
    258    protected:
    259     MacroAssembler* masm() const { return masm_; }
    260     BailoutType type() const { return type_; }
    261     Isolate* isolate() const { return masm_->isolate(); }
    262 
    263     virtual void GeneratePrologue() { }
    264 
    265    private:
    266     MacroAssembler* masm_;
    267     Deoptimizer::BailoutType type_;
    268   };
    269 
    270   class TableEntryGenerator : public EntryGenerator {
    271    public:
    272     TableEntryGenerator(MacroAssembler* masm, BailoutType type,  int count)
    273         : EntryGenerator(masm, type), count_(count) { }
    274 
    275    protected:
    276     virtual void GeneratePrologue();
    277 
    278    private:
    279     int count() const { return count_; }
    280 
    281     int count_;
    282   };
    283 
    284   int ConvertJSFrameIndexToFrameIndex(int jsframe_index);
    285 
    286   static size_t GetMaxDeoptTableSize();
    287 
    288   static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
    289                                                BailoutType type,
    290                                                int max_entry_id);
    291 
    292   Isolate* isolate() const { return isolate_; }
    293 
    294  private:
    295   static const int kMinNumberOfEntries = 64;
    296   static const int kMaxNumberOfEntries = 16384;
    297 
    298   Deoptimizer(Isolate* isolate,
    299               JSFunction* function,
    300               BailoutType type,
    301               unsigned bailout_id,
    302               Address from,
    303               int fp_to_sp_delta,
    304               Code* optimized_code);
    305   Code* FindOptimizedCode(JSFunction* function, Code* optimized_code);
    306   void PrintFunctionName();
    307   void DeleteFrameDescriptions();
    308 
    309   void DoComputeOutputFrames();
    310   void DoComputeJSFrame(TranslationIterator* iterator, int frame_index);
    311   void DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
    312                                       int frame_index);
    313   void DoComputeConstructStubFrame(TranslationIterator* iterator,
    314                                    int frame_index);
    315   void DoComputeAccessorStubFrame(TranslationIterator* iterator,
    316                                   int frame_index,
    317                                   bool is_setter_stub_frame);
    318   void DoComputeCompiledStubFrame(TranslationIterator* iterator,
    319                                   int frame_index);
    320 
    321   // Translate object, store the result into an auxiliary array
    322   // (deferred_objects_tagged_values_).
    323   void DoTranslateObject(TranslationIterator* iterator,
    324                          int object_index,
    325                          int field_index);
    326 
    327   // Translate value, store the result into the given frame slot.
    328   void DoTranslateCommand(TranslationIterator* iterator,
    329                           int frame_index,
    330                           unsigned output_offset);
    331 
    332   // Translate object, do not store the result anywhere (but do update
    333   // the deferred materialization array).
    334   void DoTranslateObjectAndSkip(TranslationIterator* iterator);
    335 
    336   unsigned ComputeInputFrameSize() const;
    337   unsigned ComputeFixedSize(JSFunction* function) const;
    338 
    339   unsigned ComputeIncomingArgumentSize(JSFunction* function) const;
    340   unsigned ComputeOutgoingArgumentSize() const;
    341 
    342   Object* ComputeLiteral(int index) const;
    343 
    344   void AddObjectStart(intptr_t slot_address, int argc, bool is_arguments);
    345   void AddObjectDuplication(intptr_t slot, int object_index);
    346   void AddObjectTaggedValue(intptr_t value);
    347   void AddObjectDoubleValue(double value);
    348   void AddDoubleValue(intptr_t slot_address, double value);
    349 
    350   bool ArgumentsObjectIsAdapted(int object_index) {
    351     ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index);
    352     int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1;
    353     return jsframe_has_adapted_arguments_[reverse_jsframe_index];
    354   }
    355 
    356   Handle<JSFunction> ArgumentsObjectFunction(int object_index) {
    357     ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index);
    358     int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1;
    359     return jsframe_functions_[reverse_jsframe_index];
    360   }
    361 
    362   // Helper function for heap object materialization.
    363   Handle<Object> MaterializeNextHeapObject();
    364   Handle<Object> MaterializeNextValue();
    365 
    366   static void GenerateDeoptimizationEntries(
    367       MacroAssembler* masm, int count, BailoutType type);
    368 
    369   // Marks all the code in the given context for deoptimization.
    370   static void MarkAllCodeForContext(Context* native_context);
    371 
    372   // Visit all the known optimized functions in a given context.
    373   static void VisitAllOptimizedFunctionsForContext(
    374       Context* context, OptimizedFunctionVisitor* visitor);
    375 
    376   // Deoptimizes all code marked in the given context.
    377   static void DeoptimizeMarkedCodeForContext(Context* native_context);
    378 
    379   // Patch the given code so that it will deoptimize itself.
    380   static void PatchCodeForDeoptimization(Isolate* isolate, Code* code);
    381 
    382   // Searches the list of known deoptimizing code for a Code object
    383   // containing the given address (which is supposedly faster than
    384   // searching all code objects).
    385   Code* FindDeoptimizingCode(Address addr);
    386 
    387   // Fill the input from from a JavaScript frame. This is used when
    388   // the debugger needs to inspect an optimized frame. For normal
    389   // deoptimizations the input frame is filled in generated code.
    390   void FillInputFrame(Address tos, JavaScriptFrame* frame);
    391 
    392   // Fill the given output frame's registers to contain the failure handler
    393   // address and the number of parameters for a stub failure trampoline.
    394   void SetPlatformCompiledStubRegisters(FrameDescription* output_frame,
    395                                         CodeStubDescriptor* desc);
    396 
    397   // Fill the given output frame's double registers with the original values
    398   // from the input frame's double registers.
    399   void CopyDoubleRegisters(FrameDescription* output_frame);
    400 
    401   // Determines whether the input frame contains alignment padding by looking
    402   // at the dynamic alignment state slot inside the frame.
    403   bool HasAlignmentPadding(JSFunction* function);
    404 
    405   Isolate* isolate_;
    406   JSFunction* function_;
    407   Code* compiled_code_;
    408   unsigned bailout_id_;
    409   BailoutType bailout_type_;
    410   Address from_;
    411   int fp_to_sp_delta_;
    412   int has_alignment_padding_;
    413 
    414   // Input frame description.
    415   FrameDescription* input_;
    416   // Number of output frames.
    417   int output_count_;
    418   // Number of output js frames.
    419   int jsframe_count_;
    420   // Array of output frame descriptions.
    421   FrameDescription** output_;
    422 
    423   // Deferred values to be materialized.
    424   List<Object*> deferred_objects_tagged_values_;
    425   List<HeapNumberMaterializationDescriptor<int> >
    426       deferred_objects_double_values_;
    427   List<ObjectMaterializationDescriptor> deferred_objects_;
    428   List<HeapNumberMaterializationDescriptor<Address> > deferred_heap_numbers_;
    429 
    430   // Key for lookup of previously materialized objects
    431   Address stack_fp_;
    432   Handle<FixedArray> previously_materialized_objects_;
    433   int prev_materialized_count_;
    434 
    435   // Output frame information. Only used during heap object materialization.
    436   List<Handle<JSFunction> > jsframe_functions_;
    437   List<bool> jsframe_has_adapted_arguments_;
    438 
    439   // Materialized objects. Only used during heap object materialization.
    440   List<Handle<Object> >* materialized_values_;
    441   List<Handle<Object> >* materialized_objects_;
    442   int materialization_value_index_;
    443   int materialization_object_index_;
    444 
    445 #ifdef DEBUG
    446   DisallowHeapAllocation* disallow_heap_allocation_;
    447 #endif  // DEBUG
    448 
    449   CodeTracer::Scope* trace_scope_;
    450 
    451   static const int table_entry_size_;
    452 
    453   friend class FrameDescription;
    454   friend class DeoptimizedFrameInfo;
    455 };
    456 
    457 
    458 class FrameDescription {
    459  public:
    460   FrameDescription(uint32_t frame_size,
    461                    JSFunction* function);
    462 
    463   void* operator new(size_t size, uint32_t frame_size) {
    464     // Subtracts kPointerSize, as the member frame_content_ already supplies
    465     // the first element of the area to store the frame.
    466     return malloc(size + frame_size - kPointerSize);
    467   }
    468 
    469   void operator delete(void* pointer, uint32_t frame_size) {
    470     free(pointer);
    471   }
    472 
    473   void operator delete(void* description) {
    474     free(description);
    475   }
    476 
    477   uint32_t GetFrameSize() const {
    478     DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
    479     return static_cast<uint32_t>(frame_size_);
    480   }
    481 
    482   JSFunction* GetFunction() const { return function_; }
    483 
    484   unsigned GetOffsetFromSlotIndex(int slot_index);
    485 
    486   intptr_t GetFrameSlot(unsigned offset) {
    487     return *GetFrameSlotPointer(offset);
    488   }
    489 
    490   double GetDoubleFrameSlot(unsigned offset) {
    491     intptr_t* ptr = GetFrameSlotPointer(offset);
    492     return read_double_value(reinterpret_cast<Address>(ptr));
    493   }
    494 
    495   void SetFrameSlot(unsigned offset, intptr_t value) {
    496     *GetFrameSlotPointer(offset) = value;
    497   }
    498 
    499   void SetCallerPc(unsigned offset, intptr_t value);
    500 
    501   void SetCallerFp(unsigned offset, intptr_t value);
    502 
    503   void SetCallerConstantPool(unsigned offset, intptr_t value);
    504 
    505   intptr_t GetRegister(unsigned n) const {
    506 #if DEBUG
    507     // This convoluted DCHECK is needed to work around a gcc problem that
    508     // improperly detects an array bounds overflow in optimized debug builds
    509     // when using a plain DCHECK.
    510     if (n >= arraysize(registers_)) {
    511       DCHECK(false);
    512       return 0;
    513     }
    514 #endif
    515     return registers_[n];
    516   }
    517 
    518   double GetDoubleRegister(unsigned n) const {
    519     DCHECK(n < arraysize(double_registers_));
    520     return double_registers_[n];
    521   }
    522 
    523   void SetRegister(unsigned n, intptr_t value) {
    524     DCHECK(n < arraysize(registers_));
    525     registers_[n] = value;
    526   }
    527 
    528   void SetDoubleRegister(unsigned n, double value) {
    529     DCHECK(n < arraysize(double_registers_));
    530     double_registers_[n] = value;
    531   }
    532 
    533   intptr_t GetTop() const { return top_; }
    534   void SetTop(intptr_t top) { top_ = top; }
    535 
    536   intptr_t GetPc() const { return pc_; }
    537   void SetPc(intptr_t pc) { pc_ = pc; }
    538 
    539   intptr_t GetFp() const { return fp_; }
    540   void SetFp(intptr_t fp) { fp_ = fp; }
    541 
    542   intptr_t GetContext() const { return context_; }
    543   void SetContext(intptr_t context) { context_ = context; }
    544 
    545   intptr_t GetConstantPool() const { return constant_pool_; }
    546   void SetConstantPool(intptr_t constant_pool) {
    547     constant_pool_ = constant_pool;
    548   }
    549 
    550   Smi* GetState() const { return state_; }
    551   void SetState(Smi* state) { state_ = state; }
    552 
    553   void SetContinuation(intptr_t pc) { continuation_ = pc; }
    554 
    555   StackFrame::Type GetFrameType() const { return type_; }
    556   void SetFrameType(StackFrame::Type type) { type_ = type; }
    557 
    558   // Get the incoming arguments count.
    559   int ComputeParametersCount();
    560 
    561   // Get a parameter value for an unoptimized frame.
    562   Object* GetParameter(int index);
    563 
    564   // Get the expression stack height for a unoptimized frame.
    565   unsigned GetExpressionCount();
    566 
    567   // Get the expression stack value for an unoptimized frame.
    568   Object* GetExpression(int index);
    569 
    570   static int registers_offset() {
    571     return OFFSET_OF(FrameDescription, registers_);
    572   }
    573 
    574   static int double_registers_offset() {
    575     return OFFSET_OF(FrameDescription, double_registers_);
    576   }
    577 
    578   static int frame_size_offset() {
    579     return OFFSET_OF(FrameDescription, frame_size_);
    580   }
    581 
    582   static int pc_offset() {
    583     return OFFSET_OF(FrameDescription, pc_);
    584   }
    585 
    586   static int state_offset() {
    587     return OFFSET_OF(FrameDescription, state_);
    588   }
    589 
    590   static int continuation_offset() {
    591     return OFFSET_OF(FrameDescription, continuation_);
    592   }
    593 
    594   static int frame_content_offset() {
    595     return OFFSET_OF(FrameDescription, frame_content_);
    596   }
    597 
    598  private:
    599   static const uint32_t kZapUint32 = 0xbeeddead;
    600 
    601   // Frame_size_ must hold a uint32_t value.  It is only a uintptr_t to
    602   // keep the variable-size array frame_content_ of type intptr_t at
    603   // the end of the structure aligned.
    604   uintptr_t frame_size_;  // Number of bytes.
    605   JSFunction* function_;
    606   intptr_t registers_[Register::kNumRegisters];
    607   double double_registers_[DoubleRegister::kMaxNumRegisters];
    608   intptr_t top_;
    609   intptr_t pc_;
    610   intptr_t fp_;
    611   intptr_t context_;
    612   intptr_t constant_pool_;
    613   StackFrame::Type type_;
    614   Smi* state_;
    615 
    616   // Continuation is the PC where the execution continues after
    617   // deoptimizing.
    618   intptr_t continuation_;
    619 
    620   // This must be at the end of the object as the object is allocated larger
    621   // than it's definition indicate to extend this array.
    622   intptr_t frame_content_[1];
    623 
    624   intptr_t* GetFrameSlotPointer(unsigned offset) {
    625     DCHECK(offset < frame_size_);
    626     return reinterpret_cast<intptr_t*>(
    627         reinterpret_cast<Address>(this) + frame_content_offset() + offset);
    628   }
    629 
    630   int ComputeFixedSize();
    631 };
    632 
    633 
    634 class DeoptimizerData {
    635  public:
    636   explicit DeoptimizerData(MemoryAllocator* allocator);
    637   ~DeoptimizerData();
    638 
    639   void Iterate(ObjectVisitor* v);
    640 
    641  private:
    642   MemoryAllocator* allocator_;
    643   int deopt_entry_code_entries_[Deoptimizer::kBailoutTypesWithCodeEntry];
    644   MemoryChunk* deopt_entry_code_[Deoptimizer::kBailoutTypesWithCodeEntry];
    645 
    646   DeoptimizedFrameInfo* deoptimized_frame_info_;
    647 
    648   Deoptimizer* current_;
    649 
    650   friend class Deoptimizer;
    651 
    652   DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
    653 };
    654 
    655 
    656 class TranslationBuffer BASE_EMBEDDED {
    657  public:
    658   explicit TranslationBuffer(Zone* zone) : contents_(256, zone) { }
    659 
    660   int CurrentIndex() const { return contents_.length(); }
    661   void Add(int32_t value, Zone* zone);
    662 
    663   Handle<ByteArray> CreateByteArray(Factory* factory);
    664 
    665  private:
    666   ZoneList<uint8_t> contents_;
    667 };
    668 
    669 
    670 class TranslationIterator BASE_EMBEDDED {
    671  public:
    672   TranslationIterator(ByteArray* buffer, int index)
    673       : buffer_(buffer), index_(index) {
    674     DCHECK(index >= 0 && index < buffer->length());
    675   }
    676 
    677   int32_t Next();
    678 
    679   bool HasNext() const { return index_ < buffer_->length(); }
    680 
    681   void Skip(int n) {
    682     for (int i = 0; i < n; i++) Next();
    683   }
    684 
    685  private:
    686   ByteArray* buffer_;
    687   int index_;
    688 };
    689 
    690 
    691 #define TRANSLATION_OPCODE_LIST(V)                                             \
    692   V(BEGIN)                                                                     \
    693   V(JS_FRAME)                                                                  \
    694   V(CONSTRUCT_STUB_FRAME)                                                      \
    695   V(GETTER_STUB_FRAME)                                                         \
    696   V(SETTER_STUB_FRAME)                                                         \
    697   V(ARGUMENTS_ADAPTOR_FRAME)                                                   \
    698   V(COMPILED_STUB_FRAME)                                                       \
    699   V(DUPLICATED_OBJECT)                                                         \
    700   V(ARGUMENTS_OBJECT)                                                          \
    701   V(CAPTURED_OBJECT)                                                           \
    702   V(REGISTER)                                                                  \
    703   V(INT32_REGISTER)                                                            \
    704   V(UINT32_REGISTER)                                                           \
    705   V(DOUBLE_REGISTER)                                                           \
    706   V(STACK_SLOT)                                                                \
    707   V(INT32_STACK_SLOT)                                                          \
    708   V(UINT32_STACK_SLOT)                                                         \
    709   V(DOUBLE_STACK_SLOT)                                                         \
    710   V(LITERAL)
    711 
    712 
    713 class Translation BASE_EMBEDDED {
    714  public:
    715 #define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
    716   enum Opcode {
    717     TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
    718     LAST = LITERAL
    719   };
    720 #undef DECLARE_TRANSLATION_OPCODE_ENUM
    721 
    722   Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
    723               Zone* zone)
    724       : buffer_(buffer),
    725         index_(buffer->CurrentIndex()),
    726         zone_(zone) {
    727     buffer_->Add(BEGIN, zone);
    728     buffer_->Add(frame_count, zone);
    729     buffer_->Add(jsframe_count, zone);
    730   }
    731 
    732   int index() const { return index_; }
    733 
    734   // Commands.
    735   void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height);
    736   void BeginCompiledStubFrame();
    737   void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
    738   void BeginConstructStubFrame(int literal_id, unsigned height);
    739   void BeginGetterStubFrame(int literal_id);
    740   void BeginSetterStubFrame(int literal_id);
    741   void BeginArgumentsObject(int args_length);
    742   void BeginCapturedObject(int length);
    743   void DuplicateObject(int object_index);
    744   void StoreRegister(Register reg);
    745   void StoreInt32Register(Register reg);
    746   void StoreUint32Register(Register reg);
    747   void StoreDoubleRegister(DoubleRegister reg);
    748   void StoreStackSlot(int index);
    749   void StoreInt32StackSlot(int index);
    750   void StoreUint32StackSlot(int index);
    751   void StoreDoubleStackSlot(int index);
    752   void StoreLiteral(int literal_id);
    753   void StoreArgumentsObject(bool args_known, int args_index, int args_length);
    754 
    755   Zone* zone() const { return zone_; }
    756 
    757   static int NumberOfOperandsFor(Opcode opcode);
    758 
    759 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
    760   static const char* StringFor(Opcode opcode);
    761 #endif
    762 
    763   // A literal id which refers to the JSFunction itself.
    764   static const int kSelfLiteralId = -239;
    765 
    766  private:
    767   TranslationBuffer* buffer_;
    768   int index_;
    769   Zone* zone_;
    770 };
    771 
    772 
    773 class SlotRef BASE_EMBEDDED {
    774  public:
    775   enum SlotRepresentation {
    776     UNKNOWN,
    777     TAGGED,
    778     INT32,
    779     UINT32,
    780     DOUBLE,
    781     LITERAL,
    782     DEFERRED_OBJECT,   // Object captured by the escape analysis.
    783                        // The number of nested objects can be obtained
    784                        // with the DeferredObjectLength() method
    785                        // (the SlotRefs of the nested objects follow
    786                        // this SlotRef in the depth-first order.)
    787     DUPLICATE_OBJECT,  // Duplicated object of a deferred object.
    788     ARGUMENTS_OBJECT   // Arguments object - only used to keep indexing
    789                        // in sync, it should not be materialized.
    790   };
    791 
    792   SlotRef()
    793       : addr_(NULL), representation_(UNKNOWN) { }
    794 
    795   SlotRef(Address addr, SlotRepresentation representation)
    796       : addr_(addr), representation_(representation) { }
    797 
    798   SlotRef(Isolate* isolate, Object* literal)
    799       : literal_(literal, isolate), representation_(LITERAL) { }
    800 
    801   static SlotRef NewArgumentsObject(int length) {
    802     SlotRef slot;
    803     slot.representation_ = ARGUMENTS_OBJECT;
    804     slot.deferred_object_length_ = length;
    805     return slot;
    806   }
    807 
    808   static SlotRef NewDeferredObject(int length) {
    809     SlotRef slot;
    810     slot.representation_ = DEFERRED_OBJECT;
    811     slot.deferred_object_length_ = length;
    812     return slot;
    813   }
    814 
    815   SlotRepresentation Representation() { return representation_; }
    816 
    817   static SlotRef NewDuplicateObject(int id) {
    818     SlotRef slot;
    819     slot.representation_ = DUPLICATE_OBJECT;
    820     slot.duplicate_object_id_ = id;
    821     return slot;
    822   }
    823 
    824   int GetChildrenCount() {
    825     if (representation_ == DEFERRED_OBJECT ||
    826         representation_ == ARGUMENTS_OBJECT) {
    827       return deferred_object_length_;
    828     } else {
    829       return 0;
    830     }
    831   }
    832 
    833   int DuplicateObjectId() { return duplicate_object_id_; }
    834 
    835   Handle<Object> GetValue(Isolate* isolate);
    836 
    837  private:
    838   Address addr_;
    839   Handle<Object> literal_;
    840   SlotRepresentation representation_;
    841   int deferred_object_length_;
    842   int duplicate_object_id_;
    843 };
    844 
    845 class SlotRefValueBuilder BASE_EMBEDDED {
    846  public:
    847   SlotRefValueBuilder(
    848       JavaScriptFrame* frame,
    849       int inlined_frame_index,
    850       int formal_parameter_count);
    851 
    852   void Prepare(Isolate* isolate);
    853   Handle<Object> GetNext(Isolate* isolate, int level);
    854   void Finish(Isolate* isolate);
    855 
    856   int args_length() { return args_length_; }
    857 
    858  private:
    859   List<Handle<Object> > materialized_objects_;
    860   Handle<FixedArray> previously_materialized_objects_;
    861   int prev_materialized_count_;
    862   Address stack_frame_id_;
    863   List<SlotRef> slot_refs_;
    864   int current_slot_;
    865   int args_length_;
    866   int first_slot_index_;
    867 
    868   static SlotRef ComputeSlotForNextArgument(
    869       Translation::Opcode opcode,
    870       TranslationIterator* iterator,
    871       DeoptimizationInputData* data,
    872       JavaScriptFrame* frame);
    873 
    874   Handle<Object> GetPreviouslyMaterialized(Isolate* isolate, int length);
    875 
    876   static Address SlotAddress(JavaScriptFrame* frame, int slot_index) {
    877     if (slot_index >= 0) {
    878       const int offset = JavaScriptFrameConstants::kLocal0Offset;
    879       return frame->fp() + offset - (slot_index * kPointerSize);
    880     } else {
    881       const int offset = JavaScriptFrameConstants::kLastParameterOffset;
    882       return frame->fp() + offset - ((slot_index + 1) * kPointerSize);
    883     }
    884   }
    885 
    886   Handle<Object> GetDeferredObject(Isolate* isolate);
    887 };
    888 
    889 class MaterializedObjectStore {
    890  public:
    891   explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
    892   }
    893 
    894   Handle<FixedArray> Get(Address fp);
    895   void Set(Address fp, Handle<FixedArray> materialized_objects);
    896   void Remove(Address fp);
    897 
    898  private:
    899   Isolate* isolate() { return isolate_; }
    900   Handle<FixedArray> GetStackEntries();
    901   Handle<FixedArray> EnsureStackEntries(int size);
    902 
    903   int StackIdToIndex(Address fp);
    904 
    905   Isolate* isolate_;
    906   List<Address> frame_fps_;
    907 };
    908 
    909 
    910 // Class used to represent an unoptimized frame when the debugger
    911 // needs to inspect a frame that is part of an optimized frame. The
    912 // internally used FrameDescription objects are not GC safe so for use
    913 // by the debugger frame information is copied to an object of this type.
    914 // Represents parameters in unadapted form so their number might mismatch
    915 // formal parameter count.
    916 class DeoptimizedFrameInfo : public Malloced {
    917  public:
    918   DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
    919                        int frame_index,
    920                        bool has_arguments_adaptor,
    921                        bool has_construct_stub);
    922   virtual ~DeoptimizedFrameInfo();
    923 
    924   // GC support.
    925   void Iterate(ObjectVisitor* v);
    926 
    927   // Return the number of incoming arguments.
    928   int parameters_count() { return parameters_count_; }
    929 
    930   // Return the height of the expression stack.
    931   int expression_count() { return expression_count_; }
    932 
    933   // Get the frame function.
    934   JSFunction* GetFunction() {
    935     return function_;
    936   }
    937 
    938   // Get the frame context.
    939   Object* GetContext() { return context_; }
    940 
    941   // Check if this frame is preceded by construct stub frame.  The bottom-most
    942   // inlined frame might still be called by an uninlined construct stub.
    943   bool HasConstructStub() {
    944     return has_construct_stub_;
    945   }
    946 
    947   // Get an incoming argument.
    948   Object* GetParameter(int index) {
    949     DCHECK(0 <= index && index < parameters_count());
    950     return parameters_[index];
    951   }
    952 
    953   // Get an expression from the expression stack.
    954   Object* GetExpression(int index) {
    955     DCHECK(0 <= index && index < expression_count());
    956     return expression_stack_[index];
    957   }
    958 
    959   int GetSourcePosition() {
    960     return source_position_;
    961   }
    962 
    963  private:
    964   // Set an incoming argument.
    965   void SetParameter(int index, Object* obj) {
    966     DCHECK(0 <= index && index < parameters_count());
    967     parameters_[index] = obj;
    968   }
    969 
    970   // Set an expression on the expression stack.
    971   void SetExpression(int index, Object* obj) {
    972     DCHECK(0 <= index && index < expression_count());
    973     expression_stack_[index] = obj;
    974   }
    975 
    976   JSFunction* function_;
    977   Object* context_;
    978   bool has_construct_stub_;
    979   int parameters_count_;
    980   int expression_count_;
    981   Object** parameters_;
    982   Object** expression_stack_;
    983   int source_position_;
    984 
    985   friend class Deoptimizer;
    986 };
    987 
    988 } }  // namespace v8::internal
    989 
    990 #endif  // V8_DEOPTIMIZER_H_
    991