lithium.h 24.9 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
#ifndef V8_CRANKSHAFT_LITHIUM_H_
#define V8_CRANKSHAFT_LITHIUM_H_
7

8 9
#include <set>

10
#include "src/allocation.h"
11
#include "src/bailout-reason.h"
12
#include "src/crankshaft/hydrogen.h"
13 14
#include "src/safepoint-table.h"
#include "src/zone-allocator.h"
15 16 17 18

namespace v8 {
namespace internal {

19 20 21 22 23 24
#define LITHIUM_OPERAND_LIST(V)               \
  V(ConstantOperand, CONSTANT_OPERAND,  128)  \
  V(StackSlot,       STACK_SLOT,        128)  \
  V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128)  \
  V(Register,        REGISTER,          16)   \
  V(DoubleRegister,  DOUBLE_REGISTER,   16)
25

26
class LOperand : public ZoneObject {
27 28 29 30 31 32 33 34
 public:
  enum Kind {
    INVALID,
    UNALLOCATED,
    CONSTANT_OPERAND,
    STACK_SLOT,
    DOUBLE_STACK_SLOT,
    REGISTER,
35
    DOUBLE_REGISTER
36 37 38 39 40 41
  };

  LOperand() : value_(KindField::encode(INVALID)) { }

  Kind kind() const { return KindField::decode(value_); }
  int index() const { return static_cast<int>(value_) >> kKindFieldWidth; }
42
#define LITHIUM_OPERAND_PREDICATE(name, type, number) \
43 44
  bool Is##name() const { return kind() == type; }
  LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_PREDICATE)
45 46
  LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0)
  LITHIUM_OPERAND_PREDICATE(Ignored, INVALID, 0)
47
#undef LITHIUM_OPERAND_PREDICATE
48 49 50 51
  bool Equals(LOperand* other) const { return value_ == other->value_; }

  void PrintTo(StringStream* stream);
  void ConvertTo(Kind kind, int index) {
52
    if (kind == REGISTER) DCHECK(index >= 0);
53 54
    value_ = KindField::encode(kind);
    value_ |= index << kKindFieldWidth;
55
    DCHECK(this->index() == index);
56 57
  }

58
  // Calls SetUpCache()/TearDownCache() for each subclass.
59
  static void SetUpCaches();
60
  static void TearDownCaches();
61

62 63 64 65 66 67 68 69 70 71
 protected:
  static const int kKindFieldWidth = 3;
  class KindField : public BitField<Kind, 0, kKindFieldWidth> { };

  LOperand(Kind kind, int index) { ConvertTo(kind, index); }

  unsigned value_;
};


72
class LUnallocated : public LOperand {
73
 public:
74 75 76 77 78 79
  enum BasicPolicy {
    FIXED_SLOT,
    EXTENDED_POLICY
  };

  enum ExtendedPolicy {
80 81 82 83 84
    NONE,
    ANY,
    FIXED_REGISTER,
    FIXED_DOUBLE_REGISTER,
    MUST_HAVE_REGISTER,
85
    MUST_HAVE_DOUBLE_REGISTER,
86
    WRITABLE_REGISTER,
87
    SAME_AS_FIRST_INPUT
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
  };

  // Lifetime of operand inside the instruction.
  enum Lifetime {
    // USED_AT_START operand is guaranteed to be live only at
    // instruction start. Register allocator is free to assign the same register
    // to some other operand used inside instruction (i.e. temporary or
    // output).
    USED_AT_START,

    // USED_AT_END operand is treated as live until the end of
    // instruction. This means that register allocator will not reuse it's
    // register for any other operand inside instruction.
    USED_AT_END
  };

104 105 106 107
  explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) {
    value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    value_ |= ExtendedPolicyField::encode(policy);
    value_ |= LifetimeField::encode(USED_AT_END);
108 109
  }

110
  LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
111
    DCHECK(policy == FIXED_SLOT);
112 113
    value_ |= BasicPolicyField::encode(policy);
    value_ |= index << FixedSlotIndexField::kShift;
114
    DCHECK(this->fixed_slot_index() == index);
115 116
  }

117
  LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
118
    DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
