deoptimizer.h 31.3 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 9
#include <vector>

10
#include "src/allocation.h"
11
#include "src/base/macros.h"
12
#include "src/boxed-float.h"
13
#include "src/deoptimize-reason.h"
14
#include "src/frame-constants.h"
15
#include "src/macro-assembler.h"
16
#include "src/source-position.h"
17
#include "src/zone/zone-chunk-list.h"
18 19 20 21 22 23

namespace v8 {
namespace internal {

class FrameDescription;
class TranslationIterator;
24
class DeoptimizedFrameInfo;
25 26 27
class TranslatedState;
class RegisterValues;

jarin's avatar
jarin committed
28
class TranslatedValue {
29 30 31 32 33 34 35 36
 public:
  // Allocation-less getter of the value.
  // Returns heap()->arguments_marker() if allocation would be
  // necessary to get the value.
  Object* GetRawValue() const;
  Handle<Object> GetValue();

  bool IsMaterializedObject() const;
37
  bool IsMaterializableByDebugger() const;
38 39 40 41 42 43 44 45 46 47 48

 private:
  friend class TranslatedState;
  friend class TranslatedFrame;

  enum Kind {
    kInvalid,
    kTagged,
    kInt32,
    kUInt32,
    kBoolBit,
49
    kFloat,
50
    kDouble,
51 52 53 54 55 56
    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.
57 58 59 60 61 62 63 64 65 66 67
  };

  TranslatedValue(TranslatedState* container, Kind kind)
      : kind_(kind), container_(container) {}
  Kind kind() const { return kind_; }
  void Handlify();
  int GetChildrenCount() const;

  static TranslatedValue NewDeferredObject(TranslatedState* container,
                                           int length, int object_index);
  static TranslatedValue NewDuplicateObject(TranslatedState* container, int id);
68 69
  static TranslatedValue NewFloat(TranslatedState* container, Float32 value);
  static TranslatedValue NewDouble(TranslatedState* container, Float64 value);
70 71 72 73
  static TranslatedValue NewInt32(TranslatedState* container, int32_t value);
  static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value);
  static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
  static TranslatedValue NewTagged(TranslatedState* container, Object* literal);
74
  static TranslatedValue NewInvalid(TranslatedState* container);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

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

  Kind kind_;
  TranslatedState* container_;  // This is only needed for materialization of
                                // objects and constructing handles (to get
                                // to the isolate).

  MaybeHandle<Object> value_;  // Before handlification, this is always null,
                               // after materialization it is never null,
                               // in between it is only null if the value needs
                               // to be materialized.

  struct MaterializedObjectInfo {
    int id_;
91
    int length_;  // Applies only to kCapturedObject kinds.
92 93 94 95 96 97 98 99 100
  };

  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_;
101
    // kind is kFloat
102
    Float32 float_value_;
103
    // kind is kDouble
104
    Float64 double_value_;
105
    // kind is kDuplicatedObject or kCapturedObject.
106 107 108 109 110 111 112
    MaterializedObjectInfo materialization_info_;
  };

  // Checked accessors for the union members.
  Object* raw_literal() const;
  int32_t int32_value() const;
  uint32_t uint32_value() const;
113 114
  Float32 float_value() const;
  Float64 double_value() const;
115 116 117 118 119 120 121 122
  int object_length() const;
  int object_index() const;
};


class TranslatedFrame {
 public:
  enum Kind {
123
    kInterpretedFunction,
124 125
    kArgumentsAdaptor,
    kConstructStub,
126 127
    kBuiltinContinuation,
    kJavaScriptBuiltinContinuation,
128 129 130 131 132 133
    kInvalid
  };

  int GetValueCount();

  Kind kind() const { return kind_; }
134
  BailoutId node_id() const { return node_id_; }
135
  Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
136
  int height() const { return height_; }
137

138 139 140 141 142
  SharedFunctionInfo* raw_shared_info() const {
    CHECK_NOT_NULL(raw_shared_info_);
    return raw_shared_info_;
  }

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  class iterator {
   public:
    iterator& operator++() {
      AdvanceIterator(&position_);
      return *this;
    }

    iterator operator++(int) {
      iterator original(position_);
      AdvanceIterator(&position_);
      return original;
    }

    bool operator==(const iterator& other) const {
      return position_ == other.position_;
    }
    bool operator!=(const iterator& other) const { return !(*this == other); }

    TranslatedValue& operator*() { return (*position_); }
    TranslatedValue* operator->() { return &(*position_); }

   private:
    friend TranslatedFrame;

    explicit iterator(std::deque<TranslatedValue>::iterator position)
        : position_(position) {}

    std::deque<TranslatedValue>::iterator position_;
  };

173 174 175
  typedef TranslatedValue& reference;
  typedef TranslatedValue const& const_reference;

176 177
  iterator begin() { return iterator(values_.begin()); }
  iterator end() { return iterator(values_.end()); }
178

179 180
  reference front() { return values_.front(); }
  const_reference front() const { return values_.front(); }
181 182 183 184 185

