1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_LITHIUM_H_ 29 #define V8_LITHIUM_H_ 30 31 #include "allocation.h" 32 #include "hydrogen.h" 33 #include "safepoint-table.h" 34 35 namespace v8 { 36 namespace internal { 37 38 #define LITHIUM_OPERAND_LIST(V) \ 39 V(ConstantOperand, CONSTANT_OPERAND) \ 40 V(StackSlot, STACK_SLOT) \ 41 V(DoubleStackSlot, DOUBLE_STACK_SLOT) \ 42 V(Register, REGISTER) \ 43 V(DoubleRegister, DOUBLE_REGISTER) 44 45 46 class LOperand: public ZoneObject { 47 public: 48 enum Kind { 49 INVALID, 50 UNALLOCATED, 51 CONSTANT_OPERAND, 52 STACK_SLOT, 53 DOUBLE_STACK_SLOT, 54 REGISTER, 55 DOUBLE_REGISTER, 56 ARGUMENT 57 }; 58 59 LOperand() : value_(KindField::encode(INVALID)) { } 60 61 Kind kind() const { return KindField::decode(value_); } 62 int index() const { return static_cast<int>(value_) >> kKindFieldWidth; } 63 #define LITHIUM_OPERAND_PREDICATE(name, type) \ 64 bool Is##name() const { return kind() == type; } 65 LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_PREDICATE) 66 LITHIUM_OPERAND_PREDICATE(Argument, ARGUMENT) 67 LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED) 68 LITHIUM_OPERAND_PREDICATE(Ignored, INVALID) 69 #undef LITHIUM_OPERAND_PREDICATE 70 bool Equals(LOperand* other) const { return value_ == other->value_; } 71 72 void PrintTo(StringStream* stream); 73 void ConvertTo(Kind kind, int index) { 74 value_ = KindField::encode(kind); 75 value_ |= index << kKindFieldWidth; 76 ASSERT(this->index() == index); 77 } 78 79 // Calls SetUpCache()/TearDownCache() for each subclass. 80 static void SetUpCaches(); 81 static void TearDownCaches(); 82 83 protected: 84 static const int kKindFieldWidth = 3; 85 class KindField : public BitField<Kind, 0, kKindFieldWidth> { }; 86 87 LOperand(Kind kind, int index) { ConvertTo(kind, index); } 88 89 unsigned value_; 90 }; 91 92 93 class LUnallocated: public LOperand { 94 public: 95 enum BasicPolicy { 96 FIXED_SLOT, 97 EXTENDED_POLICY 98 }; 99 100 enum ExtendedPolicy { 101 NONE, 102 ANY, 103 FIXED_REGISTER, 104 FIXED_DOUBLE_REGISTER, 105 MUST_HAVE_REGISTER, 106 WRITABLE_REGISTER, 107 SAME_AS_FIRST_INPUT 108 }; 109 110 // Lifetime of operand inside the instruction. 111 enum Lifetime { 112 // USED_AT_START operand is guaranteed to be live only at 113 // instruction start. Register allocator is free to assign the same register 114 // to some other operand used inside instruction (i.e. temporary or 115 // output). 116 USED_AT_START, 117 118 // USED_AT_END operand is treated as live until the end of 119 // instruction. This means that register allocator will not reuse it's 120 // register for any other operand inside instruction. 121 USED_AT_END 122 }; 123 124 explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) { 125 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 126 value_ |= ExtendedPolicyField::encode(policy); 127 value_ |= LifetimeField::encode(USED_AT_END); 128 } 129 130 LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) { 131 ASSERT(policy == FIXED_SLOT); 132 value_ |= BasicPolicyField::encode(policy); 133 value_ |= index << FixedSlotIndexField::kShift; 134 ASSERT(this->fixed_slot_index() == index); 135 } 136 137 LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) { 138 ASSERT(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER); 139 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 140 value_ |= ExtendedPolicyField::encode(policy); 141 value_ |= LifetimeField::encode(USED_AT_END); 142 value_ |= FixedRegisterField::encode(index); 143 } 144 145 LUnallocated(ExtendedPolicy policy, Lifetime lifetime) 146 : LOperand(UNALLOCATED, 0) { 147 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 148 value_ |= ExtendedPolicyField::encode(policy); 149 value_ |= LifetimeField::encode(lifetime); 150 } 151 152 LUnallocated* CopyUnconstrained(Zone* zone) { 153 LUnallocated* result = new(zone) LUnallocated(ANY); 154 result->set_virtual_register(virtual_register()); 155 return result; 156 } 157 158 static LUnallocated* cast(LOperand* op) { 159 ASSERT(op->IsUnallocated()); 160 return reinterpret_cast<LUnallocated*>(op); 161 } 162 163 // The encoding used for LUnallocated operands depends on the policy that is 164 // stored within the operand. The FIXED_SLOT policy uses a compact encoding 165 // because it accommodates a larger pay-load. 166 // 167 // For FIXED_SLOT policy: 168 // +------------------------------------------+ 169 // | slot_index | vreg | 0 | 001 | 170 // +------------------------------------------+ 171 // 172 // For all other (extended) policies: 173 // +------------------------------------------+ 174 // | reg_index | L | PPP | vreg | 1 | 001 | L ... Lifetime 175 // +------------------------------------------+ P ... Policy 176 // 177 // The slot index is a signed value which requires us to decode it manually 178 // instead of using the BitField utility class. 179 180 // The superclass has a KindField. 181 STATIC_ASSERT(kKindFieldWidth == 3); 182 183 // BitFields for all unallocated operands. 184 class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {}; 185 class VirtualRegisterField : public BitField<unsigned, 4, 18> {}; 186 187 // BitFields specific to BasicPolicy::FIXED_SLOT. 188 class FixedSlotIndexField : public BitField<int, 22, 10> {}; 189 190 // BitFields specific to BasicPolicy::EXTENDED_POLICY. 191 class ExtendedPolicyField : public BitField<ExtendedPolicy, 22, 3> {}; 192 class LifetimeField : public BitField<Lifetime, 25, 1> {}; 193 class FixedRegisterField : public BitField<int, 26, 6> {}; 194 195 static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1; 196 static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize; 197 static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1; 198 static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1)); 199 200 // Predicates for the operand policy. 201 bool HasAnyPolicy() const { 202 return basic_policy() == EXTENDED_POLICY && 203 extended_policy() == ANY; 204 } 205 bool HasFixedPolicy() const { 206 return basic_policy() == FIXED_SLOT || 207 extended_policy() == FIXED_REGISTER || 208 extended_policy() == FIXED_DOUBLE_REGISTER; 209 } 210 bool HasRegisterPolicy() const { 211 return basic_policy() == EXTENDED_POLICY && ( 212 extended_policy() == WRITABLE_REGISTER || 213 extended_policy() == MUST_HAVE_REGISTER); 214 } 215 bool HasSameAsInputPolicy() const { 216 return basic_policy() == EXTENDED_POLICY && 217 extended_policy() == SAME_AS_FIRST_INPUT; 218 } 219 bool HasFixedSlotPolicy() const { 220 return basic_policy() == FIXED_SLOT; 221 } 222 bool HasFixedRegisterPolicy() const { 223 return basic_policy() == EXTENDED_POLICY && 224 extended_policy() == FIXED_REGISTER; 225 } 226 bool HasFixedDoubleRegisterPolicy() const { 227 return basic_policy() == EXTENDED_POLICY && 228 extended_policy() == FIXED_DOUBLE_REGISTER; 229 } 230 bool HasWritableRegisterPolicy() const { 231 return basic_policy() == EXTENDED_POLICY && 232 extended_policy() == WRITABLE_REGISTER; 233 } 234 235 // [basic_policy]: Distinguish between FIXED_SLOT and all other policies. 236 BasicPolicy basic_policy() const { 237 return BasicPolicyField::decode(value_); 238 } 239 240 // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy. 241 ExtendedPolicy extended_policy() const { 242 ASSERT(basic_policy() == EXTENDED_POLICY); 243 return ExtendedPolicyField::decode(value_); 244 } 245 246 // [fixed_slot_index]: Only for FIXED_SLOT. 247 int fixed_slot_index() const { 248 ASSERT(HasFixedSlotPolicy()); 249 return static_cast<int>(value_) >> FixedSlotIndexField::kShift; 250 } 251 252 // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER. 253 int fixed_register_index() const { 254 ASSERT(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy()); 255 return FixedRegisterField::decode(value_); 256 } 257 258 // [virtual_register]: The virtual register ID for this operand. 259 int virtual_register() const { 260 return VirtualRegisterField::decode(value_); 261 } 262 void set_virtual_register(unsigned id) { 263 value_ = VirtualRegisterField::update(value_, id); 264 } 265 266 // [lifetime]: Only for non-FIXED_SLOT. 267 bool IsUsedAtStart() { 268 ASSERT(basic_policy() == EXTENDED_POLICY); 269 return LifetimeField::decode(value_) == USED_AT_START; 270 } 271 }; 272 273 274 class LMoveOperands BASE_EMBEDDED { 275 public: 276 LMoveOperands(LOperand* source, LOperand* destination) 277 : source_(source), destination_(destination) { 278 } 279 280 LOperand* source() const { return source_; } 281 void set_source(LOperand* operand) { source_ = operand; } 282 283 LOperand* destination() const { return destination_; } 284 void set_destination(LOperand* operand) { destination_ = operand; } 285 286 // The gap resolver marks moves as "in-progress" by clearing the 287 // destination (but not the source). 288 bool IsPending() const { 289 return destination_ == NULL && source_ != NULL; 290 } 291 292 // True if this move a move into the given destination operand. 293 bool Blocks(LOperand* operand) const { 294 return !IsEliminated() && source()->Equals(operand); 295 } 296 297 // A move is redundant if it's been eliminated, if its source and 298 // destination are the same, or if its destination is unneeded. 299 bool IsRedundant() const { 300 return IsEliminated() || source_->Equals(destination_) || IsIgnored(); 301 } 302 303 bool IsIgnored() const { 304 return destination_ != NULL && destination_->IsIgnored(); 305 } 306 307 // We clear both operands to indicate move that's been eliminated. 308 void Eliminate() { source_ = destination_ = NULL; } 309 bool IsEliminated() const { 310 ASSERT(source_ != NULL || destination_ == NULL); 311 return source_ == NULL; 312 } 313 314 private: 315 LOperand* source_; 316 LOperand* destination_; 317 }; 318 319 320 class LConstantOperand: public LOperand { 321 public: 322 static LConstantOperand* Create(int index, Zone* zone) { 323 ASSERT(index >= 0); 324 if (index < kNumCachedOperands) return &cache[index]; 325 return new(zone) LConstantOperand(index); 326 } 327 328 static LConstantOperand* cast(LOperand* op) { 329 ASSERT(op->IsConstantOperand()); 330 return reinterpret_cast<LConstantOperand*>(op); 331 } 332 333 static void SetUpCache(); 334 static void TearDownCache(); 335 336 private: 337 static const int kNumCachedOperands = 128; 338 static LConstantOperand* cache; 339 340 LConstantOperand() : LOperand() { } 341 explicit LConstantOperand(int index) : LOperand(CONSTANT_OPERAND, index) { } 342 }; 343 344 345 class LArgument: public LOperand { 346 public: 347 explicit LArgument(int index) : LOperand(ARGUMENT, index) { } 348 349 static LArgument* cast(LOperand* op) { 350 ASSERT(op->IsArgument()); 351 return reinterpret_cast<LArgument*>(op); 352 } 353 }; 354 355 356 class LStackSlot: public LOperand { 357 public: 358 static LStackSlot* Create(int index, Zone* zone) { 359 ASSERT(index >= 0); 360 if (index < kNumCachedOperands) return &cache[index]; 361 return new(zone) LStackSlot(index); 362 } 363 364 static LStackSlot* cast(LOperand* op) { 365 ASSERT(op->IsStackSlot()); 366 return reinterpret_cast<LStackSlot*>(op); 367 } 368 369 static void SetUpCache(); 370 static void TearDownCache(); 371 372 private: 373 static const int kNumCachedOperands = 128; 374 static LStackSlot* cache; 375 376 LStackSlot() : LOperand() { } 377 explicit LStackSlot(int index) : LOperand(STACK_SLOT, index) { } 378 }; 379 380 381 class LDoubleStackSlot: public LOperand { 382 public: 383 static LDoubleStackSlot* Create(int index, Zone* zone) { 384 ASSERT(index >= 0); 385 if (index < kNumCachedOperands) return &cache[index]; 386 return new(zone) LDoubleStackSlot(index); 387 } 388 389 static LDoubleStackSlot* cast(LOperand* op) { 390 ASSERT(op->IsStackSlot()); 391 return reinterpret_cast<LDoubleStackSlot*>(op); 392 } 393 394 static void SetUpCache(); 395 static void TearDownCache(); 396 397 private: 398 static const int kNumCachedOperands = 128; 399 static LDoubleStackSlot* cache; 400 401 LDoubleStackSlot() : LOperand() { } 402 explicit LDoubleStackSlot(int index) : LOperand(DOUBLE_STACK_SLOT, index) { } 403 }; 404 405 406 class LRegister: public LOperand { 407 public: 408 static LRegister* Create(int index, Zone* zone) { 409 ASSERT(index >= 0); 410 if (index < kNumCachedOperands) return &cache[index]; 411 return new(zone) LRegister(index); 412 } 413 414 static LRegister* cast(LOperand* op) { 415 ASSERT(op->IsRegister()); 416 return reinterpret_cast<LRegister*>(op); 417 } 418 419 static void SetUpCache(); 420 static void TearDownCache(); 421 422 private: 423 static const int kNumCachedOperands = 16; 424 static LRegister* cache; 425 426 LRegister() : LOperand() { } 427 explicit LRegister(int index) : LOperand(REGISTER, index) { } 428 }; 429 430 431 class LDoubleRegister: public LOperand { 432 public: 433 static LDoubleRegister* Create(int index, Zone* zone) { 434 ASSERT(index >= 0); 435 if (index < kNumCachedOperands) return &cache[index]; 436 return new(zone) LDoubleRegister(index); 437 } 438 439 static LDoubleRegister* cast(LOperand* op) { 440 ASSERT(op->IsDoubleRegister()); 441 return reinterpret_cast<LDoubleRegister*>(op); 442 } 443 444 static void SetUpCache(); 445 static void TearDownCache(); 446 447 private: 448 static const int kNumCachedOperands = 16; 449 static LDoubleRegister* cache; 450 451 LDoubleRegister() : LOperand() { } 452 explicit LDoubleRegister(int index) : LOperand(DOUBLE_REGISTER, index) { } 453 }; 454 455 456 class LParallelMove : public ZoneObject { 457 public: 458 explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { } 459 460 void AddMove(LOperand* from, LOperand* to, Zone* zone) { 461 move_operands_.Add(LMoveOperands(from, to), zone); 462 } 463 464 bool IsRedundant() const; 465 466 const ZoneList<LMoveOperands>* move_operands() const { 467 return &move_operands_; 468 } 469 470 void PrintDataTo(StringStream* stream) const; 471 472 private: 473 ZoneList<LMoveOperands> move_operands_; 474 }; 475 476 477 class LPointerMap: public ZoneObject { 478 public: 479 explicit LPointerMap(int position, Zone* zone) 480 : pointer_operands_(8, zone), 481 untagged_operands_(0, zone), 482 position_(position), 483 lithium_position_(-1) { } 484 485 const ZoneList<LOperand*>* GetNormalizedOperands() { 486 for (int i = 0; i < untagged_operands_.length(); ++i) { 487 RemovePointer(untagged_operands_[i]); 488 } 489 untagged_operands_.Clear(); 490 return &pointer_operands_; 491 } 492 int position() const { return position_; } 493 int lithium_position() const { return lithium_position_; } 494 495 void set_lithium_position(int pos) { 496 ASSERT(lithium_position_ == -1); 497 lithium_position_ = pos; 498 } 499 500 void RecordPointer(LOperand* op, Zone* zone); 501 void RemovePointer(LOperand* op); 502 void RecordUntagged(LOperand* op, Zone* zone); 503 void PrintTo(StringStream* stream); 504 505 private: 506 ZoneList<LOperand*> pointer_operands_; 507 ZoneList<LOperand*> untagged_operands_; 508 int position_; 509 int lithium_position_; 510 }; 511 512 513 class LEnvironment: public ZoneObject { 514 public: 515 LEnvironment(Handle<JSFunction> closure, 516 FrameType frame_type, 517 BailoutId ast_id, 518 int parameter_count, 519 int argument_count, 520 int value_count, 521 LEnvironment* outer, 522 HEnterInlined* entry, 523 Zone* zone) 524 : closure_(closure), 525 frame_type_(frame_type), 526 arguments_stack_height_(argument_count), 527 deoptimization_index_(Safepoint::kNoDeoptimizationIndex), 528 translation_index_(-1), 529 ast_id_(ast_id), 530 translation_size_(value_count), 531 parameter_count_(parameter_count), 532 pc_offset_(-1), 533 values_(value_count, zone), 534 is_tagged_(value_count, zone), 535 is_uint32_(value_count, zone), 536 object_mapping_(0, zone), 537 outer_(outer), 538 entry_(entry), 539 zone_(zone) { } 540 541 Handle<JSFunction> closure() const { return closure_; } 542 FrameType frame_type() const { return frame_type_; } 543 int arguments_stack_height() const { return arguments_stack_height_; } 544 int deoptimization_index() const { return deoptimization_index_; } 545 int translation_index() const { return translation_index_; } 546 BailoutId ast_id() const { return ast_id_; } 547 int translation_size() const { return translation_size_; } 548 int parameter_count() const { return parameter_count_; } 549 int pc_offset() const { return pc_offset_; } 550 const ZoneList<LOperand*>* values() const { return &values_; } 551 LEnvironment* outer() const { return outer_; } 552 HEnterInlined* entry() { return entry_; } 553 Zone* zone() const { return zone_; } 554 555 void AddValue(LOperand* operand, 556 Representation representation, 557 bool is_uint32) { 558 values_.Add(operand, zone()); 559 if (representation.IsSmiOrTagged()) { 560 ASSERT(!is_uint32); 561 is_tagged_.Add(values_.length() - 1, zone()); 562 } 563 564 if (is_uint32) { 565 is_uint32_.Add(values_.length() - 1, zone()); 566 } 567 } 568 569 bool HasTaggedValueAt(int index) const { 570 return is_tagged_.Contains(index); 571 } 572 573 bool HasUint32ValueAt(int index) const { 574 return is_uint32_.Contains(index); 575 } 576 577 void AddNewObject(int length, bool is_arguments) { 578 uint32_t encoded = LengthOrDupeField::encode(length) | 579 IsArgumentsField::encode(is_arguments) | 580 IsDuplicateField::encode(false); 581 object_mapping_.Add(encoded, zone()); 582 } 583 584 void AddDuplicateObject(int dupe_of) { 585 uint32_t encoded = LengthOrDupeField::encode(dupe_of) | 586 IsDuplicateField::encode(true); 587 object_mapping_.Add(encoded, zone()); 588 } 589 590 int ObjectDuplicateOfAt(int index) { 591 ASSERT(ObjectIsDuplicateAt(index)); 592 return LengthOrDupeField::decode(object_mapping_[index]); 593 } 594 595 int ObjectLengthAt(int index) { 596 ASSERT(!ObjectIsDuplicateAt(index)); 597 return LengthOrDupeField::decode(object_mapping_[index]); 598 } 599 600 bool ObjectIsArgumentsAt(int index) { 601 ASSERT(!ObjectIsDuplicateAt(index)); 602 return IsArgumentsField::decode(object_mapping_[index]); 603 } 604 605 bool ObjectIsDuplicateAt(int index) { 606 return IsDuplicateField::decode(object_mapping_[index]); 607 } 608 609 void Register(int deoptimization_index, 610 int translation_index, 611 int pc_offset) { 612 ASSERT(!HasBeenRegistered()); 613 deoptimization_index_ = deoptimization_index; 614 translation_index_ = translation_index; 615 pc_offset_ = pc_offset; 616 } 617 bool HasBeenRegistered() const { 618 return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex; 619 } 620 621 void PrintTo(StringStream* stream); 622 623 // Marker value indicating a de-materialized object. 624 static LOperand* materialization_marker() { return NULL; } 625 626 // Encoding used for the object_mapping map below. 627 class LengthOrDupeField : public BitField<int, 0, 30> { }; 628 class IsArgumentsField : public BitField<bool, 30, 1> { }; 629 class IsDuplicateField : public BitField<bool, 31, 1> { }; 630 631 private: 632 Handle<JSFunction> closure_; 633 FrameType frame_type_; 634 int arguments_stack_height_; 635 int deoptimization_index_; 636 int translation_index_; 637 BailoutId ast_id_; 638 int translation_size_; 639 int parameter_count_; 640 int pc_offset_; 641 642 // Value array: [parameters] [locals] [expression stack] [de-materialized]. 643 // |>--------- translation_size ---------<| 644 ZoneList<LOperand*> values_; 645 GrowableBitVector is_tagged_; 646 GrowableBitVector is_uint32_; 647 648 // Map with encoded information about materialization_marker operands. 649 ZoneList<uint32_t> object_mapping_; 650 651 LEnvironment* outer_; 652 HEnterInlined* entry_; 653 Zone* zone_; 654 }; 655 656 657 // Iterates over the non-null, non-constant operands in an environment. 658 class ShallowIterator BASE_EMBEDDED { 659 public: 660 explicit ShallowIterator(LEnvironment* env) 661 : env_(env), 662 limit_(env != NULL ? env->values()->length() : 0), 663 current_(0) { 664 SkipUninteresting(); 665 } 666 667 bool Done() { return current_ >= limit_; } 668 669 LOperand* Current() { 670 ASSERT(!Done()); 671 ASSERT(env_->values()->at(current_) != NULL); 672 return env_->values()->at(current_); 673 } 674 675 void Advance() { 676 ASSERT(!Done()); 677 ++current_; 678 SkipUninteresting(); 679 } 680 681 LEnvironment* env() { return env_; } 682 683 private: 684 bool ShouldSkip(LOperand* op) { 685 return op == NULL || op->IsConstantOperand() || op->IsArgument(); 686 } 687 688 // Skip until something interesting, beginning with and including current_. 689 void SkipUninteresting() { 690 while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) { 691 ++current_; 692 } 693 } 694 695 LEnvironment* env_; 696 int limit_; 697 int current_; 698 }; 699 700 701 // Iterator for non-null, non-constant operands incl. outer environments. 702 class DeepIterator BASE_EMBEDDED { 703 public: 704 explicit DeepIterator(LEnvironment* env) 705 : current_iterator_(env) { 706 SkipUninteresting(); 707 } 708 709 bool Done() { return current_iterator_.Done(); } 710 711 LOperand* Current() { 712 ASSERT(!current_iterator_.Done()); 713 ASSERT(current_iterator_.Current() != NULL); 714 return current_iterator_.Current(); 715 } 716 717 void Advance() { 718 current_iterator_.Advance(); 719 SkipUninteresting(); 720 } 721 722 private: 723 void SkipUninteresting() { 724 while (current_iterator_.env() != NULL && current_iterator_.Done()) { 725 current_iterator_ = ShallowIterator(current_iterator_.env()->outer()); 726 } 727 } 728 729 ShallowIterator current_iterator_; 730 }; 731 732 733 class LPlatformChunk; 734 class LGap; 735 class LLabel; 736 737 // Superclass providing data and behavior common to all the 738 // arch-specific LPlatformChunk classes. 739 class LChunk: public ZoneObject { 740 public: 741 static LChunk* NewChunk(HGraph* graph); 742 743 void AddInstruction(LInstruction* instruction, HBasicBlock* block); 744 LConstantOperand* DefineConstantOperand(HConstant* constant); 745 HConstant* LookupConstant(LConstantOperand* operand) const; 746 Representation LookupLiteralRepresentation(LConstantOperand* operand) const; 747 748 int ParameterAt(int index); 749 int GetParameterStackSlot(int index) const; 750 int spill_slot_count() const { return spill_slot_count_; } 751 CompilationInfo* info() const { return info_; } 752 HGraph* graph() const { return graph_; } 753 Isolate* isolate() const { return graph_->isolate(); } 754 const ZoneList<LInstruction*>* instructions() const { return &instructions_; } 755 void AddGapMove(int index, LOperand* from, LOperand* to); 756 LGap* GetGapAt(int index) const; 757 bool IsGapAt(int index) const; 758 int NearestGapPos(int index) const; 759 void MarkEmptyBlocks(); 760 const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; } 761 LLabel* GetLabel(int block_id) const; 762 int LookupDestination(int block_id) const; 763 Label* GetAssemblyLabel(int block_id) const; 764 765 const ZoneList<Handle<JSFunction> >* inlined_closures() const { 766 return &inlined_closures_; 767 } 768 769 void AddInlinedClosure(Handle<JSFunction> closure) { 770 inlined_closures_.Add(closure, zone()); 771 } 772 773 Zone* zone() const { return info_->zone(); } 774 775 Handle<Code> Codegen(); 776 777 void set_allocated_double_registers(BitVector* allocated_registers); 778 BitVector* allocated_double_registers() { 779 return allocated_double_registers_; 780 } 781 782 protected: 783 LChunk(CompilationInfo* info, HGraph* graph); 784 785 int spill_slot_count_; 786 787 private: 788 CompilationInfo* info_; 789 HGraph* const graph_; 790 BitVector* allocated_double_registers_; 791 ZoneList<LInstruction*> instructions_; 792 ZoneList<LPointerMap*> pointer_maps_; 793 ZoneList<Handle<JSFunction> > inlined_closures_; 794 }; 795 796 797 int ElementsKindToShiftSize(ElementsKind elements_kind); 798 int StackSlotOffset(int index); 799 800 enum NumberUntagDMode { 801 NUMBER_CANDIDATE_IS_SMI, 802 NUMBER_CANDIDATE_IS_ANY_TAGGED 803 }; 804 805 806 class LPhase : public CompilationPhase { 807 public: 808 LPhase(const char* name, LChunk* chunk) 809 : CompilationPhase(name, chunk->info()), 810 chunk_(chunk) { } 811 ~LPhase(); 812 813 private: 814 LChunk* chunk_; 815 816 DISALLOW_COPY_AND_ASSIGN(LPhase); 817 }; 818 819 820 } } // namespace v8::internal 821 822 #endif // V8_LITHIUM_H_ 823