119 120 121 122
    value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    value_ |= ExtendedPolicyField::encode(policy);
    value_ |= LifetimeField::encode(USED_AT_END);
    value_ |= FixedRegisterField::encode(index);
123 124
  }

125 126 127 128 129 130
  LUnallocated(ExtendedPolicy policy, Lifetime lifetime)
      : LOperand(UNALLOCATED, 0) {
    value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    value_ |= ExtendedPolicyField::encode(policy);
    value_ |= LifetimeField::encode(lifetime);
  }
131

132 133 134 135 136
  LUnallocated* CopyUnconstrained(Zone* zone) {
    LUnallocated* result = new(zone) LUnallocated(ANY);
    result->set_virtual_register(virtual_register());
    return result;
  }
137

138
  static LUnallocated* cast(LOperand* op) {
139
    DCHECK(op->IsUnallocated());
140 141
    return reinterpret_cast<LUnallocated*>(op);
  }
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
  // The encoding used for LUnallocated operands depends on the policy that is
  // stored within the operand. The FIXED_SLOT policy uses a compact encoding
  // because it accommodates a larger pay-load.
  //
  // For FIXED_SLOT policy:
  //     +------------------------------------------+
  //     |       slot_index      |  vreg  | 0 | 001 |
  //     +------------------------------------------+
  //
  // For all other (extended) policies:
  //     +------------------------------------------+
  //     |  reg_index  | L | PPP |  vreg  | 1 | 001 |    L ... Lifetime
  //     +------------------------------------------+    P ... Policy
  //
  // The slot index is a signed value which requires us to decode it manually
  // instead of using the BitField utility class.

  // The superclass has a KindField.
  STATIC_ASSERT(kKindFieldWidth == 3);

  // BitFields for all unallocated operands.
  class BasicPolicyField     : public BitField<BasicPolicy,     3,  1> {};
165
  class VirtualRegisterField : public BitField<unsigned,        4, 18> {};
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

  // BitFields specific to BasicPolicy::FIXED_SLOT.
  class FixedSlotIndexField  : public BitField<int,            22, 10> {};

  // BitFields specific to BasicPolicy::EXTENDED_POLICY.
  class ExtendedPolicyField  : public BitField<ExtendedPolicy, 22,  3> {};
  class LifetimeField        : public BitField<Lifetime,       25,  1> {};
  class FixedRegisterField   : public BitField<int,            26,  6> {};

  static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1;
  static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
  static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
  static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));

  // Predicates for the operand policy.
181
  bool HasAnyPolicy() const {
182 183
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == ANY;
184 185
  }
  bool HasFixedPolicy() const {
186 187 188
    return basic_policy() == FIXED_SLOT ||
        extended_policy() == FIXED_REGISTER ||
        extended_policy() == FIXED_DOUBLE_REGISTER;
189 190
  }
  bool HasRegisterPolicy() const {
191 192 193
    return basic_policy() == EXTENDED_POLICY && (
        extended_policy() == WRITABLE_REGISTER ||
        extended_policy() == MUST_HAVE_REGISTER);
194
  }
195 196 197 198
  bool HasDoubleRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == MUST_HAVE_DOUBLE_REGISTER;
  }
199
  bool HasSameAsInputPolicy() const {
200 201 202 203 204 205 206 207 208
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == SAME_AS_FIRST_INPUT;
  }
  bool HasFixedSlotPolicy() const {
    return basic_policy() == FIXED_SLOT;
  }
  bool HasFixedRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == FIXED_REGISTER;
209
  }
210 211 212
  bool HasFixedDoubleRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == FIXED_DOUBLE_REGISTER;
213
  }
214 215 216
  bool HasWritableRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == WRITABLE_REGISTER;
217 218
  }

219 220 221
  // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
  BasicPolicy basic_policy() const {
    return BasicPolicyField::decode(value_);
222 223
  }

224 225
  // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
  ExtendedPolicy extended_policy() const {
226
    DCHECK(basic_policy() == EXTENDED_POLICY);
227
    return ExtendedPolicyField::decode(value_);
228 229
  }

