deoptimizer.h 30.5 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 "src/v8.h"
9

10 11 12
#include "src/allocation.h"
#include "src/macro-assembler.h"
#include "src/zone-inl.h"
13 14 15 16 17


namespace v8 {
namespace internal {

18 19

static inline double read_double_value(Address p) {
20 21 22
  double d;
  memcpy(&d, p, sizeof(d));
  return d;
23 24 25
}


26 27
class FrameDescription;
class TranslationIterator;
28
class DeoptimizedFrameInfo;
29

30
template<typename T>
31
class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
32
 public:
33 34
  HeapNumberMaterializationDescriptor(T destination, double value)
      : destination_(destination), value_(value) { }
35

36 37
  T destination() const { return destination_; }
  double value() const { return value_; }
38 39

 private:
40 41
  T destination_;
  double value_;
42 43 44
};


45
class ObjectMaterializationDescriptor BASE_EMBEDDED {
46
 public:
47 48 49 50 51 52 53
  ObjectMaterializationDescriptor(
      Address slot_address, int frame, int length, int duplicate, bool is_args)
      : slot_address_(slot_address),
        jsframe_index_(frame),
        object_length_(length),
        duplicate_object_(duplicate),
        is_arguments_(is_args) { }
54 55

  Address slot_address() const { return slot_address_; }
56
  int jsframe_index() const { return jsframe_index_; }
57
  int object_length() const { return object_length_; }
58 59 60 61 62 63 64
  int duplicate_object() const { return duplicate_object_; }
  bool is_arguments() const { return is_arguments_; }

  // Only used for allocated receivers in DoComputeConstructStubFrame.
  void patch_slot_address(intptr_t slot) {
    slot_address_ = reinterpret_cast<Address>(slot);
  }
65 66 67

 private:
  Address slot_address_;
68
  int jsframe_index_;
69
  int object_length_;
70 71
  int duplicate_object_;
  bool is_arguments_;
72 73 74
};


75 76 77 78 79
class OptimizedFunctionVisitor BASE_EMBEDDED {
 public:
  virtual ~OptimizedFunctionVisitor() {}

  // Function which is called before iteration of any optimized functions
80
  // from given native context.
81 82 83 84 85
  virtual void EnterContext(Context* context) = 0;

  virtual void VisitFunction(JSFunction* function) = 0;

  // Function which is called after iteration of all optimized functions
86
  // from given native context.
87 88 89 90 91 92 93 94 95
  virtual void LeaveContext(Context* context) = 0;
};


class Deoptimizer : public Malloced {
 public:
  enum BailoutType {
    EAGER,
    LAZY,
96
    SOFT,
97 98 99
    // This last bailout type is not really a bailout, but used by the
    // debugger to deoptimize stack frames to allow inspection.
    DEBUGGER
100 101
  };

102 103
  static const int kBailoutTypesWithCodeEntry = SOFT + 1;

104
  struct Reason {
105 106
    Reason(int r, const char* m, const char* d)
        : raw_position(r), mnemonic(m), detail(d) {}
107 108 109 110 111 112 113 114 115

    bool operator==(const Reason& other) const {
      return raw_position == other.raw_position &&
             CStringEquals(mnemonic, other.mnemonic) &&
             CStringEquals(detail, other.detail);
    }

    bool operator!=(const Reason& other) const { return !(*this == other); }

116
    int raw_position;
117 118 119 120
    const char* mnemonic;
    const char* detail;
  };

121
  struct JumpTableEntry : public ZoneObject {
122 123
    inline JumpTableEntry(Address entry, const Reason& the_reason,
                          Deoptimizer::BailoutType type, bool frame)
124 125
        : label(),
          address(entry),
126
          reason(the_reason),
127
          bailout_type(type),
128
          needs_frame(frame) {}
129 130 131 132 133 134 135

