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