deoptimizer.h 30 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 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

static inline double read_double_value(Address p) {
#ifdef V8_HOST_CAN_READ_UNALIGNED
  return Memory::double_at(p);
#else  // V8_HOST_CAN_READ_UNALIGNED
  // Prevent gcc from using load-double (mips ldc1) on (possibly)
  // non-64-bit aligned address.
  union conversion {
    double d;
    uint32_t u[2];
  } c;
  c.u[0] = *reinterpret_cast<uint32_t*>(p);
  c.u[1] = *reinterpret_cast<uint32_t*>(p + 4);
  return c.d;
#endif  // V8_HOST_CAN_READ_UNALIGNED
}


36 37
class FrameDescription;
class TranslationIterator;
38
class DeoptimizedFrameInfo;
39

40
template<typename T>
41
class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
42
 public:
43 44
  HeapNumberMaterializationDescriptor(T destination, double value)
      : destination_(destination), value_(value) { }
45

46 47
  T destination() const { return destination_; }
  double value() const { return value_; }
48 49

 private:
50 51
  T destination_;
  double value_;
52 53 54
};


55
class ObjectMaterializationDescriptor BASE_EMBEDDED {
56
 public:
57 58 59 60 61 62 63
  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) { }
64 65

  Address slot_address() const { return slot_address_; }
66
  int jsframe_index() const { return jsframe_index_; }
67
  int object_length() const { return object_length_; }
68 69 70 71 72 73 74
  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);
  }
75 76 77

 private:
  Address slot_address_;
78
  int jsframe_index_;
79
  int object_length_;
80 81
  int duplicate_object_;
  bool is_arguments_;
82 83 84
};


85 86 87 88 89
class OptimizedFunctionVisitor BASE_EMBEDDED {
 public:
  virtual ~OptimizedFunctionVisitor() {}

  // Function which is called before iteration of any optimized functions
90
  // from given native context.
91 92 93 94 95
  virtual void EnterContext(Context* context) = 0;

  virtual void VisitFunction(JSFunction* function) = 0;

  // Function which is called after iteration of all optimized functions
96
  // from given native context.
97 98 99 100 101 102 103 104 105
  virtual void LeaveContext(Context* context) = 0;
};


class Deoptimizer : public Malloced {
 public:
  enum BailoutType {
    EAGER,
    LAZY,
106
    SOFT,
107 108 109
    // This last bailout type is not really a bailout, but used by the
    // debugger to deoptimize stack frames to allow inspection.
    DEBUGGER
110 111
  };

112 113
  static const int kBailoutTypesWithCodeEntry = SOFT + 1;

114
  struct JumpTableEntry : public ZoneObject {
115 116 117 118 119 120 121 122 123 124 125 126 127
    inline JumpTableEntry(Address entry,
                          Deoptimizer::BailoutType type,
                          bool frame)
        : label(),
          address(entry),
          bailout_type(type),
          needs_frame(frame) { }
    Label label;
    Address address;
    Deoptimizer::BailoutType bailout_type;
    bool needs_frame;
  };

128 129
  static bool TraceEnabledFor(BailoutType deopt_type,
                              StackFrame::Type frame_type);
130 131
  static const char* MessageFor(BailoutType type);

132 133
  int output_count() const { return output_count_; }

134 135 136
  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_; }
137

138 139 140
  // Number of created JS frames. Not all created frames are necessarily JS.
  int jsframe_count() const { return jsframe_count_; }

141 142 143 144
  static Deoptimizer* New(JSFunction* function,
                          BailoutType type,
                          unsigned bailout_id,
                          Address from,
145 146 147
                          int fp_to_sp_delta,
                          Isolate* isolate);
  static Deoptimizer* Grab(Isolate* isolate);
148

149 150 151
  // The returned object with information on the optimized frame needs to be
  // freed before another one can be generated.
  static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
152
                                                        int jsframe_index,
153 154 155 156
                                                        Isolate* isolate);
  static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
                                             Isolate* isolate);

157 158 159 160 161 162 163
  // 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);

164 165 166 167 168
  // 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);

169
  // Deoptimize all code in the given isolate.
170
  static void DeoptimizeAll(Isolate* isolate);
171

172
  // Deoptimize code associated with the given global object.
173 174
  static void DeoptimizeGlobalObject(JSObject* object);

175 176 177 178
  // 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);
179

180 181 182
  // Visit all the known optimized functions in a given isolate.
  static void VisitAllOptimizedFunctions(
      Isolate* isolate, OptimizedFunctionVisitor* visitor);
