1// Copyright 2011 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#include "v8.h"
29
30#include "factory.h"
31#include "hydrogen.h"
32
33#if V8_TARGET_ARCH_IA32
34#include "ia32/lithium-ia32.h"
35#elif V8_TARGET_ARCH_X64
36#include "x64/lithium-x64.h"
37#elif V8_TARGET_ARCH_ARM
38#include "arm/lithium-arm.h"
39#elif V8_TARGET_ARCH_MIPS
40#include "mips/lithium-mips.h"
41#else
42#error Unsupported target architecture.
43#endif
44
45namespace v8 {
46namespace internal {
47
48#define DEFINE_COMPILE(type)                                         \
49  LInstruction* H##type::CompileToLithium(LChunkBuilder* builder) {  \
50    return builder->Do##type(this);                                  \
51  }
52HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
53#undef DEFINE_COMPILE
54
55
56const char* Representation::Mnemonic() const {
57  switch (kind_) {
58    case kNone: return "v";
59    case kTagged: return "t";
60    case kDouble: return "d";
61    case kInteger32: return "i";
62    case kExternal: return "x";
63    case kNumRepresentations:
64      UNREACHABLE();
65      return NULL;
66  }
67  UNREACHABLE();
68  return NULL;
69}
70
71
72static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) {
73  if (result > kMaxInt) {
74    *overflow = true;
75    return kMaxInt;
76  }
77  if (result < kMinInt) {
78    *overflow = true;
79    return kMinInt;
80  }
81  return static_cast<int32_t>(result);
82}
83
84
85static int32_t AddWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
86  int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b);
87  return ConvertAndSetOverflow(result, overflow);
88}
89
90
91static int32_t SubWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
92  int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b);
93  return ConvertAndSetOverflow(result, overflow);
94}
95
96
97static int32_t MulWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
98  int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b);
99  return ConvertAndSetOverflow(result, overflow);
100}
101
102
103int32_t Range::Mask() const {
104  if (lower_ == upper_) return lower_;
105  if (lower_ >= 0) {
106    int32_t res = 1;
107    while (res < upper_) {
108      res = (res << 1) | 1;
109    }
110    return res;
111  }
112  return 0xffffffff;
113}
114
115
116void Range::AddConstant(int32_t value) {
117  if (value == 0) return;
118  bool may_overflow = false;  // Overflow is ignored here.
119  lower_ = AddWithoutOverflow(lower_, value, &may_overflow);
120  upper_ = AddWithoutOverflow(upper_, value, &may_overflow);
121  Verify();
122}
123
124
125void Range::Intersect(Range* other) {
126  upper_ = Min(upper_, other->upper_);
127  lower_ = Max(lower_, other->lower_);
128  bool b = CanBeMinusZero() && other->CanBeMinusZero();
129  set_can_be_minus_zero(b);
130}
131
132
133void Range::Union(Range* other) {
134  upper_ = Max(upper_, other->upper_);
135  lower_ = Min(lower_, other->lower_);
136  bool b = CanBeMinusZero() || other->CanBeMinusZero();
137  set_can_be_minus_zero(b);
138}
139
140
141void Range::Sar(int32_t value) {
142  int32_t bits = value & 0x1F;
143  lower_ = lower_ >> bits;
144  upper_ = upper_ >> bits;
145  set_can_be_minus_zero(false);
146}
147
148
149void Range::Shl(int32_t value) {
150  int32_t bits = value & 0x1F;
151  int old_lower = lower_;
152  int old_upper = upper_;
153  lower_ = lower_ << bits;
154  upper_ = upper_ << bits;
155  if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) {
156    upper_ = kMaxInt;
157    lower_ = kMinInt;
158  }
159  set_can_be_minus_zero(false);
160}
161
162
163bool Range::AddAndCheckOverflow(Range* other) {
164  bool may_overflow = false;
165  lower_ = AddWithoutOverflow(lower_, other->lower(), &may_overflow);
166  upper_ = AddWithoutOverflow(upper_, other->upper(), &may_overflow);
167  KeepOrder();
168  Verify();
169  return may_overflow;
170}
171
172
173bool Range::SubAndCheckOverflow(Range* other) {
174  bool may_overflow = false;
175  lower_ = SubWithoutOverflow(lower_, other->upper(), &may_overflow);
176  upper_ = SubWithoutOverflow(upper_, other->lower(), &may_overflow);
177  KeepOrder();
178  Verify();
179  return may_overflow;
180}
181
182
183void Range::KeepOrder() {
184  if (lower_ > upper_) {
185    int32_t tmp = lower_;
186    lower_ = upper_;
187    upper_ = tmp;
188  }
189}
190
191
192void Range::Verify() const {
193  ASSERT(lower_ <= upper_);
194}
195
196
197bool Range::MulAndCheckOverflow(Range* other) {
198  bool may_overflow = false;
199  int v1 = MulWithoutOverflow(lower_, other->lower(), &may_overflow);
200  int v2 = MulWithoutOverflow(lower_, other->upper(), &may_overflow);
201  int v3 = MulWithoutOverflow(upper_, other->lower(), &may_overflow);
202  int v4 = MulWithoutOverflow(upper_, other->upper(), &may_overflow);
203  lower_ = Min(Min(v1, v2), Min(v3, v4));
204  upper_ = Max(Max(v1, v2), Max(v3, v4));
205  Verify();
206  return may_overflow;
207}
208
209
210const char* HType::ToString() {
211  switch (type_) {
212    case kTagged: return "tagged";
213    case kTaggedPrimitive: return "primitive";
214    case kTaggedNumber: return "number";
215    case kSmi: return "smi";
216    case kHeapNumber: return "heap-number";
217    case kString: return "string";
218    case kBoolean: return "boolean";
219    case kNonPrimitive: return "non-primitive";
220    case kJSArray: return "array";
221    case kJSObject: return "object";
222    case kUninitialized: return "uninitialized";
223  }
224  UNREACHABLE();
225  return "Unreachable code";
226}
227
228
229const char* HType::ToShortString() {
230  switch (type_) {
231    case kTagged: return "t";
232    case kTaggedPrimitive: return "p";
233    case kTaggedNumber: return "n";
234    case kSmi: return "m";
235    case kHeapNumber: return "h";
236    case kString: return "s";
237    case kBoolean: return "b";
238    case kNonPrimitive: return "r";
239    case kJSArray: return "a";
240    case kJSObject: return "o";
241    case kUninitialized: return "z";
242  }
243  UNREACHABLE();
244  return "Unreachable code";
245}
246
247
248HType HType::TypeFromValue(Handle<Object> value) {
249  HType result = HType::Tagged();
250  if (value->IsSmi()) {
251    result = HType::Smi();
252  } else if (value->IsHeapNumber()) {
253    result = HType::HeapNumber();
254  } else if (value->IsString()) {
255    result = HType::String();
256  } else if (value->IsBoolean()) {
257    result = HType::Boolean();
258  } else if (value->IsJSObject()) {
259    result = HType::JSObject();
260  } else if (value->IsJSArray()) {
261    result = HType::JSArray();
262  }
263  return result;
264}
265
266
267int HValue::LookupOperandIndex(int occurrence_index, HValue* op) {
268  for (int i = 0; i < OperandCount(); ++i) {
269    if (OperandAt(i) == op) {
270      if (occurrence_index == 0) return i;
271      --occurrence_index;
272    }
273  }
274  return -1;
275}
276
277
278bool HValue::IsDefinedAfter(HBasicBlock* other) const {
279  return block()->block_id() > other->block_id();
280}
281
282
283bool HValue::UsesMultipleTimes(HValue* op) {
284  bool seen = false;
285  for (int i = 0; i < OperandCount(); ++i) {
286    if (OperandAt(i) == op) {
287      if (seen) return true;
288      seen = true;
289    }
290  }
291  return false;
292}
293
294
295bool HValue::Equals(HValue* other) {
296  if (other->opcode() != opcode()) return false;
297  if (!other->representation().Equals(representation())) return false;
298  if (!other->type_.Equals(type_)) return false;
299  if (other->flags() != flags()) return false;
300  if (OperandCount() != other->OperandCount()) return false;
301  for (int i = 0; i < OperandCount(); ++i) {
302    if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false;
303  }
304  bool result = DataEquals(other);
305  ASSERT(!result || Hashcode() == other->Hashcode());
306  return result;
307}
308
309
310intptr_t HValue::Hashcode() {
311  intptr_t result = opcode();
312  int count = OperandCount();
313  for (int i = 0; i < count; ++i) {
314    result = result * 19 + OperandAt(i)->id() + (result >> 7);
315  }
316  return result;
317}
318
319
320void HValue::SetOperandAt(int index, HValue* value) {
321  ASSERT(value == NULL || !value->representation().IsNone());
322  RegisterUse(index, value);
323  InternalSetOperandAt(index, value);
324}
325
326
327void HValue::ReplaceAndDelete(HValue* other) {
328  if (other != NULL) ReplaceValue(other);
329  Delete();
330}
331
332
333void HValue::ReplaceValue(HValue* other) {
334  for (int i = 0; i < uses_.length(); ++i) {
335    HValue* use = uses_[i];
336    ASSERT(!use->block()->IsStartBlock());
337    InternalReplaceAtUse(use, other);
338    other->uses_.Add(use);
339  }
340  uses_.Rewind(0);
341}
342
343
344void HValue::ClearOperands() {
345  for (int i = 0; i < OperandCount(); ++i) {
346    SetOperandAt(i, NULL);
347  }
348}
349
350
351void HValue::Delete() {
352  ASSERT(HasNoUses());
353  ClearOperands();
354  DeleteFromGraph();
355}
356
357
358void HValue::ReplaceAtUse(HValue* use, HValue* other) {
359  for (int i = 0; i < use->OperandCount(); ++i) {
360    if (use->OperandAt(i) == this) {
361      use->SetOperandAt(i, other);
362    }
363  }
364}
365
366
367void HValue::ReplaceFirstAtUse(HValue* use, HValue* other, Representation r) {
368  for (int i = 0; i < use->OperandCount(); ++i) {
369    if (use->RequiredInputRepresentation(i).Equals(r) &&
370        use->OperandAt(i) == this) {
371      use->SetOperandAt(i, other);
372      return;
373    }
374  }
375}
376
377
378void HValue::InternalReplaceAtUse(HValue* use, HValue* other) {
379  for (int i = 0; i < use->OperandCount(); ++i) {
380    if (use->OperandAt(i) == this) {
381      // Call internal method that does not update use lists. The caller is
382      // responsible for doing so.
383      use->InternalSetOperandAt(i, other);
384    }
385  }
386}
387
388
389void HValue::SetBlock(HBasicBlock* block) {
390  ASSERT(block_ == NULL || block == NULL);
391  block_ = block;
392  if (id_ == kNoNumber && block != NULL) {
393    id_ = block->graph()->GetNextValueID(this);
394  }
395}
396
397
398void HValue::PrintTypeTo(HType type, StringStream* stream) {
399  stream->Add(type.ToShortString());
400}
401
402
403void HValue::PrintNameTo(StringStream* stream) {
404  stream->Add("%s%d", representation_.Mnemonic(), id());
405}
406
407
408bool HValue::UpdateInferredType() {
409  HType type = CalculateInferredType();
410  bool result = (!type.Equals(type_));
411  type_ = type;
412  return result;
413}
414
415
416void HValue::RegisterUse(int index, HValue* new_value) {
417  HValue* old_value = OperandAt(index);
418  if (old_value == new_value) return;
419  if (old_value != NULL) old_value->uses_.RemoveElement(this);
420  if (new_value != NULL) {
421    new_value->uses_.Add(this);
422  }
423}
424
425
426void HValue::AddNewRange(Range* r) {
427  if (!HasRange()) ComputeInitialRange();
428  if (!HasRange()) range_ = new Range();
429  ASSERT(HasRange());
430  r->StackUpon(range_);
431  range_ = r;
432}
433
434
435void HValue::RemoveLastAddedRange() {
436  ASSERT(HasRange());
437  ASSERT(range_->next() != NULL);
438  range_ = range_->next();
439}
440
441
442void HValue::ComputeInitialRange() {
443  ASSERT(!HasRange());
444  range_ = InferRange();
445  ASSERT(HasRange());
446}
447
448
449void HInstruction::PrintTo(StringStream* stream) {
450  stream->Add("%s", Mnemonic());
451  if (HasSideEffects()) stream->Add("*");
452  stream->Add(" ");
453  PrintDataTo(stream);
454
455  if (range() != NULL &&
456      !range()->IsMostGeneric() &&
457      !range()->CanBeMinusZero()) {
458    stream->Add(" range[%d,%d,m0=%d]",
459                range()->lower(),
460                range()->upper(),
461                static_cast<int>(range()->CanBeMinusZero()));
462  }
463
464  int changes_flags = (flags() & HValue::ChangesFlagsMask());
465  if (changes_flags != 0) {
466    stream->Add(" changes[0x%x]", changes_flags);
467  }
468
469  if (representation().IsTagged() && !type().Equals(HType::Tagged())) {
470    stream->Add(" type[%s]", type().ToString());
471  }
472}
473
474
475void HInstruction::Unlink() {
476  ASSERT(IsLinked());
477  ASSERT(!IsControlInstruction());  // Must never move control instructions.
478  ASSERT(!IsBlockEntry());  // Doesn't make sense to delete these.
479  ASSERT(previous_ != NULL);
480  previous_->next_ = next_;
481  if (next_ == NULL) {
482    ASSERT(block()->last() == this);
483    block()->set_last(previous_);
484  } else {
485    next_->previous_ = previous_;
486  }
487  clear_block();
488}
489
490
491void HInstruction::InsertBefore(HInstruction* next) {
492  ASSERT(!IsLinked());
493  ASSERT(!next->IsBlockEntry());
494  ASSERT(!IsControlInstruction());
495  ASSERT(!next->block()->IsStartBlock());
496  ASSERT(next->previous_ != NULL);
497  HInstruction* prev = next->previous();
498  prev->next_ = this;
499  next->previous_ = this;
500  next_ = next;
501  previous_ = prev;
502  SetBlock(next->block());
503}
504
505
506void HInstruction::InsertAfter(HInstruction* previous) {
507  ASSERT(!IsLinked());
508  ASSERT(!previous->IsControlInstruction());
509  ASSERT(!IsControlInstruction() || previous->next_ == NULL);
510  HBasicBlock* block = previous->block();
511  // Never insert anything except constants into the start block after finishing
512  // it.
513  if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) {
514    ASSERT(block->end()->SecondSuccessor() == NULL);
515    InsertAfter(block->end()->FirstSuccessor()->first());
516    return;
517  }
518
519  // If we're inserting after an instruction with side-effects that is
520  // followed by a simulate instruction, we need to insert after the
521  // simulate instruction instead.
522  HInstruction* next = previous->next_;
523  if (previous->HasSideEffects() && next != NULL) {
524    ASSERT(next->IsSimulate());
525    previous = next;
526    next = previous->next_;
527  }
528
529  previous_ = previous;
530  next_ = next;
531  SetBlock(block);
532  previous->next_ = this;
533  if (next != NULL) next->previous_ = this;
534}
535
536
537#ifdef DEBUG
538void HInstruction::Verify() {
539  // Verify that input operands are defined before use.
540  HBasicBlock* cur_block = block();
541  for (int i = 0; i < OperandCount(); ++i) {
542    HValue* other_operand = OperandAt(i);
543    HBasicBlock* other_block = other_operand->block();
544    if (cur_block == other_block) {
545      if (!other_operand->IsPhi()) {
546        HInstruction* cur = cur_block->first();
547        while (cur != NULL) {
548          ASSERT(cur != this);  // We should reach other_operand before!
549          if (cur == other_operand) break;
550          cur = cur->next();
551        }
552        // Must reach other operand in the same block!
553        ASSERT(cur == other_operand);
554      }
555    } else {
556      ASSERT(other_block->Dominates(cur_block));
557    }
558  }
559
560  // Verify that instructions that may have side-effects are followed
561  // by a simulate instruction.
562  if (HasSideEffects() && !IsOsrEntry()) {
563    ASSERT(next()->IsSimulate());
564  }
565
566  // Verify that instructions that can be eliminated by GVN have overridden
567  // HValue::DataEquals.  The default implementation is UNREACHABLE.  We
568  // don't actually care whether DataEquals returns true or false here.
569  if (CheckFlag(kUseGVN)) DataEquals(this);
570}
571#endif
572
573
574void HUnaryCall::PrintDataTo(StringStream* stream) {
575  value()->PrintNameTo(stream);
576  stream->Add(" ");
577  stream->Add("#%d", argument_count());
578}
579
580
581void HBinaryCall::PrintDataTo(StringStream* stream) {
582  first()->PrintNameTo(stream);
583  stream->Add(" ");
584  second()->PrintNameTo(stream);
585  stream->Add(" ");
586  stream->Add("#%d", argument_count());
587}
588
589
590void HCallConstantFunction::PrintDataTo(StringStream* stream) {
591  if (IsApplyFunction()) {
592    stream->Add("optimized apply ");
593  } else {
594    stream->Add("%o ", function()->shared()->DebugName());
595  }
596  stream->Add("#%d", argument_count());
597}
598
599
600void HCallNamed::PrintDataTo(StringStream* stream) {
601  stream->Add("%o ", *name());
602  HUnaryCall::PrintDataTo(stream);
603}
604
605
606void HCallGlobal::PrintDataTo(StringStream* stream) {
607  stream->Add("%o ", *name());
608  HUnaryCall::PrintDataTo(stream);
609}
610
611
612void HCallKnownGlobal::PrintDataTo(StringStream* stream) {
613  stream->Add("o ", target()->shared()->DebugName());
614  stream->Add("#%d", argument_count());
615}
616
617
618void HCallRuntime::PrintDataTo(StringStream* stream) {
619  stream->Add("%o ", *name());
620  stream->Add("#%d", argument_count());
621}
622
623
624void HClassOfTest::PrintDataTo(StringStream* stream) {
625  stream->Add("class_of_test(");
626  value()->PrintNameTo(stream);
627  stream->Add(", \"%o\")", *class_name());
628}
629
630
631void HAccessArgumentsAt::PrintDataTo(StringStream* stream) {
632  arguments()->PrintNameTo(stream);
633  stream->Add("[");
634  index()->PrintNameTo(stream);
635  stream->Add("], length ");
636  length()->PrintNameTo(stream);
637}
638
639
640void HControlInstruction::PrintDataTo(StringStream* stream) {
641  if (FirstSuccessor() != NULL) {
642    int first_id = FirstSuccessor()->block_id();
643    if (SecondSuccessor() == NULL) {
644      stream->Add(" B%d", first_id);
645    } else {
646      int second_id = SecondSuccessor()->block_id();
647      stream->Add(" goto (B%d, B%d)", first_id, second_id);
648    }
649  }
650}
651
652
653void HUnaryControlInstruction::PrintDataTo(StringStream* stream) {
654  value()->PrintNameTo(stream);
655  HControlInstruction::PrintDataTo(stream);
656}
657
658
659void HCompareMap::PrintDataTo(StringStream* stream) {
660  value()->PrintNameTo(stream);
661  stream->Add(" (%p)", *map());
662  HControlInstruction::PrintDataTo(stream);
663}
664
665
666const char* HUnaryMathOperation::OpName() const {
667  switch (op()) {
668    case kMathFloor: return "floor";
669    case kMathRound: return "round";
670    case kMathCeil: return "ceil";
671    case kMathAbs: return "abs";
672    case kMathLog: return "log";
673    case kMathSin: return "sin";
674    case kMathCos: return "cos";
675    case kMathTan: return "tan";
676    case kMathASin: return "asin";
677    case kMathACos: return "acos";
678    case kMathATan: return "atan";
679    case kMathExp: return "exp";
680    case kMathSqrt: return "sqrt";
681    default: break;
682  }
683  return "(unknown operation)";
684}
685
686
687void HUnaryMathOperation::PrintDataTo(StringStream* stream) {
688  const char* name = OpName();
689  stream->Add("%s ", name);
690  value()->PrintNameTo(stream);
691}
692
693
694void HUnaryOperation::PrintDataTo(StringStream* stream) {
695  value()->PrintNameTo(stream);
696}
697
698
699void HHasInstanceType::PrintDataTo(StringStream* stream) {
700  value()->PrintNameTo(stream);
701  switch (from_) {
702    case FIRST_JS_OBJECT_TYPE:
703      if (to_ == LAST_TYPE) stream->Add(" spec_object");
704      break;
705    case JS_REGEXP_TYPE:
706      if (to_ == JS_REGEXP_TYPE) stream->Add(" reg_exp");
707      break;
708    case JS_ARRAY_TYPE:
709      if (to_ == JS_ARRAY_TYPE) stream->Add(" array");
710      break;
711    case JS_FUNCTION_TYPE:
712      if (to_ == JS_FUNCTION_TYPE) stream->Add(" function");
713      break;
714    default:
715      break;
716  }
717}
718
719
720void HTypeofIs::PrintDataTo(StringStream* stream) {
721  value()->PrintNameTo(stream);
722  stream->Add(" == ");
723  stream->Add(type_literal_->ToAsciiVector());
724}
725
726
727void HChange::PrintDataTo(StringStream* stream) {
728  HUnaryOperation::PrintDataTo(stream);
729  stream->Add(" %s to %s", from_.Mnemonic(), to().Mnemonic());
730
731  if (CanTruncateToInt32()) stream->Add(" truncating-int32");
732  if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
733}
734
735
736HCheckInstanceType* HCheckInstanceType::NewIsJSObjectOrJSFunction(
737    HValue* value)  {
738  STATIC_ASSERT((LAST_JS_OBJECT_TYPE + 1) == JS_FUNCTION_TYPE);
739  return new HCheckInstanceType(value, FIRST_JS_OBJECT_TYPE, JS_FUNCTION_TYPE);
740}
741
742
743void HCheckMap::PrintDataTo(StringStream* stream) {
744  value()->PrintNameTo(stream);
745  stream->Add(" %p", *map());
746}
747
748
749void HCheckFunction::PrintDataTo(StringStream* stream) {
750  value()->PrintNameTo(stream);
751  stream->Add(" %p", *target());
752}
753
754
755void HCallStub::PrintDataTo(StringStream* stream) {
756  stream->Add("%s ",
757              CodeStub::MajorName(major_key_, false));
758  HUnaryCall::PrintDataTo(stream);
759}
760
761
762void HInstanceOf::PrintDataTo(StringStream* stream) {
763  left()->PrintNameTo(stream);
764  stream->Add(" ");
765  right()->PrintNameTo(stream);
766  stream->Add(" ");
767  context()->PrintNameTo(stream);
768}
769
770
771Range* HValue::InferRange() {
772  if (representation().IsTagged()) {
773    // Tagged values are always in int32 range when converted to integer,
774    // but they can contain -0.
775    Range* result = new Range();
776    result->set_can_be_minus_zero(true);
777    return result;
778  } else if (representation().IsNone()) {
779    return NULL;
780  } else {
781    // Untagged integer32 cannot be -0 and we don't compute ranges for
782    // untagged doubles.
783    return new Range();
784  }
785}
786
787
788Range* HConstant::InferRange() {
789  if (has_int32_value_) {
790    Range* result = new Range(int32_value_, int32_value_);
791    result->set_can_be_minus_zero(false);
792    return result;
793  }
794  return HValue::InferRange();
795}
796
797
798Range* HPhi::InferRange() {
799  if (representation().IsInteger32()) {
800    if (block()->IsLoopHeader()) {
801      Range* range = new Range(kMinInt, kMaxInt);
802      return range;
803    } else {
804      Range* range = OperandAt(0)->range()->Copy();
805      for (int i = 1; i < OperandCount(); ++i) {
806        range->Union(OperandAt(i)->range());
807      }
808      return range;
809    }
810  } else {
811    return HValue::InferRange();
812  }
813}
814
815
816Range* HAdd::InferRange() {
817  if (representation().IsInteger32()) {
818    Range* a = left()->range();
819    Range* b = right()->range();
820    Range* res = a->Copy();
821    if (!res->AddAndCheckOverflow(b)) {
822      ClearFlag(kCanOverflow);
823    }
824    bool m0 = a->CanBeMinusZero() && b->CanBeMinusZero();
825    res->set_can_be_minus_zero(m0);
826    return res;
827  } else {
828    return HValue::InferRange();
829  }
830}
831
832
833Range* HSub::InferRange() {
834  if (representation().IsInteger32()) {
835    Range* a = left()->range();
836    Range* b = right()->range();
837    Range* res = a->Copy();
838    if (!res->SubAndCheckOverflow(b)) {
839      ClearFlag(kCanOverflow);
840    }
841    res->set_can_be_minus_zero(a->CanBeMinusZero() && b->CanBeZero());
842    return res;
843  } else {
844    return HValue::InferRange();
845  }
846}
847
848
849Range* HMul::InferRange() {
850  if (representation().IsInteger32()) {
851    Range* a = left()->range();
852    Range* b = right()->range();
853    Range* res = a->Copy();
854    if (!res->MulAndCheckOverflow(b)) {
855      ClearFlag(kCanOverflow);
856    }
857    bool m0 = (a->CanBeZero() && b->CanBeNegative()) ||
858        (a->CanBeNegative() && b->CanBeZero());
859    res->set_can_be_minus_zero(m0);
860    return res;
861  } else {
862    return HValue::InferRange();
863  }
864}
865
866
867Range* HDiv::InferRange() {
868  if (representation().IsInteger32()) {
869    Range* result = new Range();
870    if (left()->range()->CanBeMinusZero()) {
871      result->set_can_be_minus_zero(true);
872    }
873
874    if (left()->range()->CanBeZero() && right()->range()->CanBeNegative()) {
875      result->set_can_be_minus_zero(true);
876    }
877
878    if (right()->range()->Includes(-1) && left()->range()->Includes(kMinInt)) {
879      SetFlag(HValue::kCanOverflow);
880    }
881
882    if (!right()->range()->CanBeZero()) {
883      ClearFlag(HValue::kCanBeDivByZero);
884    }
885    return result;
886  } else {
887    return HValue::InferRange();
888  }
889}
890
891
892Range* HMod::InferRange() {
893  if (representation().IsInteger32()) {
894    Range* a = left()->range();
895    Range* result = new Range();
896    if (a->CanBeMinusZero() || a->CanBeNegative()) {
897      result->set_can_be_minus_zero(true);
898    }
899    if (!right()->range()->CanBeZero()) {
900      ClearFlag(HValue::kCanBeDivByZero);
901    }
902    return result;
903  } else {
904    return HValue::InferRange();
905  }
906}
907
908
909void HPhi::PrintTo(StringStream* stream) {
910  stream->Add("[");
911  for (int i = 0; i < OperandCount(); ++i) {
912    HValue* value = OperandAt(i);
913    stream->Add(" ");
914    value->PrintNameTo(stream);
915    stream->Add(" ");
916  }
917  stream->Add(" uses%d_%di_%dd_%dt]",
918              uses()->length(),
919              int32_non_phi_uses() + int32_indirect_uses(),
920              double_non_phi_uses() + double_indirect_uses(),
921              tagged_non_phi_uses() + tagged_indirect_uses());
922}
923
924
925void HPhi::AddInput(HValue* value) {
926  inputs_.Add(NULL);
927  SetOperandAt(OperandCount() - 1, value);
928  // Mark phis that may have 'arguments' directly or indirectly as an operand.
929  if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) {
930    SetFlag(kIsArguments);
931  }
932}
933
934
935bool HPhi::HasRealUses() {
936  for (int i = 0; i < uses()->length(); i++) {
937    if (!uses()->at(i)->IsPhi()) return true;
938  }
939  return false;
940}
941
942
943HValue* HPhi::GetRedundantReplacement() {
944  HValue* candidate = NULL;
945  int count = OperandCount();
946  int position = 0;
947  while (position < count && candidate == NULL) {
948    HValue* current = OperandAt(position++);
949    if (current != this) candidate = current;
950  }
951  while (position < count) {
952    HValue* current = OperandAt(position++);
953    if (current != this && current != candidate) return NULL;
954  }
955  ASSERT(candidate != this);
956  return candidate;
957}
958
959
960void HPhi::DeleteFromGraph() {
961  ASSERT(block() != NULL);
962  block()->RemovePhi(this);
963  ASSERT(block() == NULL);
964}
965
966
967void HPhi::InitRealUses(int phi_id) {
968  // Initialize real uses.
969  phi_id_ = phi_id;
970  for (int j = 0; j < uses()->length(); j++) {
971    HValue* use = uses()->at(j);
972    if (!use->IsPhi()) {
973      int index = use->LookupOperandIndex(0, this);
974      Representation req_rep = use->RequiredInputRepresentation(index);
975      non_phi_uses_[req_rep.kind()]++;
976    }
977  }
978}
979
980
981void HPhi::AddNonPhiUsesFrom(HPhi* other) {
982  for (int i = 0; i < Representation::kNumRepresentations; i++) {
983    indirect_uses_[i] += other->non_phi_uses_[i];
984  }
985}
986
987
988void HPhi::AddIndirectUsesTo(int* dest) {
989  for (int i = 0; i < Representation::kNumRepresentations; i++) {
990    dest[i] += indirect_uses_[i];
991  }
992}
993
994
995void HSimulate::PrintDataTo(StringStream* stream) {
996  stream->Add("id=%d ", ast_id());
997  if (pop_count_ > 0) stream->Add("pop %d", pop_count_);
998  if (values_.length() > 0) {
999    if (pop_count_ > 0) stream->Add(" /");
1000    for (int i = 0; i < values_.length(); ++i) {
1001      if (!HasAssignedIndexAt(i)) {
1002        stream->Add(" push ");
1003      } else {
1004        stream->Add(" var[%d] = ", GetAssignedIndexAt(i));
1005      }
1006      values_[i]->PrintNameTo(stream);
1007    }
1008  }
1009}
1010
1011
1012void HEnterInlined::PrintDataTo(StringStream* stream) {
1013  SmartPointer<char> name = function()->debug_name()->ToCString();
1014  stream->Add("%s, id=%d", *name, function()->id());
1015}
1016
1017
1018HConstant::HConstant(Handle<Object> handle, Representation r)
1019    : handle_(handle),
1020      constant_type_(HType::TypeFromValue(handle)),
1021      has_int32_value_(false),
1022      int32_value_(0),
1023      has_double_value_(false),
1024      double_value_(0)  {
1025  set_representation(r);
1026  SetFlag(kUseGVN);
1027  if (handle_->IsNumber()) {
1028    double n = handle_->Number();
1029    double roundtrip_value = static_cast<double>(static_cast<int32_t>(n));
1030    has_int32_value_ = BitCast<int64_t>(roundtrip_value) == BitCast<int64_t>(n);
1031    if (has_int32_value_) int32_value_ = static_cast<int32_t>(n);
1032    double_value_ = n;
1033    has_double_value_ = true;
1034  }
1035}
1036
1037
1038HConstant* HConstant::CopyToRepresentation(Representation r) const {
1039  if (r.IsInteger32() && !has_int32_value_) return NULL;
1040  if (r.IsDouble() && !has_double_value_) return NULL;
1041  return new HConstant(handle_, r);
1042}
1043
1044
1045HConstant* HConstant::CopyToTruncatedInt32() const {
1046  if (!has_double_value_) return NULL;
1047  int32_t truncated = NumberToInt32(*handle_);
1048  return new HConstant(FACTORY->NewNumberFromInt(truncated),
1049                       Representation::Integer32());
1050}
1051
1052
1053bool HConstant::ToBoolean() const {
1054  // Converts the constant's boolean value according to
1055  // ECMAScript section 9.2 ToBoolean conversion.
1056  if (HasInteger32Value()) return Integer32Value() != 0;
1057  if (HasDoubleValue()) {
1058    double v = DoubleValue();
1059    return v != 0 && !isnan(v);
1060  }
1061  if (handle()->IsTrue()) return true;
1062  if (handle()->IsFalse()) return false;
1063  if (handle()->IsUndefined()) return false;
1064  if (handle()->IsNull()) return false;
1065  if (handle()->IsString() &&
1066      String::cast(*handle())->length() == 0) return false;
1067  return true;
1068}
1069
1070void HConstant::PrintDataTo(StringStream* stream) {
1071  handle()->ShortPrint(stream);
1072}
1073
1074
1075bool HArrayLiteral::IsCopyOnWrite() const {
1076  return constant_elements()->map() == HEAP->fixed_cow_array_map();
1077}
1078
1079
1080void HBinaryOperation::PrintDataTo(StringStream* stream) {
1081  left()->PrintNameTo(stream);
1082  stream->Add(" ");
1083  right()->PrintNameTo(stream);
1084  if (CheckFlag(kCanOverflow)) stream->Add(" !");
1085  if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
1086}
1087
1088
1089Range* HBitAnd::InferRange() {
1090  int32_t left_mask = (left()->range() != NULL)
1091      ? left()->range()->Mask()
1092      : 0xffffffff;
1093  int32_t right_mask = (right()->range() != NULL)
1094      ? right()->range()->Mask()
1095      : 0xffffffff;
1096  int32_t result_mask = left_mask & right_mask;
1097  return (result_mask >= 0)
1098      ? new Range(0, result_mask)
1099      : HValue::InferRange();
1100}
1101
1102
1103Range* HBitOr::InferRange() {
1104  int32_t left_mask = (left()->range() != NULL)
1105      ? left()->range()->Mask()
1106      : 0xffffffff;
1107  int32_t right_mask = (right()->range() != NULL)
1108      ? right()->range()->Mask()
1109      : 0xffffffff;
1110  int32_t result_mask = left_mask | right_mask;
1111  return (result_mask >= 0)
1112      ? new Range(0, result_mask)
1113      : HValue::InferRange();
1114}
1115
1116
1117Range* HSar::InferRange() {
1118  if (right()->IsConstant()) {
1119    HConstant* c = HConstant::cast(right());
1120    if (c->HasInteger32Value()) {
1121      Range* result = (left()->range() != NULL)
1122          ? left()->range()->Copy()
1123          : new Range();
1124      result->Sar(c->Integer32Value());
1125      return result;
1126    }
1127  }
1128  return HValue::InferRange();
1129}
1130
1131
1132Range* HShl::InferRange() {
1133  if (right()->IsConstant()) {
1134    HConstant* c = HConstant::cast(right());
1135    if (c->HasInteger32Value()) {
1136      Range* result = (left()->range() != NULL)
1137          ? left()->range()->Copy()
1138          : new Range();
1139      result->Shl(c->Integer32Value());
1140      return result;
1141    }
1142  }
1143  return HValue::InferRange();
1144}
1145
1146
1147
1148void HCompare::PrintDataTo(StringStream* stream) {
1149  stream->Add(Token::Name(token()));
1150  stream->Add(" ");
1151  HBinaryOperation::PrintDataTo(stream);
1152}
1153
1154
1155void HCompare::SetInputRepresentation(Representation r) {
1156  input_representation_ = r;
1157  if (r.IsTagged()) {
1158    SetAllSideEffects();
1159    ClearFlag(kUseGVN);
1160  } else if (r.IsDouble()) {
1161    SetFlag(kDeoptimizeOnUndefined);
1162    ClearAllSideEffects();
1163    SetFlag(kUseGVN);
1164  } else {
1165    ClearAllSideEffects();
1166    SetFlag(kUseGVN);
1167  }
1168}
1169
1170
1171void HParameter::PrintDataTo(StringStream* stream) {
1172  stream->Add("%u", index());
1173}
1174
1175
1176void HLoadNamedField::PrintDataTo(StringStream* stream) {
1177  object()->PrintNameTo(stream);
1178  stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
1179}
1180
1181
1182HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* object,
1183                                                       ZoneMapList* types,
1184                                                       Handle<String> name)
1185    : HUnaryOperation(object),
1186      types_(Min(types->length(), kMaxLoadPolymorphism)),
1187      name_(name),
1188      need_generic_(false) {
1189  set_representation(Representation::Tagged());
1190  SetFlag(kDependsOnMaps);
1191  for (int i = 0;
1192       i < types->length() && types_.length() < kMaxLoadPolymorphism;
1193       ++i) {
1194    Handle<Map> map = types->at(i);
1195    LookupResult lookup;
1196    map->LookupInDescriptors(NULL, *name, &lookup);
1197    if (lookup.IsProperty() && lookup.type() == FIELD) {
1198      types_.Add(types->at(i));
1199      int index = lookup.GetLocalFieldIndexFromMap(*map);
1200      if (index < 0) {
1201        SetFlag(kDependsOnInobjectFields);
1202      } else {
1203        SetFlag(kDependsOnBackingStoreFields);
1204      }
1205    }
1206  }
1207
1208  if (types_.length() == types->length() && FLAG_deoptimize_uncommon_cases) {
1209    SetFlag(kUseGVN);
1210  } else {
1211    SetAllSideEffects();
1212    need_generic_ = true;
1213  }
1214}
1215
1216
1217bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
1218  HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
1219  if (types_.length() != other->types()->length()) return false;
1220  if (!name_.is_identical_to(other->name())) return false;
1221  if (need_generic_ != other->need_generic_) return false;
1222  for (int i = 0; i < types_.length(); i++) {
1223    bool found = false;
1224    for (int j = 0; j < types_.length(); j++) {
1225      if (types_.at(j).is_identical_to(other->types()->at(i))) {
1226        found = true;
1227        break;
1228      }
1229    }
1230    if (!found) return false;
1231  }
1232  return true;
1233}
1234
1235
1236void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
1237  object()->PrintNameTo(stream);
1238  stream->Add("[");
1239  key()->PrintNameTo(stream);
1240  stream->Add("]");
1241}
1242
1243
1244void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) {
1245  object()->PrintNameTo(stream);
1246  stream->Add("[");
1247  key()->PrintNameTo(stream);
1248  stream->Add("]");
1249}
1250
1251
1252void HLoadKeyedSpecializedArrayElement::PrintDataTo(
1253    StringStream* stream) {
1254  external_pointer()->PrintNameTo(stream);
1255  stream->Add(".");
1256  switch (array_type()) {
1257    case kExternalByteArray:
1258      stream->Add("byte");
1259      break;
1260    case kExternalUnsignedByteArray:
1261      stream->Add("u_byte");
1262      break;
1263    case kExternalShortArray:
1264      stream->Add("short");
1265      break;
1266    case kExternalUnsignedShortArray:
1267      stream->Add("u_short");
1268      break;
1269    case kExternalIntArray:
1270      stream->Add("int");
1271      break;
1272    case kExternalUnsignedIntArray:
1273      stream->Add("u_int");
1274      break;
1275    case kExternalFloatArray:
1276      stream->Add("float");
1277      break;
1278    case kExternalPixelArray:
1279      stream->Add("pixel");
1280      break;
1281  }
1282  stream->Add("[");
1283  key()->PrintNameTo(stream);
1284  stream->Add("]");
1285}
1286
1287
1288void HStoreNamedGeneric::PrintDataTo(StringStream* stream) {
1289  object()->PrintNameTo(stream);
1290  stream->Add(".");
1291  ASSERT(name()->IsString());
1292  stream->Add(*String::cast(*name())->ToCString());
1293  stream->Add(" = ");
1294  value()->PrintNameTo(stream);
1295}
1296
1297
1298void HStoreNamedField::PrintDataTo(StringStream* stream) {
1299  object()->PrintNameTo(stream);
1300  stream->Add(".");
1301  ASSERT(name()->IsString());
1302  stream->Add(*String::cast(*name())->ToCString());
1303  stream->Add(" = ");
1304  value()->PrintNameTo(stream);
1305  if (!transition().is_null()) {
1306    stream->Add(" (transition map %p)", *transition());
1307  }
1308}
1309
1310
1311void HStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
1312  object()->PrintNameTo(stream);
1313  stream->Add("[");
1314  key()->PrintNameTo(stream);
1315  stream->Add("] = ");
1316  value()->PrintNameTo(stream);
1317}
1318
1319
1320void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
1321  object()->PrintNameTo(stream);
1322  stream->Add("[");
1323  key()->PrintNameTo(stream);
1324  stream->Add("] = ");
1325  value()->PrintNameTo(stream);
1326}
1327
1328
1329void HStoreKeyedSpecializedArrayElement::PrintDataTo(
1330    StringStream* stream) {
1331  external_pointer()->PrintNameTo(stream);
1332  stream->Add(".");
1333  switch (array_type()) {
1334    case kExternalByteArray:
1335      stream->Add("byte");
1336      break;
1337    case kExternalUnsignedByteArray:
1338      stream->Add("u_byte");
1339      break;
1340    case kExternalShortArray:
1341      stream->Add("short");
1342      break;
1343    case kExternalUnsignedShortArray:
1344      stream->Add("u_short");
1345      break;
1346    case kExternalIntArray:
1347      stream->Add("int");
1348      break;
1349    case kExternalUnsignedIntArray:
1350      stream->Add("u_int");
1351      break;
1352    case kExternalFloatArray:
1353      stream->Add("float");
1354      break;
1355    case kExternalPixelArray:
1356      stream->Add("pixel");
1357      break;
1358  }
1359  stream->Add("[");
1360  key()->PrintNameTo(stream);
1361  stream->Add("] = ");
1362  value()->PrintNameTo(stream);
1363}
1364
1365
1366void HLoadGlobalCell::PrintDataTo(StringStream* stream) {
1367  stream->Add("[%p]", *cell());
1368  if (check_hole_value()) stream->Add(" (deleteable/read-only)");
1369}
1370
1371
1372void HLoadGlobalGeneric::PrintDataTo(StringStream* stream) {
1373  stream->Add("%o ", *name());
1374}
1375
1376
1377void HStoreGlobalCell::PrintDataTo(StringStream* stream) {
1378  stream->Add("[%p] = ", *cell());
1379  value()->PrintNameTo(stream);
1380}
1381
1382
1383void HStoreGlobalGeneric::PrintDataTo(StringStream* stream) {
1384  stream->Add("%o = ", *name());
1385  value()->PrintNameTo(stream);
1386}
1387
1388
1389void HLoadContextSlot::PrintDataTo(StringStream* stream) {
1390  value()->PrintNameTo(stream);
1391  stream->Add("[%d]", slot_index());
1392}
1393
1394
1395void HStoreContextSlot::PrintDataTo(StringStream* stream) {
1396  context()->PrintNameTo(stream);
1397  stream->Add("[%d] = ", slot_index());
1398  value()->PrintNameTo(stream);
1399}
1400
1401
1402// Implementation of type inference and type conversions. Calculates
1403// the inferred type of this instruction based on the input operands.
1404
1405HType HValue::CalculateInferredType() {
1406  return type_;
1407}
1408
1409
1410HType HCheckMap::CalculateInferredType() {
1411  return value()->type();
1412}
1413
1414
1415HType HCheckFunction::CalculateInferredType() {
1416  return value()->type();
1417}
1418
1419
1420HType HCheckNonSmi::CalculateInferredType() {
1421  // TODO(kasperl): Is there any way to signal that this isn't a smi?
1422  return HType::Tagged();
1423}
1424
1425
1426HType HCheckSmi::CalculateInferredType() {
1427  return HType::Smi();
1428}
1429
1430
1431HType HPhi::CalculateInferredType() {
1432  HType result = HType::Uninitialized();
1433  for (int i = 0; i < OperandCount(); ++i) {
1434    HType current = OperandAt(i)->type();
1435    result = result.Combine(current);
1436  }
1437  return result;
1438}
1439
1440
1441HType HConstant::CalculateInferredType() {
1442  return constant_type_;
1443}
1444
1445
1446HType HCompare::CalculateInferredType() {
1447  return HType::Boolean();
1448}
1449
1450
1451HType HCompareJSObjectEq::CalculateInferredType() {
1452  return HType::Boolean();
1453}
1454
1455
1456HType HUnaryPredicate::CalculateInferredType() {
1457  return HType::Boolean();
1458}
1459
1460
1461HType HBitwiseBinaryOperation::CalculateInferredType() {
1462  return HType::TaggedNumber();
1463}
1464
1465
1466HType HArithmeticBinaryOperation::CalculateInferredType() {
1467  return HType::TaggedNumber();
1468}
1469
1470
1471HType HAdd::CalculateInferredType() {
1472  return HType::Tagged();
1473}
1474
1475
1476HType HBitAnd::CalculateInferredType() {
1477  return HType::TaggedNumber();
1478}
1479
1480
1481HType HBitXor::CalculateInferredType() {
1482  return HType::TaggedNumber();
1483}
1484
1485
1486HType HBitOr::CalculateInferredType() {
1487  return HType::TaggedNumber();
1488}
1489
1490
1491HType HBitNot::CalculateInferredType() {
1492  return HType::TaggedNumber();
1493}
1494
1495
1496HType HUnaryMathOperation::CalculateInferredType() {
1497  return HType::TaggedNumber();
1498}
1499
1500
1501HType HShl::CalculateInferredType() {
1502  return HType::TaggedNumber();
1503}
1504
1505
1506HType HShr::CalculateInferredType() {
1507  return HType::TaggedNumber();
1508}
1509
1510
1511HType HSar::CalculateInferredType() {
1512  return HType::TaggedNumber();
1513}
1514
1515
1516HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero(
1517    BitVector* visited) {
1518  visited->Add(id());
1519  if (representation().IsInteger32() &&
1520      !value()->representation().IsInteger32()) {
1521    if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
1522      SetFlag(kBailoutOnMinusZero);
1523    }
1524  }
1525  if (RequiredInputRepresentation(0).IsInteger32() &&
1526      representation().IsInteger32()) {
1527    return value();
1528  }
1529  return NULL;
1530}
1531
1532
1533
1534HValue* HChange::EnsureAndPropagateNotMinusZero(BitVector* visited) {
1535  visited->Add(id());
1536  if (from().IsInteger32()) return NULL;
1537  if (CanTruncateToInt32()) return NULL;
1538  if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
1539    SetFlag(kBailoutOnMinusZero);
1540  }
1541  ASSERT(!from().IsInteger32() || !to().IsInteger32());
1542  return NULL;
1543}
1544
1545
1546HValue* HMod::EnsureAndPropagateNotMinusZero(BitVector* visited) {
1547  visited->Add(id());
1548  if (range() == NULL || range()->CanBeMinusZero()) {
1549    SetFlag(kBailoutOnMinusZero);
1550    return left();
1551  }
1552  return NULL;
1553}
1554
1555
1556HValue* HDiv::EnsureAndPropagateNotMinusZero(BitVector* visited) {
1557  visited->Add(id());
1558  if (range() == NULL || range()->CanBeMinusZero()) {
1559    SetFlag(kBailoutOnMinusZero);
1560  }
1561  return NULL;
1562}
1563
1564
1565HValue* HMul::EnsureAndPropagateNotMinusZero(BitVector* visited) {
1566  visited->Add(id());
1567  if (range() == NULL || range()->CanBeMinusZero()) {
1568    SetFlag(kBailoutOnMinusZero);
1569  }
1570  return NULL;
1571}
1572
1573
1574HValue* HSub::EnsureAndPropagateNotMinusZero(BitVector* visited) {
1575  visited->Add(id());
1576  // Propagate to the left argument. If the left argument cannot be -0, then
1577  // the result of the add operation cannot be either.
1578  if (range() == NULL || range()->CanBeMinusZero()) {
1579    return left();
1580  }
1581  return NULL;
1582}
1583
1584
1585HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) {
1586  visited->Add(id());
1587  // Propagate to the left argument. If the left argument cannot be -0, then
1588  // the result of the sub operation cannot be either.
1589  if (range() == NULL || range()->CanBeMinusZero()) {
1590    return left();
1591  }
1592  return NULL;
1593}
1594
1595
1596// Node-specific verification code is only included in debug mode.
1597#ifdef DEBUG
1598
1599void HPhi::Verify() {
1600  ASSERT(OperandCount() == block()->predecessors()->length());
1601  for (int i = 0; i < OperandCount(); ++i) {
1602    HValue* value = OperandAt(i);
1603    HBasicBlock* defining_block = value->block();
1604    HBasicBlock* predecessor_block = block()->predecessors()->at(i);
1605    ASSERT(defining_block == predecessor_block ||
1606           defining_block->Dominates(predecessor_block));
1607  }
1608}
1609
1610
1611void HSimulate::Verify() {
1612  HInstruction::Verify();
1613  ASSERT(HasAstId());
1614}
1615
1616
1617void HBoundsCheck::Verify() {
1618  HInstruction::Verify();
1619}
1620
1621
1622void HCheckSmi::Verify() {
1623  HInstruction::Verify();
1624  ASSERT(HasNoUses());
1625}
1626
1627
1628void HCheckNonSmi::Verify() {
1629  HInstruction::Verify();
1630  ASSERT(HasNoUses());
1631}
1632
1633
1634void HCheckInstanceType::Verify() {
1635  HInstruction::Verify();
1636  ASSERT(HasNoUses());
1637}
1638
1639
1640void HCheckMap::Verify() {
1641  HInstruction::Verify();
1642  ASSERT(HasNoUses());
1643}
1644
1645
1646void HCheckFunction::Verify() {
1647  HInstruction::Verify();
1648  ASSERT(HasNoUses());
1649}
1650
1651
1652void HCheckPrototypeMaps::Verify() {
1653  HInstruction::Verify();
1654  ASSERT(HasNoUses());
1655}
1656
1657#endif
1658
1659} }  // namespace v8::internal
1660