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

#ifndef V8_DEOPTIMIZER_H_
#define V8_DEOPTIMIZER_H_

8 9
#include "src/allocation.h"
#include "src/macro-assembler.h"
10 11 12 13 14 15 16


namespace v8 {
namespace internal {

class FrameDescription;
class TranslationIterator;
17
class DeoptimizedFrameInfo;
18 19 20
class TranslatedState;
class RegisterValues;

jarin's avatar
jarin committed
21
class TranslatedValue {
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
 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;

 private:
  friend class TranslatedState;
  friend class TranslatedFrame;

  enum Kind {
    kInvalid,
    kTagged,
    kInt32,
    kUInt32,
    kBoolBit,
    kDouble,
    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.
    kArgumentsObject    // Arguments object - only used to keep indexing
                        // in sync, it should not be materialized.
  };

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

  static TranslatedValue NewArgumentsObject(TranslatedState* container,
                                            int length, int object_index);
  static TranslatedValue NewDeferredObject(TranslatedState* container,
                                           int length, int object_index);
  static TranslatedValue NewDuplicateObject(TranslatedState* container, int id);
  static TranslatedValue NewDouble(TranslatedState* container, double value);
  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);
68
  static TranslatedValue NewInvalid(TranslatedState* container);
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

  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_;
    int length_;  // Applies only to kArgumentsObject or kCapturedObject kinds.
  };

  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_;
    // kind is kDouble
    double double_value_;
    // kind is kDuplicatedObject or kArgumentsObject or kCapturedObject.
    MaterializedObjectInfo materialization_info_;
  };

  // Checked accessors for the union members.
  Object* raw_literal() const;
  int32_t int32_value() const;
  uint32_t uint32_value() const;
  double double_value() const;
  int object_length() const;
  int object_index() const;
};


class TranslatedFrame {
 public:
  enum Kind {
    kFunction,
    kGetter,
    kSetter,
    kArgumentsAdaptor,
    kConstructStub,
    kCompiledStub,
    kInvalid
  };

  int GetValueCount();

  Kind kind() const { return kind_; }
126
  BailoutId node_id() const { return node_id_; }
127
  Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
128
  int height() const { return height_; }
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

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

160 161 162
  typedef TranslatedValue& reference;
  typedef TranslatedValue const& const_reference;

163 164
  iterator begin() { return iterator(values_.begin()); }
  iterator end() { return iterator(values_.end()); }
165

166 167
  reference front() { return values_.front(); }
  const_reference front() const { return values_.front(); }
168 169 170 171 172

 private:
  friend class TranslatedState;

  // Constructor static methods.
173 174 175 176 177
  static TranslatedFrame JSFrame(BailoutId node_id,
                                 SharedFunctionInfo* shared_info, int height);
  static TranslatedFrame AccessorFrame(Kind kind,
                                       SharedFunctionInfo* shared_info);
  static TranslatedFrame ArgumentsAdaptorFrame(SharedFunctionInfo* shared_info,
178
                                               int height);
179 180
  static TranslatedFrame ConstructStubFrame(SharedFunctionInfo* shared_info,
                                            int height);
181 182 183 184 185 186 187 188 189
  static TranslatedFrame CompiledStubFrame(int height, Isolate* isolate) {
    return TranslatedFrame(kCompiledStub, isolate, nullptr, height);
  }
  static TranslatedFrame InvalidFrame() {
    return TranslatedFrame(kInvalid, nullptr);
  }

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

190 191
  TranslatedFrame(Kind kind, Isolate* isolate,
                  SharedFunctionInfo* shared_info = nullptr, int height = 0)
192 193
      : kind_(kind),
        node_id_(BailoutId::None()),
194
        raw_shared_info_(shared_info),
195 196 197 198 199
        height_(height),
        isolate_(isolate) {}


  void Add(const TranslatedValue& value) { values_.push_back(value); }
200
  void Handlify();
201 202 203

