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