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_CRANKSHAFT_LITHIUM_H_ 6 #define V8_CRANKSHAFT_LITHIUM_H_ 7 8 #include <set> 9 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 #include "src/safepoint-table.h" 15 #include "src/zone/zone-allocator.h" 16 17 namespace v8 { 18 namespace internal { 19 20 #define LITHIUM_OPERAND_LIST(V) \ 21 V(ConstantOperand, CONSTANT_OPERAND, 128) \ 22 V(StackSlot, STACK_SLOT, 128) \ 23 V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \ 24 V(Register, REGISTER, 16) \ 25 V(DoubleRegister, DOUBLE_REGISTER, 16) 26 27 class LOperand : public ZoneObject { 28 public: 29 enum Kind { 30 INVALID, 31 UNALLOCATED, 32 CONSTANT_OPERAND, 33 STACK_SLOT, 34 DOUBLE_STACK_SLOT, 35 REGISTER, 36 DOUBLE_REGISTER 37 }; 38 39 LOperand() : value_(KindField::encode(INVALID)) { } 40 41 Kind kind() const { return KindField::decode(value_); } 42 int index() const { return static_cast<int>(value_) >> kKindFieldWidth; } 43 #define LITHIUM_OPERAND_PREDICATE(name, type, number) \ 44 bool Is##name() const { return kind() == type; } 45 LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_PREDICATE) 46 LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0) 47 LITHIUM_OPERAND_PREDICATE(Ignored, INVALID, 0) 48 #undef LITHIUM_OPERAND_PREDICATE 49 bool Equals(LOperand* other) const { return value_ == other->value_; } 50 51 void PrintTo(StringStream* stream); 52 void ConvertTo(Kind kind, int index) { 53 if (kind == REGISTER) DCHECK(index >= 0); 54 value_ = KindField::encode(kind); 55 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 protected: 64 static const int kKindFieldWidth = 3; 65 class KindField : public BitField<Kind, 0, kKindFieldWidth> { }; 66 67 LOperand(Kind kind, int index) { ConvertTo(kind, index); } 68 69 unsigned value_; 70 }; 71 72 73 class LUnallocated : public LOperand { 74 public: 75 enum BasicPolicy { 76 FIXED_SLOT, 77 EXTENDED_POLICY 78 }; 79 80 enum ExtendedPolicy { 81 NONE, 82 ANY, 83 FIXED_REGISTER, 84 FIXED_DOUBLE_REGISTER, 85 MUST_HAVE_REGISTER, 86 MUST_HAVE_DOUBLE_REGISTER, 87 WRITABLE_REGISTER, 88 SAME_AS_FIRST_INPUT 89 }; 90 91 // Lifetime of operand inside the instruction. 92 enum Lifetime { 93 // USED_AT_START operand is guaranteed to be live only at 94 // instruction start. Register allocator is free to assign the same register 95 // to some other operand used inside instruction (i.e. temporary or 96 // output). 97 USED_AT_START, 98 99 // USED_AT_END operand is treated as live until the end of 100 // instruction. This means that register allocator will not reuse it's 101 // register for any other operand inside instruction. 102 USED_AT_END 103 }; 104 105 explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) { 106 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 107 value_ |= ExtendedPolicyField::encode(policy); 108 value_ |= LifetimeField::encode(USED_AT_END); 109 } 110 111 LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) { 112 DCHECK(policy == FIXED_SLOT); 113 value_ |= BasicPolicyField::encode(policy); 114 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 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 121 value_ |= ExtendedPolicyField::encode(policy); 122 value_ |= LifetimeField::encode(USED_AT_END); 123 value_ |= FixedRegisterField::encode(index); 124 } 125 126 LUnallocated(ExtendedPolicy policy, Lifetime lifetime) 127 : LOperand(UNALLOCATED, 0) { 128 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 129 value_ |= ExtendedPolicyField::encode(policy); 130 value_ |= LifetimeField::encode(lifetime); 131 } 132 133 LUnallocated* CopyUnconstrained(Zone* zone) { 134 LUnallocated* result = new(zone) LUnallocated(ANY); 135 result->set_virtual_register(virtual_register()); 136 return result; 137 } 138 139 static LUnallocated* cast(LOperand* op) { 140 DCHECK(op->IsUnallocated()); 141 return reinterpret_cast<LUnallocated*>(op); 142 } 143 144 // The encoding used for LUnallocated operands depends on the policy that is 145 // stored within the operand. The FIXED_SLOT policy uses a compact encoding 146 // because it accommodates a larger pay-load. 147 // 148 // For FIXED_SLOT policy: 149 // +------------------------------------------+ 150 // | slot_index | vreg | 0 | 001 | 151 // +------------------------------------------+ 152 // 153 // For all other (extended) policies: 154 // +------------------------------------------+ 155 // | reg_index | L | PPP | vreg | 1 | 001 | L ... Lifetime 156 // +------------------------------------------+ P ... Policy 157 // 158 // The slot index is a signed value which requires us to decode it manually 159 // instead of using the BitField utility class. 160 161 // The superclass has a KindField. 162 STATIC_ASSERT(kKindFieldWidth == 3); 163 164 // BitFields for all unallocated operands. 165 class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {}; 166 class VirtualRegisterField : public BitField<unsigned, 4, 18> {}; 167 168 // BitFields specific to BasicPolicy::FIXED_SLOT. 169 class FixedSlotIndexField : public BitField<int, 22, 10> {}; 170 171 // BitFields specific to BasicPolicy::EXTENDED_POLICY. 172 class ExtendedPolicyField : public BitField<ExtendedPolicy, 22, 3> {}; 173 class LifetimeField : public BitField<Lifetime, 25, 1> {}; 174 class FixedRegisterField : public BitField<int, 26, 6> {}; 175 176 static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1; 177 static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize; 178 static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1; 179 static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1)); 180 181 // Predicates for the operand policy. 182 bool HasAnyPolicy() const { 183 return basic_policy() == EXTENDED_POLICY && 184 extended_policy() == ANY; 185 } 186 bool HasFixedPolicy() const { 187 return basic_policy() == FIXED_SLOT || 188 extended_policy() == FIXED_REGISTER || 189 extended_policy() == FIXED_DOUBLE_REGISTER; 190 } 191 bool HasRegisterPolicy() const { 192 return basic_policy() == EXTENDED_POLICY && ( 193 extended_policy() == WRITABLE_REGISTER || 194 extended_policy() == MUST_HAVE_REGISTER); 195 } 196 bool HasDoubleRegisterPolicy() const { 197 return basic_policy() == EXTENDED_POLICY && 198 extended_policy() == MUST_HAVE_DOUBLE_REGISTER; 199 } 200 bool HasSameAsInputPolicy() const { 201 return basic_policy() == EXTENDED_POLICY && 202 extended_policy() == SAME_AS_FIRST_INPUT; 203 } 204 bool HasFixedSlotPolicy() const { 205 return basic_policy() == FIXED_SLOT; 206 } 207 bool HasFixedRegisterPolicy() const { 208 return basic_policy() == EXTENDED_POLICY && 209 extended_policy() == FIXED_REGISTER; 210 } 211 bool HasFixedDoubleRegisterPolicy() const { 212 return basic_policy() == EXTENDED_POLICY && 213 extended_policy() == FIXED_DOUBLE_REGISTER; 214 } 215 bool HasWritableRegisterPolicy() const { 216 return basic_policy() == EXTENDED_POLICY && 217 extended_policy() == WRITABLE_REGISTER; 218 } 219 220 // [basic_policy]: Distinguish between FIXED_SLOT and all other policies. 221 BasicPolicy basic_policy() const { 222 return BasicPolicyField::decode(value_); 223 } 224 225 // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy. 226 ExtendedPolicy extended_policy() const { 227 DCHECK(basic_policy() == EXTENDED_POLICY); 228 return ExtendedPolicyField::decode(value_); 229 } 230 231 // [fixed_slot_index]: Only for FIXED_SLOT. 232 int fixed_slot_index() const { 233 DCHECK(HasFixedSlotPolicy()); 234 return static_cast<int>(value_) >> FixedSlotIndexField::kShift; 235 } 236 237 // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER. 238 int fixed_register_index() const { 239 DCHECK(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy()); 240 return FixedRegisterField::decode(value_); 241 } 242 243 // [virtual_register]: The virtual register ID for this operand. 244 int virtual_register() const { 245 return VirtualRegisterField::decode(value_); 246 } 247 void set_virtual_register(unsigned id) { 248 value_ = VirtualRegisterField::update(value_, id); 249 } 250 251 // [lifetime]: Only for non-FIXED_SLOT. 252 bool IsUsedAtStart() { 253 DCHECK(basic_policy() == EXTENDED_POLICY); 254 return LifetimeField::decode(value_) == USED_AT_START; 255 } 256 257 static bool TooManyParameters(int num_parameters) { 258 const int parameter_limit = -LUnallocated::kMinFixedSlotIndex; 259 return num_parameters + 1 > parameter_limit; 260 } 261 262 static bool TooManyParametersOrStackSlots(int num_parameters, 263 int num_stack_slots) { 264 const int locals_limit = LUnallocated::kMaxFixedSlotIndex; 265 return num_parameters + 1 + num_stack_slots > locals_limit; 266 } 267 }; 268 269 270 class LMoveOperands final BASE_EMBEDDED { 271 public: 272 LMoveOperands(LOperand* source, LOperand* destination) 273 : source_(source), destination_(destination) { 274 } 275 276 LOperand* source() const { return source_; } 277 void set_source(LOperand* operand) { source_ = operand; } 278 279 LOperand* destination() const { return destination_; } 280 void set_destination(LOperand* operand) { destination_ = operand; } 281 282 // The gap resolver marks moves as "in-progress" by clearing the 283 // destination (but not the source). 284 bool IsPending() const { 285 return destination_ == NULL && source_ != NULL; 286 } 287 288 // True if this move a move into the given destination operand. 289 bool Blocks(LOperand* operand) const { 290 return !IsEliminated() && source()->Equals(operand); 291 } 292 293 // 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 return IsEliminated() || source_->Equals(destination_) || IsIgnored() || 297 (destination_ != NULL && destination_->IsConstantOperand()); 298 } 299 300 bool IsIgnored() const { 301 return destination_ != NULL && destination_->IsIgnored(); 302 } 303 304 // We clear both operands to indicate move that's been eliminated. 305 void Eliminate() { source_ = destination_ = NULL; } 306 bool IsEliminated() const { 307 DCHECK(source_ != NULL || destination_ == NULL); 308 return source_ == NULL; 309 } 310 311 private: 312 LOperand* source_; 313 LOperand* destination_; 314 }; 315 316 317 template <LOperand::Kind kOperandKind, int kNumCachedOperands> 318 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 LSubKindOperand() : LOperand() { } 338 explicit LSubKindOperand(int index) : LOperand(kOperandKind, index) { } 339 }; 340 341 342 #define LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number) \ 343 typedef LSubKindOperand<LOperand::type, number> L##name; 344 LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS) 345 #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 void AddMove(LOperand* from, LOperand* to, Zone* zone) { 353 move_operands_.Add(LMoveOperands(from, to), zone); 354 } 355 356 bool IsRedundant() const; 357 358 ZoneList<LMoveOperands>* move_operands() { return &move_operands_; } 359 360 void PrintDataTo(StringStream* stream) const; 361 362 private: 363 ZoneList<LMoveOperands> move_operands_; 364 }; 365 366 367 class LPointerMap final : public ZoneObject { 368 public: 369 explicit LPointerMap(Zone* zone) 370 : pointer_operands_(8, zone), 371 untagged_operands_(0, zone), 372 lithium_position_(-1) { } 373 374 const ZoneList<LOperand*>* GetNormalizedOperands() { 375 for (int i = 0; i < untagged_operands_.length(); ++i) { 376 RemovePointer(untagged_operands_[i]); 377 } 378 untagged_operands_.Clear(); 379 return &pointer_operands_; 380 } 381 int lithium_position() const { return lithium_position_; } 382 383 void set_lithium_position(int pos) { 384 DCHECK(lithium_position_ == -1); 385 lithium_position_ = pos; 386 } 387 388 void RecordPointer(LOperand* op, Zone* zone); 389 void RemovePointer(LOperand* op); 390 void RecordUntagged(LOperand* op, Zone* zone); 391 void PrintTo(StringStream* stream); 392 393 private: 394 ZoneList<LOperand*> pointer_operands_; 395 ZoneList<LOperand*> untagged_operands_; 396 int lithium_position_; 397 }; 398 399 400 class LEnvironment final : public ZoneObject { 401 public: 402 LEnvironment(Handle<JSFunction> closure, 403 FrameType frame_type, 404 BailoutId ast_id, 405 int parameter_count, 406 int argument_count, 407 int value_count, 408 LEnvironment* outer, 409 HEnterInlined* entry, 410 Zone* zone) 411 : closure_(closure), 412 frame_type_(frame_type), 413 arguments_stack_height_(argument_count), 414 deoptimization_index_(Safepoint::kNoDeoptimizationIndex), 415 translation_index_(-1), 416 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 zone_(zone), 427 has_been_used_(false) { } 428 429 Handle<JSFunction> closure() const { return closure_; } 430 FrameType frame_type() const { return frame_type_; } 431 int arguments_stack_height() const { return arguments_stack_height_; } 432 int deoptimization_index() const { return deoptimization_index_; } 433 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 const ZoneList<LOperand*>* values() const { return &values_; } 439 LEnvironment* outer() const { return outer_; } 440 HEnterInlined* entry() { return entry_; } 441 Zone* zone() const { return zone_; } 442 443 bool has_been_used() const { return has_been_used_; } 444 void set_has_been_used() { has_been_used_ = true; } 445 446 void AddValue(LOperand* operand, 447 Representation representation, 448 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 bool HasUint32ValueAt(int index) const { 465 return is_uint32_.Contains(index); 466 } 467 468 void AddNewObject(int length, bool is_arguments) { 469 uint32_t encoded = LengthOrDupeField::encode(length) | 470 IsArgumentsField::encode(is_arguments) | 471 IsDuplicateField::encode(false); 472 object_mapping_.Add(encoded, zone()); 473 } 474 475 void AddDuplicateObject(int dupe_of) { 476 uint32_t encoded = LengthOrDupeField::encode(dupe_of) | 477 IsDuplicateField::encode(true); 478 object_mapping_.Add(encoded, zone()); 479 } 480 481 int ObjectDuplicateOfAt(int index) { 482 DCHECK(ObjectIsDuplicateAt(index)); 483 return LengthOrDupeField::decode(object_mapping_[index]); 484 } 485 486 int ObjectLengthAt(int index) { 487 DCHECK(!ObjectIsDuplicateAt(index)); 488 return LengthOrDupeField::decode(object_mapping_[index]); 489 } 490 491 bool ObjectIsArgumentsAt(int index) { 492 DCHECK(!ObjectIsDuplicateAt(index)); 493 return IsArgumentsField::decode(object_mapping_[index]); 494 } 495 496 bool ObjectIsDuplicateAt(int index) { 497 return IsDuplicateField::decode(object_mapping_[index]); 498 } 499 500 void Register(int deoptimization_index, 501 int translation_index, 502 int pc_offset) { 503 DCHECK(!HasBeenRegistered()); 504 deoptimization_index_ = deoptimization_index; 505 translation_index_ = translation_index; 506 pc_offset_ = pc_offset; 507 } 508 bool HasBeenRegistered() const { 509 return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex; 510 } 511 512 void PrintTo(StringStream* stream); 513 514 // Marker value indicating a de-materialized object. 515 static LOperand* materialization_marker() { return NULL; } 516 517 // Encoding used for the object_mapping map below. 518 class LengthOrDupeField : public BitField<int, 0, 30> { }; 519 class IsArgumentsField : public BitField<bool, 30, 1> { }; 520 class IsDuplicateField : public BitField<bool, 31, 1> { }; 521 522 private: 523 Handle<JSFunction> closure_; 524 FrameType frame_type_; 525 int arguments_stack_height_; 526 int deoptimization_index_; 527 int translation_index_; 528 BailoutId ast_id_; 529 int translation_size_; 530 int parameter_count_; 531 int pc_offset_; 532 533 // Value array: [parameters] [locals] [expression stack] [de-materialized]. 534 // |>--------- translation_size ---------<| 535 ZoneList<LOperand*> values_; 536 GrowableBitVector is_tagged_; 537 GrowableBitVector is_uint32_; 538 539 // Map with encoded information about materialization_marker operands. 540 ZoneList<uint32_t> object_mapping_; 541 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 public: 552 explicit ShallowIterator(LEnvironment* env) 553 : env_(env), 554 limit_(env != NULL ? env->values()->length() : 0), 555 current_(0) { 556 SkipUninteresting(); 557 } 558 559 bool Done() { return current_ >= limit_; } 560 561 LOperand* Current() { 562 DCHECK(!Done()); 563 DCHECK(env_->values()->at(current_) != NULL); 564 return env_->values()->at(current_); 565 } 566 567 void Advance() { 568 DCHECK(!Done()); 569 ++current_; 570 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 // Skip until something interesting, beginning with and including current_. 581 void SkipUninteresting() { 582 while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) { 583 ++current_; 584 } 585 } 586 587 LEnvironment* env_; 588 int limit_; 589 int current_; 590 }; 591 592 593 // Iterator for non-null, non-constant operands incl. outer environments. 594 class DeepIterator final BASE_EMBEDDED { 595 public: 596 explicit DeepIterator(LEnvironment* env) 597 : current_iterator_(env) { 598 SkipUninteresting(); 599 } 600 601 bool Done() { return current_iterator_.Done(); } 602 603 LOperand* Current() { 604 DCHECK(!current_iterator_.Done()); 605 DCHECK(current_iterator_.Current() != NULL); 606 return current_iterator_.Current(); 607 } 608 609 void Advance() { 610 current_iterator_.Advance(); 611 SkipUninteresting(); 612 } 613 614 private: 615 void SkipUninteresting() { 616 while (current_iterator_.env() != NULL && current_iterator_.Done()) { 617 current_iterator_ = ShallowIterator(current_iterator_.env()->outer()); 618 } 619 } 620 621 ShallowIterator current_iterator_; 622 }; 623 624 625 class LPlatformChunk; 626 class LGap; 627 class LLabel; 628 629 // 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 void AddInstruction(LInstruction* instruction, HBasicBlock* block); 636 LConstantOperand* DefineConstantOperand(HConstant* constant); 637 HConstant* LookupConstant(LConstantOperand* operand) const; 638 Representation LookupLiteralRepresentation(LConstantOperand* operand) const; 639 640 int ParameterAt(int index); 641 int GetParameterStackSlot(int index) const; 642 bool HasAllocatedStackSlots() const { 643 return current_frame_slots_ != base_frame_slots_; 644 } 645 int GetSpillSlotCount() const { 646 return current_frame_slots_ - base_frame_slots_; 647 } 648 int GetTotalFrameSlotCount() const { return current_frame_slots_; } 649 CompilationInfo* info() const { return info_; } 650 HGraph* graph() const { return graph_; } 651 Isolate* isolate() const { return graph_->isolate(); } 652 const ZoneList<LInstruction*>* instructions() const { return &instructions_; } 653 void AddGapMove(int index, LOperand* from, LOperand* to); 654 LGap* GetGapAt(int index) const; 655 bool IsGapAt(int index) const; 656 int NearestGapPos(int index) const; 657 void MarkEmptyBlocks(); 658 const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; } 659 LLabel* GetLabel(int block_id) const; 660 int LookupDestination(int block_id) const; 661 Label* GetAssemblyLabel(int block_id) const; 662 663 void AddDeprecationDependency(Handle<Map> map) { 664 DCHECK(!map->is_deprecated()); 665 if (!map->CanBeDeprecated()) return; 666 DCHECK(!info_->IsStub()); 667 deprecation_dependencies_.Add(map, zone()); 668 } 669 670 void AddStabilityDependency(Handle<Map> map) { 671 DCHECK(map->is_stable()); 672 if (!map->CanTransition()) return; 673 DCHECK(!info_->IsStub()); 674 stability_dependencies_.Add(map, zone()); 675 } 676 677 Zone* zone() const { return info_->zone(); } 678 679 Handle<Code> Codegen(); 680 681 void set_allocated_double_registers(BitVector* allocated_registers); 682 BitVector* allocated_double_registers() { 683 return allocated_double_registers_; 684 } 685 686 protected: 687 LChunk(CompilationInfo* info, HGraph* graph); 688 689 int base_frame_slots_; 690 int current_frame_slots_; 691 692 private: 693 void CommitDependencies(Handle<Code> code) const; 694 695 CompilationInfo* info_; 696 HGraph* const graph_; 697 BitVector* allocated_double_registers_; 698 ZoneList<LInstruction*> instructions_; 699 ZoneList<LPointerMap*> pointer_maps_; 700 ZoneList<Handle<Map>> deprecation_dependencies_; 701 ZoneList<Handle<Map>> stability_dependencies_; 702 }; 703 704 705 class LChunkBuilderBase BASE_EMBEDDED { 706 public: 707 explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph) 708 : argument_count_(0), 709 chunk_(NULL), 710 info_(info), 711 graph_(graph), 712 status_(UNUSED), 713 zone_(graph->zone()) {} 714 715 virtual ~LChunkBuilderBase() { } 716 717 void Abort(BailoutReason reason); 718 void Retry(BailoutReason reason); 719 720 protected: 721 enum Status { UNUSED, BUILDING, DONE, ABORTED }; 722 723 LPlatformChunk* chunk() const { return chunk_; } 724 CompilationInfo* info() const { return info_; } 725 HGraph* graph() const { return graph_; } 726 int argument_count() const { return argument_count_; } 727 Isolate* isolate() const { return graph_->isolate(); } 728 Heap* heap() const { return isolate()->heap(); } 729 730 bool is_unused() const { return status_ == UNUSED; } 731 bool is_building() const { return status_ == BUILDING; } 732 bool is_done() const { return status_ == DONE; } 733 bool is_aborted() const { return status_ == ABORTED; } 734 735 // An input operand in register, stack slot or a constant operand. 736 // Will not be moved to a register even if one is freely available. 737 virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0; 738 739 // Constructs proper environment for a lazy bailout point after call, creates 740 // LLazyBailout instruction and adds it to current block. 741 void CreateLazyBailoutForCall(HBasicBlock* current_block, LInstruction* instr, 742 HInstruction* hydrogen_val); 743 744 // Assigns given environment to an instruction. An instruction which can 745 // deoptimize must have an environment. 746 LInstruction* AssignEnvironment(LInstruction* instr, 747 HEnvironment* hydrogen_env); 748 749 LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, 750 int* argument_index_accumulator, 751 ZoneList<HValue*>* objects_to_materialize); 752 void AddObjectToMaterialize(HValue* value, 753 ZoneList<HValue*>* objects_to_materialize, 754 LEnvironment* result); 755 756 Zone* zone() const { return zone_; } 757 758 int argument_count_; 759 LPlatformChunk* chunk_; 760 CompilationInfo* info_; 761 HGraph* const graph_; 762 Status status_; 763 764 private: 765 Zone* zone_; 766 }; 767 768 769 enum NumberUntagDMode { 770 NUMBER_CANDIDATE_IS_SMI, 771 NUMBER_CANDIDATE_IS_ANY_TAGGED 772 }; 773 774 775 class LPhase : public CompilationPhase { 776 public: 777 LPhase(const char* name, LChunk* chunk) 778 : CompilationPhase(name, chunk->info()), 779 chunk_(chunk) { } 780 ~LPhase(); 781 782 private: 783 LChunk* chunk_; 784 785 DISALLOW_COPY_AND_ASSIGN(LPhase); 786 }; 787 788 789 // A register-allocator view of a Lithium instruction. It contains the id of 790 // the output operand and a list of input operand uses. 791 792 enum RegisterKind { 793 UNALLOCATED_REGISTERS, 794 GENERAL_REGISTERS, 795 DOUBLE_REGISTERS 796 }; 797 798 // Iterator for non-null temp operands. 799 class TempIterator BASE_EMBEDDED { 800 public: 801 inline explicit TempIterator(LInstruction* instr); 802 inline bool Done(); 803 inline LOperand* Current(); 804 inline void Advance(); 805 806 private: 807 inline void SkipUninteresting(); 808 LInstruction* instr_; 809 int limit_; 810 int current_; 811 }; 812 813 814 // Iterator for non-constant input operands. 815 class InputIterator BASE_EMBEDDED { 816 public: 817 inline explicit InputIterator(LInstruction* instr); 818 inline bool Done(); 819 inline LOperand* Current(); 820 inline void Advance(); 821 822 private: 823 inline void SkipUninteresting(); 824 LInstruction* instr_; 825 int limit_; 826 int current_; 827 }; 828 829 830 class UseIterator BASE_EMBEDDED { 831 public: 832 inline explicit UseIterator(LInstruction* instr); 833 inline bool Done(); 834 inline LOperand* Current(); 835 inline void Advance(); 836 837 private: 838 InputIterator input_iterator_; 839 DeepIterator env_iterator_; 840 }; 841 842 class LInstruction; 843 class LCodeGen; 844 } // namespace internal 845 } // namespace v8 846 847 #endif // V8_CRANKSHAFT_LITHIUM_H_ 848