Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_DEOPTIMIZER_H_
     29 #define V8_DEOPTIMIZER_H_
     30 
     31 #include "v8.h"
     32 
     33 #include "allocation.h"
     34 #include "macro-assembler.h"
     35 #include "zone-inl.h"
     36 
     37 
     38 namespace v8 {
     39 namespace internal {
     40 
     41 class FrameDescription;
     42 class TranslationIterator;
     43 class DeoptimizingCodeListNode;
     44 class DeoptimizedFrameInfo;
     45 
     46 class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
     47  public:
     48   HeapNumberMaterializationDescriptor(Address slot_address, double val)
     49       : slot_address_(slot_address), val_(val) { }
     50 
     51   Address slot_address() const { return slot_address_; }
     52   double value() const { return val_; }
     53 
     54  private:
     55   Address slot_address_;
     56   double val_;
     57 };
     58 
     59 
     60 class OptimizedFunctionVisitor BASE_EMBEDDED {
     61  public:
     62   virtual ~OptimizedFunctionVisitor() {}
     63 
     64   // Function which is called before iteration of any optimized functions
     65   // from given global context.
     66   virtual void EnterContext(Context* context) = 0;
     67 
     68   virtual void VisitFunction(JSFunction* function) = 0;
     69 
     70   // Function which is called after iteration of all optimized functions
     71   // from given global context.
     72   virtual void LeaveContext(Context* context) = 0;
     73 };
     74 
     75 
     76 class Deoptimizer;
     77 
     78 
     79 class DeoptimizerData {
     80  public:
     81   DeoptimizerData();
     82   ~DeoptimizerData();
     83 
     84 #ifdef ENABLE_DEBUGGER_SUPPORT
     85   void Iterate(ObjectVisitor* v);
     86 #endif
     87 
     88  private:
     89   MemoryChunk* eager_deoptimization_entry_code_;
     90   MemoryChunk* lazy_deoptimization_entry_code_;
     91   Deoptimizer* current_;
     92 
     93 #ifdef ENABLE_DEBUGGER_SUPPORT
     94   DeoptimizedFrameInfo* deoptimized_frame_info_;
     95 #endif
     96 
     97   // List of deoptimized code which still have references from active stack
     98   // frames. These code objects are needed by the deoptimizer when deoptimizing
     99   // a frame for which the code object for the function function has been
    100   // changed from the code present when deoptimizing was done.
    101   DeoptimizingCodeListNode* deoptimizing_code_list_;
    102 
    103   friend class Deoptimizer;
    104 
    105   DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
    106 };
    107 
    108 
    109 class Deoptimizer : public Malloced {
    110  public:
    111   enum BailoutType {
    112     EAGER,
    113     LAZY,
    114     OSR,
    115     // This last bailout type is not really a bailout, but used by the
    116     // debugger to deoptimize stack frames to allow inspection.
    117     DEBUGGER
    118   };
    119 
    120   int output_count() const { return output_count_; }
    121 
    122   // Number of created JS frames. Not all created frames are necessarily JS.
    123   int jsframe_count() const { return jsframe_count_; }
    124 
    125   static Deoptimizer* New(JSFunction* function,
    126                           BailoutType type,
    127                           unsigned bailout_id,
    128                           Address from,
    129                           int fp_to_sp_delta,
    130                           Isolate* isolate);
    131   static Deoptimizer* Grab(Isolate* isolate);
    132 
    133 #ifdef ENABLE_DEBUGGER_SUPPORT
    134   // The returned object with information on the optimized frame needs to be
    135   // freed before another one can be generated.
    136   static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
    137                                                         int jsframe_index,
    138                                                         Isolate* isolate);
    139   static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
    140                                              Isolate* isolate);
    141 #endif
    142 
    143   // Makes sure that there is enough room in the relocation
    144   // information of a code object to perform lazy deoptimization
    145   // patching. If there is not enough room a new relocation
    146   // information object is allocated and comments are added until it
    147   // is big enough.
    148   static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code);
    149 
    150   // Deoptimize the function now. Its current optimized code will never be run
    151   // again and any activations of the optimized code will get deoptimized when
    152   // execution returns.
    153   static void DeoptimizeFunction(JSFunction* function);
    154 
    155   // Deoptimize all functions in the heap.
    156   static void DeoptimizeAll();
    157 
    158   static void DeoptimizeGlobalObject(JSObject* object);
    159 
    160   static void VisitAllOptimizedFunctionsForContext(
    161       Context* context, OptimizedFunctionVisitor* visitor);
    162 
    163   static void VisitAllOptimizedFunctionsForGlobalObject(
    164       JSObject* object, OptimizedFunctionVisitor* visitor);
    165 
    166   static void VisitAllOptimizedFunctions(OptimizedFunctionVisitor* visitor);
    167 
    168   // The size in bytes of the code required at a lazy deopt patch site.
    169   static int patch_size();
    170 
    171   // Patch all stack guard checks in the unoptimized code to
    172   // unconditionally call replacement_code.
    173   static void PatchStackCheckCode(Code* unoptimized_code,
    174                                   Code* check_code,
    175                                   Code* replacement_code);
    176 
    177   // Patch stack guard check at instruction before pc_after in
    178   // the unoptimized code to unconditionally call replacement_code.
    179   static void PatchStackCheckCodeAt(Code* unoptimized_code,
    180                                     Address pc_after,
    181                                     Code* check_code,
    182                                     Code* replacement_code);
    183 
    184   // Change all patched stack guard checks in the unoptimized code
    185   // back to a normal stack guard check.
    186   static void RevertStackCheckCode(Code* unoptimized_code,
    187                                    Code* check_code,
    188                                    Code* replacement_code);
    189 
    190   // Change all patched stack guard checks in the unoptimized code
    191   // back to a normal stack guard check.
    192   static void RevertStackCheckCodeAt(Code* unoptimized_code,
    193                                      Address pc_after,
    194                                      Code* check_code,
    195                                      Code* replacement_code);
    196 
    197   ~Deoptimizer();
    198 
    199   void MaterializeHeapNumbers();
    200 #ifdef ENABLE_DEBUGGER_SUPPORT
    201   void MaterializeHeapNumbersForDebuggerInspectableFrame(
    202       Address parameters_top,
    203       uint32_t parameters_size,
    204       Address expressions_top,
    205       uint32_t expressions_size,
    206       DeoptimizedFrameInfo* info);
    207 #endif
    208 
    209   static void ComputeOutputFrames(Deoptimizer* deoptimizer);
    210 
    211   static Address GetDeoptimizationEntry(int id, BailoutType type);
    212   static int GetDeoptimizationId(Address addr, BailoutType type);
    213   static int GetOutputInfo(DeoptimizationOutputData* data,
    214                            unsigned node_id,
    215                            SharedFunctionInfo* shared);
    216 
    217   // Code generation support.
    218   static int input_offset() { return OFFSET_OF(Deoptimizer, input_); }
    219   static int output_count_offset() {
    220     return OFFSET_OF(Deoptimizer, output_count_);
    221   }
    222   static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
    223 
    224   static int GetDeoptimizedCodeCount(Isolate* isolate);
    225 
    226   static const int kNotDeoptimizationEntry = -1;
    227 
    228   // Generators for the deoptimization entry code.
    229   class EntryGenerator BASE_EMBEDDED {
    230    public:
    231     EntryGenerator(MacroAssembler* masm, BailoutType type)
    232         : masm_(masm), type_(type) { }
    233     virtual ~EntryGenerator() { }
    234 
    235     void Generate();
    236 
    237    protected:
    238     MacroAssembler* masm() const { return masm_; }
    239     BailoutType type() const { return type_; }
    240 
    241     virtual void GeneratePrologue() { }
    242 
    243    private:
    244     MacroAssembler* masm_;
    245     Deoptimizer::BailoutType type_;
    246   };
    247 
    248   class TableEntryGenerator : public EntryGenerator {
    249    public:
    250     TableEntryGenerator(MacroAssembler* masm, BailoutType type,  int count)
    251         : EntryGenerator(masm, type), count_(count) { }
    252 
    253    protected:
    254     virtual void GeneratePrologue();
    255 
    256    private:
    257     int count() const { return count_; }
    258 
    259     int count_;
    260   };
    261 
    262   int ConvertJSFrameIndexToFrameIndex(int jsframe_index);
    263 
    264  private:
    265   static const int kNumberOfEntries = 16384;
    266 
    267   Deoptimizer(Isolate* isolate,
    268               JSFunction* function,
    269               BailoutType type,
    270               unsigned bailout_id,
    271               Address from,
    272               int fp_to_sp_delta,
    273               Code* optimized_code);
    274   void DeleteFrameDescriptions();
    275 
    276   void DoComputeOutputFrames();
    277   void DoComputeOsrOutputFrame();
    278   void DoComputeJSFrame(TranslationIterator* iterator, int frame_index);
    279   void DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
    280                                       int frame_index);
    281   void DoComputeConstructStubFrame(TranslationIterator* iterator,
    282                                    int frame_index);
    283   void DoTranslateCommand(TranslationIterator* iterator,
    284                           int frame_index,
    285                           unsigned output_offset);
    286   // Translate a command for OSR.  Updates the input offset to be used for
    287   // the next command.  Returns false if translation of the command failed
    288   // (e.g., a number conversion failed) and may or may not have updated the
    289   // input offset.
    290   bool DoOsrTranslateCommand(TranslationIterator* iterator,
    291                              int* input_offset);
    292 
    293   unsigned ComputeInputFrameSize() const;
    294   unsigned ComputeFixedSize(JSFunction* function) const;
    295 
    296   unsigned ComputeIncomingArgumentSize(JSFunction* function) const;
    297   unsigned ComputeOutgoingArgumentSize() const;
    298 
    299   Object* ComputeLiteral(int index) const;
    300 
    301   void AddDoubleValue(intptr_t slot_address, double value);
    302 
    303   static MemoryChunk* CreateCode(BailoutType type);
    304   static void GenerateDeoptimizationEntries(
    305       MacroAssembler* masm, int count, BailoutType type);
    306 
    307   // Weak handle callback for deoptimizing code objects.
    308   static void HandleWeakDeoptimizedCode(
    309       v8::Persistent<v8::Value> obj, void* data);
    310   static Code* FindDeoptimizingCodeFromAddress(Address addr);
    311   static void RemoveDeoptimizingCode(Code* code);
    312 
    313   // Fill the input from from a JavaScript frame. This is used when
    314   // the debugger needs to inspect an optimized frame. For normal
    315   // deoptimizations the input frame is filled in generated code.
    316   void FillInputFrame(Address tos, JavaScriptFrame* frame);
    317 
    318   Isolate* isolate_;
    319   JSFunction* function_;
    320   Code* optimized_code_;
    321   unsigned bailout_id_;
    322   BailoutType bailout_type_;
    323   Address from_;
    324   int fp_to_sp_delta_;
    325 
    326   // Input frame description.
    327   FrameDescription* input_;
    328   // Number of output frames.
    329   int output_count_;
    330   // Number of output js frames.
    331   int jsframe_count_;
    332   // Array of output frame descriptions.
    333   FrameDescription** output_;
    334 
    335   List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
    336 
    337   static const int table_entry_size_;
    338 
    339   friend class FrameDescription;
    340   friend class DeoptimizingCodeListNode;
    341   friend class DeoptimizedFrameInfo;
    342 };
    343 
    344 
    345 class FrameDescription {
    346  public:
    347   FrameDescription(uint32_t frame_size,
    348                    JSFunction* function);
    349 
    350   void* operator new(size_t size, uint32_t frame_size) {
    351     // Subtracts kPointerSize, as the member frame_content_ already supplies
    352     // the first element of the area to store the frame.
    353     return malloc(size + frame_size - kPointerSize);
    354   }
    355 
    356   void operator delete(void* pointer, uint32_t frame_size) {
    357     free(pointer);
    358   }
    359 
    360   void operator delete(void* description) {
    361     free(description);
    362   }
    363 
    364   uint32_t GetFrameSize() const {
    365     ASSERT(static_cast<uint32_t>(frame_size_) == frame_size_);
    366     return static_cast<uint32_t>(frame_size_);
    367   }
    368 
    369   JSFunction* GetFunction() const { return function_; }
    370 
    371   unsigned GetOffsetFromSlotIndex(int slot_index);
    372 
    373   intptr_t GetFrameSlot(unsigned offset) {
    374     return *GetFrameSlotPointer(offset);
    375   }
    376 
    377   double GetDoubleFrameSlot(unsigned offset) {
    378     intptr_t* ptr = GetFrameSlotPointer(offset);
    379 #if V8_TARGET_ARCH_MIPS
    380     // Prevent gcc from using load-double (mips ldc1) on (possibly)
    381     // non-64-bit aligned double. Uses two lwc1 instructions.
    382     union conversion {
    383       double d;
    384       uint32_t u[2];
    385     } c;
    386     c.u[0] = *reinterpret_cast<uint32_t*>(ptr);
    387     c.u[1] = *(reinterpret_cast<uint32_t*>(ptr) + 1);
    388     return c.d;
    389 #else
    390     return *reinterpret_cast<double*>(ptr);
    391 #endif
    392   }
    393 
    394   void SetFrameSlot(unsigned offset, intptr_t value) {
    395     *GetFrameSlotPointer(offset) = value;
    396   }
    397 
    398   intptr_t GetRegister(unsigned n) const {
    399     ASSERT(n < ARRAY_SIZE(registers_));
    400     return registers_[n];
    401   }
    402 
    403   double GetDoubleRegister(unsigned n) const {
    404     ASSERT(n < ARRAY_SIZE(double_registers_));
    405     return double_registers_[n];
    406   }
    407 
    408   void SetRegister(unsigned n, intptr_t value) {
    409     ASSERT(n < ARRAY_SIZE(registers_));
    410     registers_[n] = value;
    411   }
    412 
    413   void SetDoubleRegister(unsigned n, double value) {
    414     ASSERT(n < ARRAY_SIZE(double_registers_));
    415     double_registers_[n] = value;
    416   }
    417 
    418   intptr_t GetTop() const { return top_; }
    419   void SetTop(intptr_t top) { top_ = top; }
    420 
    421   intptr_t GetPc() const { return pc_; }
    422   void SetPc(intptr_t pc) { pc_ = pc; }
    423 
    424   intptr_t GetFp() const { return fp_; }
    425   void SetFp(intptr_t fp) { fp_ = fp; }
    426 
    427   intptr_t GetContext() const { return context_; }
    428   void SetContext(intptr_t context) { context_ = context; }
    429 
    430   Smi* GetState() const { return state_; }
    431   void SetState(Smi* state) { state_ = state; }
    432 
    433   void SetContinuation(intptr_t pc) { continuation_ = pc; }
    434 
    435   StackFrame::Type GetFrameType() const { return type_; }
    436   void SetFrameType(StackFrame::Type type) { type_ = type; }
    437 
    438   // Get the incoming arguments count.
    439   int ComputeParametersCount();
    440 
    441   // Get a parameter value for an unoptimized frame.
    442   Object* GetParameter(int index);
    443 
    444   // Get the expression stack height for a unoptimized frame.
    445   unsigned GetExpressionCount();
    446 
    447   // Get the expression stack value for an unoptimized frame.
    448   Object* GetExpression(int index);
    449 
    450   static int registers_offset() {
    451     return OFFSET_OF(FrameDescription, registers_);
    452   }
    453 
    454   static int double_registers_offset() {
    455     return OFFSET_OF(FrameDescription, double_registers_);
    456   }
    457 
    458   static int frame_size_offset() {
    459     return OFFSET_OF(FrameDescription, frame_size_);
    460   }
    461 
    462   static int pc_offset() {
    463     return OFFSET_OF(FrameDescription, pc_);
    464   }
    465 
    466   static int state_offset() {
    467     return OFFSET_OF(FrameDescription, state_);
    468   }
    469 
    470   static int continuation_offset() {
    471     return OFFSET_OF(FrameDescription, continuation_);
    472   }
    473 
    474   static int frame_content_offset() {
    475     return OFFSET_OF(FrameDescription, frame_content_);
    476   }
    477 
    478  private:
    479   static const uint32_t kZapUint32 = 0xbeeddead;
    480 
    481   // Frame_size_ must hold a uint32_t value.  It is only a uintptr_t to
    482   // keep the variable-size array frame_content_ of type intptr_t at
    483   // the end of the structure aligned.
    484   uintptr_t frame_size_;  // Number of bytes.
    485   JSFunction* function_;
    486   intptr_t registers_[Register::kNumRegisters];
    487   double double_registers_[DoubleRegister::kNumAllocatableRegisters];
    488   intptr_t top_;
    489   intptr_t pc_;
    490   intptr_t fp_;
    491   intptr_t context_;
    492   StackFrame::Type type_;
    493   Smi* state_;
    494 #ifdef DEBUG
    495   Code::Kind kind_;
    496 #endif
    497 
    498   // Continuation is the PC where the execution continues after
    499   // deoptimizing.
    500   intptr_t continuation_;
    501 
    502   // This must be at the end of the object as the object is allocated larger
    503   // than it's definition indicate to extend this array.
    504   intptr_t frame_content_[1];
    505 
    506   intptr_t* GetFrameSlotPointer(unsigned offset) {
    507     ASSERT(offset < frame_size_);
    508     return reinterpret_cast<intptr_t*>(
    509         reinterpret_cast<Address>(this) + frame_content_offset() + offset);
    510   }
    511 
    512   int ComputeFixedSize();
    513 };
    514 
    515 
    516 class TranslationBuffer BASE_EMBEDDED {
    517  public:
    518   TranslationBuffer() : contents_(256) { }
    519 
    520   int CurrentIndex() const { return contents_.length(); }
    521   void Add(int32_t value);
    522 
    523   Handle<ByteArray> CreateByteArray();
    524 
    525  private:
    526   ZoneList<uint8_t> contents_;
    527 };
    528 
    529 
    530 class TranslationIterator BASE_EMBEDDED {
    531  public:
    532   TranslationIterator(ByteArray* buffer, int index)
    533       : buffer_(buffer), index_(index) {
    534     ASSERT(index >= 0 && index < buffer->length());
    535   }
    536 
    537   int32_t Next();
    538 
    539   bool HasNext() const { return index_ < buffer_->length(); }
    540 
    541   void Skip(int n) {
    542     for (int i = 0; i < n; i++) Next();
    543   }
    544 
    545  private:
    546   ByteArray* buffer_;
    547   int index_;
    548 };
    549 
    550 
    551 class Translation BASE_EMBEDDED {
    552  public:
    553   enum Opcode {
    554     BEGIN,
    555     JS_FRAME,
    556     CONSTRUCT_STUB_FRAME,
    557     ARGUMENTS_ADAPTOR_FRAME,
    558     REGISTER,
    559     INT32_REGISTER,
    560     DOUBLE_REGISTER,
    561     STACK_SLOT,
    562     INT32_STACK_SLOT,
    563     DOUBLE_STACK_SLOT,
    564     LITERAL,
    565     ARGUMENTS_OBJECT,
    566 
    567     // A prefix indicating that the next command is a duplicate of the one
    568     // that follows it.
    569     DUPLICATE
    570   };
    571 
    572   Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count)
    573       : buffer_(buffer),
    574         index_(buffer->CurrentIndex()) {
    575     buffer_->Add(BEGIN);
    576     buffer_->Add(frame_count);
    577     buffer_->Add(jsframe_count);
    578   }
    579 
    580   int index() const { return index_; }
    581 
    582   // Commands.
    583   void BeginJSFrame(int node_id, int literal_id, unsigned height);
    584   void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
    585   void BeginConstructStubFrame(int literal_id, unsigned height);
    586   void StoreRegister(Register reg);
    587   void StoreInt32Register(Register reg);
    588   void StoreDoubleRegister(DoubleRegister reg);
    589   void StoreStackSlot(int index);
    590   void StoreInt32StackSlot(int index);
    591   void StoreDoubleStackSlot(int index);
    592   void StoreLiteral(int literal_id);
    593   void StoreArgumentsObject();
    594   void MarkDuplicate();
    595 
    596   static int NumberOfOperandsFor(Opcode opcode);
    597 
    598 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
    599   static const char* StringFor(Opcode opcode);
    600 #endif
    601 
    602  private:
    603   TranslationBuffer* buffer_;
    604   int index_;
    605 };
    606 
    607 
    608 // Linked list holding deoptimizing code objects. The deoptimizing code objects
    609 // are kept as weak handles until they are no longer activated on the stack.
    610 class DeoptimizingCodeListNode : public Malloced {
    611  public:
    612   explicit DeoptimizingCodeListNode(Code* code);
    613   ~DeoptimizingCodeListNode();
    614 
    615   DeoptimizingCodeListNode* next() const { return next_; }
    616   void set_next(DeoptimizingCodeListNode* next) { next_ = next; }
    617   Handle<Code> code() const { return code_; }
    618 
    619  private:
    620   // Global (weak) handle to the deoptimizing code object.
    621   Handle<Code> code_;
    622 
    623   // Next pointer for linked list.
    624   DeoptimizingCodeListNode* next_;
    625 };
    626 
    627 
    628 class SlotRef BASE_EMBEDDED {
    629  public:
    630   enum SlotRepresentation {
    631     UNKNOWN,
    632     TAGGED,
    633     INT32,
    634     DOUBLE,
    635     LITERAL
    636   };
    637 
    638   SlotRef()
    639       : addr_(NULL), representation_(UNKNOWN) { }
    640 
    641   SlotRef(Address addr, SlotRepresentation representation)
    642       : addr_(addr), representation_(representation) { }
    643 
    644   explicit SlotRef(Object* literal)
    645       : literal_(literal), representation_(LITERAL) { }
    646 
    647   Handle<Object> GetValue() {
    648     switch (representation_) {
    649       case TAGGED:
    650         return Handle<Object>(Memory::Object_at(addr_));
    651 
    652       case INT32: {
    653         int value = Memory::int32_at(addr_);
    654         if (Smi::IsValid(value)) {
    655           return Handle<Object>(Smi::FromInt(value));
    656         } else {
    657           return Isolate::Current()->factory()->NewNumberFromInt(value);
    658         }
    659       }
    660 
    661       case DOUBLE: {
    662         double value = Memory::double_at(addr_);
    663         return Isolate::Current()->factory()->NewNumber(value);
    664       }
    665 
    666       case LITERAL:
    667         return literal_;
    668 
    669       default:
    670         UNREACHABLE();
    671         return Handle<Object>::null();
    672     }
    673   }
    674 
    675   static Vector<SlotRef> ComputeSlotMappingForArguments(
    676       JavaScriptFrame* frame,
    677       int inlined_frame_index,
    678       int formal_parameter_count);
    679 
    680  private:
    681   Address addr_;
    682   Handle<Object> literal_;
    683   SlotRepresentation representation_;
    684 
    685   static Address SlotAddress(JavaScriptFrame* frame, int slot_index) {
    686     if (slot_index >= 0) {
    687       const int offset = JavaScriptFrameConstants::kLocal0Offset;
    688       return frame->fp() + offset - (slot_index * kPointerSize);
    689     } else {
    690       const int offset = JavaScriptFrameConstants::kLastParameterOffset;
    691       return frame->fp() + offset - ((slot_index + 1) * kPointerSize);
    692     }
    693   }
    694 
    695   static SlotRef ComputeSlotForNextArgument(TranslationIterator* iterator,
    696                                             DeoptimizationInputData* data,
    697                                             JavaScriptFrame* frame);
    698 
    699   static void ComputeSlotsForArguments(
    700       Vector<SlotRef>* args_slots,
    701       TranslationIterator* iterator,
    702       DeoptimizationInputData* data,
    703       JavaScriptFrame* frame);
    704 };
    705 
    706 
    707 #ifdef ENABLE_DEBUGGER_SUPPORT
    708 // Class used to represent an unoptimized frame when the debugger
    709 // needs to inspect a frame that is part of an optimized frame. The
    710 // internally used FrameDescription objects are not GC safe so for use
    711 // by the debugger frame information is copied to an object of this type.
    712 // Represents parameters in unadapted form so their number might mismatch
    713 // formal parameter count.
    714 class DeoptimizedFrameInfo : public Malloced {
    715  public:
    716   DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
    717                        int frame_index,
    718                        bool has_arguments_adaptor,
    719                        bool has_construct_stub);
    720   virtual ~DeoptimizedFrameInfo();
    721 
    722   // GC support.
    723   void Iterate(ObjectVisitor* v);
    724 
    725   // Return the number of incoming arguments.
    726   int parameters_count() { return parameters_count_; }
    727 
    728   // Return the height of the expression stack.
    729   int expression_count() { return expression_count_; }
    730 
    731   // Get the frame function.
    732   JSFunction* GetFunction() {
    733     return function_;
    734   }
    735 
    736   // Check if this frame is preceded by construct stub frame.  The bottom-most
    737   // inlined frame might still be called by an uninlined construct stub.
    738   bool HasConstructStub() {
    739     return has_construct_stub_;
    740   }
    741 
    742   // Get an incoming argument.
    743   Object* GetParameter(int index) {
    744     ASSERT(0 <= index && index < parameters_count());
    745     return parameters_[index];
    746   }
    747 
    748   // Get an expression from the expression stack.
    749   Object* GetExpression(int index) {
    750     ASSERT(0 <= index && index < expression_count());
    751     return expression_stack_[index];
    752   }
    753 
    754   int GetSourcePosition() {
    755     return source_position_;
    756   }
    757 
    758  private:
    759   // Set an incoming argument.
    760   void SetParameter(int index, Object* obj) {
    761     ASSERT(0 <= index && index < parameters_count());
    762     parameters_[index] = obj;
    763   }
    764 
    765   // Set an expression on the expression stack.
    766   void SetExpression(int index, Object* obj) {
    767     ASSERT(0 <= index && index < expression_count());
    768     expression_stack_[index] = obj;
    769   }
    770 
    771   JSFunction* function_;
    772   bool has_construct_stub_;
    773   int parameters_count_;
    774   int expression_count_;
    775   Object** parameters_;
    776   Object** expression_stack_;
    777   int source_position_;
    778 
    779   friend class Deoptimizer;
    780 };
    781 #endif
    782 
    783 } }  // namespace v8::internal
    784 
    785 #endif  // V8_DEOPTIMIZER_H_
    786