 private:
  friend class TranslatedState;

  // Constructor static methods.
186 187 188
  static TranslatedFrame InterpretedFrame(BailoutId bytecode_offset,
                                          SharedFunctionInfo* shared_info,
                                          int height);
189 190 191
  static TranslatedFrame AccessorFrame(Kind kind,
                                       SharedFunctionInfo* shared_info);
  static TranslatedFrame ArgumentsAdaptorFrame(SharedFunctionInfo* shared_info,
192
                                               int height);
193 194
  static TranslatedFrame ConstructStubFrame(BailoutId bailout_id,
                                            SharedFunctionInfo* shared_info,
195
                                            int height);
196 197 198 199
  static TranslatedFrame BuiltinContinuationFrame(
      BailoutId bailout_id, SharedFunctionInfo* shared_info, int height);
  static TranslatedFrame JavaScriptBuiltinContinuationFrame(
      BailoutId bailout_id, SharedFunctionInfo* shared_info, int height);
200 201 202 203 204 205
  static TranslatedFrame InvalidFrame() {
    return TranslatedFrame(kInvalid, nullptr);
  }

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

206 207
  TranslatedFrame(Kind kind, SharedFunctionInfo* shared_info = nullptr,
                  int height = 0)
208 209
      : kind_(kind),
        node_id_(BailoutId::None()),
210
        raw_shared_info_(shared_info),
211
        height_(height) {}
212 213

  void Add(const TranslatedValue& value) { values_.push_back(value); }
214
  void Handlify();
215 216 217

  Kind kind_;
  BailoutId node_id_;
218 219
  SharedFunctionInfo* raw_shared_info_;
  Handle<SharedFunctionInfo> shared_info_;
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
  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:
  TranslatedState();
246
  explicit TranslatedState(const JavaScriptFrame* frame);
247

248
  void Prepare(Address stack_frame_pointer);
249 250

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

253 254 255 256
  typedef std::vector<TranslatedFrame>::iterator iterator;
  iterator begin() { return frames_.begin(); }
  iterator end() { return frames_.end(); }

257 258 259 260
  typedef std::vector<TranslatedFrame>::const_iterator const_iterator;
  const_iterator begin() const { return frames_.begin(); }
  const_iterator end() const { return frames_.end(); }

261 262
  std::vector<TranslatedFrame>& frames() { return frames_; }

263
  TranslatedFrame* GetFrameFromJSFrameIndex(int jsframe_index);
264 265 266 267 268
  TranslatedFrame* GetArgumentsInfoFromJSFrameIndex(int jsframe_index,
                                                    int* arguments_count);

  Isolate* isolate() { return isolate_; }

269 270
  void Init(Address input_frame_pointer, TranslationIterator* iterator,
            FixedArray* literal_array, RegisterValues* registers,
271
            FILE* trace_file, int parameter_count);
272 273 274 275 276 277 278 279

 private:
  friend TranslatedValue;

  TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator,
                                            FixedArray* literal_array,
                                            Address fp,
                                            FILE* trace_file);
280 281 282
  int CreateNextTranslatedValue(int frame_index, TranslationIterator* iterator,
                                FixedArray* literal_array, Address fp,
                                RegisterValues* registers, FILE* trace_file);
283 284
  Address ComputeArgumentsPosition(Address input_frame_pointer,
                                   CreateArgumentsType type, int* length);
285 286
  void CreateArgumentsElementsTranslatedValues(int frame_index,
                                               Address input_frame_pointer,
287 288
                                               CreateArgumentsType type,
                                               FILE* trace_file);
289 290 291 292

  void UpdateFromPreviouslyMaterializedObjects();
  Handle<Object> MaterializeAt(int frame_index, int* value_index);
  Handle<Object> MaterializeObjectAt(int object_index);
