deoptimizer.h 36.1 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_DEOPTIMIZER_H_
#define V8_DEOPTIMIZER_H_

8
#include <stack>
9 10
#include <vector>

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 26 27 28 29

namespace v8 {
namespace internal {

class FrameDescription;
class TranslationIterator;
30
class DeoptimizedFrameInfo;
31 32 33
class TranslatedState;
class RegisterValues;

jarin's avatar
jarin committed
34
class TranslatedValue {
35 36
 public:
  // Allocation-less getter of the value.
37 38
  // Returns ReadOnlyRoots::arguments_marker() if allocation would be necessary
  // to get the value.
39
  Object* GetRawValue() const;
40 41 42

  // Getter for the value, takes care of materializing the subgraph
  // reachable from this value.
43 44 45
  Handle<Object> GetValue();

  bool IsMaterializedObject() const;
46
  bool IsMaterializableByDebugger() const;
47 48 49 50 51

 private:
  friend class TranslatedState;
  friend class TranslatedFrame;

52
  enum Kind : uint8_t {
53 54 55
    kInvalid,
    kTagged,
    kInt32,
56
    kInt64,
57 58
    kUInt32,
    kBoolBit,
59
    kFloat,
60
    kDouble,
61 62 63 64 65 66
    kCapturedObject,   // Object captured by the escape analysis.
                       // The number of nested objects can be obtained
                       // with the DeferredObjectLength() method
                       // (the values of the nested objects follow
                       // this value in the depth-first order.)
    kDuplicatedObject  // Duplicated object of a deferred object.
67 68
  };

69 70 71 72 73 74 75 76
  enum MaterializationState : uint8_t {
    kUninitialized,
    kAllocated,  // Storage for the object has been allocated (or
                 // enqueued for allocation).
    kFinished,   // The object has been initialized (or enqueued for
                 // initialization).
  };

77 78 79
  TranslatedValue(TranslatedState* container, Kind kind)
      : kind_(kind), container_(container) {}
  Kind kind() const { return kind_; }
80 81 82
  MaterializationState materialization_state() const {
    return materialization_state_;
  }
83 84 85 86 87 88
  void Handlify();
  int GetChildrenCount() const;

  static TranslatedValue NewDeferredObject(TranslatedState* container,
                                           int length, int object_index);
  static TranslatedValue NewDuplicateObject(TranslatedState* container, int id);
89 90
  static TranslatedValue NewFloat(TranslatedState* container, Float32 value);
  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 94 95
  static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value);
  static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
  static TranslatedValue NewTagged(TranslatedState* container, Object* literal);
96
  static TranslatedValue NewInvalid(TranslatedState* container);
97 98 99 100

  Isolate* isolate() const;
  void MaterializeSimple();

101 102 103 104 105 106 107 108 109 110
  void set_storage(Handle<HeapObject> storage) { storage_ = storage; }
  void set_initialized_storage(Handle<Object> storage);
  void mark_finished() { materialization_state_ = kFinished; }
  void mark_allocated() { materialization_state_ = kAllocated; }

  Handle<Object> GetStorage() {
    DCHECK_NE(kUninitialized, materialization_state());
    return storage_;
  }

111
  Kind kind_;
112
  MaterializationState materialization_state_ = kUninitialized;
113 114 115 116
  TranslatedState* container_;  // This is only needed for materialization of
                                // objects and constructing handles (to get
                                // to the isolate).

117 118 119
  Handle<Object> storage_;  // Contains the materialized value or the
                            // byte-array that will be later morphed into
                            // the materialized object.
120 121 122

  struct MaterializedObjectInfo {
    int id_;
123
    int length_;  // Applies only to kCapturedObject kinds.
124 125 126 127 128 129 130 131 132
  };

  union {
    // kind kTagged. After handlification it is always nullptr.
    Object* raw_literal_;
    // kind is kUInt32 or kBoolBit.
    uint32_t uint32_value_;
    // kind is kInt32.
    int32_t int32_value_;
133 134
    // kind is kInt64.
    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 141 142 143 144 145
    MaterializedObjectInfo materialization_info_;
  };

  // Checked accessors for the union members.
  Object* raw_literal() const;
  int32_t int32_value() const;
146
  int64_t int64_value() const;
147
  uint32_t uint32_value() const;
148 149
  Float32 float_value() const;
  Float64 double_value() const;
150 151 152 153 154 155 156 157
  int object_length() const;
  int object_index() const;
};


class TranslatedFrame {
 public:
  enum Kind {
158
    kInterpretedFunction,
159 160
    kArgumentsAdaptor,
    kConstructStub,
161 162
    kBuiltinContinuation,
    kJavaScriptBuiltinContinuation,
163
    kJavaScriptBuiltinContinuationWithCatch,
164 165 166 167 168 169
    kInvalid
  };

  int GetValueCount();

  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

174 175 176 177 178
  SharedFunctionInfo* raw_shared_info() const {
    CHECK_NOT_NULL(raw_shared_info_);
    return raw_shared_info_;
  }

179 180 181
  class iterator {
   public:
    iterator& operator++() {
182
      ++input_index_;
183 184 185 186 187
      AdvanceIterator(&position_);
      return *this;
    }