230 231
  // [fixed_slot_index]: Only for FIXED_SLOT.
  int fixed_slot_index() const {
232
    DCHECK(HasFixedSlotPolicy());
233
    return static_cast<int>(value_) >> FixedSlotIndexField::kShift;
234 235
  }

236 237
  // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
  int fixed_register_index() const {
238
    DCHECK(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
239
    return FixedRegisterField::decode(value_);
240 241
  }

242 243 244 245 246 247
  // [virtual_register]: The virtual register ID for this operand.
  int virtual_register() const {
    return VirtualRegisterField::decode(value_);
  }
  void set_virtual_register(unsigned id) {
    value_ = VirtualRegisterField::update(value_, id);
248 249
  }

250 251
  // [lifetime]: Only for non-FIXED_SLOT.
  bool IsUsedAtStart() {
252
    DCHECK(basic_policy() == EXTENDED_POLICY);
253
    return LifetimeField::decode(value_) == USED_AT_START;
254
  }
255 256 257 258 259 260 261 262 263 264 265

  static bool TooManyParameters(int num_parameters) {
    const int parameter_limit = -LUnallocated::kMinFixedSlotIndex;
    return num_parameters + 1 > parameter_limit;
  }

  static bool TooManyParametersOrStackSlots(int num_parameters,
                                            int num_stack_slots) {
    const int locals_limit = LUnallocated::kMaxFixedSlotIndex;
    return num_parameters + 1 + num_stack_slots > locals_limit;
  }
266 267 268
};


269
class LMoveOperands final BASE_EMBEDDED {
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
 public:
  LMoveOperands(LOperand* source, LOperand* destination)
      : source_(source), destination_(destination) {
  }

  LOperand* source() const { return source_; }
  void set_source(LOperand* operand) { source_ = operand; }

  LOperand* destination() const { return destination_; }
  void set_destination(LOperand* operand) { destination_ = operand; }

  // The gap resolver marks moves as "in-progress" by clearing the
  // destination (but not the source).
  bool IsPending() const {
    return destination_ == NULL && source_ != NULL;
  }

  // True if this move a move into the given destination operand.
  bool Blocks(LOperand* operand) const {
    return !IsEliminated() && source()->Equals(operand);
  }

  // A move is redundant if it's been eliminated, if its source and
293
  // destination are the same, or if its destination is unneeded or constant.
294
  bool IsRedundant() const {
295 296
    return IsEliminated() || source_->Equals(destination_) || IsIgnored() ||
           (destination_ != NULL && destination_->IsConstantOperand());
297 298 299
  }

  bool IsIgnored() const {
300
    return destination_ != NULL && destination_->IsIgnored();
301 302 303 304 305
  }

  // We clear both operands to indicate move that's been eliminated.
  void Eliminate() { source_ = destination_ = NULL; }
  bool IsEliminated() const {
306
    DCHECK(source_ != NULL || destination_ == NULL);
307 308 309 310 311 312 313 314 315
    return source_ == NULL;
  }

 private:
  LOperand* source_;
  LOperand* destination_;
};


316 317
template <LOperand::Kind kOperandKind, int kNumCachedOperands>
class LSubKindOperand final : public LOperand {
318
 public:
319
  static LSubKindOperand* Create(int index, Zone* zone) {
320
    DCHECK(index >= 0);
321
    if (index < kNumCachedOperands) return &cache[index];
322
    return new(zone) LSubKindOperand(index);
323 324
  }

325
  static LSubKindOperand* cast(LOperand* op) {
326
    DCHECK(op->kind() == kOperandKind);
327
    return reinterpret_cast<LSubKindOperand*>(op);
328 329
  }

330
  static void SetUpCache();
331
  static void TearDownCache();
332 333

 private:
334
  static LSubKindOperand* cache;
335

336 337
  LSubKindOperand() : LOperand() { }
  explicit LSubKindOperand(int index) : LOperand(kOperandKind, index) { }
338 339 340
};


341 342 343 344
#define LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number)   \
typedef LSubKindOperand<LOperand::type, number> L##name;
LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS)
#undef LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS
345 346


347
class LParallelMove final : public ZoneObject {
348
 public:
349
  explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { }
350

351 352
  void AddMove(LOperand* from, LOperand* to, Zone* zone) {
    move_operands_.Add(LMoveOperands(from, to), zone);
353 354 355 356
  }