293 294 295
  class CapturedObjectMaterializer;
  Handle<Object> MaterializeCapturedObjectAt(TranslatedValue* slot,
                                             int frame_index, int* value_index);
296 297

  static uint32_t GetUInt32Slot(Address fp, int slot_index);
298 299
  static Float32 GetFloatSlot(Address fp, int slot_index);
  static Float64 GetDoubleSlot(Address fp, int slot_index);
300 301 302 303

  std::vector<TranslatedFrame> frames_;
  Isolate* isolate_;
  Address stack_frame_pointer_;
304
  int formal_parameter_count_;
305 306 307 308 309 310 311

  struct ObjectPosition {
    int frame_index_;
    int value_index_;
  };
  std::deque<ObjectPosition> object_positions_;
};
312

313

314 315 316 317 318 319 320 321
class OptimizedFunctionVisitor BASE_EMBEDDED {
 public:
  virtual ~OptimizedFunctionVisitor() {}
  virtual void VisitFunction(JSFunction* function) = 0;
};

class Deoptimizer : public Malloced {
 public:
322
  enum BailoutType { EAGER, LAZY, SOFT, kLastBailoutType = SOFT };
323

324
  struct DeoptInfo {
325 326
    DeoptInfo(SourcePosition position, DeoptimizeReason deopt_reason,
              int deopt_id)
327
        : position(position), deopt_reason(deopt_reason), deopt_id(deopt_id) {}
328

329
    SourcePosition position;
330
    DeoptimizeReason deopt_reason;
331 332 333
    int deopt_id;

    static const int kNoDeoptId = -1;
334 335
  };

336
  static DeoptInfo GetDeoptInfo(Code* code, byte* from);
337

338 339
  static int ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo* shared,
                                                    BailoutId node_id);
340

341
  struct JumpTableEntry : public ZoneObject {
342
    inline JumpTableEntry(Address entry, const DeoptInfo& deopt_info,
343
                          Deoptimizer::BailoutType type, bool frame)
344 345
        : label(),
          address(entry),
346
          deopt_info(deopt_info),
347
          bailout_type(type),
348
          needs_frame(frame) {}
349 350 351

    bool IsEquivalentTo(const JumpTableEntry& other) const {
      return address == other.address && bailout_type == other.bailout_type &&
352
             needs_frame == other.needs_frame;
353 354
    }

355 356
    Label label;
    Address address;
357
    DeoptInfo deopt_info;
358 359 360 361
    Deoptimizer::BailoutType bailout_type;
    bool needs_frame;
  };

362 363
  static const char* MessageFor(BailoutType type);

364 365
  int output_count() const { return output_count_; }

366 367
  Handle<JSFunction> function() const;
  Handle<Code> compiled_code() const;
368
  BailoutType bailout_type() const { return bailout_type_; }
369
  bool preserve_optimized() const { return preserve_optimized_; }
370

371 372 373
  // Number of created JS frames. Not all created frames are necessarily JS.
  int jsframe_count() const { return jsframe_count_; }

374 375 376 377
  static Deoptimizer* New(JSFunction* function,
                          BailoutType type,
                          unsigned bailout_id,
                          Address from,
378 379 380
                          int fp_to_sp_delta,
                          Isolate* isolate);
  static Deoptimizer* Grab(Isolate* isolate);
381

382 383 384
  // The returned object with information on the optimized frame needs to be
  // freed before another one can be generated.
  static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
385
                                                        int jsframe_index,
386 387
                                                        Isolate* isolate);

388 389
  // Deoptimize the function now. Its current optimized code will never be run
  // again and any activations of the optimized code will get deoptimized when
390 391 392
  // 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);
393

394
  // Deoptimize all code in the given isolate.
395
  static void DeoptimizeAll(Isolate* isolate);
396

397 398 399 400
  // 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);
401

402 403
  ~Deoptimizer();

404
  void MaterializeHeapObjects();
405

406
  static void ComputeOutputFrames(Deoptimizer* deoptimizer);
407

408 409
  static Address GetDeoptimizationEntry(Isolate* isolate, int id,
                                        BailoutType type);
410 411 412
  static int GetDeoptimizationId(Isolate* isolate,
                                 Address addr,
                                 BailoutType type);
413 414 415 416 417 418 419 420

  // 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_); }

421 422 423 424
  static int caller_frame_top_offset() {
    return OFFSET_OF(Deoptimizer, caller_frame_top_);
  }