    iterator operator++(int) {
188
      ++input_index_;
189 190 191 192 193 194
      iterator original(position_);
      AdvanceIterator(&position_);
      return original;
    }

    bool operator==(const iterator& other) const {
195
      // Ignore {input_index_} for equality.
196 197 198 199 200 201
      return position_ == other.position_;
    }
    bool operator!=(const iterator& other) const { return !(*this == other); }

    TranslatedValue& operator*() { return (*position_); }
    TranslatedValue* operator->() { return &(*position_); }
202 203
    const TranslatedValue& operator*() const { return (*position_); }
    const TranslatedValue* operator->() const { return &(*position_); }
204

205 206
    int input_index() const { return input_index_; }

207 208 209 210
   private:
    friend TranslatedFrame;

    explicit iterator(std::deque<TranslatedValue>::iterator position)
211
        : position_(position), input_index_(0) {}
212 213

    std::deque<TranslatedValue>::iterator position_;
214
    int input_index_;
215 216
  };

217 218 219
  typedef TranslatedValue& reference;
  typedef TranslatedValue const& const_reference;

220 221
  iterator begin() { return iterator(values_.begin()); }
  iterator end() { return iterator(values_.end()); }
222

223 224
  reference front() { return values_.front(); }
  const_reference front() const { return values_.front(); }
225 226 227 228 229

 private:
  friend class TranslatedState;

  // Constructor static methods.
230 231 232
  static TranslatedFrame InterpretedFrame(BailoutId bytecode_offset,
                                          SharedFunctionInfo* shared_info,
                                          int height);
233 234 235
  static TranslatedFrame AccessorFrame(Kind kind,
                                       SharedFunctionInfo* shared_info);
  static TranslatedFrame ArgumentsAdaptorFrame(SharedFunctionInfo* shared_info,
236
                                               int height);
237 238
  static TranslatedFrame ConstructStubFrame(BailoutId bailout_id,
                                            SharedFunctionInfo* shared_info,
239
                                            int height);
240 241 242 243
  static TranslatedFrame BuiltinContinuationFrame(
      BailoutId bailout_id, SharedFunctionInfo* shared_info, int height);
  static TranslatedFrame JavaScriptBuiltinContinuationFrame(
      BailoutId bailout_id, SharedFunctionInfo* shared_info, int height);
244 245
  static TranslatedFrame JavaScriptBuiltinContinuationWithCatchFrame(
      BailoutId bailout_id, SharedFunctionInfo* shared_info, int height);
246 247 248 249 250 251
  static TranslatedFrame InvalidFrame() {
    return TranslatedFrame(kInvalid, nullptr);
  }

  static void AdvanceIterator(std::deque<TranslatedValue>::iterator* iter);

252 253
  TranslatedFrame(Kind kind, SharedFunctionInfo* shared_info = nullptr,
                  int height = 0)
254 255
      : kind_(kind),
        node_id_(BailoutId::None()),
256
        raw_shared_info_(shared_info),
257
        height_(height) {}
258 259

  void Add(const TranslatedValue& value) { values_.push_back(value); }
260
  TranslatedValue* ValueAt(int index) { return &(values_[index]); }
261
  void Handlify();
262 263 264

  Kind kind_;
  BailoutId node_id_;
265 266
  SharedFunctionInfo* raw_shared_info_;
  Handle<SharedFunctionInfo> shared_info_;
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
  int height_;

  typedef std::deque<TranslatedValue> ValuesContainer;

  ValuesContainer values_;
};


// Auxiliary class for translating deoptimization values.
// Typical usage sequence:
//
// 1. Construct the instance. This will involve reading out the translations
//    and resolving them to values using the supplied frame pointer and
//    machine state (registers). This phase is guaranteed not to allocate
//    and not to use any HandleScope. Any object pointers will be stored raw.
//
// 2. Handlify pointers. This will convert all the raw pointers to handles.
//
// 3. Reading out the frame values.
//
// Note: After the instance is constructed, it is possible to iterate over
// the values eagerly.

class TranslatedState {
 public:
292
  TranslatedState() = default;
293
  explicit TranslatedState(const JavaScriptFrame* frame);
294

295
  void Prepare(Address stack_frame_pointer);
296 297

  // Store newly materialized values into the isolate.
298
  void StoreMaterializedValuesAndDeopt(JavaScriptFrame* frame);
299

300 301 302 303
  typedef std::vector<TranslatedFrame>::iterator iterator;
  iterator begin() { return frames_.begin(); }
  iterator end() { return frames_.end(); }

304 305 306 307
  typedef std::vector<TranslatedFrame>::const_iterator const_iterator;
  const_iterator begin() const { return frames_.begin(); }
  const_iterator end() const { return frames_.end(); }

308 309
  std::vector<TranslatedFrame>& frames() { return frames_; }

310
  TranslatedFrame* GetFrameFromJSFrameIndex(int jsframe_index);
311 312 313 314 315
  TranslatedFrame* GetArgumentsInfoFromJSFrameIndex(int jsframe_index,
                                                    int* arguments_count);