    bool IsEquivalentTo(const JumpTableEntry& other) const {
      return address == other.address && bailout_type == other.bailout_type &&
             needs_frame == other.needs_frame &&
             (!FLAG_trace_deopt || reason == other.reason);
    }

136 137
    Label label;
    Address address;
138
    Reason reason;
139 140 141 142
    Deoptimizer::BailoutType bailout_type;
    bool needs_frame;
  };

143 144
  static bool TraceEnabledFor(BailoutType deopt_type,
                              StackFrame::Type frame_type);
145 146
  static const char* MessageFor(BailoutType type);

147 148
  int output_count() const { return output_count_; }

149 150 151
  Handle<JSFunction> function() const { return Handle<JSFunction>(function_); }
  Handle<Code> compiled_code() const { return Handle<Code>(compiled_code_); }
  BailoutType bailout_type() const { return bailout_type_; }
152

153 154 155
  // Number of created JS frames. Not all created frames are necessarily JS.
  int jsframe_count() const { return jsframe_count_; }

156 157 158 159
  static Deoptimizer* New(JSFunction* function,
                          BailoutType type,
                          unsigned bailout_id,
                          Address from,
160 161 162
                          int fp_to_sp_delta,
                          Isolate* isolate);
  static Deoptimizer* Grab(Isolate* isolate);
163

164 165 166
  // The returned object with information on the optimized frame needs to be
  // freed before another one can be generated.
  static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
167
                                                        int jsframe_index,
168 169 170 171
                                                        Isolate* isolate);
  static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
                                             Isolate* isolate);

172 173 174 175 176 177 178
  // Makes sure that there is enough room in the relocation
  // information of a code object to perform lazy deoptimization
  // patching. If there is not enough room a new relocation
  // information object is allocated and comments are added until it
  // is big enough.
  static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code);

179 180 181 182 183
  // Deoptimize the function now. Its current optimized code will never be run
  // again and any activations of the optimized code will get deoptimized when
  // execution returns.
  static void DeoptimizeFunction(JSFunction* function);

184
  // Deoptimize all code in the given isolate.
185
  static void DeoptimizeAll(Isolate* isolate);
186

187
  // Deoptimize code associated with the given global object.
188 189
  static void DeoptimizeGlobalObject(JSObject* object);

190 191 192 193
  // 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);
194

195 196 197
  // Visit all the known optimized functions in a given isolate.
  static void VisitAllOptimizedFunctions(
      Isolate* isolate, OptimizedFunctionVisitor* visitor);
198

199 200 201
  // The size in bytes of the code required at a lazy deopt patch site.
  static int patch_size();

202 203
  ~Deoptimizer();

204
  void MaterializeHeapObjects(JavaScriptFrameIterator* it);
205

206
  void MaterializeHeapNumbersForDebuggerInspectableFrame(
207 208 209 210 211
      Address parameters_top,
      uint32_t parameters_size,
      Address expressions_top,
      uint32_t expressions_size,
      DeoptimizedFrameInfo* info);
212

213
  static void ComputeOutputFrames(Deoptimizer* deoptimizer);
214

215 216 217 218 219 220 221 222

  enum GetEntryMode {
    CALCULATE_ENTRY_ADDRESS,
    ENSURE_ENTRY_CODE
  };


  static Address GetDeoptimizationEntry(
223
      Isolate* isolate,
224 225 226
      int id,
      BailoutType type,
      GetEntryMode mode = ENSURE_ENTRY_CODE);
227 228 229
  static int GetDeoptimizationId(Isolate* isolate,
                                 Address addr,
                                 BailoutType type);
230
  static int GetOutputInfo(DeoptimizationOutputData* data,
231
                           BailoutId node_id,
232
                           SharedFunctionInfo* shared);
233 234 235 236 237 238 239 240

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

241 242 243 244
  static int has_alignment_padding_offset() {
    return OFFSET_OF(Deoptimizer, has_alignment_padding_);
  }