  Kind kind_;
  BailoutId node_id_;
204 205
  SharedFunctionInfo* raw_shared_info_;
  Handle<SharedFunctionInfo> shared_info_;
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
  int height_;
  Isolate* isolate_;

  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();
  explicit TranslatedState(JavaScriptFrame* frame);

  void Prepare(bool has_adapted_arguments, Address stack_frame_pointer);

  // Store newly materialized values into the isolate.
  void StoreMaterializedValuesAndDeopt();

240 241 242 243
  typedef std::vector<TranslatedFrame>::iterator iterator;
  iterator begin() { return frames_.begin(); }
  iterator end() { return frames_.end(); }

244 245 246 247
  typedef std::vector<TranslatedFrame>::const_iterator const_iterator;
  const_iterator begin() const { return frames_.begin(); }
  const_iterator end() const { return frames_.end(); }

248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
  std::vector<TranslatedFrame>& frames() { return frames_; }

  TranslatedFrame* GetArgumentsInfoFromJSFrameIndex(int jsframe_index,
                                                    int* arguments_count);

  Isolate* isolate() { return isolate_; }

  void Init(Address input_frame_pointer, JSFunction* input_frame_function,
            TranslationIterator* iterator, FixedArray* literal_array,
            RegisterValues* registers, FILE* trace_file);

 private:
  friend TranslatedValue;

  TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator,
                                            FixedArray* literal_array,
                                            Address fp,
                                            JSFunction* frame_function,
                                            FILE* trace_file);
  TranslatedValue CreateNextTranslatedValue(int frame_index, int value_index,
                                            TranslationIterator* iterator,
                                            FixedArray* literal_array,
                                            Address fp,
                                            RegisterValues* registers,
                                            FILE* trace_file);

  void UpdateFromPreviouslyMaterializedObjects();
  Handle<Object> MaterializeAt(int frame_index, int* value_index);
  Handle<Object> MaterializeObjectAt(int object_index);
  bool GetAdaptedArguments(Handle<JSObject>* result, int frame_index);

  static uint32_t GetUInt32Slot(Address fp, int slot_index);

  std::vector<TranslatedFrame> frames_;
  Isolate* isolate_;
  Address stack_frame_pointer_;
  bool has_adapted_arguments_;

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

293

294 295 296 297 298
class OptimizedFunctionVisitor BASE_EMBEDDED {
 public:
  virtual ~OptimizedFunctionVisitor() {}

  // Function which is called before iteration of any optimized functions
299
  // from given native context.
300 301 302 303 304
  virtual void EnterContext(Context* context) = 0;

  virtual void VisitFunction(JSFunction* function) = 0;

  // Function which is called after iteration of all optimized functions
305
  // from given native context.
306 307 308 309
  virtual void LeaveContext(Context* context) = 0;
};


310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
#define DEOPT_MESSAGES_LIST(V)                                                 \
  V(kNoReason, "no reason")                                                    \
  V(kConstantGlobalVariableAssignment, "Constant global variable assignment")  \
  V(kConversionOverflow, "conversion overflow")                                \
  V(kDivisionByZero, "division by zero")                                       \
  V(kElementsKindUnhandledInKeyedLoadGenericStub,                              \
    "ElementsKind unhandled in KeyedLoadGenericStub")                          \
  V(kExpectedHeapNumber, "Expected heap number")                               \
  V(kExpectedSmi, "Expected smi")                                              \
  V(kForcedDeoptToRuntime, "Forced deopt to runtime")                          \
  V(kHole, "hole")                                                             \
  V(kHoleyArrayDespitePackedElements_kindFeedback,                             \
    "Holey array despite packed elements_kind feedback")                       \
  V(kInstanceMigrationFailed, "instance migration failed")                     \
  V(kInsufficientTypeFeedbackForCallWithArguments,                             \
    "Insufficient type feedback for call with arguments")                      \
  V(kInsufficientTypeFeedbackForCombinedTypeOfBinaryOperation,                 \
    "Insufficient type feedback for combined type of binary operation")        \
  V(kInsufficientTypeFeedbackForGenericNamedAccess,                            \
    "Insufficient type feedback for generic named access")                     \
  V(kInsufficientTypeFeedbackForKeyedLoad,                                     \
    "Insufficient type feedback for keyed load")                               \
  V(kInsufficientTypeFeedbackForKeyedStore,                                    \
    "Insufficient type feedback for keyed store")                              \
  V(kInsufficientTypeFeedbackForLHSOfBinaryOperation,                          \
    "Insufficient type feedback for LHS of binary operation")                  \
  V(kInsufficientTypeFeedbackForRHSOfBinaryOperation,                          \
    "Insufficient type feedback for RHS of binary operation")                  \
  V(kKeyIsNegative, "key is negative")                                         \
  V(kLostPrecision, "lost precision")                                          \
  V(kLostPrecisionOrNaN, "lost precision or NaN")                              \
  V(kMementoFound, "memento found")                                            \
  V(kMinusZero, "minus zero")                                                  \
  V(kNaN, "NaN")                                                               \
  V(kNegativeKeyEncountered, "Negative key encountered")                       \
  V(kNegativeValue, "negative value")                                          \
  V(kNoCache, "no cache")                                                      \
  V(kNonStrictElementsInKeyedLoadGenericStub,                                  \
    "non-strict elements in KeyedLoadGenericStub")                             \