  Isolate* isolate() { return isolate_; }

316 317 318
  void Init(Isolate* isolate, Address input_frame_pointer,
            TranslationIterator* iterator, FixedArray* literal_array,
            RegisterValues* registers, FILE* trace_file, int parameter_count);
319

320
  void VerifyMaterializedObjects();
321
  bool DoUpdateFeedback();
322

323 324 325 326 327 328 329
 private:
  friend TranslatedValue;

  TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator,
                                            FixedArray* literal_array,
                                            Address fp,
                                            FILE* trace_file);
330 331 332
  int CreateNextTranslatedValue(int frame_index, TranslationIterator* iterator,
                                FixedArray* literal_array, Address fp,
                                RegisterValues* registers, FILE* trace_file);
333 334
  Address ComputeArgumentsPosition(Address input_frame_pointer,
                                   CreateArgumentsType type, int* length);
335 336
  void CreateArgumentsElementsTranslatedValues(int frame_index,
                                               Address input_frame_pointer,
337 338
                                               CreateArgumentsType type,
                                               FILE* trace_file);
339 340

  void UpdateFromPreviouslyMaterializedObjects();
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
  void MaterializeFixedDoubleArray(TranslatedFrame* frame, int* value_index,
                                   TranslatedValue* slot, Handle<Map> map);
  void MaterializeMutableHeapNumber(TranslatedFrame* frame, int* value_index,
                                    TranslatedValue* slot);

  void EnsureObjectAllocatedAt(TranslatedValue* slot);

  void SkipSlots(int slots_to_skip, TranslatedFrame* frame, int* value_index);

  Handle<ByteArray> AllocateStorageFor(TranslatedValue* slot);
  void EnsureJSObjectAllocated(TranslatedValue* slot, Handle<Map> map);
  void EnsurePropertiesAllocatedAndMarked(TranslatedValue* properties_slot,
                                          Handle<Map> map);
  void EnsureChildrenAllocated(int count, TranslatedFrame* frame,
                               int* value_index, std::stack<int>* worklist);
  void EnsureCapturedObjectAllocatedAt(int object_index,
                                       std::stack<int>* worklist);
  Handle<Object> InitializeObjectAt(TranslatedValue* slot);
  void InitializeCapturedObjectAt(int object_index, std::stack<int>* worklist,
                                  const DisallowHeapAllocation& no_allocation);
  void InitializeJSObjectAt(TranslatedFrame* frame, int* value_index,
                            TranslatedValue* slot, Handle<Map> map,
                            const DisallowHeapAllocation& no_allocation);
  void InitializeObjectWithTaggedFieldsAt(
      TranslatedFrame* frame, int* value_index, TranslatedValue* slot,
      Handle<Map> map, const DisallowHeapAllocation& no_allocation);

368
  void ReadUpdateFeedback(TranslationIterator* iterator,
369
                          FixedArray* literal_array, FILE* trace_file);
370

371 372 373
  TranslatedValue* ResolveCapturedObject(TranslatedValue* slot);
  TranslatedValue* GetValueByObjectIndex(int object_index);
  Handle<Object> GetValueAndAdvance(TranslatedFrame* frame, int* value_index);
374 375

  static uint32_t GetUInt32Slot(Address fp, int slot_index);
376
  static uint64_t GetUInt64Slot(Address fp, int slot_index);
377 378
  static Float32 GetFloatSlot(Address fp, int slot_index);
  static Float64 GetDoubleSlot(Address fp, int slot_index);
379 380

  std::vector<TranslatedFrame> frames_;
381
  Isolate* isolate_ = nullptr;
382
  Address stack_frame_pointer_ = kNullAddress;
383
  int formal_parameter_count_;
384 385 386 387 388 389

  struct ObjectPosition {
    int frame_index_;
    int value_index_;
  };
  std::deque<ObjectPosition> object_positions_;
390 391 392
  Handle<FeedbackVector> feedback_vector_handle_;
  FeedbackVector* feedback_vector_ = nullptr;
  FeedbackSlot feedback_slot_;
393
};
394

395
class OptimizedFunctionVisitor {
396
 public:
397
  virtual ~OptimizedFunctionVisitor() = default;
398 399 400 401 402
  virtual void VisitFunction(JSFunction* function) = 0;
};

class Deoptimizer : public Malloced {
 public:
403
  struct DeoptInfo {
404 405
    DeoptInfo(SourcePosition position, DeoptimizeReason deopt_reason,
              int deopt_id)
406
        : position(position), deopt_reason(deopt_reason), deopt_id(deopt_id) {}
407

408
    SourcePosition position;
409
    DeoptimizeReason deopt_reason;
410 411 412
    int deopt_id;

    static const int kNoDeoptId = -1;
413 414
  };

415
  static DeoptInfo GetDeoptInfo(Code* code, Address from);
416

417 418
  static int ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo* shared,
                                                    BailoutId node_id);
419