  bool IsRedundant() const;

357
  ZoneList<LMoveOperands>* move_operands() { return &move_operands_; }
358 359 360 361 362 363 364 365

  void PrintDataTo(StringStream* stream) const;

 private:
  ZoneList<LMoveOperands> move_operands_;
};


366
class LPointerMap final : public ZoneObject {
367
 public:
368
  explicit LPointerMap(Zone* zone)
369 370
      : pointer_operands_(8, zone),
        untagged_operands_(0, zone),
371 372 373 374 375 376 377 378 379
        lithium_position_(-1) { }

  const ZoneList<LOperand*>* GetNormalizedOperands() {
    for (int i = 0; i < untagged_operands_.length(); ++i) {
      RemovePointer(untagged_operands_[i]);
    }
    untagged_operands_.Clear();
    return &pointer_operands_;
  }
380 381 382
  int lithium_position() const { return lithium_position_; }

  void set_lithium_position(int pos) {
383
    DCHECK(lithium_position_ == -1);
384 385 386
    lithium_position_ = pos;
  }

387
  void RecordPointer(LOperand* op, Zone* zone);
388
  void RemovePointer(LOperand* op);
389
  void RecordUntagged(LOperand* op, Zone* zone);
390 391 392 393
  void PrintTo(StringStream* stream);

 private:
  ZoneList<LOperand*> pointer_operands_;
394
  ZoneList<LOperand*> untagged_operands_;
395 396 397 398
  int lithium_position_;
};


399
class LEnvironment final : public ZoneObject {
400 401
 public:
  LEnvironment(Handle<JSFunction> closure,
402
               FrameType frame_type,
403
               BailoutId ast_id,
404 405 406
               int parameter_count,
               int argument_count,
               int value_count,
407
               LEnvironment* outer,
408
               HEnterInlined* entry,
409
               Zone* zone)
410
      : closure_(closure),
411
        frame_type_(frame_type),
412 413 414 415
        arguments_stack_height_(argument_count),
        deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
        translation_index_(-1),
        ast_id_(ast_id),
416
        translation_size_(value_count),
417
        parameter_count_(parameter_count),
418
        pc_offset_(-1),
419
        values_(value_count, zone),
420
        is_tagged_(value_count, zone),
421
        is_uint32_(value_count, zone),
422
        object_mapping_(0, zone),
423
        outer_(outer),
424
        entry_(entry),
425 426
        zone_(zone),
        has_been_used_(false) { }
427 428

  Handle<JSFunction> closure() const { return closure_; }
429
  FrameType frame_type() const { return frame_type_; }
430 431 432
  int arguments_stack_height() const { return arguments_stack_height_; }
  int deoptimization_index() const { return deoptimization_index_; }
  int translation_index() const { return translation_index_; }
433
  BailoutId ast_id() const { return ast_id_; }
434
  int translation_size() const { return translation_size_; }
435
  int parameter_count() const { return parameter_count_; }
436
  int pc_offset() const { return pc_offset_; }
437 438
  const ZoneList<LOperand*>* values() const { return &values_; }
  LEnvironment* outer() const { return outer_; }
439
  HEnterInlined* entry() { return entry_; }
440
  Zone* zone() const { return zone_; }
441

442 443 444
  bool has_been_used() const { return has_been_used_; }
  void set_has_been_used() { has_been_used_ = true; }

445 446 447
  void AddValue(LOperand* operand,
                Representation representation,
                bool is_uint32) {
448
    values_.Add(operand, zone());
449
    if (representation.IsSmiOrTagged()) {
450
      DCHECK(!is_uint32);
451
      is_tagged_.Add(values_.length() - 1, zone());
452
    }
453 454

    if (is_uint32) {
455
      is_uint32_.Add(values_.length() - 1, zone());
456
    }
457 458 459
  }

