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