183

184 185 186
  // The size in bytes of the code required at a lazy deopt patch site.
  static int patch_size();

187 188
  ~Deoptimizer();

189
  void MaterializeHeapObjects(JavaScriptFrameIterator* it);
190

191
  void MaterializeHeapNumbersForDebuggerInspectableFrame(
192 193 194 195 196
      Address parameters_top,
      uint32_t parameters_size,
      Address expressions_top,
      uint32_t expressions_size,
      DeoptimizedFrameInfo* info);
197

198
  static void ComputeOutputFrames(Deoptimizer* deoptimizer);
199

200 201 202 203 204 205 206 207

  enum GetEntryMode {
    CALCULATE_ENTRY_ADDRESS,
    ENSURE_ENTRY_CODE
  };


  static Address GetDeoptimizationEntry(
208
      Isolate* isolate,
209 210 211
      int id,
      BailoutType type,
      GetEntryMode mode = ENSURE_ENTRY_CODE);
212 213 214
  static int GetDeoptimizationId(Isolate* isolate,
                                 Address addr,
                                 BailoutType type);
215
  static int GetOutputInfo(DeoptimizationOutputData* data,
216
                           BailoutId node_id,
217
                           SharedFunctionInfo* shared);
218 219 220 221 222 223 224 225

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

226 227 228 229
  static int has_alignment_padding_offset() {
    return OFFSET_OF(Deoptimizer, has_alignment_padding_);
  }

230
  static int GetDeoptimizedCodeCount(Isolate* isolate);
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245

  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_; }
246
    Isolate* isolate() const { return masm_->isolate(); }
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

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

269 270
  int ConvertJSFrameIndexToFrameIndex(int jsframe_index);

271 272
  static size_t GetMaxDeoptTableSize();

273 274
  static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
                                               BailoutType type,
275 276
                                               int max_entry_id);

277 278
  Isolate* isolate() const { return isolate_; }

279
 private:
280 281
  static const int kMinNumberOfEntries = 64;
  static const int kMaxNumberOfEntries = 16384;
282

283 284
  Deoptimizer(Isolate* isolate,
              JSFunction* function,
285 286 287
              BailoutType type,
              unsigned bailout_id,
              Address from,
288 289
              int fp_to_sp_delta,
              Code* optimized_code);
290 291
  Code* FindOptimizedCode(JSFunction* function, Code* optimized_code);
  void PrintFunctionName();
292 293 294
  void DeleteFrameDescriptions();

  void DoComputeOutputFrames();
295 296 297
  void DoComputeJSFrame(TranslationIterator* iterator, int frame_index);
  void DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
                                      int frame_index);
298 299
  void DoComputeConstructStubFrame(TranslationIterator* iterator,
                                   int frame_index);
300 301 302
  void DoComputeAccessorStubFrame(TranslationIterator* iterator,
                                  int frame_index,
                                  bool is_setter_stub_frame);
303 304
  void DoComputeCompiledStubFrame(TranslationIterator* iterator,
                                  int frame_index);
305

306 307
  // Translate object, store the result into an auxiliary array
  // (deferred_objects_tagged_values_).
308
  void DoTranslateObject(TranslationIterator* iterator,
309
                         int object_index,
310 311
                         int field_index);

312
  // Translate value, store the result into the given frame slot.
313
  void DoTranslateCommand(TranslationIterator* iterator,
314 315
                          int frame_index,
                          unsigned output_offset);
316

317 318 319 320
  // Translate object, do not store the result anywhere (but do update
  // the deferred materialization array).
  void DoTranslateObjectAndSkip(TranslationIterator* iterator);

321 322 323 324 325 326 327 328
  unsigned ComputeInputFrameSize() const;
  unsigned ComputeFixedSize(JSFunction* function) const;

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

  Object* ComputeLiteral(int index) const;

329 330
  void AddObjectStart(intptr_t slot_address, int argc, bool is_arguments);
  void AddObjectDuplication(intptr_t slot, int object_index);
331 332
  void AddObjectTaggedValue(intptr_t value);
  void AddObjectDoubleValue(double value);
333
  void AddDoubleValue(intptr_t slot_address, double value);
334

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
  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();

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

354 355 356 357 358 359
  // 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);
360

361 362
  // Deoptimizes all code marked in the given context.
  static void DeoptimizeMarkedCodeForContext(Context* native_context);
363 364 365

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

367 368 369 370 371
  // 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);

372 373 374 375 376
  // 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);

377 378 379 380 381 382 383 384 385
  // 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,
                                        CodeStubInterfaceDescriptor* desc);

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