425
  static int GetDeoptimizedCodeCount(Isolate* isolate);
426 427 428 429

  static const int kNotDeoptimizationEntry = -1;

  // Generators for the deoptimization entry code.
430
  class TableEntryGenerator BASE_EMBEDDED {
431
   public:
432 433
    TableEntryGenerator(MacroAssembler* masm, BailoutType type, int count)
        : masm_(masm), type_(type), count_(count) {}
434 435 436 437 438 439

    void Generate();

   protected:
    MacroAssembler* masm() const { return masm_; }
    BailoutType type() const { return type_; }
440
    Isolate* isolate() const { return masm_->isolate(); }
441

442
    void GeneratePrologue();
443 444 445 446

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

447 448
    MacroAssembler* masm_;
    Deoptimizer::BailoutType type_;
449 450 451
    int count_;
  };

452
  static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
453
                                               BailoutType type);
454
  static void EnsureCodeForMaxDeoptimizationEntries(Isolate* isolate);
455

456 457
  Isolate* isolate() const { return isolate_; }

458
 private:
459 460
  static const int kMinNumberOfEntries = 64;
  static const int kMaxNumberOfEntries = 16384;
461

462 463
  Deoptimizer(Isolate* isolate, JSFunction* function, BailoutType type,
              unsigned bailout_id, Address from, int fp_to_sp_delta);
464
  Code* FindOptimizedCode();
465
  void PrintFunctionName();
466 467 468
  void DeleteFrameDescriptions();

  void DoComputeOutputFrames();
469 470 471 472 473 474
  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);
475 476
  void DoComputeBuiltinContinuation(TranslatedFrame* translated_frame,
                                    int frame_index, bool java_script_frame);
477

478 479 480 481 482 483 484 485 486 487
  void WriteTranslatedValueToOutput(
      TranslatedFrame::iterator* iterator, int* input_index, int frame_index,
      unsigned output_offset, const char* debug_hint_string = nullptr,
      Address output_address_for_materialization = nullptr);
  void WriteValueToOutput(Object* value, int input_index, int frame_index,
                          unsigned output_offset,
                          const char* debug_hint_string);
  void DebugPrintOutputSlot(intptr_t value, int frame_index,
                            unsigned output_offset,
                            const char* debug_hint_string);
488

489
  unsigned ComputeInputFrameAboveFpFixedSize() const;
490
  unsigned ComputeInputFrameSize() const;
491 492
  static unsigned ComputeJavascriptFixedSize(SharedFunctionInfo* shared);
  static unsigned ComputeInterpretedFixedSize(SharedFunctionInfo* shared);
493

494
  static unsigned ComputeIncomingArgumentSize(SharedFunctionInfo* shared);
495
  static unsigned ComputeOutgoingArgumentSize(Code* code, unsigned bailout_id);
496 497 498 499

  static void GenerateDeoptimizationEntries(
      MacroAssembler* masm, int count, BailoutType type);

500 501 502 503 504
  // 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);
505

506 507 508 509
  // Some architectures need to push padding together with the TOS register
  // in order to maintain stack alignment.
  static bool PadTopOfStackRegister();

510 511 512 513 514
  // 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);

515
  Isolate* isolate_;
516
  JSFunction* function_;
517
  Code* compiled_code_;
518 519
  unsigned bailout_id_;
  BailoutType bailout_type_;
520
  bool preserve_optimized_;
521 522
  Address from_;
  int fp_to_sp_delta_;
523 524 525
  bool deoptimizing_throw_;
  int catch_handler_data_;
  int catch_handler_pc_offset_;
526 527 528 529 530

  // Input frame description.
  FrameDescription* input_;
  // Number of output frames.
  int output_count_;
531 532
  // Number of output js frames.
  int jsframe_count_;
533 534 535
  // Array of output frame descriptions.
  FrameDescription** output_;

536 537 538 539 540 541 542
  // 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
543
  // Key for lookup of previously materialized objects
544
  intptr_t stack_fp_;
jarin@chromium.org's avatar
jarin@chromium.org committed
545

546 547 548 549 550 551
  TranslatedState translated_state_;
  struct ValueToMaterialize {
    Address output_slot_address_;
    TranslatedFrame::iterator value_;
  };
  std::vector<ValueToMaterialize> values_to_materialize_;
552

