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

5 6
#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/compilation-phase.h"
13
#include "src/crankshaft/hydrogen.h"
14 15
#include "src/safepoint-table.h"
#include "src/zone-allocator.h"
16 17 18 19

namespace v8 {
namespace internal {

20 21 22 23 24 25
#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)
26

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

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

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

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

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

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

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

  unsigned value_;
};


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

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

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

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

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

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

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

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

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

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
  // 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> {};
166
  class VirtualRegisterField : public BitField<unsigned,        4, 18> {};
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181

  // 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.
182
  bool HasAnyPolicy() const {
183 184
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == ANY;
185 186
  }
  bool HasFixedPolicy() const {
187 188 189
    return basic_policy() == FIXED_SLOT ||
        extended_policy() == FIXED_REGISTER ||
        extended_policy() == FIXED_DOUBLE_REGISTER;
190 191
  }
  bool HasRegisterPolicy() const {
192 193 194
    return basic_policy() == EXTENDED_POLICY && (
        extended_policy() == WRITABLE_REGISTER ||
        extended_policy() == MUST_HAVE_REGISTER);
195
  }
196 197 198 199
  bool HasDoubleRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == MUST_HAVE_DOUBLE_REGISTER;
  }
200
  bool HasSameAsInputPolicy() const {
201 202 203 204 205 206 207 208 209
    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;
210
  }
211 212 213
  bool HasFixedDoubleRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == FIXED_DOUBLE_REGISTER;
214
  }
215 216 217
  bool HasWritableRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
        extended_policy() == WRITABLE_REGISTER;
218 219
  }

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

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

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

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

243 244 245 246 247 248
  // [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);
249 250
  }

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

  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;
  }
267 268 269
};


270
class LMoveOperands final BASE_EMBEDDED {
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
 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
294
  // destination are the same, or if its destination is unneeded or constant.
295
  bool IsRedundant() const {
296 297
    return IsEliminated() || source_->Equals(destination_) || IsIgnored() ||
           (destination_ != NULL && destination_->IsConstantOperand());
298 299 300
  }

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

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

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


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

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

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

 private:
335
  static LSubKindOperand* cache;
336

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


342 343 344 345
#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
346 347


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

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

  bool IsRedundant() const;

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

  void PrintDataTo(StringStream* stream) const;

 private:
  ZoneList<LMoveOperands> move_operands_;
};


367
class LPointerMap final : public ZoneObject {
368
 public:
369
  explicit LPointerMap(Zone* zone)
370 371
      : pointer_operands_(8, zone),
        untagged_operands_(0, zone),
372 373 374 375 376 377 378 379 380
        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_;
  }
381 382 383
  int lithium_position() const { return lithium_position_; }

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

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

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


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

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

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

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

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

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

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

468 469 470 471 472 473 474 475 476 477 478 479 480 481
  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) {
482
    DCHECK(ObjectIsDuplicateAt(index));
483 484 485 486
    return LengthOrDupeField::decode(object_mapping_[index]);
  }

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

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

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

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

  void PrintTo(StringStream* stream);

514 515 516 517 518 519 520 521
  // 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> { };

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

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

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

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

548 549

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

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

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

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

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

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

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

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


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

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

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

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

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

  ShallowIterator current_iterator_;
};

624

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

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

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

  int ParameterAt(int index);
  int GetParameterStackSlot(int index) const;
642 643 644 645 646 647 648
  bool HasAllocatedStackSlots() const {
    return current_frame_slots_ != base_frame_slots_;
  }
  int GetSpillSlotCount() const {
    return current_frame_slots_ - base_frame_slots_;
  }
  int GetTotalFrameSlotCount() const { return current_frame_slots_; }
649 650
  CompilationInfo* info() const { return info_; }
  HGraph* graph() const { return graph_; }
651
  Isolate* isolate() const { return graph_->isolate(); }
652 653 654 655 656 657 658 659 660 661 662
  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;