420
  struct JumpTableEntry : public ZoneObject {
421
    inline JumpTableEntry(Address entry, const DeoptInfo& deopt_info,
422
                          DeoptimizeKind kind, bool frame)
423 424
        : label(),
          address(entry),
425
          deopt_info(deopt_info),
426
          deopt_kind(kind),
427
          needs_frame(frame) {}
428 429

    bool IsEquivalentTo(const JumpTableEntry& other) const {
430
      return address == other.address && deopt_kind == other.deopt_kind &&
431
             needs_frame == other.needs_frame;
432 433
    }

434 435
    Label label;
    Address address;
436
    DeoptInfo deopt_info;
437
    DeoptimizeKind deopt_kind;
438 439 440
    bool needs_frame;
  };

441
  static const char* MessageFor(DeoptimizeKind kind);
442

443 444
  int output_count() const { return output_count_; }

445 446
  Handle<JSFunction> function() const;
  Handle<Code> compiled_code() const;
447
  DeoptimizeKind deopt_kind() const { return deopt_kind_; }
448

449 450 451
  // Number of created JS frames. Not all created frames are necessarily JS.
  int jsframe_count() const { return jsframe_count_; }

452 453
  static Deoptimizer* New(JSFunction* function, DeoptimizeKind kind,
                          unsigned bailout_id, Address from, int fp_to_sp_delta,
454 455
                          Isolate* isolate);
  static Deoptimizer* Grab(Isolate* isolate);
456

457 458 459
  // The returned object with information on the optimized frame needs to be
  // freed before another one can be generated.
  static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
460
                                                        int jsframe_index,
461 462
                                                        Isolate* isolate);

463 464
  // Deoptimize the function now. Its current optimized code will never be run
  // again and any activations of the optimized code will get deoptimized when
465 466 467
  // execution returns. If {code} is specified then the given code is targeted
  // instead of the function code (e.g. OSR code not installed on function).
  static void DeoptimizeFunction(JSFunction* function, Code* code = nullptr);
468

469
  // Deoptimize all code in the given isolate.
470
  static void DeoptimizeAll(Isolate* isolate);
471

472 473 474 475
  // Deoptimizes all optimized code that has been previously marked
  // (via code->set_marked_for_deoptimization) and unlinks all functions that
  // refer to that code.
  static void DeoptimizeMarkedCode(Isolate* isolate);
476

477 478
  ~Deoptimizer();

479
  void MaterializeHeapObjects();
480

481
  static void ComputeOutputFrames(Deoptimizer* deoptimizer);
482

483
  static Address GetDeoptimizationEntry(Isolate* isolate, int id,
484 485 486
                                        DeoptimizeKind kind);
  static int GetDeoptimizationId(Isolate* isolate, Address addr,
                                 DeoptimizeKind kind);
487

488 489 490 491 492
  // Returns true if {addr} is a deoptimization entry and stores its type in
  // {type}. Returns false if {addr} is not a deoptimization entry.
  static bool IsDeoptimizationEntry(Isolate* isolate, Address addr,
                                    DeoptimizeKind* type);

493 494 495 496 497 498 499
  // Code generation support.
  static int input_offset() { return OFFSET_OF(Deoptimizer, input_); }
  static int output_count_offset() {
    return OFFSET_OF(Deoptimizer, output_count_);
  }
  static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }

500 501 502 503
  static int caller_frame_top_offset() {
    return OFFSET_OF(Deoptimizer, caller_frame_top_);
  }

504
  static int GetDeoptimizedCodeCount(Isolate* isolate);
505 506 507 508

  static const int kNotDeoptimizationEntry = -1;

  // Generators for the deoptimization entry code.
509
  class TableEntryGenerator {
510
   public:
511 512
    TableEntryGenerator(MacroAssembler* masm, DeoptimizeKind kind, int count)
        : masm_(masm), deopt_kind_(kind), count_(count) {}
513 514 515 516 517

    void Generate();

   protected:
    MacroAssembler* masm() const { return masm_; }
518
    DeoptimizeKind deopt_kind() const { return deopt_kind_; }
519
    Isolate* isolate() const { return masm_->isolate(); }
520

521
    void GeneratePrologue();
522 523 524 525

   private:
    int count() const { return count_; }

526
    MacroAssembler* masm_;
527
    DeoptimizeKind deopt_kind_;
528 529 530
    int count_;
  };

531
  static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
532
                                               DeoptimizeKind kind);
533
  static void EnsureCodeForMaxDeoptimizationEntries(Isolate* isolate);
534

535 536
  Isolate* isolate() const { return isolate_; }

537
 private:
538
  friend class FrameWriter;
539 540
  void QueueValueForMaterialization(Address output_address, Object* obj,
                                    const TranslatedFrame::iterator& iterator);
541

542 543
  static const int kMinNumberOfEntries = 64;
  static const int kMaxNumberOfEntries = 16384;
544

545
  Deoptimizer(Isolate* isolate, JSFunction* function, DeoptimizeKind kind,
546
              unsigned bailout_id, Address from, int fp_to_sp_delta);
547
  Code* FindOptimizedCode();
548
  void PrintFunctionName();