349
  V(kNotADateObject, "not a date object")                                      \
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
  V(kNotAHeapNumber, "not a heap number")                                      \
  V(kNotAHeapNumberUndefinedBoolean, "not a heap number/undefined/true/false") \
  V(kNotAHeapNumberUndefined, "not a heap number/undefined")                   \
  V(kNotAJavaScriptObject, "not a JavaScript object")                          \
  V(kNotASmi, "not a Smi")                                                     \
  V(kNull, "null")                                                             \
  V(kOutOfBounds, "out of bounds")                                             \
  V(kOutsideOfRange, "Outside of range")                                       \
  V(kOverflow, "overflow")                                                     \
  V(kReceiverWasAGlobalObject, "receiver was a global object")                 \
  V(kSmi, "Smi")                                                               \
  V(kTooManyArguments, "too many arguments")                                   \
  V(kTooManyUndetectableTypes, "Too many undetectable types")                  \
  V(kTracingElementsTransitions, "Tracing elements transitions")               \
  V(kTypeMismatchBetweenFeedbackAndConstant,                                   \
    "Type mismatch between feedback and constant")                             \
  V(kUndefined, "undefined")                                                   \
  V(kUnexpectedCellContentsInConstantGlobalStore,                              \
    "Unexpected cell contents in constant global store")                       \
  V(kUnexpectedCellContentsInGlobalStore,                                      \
    "Unexpected cell contents in global store")                                \
  V(kUnexpectedObject, "unexpected object")                                    \
  V(kUnexpectedRHSOfBinaryOperation, "Unexpected RHS of binary operation")     \
  V(kUninitializedBoilerplateInFastClone,                                      \
    "Uninitialized boilerplate in fast clone")                                 \
  V(kUninitializedBoilerplateLiterals, "Uninitialized boilerplate literals")   \
  V(kUnknownMapInPolymorphicAccess, "Unknown map in polymorphic access")       \
  V(kUnknownMapInPolymorphicCall, "Unknown map in polymorphic call")           \
  V(kUnknownMapInPolymorphicElementAccess,                                     \
    "Unknown map in polymorphic element access")                               \
  V(kUnknownMap, "Unknown map")                                                \
  V(kValueMismatch, "value mismatch")                                          \
  V(kWrongInstanceType, "wrong instance type")                                 \
383
  V(kWrongMap, "wrong map")                                                    \
384 385
  V(kUndefinedOrNullInForIn, "null or undefined in for-in")                    \
  V(kUndefinedOrNullInToObject, "null or undefined in ToObject")
386 387