663 664
  const ZoneList<Handle<SharedFunctionInfo>>& inlined_functions() const {
    return inlined_functions_;
665 666
  }

667 668
  void AddInlinedFunction(Handle<SharedFunctionInfo> closure) {
    inlined_functions_.Add(closure, zone());
669 670
  }

671
  void AddDeprecationDependency(Handle<Map> map) {
672
    DCHECK(!map->is_deprecated());
673
    if (!map->CanBeDeprecated()) return;
674
    DCHECK(!info_->IsStub());
675
    deprecation_dependencies_.Add(map, zone());
676 677
  }

678
  void AddStabilityDependency(Handle<Map> map) {
679
    DCHECK(map->is_stable());
680
    if (!map->CanTransition()) return;
681
    DCHECK(!info_->IsStub());
682
    stability_dependencies_.Add(map, zone());
683 684
  }

685 686
  Zone* zone() const { return info_->zone(); }

687
  Handle<Code> Codegen();
688

689 690 691 692 693
  void set_allocated_double_registers(BitVector* allocated_registers);
  BitVector* allocated_double_registers() {
    return allocated_double_registers_;
  }

694
 protected:
695
  LChunk(CompilationInfo* info, HGraph* graph);
696

697 698
  int base_frame_slots_;
  int current_frame_slots_;
699 700

 private:
701 702
  void CommitDependencies(Handle<Code> code) const;

703 704
  CompilationInfo* info_;
  HGraph* const graph_;
705
  BitVector* allocated_double_registers_;
706 707
  ZoneList<LInstruction*> instructions_;
  ZoneList<LPointerMap*> pointer_maps_;
708
  ZoneList<Handle<SharedFunctionInfo>> inlined_functions_;
709 710
  ZoneList<Handle<Map>> deprecation_dependencies_;
  ZoneList<Handle<Map>> stability_dependencies_;
711 712 713
};


714 715
class LChunkBuilderBase BASE_EMBEDDED {
 public:
716
  explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph)
717
      : argument_count_(0),
718 719 720 721 722
        chunk_(NULL),
        info_(info),
        graph_(graph),
        status_(UNUSED),
        zone_(graph->zone()) {}
723 724 725

  virtual ~LChunkBuilderBase() { }

726 727 728
  void Abort(BailoutReason reason);
  void Retry(BailoutReason reason);

729
 protected:
730 731 732 733 734 735 736 737 738 739 740 741 742 743
  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; }

744 745 746 747
  // 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;

748 749 750 751 752
  // Constructs proper environment for a lazy bailout point after call, creates
  // LLazyBailout instruction and adds it to current block.
  void CreateLazyBailoutForCall(HBasicBlock* current_block, LInstruction* instr,
                                HInstruction* hydrogen_val);

753 754 755 756 757
  // Assigns given environment to an instruction.  An instruction which can
  // deoptimize must have an environment.
  LInstruction* AssignEnvironment(LInstruction* instr,
                                  HEnvironment* hydrogen_env);

758 759 760 761 762 763 764 765 766 767
  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_;
768 769 770 771
  LPlatformChunk* chunk_;
  CompilationInfo* info_;
  HGraph* const graph_;
  Status status_;
772 773 774 775 776 777

 private:
  Zone* zone_;
};


778 779
enum NumberUntagDMode {
  NUMBER_CANDIDATE_IS_SMI,
780
  NUMBER_CANDIDATE_IS_ANY_TAGGED
781 782
};

783

784 785 786
class LPhase : public CompilationPhase {
 public:
  LPhase(const char* name, LChunk* chunk)
787
      : CompilationPhase(name, chunk->info()),
788 789 790 791 792 793 794 795 796 797
        chunk_(chunk) { }
  ~LPhase();

 private:
  LChunk* chunk_;

  DISALLOW_COPY_AND_ASSIGN(LPhase);
};


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 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
// 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;
853 854
}  // namespace internal
}  // namespace v8
855

856
#endif  // V8_CRANKSHAFT_LITHIUM_H_