245
  static int GetDeoptimizedCodeCount(Isolate* isolate);
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260

  static const int kNotDeoptimizationEntry = -1;

  // Generators for the deoptimization entry code.
  class EntryGenerator BASE_EMBEDDED {
   public:
    EntryGenerator(MacroAssembler* masm, BailoutType type)
        : masm_(masm), type_(type) { }
    virtual ~EntryGenerator() { }

    void Generate();

   protected:
    MacroAssembler* masm() const { return masm_; }
    BailoutType type() const { return type_; }
261
    Isolate* isolate() const { return masm_->isolate(); }
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283

    virtual void GeneratePrologue() { }

   private:
    MacroAssembler* masm_;
    Deoptimizer::BailoutType type_;
  };

  class TableEntryGenerator : public EntryGenerator {
   public:
    TableEntryGenerator(MacroAssembler* masm, BailoutType type,  int count)
        : EntryGenerator(masm, type), count_(count) { }

   protected:
    virtual void GeneratePrologue();

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

    int count_;
  };

284 285
  int ConvertJSFrameIndexToFrameIndex(int jsframe_index);

286 287
  static size_t GetMaxDeoptTableSize();

288 289
  static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
                                               BailoutType type,
290 291
                                               int max_entry_id);

292 293
  Isolate* isolate() const { return isolate_; }

294
 private:
295 296
  static const int kMinNumberOfEntries = 64;
  static const int kMaxNumberOfEntries = 16384;
297

298 299
  Deoptimizer(Isolate* isolate,
              JSFunction* function,
300 301 302
              BailoutType type,
              unsigned bailout_id,
              Address from,
303 304
              int fp_to_sp_delta,
              Code* optimized_code);
305 306
  Code* FindOptimizedCode(JSFunction* function, Code* optimized_code);
  void PrintFunctionName();
307 308 309
  void DeleteFrameDescriptions();

  void DoComputeOutputFrames();
310 311 312
  void DoComputeJSFrame(TranslationIterator* iterator, int frame_index);
  void DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
                                      int frame_index);
313 314
  void DoComputeConstructStubFrame(TranslationIterator* iterator,
                                   int frame_index);
315 316 317
  void DoComputeAccessorStubFrame(TranslationIterator* iterator,
                                  int frame_index,
                                  bool is_setter_stub_frame);
318 319
  void DoComputeCompiledStubFrame(TranslationIterator* iterator,
                                  int frame_index);
320

321 322
  // Translate object, store the result into an auxiliary array
  // (deferred_objects_tagged_values_).
323
  void DoTranslateObject(TranslationIterator* iterator,
324
                         int object_index,
325 326
                         int field_index);

327
  // Translate value, store the result into the given frame slot.
328
  void DoTranslateCommand(TranslationIterator* iterator,
329 330
                          int frame_index,
                          unsigned output_offset);
331

332 333 334 335
  // Translate object, do not store the result anywhere (but do update
  // the deferred materialization array).
  void DoTranslateObjectAndSkip(TranslationIterator* iterator);

336 337 338 339 340 341 342 343
  unsigned ComputeInputFrameSize() const;
  unsigned ComputeFixedSize(JSFunction* function) const;

  unsigned ComputeIncomingArgumentSize(JSFunction* function) const;
  unsigned ComputeOutgoingArgumentSize() const;

  Object* ComputeLiteral(int index) const;

344 345
  void AddObjectStart(intptr_t slot_address, int argc, bool is_arguments);
  void AddObjectDuplication(intptr_t slot, int object_index);
346 347
  void AddObjectTaggedValue(intptr_t value);
  void AddObjectDoubleValue(double value);
348
  void AddDoubleValue(intptr_t slot_address, double value);
349

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
  bool ArgumentsObjectIsAdapted(int object_index) {
    ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index);
    int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1;
    return jsframe_has_adapted_arguments_[reverse_jsframe_index];
  }

  Handle<JSFunction> ArgumentsObjectFunction(int object_index) {
    ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index);
    int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1;
    return jsframe_functions_[reverse_jsframe_index];
  }

  // Helper function for heap object materialization.
  Handle<Object> MaterializeNextHeapObject();
  Handle<Object> MaterializeNextValue();

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