  bool HasTaggedValueAt(int index) const {
460
    return is_tagged_.Contains(index);
461 462
  }

463 464 465 466
  bool HasUint32ValueAt(int index) const {
    return is_uint32_.Contains(index);
  }

467 468 469 470 471 472 473 474 475 476 477 478 479 480
  void AddNewObject(int length, bool is_arguments) {
    uint32_t encoded = LengthOrDupeField::encode(length) |
                       IsArgumentsField::encode(is_arguments) |
                       IsDuplicateField::encode(false);
    object_mapping_.Add(encoded, zone());
  }

  void AddDuplicateObject(int dupe_of) {
    uint32_t encoded = LengthOrDupeField::encode(dupe_of) |
                       IsDuplicateField::encode(true);
    object_mapping_.Add(encoded, zone());
  }

  int ObjectDuplicateOfAt(int index) {
481
    DCHECK(ObjectIsDuplicateAt(index));
482 483 484 485
    return LengthOrDupeField::decode(object_mapping_[index]);
  }

  int ObjectLengthAt(int index) {
486
    DCHECK(!ObjectIsDuplicateAt(index));
487 488 489 490
    return LengthOrDupeField::decode(object_mapping_[index]);
  }

  bool ObjectIsArgumentsAt(int index) {
491
    DCHECK(!ObjectIsDuplicateAt(index));
492 493 494 495 496 497 498
    return IsArgumentsField::decode(object_mapping_[index]);
  }

  bool ObjectIsDuplicateAt(int index) {
    return IsDuplicateField::decode(object_mapping_[index]);
  }

499 500 501
  void Register(int deoptimization_index,
                int translation_index,
                int pc_offset) {
502
    DCHECK(!HasBeenRegistered());
503 504
    deoptimization_index_ = deoptimization_index;
    translation_index_ = translation_index;
505
    pc_offset_ = pc_offset;
506 507 508 509 510 511 512
  }
  bool HasBeenRegistered() const {
    return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
  }

  void PrintTo(StringStream* stream);

513 514 515 516 517 518 519 520
  // Marker value indicating a de-materialized object.
  static LOperand* materialization_marker() { return NULL; }

  // Encoding used for the object_mapping map below.
  class LengthOrDupeField : public BitField<int,   0, 30> { };
  class IsArgumentsField  : public BitField<bool, 30,  1> { };
  class IsDuplicateField  : public BitField<bool, 31,  1> { };

521 522
 private:
  Handle<JSFunction> closure_;
523
  FrameType frame_type_;
524 525 526
  int arguments_stack_height_;
  int deoptimization_index_;
  int translation_index_;
527
  BailoutId ast_id_;
528
  int translation_size_;
529
  int parameter_count_;
530
  int pc_offset_;
531 532 533

  // Value array: [parameters] [locals] [expression stack] [de-materialized].
  //              |>--------- translation_size ---------<|
534
  ZoneList<LOperand*> values_;
535 536
  GrowableBitVector is_tagged_;
  GrowableBitVector is_uint32_;
537 538 539 540

  // Map with encoded information about materialization_marker operands.
  ZoneList<uint32_t> object_mapping_;

541
  LEnvironment* outer_;
542
  HEnterInlined* entry_;
543
  Zone* zone_;
544
  bool has_been_used_;
545 546
};

547 548

// Iterates over the non-null, non-constant operands in an environment.
549
class ShallowIterator final BASE_EMBEDDED {
550 551 552 553 554
 public:
  explicit ShallowIterator(LEnvironment* env)
      : env_(env),
        limit_(env != NULL ? env->values()->length() : 0),
        current_(0) {
555
    SkipUninteresting();
556 557
  }

558
  bool Done() { return current_ >= limit_; }
559

560
  LOperand* Current() {
561 562
    DCHECK(!Done());
    DCHECK(env_->values()->at(current_) != NULL);
563 564 565
    return env_->values()->at(current_);
  }

566
  void Advance() {
567
    DCHECK(!Done());
568 569
    ++current_;
    SkipUninteresting();
570 571
  }

572
  LEnvironment* env() { return env_; }
573 574

 private:
575
  bool ShouldSkip(LOperand* op) {
576
    return op == NULL || op->IsConstantOperand();
577 578
  }

579 580 581 582
  // Skip until something interesting, beginning with and including current_.
  void SkipUninteresting() {
    while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) {
      ++current_;
583 584 585 586 587 588 589 590 591 592
    }
  }

  LEnvironment* env_;
  int limit_;
  int current_;
};


