• 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/compilation-phase.h"
13 #include "src/crankshaft/hydrogen.h"
14 #include "src/safepoint-table.h"
15 #include "src/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 
LOperand()39   LOperand() : value_(KindField::encode(INVALID)) { }
40 
kind()41   Kind kind() const { return KindField::decode(value_); }
index()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
Equals(LOperand * other)49   bool Equals(LOperand* other) const { return value_ == other->value_; }
50 
51   void PrintTo(StringStream* stream);
ConvertTo(Kind kind,int index)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 
LOperand(Kind kind,int index)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 
LUnallocated(ExtendedPolicy policy)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 
LUnallocated(BasicPolicy policy,int index)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 
LUnallocated(ExtendedPolicy policy,int index)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 
LUnallocated(ExtendedPolicy policy,Lifetime lifetime)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 
CopyUnconstrained(Zone * zone)133   LUnallocated* CopyUnconstrained(Zone* zone) {
134     LUnallocated* result = new(zone) LUnallocated(ANY);
135     result->set_virtual_register(virtual_register());
136     return result;
137   }
138 
cast(LOperand * op)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.
HasAnyPolicy()182   bool HasAnyPolicy() const {
183     return basic_policy() == EXTENDED_POLICY &&
184         extended_policy() == ANY;
185   }
HasFixedPolicy()186   bool HasFixedPolicy() const {
187     return basic_policy() == FIXED_SLOT ||
188         extended_policy() == FIXED_REGISTER ||
189         extended_policy() == FIXED_DOUBLE_REGISTER;
190   }
HasRegisterPolicy()191   bool HasRegisterPolicy() const {
192     return basic_policy() == EXTENDED_POLICY && (
193         extended_policy() == WRITABLE_REGISTER ||
194         extended_policy() == MUST_HAVE_REGISTER);
195   }
HasDoubleRegisterPolicy()196   bool HasDoubleRegisterPolicy() const {
197     return basic_policy() == EXTENDED_POLICY &&
198         extended_policy() == MUST_HAVE_DOUBLE_REGISTER;
199   }
HasSameAsInputPolicy()200   bool HasSameAsInputPolicy() const {
201     return basic_policy() == EXTENDED_POLICY &&
202         extended_policy() == SAME_AS_FIRST_INPUT;
203   }
HasFixedSlotPolicy()204   bool HasFixedSlotPolicy() const {
205     return basic_policy() == FIXED_SLOT;
206   }
HasFixedRegisterPolicy()207   bool HasFixedRegisterPolicy() const {
208     return basic_policy() == EXTENDED_POLICY &&
209         extended_policy() == FIXED_REGISTER;
210   }
HasFixedDoubleRegisterPolicy()211   bool HasFixedDoubleRegisterPolicy() const {
212     return basic_policy() == EXTENDED_POLICY &&
213         extended_policy() == FIXED_DOUBLE_REGISTER;
214   }
HasWritableRegisterPolicy()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.
basic_policy()221   BasicPolicy basic_policy() const {
222     return BasicPolicyField::decode(value_);
223   }
224 
225   // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
extended_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.
fixed_slot_index()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.
fixed_register_index()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.
virtual_register()244   int virtual_register() const {
245     return VirtualRegisterField::decode(value_);
246   }
set_virtual_register(unsigned id)247   void set_virtual_register(unsigned id) {
248     value_ = VirtualRegisterField::update(value_, id);
249   }
250 
251   // [lifetime]: Only for non-FIXED_SLOT.
IsUsedAtStart()252   bool IsUsedAtStart() {
253     DCHECK(basic_policy() == EXTENDED_POLICY);
254     return LifetimeField::decode(value_) == USED_AT_START;
255   }
256 
TooManyParameters(int num_parameters)257   static bool TooManyParameters(int num_parameters) {
258     const int parameter_limit = -LUnallocated::kMinFixedSlotIndex;
259     return num_parameters + 1 > parameter_limit;
260   }
261 
TooManyParametersOrStackSlots(int num_parameters,int num_stack_slots)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:
LMoveOperands(LOperand * source,LOperand * destination)272   LMoveOperands(LOperand* source, LOperand* destination)
273       : source_(source), destination_(destination) {
274   }
275 
source()276   LOperand* source() const { return source_; }
set_source(LOperand * operand)277   void set_source(LOperand* operand) { source_ = operand; }
278 
destination()279   LOperand* destination() const { return destination_; }
set_destination(LOperand * operand)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).
IsPending()284   bool IsPending() const {
285     return destination_ == NULL && source_ != NULL;
286   }
287 
288   // True if this move a move into the given destination operand.
Blocks(LOperand * 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.
IsRedundant()295   bool IsRedundant() const {
296     return IsEliminated() || source_->Equals(destination_) || IsIgnored() ||
297            (destination_ != NULL && destination_->IsConstantOperand());
298   }
299 
IsIgnored()300   bool IsIgnored() const {
301     return destination_ != NULL && destination_->IsIgnored();
302   }
303 
304   // We clear both operands to indicate move that's been eliminated.
Eliminate()305   void Eliminate() { source_ = destination_ = NULL; }
IsEliminated()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:
Create(int index,Zone * zone)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 
cast(LOperand * op)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 
LSubKindOperand()337   LSubKindOperand() : LOperand() { }
LSubKindOperand(int index)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;
LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS)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:
LPointerMap(Zone * zone)369   explicit LPointerMap(Zone* zone)
370       : pointer_operands_(8, zone),
371         untagged_operands_(0, zone),
372         lithium_position_(-1) { }
373 
GetNormalizedOperands()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   }
lithium_position()381   int lithium_position() const { return lithium_position_; }
382 
set_lithium_position(int pos)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:
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)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 
closure()429   Handle<JSFunction> closure() const { return closure_; }
frame_type()430   FrameType frame_type() const { return frame_type_; }
arguments_stack_height()431   int arguments_stack_height() const { return arguments_stack_height_; }
deoptimization_index()432   int deoptimization_index() const { return deoptimization_index_; }
translation_index()433   int translation_index() const { return translation_index_; }
ast_id()434   BailoutId ast_id() const { return ast_id_; }
translation_size()435   int translation_size() const { return translation_size_; }
parameter_count()436   int parameter_count() const { return parameter_count_; }
pc_offset()437   int pc_offset() const { return pc_offset_; }
values()438   const ZoneList<LOperand*>* values() const { return &values_; }
outer()439   LEnvironment* outer() const { return outer_; }
entry()440   HEnterInlined* entry() { return entry_; }
zone()441   Zone* zone() const { return zone_; }
442 
has_been_used()443   bool has_been_used() const { return has_been_used_; }
set_has_been_used()444   void set_has_been_used() { has_been_used_ = true; }
445 
AddValue(LOperand * operand,Representation representation,bool is_uint32)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 
HasTaggedValueAt(int index)460   bool HasTaggedValueAt(int index) const {
461     return is_tagged_.Contains(index);
462   }
463 
HasUint32ValueAt(int index)464   bool HasUint32ValueAt(int index) const {
465     return is_uint32_.Contains(index);
466   }
467 
AddNewObject(int length,bool is_arguments)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 
AddDuplicateObject(int dupe_of)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 
ObjectDuplicateOfAt(int index)481   int ObjectDuplicateOfAt(int index) {
482     DCHECK(ObjectIsDuplicateAt(index));
483     return LengthOrDupeField::decode(object_mapping_[index]);
484   }
485 
ObjectLengthAt(int index)486   int ObjectLengthAt(int index) {
487     DCHECK(!ObjectIsDuplicateAt(index));
488     return LengthOrDupeField::decode(object_mapping_[index]);
489   }
490 
ObjectIsArgumentsAt(int index)491   bool ObjectIsArgumentsAt(int index) {
492     DCHECK(!ObjectIsDuplicateAt(index));
493     return IsArgumentsField::decode(object_mapping_[index]);
494   }
495 
ObjectIsDuplicateAt(int index)496   bool ObjectIsDuplicateAt(int index) {
497     return IsDuplicateField::decode(object_mapping_[index]);
498   }
499 
Register(int deoptimization_index,int translation_index,int pc_offset)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   }
HasBeenRegistered()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.
materialization_marker()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:
ShallowIterator(LEnvironment * env)552   explicit ShallowIterator(LEnvironment* env)
553       : env_(env),
554         limit_(env != NULL ? env->values()->length() : 0),
555         current_(0) {
556     SkipUninteresting();
557   }
558 
Done()559   bool Done() { return current_ >= limit_; }
560 
Current()561   LOperand* Current() {
562     DCHECK(!Done());
563     DCHECK(env_->values()->at(current_) != NULL);
564     return env_->values()->at(current_);
565   }
566 
Advance()567   void Advance() {
568     DCHECK(!Done());
569     ++current_;
570     SkipUninteresting();
571   }
572 
env()573   LEnvironment* env() { return env_; }
574 
575  private:
ShouldSkip(LOperand * op)576   bool ShouldSkip(LOperand* op) {
577     return op == NULL || op->IsConstantOperand();
578   }
579 
580   // Skip until something interesting, beginning with and including current_.
SkipUninteresting()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:
DeepIterator(LEnvironment * env)596   explicit DeepIterator(LEnvironment* env)
597       : current_iterator_(env) {
598     SkipUninteresting();
599   }
600 
Done()601   bool Done() { return current_iterator_.Done(); }
602 
Current()603   LOperand* Current() {
604     DCHECK(!current_iterator_.Done());
605     DCHECK(current_iterator_.Current() != NULL);
606     return current_iterator_.Current();
607   }
608 
Advance()609   void Advance() {
610     current_iterator_.Advance();
611     SkipUninteresting();
612   }
613 
614  private:
SkipUninteresting()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;
HasAllocatedStackSlots()642   bool HasAllocatedStackSlots() const {
643     return current_frame_slots_ != base_frame_slots_;
644   }
GetSpillSlotCount()645   int GetSpillSlotCount() const {
646     return current_frame_slots_ - base_frame_slots_;
647   }
GetTotalFrameSlotCount()648   int GetTotalFrameSlotCount() const { return current_frame_slots_; }
info()649   CompilationInfo* info() const { return info_; }
graph()650   HGraph* graph() const { return graph_; }
isolate()651   Isolate* isolate() const { return graph_->isolate(); }
instructions()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();
pointer_maps()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 
inlined_functions()663   const ZoneList<Handle<SharedFunctionInfo>>& inlined_functions() const {
664     return inlined_functions_;
665   }
666 
AddInlinedFunction(Handle<SharedFunctionInfo> closure)667   void AddInlinedFunction(Handle<SharedFunctionInfo> closure) {
668     inlined_functions_.Add(closure, zone());
669   }
670 
AddDeprecationDependency(Handle<Map> map)671   void AddDeprecationDependency(Handle<Map> map) {
672     DCHECK(!map->is_deprecated());
673     if (!map->CanBeDeprecated()) return;
674     DCHECK(!info_->IsStub());
675     deprecation_dependencies_.Add(map, zone());
676   }
677 
AddStabilityDependency(Handle<Map> map)678   void AddStabilityDependency(Handle<Map> map) {
679     DCHECK(map->is_stable());
680     if (!map->CanTransition()) return;
681     DCHECK(!info_->IsStub());
682     stability_dependencies_.Add(map, zone());
683   }
684 
zone()685   Zone* zone() const { return info_->zone(); }
686 
687   Handle<Code> Codegen();
688 
689   void set_allocated_double_registers(BitVector* allocated_registers);
allocated_double_registers()690   BitVector* allocated_double_registers() {
691     return allocated_double_registers_;
692   }
693 
694  protected:
695   LChunk(CompilationInfo* info, HGraph* graph);
696 
697   int base_frame_slots_;
698   int current_frame_slots_;
699 
700  private:
701   void CommitDependencies(Handle<Code> code) const;
702 
703   CompilationInfo* info_;
704   HGraph* const graph_;
705   BitVector* allocated_double_registers_;
706   ZoneList<LInstruction*> instructions_;
707   ZoneList<LPointerMap*> pointer_maps_;
708   ZoneList<Handle<SharedFunctionInfo>> inlined_functions_;
709   ZoneList<Handle<Map>> deprecation_dependencies_;
710   ZoneList<Handle<Map>> stability_dependencies_;
711 };
712 
713 
714 class LChunkBuilderBase BASE_EMBEDDED {
715  public:
LChunkBuilderBase(CompilationInfo * info,HGraph * graph)716   explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph)
717       : argument_count_(0),
718         chunk_(NULL),
719         info_(info),
720         graph_(graph),
721         status_(UNUSED),
722         zone_(graph->zone()) {}
723 
~LChunkBuilderBase()724   virtual ~LChunkBuilderBase() { }
725 
726   void Abort(BailoutReason reason);
727   void Retry(BailoutReason reason);
728 
729  protected:
730   enum Status { UNUSED, BUILDING, DONE, ABORTED };
731 
chunk()732   LPlatformChunk* chunk() const { return chunk_; }
info()733   CompilationInfo* info() const { return info_; }
graph()734   HGraph* graph() const { return graph_; }
argument_count()735   int argument_count() const { return argument_count_; }
isolate()736   Isolate* isolate() const { return graph_->isolate(); }
heap()737   Heap* heap() const { return isolate()->heap(); }
738 
is_unused()739   bool is_unused() const { return status_ == UNUSED; }
is_building()740   bool is_building() const { return status_ == BUILDING; }
is_done()741   bool is_done() const { return status_ == DONE; }
is_aborted()742   bool is_aborted() const { return status_ == ABORTED; }
743 
744   // An input operand in register, stack slot or a constant operand.
745   // Will not be moved to a register even if one is freely available.
746   virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0;
747 
748   // Constructs proper environment for a lazy bailout point after call, creates
749   // LLazyBailout instruction and adds it to current block.
750   void CreateLazyBailoutForCall(HBasicBlock* current_block, LInstruction* instr,
751                                 HInstruction* hydrogen_val);
752 
753   // Assigns given environment to an instruction.  An instruction which can
754   // deoptimize must have an environment.
755   LInstruction* AssignEnvironment(LInstruction* instr,
756                                   HEnvironment* hydrogen_env);
757 
758   LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
759                                   int* argument_index_accumulator,
760                                   ZoneList<HValue*>* objects_to_materialize);
761   void AddObjectToMaterialize(HValue* value,
762                               ZoneList<HValue*>* objects_to_materialize,
763                               LEnvironment* result);
764 
zone()765   Zone* zone() const { return zone_; }
766 
767   int argument_count_;
768   LPlatformChunk* chunk_;
769   CompilationInfo* info_;
770   HGraph* const graph_;
771   Status status_;
772 
773  private:
774   Zone* zone_;
775 };
776 
777 
778 enum NumberUntagDMode {
779   NUMBER_CANDIDATE_IS_SMI,
780   NUMBER_CANDIDATE_IS_ANY_TAGGED
781 };
782 
783 
784 class LPhase : public CompilationPhase {
785  public:
LPhase(const char * name,LChunk * chunk)786   LPhase(const char* name, LChunk* chunk)
787       : CompilationPhase(name, chunk->info()),
788         chunk_(chunk) { }
789   ~LPhase();
790 
791  private:
792   LChunk* chunk_;
793 
794   DISALLOW_COPY_AND_ASSIGN(LPhase);
795 };
796 
797 
798 // A register-allocator view of a Lithium instruction. It contains the id of
799 // the output operand and a list of input operand uses.
800 
801 enum RegisterKind {
802   UNALLOCATED_REGISTERS,
803   GENERAL_REGISTERS,
804   DOUBLE_REGISTERS
805 };
806 
807 // Iterator for non-null temp operands.
808 class TempIterator BASE_EMBEDDED {
809  public:
810   inline explicit TempIterator(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 // Iterator for non-constant input operands.
824 class InputIterator BASE_EMBEDDED {
825  public:
826   inline explicit InputIterator(LInstruction* instr);
827   inline bool Done();
828   inline LOperand* Current();
829   inline void Advance();
830 
831  private:
832   inline void SkipUninteresting();
833   LInstruction* instr_;
834   int limit_;
835   int current_;
836 };
837 
838 
839 class UseIterator BASE_EMBEDDED {
840  public:
841   inline explicit UseIterator(LInstruction* instr);
842   inline bool Done();
843   inline LOperand* Current();
844   inline void Advance();
845 
846  private:
847   InputIterator input_iterator_;
848   DeepIterator env_iterator_;
849 };
850 
851 class LInstruction;
852 class LCodeGen;
853 }  // namespace internal
854 }  // namespace v8
855 
856 #endif  // V8_CRANKSHAFT_LITHIUM_H_
857