369 370 371 372 373 374
  // Marks all the code in the given context for deoptimization.
  static void MarkAllCodeForContext(Context* native_context);

  // Visit all the known optimized functions in a given context.
  static void VisitAllOptimizedFunctionsForContext(
      Context* context, OptimizedFunctionVisitor* visitor);
375

376 377
  // Deoptimizes all code marked in the given context.
  static void DeoptimizeMarkedCodeForContext(Context* native_context);
378 379 380

  // Patch the given code so that it will deoptimize itself.
  static void PatchCodeForDeoptimization(Isolate* isolate, Code* code);
381

382 383 384 385 386
  // 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);

387 388 389 390 391
  // Fill the input from from a JavaScript frame. This is used when
  // the debugger needs to inspect an optimized frame. For normal
  // deoptimizations the input frame is filled in generated code.
  void FillInputFrame(Address tos, JavaScriptFrame* frame);

392 393 394
  // Fill the given output frame's registers to contain the failure handler
  // address and the number of parameters for a stub failure trampoline.
  void SetPlatformCompiledStubRegisters(FrameDescription* output_frame,
395
                                        CodeStubDescriptor* desc);
396 397 398 399 400

  // Fill the given output frame's double registers with the original values
  // from the input frame's double registers.
  void CopyDoubleRegisters(FrameDescription* output_frame);

401 402 403 404
  // Determines whether the input frame contains alignment padding by looking
  // at the dynamic alignment state slot inside the frame.
  bool HasAlignmentPadding(JSFunction* function);

405
  Isolate* isolate_;
406
  JSFunction* function_;
407
  Code* compiled_code_;
408 409 410 411
  unsigned bailout_id_;
  BailoutType bailout_type_;
  Address from_;
  int fp_to_sp_delta_;
412
  int has_alignment_padding_;
413 414 415 416 417

  // Input frame description.
  FrameDescription* input_;
  // Number of output frames.
  int output_count_;
418 419
  // Number of output js frames.
  int jsframe_count_;
420 421 422
  // Array of output frame descriptions.
  FrameDescription** output_;

423
  // Deferred values to be materialized.
424
  List<Object*> deferred_objects_tagged_values_;
425 426
  List<HeapNumberMaterializationDescriptor<int> >
      deferred_objects_double_values_;
427
  List<ObjectMaterializationDescriptor> deferred_objects_;
428
  List<HeapNumberMaterializationDescriptor<Address> > deferred_heap_numbers_;
429

jarin@chromium.org's avatar
jarin@chromium.org committed
430 431 432 433 434
  // Key for lookup of previously materialized objects
  Address stack_fp_;
  Handle<FixedArray> previously_materialized_objects_;
  int prev_materialized_count_;

435 436 437 438 439 440 441 442 443 444
  // Output frame information. Only used during heap object materialization.
  List<Handle<JSFunction> > jsframe_functions_;
  List<bool> jsframe_has_adapted_arguments_;

  // Materialized objects. Only used during heap object materialization.
  List<Handle<Object> >* materialized_values_;
  List<Handle<Object> >* materialized_objects_;
  int materialization_value_index_;
  int materialization_object_index_;

445 446 447
#ifdef DEBUG
  DisallowHeapAllocation* disallow_heap_allocation_;
#endif  // DEBUG
448

449
  CodeTracer::Scope* trace_scope_;
450

451
  static const int table_entry_size_;
452 453

  friend class FrameDescription;
454
  friend class DeoptimizedFrameInfo;
455 456 457 458 459 460 461 462 463
};


class FrameDescription {
 public:
  FrameDescription(uint32_t frame_size,
                   JSFunction* function);

  void* operator new(size_t size, uint32_t frame_size) {
464 465 466
    // 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);
467 468
  }

469 470 471 472
  void operator delete(void* pointer, uint32_t frame_size) {
    free(pointer);
  }

473 474 475 476
  void operator delete(void* description) {
    free(description);
  }

477
  uint32_t GetFrameSize() const {
478
    DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
479 480
    return static_cast<uint32_t>(frame_size_);
  }
481 482 483