549 550
  void DeleteFrameDescriptions();

551 552 553
  static bool IsInDeoptimizationTable(Isolate* isolate, Address addr,
                                      DeoptimizeKind type);

554
  void DoComputeOutputFrames();
555 556 557 558 559 560
  void DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
                                 int frame_index, bool goto_catch_handler);
  void DoComputeArgumentsAdaptorFrame(TranslatedFrame* translated_frame,
                                      int frame_index);
  void DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
                                   int frame_index);
561 562 563 564 565 566 567 568 569 570 571 572 573 574

  enum class BuiltinContinuationMode {
    STUB,
    JAVASCRIPT,
    JAVASCRIPT_WITH_CATCH,
    JAVASCRIPT_HANDLE_EXCEPTION
  };
  static bool BuiltinContinuationModeIsWithCatch(BuiltinContinuationMode mode);
  static bool BuiltinContinuationModeIsJavaScript(BuiltinContinuationMode mode);
  static StackFrame::Type BuiltinContinuationModeToFrameType(
      BuiltinContinuationMode mode);
  static Builtins::Name TrampolineForBuiltinContinuation(
      BuiltinContinuationMode mode, bool must_handle_result);

575
  void DoComputeBuiltinContinuation(TranslatedFrame* translated_frame,
576 577
                                    int frame_index,
                                    BuiltinContinuationMode mode);
578

579
  unsigned ComputeInputFrameAboveFpFixedSize() const;
580
  unsigned ComputeInputFrameSize() const;
581
  static unsigned ComputeInterpretedFixedSize(SharedFunctionInfo* shared);
582

583
  static unsigned ComputeIncomingArgumentSize(SharedFunctionInfo* shared);
584
  static unsigned ComputeOutgoingArgumentSize(Code* code, unsigned bailout_id);
585

586 587
  static void GenerateDeoptimizationEntries(MacroAssembler* masm, int count,
                                            DeoptimizeKind kind);
588

589 590 591 592 593
  // Marks all the code in the given context for deoptimization.
  static void MarkAllCodeForContext(Context* native_context);

  // Deoptimizes all code marked in the given context.
  static void DeoptimizeMarkedCodeForContext(Context* native_context);
594

595 596 597 598
  // Some architectures need to push padding together with the TOS register
  // in order to maintain stack alignment.
  static bool PadTopOfStackRegister();

599 600 601 602 603
  // Searches the list of known deoptimizing code for a Code object
  // containing the given address (which is supposedly faster than
  // searching all code objects).
  Code* FindDeoptimizingCode(Address addr);

604
  Isolate* isolate_;
605
  JSFunction* function_;
606
  Code* compiled_code_;
607
  unsigned bailout_id_;
608
  DeoptimizeKind deopt_kind_;
609 610
  Address from_;
  int fp_to_sp_delta_;
611 612 613
  bool deoptimizing_throw_;
  int catch_handler_data_;
  int catch_handler_pc_offset_;
614 615 616 617 618

  // Input frame description.
  FrameDescription* input_;
  // Number of output frames.
  int output_count_;
619 620
  // Number of output js frames.
  int jsframe_count_;
621 622 623
  // Array of output frame descriptions.
  FrameDescription** output_;

624 625 626 627 628 629 630
  // Caller frame details computed from input frame.
  intptr_t caller_frame_top_;
  intptr_t caller_fp_;
  intptr_t caller_pc_;
  intptr_t caller_constant_pool_;
  intptr_t input_frame_context_;

jarin@chromium.org's avatar
jarin@chromium.org committed
631
  // Key for lookup of previously materialized objects
632
  intptr_t stack_fp_;
jarin@chromium.org's avatar
jarin@chromium.org committed
633

634 635 636 637 638 639
  TranslatedState translated_state_;
  struct ValueToMaterialize {
    Address output_slot_address_;
    TranslatedFrame::iterator value_;
  };
  std::vector<ValueToMaterialize> values_to_materialize_;
640

641 642 643
#ifdef DEBUG
  DisallowHeapAllocation* disallow_heap_allocation_;
#endif  // DEBUG
644

645
  CodeTracer::Scope* trace_scope_;
646

647
  static const int table_entry_size_;
648 649

  friend class FrameDescription;
650
  friend class DeoptimizedFrameInfo;
651 652 653
};


654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
class RegisterValues {
 public:
  intptr_t GetRegister(unsigned n) const {
#if DEBUG
    // This convoluted DCHECK is needed to work around a gcc problem that
    // improperly detects an array bounds overflow in optimized debug builds
    // when using a plain DCHECK.
    if (n >= arraysize(registers_)) {
      DCHECK(false);
      return 0;
    }
#endif
    return registers_[n];
  }

669
  Float32 GetFloatRegister(unsigned n) const {
670 671 672 673
    DCHECK(n < arraysize(float_registers_));
    return float_registers_[n];
  }

674
  Float64 GetDoubleRegister(unsigned n) const {
675 676 677 678 679 680 681 682 683
    DCHECK(n < arraysize(double_registers_));
    return double_registers_[n];
  }

