• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_LITHIUM_H_
29 #define V8_LITHIUM_H_
30 
31 #include "allocation.h"
32 #include "hydrogen.h"
33 #include "safepoint-table.h"
34 
35 namespace v8 {
36 namespace internal {
37 
38 #define LITHIUM_OPERAND_LIST(V)         \
39   V(ConstantOperand, CONSTANT_OPERAND)  \
40   V(StackSlot,       STACK_SLOT)        \
41   V(DoubleStackSlot, DOUBLE_STACK_SLOT) \
42   V(Register,        REGISTER)          \
43   V(DoubleRegister,  DOUBLE_REGISTER)
44 
45 
46 class LOperand : public ZoneObject {
47  public:
48   enum Kind {
49     INVALID,
50     UNALLOCATED,
51     CONSTANT_OPERAND,
52     STACK_SLOT,
53     DOUBLE_STACK_SLOT,
54     REGISTER,
55     DOUBLE_REGISTER,
56     ARGUMENT
57   };
58 
LOperand()59   LOperand() : value_(KindField::encode(INVALID)) { }
60 
kind()61   Kind kind() const { return KindField::decode(value_); }
index()62   int index() const { return static_cast<int>(value_) >> kKindFieldWidth; }
63 #define LITHIUM_OPERAND_PREDICATE(name, type) \
64   bool Is##name() const { return kind() == type; }
65   LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_PREDICATE)
LITHIUM_OPERAND_PREDICATE(Argument,ARGUMENT)66   LITHIUM_OPERAND_PREDICATE(Argument, ARGUMENT)
67   LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED)
68   LITHIUM_OPERAND_PREDICATE(Ignored, INVALID)
69 #undef LITHIUM_OPERAND_PREDICATE
70   bool Equals(LOperand* other) const { return value_ == other->value_; }
71 
72   void PrintTo(StringStream* stream);
ConvertTo(Kind kind,int index)73   void ConvertTo(Kind kind, int index) {
74     value_ = KindField::encode(kind);
75     value_ |= index << kKindFieldWidth;
76     ASSERT(this->index() == index);
77   }
78 
79   // Calls SetUpCache()/TearDownCache() for each subclass.
80   static void SetUpCaches();
81   static void TearDownCaches();
82 
83  protected:
84   static const int kKindFieldWidth = 3;
85   class KindField : public BitField<Kind, 0, kKindFieldWidth> { };
86 
LOperand(Kind kind,int index)87   LOperand(Kind kind, int index) { ConvertTo(kind, index); }
88 
89   unsigned value_;
90 };
91 
92 
93 class LUnallocated : public LOperand {
94  public:
95   enum BasicPolicy {
96     FIXED_SLOT,
97     EXTENDED_POLICY
98   };
99 
100   enum ExtendedPolicy {
101     NONE,
102     ANY,
103     FIXED_REGISTER,
104     FIXED_DOUBLE_REGISTER,
105     MUST_HAVE_REGISTER,
106     WRITABLE_REGISTER,
107     SAME_AS_FIRST_INPUT
108   };
109 
110   // Lifetime of operand inside the instruction.
111   enum Lifetime {
112     // USED_AT_START operand is guaranteed to be live only at
113     // instruction start. Register allocator is free to assign the same register
114     // to some other operand used inside instruction (i.e. temporary or
115     // output).
116     USED_AT_START,
117 
118     // USED_AT_END operand is treated as live until the end of
119     // instruction. This means that register allocator will not reuse it's
120     // register for any other operand inside instruction.
121     USED_AT_END
122   };
123 
LUnallocated(ExtendedPolicy policy)124   explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) {
125     value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
126     value_ |= ExtendedPolicyField::encode(policy);
127     value_ |= LifetimeField::encode(USED_AT_END);
128   }
129 
LUnallocated(BasicPolicy policy,int index)130   LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
131     ASSERT(policy == FIXED_SLOT);
132     value_ |= BasicPolicyField::encode(policy);
133     value_ |= index << FixedSlotIndexField::kShift;
134     ASSERT(this->fixed_slot_index() == index);
135   }
136 
LUnallocated(ExtendedPolicy policy,int index)137   LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
138     ASSERT(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
139     value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
140     value_ |= ExtendedPolicyField::encode(policy);
141     value_ |= LifetimeField::encode(USED_AT_END);
142     value_ |= FixedRegisterField::encode(index);
143   }
144 
LUnallocated(ExtendedPolicy policy,Lifetime lifetime)145   LUnallocated(ExtendedPolicy policy, Lifetime lifetime)
146       : LOperand(UNALLOCATED, 0) {
147     value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
148     value_ |= ExtendedPolicyField::encode(policy);
149     value_ |= LifetimeField::encode(lifetime);
150   }
151 
CopyUnconstrained(Zone * zone)152   LUnallocated* CopyUnconstrained(Zone* zone) {
153     LUnallocated* result = new(zone) LUnallocated(ANY);
154     result->set_virtual_register(virtual_register());
155     return result;
156   }
157 
cast(LOperand * op)158   static LUnallocated* cast(LOperand* op) {
159     ASSERT(op->IsUnallocated());
160     return reinterpret_cast<LUnallocated*>(op);
161   }
162 
163   // The encoding used for LUnallocated operands depends on the policy that is
164   // stored within the operand. The FIXED_SLOT policy uses a compact encoding
165   // because it accommodates a larger pay-load.
166   //
167   // For FIXED_SLOT policy:
168   //     +------------------------------------------+
169   //     |       slot_index      |  vreg  | 0 | 001 |
170   //     +------------------------------------------+
171   //
172   // For all other (extended) policies:
173   //     +------------------------------------------+
174   //     |  reg_index  | L | PPP |  vreg  | 1 | 001 |    L ... Lifetime
175   //     +------------------------------------------+    P ... Policy
176   //
177   // The slot index is a signed value which requires us to decode it manually
178   // instead of using the BitField utility class.
179 
180   // The superclass has a KindField.
181   STATIC_ASSERT(kKindFieldWidth == 3);
182 
183   // BitFields for all unallocated operands.
184   class BasicPolicyField     : public BitField<BasicPolicy,     3,  1> {};
185   class VirtualRegisterField : public BitField<unsigned,        4, 18> {};
186 
187   // BitFields specific to BasicPolicy::FIXED_SLOT.
188   class FixedSlotIndexField  : public BitField<int,            22, 10> {};
189 
190   // BitFields specific to BasicPolicy::EXTENDED_POLICY.
191   class ExtendedPolicyField  : public BitField<ExtendedPolicy, 22,  3> {};
192   class LifetimeField        : public BitField<Lifetime,       25,  1> {};
193   class FixedRegisterField   : public BitField<int,            26,  6> {};
194 
195   static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1;
196   static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
197   static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
198   static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));
199 
200   // Predicates for the operand policy.
HasAnyPolicy()201   bool HasAnyPolicy() const {
202     return basic_policy() == EXTENDED_POLICY &&
203         extended_policy() == ANY;
204   }
HasFixedPolicy()205   bool HasFixedPolicy() const {
206     return basic_policy() == FIXED_SLOT ||
207         extended_policy() == FIXED_REGISTER ||
208         extended_policy() == FIXED_DOUBLE_REGISTER;
209   }
HasRegisterPolicy()210   bool HasRegisterPolicy() const {
211     return basic_policy() == EXTENDED_POLICY && (
212         extended_policy() == WRITABLE_REGISTER ||
213         extended_policy() == MUST_HAVE_REGISTER);
214   }
HasSameAsInputPolicy()215   bool HasSameAsInputPolicy() const {
216     return basic_policy() == EXTENDED_POLICY &&
217         extended_policy() == SAME_AS_FIRST_INPUT;
218   }
HasFixedSlotPolicy()219   bool HasFixedSlotPolicy() const {
220     return basic_policy() == FIXED_SLOT;
221   }
HasFixedRegisterPolicy()222   bool HasFixedRegisterPolicy() const {
223     return basic_policy() == EXTENDED_POLICY &&
224         extended_policy() == FIXED_REGISTER;
225   }
HasFixedDoubleRegisterPolicy()226   bool HasFixedDoubleRegisterPolicy() const {
227     return basic_policy() == EXTENDED_POLICY &&
228         extended_policy() == FIXED_DOUBLE_REGISTER;
229   }
HasWritableRegisterPolicy()230   bool HasWritableRegisterPolicy() const {
231     return basic_policy() == EXTENDED_POLICY &&
232         extended_policy() == WRITABLE_REGISTER;
233   }
234 
235   // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
basic_policy()236   BasicPolicy basic_policy() const {
237     return BasicPolicyField::decode(value_);
238   }
239 
240   // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
extended_policy()241   ExtendedPolicy extended_policy() const {
242     ASSERT(basic_policy() == EXTENDED_POLICY);
243     return ExtendedPolicyField::decode(value_);
244   }
245 
246   // [fixed_slot_index]: Only for FIXED_SLOT.
fixed_slot_index()247   int fixed_slot_index() const {
248     ASSERT(HasFixedSlotPolicy());
249     return static_cast<int>(value_) >> FixedSlotIndexField::kShift;
250   }
251 
252   // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
fixed_register_index()253   int fixed_register_index() const {
254     ASSERT(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
255     return FixedRegisterField::decode(value_);
256   }
257 
258   // [virtual_register]: The virtual register ID for this operand.
virtual_register()259   int virtual_register() const {
260     return VirtualRegisterField::decode(value_);
261   }
set_virtual_register(unsigned id)262   void set_virtual_register(unsigned id) {
263     value_ = VirtualRegisterField::update(value_, id);
264   }
265 
266   // [lifetime]: Only for non-FIXED_SLOT.
IsUsedAtStart()267   bool IsUsedAtStart() {
268     ASSERT(basic_policy() == EXTENDED_POLICY);
269     return LifetimeField::decode(value_) == USED_AT_START;
270   }
271 };
272 
273 
274 class LMoveOperands V8_FINAL BASE_EMBEDDED {
275  public:
LMoveOperands(LOperand * source,LOperand * destination)276   LMoveOperands(LOperand* source, LOperand* destination)
277       : source_(source), destination_(destination) {
278   }
279 
source()280   LOperand* source() const { return source_; }
set_source(LOperand * operand)281   void set_source(LOperand* operand) { source_ = operand; }
282 
destination()283   LOperand* destination() const { return destination_; }
set_destination(LOperand * operand)284   void set_destination(LOperand* operand) { destination_ = operand; }
285 
286   // The gap resolver marks moves as "in-progress" by clearing the
287   // destination (but not the source).
IsPending()288   bool IsPending() const {
289     return destination_ == NULL && source_ != NULL;
290   }
291 
292   // True if this move a move into the given destination operand.
Blocks(LOperand * operand)293   bool Blocks(LOperand* operand) const {
294     return !IsEliminated() && source()->Equals(operand);
295   }
296 
297   // A move is redundant if it's been eliminated, if its source and
298   // destination are the same, or if its destination is unneeded.
IsRedundant()299   bool IsRedundant() const {
300     return IsEliminated() || source_->Equals(destination_) || IsIgnored();
301   }
302 
IsIgnored()303   bool IsIgnored() const {
304     return destination_ != NULL && destination_->IsIgnored();
305   }
306 
307   // We clear both operands to indicate move that's been eliminated.
Eliminate()308   void Eliminate() { source_ = destination_ = NULL; }
IsEliminated()309   bool IsEliminated() const {
310     ASSERT(source_ != NULL || destination_ == NULL);
311     return source_ == NULL;
312   }
313 
314  private:
315   LOperand* source_;
316   LOperand* destination_;
317 };
318 
319 
320 class LConstantOperand V8_FINAL : public LOperand {
321  public:
Create(int index,Zone * zone)322   static LConstantOperand* Create(int index, Zone* zone) {
323     ASSERT(index >= 0);
324     if (index < kNumCachedOperands) return &cache[index];
325     return new(zone) LConstantOperand(index);
326   }
327 
cast(LOperand * op)328   static LConstantOperand* cast(LOperand* op) {
329     ASSERT(op->IsConstantOperand());
330     return reinterpret_cast<LConstantOperand*>(op);
331   }
332 
333   static void SetUpCache();
334   static void TearDownCache();
335 
336  private:
337   static const int kNumCachedOperands = 128;
338   static LConstantOperand* cache;
339 
LConstantOperand()340   LConstantOperand() : LOperand() { }
LConstantOperand(int index)341   explicit LConstantOperand(int index) : LOperand(CONSTANT_OPERAND, index) { }
342 };
343 
344 
345 class LArgument V8_FINAL : public LOperand {
346  public:
LArgument(int index)347   explicit LArgument(int index) : LOperand(ARGUMENT, index) { }
348 
cast(LOperand * op)349   static LArgument* cast(LOperand* op) {
350     ASSERT(op->IsArgument());
351     return reinterpret_cast<LArgument*>(op);
352   }
353 };
354 
355 
356 class LStackSlot V8_FINAL : public LOperand {
357  public:
Create(int index,Zone * zone)358   static LStackSlot* Create(int index, Zone* zone) {
359     ASSERT(index >= 0);
360     if (index < kNumCachedOperands) return &cache[index];
361     return new(zone) LStackSlot(index);
362   }
363 
cast(LOperand * op)364   static LStackSlot* cast(LOperand* op) {
365     ASSERT(op->IsStackSlot());
366     return reinterpret_cast<LStackSlot*>(op);
367   }
368 
369   static void SetUpCache();
370   static void TearDownCache();
371 
372  private:
373   static const int kNumCachedOperands = 128;
374   static LStackSlot* cache;
375 
LStackSlot()376   LStackSlot() : LOperand() { }
LStackSlot(int index)377   explicit LStackSlot(int index) : LOperand(STACK_SLOT, index) { }
378 };
379 
380 
381 class LDoubleStackSlot V8_FINAL : public LOperand {
382  public:
Create(int index,Zone * zone)383   static LDoubleStackSlot* Create(int index, Zone* zone) {
384     ASSERT(index >= 0);
385     if (index < kNumCachedOperands) return &cache[index];
386     return new(zone) LDoubleStackSlot(index);
387   }
388 
cast(LOperand * op)389   static LDoubleStackSlot* cast(LOperand* op) {
390     ASSERT(op->IsStackSlot());
391     return reinterpret_cast<LDoubleStackSlot*>(op);
392   }
393 
394   static void SetUpCache();
395   static void TearDownCache();
396 
397  private:
398   static const int kNumCachedOperands = 128;
399   static LDoubleStackSlot* cache;
400 
LDoubleStackSlot()401   LDoubleStackSlot() : LOperand() { }
LDoubleStackSlot(int index)402   explicit LDoubleStackSlot(int index) : LOperand(DOUBLE_STACK_SLOT, index) { }
403 };
404 
405 
406 class LRegister V8_FINAL : public LOperand {
407  public:
Create(int index,Zone * zone)408   static LRegister* Create(int index, Zone* zone) {
409     ASSERT(index >= 0);
410     if (index < kNumCachedOperands) return &cache[index];
411     return new(zone) LRegister(index);
412   }
413 
cast(LOperand * op)414   static LRegister* cast(LOperand* op) {
415     ASSERT(op->IsRegister());
416     return reinterpret_cast<LRegister*>(op);
417   }
418 
419   static void SetUpCache();
420   static void TearDownCache();
421 
422  private:
423   static const int kNumCachedOperands = 16;
424   static LRegister* cache;
425 
LRegister()426   LRegister() : LOperand() { }
LRegister(int index)427   explicit LRegister(int index) : LOperand(REGISTER, index) { }
428 };
429 
430 
431 class LDoubleRegister V8_FINAL : public LOperand {
432  public:
Create(int index,Zone * zone)433   static LDoubleRegister* Create(int index, Zone* zone) {
434     ASSERT(index >= 0);
435     if (index < kNumCachedOperands) return &cache[index];
436     return new(zone) LDoubleRegister(index);
437   }
438 
cast(LOperand * op)439   static LDoubleRegister* cast(LOperand* op) {
440     ASSERT(op->IsDoubleRegister());
441     return reinterpret_cast<LDoubleRegister*>(op);
442   }
443 
444   static void SetUpCache();
445   static void TearDownCache();
446 
447  private:
448   static const int kNumCachedOperands = 16;
449   static LDoubleRegister* cache;
450 
LDoubleRegister()451   LDoubleRegister() : LOperand() { }
LDoubleRegister(int index)452   explicit LDoubleRegister(int index) : LOperand(DOUBLE_REGISTER, index) { }
453 };
454 
455 
456 class LParallelMove V8_FINAL : public ZoneObject {
457  public:
LParallelMove(Zone * zone)458   explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { }
459 
AddMove(LOperand * from,LOperand * to,Zone * zone)460   void AddMove(LOperand* from, LOperand* to, Zone* zone) {
461     move_operands_.Add(LMoveOperands(from, to), zone);
462   }
463 
464   bool IsRedundant() const;
465 
move_operands()466   const ZoneList<LMoveOperands>* move_operands() const {
467     return &move_operands_;
468   }
469 
470   void PrintDataTo(StringStream* stream) const;
471 
472  private:
473   ZoneList<LMoveOperands> move_operands_;
474 };
475 
476 
477 class LPointerMap V8_FINAL : public ZoneObject {
478  public:
LPointerMap(Zone * zone)479   explicit LPointerMap(Zone* zone)
480       : pointer_operands_(8, zone),
481         untagged_operands_(0, zone),
482         lithium_position_(-1) { }
483 
GetNormalizedOperands()484   const ZoneList<LOperand*>* GetNormalizedOperands() {
485     for (int i = 0; i < untagged_operands_.length(); ++i) {
486       RemovePointer(untagged_operands_[i]);
487     }
488     untagged_operands_.Clear();
489     return &pointer_operands_;
490   }
lithium_position()491   int lithium_position() const { return lithium_position_; }
492 
set_lithium_position(int pos)493   void set_lithium_position(int pos) {
494     ASSERT(lithium_position_ == -1);
495     lithium_position_ = pos;
496   }
497 
498   void RecordPointer(LOperand* op, Zone* zone);
499   void RemovePointer(LOperand* op);
500   void RecordUntagged(LOperand* op, Zone* zone);
501   void PrintTo(StringStream* stream);
502 
503  private:
504   ZoneList<LOperand*> pointer_operands_;
505   ZoneList<LOperand*> untagged_operands_;
506   int lithium_position_;
507 };
508 
509 
510 class LEnvironment V8_FINAL : public ZoneObject {
511  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)512   LEnvironment(Handle<JSFunction> closure,
513                FrameType frame_type,
514                BailoutId ast_id,
515                int parameter_count,
516                int argument_count,
517                int value_count,
518                LEnvironment* outer,
519                HEnterInlined* entry,
520                Zone* zone)
521       : closure_(closure),
522         frame_type_(frame_type),
523         arguments_stack_height_(argument_count),
524         deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
525         translation_index_(-1),
526         ast_id_(ast_id),
527         translation_size_(value_count),
528         parameter_count_(parameter_count),
529         pc_offset_(-1),
530         values_(value_count, zone),
531         is_tagged_(value_count, zone),
532         is_uint32_(value_count, zone),
533         object_mapping_(0, zone),
534         outer_(outer),
535         entry_(entry),
536         zone_(zone) { }
537 
closure()538   Handle<JSFunction> closure() const { return closure_; }
frame_type()539   FrameType frame_type() const { return frame_type_; }
arguments_stack_height()540   int arguments_stack_height() const { return arguments_stack_height_; }
deoptimization_index()541   int deoptimization_index() const { return deoptimization_index_; }
translation_index()542   int translation_index() const { return translation_index_; }
ast_id()543   BailoutId ast_id() const { return ast_id_; }
translation_size()544   int translation_size() const { return translation_size_; }
parameter_count()545   int parameter_count() const { return parameter_count_; }
pc_offset()546   int pc_offset() const { return pc_offset_; }
values()547   const ZoneList<LOperand*>* values() const { return &values_; }
outer()548   LEnvironment* outer() const { return outer_; }
entry()549   HEnterInlined* entry() { return entry_; }
zone()550   Zone* zone() const { return zone_; }
551 
AddValue(LOperand * operand,Representation representation,bool is_uint32)552   void AddValue(LOperand* operand,
553                 Representation representation,
554                 bool is_uint32) {
555     values_.Add(operand, zone());
556     if (representation.IsSmiOrTagged()) {
557       ASSERT(!is_uint32);
558       is_tagged_.Add(values_.length() - 1, zone());
559     }
560 
561     if (is_uint32) {
562       is_uint32_.Add(values_.length() - 1, zone());
563     }
564   }
565 
HasTaggedValueAt(int index)566   bool HasTaggedValueAt(int index) const {
567     return is_tagged_.Contains(index);
568   }
569 
HasUint32ValueAt(int index)570   bool HasUint32ValueAt(int index) const {
571     return is_uint32_.Contains(index);
572   }
573 
AddNewObject(int length,bool is_arguments)574   void AddNewObject(int length, bool is_arguments) {
575     uint32_t encoded = LengthOrDupeField::encode(length) |
576                        IsArgumentsField::encode(is_arguments) |
577                        IsDuplicateField::encode(false);
578     object_mapping_.Add(encoded, zone());
579   }
580 
AddDuplicateObject(int dupe_of)581   void AddDuplicateObject(int dupe_of) {
582     uint32_t encoded = LengthOrDupeField::encode(dupe_of) |
583                        IsDuplicateField::encode(true);
584     object_mapping_.Add(encoded, zone());
585   }
586 
ObjectDuplicateOfAt(int index)587   int ObjectDuplicateOfAt(int index) {
588     ASSERT(ObjectIsDuplicateAt(index));
589     return LengthOrDupeField::decode(object_mapping_[index]);
590   }
591 
ObjectLengthAt(int index)592   int ObjectLengthAt(int index) {
593     ASSERT(!ObjectIsDuplicateAt(index));
594     return LengthOrDupeField::decode(object_mapping_[index]);
595   }
596 
ObjectIsArgumentsAt(int index)597   bool ObjectIsArgumentsAt(int index) {
598     ASSERT(!ObjectIsDuplicateAt(index));
599     return IsArgumentsField::decode(object_mapping_[index]);
600   }
601 
ObjectIsDuplicateAt(int index)602   bool ObjectIsDuplicateAt(int index) {
603     return IsDuplicateField::decode(object_mapping_[index]);
604   }
605 
Register(int deoptimization_index,int translation_index,int pc_offset)606   void Register(int deoptimization_index,
607                 int translation_index,
608                 int pc_offset) {
609     ASSERT(!HasBeenRegistered());
610     deoptimization_index_ = deoptimization_index;
611     translation_index_ = translation_index;
612     pc_offset_ = pc_offset;
613   }
HasBeenRegistered()614   bool HasBeenRegistered() const {
615     return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
616   }
617 
618   void PrintTo(StringStream* stream);
619 
620   // Marker value indicating a de-materialized object.
materialization_marker()621   static LOperand* materialization_marker() { return NULL; }
622 
623   // Encoding used for the object_mapping map below.
624   class LengthOrDupeField : public BitField<int,   0, 30> { };
625   class IsArgumentsField  : public BitField<bool, 30,  1> { };
626   class IsDuplicateField  : public BitField<bool, 31,  1> { };
627 
628  private:
629   Handle<JSFunction> closure_;
630   FrameType frame_type_;
631   int arguments_stack_height_;
632   int deoptimization_index_;
633   int translation_index_;
634   BailoutId ast_id_;
635   int translation_size_;
636   int parameter_count_;
637   int pc_offset_;
638 
639   // Value array: [parameters] [locals] [expression stack] [de-materialized].
640   //              |>--------- translation_size ---------<|
641   ZoneList<LOperand*> values_;
642   GrowableBitVector is_tagged_;
643   GrowableBitVector is_uint32_;
644 
645   // Map with encoded information about materialization_marker operands.
646   ZoneList<uint32_t> object_mapping_;
647 
648   LEnvironment* outer_;
649   HEnterInlined* entry_;
650   Zone* zone_;
651 };
652 
653 
654 // Iterates over the non-null, non-constant operands in an environment.
655 class ShallowIterator V8_FINAL BASE_EMBEDDED {
656  public:
ShallowIterator(LEnvironment * env)657   explicit ShallowIterator(LEnvironment* env)
658       : env_(env),
659         limit_(env != NULL ? env->values()->length() : 0),
660         current_(0) {
661     SkipUninteresting();
662   }
663 
Done()664   bool Done() { return current_ >= limit_; }
665 
Current()666   LOperand* Current() {
667     ASSERT(!Done());
668     ASSERT(env_->values()->at(current_) != NULL);
669     return env_->values()->at(current_);
670   }
671 
Advance()672   void Advance() {
673     ASSERT(!Done());
674     ++current_;
675     SkipUninteresting();
676   }
677 
env()678   LEnvironment* env() { return env_; }
679 
680  private:
ShouldSkip(LOperand * op)681   bool ShouldSkip(LOperand* op) {
682     return op == NULL || op->IsConstantOperand() || op->IsArgument();
683   }
684 
685   // Skip until something interesting, beginning with and including current_.
SkipUninteresting()686   void SkipUninteresting() {
687     while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) {
688       ++current_;
689     }
690   }
691 
692   LEnvironment* env_;
693   int limit_;
694   int current_;
695 };
696 
697 
698 // Iterator for non-null, non-constant operands incl. outer environments.
699 class DeepIterator V8_FINAL BASE_EMBEDDED {
700  public:
DeepIterator(LEnvironment * env)701   explicit DeepIterator(LEnvironment* env)
702       : current_iterator_(env) {
703     SkipUninteresting();
704   }
705 
Done()706   bool Done() { return current_iterator_.Done(); }
707 
Current()708   LOperand* Current() {
709     ASSERT(!current_iterator_.Done());
710     ASSERT(current_iterator_.Current() != NULL);
711     return current_iterator_.Current();
712   }
713 
Advance()714   void Advance() {
715     current_iterator_.Advance();
716     SkipUninteresting();
717   }
718 
719  private:
SkipUninteresting()720   void SkipUninteresting() {
721     while (current_iterator_.env() != NULL && current_iterator_.Done()) {
722       current_iterator_ = ShallowIterator(current_iterator_.env()->outer());
723     }
724   }
725 
726   ShallowIterator current_iterator_;
727 };
728 
729 
730 class LPlatformChunk;
731 class LGap;
732 class LLabel;
733 
734 // Superclass providing data and behavior common to all the
735 // arch-specific LPlatformChunk classes.
736 class LChunk : public ZoneObject {
737  public:
738   static LChunk* NewChunk(HGraph* graph);
739 
740   void AddInstruction(LInstruction* instruction, HBasicBlock* block);
741   LConstantOperand* DefineConstantOperand(HConstant* constant);
742   HConstant* LookupConstant(LConstantOperand* operand) const;
743   Representation LookupLiteralRepresentation(LConstantOperand* operand) const;
744 
745   int ParameterAt(int index);
746   int GetParameterStackSlot(int index) const;
spill_slot_count()747   int spill_slot_count() const { return spill_slot_count_; }
info()748   CompilationInfo* info() const { return info_; }
graph()749   HGraph* graph() const { return graph_; }
isolate()750   Isolate* isolate() const { return graph_->isolate(); }
instructions()751   const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
752   void AddGapMove(int index, LOperand* from, LOperand* to);
753   LGap* GetGapAt(int index) const;
754   bool IsGapAt(int index) const;
755   int NearestGapPos(int index) const;
756   void MarkEmptyBlocks();
pointer_maps()757   const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
758   LLabel* GetLabel(int block_id) const;
759   int LookupDestination(int block_id) const;
760   Label* GetAssemblyLabel(int block_id) const;
761 
inlined_closures()762   const ZoneList<Handle<JSFunction> >* inlined_closures() const {
763     return &inlined_closures_;
764   }
765 
AddInlinedClosure(Handle<JSFunction> closure)766   void AddInlinedClosure(Handle<JSFunction> closure) {
767     inlined_closures_.Add(closure, zone());
768   }
769 
zone()770   Zone* zone() const { return info_->zone(); }
771 
772   Handle<Code> Codegen();
773 
774   void set_allocated_double_registers(BitVector* allocated_registers);
allocated_double_registers()775   BitVector* allocated_double_registers() {
776     return allocated_double_registers_;
777   }
778 
779  protected:
780   LChunk(CompilationInfo* info, HGraph* graph);
781 
782   int spill_slot_count_;
783 
784  private:
785   CompilationInfo* info_;
786   HGraph* const graph_;
787   BitVector* allocated_double_registers_;
788   ZoneList<LInstruction*> instructions_;
789   ZoneList<LPointerMap*> pointer_maps_;
790   ZoneList<Handle<JSFunction> > inlined_closures_;
791 };
792 
793 
794 int StackSlotOffset(int index);
795 
796 enum NumberUntagDMode {
797   NUMBER_CANDIDATE_IS_SMI,
798   NUMBER_CANDIDATE_IS_ANY_TAGGED
799 };
800 
801 
802 class LPhase : public CompilationPhase {
803  public:
LPhase(const char * name,LChunk * chunk)804   LPhase(const char* name, LChunk* chunk)
805       : CompilationPhase(name, chunk->info()),
806         chunk_(chunk) { }
807   ~LPhase();
808 
809  private:
810   LChunk* chunk_;
811 
812   DISALLOW_COPY_AND_ASSIGN(LPhase);
813 };
814 
815 
816 } }  // namespace v8::internal
817 
818 #endif  // V8_LITHIUM_H_
819