  JSFunction* GetFunction() const { return function_; }

484
  unsigned GetOffsetFromSlotIndex(int slot_index);
485

486
  intptr_t GetFrameSlot(unsigned offset) {
487 488 489 490
    return *GetFrameSlotPointer(offset);
  }

  double GetDoubleFrameSlot(unsigned offset) {
491
    intptr_t* ptr = GetFrameSlotPointer(offset);
492
    return read_double_value(reinterpret_cast<Address>(ptr));
493 494
  }

495
  void SetFrameSlot(unsigned offset, intptr_t value) {
496 497 498
    *GetFrameSlotPointer(offset) = value;
  }

499 500 501 502
  void SetCallerPc(unsigned offset, intptr_t value);

  void SetCallerFp(unsigned offset, intptr_t value);

503 504
  void SetCallerConstantPool(unsigned offset, intptr_t value);

505
  intptr_t GetRegister(unsigned n) const {
506
#if DEBUG
507
    // This convoluted DCHECK is needed to work around a gcc problem that
508
    // improperly detects an array bounds overflow in optimized debug builds
509
    // when using a plain DCHECK.
510
    if (n >= arraysize(registers_)) {
511
      DCHECK(false);
512 513 514
      return 0;
    }
#endif
515 516 517 518
    return registers_[n];
  }

  double GetDoubleRegister(unsigned n) const {
519
    DCHECK(n < arraysize(double_registers_));
520 521 522
    return double_registers_[n];
  }

523
  void SetRegister(unsigned n, intptr_t value) {
524
    DCHECK(n < arraysize(registers_));
525 526 527 528
    registers_[n] = value;
  }

  void SetDoubleRegister(unsigned n, double value) {
529
    DCHECK(n < arraysize(double_registers_));
530 531 532
    double_registers_[n] = value;
  }

533 534
  intptr_t GetTop() const { return top_; }
  void SetTop(intptr_t top) { top_ = top; }
535

536 537
  intptr_t GetPc() const { return pc_; }
  void SetPc(intptr_t pc) { pc_ = pc; }
538

539 540
  intptr_t GetFp() const { return fp_; }
  void SetFp(intptr_t fp) { fp_ = fp; }
541

542 543 544
  intptr_t GetContext() const { return context_; }
  void SetContext(intptr_t context) { context_ = context; }

545 546 547 548 549
  intptr_t GetConstantPool() const { return constant_pool_; }
  void SetConstantPool(intptr_t constant_pool) {
    constant_pool_ = constant_pool;
  }

550 551 552
  Smi* GetState() const { return state_; }
  void SetState(Smi* state) { state_ = state; }

553
  void SetContinuation(intptr_t pc) { continuation_ = pc; }
554

555 556
  StackFrame::Type GetFrameType() const { return type_; }
  void SetFrameType(StackFrame::Type type) { type_ = type; }
557

558 559 560 561
  // Get the incoming arguments count.
  int ComputeParametersCount();

  // Get a parameter value for an unoptimized frame.
562
  Object* GetParameter(int index);
563

564
  // Get the expression stack height for a unoptimized frame.
565
  unsigned GetExpressionCount();
566 567

  // Get the expression stack value for an unoptimized frame.
568
  Object* GetExpression(int index);
569

570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
  static int registers_offset() {
    return OFFSET_OF(FrameDescription, registers_);
  }

  static int double_registers_offset() {
    return OFFSET_OF(FrameDescription, double_registers_);
  }

  static int frame_size_offset() {
    return OFFSET_OF(FrameDescription, frame_size_);
  }

  static int pc_offset() {
    return OFFSET_OF(FrameDescription, pc_);
  }

  static int state_offset() {
    return OFFSET_OF(FrameDescription, state_);
  }

  static int continuation_offset() {
    return OFFSET_OF(FrameDescription, continuation_);
  }

  static int frame_content_offset() {
595
    return OFFSET_OF(FrameDescription, frame_content_);
596 597 598 599 600
  }