  void SetRegister(unsigned n, intptr_t value) {
    DCHECK(n < arraysize(registers_));
    registers_[n] = value;
  }

684
  void SetFloatRegister(unsigned n, Float32 value) {
685 686 687 688
    DCHECK(n < arraysize(float_registers_));
    float_registers_[n] = value;
  }

689
  void SetDoubleRegister(unsigned n, Float64 value) {
690 691 692 693
    DCHECK(n < arraysize(double_registers_));
    double_registers_[n] = value;
  }

694 695 696 697 698
  // Generated code is writing directly into the below arrays, make sure their
  // element sizes fit what the machine instructions expect.
  static_assert(sizeof(Float32) == kFloatSize, "size mismatch");
  static_assert(sizeof(Float64) == kDoubleSize, "size mismatch");

699
  intptr_t registers_[Register::kNumRegisters];
700 701
  Float32 float_registers_[FloatRegister::kNumRegisters];
  Float64 double_registers_[DoubleRegister::kNumRegisters];
702 703 704
};


705 706
class FrameDescription {
 public:
707
  explicit FrameDescription(uint32_t frame_size, int parameter_count = 0);
708 709

  void* operator new(size_t size, uint32_t frame_size) {
710 711 712
    // Subtracts kPointerSize, as the member frame_content_ already supplies
    // the first element of the area to store the frame.
    return malloc(size + frame_size - kPointerSize);
713 714
  }

715 716 717 718
  void operator delete(void* pointer, uint32_t frame_size) {
    free(pointer);
  }

719 720 721 722
  void operator delete(void* description) {
    free(description);
  }

723
  uint32_t GetFrameSize() const {
724
    USE(frame_content_);
725
    DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
726 727
    return static_cast<uint32_t>(frame_size_);
  }
728

729
  intptr_t GetFrameSlot(unsigned offset) {
730 731 732
    return *GetFrameSlotPointer(offset);
  }

733 734 735 736 737 738
  unsigned GetLastArgumentSlotOffset() {
    int parameter_slots = parameter_count();
    if (kPadArguments) parameter_slots = RoundUp(parameter_slots, 2);
    return GetFrameSize() - parameter_slots * kPointerSize;
  }

739
  Address GetFramePointerAddress() {
740 741
    int fp_offset =
        GetLastArgumentSlotOffset() - StandardFrameConstants::kCallerSPOffset;
742
    return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset));
743 744
  }

745 746
  RegisterValues* GetRegisterValues() { return &register_values_; }

747
  void SetFrameSlot(unsigned offset, intptr_t value) {
748 749 750
    *GetFrameSlotPointer(offset) = value;
  }

751 752 753 754
  void SetCallerPc(unsigned offset, intptr_t value);

  void SetCallerFp(unsigned offset, intptr_t value);

755 756
  void SetCallerConstantPool(unsigned offset, intptr_t value);

757
  intptr_t GetRegister(unsigned n) const {
758
    return register_values_.GetRegister(n);
759 760
  }

761
  Float64 GetDoubleRegister(unsigned n) const {
762
    return register_values_.GetDoubleRegister(n);
763 764
  }

765
  void SetRegister(unsigned n, intptr_t value) {
766
    register_values_.SetRegister(n, value);
767 768
  }

769
  void SetDoubleRegister(unsigned n, Float64 value) {
770
    register_values_.SetDoubleRegister(n, value);
771 772
  }

773 774
  intptr_t GetTop() const { return top_; }
  void SetTop(intptr_t top) { top_ = top; }
775

776 777
  intptr_t GetPc() const { return pc_; }
  void SetPc(intptr_t pc) { pc_ = pc; }
778

779 780
  intptr_t GetFp() const { return fp_; }
  void SetFp(intptr_t fp) { fp_ = fp; }
781

782 783 784
  intptr_t GetContext() const { return context_; }
  void SetContext(intptr_t context) { context_ = context; }

785 786 787 788 789
  intptr_t GetConstantPool() const { return constant_pool_; }
  void SetConstantPool(intptr_t constant_pool) {
    constant_pool_ = constant_pool;
  }

790
  void SetContinuation(intptr_t pc) { continuation_ = pc; }
791

792 793
  // Argument count, including receiver.
  int parameter_count() { return parameter_count_; }
794

795
  static int registers_offset() {
796
    return OFFSET_OF(FrameDescription, register_values_.registers_);
797 798 799
  }

  static int double_registers_offset() {
800
    return OFFSET_OF(FrameDescription, register_values_.double_registers_);
801 802
  }

803 804 805 806
  static int float_registers_offset() {
    return OFFSET_OF(FrameDescription, register_values_.float_registers_);
  }

807
  static int frame_size_offset() {
808
    return offsetof(FrameDescription, frame_size_);
809 810
  }

811
  static int pc_offset() { return offsetof(FrameDescription, pc_); }
812 813

  static int continuation_offset() {
814
    return offsetof(FrameDescription, continuation_);
815 816 817
  }

  static int frame_content_offset() {
818
    return offsetof(FrameDescription, frame_content_);
819 820 821 822 823
  }

 private:
  static const uint32_t kZapUint32 = 0xbeeddead;