388 389 390 391 392
class Deoptimizer : public Malloced {
 public:
  enum BailoutType {
    EAGER,
    LAZY,
393
    SOFT,
394 395
    // This last bailout type is not really a bailout, but used by the
    // debugger to deoptimize stack frames to allow inspection.
396 397
    DEBUGGER,
    kBailoutTypesWithCodeEntry = SOFT + 1
398 399
  };

400 401 402 403 404 405 406
#define DEOPT_MESSAGES_CONSTANTS(C, T) C,
  enum DeoptReason {
    DEOPT_MESSAGES_LIST(DEOPT_MESSAGES_CONSTANTS) kLastDeoptReason
  };
#undef DEOPT_MESSAGES_CONSTANTS
  static const char* GetDeoptReason(DeoptReason deopt_reason);

407
  struct DeoptInfo {
408
    DeoptInfo(SourcePosition position, const char* m, DeoptReason d)
409
        : position(position), mnemonic(m), deopt_reason(d), inlining_id(0) {}
410

411
    SourcePosition position;
412
    const char* mnemonic;
413
    DeoptReason deopt_reason;
414
    int inlining_id;
415 416
  };

417
  static DeoptInfo GetDeoptInfo(Code* code, byte* from);
418

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

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

433 434
    Label label;
    Address address;
435
    DeoptInfo deopt_info;
436 437 438 439
    Deoptimizer::BailoutType bailout_type;
    bool needs_frame;
  };

440 441
  static bool TraceEnabledFor(BailoutType deopt_type,
                              StackFrame::Type frame_type);
442 443
  static const char* MessageFor(BailoutType type);

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

446 447 448
  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_; }
449

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

453 454 455 456
  static Deoptimizer* New(JSFunction* function,
                          BailoutType type,
                          unsigned bailout_id,
                          Address from,
457 458 459
                          int fp_to_sp_delta,
                          Isolate* isolate);
  static Deoptimizer* Grab(Isolate* isolate);
460

461 462 463
  // The returned object with information on the optimized frame needs to be
  // freed before another one can be generated.
  static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
464
                                                        int jsframe_index,
465 466 467 468
                                                        Isolate* isolate);
  static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
                                             Isolate* isolate);

469 470 471 472 473 474 475
  // 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);

476 477 478 479 480
  // 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);

481
  // Deoptimize all code in the given isolate.
482
  static void DeoptimizeAll(Isolate* isolate);
483

484 485 486 487
  // 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);
488

489 490 491
  // Visit all the known optimized functions in a given isolate.
  static void VisitAllOptimizedFunctions(
      Isolate* isolate, OptimizedFunctionVisitor* visitor);
492

493 494 495
  // The size in bytes of the code required at a lazy deopt patch site.
  static int patch_size();

496 497
  ~Deoptimizer();

498
  void MaterializeHeapObjects(JavaScriptFrameIterator* it);
499

500
  void MaterializeHeapNumbersForDebuggerInspectableFrame(
501
      int frame_index, int parameter_count, int expression_count,
502
      DeoptimizedFrameInfo* info);
503

504
  static void ComputeOutputFrames(Deoptimizer* deoptimizer);
505

506 507 508 509 510 511 512 513

  enum GetEntryMode {
    CALCULATE_ENTRY_ADDRESS,
    ENSURE_ENTRY_CODE
  };


  static Address GetDeoptimizationEntry(
514
      Isolate* isolate,
515 516 517
      int id,
      BailoutType type,
      GetEntryMode mode = ENSURE_ENTRY_CODE);
518 519 520
  static int GetDeoptimizationId(Isolate* isolate,
                                 Address addr,
                                 BailoutType type);
521
  static int GetOutputInfo(DeoptimizationOutputData* data,
522
                           BailoutId node_id,
523
                           SharedFunctionInfo* shared);
524 525 526 527 528 529 530 531

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

532 533 534 535
  static int has_alignment_padding_offset() {
    return OFFSET_OF(Deoptimizer, has_alignment_padding_);
  }

536
  static int GetDeoptimizedCodeCount(Isolate* isolate);
537 538 539 540

  static const int kNotDeoptimizationEntry = -1;

  // Generators for the deoptimization entry code.