386 387 388 389
  // Determines whether the input frame contains alignment padding by looking
  // at the dynamic alignment state slot inside the frame.
  bool HasAlignmentPadding(JSFunction* function);

390
  Isolate* isolate_;
391
  JSFunction* function_;
392
  Code* compiled_code_;
393 394 395 396
  unsigned bailout_id_;
  BailoutType bailout_type_;
  Address from_;
  int fp_to_sp_delta_;
397
  int has_alignment_padding_;
398 399 400 401 402

  // Input frame description.
  FrameDescription* input_;
  // Number of output frames.
  int output_count_;
403 404
  // Number of output js frames.
  int jsframe_count_;
405 406 407
  // Array of output frame descriptions.
  FrameDescription** output_;

408
  // Deferred values to be materialized.
409
  List<Object*> deferred_objects_tagged_values_;
410 411
  List<HeapNumberMaterializationDescriptor<int> >
      deferred_objects_double_values_;
412
  List<ObjectMaterializationDescriptor> deferred_objects_;
413
  List<HeapNumberMaterializationDescriptor<Address> > deferred_heap_numbers_;
414

jarin@chromium.org's avatar
jarin@chromium.org committed
415 416 417 418 419
  // Key for lookup of previously materialized objects
  Address stack_fp_;
  Handle<FixedArray> previously_materialized_objects_;
  int prev_materialized_count_;

420 421 422 423 424 425 426 427 428 429
  // 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_;

430 431 432
#ifdef DEBUG
  DisallowHeapAllocation* disallow_heap_allocation_;
#endif  // DEBUG
433

434
  CodeTracer::Scope* trace_scope_;
435

436
  static const int table_entry_size_;
437 438

  friend class FrameDescription;
439
  friend class DeoptimizedFrameInfo;
440 441 442 443 444 445 446 447 448
};


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

  void* operator new(size_t size, uint32_t frame_size) {
449 450 451
    // 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);
452 453
  }

454 455 456 457
  void operator delete(void* pointer, uint32_t frame_size) {
    free(pointer);
  }

458 459 460 461
  void operator delete(void* description) {
    free(description);
  }

462 463 464 465
  uint32_t GetFrameSize() const {
    ASSERT(static_cast<uint32_t>(frame_size_) == frame_size_);
    return static_cast<uint32_t>(frame_size_);
  }
466 467 468

  JSFunction* GetFunction() const { return function_; }

469
  unsigned GetOffsetFromSlotIndex(int slot_index);
470

471
  intptr_t GetFrameSlot(unsigned offset) {
472 473 474 475
    return *GetFrameSlotPointer(offset);
  }

  double GetDoubleFrameSlot(unsigned offset) {
476
    intptr_t* ptr = GetFrameSlotPointer(offset);
477
    return read_double_value(reinterpret_cast<Address>(ptr));
478 479
  }

480
  void SetFrameSlot(unsigned offset, intptr_t value) {
481 482 483
    *GetFrameSlotPointer(offset) = value;
  }

484 485 486 487
  void SetCallerPc(unsigned offset, intptr_t value);

  void SetCallerFp(unsigned offset, intptr_t value);

488 489
  void SetCallerConstantPool(unsigned offset, intptr_t value);

490
  intptr_t GetRegister(unsigned n) const {
491 492 493 494 495 496 497 498 499
#if DEBUG
    // This convoluted ASSERT is needed to work around a gcc problem that
    // improperly detects an array bounds overflow in optimized debug builds
    // when using a plain ASSERT.
    if (n >= ARRAY_SIZE(registers_)) {
      ASSERT(false);
      return 0;
    }
#endif
500 501 502 503 504 505 506 507
    return registers_[n];
  }

  double GetDoubleRegister(unsigned n) const {
    ASSERT(n < ARRAY_SIZE(double_registers_));
    return double_registers_[n];
  }

508
  void SetRegister(unsigned n, intptr_t value) {
509 510 511 512 513 514 515 516 517
    ASSERT(n < ARRAY_SIZE(registers_));
    registers_[n] = value;
  }

  void SetDoubleRegister(unsigned n, double value) {
    ASSERT(n < ARRAY_SIZE(double_registers_));
    double_registers_[n] = value;
  }

518 519
  intptr_t GetTop() const { return top_; }
  void SetTop(intptr_t top) { top_ = top; }
520

521 522
  intptr_t GetPc() const { return pc_; }
  void SetPc(intptr_t pc) { pc_ = pc; }
523