824 825 826
  // Frame_size_ must hold a uint32_t value.  It is only a uintptr_t to
  // keep the variable-size array frame_content_ of type intptr_t at
  // the end of the structure aligned.
827
  uintptr_t frame_size_;  // Number of bytes.
828
  int parameter_count_;
829
  RegisterValues register_values_;
830 831 832
  intptr_t top_;
  intptr_t pc_;
  intptr_t fp_;
833
  intptr_t context_;
834
  intptr_t constant_pool_;
835 836 837

  // Continuation is the PC where the execution continues after
  // deoptimizing.
838
  intptr_t continuation_;
839

840 841 842 843
  // This must be at the end of the object as the object is allocated larger
  // than it's definition indicate to extend this array.
  intptr_t frame_content_[1];

844
  intptr_t* GetFrameSlotPointer(unsigned offset) {
845
    DCHECK(offset < frame_size_);
846
    return reinterpret_cast<intptr_t*>(
847 848 849 850 851
        reinterpret_cast<Address>(this) + frame_content_offset() + offset);
  }
};


852 853
class DeoptimizerData {
 public:
854
  explicit DeoptimizerData(Heap* heap);
855 856 857
  ~DeoptimizerData();

 private:
858
  Heap* heap_;
859 860 861 862 863
  static const int kLastDeoptimizeKind =
      static_cast<int>(DeoptimizeKind::kLastDeoptimizeKind);
  Code* deopt_entry_code_[kLastDeoptimizeKind + 1];
  Code* deopt_entry_code(DeoptimizeKind kind);
  void set_deopt_entry_code(DeoptimizeKind kind, Code* code);
864

865
  Deoptimizer* current_;
866 867 868 869 870 871

  friend class Deoptimizer;

  DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
};

872
class TranslationBuffer {
873
 public:
874
  explicit TranslationBuffer(Zone* zone) : contents_(zone) {}
875

876 877
  int CurrentIndex() const { return static_cast<int>(contents_.size()); }
  void Add(int32_t value);
878

879
  Handle<ByteArray> CreateByteArray(Factory* factory);
880 881

 private:
882
  ZoneChunkList<uint8_t> contents_;
883 884
};

885
class TranslationIterator {
886
 public:
887
  TranslationIterator(ByteArray* buffer, int index);
888 889 890

  int32_t Next();

891
  bool HasNext() const;
892 893 894 895 896 897 898 899 900 901

  void Skip(int n) {
    for (int i = 0; i < n; i++) Next();
  }

 private:
  ByteArray* buffer_;
  int index_;
};

902 903 904 905 906 907 908 909 910 911 912 913 914 915
#define TRANSLATION_OPCODE_LIST(V)                     \
  V(BEGIN)                                             \
  V(INTERPRETED_FRAME)                                 \
  V(BUILTIN_CONTINUATION_FRAME)                        \
  V(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME)            \
  V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME) \
  V(CONSTRUCT_STUB_FRAME)                              \
  V(ARGUMENTS_ADAPTOR_FRAME)                           \
  V(DUPLICATED_OBJECT)                                 \
  V(ARGUMENTS_ELEMENTS)                                \
  V(ARGUMENTS_LENGTH)                                  \
  V(CAPTURED_OBJECT)                                   \
  V(REGISTER)                                          \
  V(INT32_REGISTER)                                    \
916
  V(INT64_REGISTER)                                    \
917 918 919 920 921 922
  V(UINT32_REGISTER)                                   \
  V(BOOL_REGISTER)                                     \
  V(FLOAT_REGISTER)                                    \
  V(DOUBLE_REGISTER)                                   \
  V(STACK_SLOT)                                        \
  V(INT32_STACK_SLOT)                                  \
923
  V(INT64_STACK_SLOT)                                  \
924 925 926 927 928
  V(UINT32_STACK_SLOT)                                 \
  V(BOOL_STACK_SLOT)                                   \
  V(FLOAT_STACK_SLOT)                                  \
  V(DOUBLE_STACK_SLOT)                                 \
  V(LITERAL)                                           \
929
  V(UPDATE_FEEDBACK)
930

931
class Translation {
932
 public:
933
#define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
934
  enum Opcode {
935 936
    TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
    LAST = LITERAL
937
  };
938
#undef DECLARE_TRANSLATION_OPCODE_ENUM
939

940
  Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
941 942
              int update_feedback_count, Zone* zone)
      : buffer_(buffer), index_(buffer->CurrentIndex()), zone_(zone) {
943 944 945
    buffer_->Add(BEGIN);
    buffer_->Add(frame_count);
    buffer_->Add(jsframe_count);
946
    buffer_->Add(update_feedback_count);
947 948 949 950 951
  }

  int index() const { return index_; }

  // Commands.
952 953
  void BeginInterpretedFrame(BailoutId bytecode_offset, int literal_id,
                             unsigned height);
954
  void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
955 956
  void BeginConstructStubFrame(BailoutId bailout_id, int literal_id,
                               unsigned height);