541
  class TableEntryGenerator BASE_EMBEDDED {
542
   public:
543 544
    TableEntryGenerator(MacroAssembler* masm, BailoutType type, int count)
        : masm_(masm), type_(type), count_(count) {}
545 546 547 548 549 550

    void Generate();

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

553
    void GeneratePrologue();
554 555 556 557

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

558 559
    MacroAssembler* masm_;
    Deoptimizer::BailoutType type_;
560 561 562
    int count_;
  };

563 564
  int ConvertJSFrameIndexToFrameIndex(int jsframe_index);

565 566
  static size_t GetMaxDeoptTableSize();

567 568
  static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
                                               BailoutType type,
569 570
                                               int max_entry_id);

571 572
  Isolate* isolate() const { return isolate_; }

573
 private:
574 575
  static const int kMinNumberOfEntries = 64;
  static const int kMaxNumberOfEntries = 16384;
576

577 578
  Deoptimizer(Isolate* isolate,
              JSFunction* function,
579 580 581
              BailoutType type,
              unsigned bailout_id,
              Address from,
582 583
              int fp_to_sp_delta,
              Code* optimized_code);
584 585
  Code* FindOptimizedCode(JSFunction* function, Code* optimized_code);
  void PrintFunctionName();
586 587 588
  void DeleteFrameDescriptions();

  void DoComputeOutputFrames();
589 590 591
  void DoComputeJSFrame(TranslationIterator* iterator, int frame_index);
  void DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
                                      int frame_index);
592 593
  void DoComputeConstructStubFrame(TranslationIterator* iterator,
                                   int frame_index);
594 595 596
  void DoComputeAccessorStubFrame(TranslationIterator* iterator,
                                  int frame_index,
                                  bool is_setter_stub_frame);
597 598
  void DoComputeCompiledStubFrame(TranslationIterator* iterator,
                                  int frame_index);
599

600 601 602 603 604 605 606 607 608 609
  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);
610

611 612 613 614
  unsigned ComputeInputFrameSize() const;
  unsigned ComputeFixedSize(JSFunction* function) const;

  unsigned ComputeIncomingArgumentSize(JSFunction* function) const;
615
  static unsigned ComputeOutgoingArgumentSize(Code* code, unsigned bailout_id);
616 617 618 619 620 621

  Object* ComputeLiteral(int index) const;

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

622 623 624 625 626 627
  // 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);
628

629 630
  // Deoptimizes all code marked in the given context.
  static void DeoptimizeMarkedCodeForContext(Context* native_context);
631 632 633

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

635 636 637 638 639
  // 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);

640 641 642 643 644
  // 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);

645 646 647
  // 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,
648
                                        CodeStubDescriptor* desc);
649 650 651 652 653

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

654 655 656 657
  // Determines whether the input frame contains alignment padding by looking
  // at the dynamic alignment state slot inside the frame.
  bool HasAlignmentPadding(JSFunction* function);

658
  Isolate* isolate_;
659
  JSFunction* function_;
660
  Code* compiled_code_;
661 662 663 664
  unsigned bailout_id_;
  BailoutType bailout_type_;
  Address from_;
  int fp_to_sp_delta_;
665
  int has_alignment_padding_;
666 667 668 669 670

  // Input frame description.
  FrameDescription* input_;
  // Number of output frames.
  int output_count_;
671 672
  // Number of output js frames.
  int jsframe_count_;
673 674 675
  // Array of output frame descriptions.
  FrameDescription** output_;

jarin@chromium.org's avatar
jarin@chromium.org committed
676 677 678
  // Key for lookup of previously materialized objects
  Address stack_fp_;

679 680 681 682 683 684
  TranslatedState translated_state_;
  struct ValueToMaterialize {
    Address output_slot_address_;
    TranslatedFrame::iterator value_;
  };
  std::vector<ValueToMaterialize> values_to_materialize_;
685

686 687 688
#ifdef DEBUG
  DisallowHeapAllocation* disallow_heap_allocation_;
#endif  // DEBUG
689

690
  CodeTracer::Scope* trace_scope_;
691

692
  static const int table_entry_size_;
693 694

  friend class FrameDescription;
