lithium.h 22.3 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_LITHIUM_H_
#define V8_LITHIUM_H_

8 9
#include <set>

10
#include "allocation.h"
11 12
#include "hydrogen.h"
#include "safepoint-table.h"
13
#include "zone-allocator.h"
14 15 16 17

namespace v8 {
namespace internal {

18 19 20 21 22 23
#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)
24 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 52 53 54 55 56
  bool Equals(LOperand* other) const { return value_ == other->value_; }

  void PrintTo(StringStream* stream);
  void ConvertTo(Kind kind, int index) {
    value_ = KindField::encode(kind);
    value_ |= index << kKindFieldWidth;
    ASSERT(this->index() == index);
  }

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

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

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

  unsigned value_;
};


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

249 250 251 252
  // [lifetime]: Only for non-FIXED_SLOT.
  bool IsUsedAtStart() {
    ASSERT(basic_policy() == EXTENDED_POLICY);
    return LifetimeField::decode(value_) == USED_AT_START;
253 254 255 256
  }
};


257
class LMoveOperands V8_FINAL BASE_EMBEDDED {
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
 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
  // destination are the same, or if its destination is unneeded.
  bool IsRedundant() const {
    return IsEliminated() || source_->Equals(destination_) || IsIgnored();
  }

  bool IsIgnored() const {
287
    return destination_ != NULL && destination_->IsIgnored();
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
  }

  // We clear both operands to indicate move that's been eliminated.
  void Eliminate() { source_ = destination_ = NULL; }
  bool IsEliminated() const {
    ASSERT(source_ != NULL || destination_ == NULL);
    return source_ == NULL;
  }

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


303 304
template<LOperand::Kind kOperandKind, int kNumCachedOperands>
class LSubKindOperand V8_FINAL : public LOperand {
305
 public:
306
  static LSubKindOperand* Create(int index, Zone* zone) {
307 308
    ASSERT(index >= 0);
    if (index < kNumCachedOperands) return &cache[index];
309
    return new(zone) LSubKindOperand(index);
310 311
  }

312 313 314
  static LSubKindOperand* cast(LOperand* op) {
    ASSERT(op->kind() == kOperandKind);
    return reinterpret_cast<LSubKindOperand*>(op);
315 316
  }

317
  static void SetUpCache();
318
  static void TearDownCache();
319 320

 private:
321
  static LSubKindOperand* cache;
322

323 324
  LSubKindOperand() : LOperand() { }
  explicit LSubKindOperand(int index) : LOperand(kOperandKind, index) { }
325 326 327
};


328 329 330 331
#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
332 333


334
class LParallelMove V8_FINAL : public ZoneObject {
335
 public:
336
  explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { }
337

338 339
  void AddMove(LOperand* from, LOperand* to, Zone* zone) {
    move_operands_.Add(LMoveOperands(from, to), zone);
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
  }

  bool IsRedundant() const;

  const ZoneList<LMoveOperands>* move_operands() const {
    return &move_operands_;
  }

  void PrintDataTo(StringStream* stream) const;

 private:
  ZoneList<LMoveOperands> move_operands_;
};


355
class LPointerMap V8_FINAL : public ZoneObject {
356
 public:
357
  explicit LPointerMap(Zone* zone)
358 359
      : pointer_operands_(8, zone),
        untagged_operands_(0, zone),
360 361 362 363 364 365 366 367 368
        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_;
  }
369 370 371 372 373 374 375
  int lithium_position() const { return lithium_position_; }

  void set_lithium_position(int pos) {
    ASSERT(lithium_position_ == -1);
    lithium_position_ = pos;
  }

376
  void RecordPointer(LOperand* op, Zone* zone);
377
  void RemovePointer(LOperand* op);
378
  void RecordUntagged(LOperand* op, Zone* zone);
379 380 381 382
  void PrintTo(StringStream* stream);

 private:
  ZoneList<LOperand*> pointer_operands_;
383
  ZoneList<LOperand*> untagged_operands_;
384 385 386 387
  int lithium_position_;
};


388
class LEnvironment V8_FINAL : public ZoneObject {
389 390
 public:
  LEnvironment(Handle<JSFunction> closure,
391
               FrameType frame_type,
392
               BailoutId ast_id,
393 394 395
               int parameter_count,
               int argument_count,
               int value_count,
396
               LEnvironment* outer,
397
               HEnterInlined* entry,
398
               Zone* zone)
399
      : closure_(closure),
400
        frame_type_(frame_type),
401 402 403 404
        arguments_stack_height_(argument_count),
        deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
        translation_index_(-1),
        ast_id_(ast_id),
405
        translation_size_(value_count),
406
        parameter_count_(parameter_count),
407
        pc_offset_(-1),
408
        values_(value_count, zone),
409
        is_tagged_(value_count, zone),
410
        is_uint32_(value_count, zone),
411
        object_mapping_(0, zone),
412
        outer_(outer),
413
        entry_(entry),
414 415
        zone_(zone),
        has_been_used_(false) { }
416 417

