• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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 
TooManyParameters(int num_parameters)256   static bool TooManyParameters(int num_parameters) {
257     const int parameter_limit = -LUnallocated::kMinFixedSlotIndex;
258     return num_parameters + 1 > parameter_limit;
259   }
260 
TooManyParametersOrStackSlots(int num_parameters,int num_stack_slots)261   static bool TooManyParametersOrStackSlots(int num_parameters,
262                                             int num_stack_slots) {
263     const int locals_limit = LUnallocated::kMaxFixedSlotIndex;
264     return num_parameters + 1 + num_stack_slots > locals_limit;
265   }
266 };
267 
268 
269 class LMoveOperands final BASE_EMBEDDED {
270  public:
LMoveOperands(LOperand * source,LOperand * destination)271   LMoveOperands(LOperand* source, LOperand* destination)
272       : source_(source), destination_(destination) {
273   }
274 
source()275   LOperand* source() const { return source_; }
set_source(LOperand * operand)276   void set_source(LOperand* operand) { source_ = operand; }
277 
destination()278   LOperand* destination() const { return destination_; }
set_destination(LOperand * operand)279   void set_destination(LOperand* operand) { destination_ = operand; }
280 
281   // The gap resolver marks moves as "in-progress" by clearing the
282   // destination (but not the source).
IsPending()283   bool IsPending() const {
284     return destination_ == NULL && source_ != NULL;
285   }
286 
287   // True if this move a move into the given destination operand.
Blocks(LOperand * operand)288   bool Blocks(LOperand* operand) const {
289     return !IsEliminated() && source()->Equals(operand);
290   }
291 
292   // A move is redundant if it's been eliminated, if its source and
293   // destination are the same, or if its destination is unneeded or constant.
IsRedundant()294   bool IsRedundant() const {
295     return IsEliminated() || source_->Equals(destination_) || IsIgnored() ||
296            (destination_ != NULL && destination_->IsConstantOperand());
297   }
298 
IsIgnored()299   bool IsIgnored() const {
300     return destination_ != NULL && destination_->IsIgnored();
301   }
302 
303   // We clear both operands to indicate move that's been eliminated.
Eliminate()304   void Eliminate() { source_ = destination_ = NULL; }
IsEliminated()305   bool IsEliminated() const {
306     DCHECK(source_ != NULL || destination_ == NULL);
307     return source_ == NULL;
308   }
309 
310  private:
311   LOperand* source_;
312   LOperand* destination_;
313 };
314 
315 
316 template <LOperand::Kind kOperandKind, int kNumCachedOperands>
317 class LSubKindOperand final : public LOperand {
318  public:
Create(int index,Zone * zone)319   static LSubKindOperand* Create(int index, Zone* zone) {
320     DCHECK(index >= 0);
321     if (index < kNumCachedOperands) return &cache[index];
322     return new(zone) LSubKindOperand(index);
323   }
324 
cast(LOperand * op)325   static LSubKindOperand* cast(LOperand* op) {
326     DCHECK(op->kind() == kOperandKind);
327     return reinterpret_cast<LSubKindOperand*>(op);
328   }
329 
330   static void SetUpCache();
331   static void TearDownCache();
332 
333  private:
334   static LSubKindOperand* cache;
335 
LSubKindOperand()336   LSubKindOperand() : LOperand() { }
LSubKindOperand(int index)337   explicit LSubKindOperand(int index) : LOperand(kOperandKind, index) { }
338 };
339 
340 
341 #define LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number)   \
342 typedef LSubKindOperand<LOperand::type, number> L##name;
LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS)343 LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS)
344 #undef LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS
345 
346 
347 class LParallelMove final : public ZoneObject {
348  public:
349   explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { }
350 
351   void AddMove(LOperand* from, LOperand* to, Zone* zone) {
352     move_operands_.Add(LMoveOperands(from, to), zone);
353   }
354 
355   bool IsRedundant() const;
356 
357   ZoneList<LMoveOperands>* move_operands() { return &move_operands_; }
358 
359   void PrintDataTo(StringStream* stream) const;
360 
361  private:
362   ZoneList<LMoveOperands> move_operands_;
363 };
364 
365 
366 class LPointerMap final : public ZoneObject {
367  public:
LPointerMap(Zone * zone)368   explicit LPointerMap(Zone* zone)
369       : pointer_operands_(8, zone),
370         untagged_operands_(0, zone),
371         lithium_position_(-1) { }
372 
GetNormalizedOperands()373   const ZoneList<LOperand*>* GetNormalizedOperands() {
374     for (int i = 0; i < untagged_operands_.length(); ++i) {
375       RemovePointer(untagged_operands_[i]);
376     }
377     untagged_operands_.Clear();
378     return &pointer_operands_;
379   }
lithium_position()380   int lithium_position() const { return lithium_position_; }
381 
set_lithium_position(int pos)382   void set_lithium_position(int pos) {
383     DCHECK(lithium_position_ == -1);
384     lithium_position_ = pos;
385   }
386 
387   void RecordPointer(LOperand* op, Zone* zone);
388   void RemovePointer(LOperand* op);
389   void RecordUntagged(LOperand* op, Zone* zone);
390   void PrintTo(StringStream* stream);
391 
392  private:
393   ZoneList<LOperand*> pointer_operands_;
394   ZoneList<LOperand*> untagged_operands_;
395   int lithium_position_;
396 };
397 
398 
399 class LEnvironment final : public ZoneObject {
400  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)401   LEnvironment(Handle<JSFunction> closure,
402                FrameType frame_type,
403                BailoutId ast_id,
404                int parameter_count,
405                int argument_count,
406                int value_count,
407                LEnvironment* outer,
408                HEnterInlined* entry,
409                Zone* zone)
410       : closure_(closure),
411         frame_type_(frame_type),
412         arguments_stack_height_(argument_count),
413         deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
414         translation_index_(-1),
415         ast_id_(ast_id),
416         translation_size_(value_count),
417         parameter_count_(parameter_count),
418         pc_offset_(-1),
419         values_(value_count, zone),
420         is_tagged_(value_count, zone),
421         is_uint32_(value_count, zone),
422         object_mapping_(0, zone),
423         outer_(outer),
424         entry_(entry),
425         zone_(zone),
426         has_been_used_(false) { }
427 
closure()428   Handle<JSFunction> closure() const { return closure_; }
frame_type()429   FrameType frame_type() const { return frame_type_; }
arguments_stack_height()430   int arguments_stack_height() const { return arguments_stack_height_; }
deoptimization_index()431   int deoptimization_index() const { return deoptimization_index_; }
translation_index()432   int translation_index() const { return translation_index_; }
ast_id()433   BailoutId ast_id() const { return ast_id_; }
translation_size()434   int translation_size() const { return translation_size_; }
parameter_count()435   int parameter_count() const { return parameter_count_; }
pc_offset()436   int pc_offset() const { return pc_offset_; }
values()437   const ZoneList<LOperand*>* values() const { return &values_; }
outer()438   LEnvironment* outer() const { return outer_; }
entry()439   HEnterInlined* entry() { return entry_; }
zone()440   Zone* zone() const { return zone_; }
441 
has_been_used()442   bool has_been_used() const { return has_been_used_; }
set_has_been_used()443   void set_has_been_used() { has_been_used_ = true; }
444 
AddValue(LOperand * operand,Representation representation,bool is_uint32)445   void AddValue(LOperand* operand,
446                 Representation representation,
447                 bool is_uint32) {
448     values_.Add(operand, zone());
449     if (representation.IsSmiOrTagged()) {
450       DCHECK(!is_uint32);
451       is_tagged_.Add(values_.length() - 1, zone());
452     }
453 
454     if (is_uint32) {
455       is_uint32_.Add(values_.length() - 1, zone());
456     }
457   }
458 
HasTaggedValueAt(int index)459   bool HasTaggedValueAt(int index) const {
460     return is_tagged_.Contains(index);
461   }
462 
HasUint32ValueAt(int index)463   bool HasUint32ValueAt(int index) const {
464     return is_uint32_.Contains(index);
465   }
466 
AddNewObject(int length,bool is_arguments)467   void AddNewObject(int length, bool is_arguments) {
468     uint32_t encoded = LengthOrDupeField::encode(length) |
469                        IsArgumentsField::encode(is_arguments) |
470                        IsDuplicateField::encode(false);
471     object_mapping_.Add(encoded, zone());
472   }
473 
AddDuplicateObject(int dupe_of)474   void AddDuplicateObject(int dupe_of) {
475     uint32_t encoded = LengthOrDupeField::encode(dupe_of) |
476                        IsDuplicateField::encode(true);
477     object_mapping_.Add(encoded, zone());
478   }
479 
ObjectDuplicateOfAt(int index)480   int ObjectDuplicateOfAt(int index) {
481     DCHECK(ObjectIsDuplicateAt(index));
482     return LengthOrDupeField::decode(object_mapping_[index]);
483   }
484 
ObjectLengthAt(int index)485   int ObjectLengthAt(int index) {
486     DCHECK(!ObjectIsDuplicateAt(index));
487     return LengthOrDupeField::decode(object_mapping_[index]);
488   }
489 
ObjectIsArgumentsAt(int index)490   bool ObjectIsArgumentsAt(int index) {
491     DCHECK(!ObjectIsDuplicateAt(index));
492     return IsArgumentsField::decode(object_mapping_[index]);
493   }
494 
ObjectIsDuplicateAt(int index)495   bool ObjectIsDuplicateAt(int index) {
496     return IsDuplicateField::decode(object_mapping_[index]);
497   }
498 
Register(int deoptimization_index,int translation_index,int pc_offset)499   void Register(int deoptimization_index,
500                 int translation_index,
501                 int pc_offset) {
502     DCHECK(!HasBeenRegistered());
503     deoptimization_index_ = deoptimization_index;
504     translation_index_ = translation_index;
505     pc_offset_ = pc_offset;
506   }
HasBeenRegistered()507   bool HasBeenRegistered() const {
508     return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
509   }
510 
511   void PrintTo(StringStream* stream);
512 
513   // Marker value indicating a de-materialized object.
materialization_marker()514   static LOperand* materialization_marker() { return NULL; }
515 
516   // Encoding used for the object_mapping map below.
517   class LengthOrDupeField : public BitField<int,   0, 30> { };
518   class IsArgumentsField  : public BitField<bool, 30,  1> { };
519   class IsDuplicateField  : public BitField<bool, 31,  1> { };
520 
521  private:
522   Handle<JSFunction> closure_;
523   FrameType frame_type_;
524   int arguments_stack_height_;
525   int deoptimization_index_;
526   int translation_index_;
527   BailoutId ast_id_;
528   int translation_size_;
529   int parameter_count_;
530   int pc_offset_;
531 
532   // Value array: [parameters] [locals] [expression stack] [de-materialized].
533   //              |>--------- translation_size ---------<|
534   ZoneList<LOperand*> values_;
535   GrowableBitVector is_tagged_;
536   GrowableBitVector is_uint32_;
537 
538   // Map with encoded information about materialization_marker operands.
539   ZoneList<uint32_t> object_mapping_;
540 
541   LEnvironment* outer_;
542   HEnterInlined* entry_;
543   Zone* zone_;
544   bool has_been_used_;
545 };
546 
547 
548 // Iterates over the non-null, non-constant operands in an environment.
549 class ShallowIterator final BASE_EMBEDDED {
550  public:
ShallowIterator(LEnvironment * env)551   explicit ShallowIterator(LEnvironment* env)
552       : env_(env),
553         limit_(env != NULL ? env->values()->length() : 0),
554         current_(0) {
555     SkipUninteresting();
556   }
557 
Done()558   bool Done() { return current_ >= limit_; }
559 
Current()560   LOperand* Current() {
561     DCHECK(!Done());
562     DCHECK(env_->values()->at(current_) != NULL);
563     return env_->values()->at(current_);
564   }
565 
Advance()566   void Advance() {
567     DCHECK(!Done());
568     ++current_;
569     SkipUninteresting();
570   }
571 
env()572   LEnvironment* env() { return env_; }
573 
574  private:
ShouldSkip(LOperand * op)575   bool ShouldSkip(LOperand* op) {
576     return op == NULL || op->IsConstantOperand();
577   }
578 
579   // Skip until something interesting, beginning with and including current_.
SkipUninteresting()580   void SkipUninteresting() {
581     while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) {
582       ++current_;
583     }
584   }
585 
586   LEnvironment* env_;
587   int limit_;
588   int current_;
589 };
590 
591 
592 // Iterator for non-null, non-constant operands incl. outer environments.
593 class DeepIterator final BASE_EMBEDDED {
594  public:
DeepIterator(LEnvironment * env)595   explicit DeepIterator(LEnvironment* env)
596       : current_iterator_(env) {
597     SkipUninteresting();
598   }
599 
Done()600   bool Done() { return current_iterator_.Done(); }
601 
Current()602   LOperand* Current() {
603     DCHECK(!current_iterator_.Done());
604     DCHECK(current_iterator_.Current() != NULL);
605     return current_iterator_.Current();
606   }
607 
Advance()608   void Advance() {
609     current_iterator_.Advance();
610     SkipUninteresting();
611   }
612 
613  private:
SkipUninteresting()614   void SkipUninteresting() {
615     while (current_iterator_.env() != NULL && current_iterator_.Done()) {
616       current_iterator_ = ShallowIterator(current_iterator_.env()->outer());
617     }
618   }
619 
620   ShallowIterator current_iterator_;
621 };
622 
623 
624 class LPlatformChunk;
625 class LGap;
626 class LLabel;
627 
628 // Superclass providing data and behavior common to all the
629 // arch-specific LPlatformChunk classes.
630 class LChunk : public ZoneObject {
631  public:
632   static LChunk* NewChunk(HGraph* graph);
633 
634   void AddInstruction(LInstruction* instruction, HBasicBlock* block);
635   LConstantOperand* DefineConstantOperand(HConstant* constant);
636   HConstant* LookupConstant(LConstantOperand* operand) const;
637   Representation LookupLiteralRepresentation(LConstantOperand* operand) const;
638 
639   int ParameterAt(int index);
640   int GetParameterStackSlot(int index) const;
spill_slot_count()641   int spill_slot_count() const { return spill_slot_count_; }
info()642   CompilationInfo* info() const { return info_; }
graph()643   HGraph* graph() const { return graph_; }
isolate()644   Isolate* isolate() const { return graph_->isolate(); }
instructions()645   const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
646   void AddGapMove(int index, LOperand* from, LOperand* to);
647   LGap* GetGapAt(int index) const;
648   bool IsGapAt(int index) const;
649   int NearestGapPos(int index) const;
650   void MarkEmptyBlocks();
pointer_maps()651   const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
652   LLabel* GetLabel(int block_id) const;
653   int LookupDestination(int block_id) const;
654   Label* GetAssemblyLabel(int block_id) const;
655 
inlined_functions()656   const ZoneList<Handle<SharedFunctionInfo>>& inlined_functions() const {
657     return inlined_functions_;
658   }
659 
AddInlinedFunction(Handle<SharedFunctionInfo> closure)660   void AddInlinedFunction(Handle<SharedFunctionInfo> closure) {
661     inlined_functions_.Add(closure, zone());
662   }
663 
AddDeprecationDependency(Handle<Map> map)664   void AddDeprecationDependency(Handle<Map> map) {
665     DCHECK(!map->is_deprecated());
666     if (!map->CanBeDeprecated()) return;
667     DCHECK(!info_->IsStub());
668     deprecation_dependencies_.Add(map, zone());
669   }
670 
AddStabilityDependency(Handle<Map> map)671   void AddStabilityDependency(Handle<Map> map) {
672     DCHECK(map->is_stable());
673     if (!map->CanTransition()) return;
674     DCHECK(!info_->IsStub());
675     stability_dependencies_.Add(map, zone());
676   }
677 
zone()678   Zone* zone() const { return info_->zone(); }
679 
680   Handle<Code> Codegen();
681 
682   void set_allocated_double_registers(BitVector* allocated_registers);
allocated_double_registers()683   BitVector* allocated_double_registers() {
684     return allocated_double_registers_;
685   }
686 
687  protected:
688   LChunk(CompilationInfo* info, HGraph* graph);
689 
690   int spill_slot_count_;
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<SharedFunctionInfo>> inlined_functions_;
701   ZoneList<Handle<Map>> deprecation_dependencies_;
702   ZoneList<Handle<Map>> stability_dependencies_;
703 };
704 
705 
706 class LChunkBuilderBase BASE_EMBEDDED {
707  public:
LChunkBuilderBase(CompilationInfo * info,HGraph * graph)708   explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph)
709       : argument_count_(0),
710         chunk_(NULL),
711         info_(info),
712         graph_(graph),
713         status_(UNUSED),
714         zone_(graph->zone()) {}
715 
~LChunkBuilderBase()716   virtual ~LChunkBuilderBase() { }
717 
718   void Abort(BailoutReason reason);
719   void Retry(BailoutReason reason);
720 
721  protected:
722   enum Status { UNUSED, BUILDING, DONE, ABORTED };
723 
chunk()724   LPlatformChunk* chunk() const { return chunk_; }
info()725   CompilationInfo* info() const { return info_; }
graph()726   HGraph* graph() const { return graph_; }
argument_count()727   int argument_count() const { return argument_count_; }
isolate()728   Isolate* isolate() const { return graph_->isolate(); }
heap()729   Heap* heap() const { return isolate()->heap(); }
730 
is_unused()731   bool is_unused() const { return status_ == UNUSED; }
is_building()732   bool is_building() const { return status_ == BUILDING; }
is_done()733   bool is_done() const { return status_ == DONE; }
is_aborted()734   bool is_aborted() const { return status_ == ABORTED; }
735 
736   // An input operand in register, stack slot or a constant operand.
737   // Will not be moved to a register even if one is freely available.
738   virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0;
739 
740   LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
741                                   int* argument_index_accumulator,
742                                   ZoneList<HValue*>* objects_to_materialize);
743   void AddObjectToMaterialize(HValue* value,
744                               ZoneList<HValue*>* objects_to_materialize,
745                               LEnvironment* result);
746 
zone()747   Zone* zone() const { return zone_; }
748 
749   int argument_count_;
750   LPlatformChunk* chunk_;
751   CompilationInfo* info_;
752   HGraph* const graph_;
753   Status status_;
754 
755  private:
756   Zone* zone_;
757 };
758 
759 
760 int StackSlotOffset(int index);
761 
762 enum NumberUntagDMode {
763   NUMBER_CANDIDATE_IS_SMI,
764   NUMBER_CANDIDATE_IS_ANY_TAGGED
765 };
766 
767 
768 class LPhase : public CompilationPhase {
769  public:
LPhase(const char * name,LChunk * chunk)770   LPhase(const char* name, LChunk* chunk)
771       : CompilationPhase(name, chunk->info()),
772         chunk_(chunk) { }
773   ~LPhase();
774 
775  private:
776   LChunk* chunk_;
777 
778   DISALLOW_COPY_AND_ASSIGN(LPhase);
779 };
780 
781 
782 // A register-allocator view of a Lithium instruction. It contains the id of
783 // the output operand and a list of input operand uses.
784 
785 enum RegisterKind {
786   UNALLOCATED_REGISTERS,
787   GENERAL_REGISTERS,
788   DOUBLE_REGISTERS
789 };
790 
791 // Iterator for non-null temp operands.
792 class TempIterator BASE_EMBEDDED {
793  public:
794   inline explicit TempIterator(LInstruction* instr);
795   inline bool Done();
796   inline LOperand* Current();
797   inline void Advance();
798 
799  private:
800   inline void SkipUninteresting();
801   LInstruction* instr_;
802   int limit_;
803   int current_;
804 };
805 
806 
807 // Iterator for non-constant input operands.
808 class InputIterator BASE_EMBEDDED {
809  public:
810   inline explicit InputIterator(LInstruction* instr);
811   inline bool Done();
812   inline LOperand* Current();
813   inline void Advance();
814 
815  private:
816   inline void SkipUninteresting();
817   LInstruction* instr_;
818   int limit_;
819   int current_;
820 };
821 
822 
823 class UseIterator BASE_EMBEDDED {
824  public:
825   inline explicit UseIterator(LInstruction* instr);
826   inline bool Done();
827   inline LOperand* Current();
828   inline void Advance();
829 
830  private:
831   InputIterator input_iterator_;
832   DeepIterator env_iterator_;
833 };
834 
835 class LInstruction;
836 class LCodeGen;
837 }  // namespace internal
838 }  // namespace v8
839 
840 #endif  // V8_CRANKSHAFT_LITHIUM_H_
841