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