  Handle<JSFunction> closure() const { return closure_; }
418
  FrameType frame_type() const { return frame_type_; }
419 420 421
  int arguments_stack_height() const { return arguments_stack_height_; }
  int deoptimization_index() const { return deoptimization_index_; }
  int translation_index() const { return translation_index_; }
422
  BailoutId ast_id() const { return ast_id_; }
423
  int translation_size() const { return translation_size_; }
424
  int parameter_count() const { return parameter_count_; }
425
  int pc_offset() const { return pc_offset_; }
426 427
  const ZoneList<LOperand*>* values() const { return &values_; }
  LEnvironment* outer() const { return outer_; }
428
  HEnterInlined* entry() { return entry_; }
429
  Zone* zone() const { return zone_; }
430

431 432 433
  bool has_been_used() const { return has_been_used_; }
  void set_has_been_used() { has_been_used_ = true; }

434 435 436
  void AddValue(LOperand* operand,
                Representation representation,
                bool is_uint32) {
437
    values_.Add(operand, zone());
438
    if (representation.IsSmiOrTagged()) {
439
      ASSERT(!is_uint32);
440
      is_tagged_.Add(values_.length() - 1, zone());
441
    }
442 443

    if (is_uint32) {
444
      is_uint32_.Add(values_.length() - 1, zone());
445
    }
446 447 448
  }

  bool HasTaggedValueAt(int index) const {
449
    return is_tagged_.Contains(index);
450 451
  }

452 453 454 455
  bool HasUint32ValueAt(int index) const {
    return is_uint32_.Contains(index);
  }

456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
  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) {
    ASSERT(ObjectIsDuplicateAt(index));
    return LengthOrDupeField::decode(object_mapping_[index]);
  }

  int ObjectLengthAt(int index) {
    ASSERT(!ObjectIsDuplicateAt(index));
    return LengthOrDupeField::decode(object_mapping_[index]);
  }

  bool ObjectIsArgumentsAt(int index) {
    ASSERT(!ObjectIsDuplicateAt(index));
    return IsArgumentsField::decode(object_mapping_[index]);
  }

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

488 489 490
  void Register(int deoptimization_index,
                int translation_index,
                int pc_offset) {
491 492 493
    ASSERT(!HasBeenRegistered());
    deoptimization_index_ = deoptimization_index;
    translation_index_ = translation_index;
494
    pc_offset_ = pc_offset;
495 496 497 498 499 500 501
  }
  bool HasBeenRegistered() const {
    return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
  }

  void PrintTo(StringStream* stream);

502 503 504 505 506 507 508 509
  // 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> { };

510 511
 private:
  Handle<JSFunction> closure_;
512
  FrameType frame_type_;
513 514 515
  int arguments_stack_height_;
  int deoptimization_index_;
  int translation_index_;
516
  BailoutId ast_id_;
517
  int translation_size_;
518
  int parameter_count_;
519
  int pc_offset_;
520 521 522

  // Value array: [parameters] [locals] [expression stack] [de-materialized].
  //              |>--------- translation_size ---------<|
523
  ZoneList<LOperand*> values_;
524 525
  GrowableBitVector is_tagged_;
  GrowableBitVector is_uint32_;
526 527 528 529

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

530
  LEnvironment* outer_;
531
  HEnterInlined* entry_;
532
  Zone* zone_;
533
  bool has_been_used_;
534 535
};

536 537

// Iterates over the non-null, non-constant operands in an environment.
538
class ShallowIterator V8_FINAL BASE_EMBEDDED {
539 540 541 542 543
 public:
  explicit ShallowIterator(LEnvironment* env)
      : env_(env),
        limit_(env != NULL ? env->values()->length() : 0),
        current_(0) {
544
    SkipUninteresting();
545 546
  }

547
  bool Done() { return current_ >= limit_; }
548

549 550
  LOperand* Current() {
    ASSERT(!Done());
551
    ASSERT(env_->values()->at(current_) != NULL);
552 553 554
    return env_->values()->at(current_);
  }

555 556 557 558
  void Advance() {
    ASSERT(!Done());
    ++current_;
    SkipUninteresting();
559 560
  }

561
  LEnvironment* env() { return env_; }
562 563

 private:
564
  bool ShouldSkip(LOperand* op) {
565
    return op == NULL || op->IsConstantOperand();
566 567
  }

568 569 570 571
  // Skip until something interesting, beginning with and including current_.
  void SkipUninteresting() {
    while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) {
      ++current_;
572 573 574 575 576 577 578 579 580 581
    }
  }

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