 private:
  static const uint32_t kZapUint32 = 0xbeeddead;

601 602 603
  // 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.
604
  uintptr_t frame_size_;  // Number of bytes.
605
  JSFunction* function_;
606
  intptr_t registers_[Register::kNumRegisters];
607
  double double_registers_[DoubleRegister::kMaxNumRegisters];
608 609 610
  intptr_t top_;
  intptr_t pc_;
  intptr_t fp_;
611
  intptr_t context_;
612
  intptr_t constant_pool_;
613
  StackFrame::Type type_;
614 615 616 617
  Smi* state_;

  // Continuation is the PC where the execution continues after
  // deoptimizing.
618
  intptr_t continuation_;
619

620 621 622 623
  // 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];

624
  intptr_t* GetFrameSlotPointer(unsigned offset) {
625
    DCHECK(offset < frame_size_);
626
    return reinterpret_cast<intptr_t*>(
627 628
        reinterpret_cast<Address>(this) + frame_content_offset() + offset);
  }
629 630

  int ComputeFixedSize();
631 632 633
};


634 635 636 637 638 639 640 641 642 643 644 645 646 647
class DeoptimizerData {
 public:
  explicit DeoptimizerData(MemoryAllocator* allocator);
  ~DeoptimizerData();

  void Iterate(ObjectVisitor* v);

 private:
  MemoryAllocator* allocator_;
  int deopt_entry_code_entries_[Deoptimizer::kBailoutTypesWithCodeEntry];
  MemoryChunk* deopt_entry_code_[Deoptimizer::kBailoutTypesWithCodeEntry];

  DeoptimizedFrameInfo* deoptimized_frame_info_;

648
  Deoptimizer* current_;
649 650 651 652 653 654 655

  friend class Deoptimizer;

  DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
};


656 657
class TranslationBuffer BASE_EMBEDDED {
 public:
658
  explicit TranslationBuffer(Zone* zone) : contents_(256, zone) { }
659 660

  int CurrentIndex() const { return contents_.length(); }
661
  void Add(int32_t value, Zone* zone);
662

663
  Handle<ByteArray> CreateByteArray(Factory* factory);
664 665 666 667 668 669 670 671 672 673

 private:
  ZoneList<uint8_t> contents_;
};


class TranslationIterator BASE_EMBEDDED {
 public:
  TranslationIterator(ByteArray* buffer, int index)
      : buffer_(buffer), index_(index) {
674
    DCHECK(index >= 0 && index < buffer->length());
675 676 677 678
  }

  int32_t Next();

679
  bool HasNext() const { return index_ < buffer_->length(); }
680 681 682 683 684 685 686 687 688 689 690

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

 private:
  ByteArray* buffer_;
  int index_;
};


691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
#define TRANSLATION_OPCODE_LIST(V)                                             \
  V(BEGIN)                                                                     \
  V(JS_FRAME)                                                                  \
  V(CONSTRUCT_STUB_FRAME)                                                      \
  V(GETTER_STUB_FRAME)                                                         \
  V(SETTER_STUB_FRAME)                                                         \
  V(ARGUMENTS_ADAPTOR_FRAME)                                                   \
  V(COMPILED_STUB_FRAME)                                                       \
  V(DUPLICATED_OBJECT)                                                         \
  V(ARGUMENTS_OBJECT)                                                          \
  V(CAPTURED_OBJECT)                                                           \
  V(REGISTER)                                                                  \
  V(INT32_REGISTER)                                                            \
  V(UINT32_REGISTER)                                                           \
  V(DOUBLE_REGISTER)                                                           \
  V(STACK_SLOT)                                                                \
  V(INT32_STACK_SLOT)                                                          \
  V(UINT32_STACK_SLOT)                                                         \
  V(DOUBLE_STACK_SLOT)                                                         \
  V(LITERAL)


713 714
class Translation BASE_EMBEDDED {
 public:
715
#define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
716
  enum Opcode {
717 718
    TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
    LAST = LITERAL
719
  };
720
#undef DECLARE_TRANSLATION_OPCODE_ENUM
721

722 723
  Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
              Zone* zone)
724
      : buffer_(buffer),
