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