553 554 555
#ifdef DEBUG
  DisallowHeapAllocation* disallow_heap_allocation_;
#endif  // DEBUG
556

557
  CodeTracer::Scope* trace_scope_;
558

559
  static const int table_entry_size_;
560 561

  friend class FrameDescription;
562
  friend class DeoptimizedFrameInfo;
563 564 565
};


566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
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];
  }

581
  Float32 GetFloatRegister(unsigned n) const {
582 583 584 585
    DCHECK(n < arraysize(float_registers_));
    return float_registers_[n];
  }

586
  Float64 GetDoubleRegister(unsigned n) const {
587 588 589 590 591 592 593 594 595
    DCHECK(n < arraysize(double_registers_));
    return double_registers_[n];
  }

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

596
  void SetFloatRegister(unsigned n, Float32 value) {
597 598 599 600
    DCHECK(n < arraysize(float_registers_));
    float_registers_[n] = value;
  }

601
  void SetDoubleRegister(unsigned n, Float64 value) {
602 603 604 605
    DCHECK(n < arraysize(double_registers_));
    double_registers_[n] = value;
  }

606 607 608 609 610
  // 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");

611
  intptr_t registers_[Register::kNumRegisters];
612 613
  Float32 float_registers_[FloatRegister::kNumRegisters];
  Float64 double_registers_[DoubleRegister::kNumRegisters];
614 615 616
};


617 618
class FrameDescription {
 public:
619
  explicit FrameDescription(uint32_t frame_size, int parameter_count = 0);
620 621

  void* operator new(size_t size, uint32_t frame_size) {
622 623 624
    // 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);
625 626
  }

627 628 629 630
  void operator delete(void* pointer, uint32_t frame_size) {
    free(pointer);
  }

631 632 633 634
  void operator delete(void* description) {
    free(description);
  }

635
  uint32_t GetFrameSize() const {
636
    USE(frame_content_);
637
    DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
638 639
    return static_cast<uint32_t>(frame_size_);
  }
640

641
  intptr_t GetFrameSlot(unsigned offset) {
642 643 644
    return *GetFrameSlotPointer(offset);
  }

645
  Address GetFramePointerAddress() {
646
    int fp_offset = GetFrameSize() - parameter_count() * kPointerSize -
647 648
                    StandardFrameConstants::kCallerSPOffset;
    return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset));
649 650
  }

651 652
  RegisterValues* GetRegisterValues() { return &register_values_; }

653
  void SetFrameSlot(unsigned offset, intptr_t value) {
654 655 656
    *GetFrameSlotPointer(offset) = value;
  }

657 658 659 660
  void SetCallerPc(unsigned offset, intptr_t value);

  void SetCallerFp(unsigned offset, intptr_t value);

661 662
  void SetCallerConstantPool(unsigned offset, intptr_t value);

663
  intptr_t GetRegister(unsigned n) const {
664
    return register_values_.GetRegister(n);
665 666
  }

667
  Float64 GetDoubleRegister(unsigned n) const {
668
    return register_values_.GetDoubleRegister(n);
669 670
  }

671
  void SetRegister(unsigned n, intptr_t value) {
672
    register_values_.SetRegister(n, value);
673 674
  }

675
  void SetDoubleRegister(unsigned n, Float64 value) {
676
    register_values_.SetDoubleRegister(n, value);
677 678
  }

679 680
  intptr_t GetTop() const { return top_; }
  void SetTop(intptr_t top) { top_ = top; }
681

682 683
  intptr_t GetPc() const { return pc_; }
  void SetPc(intptr_t pc) { pc_ = pc; }
684

685 686
  intptr_t GetFp() const { return fp_; }
  void SetFp(intptr_t fp) { fp_ = fp; }
687

688 689 690
  intptr_t GetContext() const { return context_; }
  void SetContext(intptr_t context) { context_ = context; }

691 692 693 694 695
  intptr_t GetConstantPool() const { return constant_pool_; }
  void SetConstantPool(intptr_t constant_pool) {
    constant_pool_ = constant_pool;
  }

696
  void SetContinuation(intptr_t pc) { continuation_ = pc; }
697

698 699
  // Argument count, including receiver.
  int parameter_count() { return parameter_count_; }
700

701
  static int registers_offset() {
702
    return OFFSET_OF(FrameDescription, register_values_.registers_);
703 704 705
  }

  static int double_registers_offset() {
706
    return OFFSET_OF(FrameDescription, register_values_.double_registers_);
707 708
  }