725 726 727 728 729
        index_(buffer->CurrentIndex()),
        zone_(zone) {
    buffer_->Add(BEGIN, zone);
    buffer_->Add(frame_count, zone);
    buffer_->Add(jsframe_count, zone);
730 731 732 733 734
  }

  int index() const { return index_; }

  // Commands.
735
  void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height);
736
  void BeginCompiledStubFrame();
737
  void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
738
  void BeginConstructStubFrame(int literal_id, unsigned height);
739
  void BeginGetterStubFrame(int literal_id);
740
  void BeginSetterStubFrame(int literal_id);
741
  void BeginArgumentsObject(int args_length);
742 743
  void BeginCapturedObject(int length);
  void DuplicateObject(int object_index);
744 745
  void StoreRegister(Register reg);
  void StoreInt32Register(Register reg);
746
  void StoreUint32Register(Register reg);
747 748 749
  void StoreDoubleRegister(DoubleRegister reg);
  void StoreStackSlot(int index);
  void StoreInt32StackSlot(int index);
750
  void StoreUint32StackSlot(int index);
751 752
  void StoreDoubleStackSlot(int index);
  void StoreLiteral(int literal_id);
753
  void StoreArgumentsObject(bool args_known, int args_index, int args_length);
754

755
  Zone* zone() const { return zone_; }
756

757 758
  static int NumberOfOperandsFor(Opcode opcode);

759
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
760 761 762
  static const char* StringFor(Opcode opcode);
#endif

763 764 765
  // A literal id which refers to the JSFunction itself.
  static const int kSelfLiteralId = -239;

766 767 768
 private:
  TranslationBuffer* buffer_;
  int index_;
769
  Zone* zone_;
770 771 772
};


773 774 775 776 777 778
class SlotRef BASE_EMBEDDED {
 public:
  enum SlotRepresentation {
    UNKNOWN,
    TAGGED,
    INT32,
779
    UINT32,
780
    DOUBLE,
jarin@chromium.org's avatar
jarin@chromium.org committed
781 782 783 784 785 786
    LITERAL,
    DEFERRED_OBJECT,   // Object captured by the escape analysis.
                       // The number of nested objects can be obtained
                       // with the DeferredObjectLength() method
                       // (the SlotRefs of the nested objects follow
                       // this SlotRef in the depth-first order.)
787 788 789
    DUPLICATE_OBJECT,  // Duplicated object of a deferred object.
    ARGUMENTS_OBJECT   // Arguments object - only used to keep indexing
                       // in sync, it should not be materialized.
790 791 792 793 794 795 796 797
  };

  SlotRef()
      : addr_(NULL), representation_(UNKNOWN) { }

  SlotRef(Address addr, SlotRepresentation representation)
      : addr_(addr), representation_(representation) { }

798 799
  SlotRef(Isolate* isolate, Object* literal)
      : literal_(literal, isolate), representation_(LITERAL) { }
800

801 802 803 804 805 806 807
  static SlotRef NewArgumentsObject(int length) {
    SlotRef slot;
    slot.representation_ = ARGUMENTS_OBJECT;
    slot.deferred_object_length_ = length;
    return slot;
  }

jarin@chromium.org's avatar
jarin@chromium.org committed
808 809 810 811 812
  static SlotRef NewDeferredObject(int length) {
    SlotRef slot;
    slot.representation_ = DEFERRED_OBJECT;
    slot.deferred_object_length_ = length;
    return slot;
813 814
  }

jarin@chromium.org's avatar
jarin@chromium.org committed
815 816 817 818 819 820 821 822 823
  SlotRepresentation Representation() { return representation_; }

  static SlotRef NewDuplicateObject(int id) {
    SlotRef slot;
    slot.representation_ = DUPLICATE_OBJECT;
    slot.duplicate_object_id_ = id;
    return slot;
  }

824 825 826 827 828 829 830 831
  int GetChildrenCount() {
    if (representation_ == DEFERRED_OBJECT ||
        representation_ == ARGUMENTS_OBJECT) {
      return deferred_object_length_;
    } else {
      return 0;
    }
  }
jarin@chromium.org's avatar
jarin@chromium.org committed
832 833 834 835