695
  friend class DeoptimizedFrameInfo;
696 697 698
};


699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
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];
  }

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

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

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

  intptr_t registers_[Register::kNumRegisters];
  double double_registers_[DoubleRegister::kMaxNumRegisters];
};


734 735 736 737 738 739
class FrameDescription {
 public:
  FrameDescription(uint32_t frame_size,
                   JSFunction* function);

  void* operator new(size_t size, uint32_t frame_size) {
740 741 742
    // 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);
743 744
  }

745
// Bug in VS2015 RC, reported fixed in RTM. Microsoft bug: 1153909.
746
#if !defined(_MSC_FULL_VER) || _MSC_FULL_VER != 190022816
747 748 749
  void operator delete(void* pointer, uint32_t frame_size) {
    free(pointer);
  }
750
#endif  // _MSC_FULL_VER
751

752 753 754 755
  void operator delete(void* description) {
    free(description);
  }

756
  uint32_t GetFrameSize() const {
757
    DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
758 759
    return static_cast<uint32_t>(frame_size_);
  }
760 761 762

  JSFunction* GetFunction() const { return function_; }

763
  unsigned GetOffsetFromSlotIndex(int slot_index);
764

765
  intptr_t GetFrameSlot(unsigned offset) {
766 767 768
    return *GetFrameSlotPointer(offset);
  }

769 770 771 772 773
  Address GetFramePointerAddress() {
    int fp_offset = GetFrameSize() -
                    (ComputeParametersCount() + 1) * kPointerSize -
                    StandardFrameConstants::kCallerSPOffset;
    return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset));
774 775
  }

776 777
  RegisterValues* GetRegisterValues() { return &register_values_; }

778
  void SetFrameSlot(unsigned offset, intptr_t value) {
779 780 781
    *GetFrameSlotPointer(offset) = value;
  }

782 783 784 785
  void SetCallerPc(unsigned offset, intptr_t value);

  void SetCallerFp(unsigned offset, intptr_t value);

786 787
  void SetCallerConstantPool(unsigned offset, intptr_t value);

788
  intptr_t GetRegister(unsigned n) const {
789
    return register_values_.GetRegister(n);
790 791 792
  }

  double GetDoubleRegister(unsigned n) const {
793
    return register_values_.GetDoubleRegister(n);
794 795
  }

796
  void SetRegister(unsigned n, intptr_t value) {
797
    register_values_.SetRegister(n, value);
798 799 800
  }

  void SetDoubleRegister(unsigned n, double value) {
801
    register_values_.SetDoubleRegister(n, value);
802 803
  }

804 805
  intptr_t GetTop() const { return top_; }
  void SetTop(intptr_t top) { top_ = top; }
806

807 808
  intptr_t GetPc() const { return pc_; }
  void SetPc(intptr_t pc) { pc_ = pc; }
809

810 811
  intptr_t GetFp() const { return fp_; }
  void SetFp(intptr_t fp) { fp_ = fp; }
812

813 814 815
  intptr_t GetContext() const { return context_; }
  void SetContext(intptr_t context) { context_ = context; }

816 817 818 819 820
  intptr_t GetConstantPool() const { return constant_pool_; }
  void SetConstantPool(intptr_t constant_pool) {
    constant_pool_ = constant_pool;
  }

821 822 823
  Smi* GetState() const { return state_; }
  void SetState(Smi* state) { state_ = state; }

824
  void SetContinuation(intptr_t pc) { continuation_ = pc; }
825

826 827
  StackFrame::Type GetFrameType() const { return type_; }
  void SetFrameType(StackFrame::Type type) { type_ = type; }
828

829 830 831 832
  // Get the incoming arguments count.
  int ComputeParametersCount();

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

835
  // Get the expression stack height for a unoptimized frame.
836
  unsigned GetExpressionCount();
837 838

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

841
  static int registers_offset() {
842
    return OFFSET_OF(FrameDescription, register_values_.registers_);
843 844 845
  }

  static int double_registers_offset() {
846
    return OFFSET_OF(FrameDescription, register_values_.double_registers_);
847 848 849
  }

  static int frame_size_offset() {
850
    return offsetof(FrameDescription, frame_size_);
851 852
  }