524 525
  intptr_t GetFp() const { return fp_; }
  void SetFp(intptr_t fp) { fp_ = fp; }
526

527 528 529
  intptr_t GetContext() const { return context_; }
  void SetContext(intptr_t context) { context_ = context; }

530 531 532 533 534
  intptr_t GetConstantPool() const { return constant_pool_; }
  void SetConstantPool(intptr_t constant_pool) {
    constant_pool_ = constant_pool;
  }

535 536 537
  Smi* GetState() const { return state_; }
  void SetState(Smi* state) { state_ = state; }

538
  void SetContinuation(intptr_t pc) { continuation_ = pc; }
539

540 541
  StackFrame::Type GetFrameType() const { return type_; }
  void SetFrameType(StackFrame::Type type) { type_ = type; }
542

543 544 545 546
  // Get the incoming arguments count.
  int ComputeParametersCount();

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

549
  // Get the expression stack height for a unoptimized frame.
550
  unsigned GetExpressionCount();
551 552

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

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
  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() {
580
    return OFFSET_OF(FrameDescription, frame_content_);
581 582 583 584 585
  }

 private:
  static const uint32_t kZapUint32 = 0xbeeddead;

586 587 588
  // 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.
589
  uintptr_t frame_size_;  // Number of bytes.
590
  JSFunction* function_;
591
  intptr_t registers_[Register::kNumRegisters];
592
  double double_registers_[DoubleRegister::kMaxNumRegisters];
593 594 595
  intptr_t top_;
  intptr_t pc_;
  intptr_t fp_;
596
  intptr_t context_;
597
  intptr_t constant_pool_;
598
  StackFrame::Type type_;
599 600 601 602
  Smi* state_;

  // Continuation is the PC where the execution continues after
  // deoptimizing.
603
  intptr_t continuation_;
604

605 606 607 608
  // 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];

609
  intptr_t* GetFrameSlotPointer(unsigned offset) {
610
    ASSERT(offset < frame_size_);
611
    return reinterpret_cast<intptr_t*>(
612 613
        reinterpret_cast<Address>(this) + frame_content_offset() + offset);
  }
614 615

  int ComputeFixedSize();
616 617 618
};


619 620 621 622 623 624 625 626 627 628 629 630 631 632
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_;

633
  Deoptimizer* current_;
634 635 636 637 638 639 640

  friend class Deoptimizer;

  DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
};


641 642
class TranslationBuffer BASE_EMBEDDED {
 public:
643
  explicit TranslationBuffer(Zone* zone) : contents_(256, zone) { }
644 645

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

648
  Handle<ByteArray> CreateByteArray(Factory* factory);
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663

 private:
  ZoneList<uint8_t> contents_;
};


class TranslationIterator BASE_EMBEDDED {
 public:
  TranslationIterator(ByteArray* buffer, int index)
      : buffer_(buffer), index_(index) {
    ASSERT(index >= 0 && index < buffer->length());
  }

  int32_t Next();

664
  bool HasNext() const { return index_ < buffer_->length(); }
665 666 667 668 669 670 671 672 673 674 675

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

 private:
  ByteArray* buffer_;
  int index_;
};


676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
#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)


698 699
class Translation BASE_EMBEDDED {
 public:
700
#define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
701
  enum Opcode {
702 703
    TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
    LAST = LITERAL
704
  };
705
#undef DECLARE_TRANSLATION_OPCODE_ENUM
706

707 708
  Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
              Zone* zone)
709
      : buffer_(buffer),
710 711 712 713 714
        index_(buffer->CurrentIndex()),
        zone_(zone) {
    buffer_->Add(BEGIN, zone);
    buffer_->Add(frame_count, zone);
    buffer_->Add(jsframe_count, zone);
715 716 717 718 719
  }

  int index() const { return index_; }

  // Commands.
720
  void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height);
721
  void BeginCompiledStubFrame();
722
  void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
723
  void BeginConstructStubFrame(int literal_id, unsigned height);
724
  void BeginGetterStubFrame(int literal_id);
725
  void BeginSetterStubFrame(int literal_id);
726
  void BeginArgumentsObject(int args_length);
727 728
  void BeginCapturedObject(int length);
  void DuplicateObject(int object_index);
729 730
  void StoreRegister(Register reg);
  void StoreInt32Register(Register reg);
731
  void StoreUint32Register(Register reg);
732 733 734
  void StoreDoubleRegister(DoubleRegister reg);
  void StoreStackSlot(int index);
  void StoreInt32StackSlot(int index);
735
  void StoreUint32StackSlot(int index);