709 710 711 712
  static int float_registers_offset() {
    return OFFSET_OF(FrameDescription, register_values_.float_registers_);
  }

713
  static int frame_size_offset() {
714
    return offsetof(FrameDescription, frame_size_);
715 716
  }

717
  static int pc_offset() { return offsetof(FrameDescription, pc_); }
718 719

  static int continuation_offset() {
720
    return offsetof(FrameDescription, continuation_);
721 722 723
  }

  static int frame_content_offset() {
724
    return offsetof(FrameDescription, frame_content_);
725 726 727 728 729
  }

 private:
  static const uint32_t kZapUint32 = 0xbeeddead;

730 731 732
  // 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.
733
  uintptr_t frame_size_;  // Number of bytes.
734
  int parameter_count_;
735
  RegisterValues register_values_;
736 737 738
  intptr_t top_;
  intptr_t pc_;
  intptr_t fp_;
739
  intptr_t context_;
740
  intptr_t constant_pool_;
741 742 743

  // Continuation is the PC where the execution continues after
  // deoptimizing.
744
  intptr_t continuation_;
745

746 747 748 749
  // 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];

750
  intptr_t* GetFrameSlotPointer(unsigned offset) {
751
    DCHECK(offset < frame_size_);
752
    return reinterpret_cast<intptr_t*>(
753 754 755 756 757
        reinterpret_cast<Address>(this) + frame_content_offset() + offset);
  }
};


758 759
class DeoptimizerData {
 public:
760
  explicit DeoptimizerData(Heap* heap);
761 762 763
  ~DeoptimizerData();

 private:
764 765
  Heap* heap_;
  Code* deopt_entry_code_[Deoptimizer::kLastBailoutType + 1];
766

767
  Deoptimizer* current_;
768 769 770 771 772 773 774

  friend class Deoptimizer;

  DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
};


775 776
class TranslationBuffer BASE_EMBEDDED {
 public:
777
  explicit TranslationBuffer(Zone* zone) : contents_(zone) {}
778

779 780
  int CurrentIndex() const { return static_cast<int>(contents_.size()); }
  void Add(int32_t value);
781

782
  Handle<ByteArray> CreateByteArray(Factory* factory);
783 784

 private:
785
  ZoneChunkList<uint8_t> contents_;
786 787 788 789 790
};


class TranslationIterator BASE_EMBEDDED {
 public:
791
  TranslationIterator(ByteArray* buffer, int index);
792 793 794

  int32_t Next();

795
  bool HasNext() const;
796 797 798 799 800 801 802 803 804 805

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

 private:
  ByteArray* buffer_;
  int index_;
};

806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
#define TRANSLATION_OPCODE_LIST(V)          \
  V(BEGIN)                                  \
  V(INTERPRETED_FRAME)                      \
  V(BUILTIN_CONTINUATION_FRAME)             \
  V(JAVA_SCRIPT_BUILTIN_CONTINUATION_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)                         \
  V(UINT32_REGISTER)                        \
  V(BOOL_REGISTER)                          \
  V(FLOAT_REGISTER)                         \
  V(DOUBLE_REGISTER)                        \
  V(STACK_SLOT)                             \
  V(INT32_STACK_SLOT)                       \
  V(UINT32_STACK_SLOT)                      \
  V(BOOL_STACK_SLOT)                        \
  V(FLOAT_STACK_SLOT)                       \
  V(DOUBLE_STACK_SLOT)                      \
829
  V(LITERAL)
830

831 832
class Translation BASE_EMBEDDED {
 public:
833
#define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
834
  enum Opcode {
835 836
    TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
    LAST = LITERAL
837
  };
838
#undef DECLARE_TRANSLATION_OPCODE_ENUM
839

840 841
  Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
              Zone* zone)
842
      : buffer_(buffer),
843 844
        index_(buffer->CurrentIndex()),
        zone_(zone) {
845 846 847
    buffer_->Add(BEGIN);
    buffer_->Add(frame_count);
    buffer_->Add(jsframe_count);
848 849 850 851 852
  }

  int index() const { return index_; }

  // Commands.
853 854
  void BeginInterpretedFrame(BailoutId bytecode_offset, int literal_id,
                             unsigned height);
855
  void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
856 857
  void BeginConstructStubFrame(BailoutId bailout_id, int literal_id,
                               unsigned height);