// Iterator for non-null, non-constant operands incl. outer environments.
582
class DeepIterator V8_FINAL BASE_EMBEDDED {
583 584
 public:
  explicit DeepIterator(LEnvironment* env)
585 586
      : current_iterator_(env) {
    SkipUninteresting();
587 588
  }

589 590 591 592
  bool Done() { return current_iterator_.Done(); }

  LOperand* Current() {
    ASSERT(!current_iterator_.Done());
593
    ASSERT(current_iterator_.Current() != NULL);
594
    return current_iterator_.Current();
595 596
  }

597 598 599
  void Advance() {
    current_iterator_.Advance();
    SkipUninteresting();
600 601 602
  }

 private:
603 604 605 606
  void SkipUninteresting() {
    while (current_iterator_.env() != NULL && current_iterator_.Done()) {
      current_iterator_ = ShallowIterator(current_iterator_.env()->outer());
    }
607 608 609 610 611
  }

  ShallowIterator current_iterator_;
};

612

613
class LPlatformChunk;
614 615 616 617
class LGap;
class LLabel;

// Superclass providing data and behavior common to all the
618
// arch-specific LPlatformChunk classes.
619
class LChunk : public ZoneObject {
620
 public:
621
  static LChunk* NewChunk(HGraph* graph);
622 623 624

  void AddInstruction(LInstruction* instruction, HBasicBlock* block);
  LConstantOperand* DefineConstantOperand(HConstant* constant);
625
  HConstant* LookupConstant(LConstantOperand* operand) const;
626 627 628 629 630 631 632
  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_; }
633
  Isolate* isolate() const { return graph_->isolate(); }
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
  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;

  const ZoneList<Handle<JSFunction> >* inlined_closures() const {
    return &inlined_closures_;
  }

  void AddInlinedClosure(Handle<JSFunction> closure) {
    inlined_closures_.Add(closure, zone());
  }

653 654 655 656 657 658 659
  void AddDeprecationDependency(Handle<Map> map) {
    ASSERT(!map->is_deprecated());
    if (!map->CanBeDeprecated()) return;
    ASSERT(!info_->IsStub());
    deprecation_dependencies_.insert(map);
  }

660 661 662 663 664 665 666
  void AddStabilityDependency(Handle<Map> map) {
    ASSERT(map->is_stable());
    if (!map->CanTransition()) return;
    ASSERT(!info_->IsStub());
    stability_dependencies_.insert(map);
  }

667 668
  Zone* zone() const { return info_->zone(); }

669
  Handle<Code> Codegen();
670

671 672 673 674 675
  void set_allocated_double_registers(BitVector* allocated_registers);
  BitVector* allocated_double_registers() {
    return allocated_double_registers_;
  }

676
 protected:
677
  LChunk(CompilationInfo* info, HGraph* graph);
678

679 680 681
  int spill_slot_count_;

 private:
682 683 684 685 686 687
  typedef std::less<Handle<Map> > MapLess;
  typedef zone_allocator<Handle<Map> > MapAllocator;
  typedef std::set<Handle<Map>, MapLess, MapAllocator> MapSet;

  void CommitDependencies(Handle<Code> code) const;

688 689
  CompilationInfo* info_;
  HGraph* const graph_;
690
  BitVector* allocated_double_registers_;
691 692 693
  ZoneList<LInstruction*> instructions_;
  ZoneList<LPointerMap*> pointer_maps_;
  ZoneList<Handle<JSFunction> > inlined_closures_;
694
  MapSet deprecation_dependencies_;
695
  MapSet stability_dependencies_;
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
class LChunkBuilderBase BASE_EMBEDDED {
 public:
  explicit LChunkBuilderBase(Zone* zone)
      : argument_count_(0),
        zone_(zone) { }

  virtual ~LChunkBuilderBase() { }

 protected:
  // 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_;

 private:
  Zone* zone_;
};


728
int StackSlotOffset(int index);
729

730 731
enum NumberUntagDMode {
  NUMBER_CANDIDATE_IS_SMI,
732
  NUMBER_CANDIDATE_IS_ANY_TAGGED
733 734
};

735

736 737 738
class LPhase : public CompilationPhase {
 public:
  LPhase(const char* name, LChunk* chunk)
739
      : CompilationPhase(name, chunk->info()),
740 741 742 743 744 745 746 747 748 749
        chunk_(chunk) { }
  ~LPhase();

 private:
  LChunk* chunk_;

  DISALLOW_COPY_AND_ASSIGN(LPhase);
};


750 751 752
} }  // namespace v8::internal

#endif  // V8_LITHIUM_H_