  int DuplicateObjectId() { return duplicate_object_id_; }

  Handle<Object> GetValue(Isolate* isolate);
836 837

 private:
838 839 840
  Address addr_;
  Handle<Object> literal_;
  SlotRepresentation representation_;
jarin@chromium.org's avatar
jarin@chromium.org committed
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
  int deferred_object_length_;
  int duplicate_object_id_;
};

class SlotRefValueBuilder BASE_EMBEDDED {
 public:
  SlotRefValueBuilder(
      JavaScriptFrame* frame,
      int inlined_frame_index,
      int formal_parameter_count);

  void Prepare(Isolate* isolate);
  Handle<Object> GetNext(Isolate* isolate, int level);
  void Finish(Isolate* isolate);

  int args_length() { return args_length_; }

 private:
  List<Handle<Object> > materialized_objects_;
  Handle<FixedArray> previously_materialized_objects_;
  int prev_materialized_count_;
  Address stack_frame_id_;
  List<SlotRef> slot_refs_;
  int current_slot_;
  int args_length_;
  int first_slot_index_;

  static SlotRef ComputeSlotForNextArgument(
      Translation::Opcode opcode,
      TranslationIterator* iterator,
      DeoptimizationInputData* data,
      JavaScriptFrame* frame);

  Handle<Object> GetPreviouslyMaterialized(Isolate* isolate, int length);
875 876 877 878 879 880 881 882 883 884 885

  static Address SlotAddress(JavaScriptFrame* frame, int slot_index) {
    if (slot_index >= 0) {
      const int offset = JavaScriptFrameConstants::kLocal0Offset;
      return frame->fp() + offset - (slot_index * kPointerSize);
    } else {
      const int offset = JavaScriptFrameConstants::kLastParameterOffset;
      return frame->fp() + offset - ((slot_index + 1) * kPointerSize);
    }
  }

jarin@chromium.org's avatar
jarin@chromium.org committed
886 887
  Handle<Object> GetDeferredObject(Isolate* isolate);
};
888

jarin@chromium.org's avatar
jarin@chromium.org committed
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906
class MaterializedObjectStore {
 public:
  explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
  }

  Handle<FixedArray> Get(Address fp);
  void Set(Address fp, Handle<FixedArray> materialized_objects);
  void Remove(Address fp);

 private:
  Isolate* isolate() { return isolate_; }
  Handle<FixedArray> GetStackEntries();
  Handle<FixedArray> EnsureStackEntries(int size);

  int StackIdToIndex(Address fp);

  Isolate* isolate_;
  List<Address> frame_fps_;
907 908 909
};


910 911 912 913
// 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.
914 915
// Represents parameters in unadapted form so their number might mismatch
// formal parameter count.
916 917
class DeoptimizedFrameInfo : public Malloced {
 public:
918 919
  DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
                       int frame_index,
920 921
                       bool has_arguments_adaptor,
                       bool has_construct_stub);
922 923 924 925 926
  virtual ~DeoptimizedFrameInfo();

  // GC support.
  void Iterate(ObjectVisitor* v);

927 928 929
  // Return the number of incoming arguments.
  int parameters_count() { return parameters_count_; }

930 931 932
  // Return the height of the expression stack.
  int expression_count() { return expression_count_; }

933 934 935 936 937
  // Get the frame function.
  JSFunction* GetFunction() {
    return function_;
  }

938 939 940
  // Get the frame context.
  Object* GetContext() { return context_; }

941 942 943 944 945 946
  // 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_;
  }

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

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

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

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

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

976
  JSFunction* function_;
977
  Object* context_;
978
  bool has_construct_stub_;
979
  int parameters_count_;
980
  int expression_count_;
981
  Object** parameters_;
982
  Object** expression_stack_;
983
  int source_position_;
984 985 986 987

  friend class Deoptimizer;
};

988 989 990
} }  // namespace v8::internal

#endif  // V8_DEOPTIMIZER_H_