858 859 860 861
  void BeginBuiltinContinuationFrame(BailoutId bailout_id, int literal_id,
                                     unsigned height);
  void BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,
                                               int literal_id, unsigned height);
862 863
  void ArgumentsElements(CreateArgumentsType type);
  void ArgumentsLength(CreateArgumentsType type);
864 865
  void BeginCapturedObject(int length);
  void DuplicateObject(int object_index);
866 867
  void StoreRegister(Register reg);
  void StoreInt32Register(Register reg);
868
  void StoreUint32Register(Register reg);
869
  void StoreBoolRegister(Register reg);
870
  void StoreFloatRegister(FloatRegister reg);
871 872 873
  void StoreDoubleRegister(DoubleRegister reg);
  void StoreStackSlot(int index);
  void StoreInt32StackSlot(int index);
874
  void StoreUint32StackSlot(int index);
875
  void StoreBoolStackSlot(int index);
876
  void StoreFloatStackSlot(int index);
877 878
  void StoreDoubleStackSlot(int index);
  void StoreLiteral(int literal_id);
879
  void StoreJSFrameFunction();
880

881
  Zone* zone() const { return zone_; }
882

883 884
  static int NumberOfOperandsFor(Opcode opcode);

885
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
886 887 888 889 890 891
  static const char* StringFor(Opcode opcode);
#endif

 private:
  TranslationBuffer* buffer_;
  int index_;
892
  Zone* zone_;
893 894 895
};


jarin@chromium.org's avatar
jarin@chromium.org committed
896 897 898 899 900 901 902
class MaterializedObjectStore {
 public:
  explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
  }

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

 private:
906
  Isolate* isolate() const { return isolate_; }
jarin@chromium.org's avatar
jarin@chromium.org committed
907 908 909 910 911 912
  Handle<FixedArray> GetStackEntries();
  Handle<FixedArray> EnsureStackEntries(int size);

  int StackIdToIndex(Address fp);

  Isolate* isolate_;
913
  std::vector<Address> frame_fps_;
914 915 916
};


917 918 919 920
// 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.
921 922
// Represents parameters in unadapted form so their number might mismatch
// formal parameter count.
923 924
class DeoptimizedFrameInfo : public Malloced {
 public:
925 926 927
  DeoptimizedFrameInfo(TranslatedState* state,
                       TranslatedState::iterator frame_it, Isolate* isolate);

928
  // Return the number of incoming arguments.
929
  int parameters_count() { return static_cast<int>(parameters_.size()); }
930

931
  // Return the height of the expression stack.
932
  int expression_count() { return static_cast<int>(expression_stack_.size()); }
933

934
  // Get the frame function.
935
  Handle<JSFunction> GetFunction() { return function_; }
936

937
  // Get the frame context.
938
  Handle<Object> GetContext() { return context_; }
939

940 941 942 943 944 945
  // Check if this frame is preceded by construct stub frame.  The bottom-most
  // inlined frame might still be called by an uninlined construct stub.
  bool HasConstructStub() {
    return has_construct_stub_;
  }

946
  // Get an incoming argument.
947
  Handle<Object> GetParameter(int index) {
948
    DCHECK(0 <= index && index < parameters_count());
949 950 951
    return parameters_[index];
  }

952
  // Get an expression from the expression stack.
953
  Handle<Object> GetExpression(int index) {
954
    DCHECK(0 <= index && index < expression_count());
955 956 957
    return expression_stack_[index];
  }

958 959
  int GetSourcePosition() {
    return source_position_;
960 961
  }

962
 private:
963
  // Set an incoming argument.
964
  void SetParameter(int index, Handle<Object> obj) {
965
    DCHECK(0 <= index && index < parameters_count());
966 967 968
    parameters_[index] = obj;
  }

969
  // Set an expression on the expression stack.
970
  void SetExpression(int index, Handle<Object> obj) {
971
    DCHECK(0 <= index && index < expression_count());
972 973 974
    expression_stack_[index] = obj;
  }

975 976
  Handle<JSFunction> function_;
  Handle<Object> context_;
977
  bool has_construct_stub_;
978 979
  std::vector<Handle<Object> > parameters_;
  std::vector<Handle<Object> > expression_stack_;
980
  int source_position_;
981 982 983 984

  friend class Deoptimizer;
};

985 986
}  // namespace internal
}  // namespace v8
987 988

#endif  // V8_DEOPTIMIZER_H_