// Iterator for non-null, non-constant operands incl. outer environments.
593
class DeepIterator final BASE_EMBEDDED {
594 595
 public:
  explicit DeepIterator(LEnvironment* env)
596 597
      : current_iterator_(env) {
    SkipUninteresting();
598 599
  }

600 601 602
  bool Done() { return current_iterator_.Done(); }

  LOperand* Current() {
603 604
    DCHECK(!current_iterator_.Done());
    DCHECK(current_iterator_.Current() != NULL);
605
    return current_iterator_.Current();
606 607
  }

608 609 610
  void Advance() {
    current_iterator_.Advance();
    SkipUninteresting();
611 612 613
  }

 private:
614 615 616 617
  void SkipUninteresting() {
    while (current_iterator_.env() != NULL && current_iterator_.Done()) {
      current_iterator_ = ShallowIterator(current_iterator_.env()->outer());
    }
618 619 620 621 622
  }

  ShallowIterator current_iterator_;
};

623

624
class LPlatformChunk;
625 626 627 628
class LGap;
class LLabel;

// Superclass providing data and behavior common to all the
629
// arch-specific LPlatformChunk classes.
630
class LChunk : public ZoneObject {
631
 public:
632
  static LChunk* NewChunk(HGraph* graph);
633 634 635

  void AddInstruction(LInstruction* instruction, HBasicBlock* block);
  LConstantOperand* DefineConstantOperand(HConstant* constant);
636
  HConstant* LookupConstant(LConstantOperand* operand) const;
637 638 639 640 641 642 643
  Representation LookupLiteralRepresentation(LConstantOperand* operand) const;

  int ParameterAt(int index);
  int GetParameterStackSlot(int index) const;
  int spill_slot_count() const { return spill_slot_count_; }
  CompilationInfo* info() const { return info_; }
  HGraph* graph() const { return graph_; }
644
  Isolate* isolate() const { return graph_->isolate(); }
645 646 647 648 649 650 651 652 653 654 655
  const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
  void AddGapMove(int index, LOperand* from, LOperand* to);
  LGap* GetGapAt(int index) const;
  bool IsGapAt(int index) const;
  int NearestGapPos(int index) const;
  void MarkEmptyBlocks();
  const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
  LLabel* GetLabel(int block_id) const;
  int LookupDestination(int block_id) const;
  Label* GetAssemblyLabel(int block_id) const;

656 657
  const ZoneList<Handle<SharedFunctionInfo>>& inlined_functions() const {
    return inlined_functions_;
658 659
  }

660 661
  void AddInlinedFunction(Handle<SharedFunctionInfo> closure) {
    inlined_functions_.Add(closure, zone());
662 663
  }

664
  void AddDeprecationDependency(Handle<Map> map) {
665
    DCHECK(!map->is_deprecated());
666
    if (!map->CanBeDeprecated()) return;
667
    DCHECK(!info_->IsStub());
668
    deprecation_dependencies_.Add(map, zone());
669 670
  }

671
  void AddStabilityDependency(Handle<Map> map) {
672
    DCHECK(map->is_stable());
673
    if (!map->CanTransition()) return;
674
    DCHECK(!info_->IsStub());
675
    stability_dependencies_.Add(map, zone());
676 677
  }

678 679
  Zone* zone() const { return info_->zone(); }

680
  Handle<Code> Codegen();
681

682 683 684 685 686
  void set_allocated_double_registers(BitVector* allocated_registers);
  BitVector* allocated_double_registers() {
    return allocated_double_registers_;
  }

687
 protected:
688
  LChunk(CompilationInfo* info, HGraph* graph);
689

690 691 692
  int spill_slot_count_;

 private:
693
  void RegisterWeakObjectsInOptimizedCode(Handle<Code> code) const;
694 695
  void CommitDependencies(Handle<Code> code) const;

696 697
  CompilationInfo* info_;
  HGraph* const graph_;
698
  BitVector* allocated_double_registers_;
699 700
  ZoneList<LInstruction*> instructions_;
  ZoneList<LPointerMap*> pointer_maps_;
701
  ZoneList<Handle<SharedFunctionInfo>> inlined_functions_;
702 703
  ZoneList<Handle<Map>> deprecation_dependencies_;
  ZoneList<Handle<Map>> stability_dependencies_;
704 705 706
};