853
  static int pc_offset() { return offsetof(FrameDescription, pc_); }
854

855
  static int state_offset() { return offsetof(FrameDescription, state_); }
856 857

  static int continuation_offset() {
858
    return offsetof(FrameDescription, continuation_);
859 860 861
  }

  static int frame_content_offset() {
862
    return offsetof(FrameDescription, frame_content_);
863 864 865 866 867
  }

 private:
  static const uint32_t kZapUint32 = 0xbeeddead;

868 869 870
  // 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.
871
  uintptr_t frame_size_;  // Number of bytes.
872
  JSFunction* function_;
873
  RegisterValues register_values_;
874 875 876
  intptr_t top_;
  intptr_t pc_;
  intptr_t fp_;
877
  intptr_t context_;
878
  intptr_t constant_pool_;
879
  StackFrame::Type type_;
880 881 882 883
  Smi* state_;

  // Continuation is the PC where the execution continues after
  // deoptimizing.
884
  intptr_t continuation_;
885

886 887 888 889
  // 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];

890
  intptr_t* GetFrameSlotPointer(unsigned offset) {
891
    DCHECK(offset < frame_size_);
892
    return reinterpret_cast<intptr_t*>(
893 894
        reinterpret_cast<Address>(this) + frame_content_offset() + offset);
  }
895 896

  int ComputeFixedSize();
897 898 899
};


900 901 902 903 904 905 906 907 908 909 910 911 912 913
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_;

914
  Deoptimizer* current_;
915 916 917 918 919 920 921

  friend class Deoptimizer;

  DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
};


922 923
class TranslationBuffer BASE_EMBEDDED {
 public:
924
  explicit TranslationBuffer(Zone* zone) : contents_(256, zone) { }
925 926

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

929
  Handle<ByteArray> CreateByteArray(Factory* factory);
930 931 932 933 934 935 936 937 938 939

 private:
  ZoneList<uint8_t> contents_;
};


class TranslationIterator BASE_EMBEDDED {
 public:
  TranslationIterator(ByteArray* buffer, int index)
      : buffer_(buffer), index_(index) {
940
    DCHECK(index >= 0 && index < buffer->length());
941 942 943 944
  }

  int32_t Next();

945
  bool HasNext() const { return index_ < buffer_->length(); }
946 947 948 949 950 951 952 953 954 955 956

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

 private:
  ByteArray* buffer_;
  int index_;
};


957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
#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(BOOL_REGISTER)                 \
  V(DOUBLE_REGISTER)               \
  V(STACK_SLOT)                    \
  V(INT32_STACK_SLOT)              \
  V(UINT32_STACK_SLOT)             \
  V(BOOL_STACK_SLOT)               \
  V(DOUBLE_STACK_SLOT)             \
978 979
  V(LITERAL)                       \
  V(JS_FRAME_FUNCTION)
980 981


982 983
class Translation BASE_EMBEDDED {
 public:
984
#define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
985
  enum Opcode {
986 987
    TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
    LAST = LITERAL
988
  };
989
#undef DECLARE_TRANSLATION_OPCODE_ENUM
990

991 992
  Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
              Zone* zone)
993
      : buffer_(buffer),
994 995 996 997 998
        index_(buffer->CurrentIndex()),
        zone_(zone) {
    buffer_->Add(BEGIN, zone);
    buffer_->Add(frame_count, zone);
    buffer_->Add(jsframe_count, zone);
999 1000 1001 1002 1003
  }

  int index() const { return index_; }

  // Commands.
1004
  void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height);
1005
  void BeginCompiledStubFrame(int height);
1006
  void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
1007
  void BeginConstructStubFrame(int literal_id, unsigned height);
1008
  void BeginGetterStubFrame(int literal_id);
1009
  void BeginSetterStubFrame(int literal_id);
1010
  void BeginArgumentsObject(int args_length);
1011 1012
  void BeginCapturedObject(int length);
  void DuplicateObject(int object_index);
