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