707 708
class LChunkBuilderBase BASE_EMBEDDED {
 public:
709
  explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph)
710
      : argument_count_(0),
711 712 713 714 715
        chunk_(NULL),
        info_(info),
        graph_(graph),
        status_(UNUSED),
        zone_(graph->zone()) {}
716 717 718

  virtual ~LChunkBuilderBase() { }

719 720 721
  void Abort(BailoutReason reason);
  void Retry(BailoutReason reason);

722
 protected:
723 724 725 726 727 728 729 730 731 732 733 734 735 736
  enum Status { UNUSED, BUILDING, DONE, ABORTED };

  LPlatformChunk* chunk() const { return chunk_; }
  CompilationInfo* info() const { return info_; }
  HGraph* graph() const { return graph_; }
  int argument_count() const { return argument_count_; }
  Isolate* isolate() const { return graph_->isolate(); }
  Heap* heap() const { return isolate()->heap(); }

  bool is_unused() const { return status_ == UNUSED; }
  bool is_building() const { return status_ == BUILDING; }
  bool is_done() const { return status_ == DONE; }
  bool is_aborted() const { return status_ == ABORTED; }

737 738 739 740 741 742 743 744 745 746 747 748 749 750
  // An input operand in register, stack slot or a constant operand.
  // Will not be moved to a register even if one is freely available.
  virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0;

  LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
                                  int* argument_index_accumulator,
                                  ZoneList<HValue*>* objects_to_materialize);
  void AddObjectToMaterialize(HValue* value,
                              ZoneList<HValue*>* objects_to_materialize,
                              LEnvironment* result);

  Zone* zone() const { return zone_; }

  int argument_count_;
751 752 753 754
  LPlatformChunk* chunk_;
  CompilationInfo* info_;
  HGraph* const graph_;
  Status status_;
755 756 757 758 759 760

 private:
  Zone* zone_;
};


761
int StackSlotOffset(int index);
762

763 764
enum NumberUntagDMode {
  NUMBER_CANDIDATE_IS_SMI,
765
  NUMBER_CANDIDATE_IS_ANY_TAGGED
766 767
};

768

769 770 771
class LPhase : public CompilationPhase {
 public:
  LPhase(const char* name, LChunk* chunk)
772
      : CompilationPhase(name, chunk->info()),
773 774 775 776 777 778 779 780 781 782
        chunk_(chunk) { }
  ~LPhase();

 private:
  LChunk* chunk_;

  DISALLOW_COPY_AND_ASSIGN(LPhase);
};


783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
// A register-allocator view of a Lithium instruction. It contains the id of
// the output operand and a list of input operand uses.

enum RegisterKind {
  UNALLOCATED_REGISTERS,
  GENERAL_REGISTERS,
  DOUBLE_REGISTERS
};

// Iterator for non-null temp operands.
class TempIterator BASE_EMBEDDED {
 public:
  inline explicit TempIterator(LInstruction* instr);
  inline bool Done();
  inline LOperand* Current();
  inline void Advance();

 private:
  inline void SkipUninteresting();
  LInstruction* instr_;
  int limit_;
  int current_;
};


// Iterator for non-constant input operands.
class InputIterator BASE_EMBEDDED {
 public:
  inline explicit InputIterator(LInstruction* instr);
  inline bool Done();
  inline LOperand* Current();
  inline void Advance();

 private:
  inline void SkipUninteresting();
  LInstruction* instr_;
  int limit_;
  int current_;
};


class UseIterator BASE_EMBEDDED {
 public:
  inline explicit UseIterator(LInstruction* instr);
  inline bool Done();
  inline LOperand* Current();
  inline void Advance();

 private:
  InputIterator input_iterator_;
  DeepIterator env_iterator_;
};

class LInstruction;
class LCodeGen;
838 839
}  // namespace internal
}  // namespace v8
840

841
#endif  // V8_CRANKSHAFT_LITHIUM_H_