1013 1014
  void StoreRegister(Register reg);
  void StoreInt32Register(Register reg);
1015
  void StoreUint32Register(Register reg);
1016
  void StoreBoolRegister(Register reg);
1017 1018 1019
  void StoreDoubleRegister(DoubleRegister reg);
  void StoreStackSlot(int index);
  void StoreInt32StackSlot(int index);
1020
  void StoreUint32StackSlot(int index);
1021
  void StoreBoolStackSlot(int index);
1022 1023
  void StoreDoubleStackSlot(int index);
  void StoreLiteral(int literal_id);
1024
  void StoreArgumentsObject(bool args_known, int args_index, int args_length);
1025
  void StoreJSFrameFunction();
1026

1027
  Zone* zone() const { return zone_; }
1028

1029 1030
  static int NumberOfOperandsFor(Opcode opcode);

1031
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
1032 1033 1034 1035 1036 1037
  static const char* StringFor(Opcode opcode);
#endif

 private:
  TranslationBuffer* buffer_;
  int index_;
1038
  Zone* zone_;
1039 1040 1041
};


jarin@chromium.org's avatar
jarin@chromium.org committed
1042 1043 1044 1045 1046 1047 1048
class MaterializedObjectStore {
 public:
  explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
  }

  Handle<FixedArray> Get(Address fp);
  void Set(Address fp, Handle<FixedArray> materialized_objects);
1049
  bool Remove(Address fp);
jarin@chromium.org's avatar
jarin@chromium.org committed
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059

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

  int StackIdToIndex(Address fp);

  Isolate* isolate_;
  List<Address> frame_fps_;
1060 1061 1062
};


1063 1064 1065 1066
// 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.
1067 1068
// Represents parameters in unadapted form so their number might mismatch
// formal parameter count.
1069 1070
class DeoptimizedFrameInfo : public Malloced {
 public:
1071 1072
  DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
                       int frame_index,
1073 1074
                       bool has_arguments_adaptor,
                       bool has_construct_stub);
1075 1076 1077 1078 1079
  virtual ~DeoptimizedFrameInfo();

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

1080 1081 1082
  // Return the number of incoming arguments.
  int parameters_count() { return parameters_count_; }

1083 1084 1085
  // Return the height of the expression stack.
  int expression_count() { return expression_count_; }

1086 1087 1088 1089 1090
  // Get the frame function.
  JSFunction* GetFunction() {
    return function_;
  }

1091 1092 1093
  // Get the frame context.
  Object* GetContext() { return context_; }

1094 1095 1096 1097 1098 1099
  // 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_;
  }

1100 1101
  // Get an incoming argument.
  Object* GetParameter(int index) {
1102
    DCHECK(0 <= index && index < parameters_count());
1103 1104 1105
    return parameters_[index];
  }

1106 1107
  // Get an expression from the expression stack.
  Object* GetExpression(int index) {
1108
    DCHECK(0 <= index && index < expression_count());
1109 1110 1111
    return expression_stack_[index];
  }

1112 1113
  int GetSourcePosition() {
    return source_position_;
1114 1115
  }

1116
 private:
1117 1118
  // Set an incoming argument.
  void SetParameter(int index, Object* obj) {
1119
    DCHECK(0 <= index && index < parameters_count());
1120 1121 1122
    parameters_[index] = obj;
  }

1123 1124
  // Set an expression on the expression stack.
  void SetExpression(int index, Object* obj) {
1125
    DCHECK(0 <= index && index < expression_count());
1126 1127 1128
    expression_stack_[index] = obj;
  }

1129
  JSFunction* function_;
1130
  Object* context_;
1131
  bool has_construct_stub_;
1132
  int parameters_count_;
1133
  int expression_count_;
1134
  Object** parameters_;
1135
  Object** expression_stack_;
1136
  int source_position_;
1137 1138 1139 1140

  friend class Deoptimizer;
};

1141 1142
}  // namespace internal
}  // namespace v8
1143 1144

#endif  // V8_DEOPTIMIZER_H_