736 737
  void StoreDoubleStackSlot(int index);
  void StoreLiteral(int literal_id);
738
  void StoreArgumentsObject(bool args_known, int args_index, int args_length);
739

740
  Zone* zone() const { return zone_; }
741

742 743
  static int NumberOfOperandsFor(Opcode opcode);

744
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
745 746 747
  static const char* StringFor(Opcode opcode);
#endif

748 749 750
  // A literal id which refers to the JSFunction itself.
  static const int kSelfLiteralId = -239;

751 752 753
 private:
  TranslationBuffer* buffer_;
  int index_;
754
  Zone* zone_;
755 756 757
};


758 759 760 761 762 763
class SlotRef BASE_EMBEDDED {
 public:
  enum SlotRepresentation {
    UNKNOWN,
    TAGGED,
    INT32,
764
    UINT32,
765
    DOUBLE,
jarin@chromium.org's avatar
jarin@chromium.org committed
766 767 768 769 770 771
    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.)
772 773 774
    DUPLICATE_OBJECT,  // Duplicated object of a deferred object.
    ARGUMENTS_OBJECT   // Arguments object - only used to keep indexing
                       // in sync, it should not be materialized.
775 776 777 778 779 780 781 782
  };

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

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

783 784
  SlotRef(Isolate* isolate, Object* literal)
      : literal_(literal, isolate), representation_(LITERAL) { }
785

786 787 788 789 790 791 792
  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
793 794 795 796 797
  static SlotRef NewDeferredObject(int length) {
    SlotRef slot;
    slot.representation_ = DEFERRED_OBJECT;
    slot.deferred_object_length_ = length;
    return slot;
798 799
  }

jarin@chromium.org's avatar
jarin@chromium.org committed
800 801 802 803 804 805 806 807 808
  SlotRepresentation Representation() { return representation_; }

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

809 810 811 812 813 814 815 816
  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
817 818 819 820

  int DuplicateObjectId() { return duplicate_object_id_; }

  Handle<Object> GetValue(Isolate* isolate);
821 822

 private:
823 824 825
  Address addr_;
  Handle<Object> literal_;
  SlotRepresentation representation_;
jarin@chromium.org's avatar
jarin@chromium.org committed
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
  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);
860 861 862 863 864 865 866 867 868 869 870

  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
871 872
  Handle<Object> GetDeferredObject(Isolate* isolate);
};
873

jarin@chromium.org's avatar
jarin@chromium.org committed
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
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_;
892 893 894
};


895 896 897 898
// 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.
899 900
// Represents parameters in unadapted form so their number might mismatch
// formal parameter count.
901 902
class DeoptimizedFrameInfo : public Malloced {
 public:
903 904
  DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
                       int frame_index,
905 906
                       bool has_arguments_adaptor,
                       bool has_construct_stub);
907 908 909 910 911
  virtual ~DeoptimizedFrameInfo();

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

912 913 914
  // Return the number of incoming arguments.
  int parameters_count() { return parameters_count_; }

915 916 917
  // Return the height of the expression stack.
  int expression_count() { return expression_count_; }

918 919 920 921 922
  // Get the frame function.
  JSFunction* GetFunction() {
    return function_;
  }

923 924 925 926 927 928
  // 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_;
  }

929 930 931 932 933 934
  // Get an incoming argument.
  Object* GetParameter(int index) {
    ASSERT(0 <= index && index < parameters_count());
    return parameters_[index];
  }

935 936 937 938 939 940
  // Get an expression from the expression stack.
  Object* GetExpression(int index) {
    ASSERT(0 <= index && index < expression_count());
    return expression_stack_[index];
  }

941 942
  int GetSourcePosition() {
    return source_position_;
943 944
  }

945
 private:
946 947 948 949 950 951
  // Set an incoming argument.
  void SetParameter(int index, Object* obj) {
    ASSERT(0 <= index && index < parameters_count());
    parameters_[index] = obj;
  }

952 953 954 955 956 957
  // Set an expression on the expression stack.
  void SetExpression(int index, Object* obj) {
    ASSERT(0 <= index && index < expression_count());
    expression_stack_[index] = obj;
  }

958
  JSFunction* function_;
959
  bool has_construct_stub_;
960
  int parameters_count_;
961
  int expression_count_;
962
  Object** parameters_;
963
  Object** expression_stack_;
964
  int source_position_;
965 966 967 968

  friend class Deoptimizer;
};

969 970 971
} }  // namespace v8::internal

#endif  // V8_DEOPTIMIZER_H_