1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_LITHIUM_H_ 6 #define V8_LITHIUM_H_ 7 8 #include <set> 9 10 #include "src/allocation.h" 11 #include "src/hydrogen.h" 12 #include "src/safepoint-table.h" 13 #include "src/zone-allocator.h" 14 15 namespace v8 { 16 namespace internal { 17 18 #define LITHIUM_OPERAND_LIST(V) \ 19 V(ConstantOperand, CONSTANT_OPERAND, 128) \ 20 V(StackSlot, STACK_SLOT, 128) \ 21 V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \ 22 V(Register, REGISTER, 16) \ 23 V(DoubleRegister, DOUBLE_REGISTER, 16) 24 25 26 class LOperand : public ZoneObject { 27 public: 28 enum Kind { 29 INVALID, 30 UNALLOCATED, 31 CONSTANT_OPERAND, 32 STACK_SLOT, 33 DOUBLE_STACK_SLOT, 34 REGISTER, 35 DOUBLE_REGISTER 36 }; 37 38 LOperand() : value_(KindField::encode(INVALID)) { } 39 40 Kind kind() const { return KindField::decode(value_); } 41 int index() const { return static_cast<int>(value_) >> kKindFieldWidth; } 42 #define LITHIUM_OPERAND_PREDICATE(name, type, number) \ 43 bool Is##name() const { return kind() == type; } 44 LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_PREDICATE) 45 LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0) 46 LITHIUM_OPERAND_PREDICATE(Ignored, INVALID, 0) 47 #undef LITHIUM_OPERAND_PREDICATE 48 bool Equals(LOperand* other) const { return value_ == other->value_; } 49 50 void PrintTo(StringStream* stream); 51 void ConvertTo(Kind kind, int index) { 52 value_ = KindField::encode(kind); 53 value_ |= index << kKindFieldWidth; 54 ASSERT(this->index() == index); 55 } 56 57 // Calls SetUpCache()/TearDownCache() for each subclass. 58 static void SetUpCaches(); 59 static void TearDownCaches(); 60 61 protected: 62 static const int kKindFieldWidth = 3; 63 class KindField : public BitField<Kind, 0, kKindFieldWidth> { }; 64 65 LOperand(Kind kind, int index) { ConvertTo(kind, index); } 66 67 unsigned value_; 68 }; 69 70 71 class LUnallocated : public LOperand { 72 public: 73 enum BasicPolicy { 74 FIXED_SLOT, 75 EXTENDED_POLICY 76 }; 77 78 enum ExtendedPolicy { 79 NONE, 80 ANY, 81 FIXED_REGISTER, 82 FIXED_DOUBLE_REGISTER, 83 MUST_HAVE_REGISTER, 84 MUST_HAVE_DOUBLE_REGISTER, 85 WRITABLE_REGISTER, 86 SAME_AS_FIRST_INPUT 87 }; 88 89 // Lifetime of operand inside the instruction. 90 enum Lifetime { 91 // USED_AT_START operand is guaranteed to be live only at 92 // instruction start. Register allocator is free to assign the same register 93 // to some other operand used inside instruction (i.e. temporary or 94 // output). 95 USED_AT_START, 96 97 // USED_AT_END operand is treated as live until the end of 98 // instruction. This means that register allocator will not reuse it's 99 // register for any other operand inside instruction. 100 USED_AT_END 101 }; 102 103 explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) { 104 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 105 value_ |= ExtendedPolicyField::encode(policy); 106 value_ |= LifetimeField::encode(USED_AT_END); 107 } 108 109 LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) { 110 ASSERT(policy == FIXED_SLOT); 111 value_ |= BasicPolicyField::encode(policy); 112 value_ |= index << FixedSlotIndexField::kShift; 113 ASSERT(this->fixed_slot_index() == index); 114 } 115 116 LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) { 117 ASSERT(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER); 118 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 119 value_ |= ExtendedPolicyField::encode(policy); 120 value_ |= LifetimeField::encode(USED_AT_END); 121 value_ |= FixedRegisterField::encode(index); 122 } 123 124 LUnallocated(ExtendedPolicy policy, Lifetime lifetime) 125 : LOperand(UNALLOCATED, 0) { 126 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 127 value_ |= ExtendedPolicyField::encode(policy); 128 value_ |= LifetimeField::encode(lifetime); 129 } 130 131 LUnallocated* CopyUnconstrained(Zone* zone) { 132 LUnallocated* result = new(zone) LUnallocated(ANY); 133 result->set_virtual_register(virtual_register()); 134 return result; 135 } 136 137 static LUnallocated* cast(LOperand* op) { 138 ASSERT(op->IsUnallocated()); 139 return reinterpret_cast<LUnallocated*>(op); 140 } 141 142 // The encoding used for LUnallocated operands depends on the policy that is 143 // stored within the operand. The FIXED_SLOT policy uses a compact encoding 144 // because it accommodates a larger pay-load. 145 // 146 // For FIXED_SLOT policy: 147 // +------------------------------------------+ 148 // | slot_index | vreg | 0 | 001 | 149 // +------------------------------------------+ 150 // 151 // For all other (extended) policies: 152 // +------------------------------------------+ 153 // | reg_index | L | PPP | vreg | 1 | 001 | L ... Lifetime 154 // +------------------------------------------+ P ... Policy 155 // 156 // The slot index is a signed value which requires us to decode it manually 157 // instead of using the BitField utility class. 158 159 // The superclass has a KindField. 160 STATIC_ASSERT(kKindFieldWidth == 3); 161 162 // BitFields for all unallocated operands. 163 class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {}; 164 class VirtualRegisterField : public BitField<unsigned, 4, 18> {}; 165 166 // BitFields specific to BasicPolicy::FIXED_SLOT. 167 class FixedSlotIndexField : public BitField<int, 22, 10> {}; 168 169 // BitFields specific to BasicPolicy::EXTENDED_POLICY. 170 class ExtendedPolicyField : public BitField<ExtendedPolicy, 22, 3> {}; 171 class LifetimeField : public BitField<Lifetime, 25, 1> {}; 172 class FixedRegisterField : public BitField<int, 26, 6> {}; 173 174 static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1; 175 static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize; 176 static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1; 177 static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1)); 178 179 // Predicates for the operand policy. 180 bool HasAnyPolicy() const { 181 return basic_policy() == EXTENDED_POLICY && 182 extended_policy() == ANY; 183 } 184 bool HasFixedPolicy() const { 185 return basic_policy() == FIXED_SLOT || 186 extended_policy() == FIXED_REGISTER || 187 extended_policy() == FIXED_DOUBLE_REGISTER; 188 } 189 bool HasRegisterPolicy() const { 190 return basic_policy() == EXTENDED_POLICY && ( 191 extended_policy() == WRITABLE_REGISTER || 192 extended_policy() == MUST_HAVE_REGISTER); 193 } 194 bool HasDoubleRegisterPolicy() const { 195 return basic_policy() == EXTENDED_POLICY && 196 extended_policy() == MUST_HAVE_DOUBLE_REGISTER; 197 } 198 bool HasSameAsInputPolicy() const { 199 return basic_policy() == EXTENDED_POLICY && 200 extended_policy() == SAME_AS_FIRST_INPUT; 201 } 202 bool HasFixedSlotPolicy() const { 203 return basic_policy() == FIXED_SLOT; 204 } 205 bool HasFixedRegisterPolicy() const { 206 return basic_policy() == EXTENDED_POLICY && 207 extended_policy() == FIXED_REGISTER; 208 } 209 bool HasFixedDoubleRegisterPolicy() const { 210 return basic_policy() == EXTENDED_POLICY && 211 extended_policy() == FIXED_DOUBLE_REGISTER; 212 } 213 bool HasWritableRegisterPolicy() const { 214 return basic_policy() == EXTENDED_POLICY && 215 extended_policy() == WRITABLE_REGISTER; 216 } 217 218 // [basic_policy]: Distinguish between FIXED_SLOT and all other policies. 219 BasicPolicy basic_policy() const { 220 return BasicPolicyField::decode(value_); 221 } 222 223 // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy. 224 ExtendedPolicy extended_policy() const { 225 ASSERT(basic_policy() == EXTENDED_POLICY); 226 return ExtendedPolicyField::decode(value_); 227 } 228 229 // [fixed_slot_index]: Only for FIXED_SLOT. 230 int fixed_slot_index() const { 231 ASSERT(HasFixedSlotPolicy()); 232 return static_cast<int>(value_) >> FixedSlotIndexField::kShift; 233 } 234 235 // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER. 236 int fixed_register_index() const { 237 ASSERT(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy()); 238 return FixedRegisterField::decode(value_); 239 } 240 241 // [virtual_register]: The virtual register ID for this operand. 242 int virtual_register() const { 243 return VirtualRegisterField::decode(value_); 244 } 245 void set_virtual_register(unsigned id) { 246 value_ = VirtualRegisterField::update(value_, id); 247 } 248 249 // [lifetime]: Only for non-FIXED_SLOT. 250 bool IsUsedAtStart() { 251 ASSERT(basic_policy() == EXTENDED_POLICY); 252 return LifetimeField::decode(value_) == USED_AT_START; 253 } 254 }; 255 256 257 class LMoveOperands V8_FINAL BASE_EMBEDDED { 258 public: 259 LMoveOperands(LOperand* source, LOperand* destination) 260 : source_(source), destination_(destination) { 261 } 262 263 LOperand* source() const { return source_; } 264 void set_source(LOperand* operand) { source_ = operand; } 265 266 LOperand* destination() const { return destination_; } 267 void set_destination(LOperand* operand) { destination_ = operand; } 268 269 // The gap resolver marks moves as "in-progress" by clearing the 270 // destination (but not the source). 271 bool IsPending() const { 272 return destination_ == NULL && source_ != NULL; 273 } 274 275 // True if this move a move into the given destination operand. 276 bool Blocks(LOperand* operand) const { 277 return !IsEliminated() && source()->Equals(operand); 278 } 279 280 // A move is redundant if it's been eliminated, if its source and 281 // destination are the same, or if its destination is unneeded. 282 bool IsRedundant() const { 283 return IsEliminated() || source_->Equals(destination_) || IsIgnored(); 284 } 285 286 bool IsIgnored() const { 287 return destination_ != NULL && destination_->IsIgnored(); 288 } 289 290 // We clear both operands to indicate move that's been eliminated. 291 void Eliminate() { source_ = destination_ = NULL; } 292 bool IsEliminated() const { 293 ASSERT(source_ != NULL || destination_ == NULL); 294 return source_ == NULL; 295 } 296 297 private: 298 LOperand* source_; 299 LOperand* destination_; 300 }; 301 302 303 template<LOperand::Kind kOperandKind, int kNumCachedOperands> 304 class LSubKindOperand V8_FINAL : public LOperand { 305 public: 306 static LSubKindOperand* Create(int index, Zone* zone) { 307 ASSERT(index >= 0); 308 if (index < kNumCachedOperands) return &cache[index]; 309 return new(zone) LSubKindOperand(index); 310 } 311 312 static LSubKindOperand* cast(LOperand* op) { 313 ASSERT(op->kind() == kOperandKind); 314 return reinterpret_cast<LSubKindOperand*>(op); 315 } 316 317 static void SetUpCache(); 318 static void TearDownCache(); 319 320 private: 321 static LSubKindOperand* cache; 322 323 LSubKindOperand() : LOperand() { } 324 explicit LSubKindOperand(int index) : LOperand(kOperandKind, index) { } 325 }; 326 327 328 #define LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number) \ 329 typedef LSubKindOperand<LOperand::type, number> L##name; 330 LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS) 331 #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 void AddMove(LOperand* from, LOperand* to, Zone* zone) { 339 move_operands_.Add(LMoveOperands(from, to), zone); 340 } 341 342 bool IsRedundant() const; 343 344 const ZoneList<LMoveOperands>* move_operands() const { 345 return &move_operands_; 346 } 347 348 void PrintDataTo(StringStream* stream) const; 349 350 private: 351 ZoneList<LMoveOperands> move_operands_; 352 }; 353 354 355 class LPointerMap V8_FINAL : public ZoneObject { 356 public: 357 explicit LPointerMap(Zone* zone) 358 : pointer_operands_(8, zone), 359 untagged_operands_(0, zone), 360 lithium_position_(-1) { } 361 362 const ZoneList<LOperand*>* GetNormalizedOperands() { 363 for (int i = 0; i < untagged_operands_.length(); ++i) { 364 RemovePointer(untagged_operands_[i]); 365 } 366 untagged_operands_.Clear(); 367 return &pointer_operands_; 368 } 369 int lithium_position() const { return lithium_position_; } 370 371 void set_lithium_position(int pos) { 372 ASSERT(lithium_position_ == -1); 373 lithium_position_ = pos; 374 } 375 376 void RecordPointer(LOperand* op, Zone* zone); 377 void RemovePointer(LOperand* op); 378 void RecordUntagged(LOperand* op, Zone* zone); 379 void PrintTo(StringStream* stream); 380 381 private: 382 ZoneList<LOperand*> pointer_operands_; 383 ZoneList<LOperand*> untagged_operands_; 384 int lithium_position_; 385 }; 386 387 388 class LEnvironment V8_FINAL : public ZoneObject { 389 public: 390 LEnvironment(Handle<JSFunction> closure, 391 FrameType frame_type, 392 BailoutId ast_id, 393 int parameter_count, 394 int argument_count, 395 int value_count, 396 LEnvironment* outer, 397 HEnterInlined* entry, 398 Zone* zone) 399 : closure_(closure), 400 frame_type_(frame_type), 401 arguments_stack_height_(argument_count), 402 deoptimization_index_(Safepoint::kNoDeoptimizationIndex), 403 translation_index_(-1), 404 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 zone_(zone), 415 has_been_used_(false) { } 416 417 Handle<JSFunction> closure() const { return closure_; } 418 FrameType frame_type() const { return frame_type_; } 419 int arguments_stack_height() const { return arguments_stack_height_; } 420 int deoptimization_index() const { return deoptimization_index_; } 421 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 const ZoneList<LOperand*>* values() const { return &values_; } 427 LEnvironment* outer() const { return outer_; } 428 HEnterInlined* entry() { return entry_; } 429 Zone* zone() const { return zone_; } 430 431 bool has_been_used() const { return has_been_used_; } 432 void set_has_been_used() { has_been_used_ = true; } 433 434 void AddValue(LOperand* operand, 435 Representation representation, 436 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 bool HasUint32ValueAt(int index) const { 453 return is_uint32_.Contains(index); 454 } 455 456 void AddNewObject(int length, bool is_arguments) { 457 uint32_t encoded = LengthOrDupeField::encode(length) | 458 IsArgumentsField::encode(is_arguments) | 459 IsDuplicateField::encode(false); 460 object_mapping_.Add(encoded, zone()); 461 } 462 463 void AddDuplicateObject(int dupe_of) { 464 uint32_t encoded = LengthOrDupeField::encode(dupe_of) | 465 IsDuplicateField::encode(true); 466 object_mapping_.Add(encoded, zone()); 467 } 468 469 int ObjectDuplicateOfAt(int index) { 470 ASSERT(ObjectIsDuplicateAt(index)); 471 return LengthOrDupeField::decode(object_mapping_[index]); 472 } 473 474 int ObjectLengthAt(int index) { 475 ASSERT(!ObjectIsDuplicateAt(index)); 476 return LengthOrDupeField::decode(object_mapping_[index]); 477 } 478 479 bool ObjectIsArgumentsAt(int index) { 480 ASSERT(!ObjectIsDuplicateAt(index)); 481 return IsArgumentsField::decode(object_mapping_[index]); 482 } 483 484 bool ObjectIsDuplicateAt(int index) { 485 return IsDuplicateField::decode(object_mapping_[index]); 486 } 487 488 void Register(int deoptimization_index, 489 int translation_index, 490 int pc_offset) { 491 ASSERT(!HasBeenRegistered()); 492 deoptimization_index_ = deoptimization_index; 493 translation_index_ = translation_index; 494 pc_offset_ = pc_offset; 495 } 496 bool HasBeenRegistered() const { 497 return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex; 498 } 499 500 void PrintTo(StringStream* stream); 501 502 // Marker value indicating a de-materialized object. 503 static LOperand* materialization_marker() { return NULL; } 504 505 // Encoding used for the object_mapping map below. 506 class LengthOrDupeField : public BitField<int, 0, 30> { }; 507 class IsArgumentsField : public BitField<bool, 30, 1> { }; 508 class IsDuplicateField : public BitField<bool, 31, 1> { }; 509 510 private: 511 Handle<JSFunction> closure_; 512 FrameType frame_type_; 513 int arguments_stack_height_; 514 int deoptimization_index_; 515 int translation_index_; 516 BailoutId ast_id_; 517 int translation_size_; 518 int parameter_count_; 519 int pc_offset_; 520 521 // Value array: [parameters] [locals] [expression stack] [de-materialized]. 522 // |>--------- translation_size ---------<| 523 ZoneList<LOperand*> values_; 524 GrowableBitVector is_tagged_; 525 GrowableBitVector is_uint32_; 526 527 // Map with encoded information about materialization_marker operands. 528 ZoneList<uint32_t> object_mapping_; 529 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 public: 540 explicit ShallowIterator(LEnvironment* env) 541 : env_(env), 542 limit_(env != NULL ? env->values()->length() : 0), 543 current_(0) { 544 SkipUninteresting(); 545 } 546 547 bool Done() { return current_ >= limit_; } 548 549 LOperand* Current() { 550 ASSERT(!Done()); 551 ASSERT(env_->values()->at(current_) != NULL); 552 return env_->values()->at(current_); 553 } 554 555 void Advance() { 556 ASSERT(!Done()); 557 ++current_; 558 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 // Skip until something interesting, beginning with and including current_. 569 void SkipUninteresting() { 570 while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) { 571 ++current_; 572 } 573 } 574 575 LEnvironment* env_; 576 int limit_; 577 int current_; 578 }; 579 580 581 // Iterator for non-null, non-constant operands incl. outer environments. 582 class DeepIterator V8_FINAL BASE_EMBEDDED { 583 public: 584 explicit DeepIterator(LEnvironment* env) 585 : current_iterator_(env) { 586 SkipUninteresting(); 587 } 588 589 bool Done() { return current_iterator_.Done(); } 590 591 LOperand* Current() { 592 ASSERT(!current_iterator_.Done()); 593 ASSERT(current_iterator_.Current() != NULL); 594 return current_iterator_.Current(); 595 } 596 597 void Advance() { 598 current_iterator_.Advance(); 599 SkipUninteresting(); 600 } 601 602 private: 603 void SkipUninteresting() { 604 while (current_iterator_.env() != NULL && current_iterator_.Done()) { 605 current_iterator_ = ShallowIterator(current_iterator_.env()->outer()); 606 } 607 } 608 609 ShallowIterator current_iterator_; 610 }; 611 612 613 class LPlatformChunk; 614 class LGap; 615 class LLabel; 616 617 // 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 void AddInstruction(LInstruction* instruction, HBasicBlock* block); 624 LConstantOperand* DefineConstantOperand(HConstant* constant); 625 HConstant* LookupConstant(LConstantOperand* operand) const; 626 Representation LookupLiteralRepresentation(LConstantOperand* operand) const; 627 628 int ParameterAt(int index); 629 int GetParameterStackSlot(int index) const; 630 int spill_slot_count() const { return spill_slot_count_; } 631 CompilationInfo* info() const { return info_; } 632 HGraph* graph() const { return graph_; } 633 Isolate* isolate() const { return graph_->isolate(); } 634 const ZoneList<LInstruction*>* instructions() const { return &instructions_; } 635 void AddGapMove(int index, LOperand* from, LOperand* to); 636 LGap* GetGapAt(int index) const; 637 bool IsGapAt(int index) const; 638 int NearestGapPos(int index) const; 639 void MarkEmptyBlocks(); 640 const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; } 641 LLabel* GetLabel(int block_id) const; 642 int LookupDestination(int block_id) const; 643 Label* GetAssemblyLabel(int block_id) const; 644 645 const ZoneList<Handle<JSFunction> >* inlined_closures() const { 646 return &inlined_closures_; 647 } 648 649 void AddInlinedClosure(Handle<JSFunction> closure) { 650 inlined_closures_.Add(closure, zone()); 651 } 652 653 void AddDeprecationDependency(Handle<Map> map) { 654 ASSERT(!map->is_deprecated()); 655 if (!map->CanBeDeprecated()) return; 656 ASSERT(!info_->IsStub()); 657 deprecation_dependencies_.insert(map); 658 } 659 660 void AddStabilityDependency(Handle<Map> map) { 661 ASSERT(map->is_stable()); 662 if (!map->CanTransition()) return; 663 ASSERT(!info_->IsStub()); 664 stability_dependencies_.insert(map); 665 } 666 667 Zone* zone() const { return info_->zone(); } 668 669 Handle<Code> Codegen(); 670 671 void set_allocated_double_registers(BitVector* allocated_registers); 672 BitVector* allocated_double_registers() { 673 return allocated_double_registers_; 674 } 675 676 protected: 677 LChunk(CompilationInfo* info, HGraph* graph); 678 679 int spill_slot_count_; 680 681 private: 682 typedef std::less<Handle<Map> > MapLess; 683 typedef zone_allocator<Handle<Map> > MapAllocator; 684 typedef std::set<Handle<Map>, MapLess, MapAllocator> MapSet; 685 686 void CommitDependencies(Handle<Code> code) const; 687 688 CompilationInfo* info_; 689 HGraph* const graph_; 690 BitVector* allocated_double_registers_; 691 ZoneList<LInstruction*> instructions_; 692 ZoneList<LPointerMap*> pointer_maps_; 693 ZoneList<Handle<JSFunction> > inlined_closures_; 694 MapSet deprecation_dependencies_; 695 MapSet stability_dependencies_; 696 }; 697 698 699 class LChunkBuilderBase BASE_EMBEDDED { 700 public: 701 explicit LChunkBuilderBase(Zone* zone) 702 : argument_count_(0), 703 zone_(zone) { } 704 705 virtual ~LChunkBuilderBase() { } 706 707 protected: 708 // An input operand in register, stack slot or a constant operand. 709 // Will not be moved to a register even if one is freely available. 710 virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0; 711 712 LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, 713 int* argument_index_accumulator, 714 ZoneList<HValue*>* objects_to_materialize); 715 void AddObjectToMaterialize(HValue* value, 716 ZoneList<HValue*>* objects_to_materialize, 717 LEnvironment* result); 718 719 Zone* zone() const { return zone_; } 720 721 int argument_count_; 722 723 private: 724 Zone* zone_; 725 }; 726 727 728 int StackSlotOffset(int index); 729 730 enum NumberUntagDMode { 731 NUMBER_CANDIDATE_IS_SMI, 732 NUMBER_CANDIDATE_IS_ANY_TAGGED 733 }; 734 735 736 class LPhase : public CompilationPhase { 737 public: 738 LPhase(const char* name, LChunk* chunk) 739 : CompilationPhase(name, chunk->info()), 740 chunk_(chunk) { } 741 ~LPhase(); 742 743 private: 744 LChunk* chunk_; 745 746 DISALLOW_COPY_AND_ASSIGN(LPhase); 747 }; 748 749 750 } } // namespace v8::internal 751 752 #endif // V8_LITHIUM_H_ 753