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/allocation.h"
9 #include "src/deoptimize-reason.h"
10 #include "src/macro-assembler.h"
11 #include "src/source-position.h"
12 #include "src/zone/zone-chunk-list.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 class FrameDescription;
18 class TranslationIterator;
19 class DeoptimizedFrameInfo;
20 class TranslatedState;
21 class RegisterValues;
22 
23 class TranslatedValue {
24  public:
25   // Allocation-less getter of the value.
26   // Returns heap()->arguments_marker() if allocation would be
27   // necessary to get the value.
28   Object* GetRawValue() const;
29   Handle<Object> GetValue();
30 
31   bool IsMaterializedObject() const;
32   bool IsMaterializableByDebugger() const;
33 
34  private:
35   friend class TranslatedState;
36   friend class TranslatedFrame;
37 
38   enum Kind {
39     kInvalid,
40     kTagged,
41     kInt32,
42     kUInt32,
43     kBoolBit,
44     kFloat,
45     kDouble,
46     kCapturedObject,    // Object captured by the escape analysis.
47                         // The number of nested objects can be obtained
48                         // with the DeferredObjectLength() method
49                         // (the values of the nested objects follow
50                         // this value in the depth-first order.)
51     kDuplicatedObject,  // Duplicated object of a deferred object.
52     kArgumentsObject    // Arguments object - only used to keep indexing
53                         // in sync, it should not be materialized.
54   };
55 
TranslatedValue(TranslatedState * container,Kind kind)56   TranslatedValue(TranslatedState* container, Kind kind)
57       : kind_(kind), container_(container) {}
kind()58   Kind kind() const { return kind_; }
59   void Handlify();
60   int GetChildrenCount() const;
61 
62   static TranslatedValue NewArgumentsObject(TranslatedState* container,
63                                             int length, int object_index);
64   static TranslatedValue NewDeferredObject(TranslatedState* container,
65                                            int length, int object_index);
66   static TranslatedValue NewDuplicateObject(TranslatedState* container, int id);
67   static TranslatedValue NewFloat(TranslatedState* container, float value);
68   static TranslatedValue NewDouble(TranslatedState* container, double value);
69   static TranslatedValue NewInt32(TranslatedState* container, int32_t value);
70   static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value);
71   static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
72   static TranslatedValue NewTagged(TranslatedState* container, Object* literal);
73   static TranslatedValue NewInvalid(TranslatedState* container);
74 
75   Isolate* isolate() const;
76   void MaterializeSimple();
77 
78   Kind kind_;
79   TranslatedState* container_;  // This is only needed for materialization of
80                                 // objects and constructing handles (to get
81                                 // to the isolate).
82 
83   MaybeHandle<Object> value_;  // Before handlification, this is always null,
84                                // after materialization it is never null,
85                                // in between it is only null if the value needs
86                                // to be materialized.
87 
88   struct MaterializedObjectInfo {
89     int id_;
90     int length_;  // Applies only to kArgumentsObject or kCapturedObject kinds.
91   };
92 
93   union {
94     // kind kTagged. After handlification it is always nullptr.
95     Object* raw_literal_;
96     // kind is kUInt32 or kBoolBit.
97     uint32_t uint32_value_;
98     // kind is kInt32.
99     int32_t int32_value_;
100     // kind is kFloat
101     float float_value_;
102     // kind is kDouble
103     double double_value_;
104     // kind is kDuplicatedObject or kArgumentsObject or kCapturedObject.
105     MaterializedObjectInfo materialization_info_;
106   };
107 
108   // Checked accessors for the union members.
109   Object* raw_literal() const;
110   int32_t int32_value() const;
111   uint32_t uint32_value() const;
112   float float_value() const;
113   double double_value() const;
114   int object_length() const;
115   int object_index() const;
116 };
117 
118 
119 class TranslatedFrame {
120  public:
121   enum Kind {
122     kFunction,
123     kInterpretedFunction,
124     kGetter,
125     kSetter,
126     kTailCallerFunction,
127     kArgumentsAdaptor,
128     kConstructStub,
129     kCompiledStub,
130     kInvalid
131   };
132 
133   int GetValueCount();
134 
kind()135   Kind kind() const { return kind_; }
node_id()136   BailoutId node_id() const { return node_id_; }
shared_info()137   Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
height()138   int height() const { return height_; }
139 
raw_shared_info()140   SharedFunctionInfo* raw_shared_info() const {
141     CHECK_NOT_NULL(raw_shared_info_);
142     return raw_shared_info_;
143   }
144 
145   class iterator {
146    public:
147     iterator& operator++() {
148       AdvanceIterator(&position_);
149       return *this;
150     }
151 
152     iterator operator++(int) {
153       iterator original(position_);
154       AdvanceIterator(&position_);
155       return original;
156     }
157 
158     bool operator==(const iterator& other) const {
159       return position_ == other.position_;
160     }
161     bool operator!=(const iterator& other) const { return !(*this == other); }
162 
163     TranslatedValue& operator*() { return (*position_); }
164     TranslatedValue* operator->() { return &(*position_); }
165 
166    private:
167     friend TranslatedFrame;
168 
iterator(std::deque<TranslatedValue>::iterator position)169     explicit iterator(std::deque<TranslatedValue>::iterator position)
170         : position_(position) {}
171 
172     std::deque<TranslatedValue>::iterator position_;
173   };
174 
175   typedef TranslatedValue& reference;
176   typedef TranslatedValue const& const_reference;
177 
begin()178   iterator begin() { return iterator(values_.begin()); }
end()179   iterator end() { return iterator(values_.end()); }
180 
front()181   reference front() { return values_.front(); }
front()182   const_reference front() const { return values_.front(); }
183 
184  private:
185   friend class TranslatedState;
186 
187   // Constructor static methods.
188   static TranslatedFrame JSFrame(BailoutId node_id,
189                                  SharedFunctionInfo* shared_info, int height);
190   static TranslatedFrame InterpretedFrame(BailoutId bytecode_offset,
191                                           SharedFunctionInfo* shared_info,
192                                           int height);
193   static TranslatedFrame AccessorFrame(Kind kind,
194                                        SharedFunctionInfo* shared_info);
195   static TranslatedFrame ArgumentsAdaptorFrame(SharedFunctionInfo* shared_info,
196                                                int height);
197   static TranslatedFrame TailCallerFrame(SharedFunctionInfo* shared_info);
198   static TranslatedFrame ConstructStubFrame(SharedFunctionInfo* shared_info,
199                                             int height);
CompiledStubFrame(int height,Isolate * isolate)200   static TranslatedFrame CompiledStubFrame(int height, Isolate* isolate) {
201     return TranslatedFrame(kCompiledStub, isolate, nullptr, height);
202   }
InvalidFrame()203   static TranslatedFrame InvalidFrame() {
204     return TranslatedFrame(kInvalid, nullptr);
205   }
206 
207   static void AdvanceIterator(std::deque<TranslatedValue>::iterator* iter);
208 
209   TranslatedFrame(Kind kind, Isolate* isolate,
210                   SharedFunctionInfo* shared_info = nullptr, int height = 0)
kind_(kind)211       : kind_(kind),
212         node_id_(BailoutId::None()),
213         raw_shared_info_(shared_info),
214         height_(height),
215         isolate_(isolate) {}
216 
217 
Add(const TranslatedValue & value)218   void Add(const TranslatedValue& value) { values_.push_back(value); }
219   void Handlify();
220 
221   Kind kind_;
222   BailoutId node_id_;
223   SharedFunctionInfo* raw_shared_info_;
224   Handle<SharedFunctionInfo> shared_info_;
225   int height_;
226   Isolate* isolate_;
227 
228   typedef std::deque<TranslatedValue> ValuesContainer;
229 
230   ValuesContainer values_;
231 };
232 
233 
234 // Auxiliary class for translating deoptimization values.
235 // Typical usage sequence:
236 //
237 // 1. Construct the instance. This will involve reading out the translations
238 //    and resolving them to values using the supplied frame pointer and
239 //    machine state (registers). This phase is guaranteed not to allocate
240 //    and not to use any HandleScope. Any object pointers will be stored raw.
241 //
242 // 2. Handlify pointers. This will convert all the raw pointers to handles.
243 //
244 // 3. Reading out the frame values.
245 //
246 // Note: After the instance is constructed, it is possible to iterate over
247 // the values eagerly.
248 
249 class TranslatedState {
250  public:
251   TranslatedState();
252   explicit TranslatedState(JavaScriptFrame* frame);
253 
254   void Prepare(bool has_adapted_arguments, Address stack_frame_pointer);
255 
256   // Store newly materialized values into the isolate.
257   void StoreMaterializedValuesAndDeopt();
258 
259   typedef std::vector<TranslatedFrame>::iterator iterator;
begin()260   iterator begin() { return frames_.begin(); }
end()261   iterator end() { return frames_.end(); }
262 
263   typedef std::vector<TranslatedFrame>::const_iterator const_iterator;
begin()264   const_iterator begin() const { return frames_.begin(); }
end()265   const_iterator end() const { return frames_.end(); }
266 
frames()267   std::vector<TranslatedFrame>& frames() { return frames_; }
268 
269   TranslatedFrame* GetArgumentsInfoFromJSFrameIndex(int jsframe_index,
270                                                     int* arguments_count);
271 
isolate()272   Isolate* isolate() { return isolate_; }
273 
274   void Init(Address input_frame_pointer, TranslationIterator* iterator,
275             FixedArray* literal_array, RegisterValues* registers,
276             FILE* trace_file);
277 
278  private:
279   friend TranslatedValue;
280 
281   TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator,
282                                             FixedArray* literal_array,
283                                             Address fp,
284                                             FILE* trace_file);
285   TranslatedValue CreateNextTranslatedValue(int frame_index, int value_index,
286                                             TranslationIterator* iterator,
287                                             FixedArray* literal_array,
288                                             Address fp,
289                                             RegisterValues* registers,
290                                             FILE* trace_file);
291 
292   void UpdateFromPreviouslyMaterializedObjects();
293   Handle<Object> MaterializeAt(int frame_index, int* value_index);
294   Handle<Object> MaterializeObjectAt(int object_index);
295   bool GetAdaptedArguments(Handle<JSObject>* result, int frame_index);
296 
297   static uint32_t GetUInt32Slot(Address fp, int slot_index);
298 
299   std::vector<TranslatedFrame> frames_;
300   Isolate* isolate_;
301   Address stack_frame_pointer_;
302   bool has_adapted_arguments_;
303 
304   struct ObjectPosition {
305     int frame_index_;
306     int value_index_;
307   };
308   std::deque<ObjectPosition> object_positions_;
309 };
310 
311 
312 class OptimizedFunctionVisitor BASE_EMBEDDED {
313  public:
~OptimizedFunctionVisitor()314   virtual ~OptimizedFunctionVisitor() {}
315 
316   // Function which is called before iteration of any optimized functions
317   // from given native context.
318   virtual void EnterContext(Context* context) = 0;
319 
320   virtual void VisitFunction(JSFunction* function) = 0;
321 
322   // Function which is called after iteration of all optimized functions
323   // from given native context.
324   virtual void LeaveContext(Context* context) = 0;
325 };
326 
327 class Deoptimizer : public Malloced {
328  public:
329   enum BailoutType { EAGER, LAZY, SOFT, kLastBailoutType = SOFT };
330 
331   enum class BailoutState {
332     NO_REGISTERS,
333     TOS_REGISTER,
334   };
335 
BailoutStateToString(BailoutState state)336   static const char* BailoutStateToString(BailoutState state) {
337     switch (state) {
338       case BailoutState::NO_REGISTERS:
339         return "NO_REGISTERS";
340       case BailoutState::TOS_REGISTER:
341         return "TOS_REGISTER";
342     }
343     UNREACHABLE();
344     return nullptr;
345   }
346 
347   struct DeoptInfo {
DeoptInfoDeoptInfo348     DeoptInfo(SourcePosition position, DeoptimizeReason deopt_reason,
349               int deopt_id)
350         : position(position), deopt_reason(deopt_reason), deopt_id(deopt_id) {}
351 
352     SourcePosition position;
353     DeoptimizeReason deopt_reason;
354     int deopt_id;
355 
356     static const int kNoDeoptId = -1;
357   };
358 
359   static DeoptInfo GetDeoptInfo(Code* code, byte* from);
360 
361   static int ComputeSourcePositionFromBaselineCode(SharedFunctionInfo* shared,
362                                                    BailoutId node_id);
363   static int ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo* shared,
364                                                     BailoutId node_id);
365 
366   struct JumpTableEntry : public ZoneObject {
JumpTableEntryJumpTableEntry367     inline JumpTableEntry(Address entry, const DeoptInfo& deopt_info,
368                           Deoptimizer::BailoutType type, bool frame)
369         : label(),
370           address(entry),
371           deopt_info(deopt_info),
372           bailout_type(type),
373           needs_frame(frame) {}
374 
IsEquivalentToJumpTableEntry375     bool IsEquivalentTo(const JumpTableEntry& other) const {
376       return address == other.address && bailout_type == other.bailout_type &&
377              needs_frame == other.needs_frame;
378     }
379 
380     Label label;
381     Address address;
382     DeoptInfo deopt_info;
383     Deoptimizer::BailoutType bailout_type;
384     bool needs_frame;
385   };
386 
387   static bool TraceEnabledFor(StackFrame::Type frame_type);
388   static const char* MessageFor(BailoutType type);
389 
output_count()390   int output_count() const { return output_count_; }
391 
function()392   Handle<JSFunction> function() const { return Handle<JSFunction>(function_); }
compiled_code()393   Handle<Code> compiled_code() const { return Handle<Code>(compiled_code_); }
bailout_type()394   BailoutType bailout_type() const { return bailout_type_; }
395 
396   // Number of created JS frames. Not all created frames are necessarily JS.
jsframe_count()397   int jsframe_count() const { return jsframe_count_; }
398 
399   static Deoptimizer* New(JSFunction* function,
400                           BailoutType type,
401                           unsigned bailout_id,
402                           Address from,
403                           int fp_to_sp_delta,
404                           Isolate* isolate);
405   static Deoptimizer* Grab(Isolate* isolate);
406 
407   // The returned object with information on the optimized frame needs to be
408   // freed before another one can be generated.
409   static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
410                                                         int jsframe_index,
411                                                         Isolate* isolate);
412 
413   // Makes sure that there is enough room in the relocation
414   // information of a code object to perform lazy deoptimization
415   // patching. If there is not enough room a new relocation
416   // information object is allocated and comments are added until it
417   // is big enough.
418   static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code);
419 
420   // Deoptimize the function now. Its current optimized code will never be run
421   // again and any activations of the optimized code will get deoptimized when
422   // execution returns.
423   static void DeoptimizeFunction(JSFunction* function);
424 
425   // Deoptimize all code in the given isolate.
426   static void DeoptimizeAll(Isolate* isolate);
427 
428   // Deoptimizes all optimized code that has been previously marked
429   // (via code->set_marked_for_deoptimization) and unlinks all functions that
430   // refer to that code.
431   static void DeoptimizeMarkedCode(Isolate* isolate);
432 
433   // Visit all the known optimized functions in a given isolate.
434   static void VisitAllOptimizedFunctions(
435       Isolate* isolate, OptimizedFunctionVisitor* visitor);
436 
437   // The size in bytes of the code required at a lazy deopt patch site.
438   static int patch_size();
439 
440   ~Deoptimizer();
441 
442   void MaterializeHeapObjects(JavaScriptFrameIterator* it);
443 
444   static void ComputeOutputFrames(Deoptimizer* deoptimizer);
445 
446 
447   enum GetEntryMode {
448     CALCULATE_ENTRY_ADDRESS,
449     ENSURE_ENTRY_CODE
450   };
451 
452 
453   static Address GetDeoptimizationEntry(
454       Isolate* isolate,
455       int id,
456       BailoutType type,
457       GetEntryMode mode = ENSURE_ENTRY_CODE);
458   static int GetDeoptimizationId(Isolate* isolate,
459                                  Address addr,
460                                  BailoutType type);
461   static int GetOutputInfo(DeoptimizationOutputData* data,
462                            BailoutId node_id,
463                            SharedFunctionInfo* shared);
464 
465   // Code generation support.
input_offset()466   static int input_offset() { return OFFSET_OF(Deoptimizer, input_); }
output_count_offset()467   static int output_count_offset() {
468     return OFFSET_OF(Deoptimizer, output_count_);
469   }
output_offset()470   static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
471 
caller_frame_top_offset()472   static int caller_frame_top_offset() {
473     return OFFSET_OF(Deoptimizer, caller_frame_top_);
474   }
475 
476   static int GetDeoptimizedCodeCount(Isolate* isolate);
477 
478   static const int kNotDeoptimizationEntry = -1;
479 
480   // Generators for the deoptimization entry code.
481   class TableEntryGenerator BASE_EMBEDDED {
482    public:
TableEntryGenerator(MacroAssembler * masm,BailoutType type,int count)483     TableEntryGenerator(MacroAssembler* masm, BailoutType type, int count)
484         : masm_(masm), type_(type), count_(count) {}
485 
486     void Generate();
487 
488    protected:
masm()489     MacroAssembler* masm() const { return masm_; }
type()490     BailoutType type() const { return type_; }
isolate()491     Isolate* isolate() const { return masm_->isolate(); }
492 
493     void GeneratePrologue();
494 
495    private:
count()496     int count() const { return count_; }
497 
498     MacroAssembler* masm_;
499     Deoptimizer::BailoutType type_;
500     int count_;
501   };
502 
503   static size_t GetMaxDeoptTableSize();
504 
505   static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
506                                                BailoutType type,
507                                                int max_entry_id);
508 
isolate()509   Isolate* isolate() const { return isolate_; }
510 
511  private:
512   static const int kMinNumberOfEntries = 64;
513   static const int kMaxNumberOfEntries = 16384;
514 
515   Deoptimizer(Isolate* isolate, JSFunction* function, BailoutType type,
516               unsigned bailout_id, Address from, int fp_to_sp_delta);
517   Code* FindOptimizedCode(JSFunction* function);
518   void PrintFunctionName();
519   void DeleteFrameDescriptions();
520 
521   void DoComputeOutputFrames();
522   void DoComputeJSFrame(TranslatedFrame* translated_frame, int frame_index,
523                         bool goto_catch_handler);
524   void DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
525                                  int frame_index, bool goto_catch_handler);
526   void DoComputeArgumentsAdaptorFrame(TranslatedFrame* translated_frame,
527                                       int frame_index);
528   void DoComputeTailCallerFrame(TranslatedFrame* translated_frame,
529                                 int frame_index);
530   void DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
531                                    int frame_index);
532   void DoComputeAccessorStubFrame(TranslatedFrame* translated_frame,
533                                   int frame_index, bool is_setter_stub_frame);
534   void DoComputeCompiledStubFrame(TranslatedFrame* translated_frame,
535                                   int frame_index);
536 
537   void WriteTranslatedValueToOutput(
538       TranslatedFrame::iterator* iterator, int* input_index, int frame_index,
539       unsigned output_offset, const char* debug_hint_string = nullptr,
540       Address output_address_for_materialization = nullptr);
541   void WriteValueToOutput(Object* value, int input_index, int frame_index,
542                           unsigned output_offset,
543                           const char* debug_hint_string);
544   void DebugPrintOutputSlot(intptr_t value, int frame_index,
545                             unsigned output_offset,
546                             const char* debug_hint_string);
547 
548   unsigned ComputeInputFrameAboveFpFixedSize() const;
549   unsigned ComputeInputFrameSize() const;
550   static unsigned ComputeJavascriptFixedSize(SharedFunctionInfo* shared);
551   static unsigned ComputeInterpretedFixedSize(SharedFunctionInfo* shared);
552 
553   static unsigned ComputeIncomingArgumentSize(SharedFunctionInfo* shared);
554   static unsigned ComputeOutgoingArgumentSize(Code* code, unsigned bailout_id);
555 
556   static void GenerateDeoptimizationEntries(
557       MacroAssembler* masm, int count, BailoutType type);
558 
559   // Marks all the code in the given context for deoptimization.
560   static void MarkAllCodeForContext(Context* native_context);
561 
562   // Visit all the known optimized functions in a given context.
563   static void VisitAllOptimizedFunctionsForContext(
564       Context* context, OptimizedFunctionVisitor* visitor);
565 
566   // Deoptimizes all code marked in the given context.
567   static void DeoptimizeMarkedCodeForContext(Context* native_context);
568 
569   // Patch the given code so that it will deoptimize itself.
570   static void PatchCodeForDeoptimization(Isolate* isolate, Code* code);
571 
572   // Searches the list of known deoptimizing code for a Code object
573   // containing the given address (which is supposedly faster than
574   // searching all code objects).
575   Code* FindDeoptimizingCode(Address addr);
576 
577   // Fill the given output frame's registers to contain the failure handler
578   // address and the number of parameters for a stub failure trampoline.
579   void SetPlatformCompiledStubRegisters(FrameDescription* output_frame,
580                                         CodeStubDescriptor* desc);
581 
582   // Fill the given output frame's double registers with the original values
583   // from the input frame's double registers.
584   void CopyDoubleRegisters(FrameDescription* output_frame);
585 
586   Isolate* isolate_;
587   JSFunction* function_;
588   Code* compiled_code_;
589   unsigned bailout_id_;
590   BailoutType bailout_type_;
591   Address from_;
592   int fp_to_sp_delta_;
593   bool deoptimizing_throw_;
594   int catch_handler_data_;
595   int catch_handler_pc_offset_;
596 
597   // Input frame description.
598   FrameDescription* input_;
599   // Number of output frames.
600   int output_count_;
601   // Number of output js frames.
602   int jsframe_count_;
603   // Array of output frame descriptions.
604   FrameDescription** output_;
605 
606   // Caller frame details computed from input frame.
607   intptr_t caller_frame_top_;
608   intptr_t caller_fp_;
609   intptr_t caller_pc_;
610   intptr_t caller_constant_pool_;
611   intptr_t input_frame_context_;
612 
613   // Key for lookup of previously materialized objects
614   intptr_t stack_fp_;
615 
616   TranslatedState translated_state_;
617   struct ValueToMaterialize {
618     Address output_slot_address_;
619     TranslatedFrame::iterator value_;
620   };
621   std::vector<ValueToMaterialize> values_to_materialize_;
622 
623 #ifdef DEBUG
624   DisallowHeapAllocation* disallow_heap_allocation_;
625 #endif  // DEBUG
626 
627   CodeTracer::Scope* trace_scope_;
628 
629   static const int table_entry_size_;
630 
631   friend class FrameDescription;
632   friend class DeoptimizedFrameInfo;
633 };
634 
635 
636 class RegisterValues {
637  public:
GetRegister(unsigned n)638   intptr_t GetRegister(unsigned n) const {
639 #if DEBUG
640     // This convoluted DCHECK is needed to work around a gcc problem that
641     // improperly detects an array bounds overflow in optimized debug builds
642     // when using a plain DCHECK.
643     if (n >= arraysize(registers_)) {
644       DCHECK(false);
645       return 0;
646     }
647 #endif
648     return registers_[n];
649   }
650 
GetFloatRegister(unsigned n)651   float GetFloatRegister(unsigned n) const {
652     DCHECK(n < arraysize(float_registers_));
653     return float_registers_[n];
654   }
655 
GetDoubleRegister(unsigned n)656   double GetDoubleRegister(unsigned n) const {
657     DCHECK(n < arraysize(double_registers_));
658     return double_registers_[n];
659   }
660 
SetRegister(unsigned n,intptr_t value)661   void SetRegister(unsigned n, intptr_t value) {
662     DCHECK(n < arraysize(registers_));
663     registers_[n] = value;
664   }
665 
SetFloatRegister(unsigned n,float value)666   void SetFloatRegister(unsigned n, float value) {
667     DCHECK(n < arraysize(float_registers_));
668     float_registers_[n] = value;
669   }
670 
SetDoubleRegister(unsigned n,double value)671   void SetDoubleRegister(unsigned n, double value) {
672     DCHECK(n < arraysize(double_registers_));
673     double_registers_[n] = value;
674   }
675 
676   intptr_t registers_[Register::kNumRegisters];
677   float float_registers_[FloatRegister::kMaxNumRegisters];
678   double double_registers_[DoubleRegister::kMaxNumRegisters];
679 };
680 
681 
682 class FrameDescription {
683  public:
684   explicit FrameDescription(uint32_t frame_size, int parameter_count = 0);
685 
new(size_t size,uint32_t frame_size)686   void* operator new(size_t size, uint32_t frame_size) {
687     // Subtracts kPointerSize, as the member frame_content_ already supplies
688     // the first element of the area to store the frame.
689     return malloc(size + frame_size - kPointerSize);
690   }
691 
delete(void * pointer,uint32_t frame_size)692   void operator delete(void* pointer, uint32_t frame_size) {
693     free(pointer);
694   }
695 
delete(void * description)696   void operator delete(void* description) {
697     free(description);
698   }
699 
GetFrameSize()700   uint32_t GetFrameSize() const {
701     DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
702     return static_cast<uint32_t>(frame_size_);
703   }
704 
GetFrameSlot(unsigned offset)705   intptr_t GetFrameSlot(unsigned offset) {
706     return *GetFrameSlotPointer(offset);
707   }
708 
GetFramePointerAddress()709   Address GetFramePointerAddress() {
710     int fp_offset = GetFrameSize() - parameter_count() * kPointerSize -
711                     StandardFrameConstants::kCallerSPOffset;
712     return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset));
713   }
714 
GetRegisterValues()715   RegisterValues* GetRegisterValues() { return &register_values_; }
716 
SetFrameSlot(unsigned offset,intptr_t value)717   void SetFrameSlot(unsigned offset, intptr_t value) {
718     *GetFrameSlotPointer(offset) = value;
719   }
720 
721   void SetCallerPc(unsigned offset, intptr_t value);
722 
723   void SetCallerFp(unsigned offset, intptr_t value);
724 
725   void SetCallerConstantPool(unsigned offset, intptr_t value);
726 
GetRegister(unsigned n)727   intptr_t GetRegister(unsigned n) const {
728     return register_values_.GetRegister(n);
729   }
730 
GetDoubleRegister(unsigned n)731   double GetDoubleRegister(unsigned n) const {
732     return register_values_.GetDoubleRegister(n);
733   }
734 
SetRegister(unsigned n,intptr_t value)735   void SetRegister(unsigned n, intptr_t value) {
736     register_values_.SetRegister(n, value);
737   }
738 
SetDoubleRegister(unsigned n,double value)739   void SetDoubleRegister(unsigned n, double value) {
740     register_values_.SetDoubleRegister(n, value);
741   }
742 
GetTop()743   intptr_t GetTop() const { return top_; }
SetTop(intptr_t top)744   void SetTop(intptr_t top) { top_ = top; }
745 
GetPc()746   intptr_t GetPc() const { return pc_; }
SetPc(intptr_t pc)747   void SetPc(intptr_t pc) { pc_ = pc; }
748 
GetFp()749   intptr_t GetFp() const { return fp_; }
SetFp(intptr_t fp)750   void SetFp(intptr_t fp) { fp_ = fp; }
751 
GetContext()752   intptr_t GetContext() const { return context_; }
SetContext(intptr_t context)753   void SetContext(intptr_t context) { context_ = context; }
754 
GetConstantPool()755   intptr_t GetConstantPool() const { return constant_pool_; }
SetConstantPool(intptr_t constant_pool)756   void SetConstantPool(intptr_t constant_pool) {
757     constant_pool_ = constant_pool;
758   }
759 
GetState()760   Smi* GetState() const { return state_; }
SetState(Smi * state)761   void SetState(Smi* state) { state_ = state; }
762 
SetContinuation(intptr_t pc)763   void SetContinuation(intptr_t pc) { continuation_ = pc; }
764 
GetFrameType()765   StackFrame::Type GetFrameType() const { return type_; }
SetFrameType(StackFrame::Type type)766   void SetFrameType(StackFrame::Type type) { type_ = type; }
767 
768   // Argument count, including receiver.
parameter_count()769   int parameter_count() { return parameter_count_; }
770 
registers_offset()771   static int registers_offset() {
772     return OFFSET_OF(FrameDescription, register_values_.registers_);
773   }
774 
double_registers_offset()775   static int double_registers_offset() {
776     return OFFSET_OF(FrameDescription, register_values_.double_registers_);
777   }
778 
frame_size_offset()779   static int frame_size_offset() {
780     return offsetof(FrameDescription, frame_size_);
781   }
782 
pc_offset()783   static int pc_offset() { return offsetof(FrameDescription, pc_); }
784 
state_offset()785   static int state_offset() { return offsetof(FrameDescription, state_); }
786 
continuation_offset()787   static int continuation_offset() {
788     return offsetof(FrameDescription, continuation_);
789   }
790 
frame_content_offset()791   static int frame_content_offset() {
792     return offsetof(FrameDescription, frame_content_);
793   }
794 
795  private:
796   static const uint32_t kZapUint32 = 0xbeeddead;
797 
798   // Frame_size_ must hold a uint32_t value.  It is only a uintptr_t to
799   // keep the variable-size array frame_content_ of type intptr_t at
800   // the end of the structure aligned.
801   uintptr_t frame_size_;  // Number of bytes.
802   int parameter_count_;
803   RegisterValues register_values_;
804   intptr_t top_;
805   intptr_t pc_;
806   intptr_t fp_;
807   intptr_t context_;
808   intptr_t constant_pool_;
809   StackFrame::Type type_;
810   Smi* state_;
811 
812   // Continuation is the PC where the execution continues after
813   // deoptimizing.
814   intptr_t continuation_;
815 
816   // This must be at the end of the object as the object is allocated larger
817   // than it's definition indicate to extend this array.
818   intptr_t frame_content_[1];
819 
GetFrameSlotPointer(unsigned offset)820   intptr_t* GetFrameSlotPointer(unsigned offset) {
821     DCHECK(offset < frame_size_);
822     return reinterpret_cast<intptr_t*>(
823         reinterpret_cast<Address>(this) + frame_content_offset() + offset);
824   }
825 };
826 
827 
828 class DeoptimizerData {
829  public:
830   explicit DeoptimizerData(MemoryAllocator* allocator);
831   ~DeoptimizerData();
832 
833  private:
834   MemoryAllocator* allocator_;
835   int deopt_entry_code_entries_[Deoptimizer::kLastBailoutType + 1];
836   MemoryChunk* deopt_entry_code_[Deoptimizer::kLastBailoutType + 1];
837 
838   Deoptimizer* current_;
839 
840   friend class Deoptimizer;
841 
842   DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
843 };
844 
845 
846 class TranslationBuffer BASE_EMBEDDED {
847  public:
TranslationBuffer(Zone * zone)848   explicit TranslationBuffer(Zone* zone) : contents_(zone) {}
849 
CurrentIndex()850   int CurrentIndex() const { return static_cast<int>(contents_.size()); }
851   void Add(int32_t value);
852 
853   Handle<ByteArray> CreateByteArray(Factory* factory);
854 
855  private:
856   ZoneChunkList<uint8_t> contents_;
857 };
858 
859 
860 class TranslationIterator BASE_EMBEDDED {
861  public:
TranslationIterator(ByteArray * buffer,int index)862   TranslationIterator(ByteArray* buffer, int index)
863       : buffer_(buffer), index_(index) {
864     DCHECK(index >= 0 && index < buffer->length());
865   }
866 
867   int32_t Next();
868 
HasNext()869   bool HasNext() const { return index_ < buffer_->length(); }
870 
Skip(int n)871   void Skip(int n) {
872     for (int i = 0; i < n; i++) Next();
873   }
874 
875  private:
876   ByteArray* buffer_;
877   int index_;
878 };
879 
880 #define TRANSLATION_OPCODE_LIST(V) \
881   V(BEGIN)                         \
882   V(JS_FRAME)                      \
883   V(INTERPRETED_FRAME)             \
884   V(CONSTRUCT_STUB_FRAME)          \
885   V(GETTER_STUB_FRAME)             \
886   V(SETTER_STUB_FRAME)             \
887   V(ARGUMENTS_ADAPTOR_FRAME)       \
888   V(TAIL_CALLER_FRAME)             \
889   V(COMPILED_STUB_FRAME)           \
890   V(DUPLICATED_OBJECT)             \
891   V(ARGUMENTS_OBJECT)              \
892   V(CAPTURED_OBJECT)               \
893   V(REGISTER)                      \
894   V(INT32_REGISTER)                \
895   V(UINT32_REGISTER)               \
896   V(BOOL_REGISTER)                 \
897   V(FLOAT_REGISTER)                \
898   V(DOUBLE_REGISTER)               \
899   V(STACK_SLOT)                    \
900   V(INT32_STACK_SLOT)              \
901   V(UINT32_STACK_SLOT)             \
902   V(BOOL_STACK_SLOT)               \
903   V(FLOAT_STACK_SLOT)              \
904   V(DOUBLE_STACK_SLOT)             \
905   V(LITERAL)
906 
907 class Translation BASE_EMBEDDED {
908  public:
909 #define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
910   enum Opcode {
911     TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
912     LAST = LITERAL
913   };
914 #undef DECLARE_TRANSLATION_OPCODE_ENUM
915 
Translation(TranslationBuffer * buffer,int frame_count,int jsframe_count,Zone * zone)916   Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
917               Zone* zone)
918       : buffer_(buffer),
919         index_(buffer->CurrentIndex()),
920         zone_(zone) {
921     buffer_->Add(BEGIN);
922     buffer_->Add(frame_count);
923     buffer_->Add(jsframe_count);
924   }
925 
index()926   int index() const { return index_; }
927 
928   // Commands.
929   void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height);
930   void BeginInterpretedFrame(BailoutId bytecode_offset, int literal_id,
931                              unsigned height);
932   void BeginCompiledStubFrame(int height);
933   void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
934   void BeginTailCallerFrame(int literal_id);
935   void BeginConstructStubFrame(int literal_id, unsigned height);
936   void BeginGetterStubFrame(int literal_id);
937   void BeginSetterStubFrame(int literal_id);
938   void BeginArgumentsObject(int args_length);
939   void BeginCapturedObject(int length);
940   void DuplicateObject(int object_index);
941   void StoreRegister(Register reg);
942   void StoreInt32Register(Register reg);
943   void StoreUint32Register(Register reg);
944   void StoreBoolRegister(Register reg);
945   void StoreFloatRegister(FloatRegister reg);
946   void StoreDoubleRegister(DoubleRegister reg);
947   void StoreStackSlot(int index);
948   void StoreInt32StackSlot(int index);
949   void StoreUint32StackSlot(int index);
950   void StoreBoolStackSlot(int index);
951   void StoreFloatStackSlot(int index);
952   void StoreDoubleStackSlot(int index);
953   void StoreLiteral(int literal_id);
954   void StoreArgumentsObject(bool args_known, int args_index, int args_length);
955   void StoreJSFrameFunction();
956 
zone()957   Zone* zone() const { return zone_; }
958 
959   static int NumberOfOperandsFor(Opcode opcode);
960 
961 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
962   static const char* StringFor(Opcode opcode);
963 #endif
964 
965  private:
966   TranslationBuffer* buffer_;
967   int index_;
968   Zone* zone_;
969 };
970 
971 
972 class MaterializedObjectStore {
973  public:
MaterializedObjectStore(Isolate * isolate)974   explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
975   }
976 
977   Handle<FixedArray> Get(Address fp);
978   void Set(Address fp, Handle<FixedArray> materialized_objects);
979   bool Remove(Address fp);
980 
981  private:
isolate()982   Isolate* isolate() { return isolate_; }
983   Handle<FixedArray> GetStackEntries();
984   Handle<FixedArray> EnsureStackEntries(int size);
985 
986   int StackIdToIndex(Address fp);
987 
988   Isolate* isolate_;
989   List<Address> frame_fps_;
990 };
991 
992 
993 // Class used to represent an unoptimized frame when the debugger
994 // needs to inspect a frame that is part of an optimized frame. The
995 // internally used FrameDescription objects are not GC safe so for use
996 // by the debugger frame information is copied to an object of this type.
997 // Represents parameters in unadapted form so their number might mismatch
998 // formal parameter count.
999 class DeoptimizedFrameInfo : public Malloced {
1000  public:
1001   DeoptimizedFrameInfo(TranslatedState* state,
1002                        TranslatedState::iterator frame_it, Isolate* isolate);
1003 
1004   // Return the number of incoming arguments.
parameters_count()1005   int parameters_count() { return static_cast<int>(parameters_.size()); }
1006 
1007   // Return the height of the expression stack.
expression_count()1008   int expression_count() { return static_cast<int>(expression_stack_.size()); }
1009 
1010   // Get the frame function.
GetFunction()1011   Handle<JSFunction> GetFunction() { return function_; }
1012 
1013   // Get the frame context.
GetContext()1014   Handle<Object> GetContext() { return context_; }
1015 
1016   // Check if this frame is preceded by construct stub frame.  The bottom-most
1017   // inlined frame might still be called by an uninlined construct stub.
HasConstructStub()1018   bool HasConstructStub() {
1019     return has_construct_stub_;
1020   }
1021 
1022   // Get an incoming argument.
GetParameter(int index)1023   Handle<Object> GetParameter(int index) {
1024     DCHECK(0 <= index && index < parameters_count());
1025     return parameters_[index];
1026   }
1027 
1028   // Get an expression from the expression stack.
GetExpression(int index)1029   Handle<Object> GetExpression(int index) {
1030     DCHECK(0 <= index && index < expression_count());
1031     return expression_stack_[index];
1032   }
1033 
GetSourcePosition()1034   int GetSourcePosition() {
1035     return source_position_;
1036   }
1037 
1038  private:
1039   // Set an incoming argument.
SetParameter(int index,Handle<Object> obj)1040   void SetParameter(int index, Handle<Object> obj) {
1041     DCHECK(0 <= index && index < parameters_count());
1042     parameters_[index] = obj;
1043   }
1044 
1045   // Set an expression on the expression stack.
SetExpression(int index,Handle<Object> obj)1046   void SetExpression(int index, Handle<Object> obj) {
1047     DCHECK(0 <= index && index < expression_count());
1048     expression_stack_[index] = obj;
1049   }
1050 
1051   Handle<JSFunction> function_;
1052   Handle<Object> context_;
1053   bool has_construct_stub_;
1054   std::vector<Handle<Object> > parameters_;
1055   std::vector<Handle<Object> > expression_stack_;
1056   int source_position_;
1057 
1058   friend class Deoptimizer;
1059 };
1060 
1061 }  // namespace internal
1062 }  // namespace v8
1063 
1064 #endif  // V8_DEOPTIMIZER_H_
1065