957 958 959 960
  void BeginBuiltinContinuationFrame(BailoutId bailout_id, int literal_id,
                                     unsigned height);
  void BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,
                                               int literal_id, unsigned height);
961 962 963
  void BeginJavaScriptBuiltinContinuationWithCatchFrame(BailoutId bailout_id,
                                                        int literal_id,
                                                        unsigned height);
964 965
  void ArgumentsElements(CreateArgumentsType type);
  void ArgumentsLength(CreateArgumentsType type);
966
  void BeginCapturedObject(int length);
967
  void AddUpdateFeedback(int vector_literal, int slot);
968
  void DuplicateObject(int object_index);
969 970
  void StoreRegister(Register reg);
  void StoreInt32Register(Register reg);
971
  void StoreInt64Register(Register reg);
972
  void StoreUint32Register(Register reg);
973
  void StoreBoolRegister(Register reg);
974
  void StoreFloatRegister(FloatRegister reg);
975 976 977
  void StoreDoubleRegister(DoubleRegister reg);
  void StoreStackSlot(int index);
  void StoreInt32StackSlot(int index);
978
  void StoreInt64StackSlot(int index);
979
  void StoreUint32StackSlot(int index);
980
  void StoreBoolStackSlot(int index);
981
  void StoreFloatStackSlot(int index);
982 983
  void StoreDoubleStackSlot(int index);
  void StoreLiteral(int literal_id);
984
  void StoreJSFrameFunction();
985

986
  Zone* zone() const { return zone_; }
987

988 989
  static int NumberOfOperandsFor(Opcode opcode);

990
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
991 992 993 994 995 996
  static const char* StringFor(Opcode opcode);
#endif

 private:
  TranslationBuffer* buffer_;
  int index_;
997
  Zone* zone_;
998 999 1000
};


jarin@chromium.org's avatar
jarin@chromium.org committed
1001 1002 1003 1004 1005 1006 1007
class MaterializedObjectStore {
 public:
  explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
  }

  Handle<FixedArray> Get(Address fp);
  void Set(Address fp, Handle<FixedArray> materialized_objects);
1008
  bool Remove(Address fp);
jarin@chromium.org's avatar
jarin@chromium.org committed
1009 1010

 private:
1011
  Isolate* isolate() const { return isolate_; }
jarin@chromium.org's avatar
jarin@chromium.org committed
1012 1013 1014 1015 1016 1017
  Handle<FixedArray> GetStackEntries();
  Handle<FixedArray> EnsureStackEntries(int size);

  int StackIdToIndex(Address fp);

  Isolate* isolate_;
1018
  std::vector<Address> frame_fps_;
1019 1020 1021
};


1022 1023 1024 1025
// Class used to represent an unoptimized frame when the debugger
// needs to inspect a frame that is part of an optimized frame. The
// internally used FrameDescription objects are not GC safe so for use
// by the debugger frame information is copied to an object of this type.
1026 1027
// Represents parameters in unadapted form so their number might mismatch
// formal parameter count.
1028 1029
class DeoptimizedFrameInfo : public Malloced {
 public:
1030 1031 1032
  DeoptimizedFrameInfo(TranslatedState* state,
                       TranslatedState::iterator frame_it, Isolate* isolate);

1033
  // Return the number of incoming arguments.
1034
  int parameters_count() { return static_cast<int>(parameters_.size()); }
1035

1036
  // Return the height of the expression stack.
1037
  int expression_count() { return static_cast<int>(expression_stack_.size()); }
1038

1039
  // Get the frame function.
1040
  Handle<JSFunction> GetFunction() { return function_; }
1041

1042
  // Get the frame context.
1043
  Handle<Object> GetContext() { return context_; }
1044

1045
  // Get an incoming argument.
1046
  Handle<Object> GetParameter(int index) {
1047
    DCHECK(0 <= index && index < parameters_count());
1048 1049 1050
    return parameters_[index];
  }

1051
  // Get an expression from the expression stack.
1052
  Handle<Object> GetExpression(int index) {
1053
    DCHECK(0 <= index && index < expression_count());
1054 1055 1056
    return expression_stack_[index];
  }

1057 1058
  int GetSourcePosition() {
    return source_position_;
1059 1060
  }

1061
 private:
1062
  // Set an incoming argument.
1063
  void SetParameter(int index, Handle<Object> obj) {
1064
    DCHECK(0 <= index && index < parameters_count());
1065 1066 1067
    parameters_[index] = obj;
  }

1068
  // Set an expression on the expression stack.
1069
  void SetExpression(int index, Handle<Object> obj) {
1070
    DCHECK(0 <= index && index < expression_count());
1071 1072 1073
    expression_stack_[index] = obj;
  }

1074 1075 1076 1077
  Handle<JSFunction> function_;
  Handle<Object> context_;
  std::vector<Handle<Object> > parameters_;
  std::vector<Handle<Object> > expression_stack_;
1078
  int source_position_;
1079 1080 1081 1082

  friend class Deoptimizer;
};

1083 1084
}  // namespace internal
}  // namespace v8
1085 1086

#endif  // V8_DEOPTIMIZER_H_