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/bailout-reason.h" 12 #include "src/hydrogen.h" 13 #include "src/safepoint-table.h" 14 #include "src/zone-allocator.h" 15 16 namespace v8 { 17 namespace internal { 18 19 #define LITHIUM_OPERAND_LIST(V) \ 20 V(ConstantOperand, CONSTANT_OPERAND, 128) \ 21 V(StackSlot, STACK_SLOT, 128) \ 22 V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \ 23 V(Register, REGISTER, 16) \ 24 V(DoubleRegister, DOUBLE_REGISTER, 16) 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 LOperand()38 LOperand() : value_(KindField::encode(INVALID)) { } 39 kind()40 Kind kind() const { return KindField::decode(value_); } index()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 Equals(LOperand * other)48 bool Equals(LOperand* other) const { return value_ == other->value_; } 49 50 void PrintTo(StringStream* stream); ConvertTo(Kind kind,int index)51 void ConvertTo(Kind kind, int index) { 52 if (kind == REGISTER) DCHECK(index >= 0); 53 value_ = KindField::encode(kind); 54 value_ |= index << kKindFieldWidth; 55 DCHECK(this->index() == index); 56 } 57 58 // Calls SetUpCache()/TearDownCache() for each subclass. 59 static void SetUpCaches(); 60 static void TearDownCaches(); 61 62 protected: 63 static const int kKindFieldWidth = 3; 64 class KindField : public BitField<Kind, 0, kKindFieldWidth> { }; 65 LOperand(Kind kind,int index)66 LOperand(Kind kind, int index) { ConvertTo(kind, index); } 67 68 unsigned value_; 69 }; 70 71 72 class LUnallocated : public LOperand { 73 public: 74 enum BasicPolicy { 75 FIXED_SLOT, 76 EXTENDED_POLICY 77 }; 78 79 enum ExtendedPolicy { 80 NONE, 81 ANY, 82 FIXED_REGISTER, 83 FIXED_DOUBLE_REGISTER, 84 MUST_HAVE_REGISTER, 85 MUST_HAVE_DOUBLE_REGISTER, 86 WRITABLE_REGISTER, 87 SAME_AS_FIRST_INPUT 88 }; 89 90 // Lifetime of operand inside the instruction. 91 enum Lifetime { 92 // USED_AT_START operand is guaranteed to be live only at 93 // instruction start. Register allocator is free to assign the same register 94 // to some other operand used inside instruction (i.e. temporary or 95 // output). 96 USED_AT_START, 97 98 // USED_AT_END operand is treated as live until the end of 99 // instruction. This means that register allocator will not reuse it's 100 // register for any other operand inside instruction. 101 USED_AT_END 102 }; 103 LUnallocated(ExtendedPolicy policy)104 explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) { 105 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 106 value_ |= ExtendedPolicyField::encode(policy); 107 value_ |= LifetimeField::encode(USED_AT_END); 108 } 109 LUnallocated(BasicPolicy policy,int index)110 LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) { 111 DCHECK(policy == FIXED_SLOT); 112 value_ |= BasicPolicyField::encode(policy); 113 value_ |= index << FixedSlotIndexField::kShift; 114 DCHECK(this->fixed_slot_index() == index); 115 } 116 LUnallocated(ExtendedPolicy policy,int index)117 LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) { 118 DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER); 119 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 120 value_ |= ExtendedPolicyField::encode(policy); 121 value_ |= LifetimeField::encode(USED_AT_END); 122 value_ |= FixedRegisterField::encode(index); 123 } 124 LUnallocated(ExtendedPolicy policy,Lifetime lifetime)125 LUnallocated(ExtendedPolicy policy, Lifetime lifetime) 126 : LOperand(UNALLOCATED, 0) { 127 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); 128 value_ |= ExtendedPolicyField::encode(policy); 129 value_ |= LifetimeField::encode(lifetime); 130 } 131 CopyUnconstrained(Zone * zone)132 LUnallocated* CopyUnconstrained(Zone* zone) { 133 LUnallocated* result = new(zone) LUnallocated(ANY); 134 result->set_virtual_register(virtual_register()); 135 return result; 136 } 137 cast(LOperand * op)138 static LUnallocated* cast(LOperand* op) { 139 DCHECK(op->IsUnallocated()); 140 return reinterpret_cast<LUnallocated*>(op); 141 } 142 143 // The encoding used for LUnallocated operands depends on the policy that is 144 // stored within the operand. The FIXED_SLOT policy uses a compact encoding 145 // because it accommodates a larger pay-load. 146 // 147 // For FIXED_SLOT policy: 148 // +------------------------------------------+ 149 // | slot_index | vreg | 0 | 001 | 150 // +------------------------------------------+ 151 // 152 // For all other (extended) policies: 153 // +------------------------------------------+ 154 // | reg_index | L | PPP | vreg | 1 | 001 | L ... Lifetime 155 // +------------------------------------------+ P ... Policy 156 // 157 // The slot index is a signed value which requires us to decode it manually 158 // instead of using the BitField utility class. 159 160 // The superclass has a KindField. 161 STATIC_ASSERT(kKindFieldWidth == 3); 162 163 // BitFields for all unallocated operands. 164 class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {}; 165 class VirtualRegisterField : public BitField<unsigned, 4, 18> {}; 166 167 // BitFields specific to BasicPolicy::FIXED_SLOT. 168 class FixedSlotIndexField : public BitField<int, 22, 10> {}; 169 170 // BitFields specific to BasicPolicy::EXTENDED_POLICY. 171 class ExtendedPolicyField : public BitField<ExtendedPolicy, 22, 3> {}; 172 class LifetimeField : public BitField<Lifetime, 25, 1> {}; 173 class FixedRegisterField : public BitField<int, 26, 6> {}; 174 175 static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1; 176 static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize; 177 static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1; 178 static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1)); 179 180 // Predicates for the operand policy. HasAnyPolicy()181 bool HasAnyPolicy() const { 182 return basic_policy() == EXTENDED_POLICY && 183 extended_policy() == ANY; 184 } HasFixedPolicy()185 bool HasFixedPolicy() const { 186 return basic_policy() == FIXED_SLOT || 187 extended_policy() == FIXED_REGISTER || 188 extended_policy() == FIXED_DOUBLE_REGISTER; 189 } HasRegisterPolicy()190 bool HasRegisterPolicy() const { 191 return basic_policy() == EXTENDED_POLICY && ( 192 extended_policy() == WRITABLE_REGISTER || 193 extended_policy() == MUST_HAVE_REGISTER); 194 } HasDoubleRegisterPolicy()195 bool HasDoubleRegisterPolicy() const { 196 return basic_policy() == EXTENDED_POLICY && 197 extended_policy() == MUST_HAVE_DOUBLE_REGISTER; 198 } HasSameAsInputPolicy()199 bool HasSameAsInputPolicy() const { 200 return basic_policy() == EXTENDED_POLICY && 201 extended_policy() == SAME_AS_FIRST_INPUT; 202 } HasFixedSlotPolicy()203 bool HasFixedSlotPolicy() const { 204 return basic_policy() == FIXED_SLOT; 205 } HasFixedRegisterPolicy()206 bool HasFixedRegisterPolicy() const { 207 return basic_policy() == EXTENDED_POLICY && 208 extended_policy() == FIXED_REGISTER; 209 } HasFixedDoubleRegisterPolicy()210 bool HasFixedDoubleRegisterPolicy() const { 211 return basic_policy() == EXTENDED_POLICY && 212 extended_policy() == FIXED_DOUBLE_REGISTER; 213 } HasWritableRegisterPolicy()214 bool HasWritableRegisterPolicy() const { 215 return basic_policy() == EXTENDED_POLICY && 216 extended_policy() == WRITABLE_REGISTER; 217 } 218 219 // [basic_policy]: Distinguish between FIXED_SLOT and all other policies. basic_policy()220 BasicPolicy basic_policy() const { 221 return BasicPolicyField::decode(value_); 222 } 223 224 // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy. extended_policy()225 ExtendedPolicy extended_policy() const { 226 DCHECK(basic_policy() == EXTENDED_POLICY); 227 return ExtendedPolicyField::decode(value_); 228 } 229 230 // [fixed_slot_index]: Only for FIXED_SLOT. fixed_slot_index()231 int fixed_slot_index() const { 232 DCHECK(HasFixedSlotPolicy()); 233 return static_cast<int>(value_) >> FixedSlotIndexField::kShift; 234 } 235 236 // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER. fixed_register_index()237 int fixed_register_index() const { 238 DCHECK(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy()); 239 return FixedRegisterField::decode(value_); 240 } 241 242 // [virtual_register]: The virtual register ID for this operand. virtual_register()243 int virtual_register() const { 244 return VirtualRegisterField::decode(value_); 245 } set_virtual_register(unsigned id)246 void set_virtual_register(unsigned id) { 247 value_ = VirtualRegisterField::update(value_, id); 248 } 249 250 // [lifetime]: Only for non-FIXED_SLOT. IsUsedAtStart()251 bool IsUsedAtStart() { 252 DCHECK(basic_policy() == EXTENDED_POLICY); 253 return LifetimeField::decode(value_) == USED_AT_START; 254 } 255 }; 256 257 258 class LMoveOperands FINAL BASE_EMBEDDED { 259 public: LMoveOperands(LOperand * source,LOperand * destination)260 LMoveOperands(LOperand* source, LOperand* destination) 261 : source_(source), destination_(destination) { 262 } 263 source()264 LOperand* source() const { return source_; } set_source(LOperand * operand)265 void set_source(LOperand* operand) { source_ = operand; } 266 destination()267 LOperand* destination() const { return destination_; } set_destination(LOperand * operand)268 void set_destination(LOperand* operand) { destination_ = operand; } 269 270 // The gap resolver marks moves as "in-progress" by clearing the 271 // destination (but not the source). IsPending()272 bool IsPending() const { 273 return destination_ == NULL && source_ != NULL; 274 } 275 276 // True if this move a move into the given destination operand. Blocks(LOperand * operand)277 bool Blocks(LOperand* operand) const { 278 return !IsEliminated() && source()->Equals(operand); 279 } 280 281 // A move is redundant if it's been eliminated, if its source and 282 // destination are the same, or if its destination is unneeded or constant. IsRedundant()283 bool IsRedundant() const { 284 return IsEliminated() || source_->Equals(destination_) || IsIgnored() || 285 (destination_ != NULL && destination_->IsConstantOperand()); 286 } 287 IsIgnored()288 bool IsIgnored() const { 289 return destination_ != NULL && destination_->IsIgnored(); 290 } 291 292 // We clear both operands to indicate move that's been eliminated. Eliminate()293 void Eliminate() { source_ = destination_ = NULL; } IsEliminated()294 bool IsEliminated() const { 295 DCHECK(source_ != NULL || destination_ == NULL); 296 return source_ == NULL; 297 } 298 299 private: 300 LOperand* source_; 301 LOperand* destination_; 302 }; 303 304 305 template<LOperand::Kind kOperandKind, int kNumCachedOperands> 306 class LSubKindOperand FINAL : public LOperand { 307 public: Create(int index,Zone * zone)308 static LSubKindOperand* Create(int index, Zone* zone) { 309 DCHECK(index >= 0); 310 if (index < kNumCachedOperands) return &cache[index]; 311 return new(zone) LSubKindOperand(index); 312 } 313 cast(LOperand * op)314 static LSubKindOperand* cast(LOperand* op) { 315 DCHECK(op->kind() == kOperandKind); 316 return reinterpret_cast<LSubKindOperand*>(op); 317 } 318 319 static void SetUpCache(); 320 static void TearDownCache(); 321 322 private: 323 static LSubKindOperand* cache; 324 LSubKindOperand()325 LSubKindOperand() : LOperand() { } LSubKindOperand(int index)326 explicit LSubKindOperand(int index) : LOperand(kOperandKind, index) { } 327 }; 328 329 330 #define LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number) \ 331 typedef LSubKindOperand<LOperand::type, number> L##name; LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS)332 LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS) 333 #undef LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS 334 335 336 class LParallelMove FINAL : public ZoneObject { 337 public: 338 explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { } 339 340 void AddMove(LOperand* from, LOperand* to, Zone* zone) { 341 move_operands_.Add(LMoveOperands(from, to), zone); 342 } 343 344 bool IsRedundant() const; 345 346 ZoneList<LMoveOperands>* move_operands() { return &move_operands_; } 347 348 void PrintDataTo(StringStream* stream) const; 349 350 private: 351 ZoneList<LMoveOperands> move_operands_; 352 }; 353 354 355 class LPointerMap FINAL : public ZoneObject { 356 public: LPointerMap(Zone * zone)357 explicit LPointerMap(Zone* zone) 358 : pointer_operands_(8, zone), 359 untagged_operands_(0, zone), 360 lithium_position_(-1) { } 361 GetNormalizedOperands()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 } lithium_position()369 int lithium_position() const { return lithium_position_; } 370 set_lithium_position(int pos)371 void set_lithium_position(int pos) { 372 DCHECK(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 FINAL : public ZoneObject { 389 public: LEnvironment(Handle<JSFunction> closure,FrameType frame_type,BailoutId ast_id,int parameter_count,int argument_count,int value_count,LEnvironment * outer,HEnterInlined * entry,Zone * zone)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 closure()417 Handle<JSFunction> closure() const { return closure_; } frame_type()418 FrameType frame_type() const { return frame_type_; } arguments_stack_height()419 int arguments_stack_height() const { return arguments_stack_height_; } deoptimization_index()420 int deoptimization_index() const { return deoptimization_index_; } translation_index()421 int translation_index() const { return translation_index_; } ast_id()422 BailoutId ast_id() const { return ast_id_; } translation_size()423 int translation_size() const { return translation_size_; } parameter_count()424 int parameter_count() const { return parameter_count_; } pc_offset()425 int pc_offset() const { return pc_offset_; } values()426 const ZoneList<LOperand*>* values() const { return &values_; } outer()427 LEnvironment* outer() const { return outer_; } entry()428 HEnterInlined* entry() { return entry_; } zone()429 Zone* zone() const { return zone_; } 430 has_been_used()431 bool has_been_used() const { return has_been_used_; } set_has_been_used()432 void set_has_been_used() { has_been_used_ = true; } 433 AddValue(LOperand * operand,Representation representation,bool is_uint32)434 void AddValue(LOperand* operand, 435 Representation representation, 436 bool is_uint32) { 437 values_.Add(operand, zone()); 438 if (representation.IsSmiOrTagged()) { 439 DCHECK(!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 HasTaggedValueAt(int index)448 bool HasTaggedValueAt(int index) const { 449 return is_tagged_.Contains(index); 450 } 451 HasUint32ValueAt(int index)452 bool HasUint32ValueAt(int index) const { 453 return is_uint32_.Contains(index); 454 } 455 AddNewObject(int length,bool is_arguments)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 AddDuplicateObject(int dupe_of)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 ObjectDuplicateOfAt(int index)469 int ObjectDuplicateOfAt(int index) { 470 DCHECK(ObjectIsDuplicateAt(index)); 471 return LengthOrDupeField::decode(object_mapping_[index]); 472 } 473 ObjectLengthAt(int index)474 int ObjectLengthAt(int index) { 475 DCHECK(!ObjectIsDuplicateAt(index)); 476 return LengthOrDupeField::decode(object_mapping_[index]); 477 } 478 ObjectIsArgumentsAt(int index)479 bool ObjectIsArgumentsAt(int index) { 480 DCHECK(!ObjectIsDuplicateAt(index)); 481 return IsArgumentsField::decode(object_mapping_[index]); 482 } 483 ObjectIsDuplicateAt(int index)484 bool ObjectIsDuplicateAt(int index) { 485 return IsDuplicateField::decode(object_mapping_[index]); 486 } 487 Register(int deoptimization_index,int translation_index,int pc_offset)488 void Register(int deoptimization_index, 489 int translation_index, 490 int pc_offset) { 491 DCHECK(!HasBeenRegistered()); 492 deoptimization_index_ = deoptimization_index; 493 translation_index_ = translation_index; 494 pc_offset_ = pc_offset; 495 } HasBeenRegistered()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. materialization_marker()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 FINAL BASE_EMBEDDED { 539 public: ShallowIterator(LEnvironment * env)540 explicit ShallowIterator(LEnvironment* env) 541 : env_(env), 542 limit_(env != NULL ? env->values()->length() : 0), 543 current_(0) { 544 SkipUninteresting(); 545 } 546 Done()547 bool Done() { return current_ >= limit_; } 548 Current()549 LOperand* Current() { 550 DCHECK(!Done()); 551 DCHECK(env_->values()->at(current_) != NULL); 552 return env_->values()->at(current_); 553 } 554 Advance()555 void Advance() { 556 DCHECK(!Done()); 557 ++current_; 558 SkipUninteresting(); 559 } 560 env()561 LEnvironment* env() { return env_; } 562 563 private: ShouldSkip(LOperand * op)564 bool ShouldSkip(LOperand* op) { 565 return op == NULL || op->IsConstantOperand(); 566 } 567 568 // Skip until something interesting, beginning with and including current_. SkipUninteresting()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 FINAL BASE_EMBEDDED { 583 public: DeepIterator(LEnvironment * env)584 explicit DeepIterator(LEnvironment* env) 585 : current_iterator_(env) { 586 SkipUninteresting(); 587 } 588 Done()589 bool Done() { return current_iterator_.Done(); } 590 Current()591 LOperand* Current() { 592 DCHECK(!current_iterator_.Done()); 593 DCHECK(current_iterator_.Current() != NULL); 594 return current_iterator_.Current(); 595 } 596 Advance()597 void Advance() { 598 current_iterator_.Advance(); 599 SkipUninteresting(); 600 } 601 602 private: SkipUninteresting()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; spill_slot_count()630 int spill_slot_count() const { return spill_slot_count_; } info()631 CompilationInfo* info() const { return info_; } graph()632 HGraph* graph() const { return graph_; } isolate()633 Isolate* isolate() const { return graph_->isolate(); } instructions()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(); pointer_maps()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 inlined_closures()645 const ZoneList<Handle<JSFunction> >* inlined_closures() const { 646 return &inlined_closures_; 647 } 648 AddInlinedClosure(Handle<JSFunction> closure)649 void AddInlinedClosure(Handle<JSFunction> closure) { 650 inlined_closures_.Add(closure, zone()); 651 } 652 AddDeprecationDependency(Handle<Map> map)653 void AddDeprecationDependency(Handle<Map> map) { 654 DCHECK(!map->is_deprecated()); 655 if (!map->CanBeDeprecated()) return; 656 DCHECK(!info_->IsStub()); 657 deprecation_dependencies_.insert(map); 658 } 659 AddStabilityDependency(Handle<Map> map)660 void AddStabilityDependency(Handle<Map> map) { 661 DCHECK(map->is_stable()); 662 if (!map->CanTransition()) return; 663 DCHECK(!info_->IsStub()); 664 stability_dependencies_.insert(map); 665 } 666 zone()667 Zone* zone() const { return info_->zone(); } 668 669 Handle<Code> Codegen(); 670 671 void set_allocated_double_registers(BitVector* allocated_registers); allocated_double_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: LChunkBuilderBase(CompilationInfo * info,HGraph * graph)701 explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph) 702 : argument_count_(0), 703 chunk_(NULL), 704 info_(info), 705 graph_(graph), 706 status_(UNUSED), 707 zone_(graph->zone()) {} 708 ~LChunkBuilderBase()709 virtual ~LChunkBuilderBase() { } 710 711 void Abort(BailoutReason reason); 712 void Retry(BailoutReason reason); 713 714 protected: 715 enum Status { UNUSED, BUILDING, DONE, ABORTED }; 716 chunk()717 LPlatformChunk* chunk() const { return chunk_; } info()718 CompilationInfo* info() const { return info_; } graph()719 HGraph* graph() const { return graph_; } argument_count()720 int argument_count() const { return argument_count_; } isolate()721 Isolate* isolate() const { return graph_->isolate(); } heap()722 Heap* heap() const { return isolate()->heap(); } 723 is_unused()724 bool is_unused() const { return status_ == UNUSED; } is_building()725 bool is_building() const { return status_ == BUILDING; } is_done()726 bool is_done() const { return status_ == DONE; } is_aborted()727 bool is_aborted() const { return status_ == ABORTED; } 728 729 // An input operand in register, stack slot or a constant operand. 730 // Will not be moved to a register even if one is freely available. 731 virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0; 732 733 LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, 734 int* argument_index_accumulator, 735 ZoneList<HValue*>* objects_to_materialize); 736 void AddObjectToMaterialize(HValue* value, 737 ZoneList<HValue*>* objects_to_materialize, 738 LEnvironment* result); 739 zone()740 Zone* zone() const { return zone_; } 741 742 int argument_count_; 743 LPlatformChunk* chunk_; 744 CompilationInfo* info_; 745 HGraph* const graph_; 746 Status status_; 747 748 private: 749 Zone* zone_; 750 }; 751 752 753 int StackSlotOffset(int index); 754 755 enum NumberUntagDMode { 756 NUMBER_CANDIDATE_IS_SMI, 757 NUMBER_CANDIDATE_IS_ANY_TAGGED 758 }; 759 760 761 class LPhase : public CompilationPhase { 762 public: LPhase(const char * name,LChunk * chunk)763 LPhase(const char* name, LChunk* chunk) 764 : CompilationPhase(name, chunk->info()), 765 chunk_(chunk) { } 766 ~LPhase(); 767 768 private: 769 LChunk* chunk_; 770 771 DISALLOW_COPY_AND_ASSIGN(LPhase); 772 }; 773 774 775 // A register-allocator view of a Lithium instruction. It contains the id of 776 // the output operand and a list of input operand uses. 777 778 enum RegisterKind { 779 UNALLOCATED_REGISTERS, 780 GENERAL_REGISTERS, 781 DOUBLE_REGISTERS 782 }; 783 784 // Iterator for non-null temp operands. 785 class TempIterator BASE_EMBEDDED { 786 public: 787 inline explicit TempIterator(LInstruction* instr); 788 inline bool Done(); 789 inline LOperand* Current(); 790 inline void Advance(); 791 792 private: 793 inline void SkipUninteresting(); 794 LInstruction* instr_; 795 int limit_; 796 int current_; 797 }; 798 799 800 // Iterator for non-constant input operands. 801 class InputIterator BASE_EMBEDDED { 802 public: 803 inline explicit InputIterator(LInstruction* instr); 804 inline bool Done(); 805 inline LOperand* Current(); 806 inline void Advance(); 807 808 private: 809 inline void SkipUninteresting(); 810 LInstruction* instr_; 811 int limit_; 812 int current_; 813 }; 814 815 816 class UseIterator BASE_EMBEDDED { 817 public: 818 inline explicit UseIterator(LInstruction* instr); 819 inline bool Done(); 820 inline LOperand* Current(); 821 inline void Advance(); 822 823 private: 824 InputIterator input_iterator_; 825 DeepIterator env_iterator_; 826 }; 827 828 class LInstruction; 829 class LCodeGen; 830 } } // namespace v8::internal 831 832 #endif // V8_LITHIUM_H_ 833