v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
hydrogen-instructions.cc
Go to the documentation of this file.
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 #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 
45 namespace v8 {
46 namespace internal {
47 
48 #define DEFINE_COMPILE(type) \
49  LInstruction* H##type::CompileToLithium(LChunkBuilder* builder) { \
50  return builder->Do##type(this); \
51  }
53 #undef DEFINE_COMPILE
54 
55 
56 const 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  default:
64  UNREACHABLE();
65  return NULL;
66  }
67 }
68 
69 
70 int HValue::LoopWeight() const {
71  const int w = FLAG_loop_weight;
72  static const int weights[] = { 1, w, w*w, w*w*w, w*w*w*w };
73  return weights[Min(block()->LoopNestingDepth(),
74  static_cast<int>(ARRAY_SIZE(weights)-1))];
75 }
76 
77 
81  // The representation of the value is dictated by type feedback and
82  // will not be changed later.
84  }
85 }
86 
87 
88 static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) {
89  if (result > kMaxInt) {
90  *overflow = true;
91  return kMaxInt;
92  }
93  if (result < kMinInt) {
94  *overflow = true;
95  return kMinInt;
96  }
97  return static_cast<int32_t>(result);
98 }
99 
100 
101 static int32_t AddWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
102  int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b);
103  return ConvertAndSetOverflow(result, overflow);
104 }
105 
106 
107 static int32_t SubWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
108  int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b);
109  return ConvertAndSetOverflow(result, overflow);
110 }
111 
112 
113 static int32_t MulWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
114  int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b);
115  return ConvertAndSetOverflow(result, overflow);
116 }
117 
118 
120  if (lower_ == upper_) return lower_;
121  if (lower_ >= 0) {
122  int32_t res = 1;
123  while (res < upper_) {
124  res = (res << 1) | 1;
125  }
126  return res;
127  }
128  return 0xffffffff;
129 }
130 
131 
133  if (value == 0) return;
134  bool may_overflow = false; // Overflow is ignored here.
135  lower_ = AddWithoutOverflow(lower_, value, &may_overflow);
136  upper_ = AddWithoutOverflow(upper_, value, &may_overflow);
137 #ifdef DEBUG
138  Verify();
139 #endif
140 }
141 
142 
143 void Range::Intersect(Range* other) {
144  upper_ = Min(upper_, other->upper_);
145  lower_ = Max(lower_, other->lower_);
146  bool b = CanBeMinusZero() && other->CanBeMinusZero();
148 }
149 
150 
151 void Range::Union(Range* other) {
152  upper_ = Max(upper_, other->upper_);
153  lower_ = Min(lower_, other->lower_);
154  bool b = CanBeMinusZero() || other->CanBeMinusZero();
156 }
157 
158 
159 void Range::CombinedMax(Range* other) {
160  upper_ = Max(upper_, other->upper_);
161  lower_ = Max(lower_, other->lower_);
163 }
164 
165 
166 void Range::CombinedMin(Range* other) {
167  upper_ = Min(upper_, other->upper_);
168  lower_ = Min(lower_, other->lower_);
170 }
171 
172 
173 void Range::Sar(int32_t value) {
174  int32_t bits = value & 0x1F;
175  lower_ = lower_ >> bits;
176  upper_ = upper_ >> bits;
177  set_can_be_minus_zero(false);
178 }
179 
180 
181 void Range::Shl(int32_t value) {
182  int32_t bits = value & 0x1F;
183  int old_lower = lower_;
184  int old_upper = upper_;
185  lower_ = lower_ << bits;
186  upper_ = upper_ << bits;
187  if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) {
188  upper_ = kMaxInt;
189  lower_ = kMinInt;
190  }
191  set_can_be_minus_zero(false);
192 }
193 
194 
196  bool may_overflow = false;
197  lower_ = AddWithoutOverflow(lower_, other->lower(), &may_overflow);
198  upper_ = AddWithoutOverflow(upper_, other->upper(), &may_overflow);
199  KeepOrder();
200 #ifdef DEBUG
201  Verify();
202 #endif
203  return may_overflow;
204 }
205 
206 
208  bool may_overflow = false;
209  lower_ = SubWithoutOverflow(lower_, other->upper(), &may_overflow);
210  upper_ = SubWithoutOverflow(upper_, other->lower(), &may_overflow);
211  KeepOrder();
212 #ifdef DEBUG
213  Verify();
214 #endif
215  return may_overflow;
216 }
217 
218 
220  if (lower_ > upper_) {
221  int32_t tmp = lower_;
222  lower_ = upper_;
223  upper_ = tmp;
224  }
225 }
226 
227 
228 #ifdef DEBUG
229 void Range::Verify() const {
230  ASSERT(lower_ <= upper_);
231 }
232 #endif
233 
234 
236  bool may_overflow = false;
237  int v1 = MulWithoutOverflow(lower_, other->lower(), &may_overflow);
238  int v2 = MulWithoutOverflow(lower_, other->upper(), &may_overflow);
239  int v3 = MulWithoutOverflow(upper_, other->lower(), &may_overflow);
240  int v4 = MulWithoutOverflow(upper_, other->upper(), &may_overflow);
241  lower_ = Min(Min(v1, v2), Min(v3, v4));
242  upper_ = Max(Max(v1, v2), Max(v3, v4));
243 #ifdef DEBUG
244  Verify();
245 #endif
246  return may_overflow;
247 }
248 
249 
250 const char* HType::ToString() {
251  switch (type_) {
252  case kTagged: return "tagged";
253  case kTaggedPrimitive: return "primitive";
254  case kTaggedNumber: return "number";
255  case kSmi: return "smi";
256  case kHeapNumber: return "heap-number";
257  case kString: return "string";
258  case kBoolean: return "boolean";
259  case kNonPrimitive: return "non-primitive";
260  case kJSArray: return "array";
261  case kJSObject: return "object";
262  case kUninitialized: return "uninitialized";
263  }
264  UNREACHABLE();
265  return "Unreachable code";
266 }
267 
268 
270  HType result = HType::Tagged();
271  if (value->IsSmi()) {
272  result = HType::Smi();
273  } else if (value->IsHeapNumber()) {
274  result = HType::HeapNumber();
275  } else if (value->IsString()) {
276  result = HType::String();
277  } else if (value->IsBoolean()) {
278  result = HType::Boolean();
279  } else if (value->IsJSObject()) {
280  result = HType::JSObject();
281  } else if (value->IsJSArray()) {
282  result = HType::JSArray();
283  }
284  return result;
285 }
286 
287 
289  return block()->block_id() > other->block_id();
290 }
291 
292 
294  // Skip and remove dead items in the use list.
295  while (tail_ != NULL && tail_->value()->CheckFlag(HValue::kIsDead)) {
296  tail_ = tail_->tail_;
297  }
298  return tail_;
299 }
300 
301 
303  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
304  if (!it.value()->CheckFlag(f)) return false;
305  }
306  return true;
307 }
308 
309 
310 HUseIterator::HUseIterator(HUseListNode* head) : next_(head) {
311  Advance();
312 }
313 
314 
315 void HUseIterator::Advance() {
316  current_ = next_;
317  if (current_ != NULL) {
318  next_ = current_->tail();
319  value_ = current_->value();
320  index_ = current_->index();
321  }
322 }
323 
324 
325 int HValue::UseCount() const {
326  int count = 0;
327  for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count;
328  return count;
329 }
330 
331 
332 HUseListNode* HValue::RemoveUse(HValue* value, int index) {
333  HUseListNode* previous = NULL;
334  HUseListNode* current = use_list_;
335  while (current != NULL) {
336  if (current->value() == value && current->index() == index) {
337  if (previous == NULL) {
338  use_list_ = current->tail();
339  } else {
340  previous->set_tail(current->tail());
341  }
342  break;
343  }
344 
345  previous = current;
346  current = current->tail();
347  }
348 
349 #ifdef DEBUG
350  // Do not reuse use list nodes in debug mode, zap them.
351  if (current != NULL) {
352  HUseListNode* temp =
353  new(block()->zone())
354  HUseListNode(current->value(), current->index(), NULL);
355  current->Zap();
356  current = temp;
357  }
358 #endif
359  return current;
360 }
361 
362 
363 bool HValue::Equals(HValue* other) {
364  if (other->opcode() != opcode()) return false;
365  if (!other->representation().Equals(representation())) return false;
366  if (!other->type_.Equals(type_)) return false;
367  if (other->flags() != flags()) return false;
368  if (OperandCount() != other->OperandCount()) return false;
369  for (int i = 0; i < OperandCount(); ++i) {
370  if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false;
371  }
372  bool result = DataEquals(other);
373  ASSERT(!result || Hashcode() == other->Hashcode());
374  return result;
375 }
376 
377 
378 intptr_t HValue::Hashcode() {
379  intptr_t result = opcode();
380  int count = OperandCount();
381  for (int i = 0; i < count; ++i) {
382  result = result * 19 + OperandAt(i)->id() + (result >> 7);
383  }
384  return result;
385 }
386 
387 
388 const char* HValue::Mnemonic() const {
389  switch (opcode()) {
390 #define MAKE_CASE(type) case k##type: return #type;
392 #undef MAKE_CASE
393  case kPhi: return "Phi";
394  default: return "";
395  }
396 }
397 
398 
399 void HValue::SetOperandAt(int index, HValue* value) {
400  RegisterUse(index, value);
401  InternalSetOperandAt(index, value);
402 }
403 
404 
406  // We replace all uses first, so Delete can assert that there are none.
407  if (other != NULL) ReplaceAllUsesWith(other);
408  ASSERT(HasNoUses());
409  Kill();
410  DeleteFromGraph();
411 }
412 
413 
415  while (use_list_ != NULL) {
416  HUseListNode* list_node = use_list_;
417  HValue* value = list_node->value();
418  ASSERT(!value->block()->IsStartBlock());
419  value->InternalSetOperandAt(list_node->index(), other);
420  use_list_ = list_node->tail();
421  list_node->set_tail(other->use_list_);
422  other->use_list_ = list_node;
423  }
424 }
425 
426 
427 void HValue::Kill() {
428  // Instead of going through the entire use list of each operand, we only
429  // check the first item in each use list and rely on the tail() method to
430  // skip dead items, removing them lazily next time we traverse the list.
431  SetFlag(kIsDead);
432  for (int i = 0; i < OperandCount(); ++i) {
433  HValue* operand = OperandAt(i);
434  if (operand == NULL) continue;
435  HUseListNode* first = operand->use_list_;
436  if (first != NULL && first->value() == this && first->index() == i) {
437  operand->use_list_ = first->tail();
438  }
439  }
440 }
441 
442 
444  ASSERT(block_ == NULL || block == NULL);
445  block_ = block;
446  if (id_ == kNoNumber && block != NULL) {
447  id_ = block->graph()->GetNextValueID(this);
448  }
449 }
450 
451 
453  if (!representation().IsTagged() || type().Equals(HType::Tagged())) return;
454  stream->Add(" type[%s]", type().ToString());
455 }
456 
457 
459  if (range() == NULL || range()->IsMostGeneric()) return;
460  stream->Add(" range[%d,%d,m0=%d]",
461  range()->lower(),
462  range()->upper(),
463  static_cast<int>(range()->CanBeMinusZero()));
464 }
465 
466 
468  GVNFlagSet changes_flags = ChangesFlags();
469  if (changes_flags.IsEmpty()) return;
470  stream->Add(" changes[");
471  if (changes_flags == AllSideEffectsFlagSet()) {
472  stream->Add("*");
473  } else {
474  bool add_comma = false;
475 #define PRINT_DO(type) \
476  if (changes_flags.Contains(kChanges##type)) { \
477  if (add_comma) stream->Add(","); \
478  add_comma = true; \
479  stream->Add(#type); \
480  }
483 #undef PRINT_DO
484  }
485  stream->Add("]");
486 }
487 
488 
490  stream->Add("%s%d", representation_.Mnemonic(), id());
491 }
492 
493 
496  bool result = (!type.Equals(type_));
497  type_ = type;
498  return result;
499 }
500 
501 
502 void HValue::RegisterUse(int index, HValue* new_value) {
503  HValue* old_value = OperandAt(index);
504  if (old_value == new_value) return;
505 
506  HUseListNode* removed = NULL;
507  if (old_value != NULL) {
508  removed = old_value->RemoveUse(this, index);
509  }
510 
511  if (new_value != NULL) {
512  if (removed == NULL) {
513  new_value->use_list_ = new(new_value->block()->zone()) HUseListNode(
514  this, index, new_value->use_list_);
515  } else {
516  removed->set_tail(new_value->use_list_);
517  new_value->use_list_ = removed;
518  }
519  }
520 }
521 
522 
523 void HValue::AddNewRange(Range* r, Zone* zone) {
524  if (!HasRange()) ComputeInitialRange(zone);
525  if (!HasRange()) range_ = new(zone) Range();
526  ASSERT(HasRange());
527  r->StackUpon(range_);
528  range_ = r;
529 }
530 
531 
533  ASSERT(HasRange());
534  ASSERT(range_->next() != NULL);
535  range_ = range_->next();
536 }
537 
538 
540  ASSERT(!HasRange());
541  range_ = InferRange(zone);
542  ASSERT(HasRange());
543 }
544 
545 
547  PrintMnemonicTo(stream);
548  PrintDataTo(stream);
549  PrintRangeTo(stream);
550  PrintChangesTo(stream);
551  PrintTypeTo(stream);
552 }
553 
554 
555 void HInstruction::PrintMnemonicTo(StringStream* stream) {
556  stream->Add("%s ", Mnemonic());
557 }
558 
559 
561  ASSERT(IsLinked());
562  ASSERT(!IsControlInstruction()); // Must never move control instructions.
563  ASSERT(!IsBlockEntry()); // Doesn't make sense to delete these.
564  ASSERT(previous_ != NULL);
565  previous_->next_ = next_;
566  if (next_ == NULL) {
567  ASSERT(block()->last() == this);
568  block()->set_last(previous_);
569  } else {
570  next_->previous_ = previous_;
571  }
572  clear_block();
573 }
574 
575 
577  ASSERT(!IsLinked());
578  ASSERT(!next->IsBlockEntry());
579  ASSERT(!IsControlInstruction());
580  ASSERT(!next->block()->IsStartBlock());
581  ASSERT(next->previous_ != NULL);
582  HInstruction* prev = next->previous();
583  prev->next_ = this;
584  next->previous_ = this;
585  next_ = next;
586  previous_ = prev;
587  SetBlock(next->block());
588 }
589 
590 
592  ASSERT(!IsLinked());
593  ASSERT(!previous->IsControlInstruction());
594  ASSERT(!IsControlInstruction() || previous->next_ == NULL);
595  HBasicBlock* block = previous->block();
596  // Never insert anything except constants into the start block after finishing
597  // it.
598  if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) {
599  ASSERT(block->end()->SecondSuccessor() == NULL);
600  InsertAfter(block->end()->FirstSuccessor()->first());
601  return;
602  }
603 
604  // If we're inserting after an instruction with side-effects that is
605  // followed by a simulate instruction, we need to insert after the
606  // simulate instruction instead.
607  HInstruction* next = previous->next_;
608  if (previous->HasObservableSideEffects() && next != NULL) {
609  ASSERT(next->IsSimulate());
610  previous = next;
611  next = previous->next_;
612  }
613 
614  previous_ = previous;
615  next_ = next;
616  SetBlock(block);
617  previous->next_ = this;
618  if (next != NULL) next->previous_ = this;
619  if (block->last() == previous) {
620  block->set_last(this);
621  }
622 }
623 
624 
625 #ifdef DEBUG
626 void HInstruction::Verify() {
627  // Verify that input operands are defined before use.
628  HBasicBlock* cur_block = block();
629  for (int i = 0; i < OperandCount(); ++i) {
630  HValue* other_operand = OperandAt(i);
631  if (other_operand == NULL) continue;
632  HBasicBlock* other_block = other_operand->block();
633  if (cur_block == other_block) {
634  if (!other_operand->IsPhi()) {
635  HInstruction* cur = this->previous();
636  while (cur != NULL) {
637  if (cur == other_operand) break;
638  cur = cur->previous();
639  }
640  // Must reach other operand in the same block!
641  ASSERT(cur == other_operand);
642  }
643  } else {
644  // If the following assert fires, you may have forgotten an
645  // AddInstruction.
646  ASSERT(other_block->Dominates(cur_block));
647  }
648  }
649 
650  // Verify that instructions that may have side-effects are followed
651  // by a simulate instruction.
652  if (HasObservableSideEffects() && !IsOsrEntry()) {
653  ASSERT(next()->IsSimulate());
654  }
655 
656  // Verify that instructions that can be eliminated by GVN have overridden
657  // HValue::DataEquals. The default implementation is UNREACHABLE. We
658  // don't actually care whether DataEquals returns true or false here.
659  if (CheckFlag(kUseGVN)) DataEquals(this);
660 }
661 #endif
662 
663 
665  value()->PrintNameTo(stream);
666  stream->Add(" ");
667  stream->Add("#%d", argument_count());
668 }
669 
670 
672  first()->PrintNameTo(stream);
673  stream->Add(" ");
674  second()->PrintNameTo(stream);
675  stream->Add(" ");
676  stream->Add("#%d", argument_count());
677 }
678 
679 
681  index()->PrintNameTo(stream);
682  stream->Add(" ");
683  length()->PrintNameTo(stream);
684 }
685 
686 
688  if (IsApplyFunction()) {
689  stream->Add("optimized apply ");
690  } else {
691  stream->Add("%o ", function()->shared()->DebugName());
692  }
693  stream->Add("#%d", argument_count());
694 }
695 
696 
698  stream->Add("%o ", *name());
699  HUnaryCall::PrintDataTo(stream);
700 }
701 
702 
704  stream->Add("%o ", *name());
705  HUnaryCall::PrintDataTo(stream);
706 }
707 
708 
710  stream->Add("%o ", target()->shared()->DebugName());
711  stream->Add("#%d", argument_count());
712 }
713 
714 
716  stream->Add("%o ", *name());
717  stream->Add("#%d", argument_count());
718 }
719 
720 
722  stream->Add("class_of_test(");
723  value()->PrintNameTo(stream);
724  stream->Add(", \"%o\")", *class_name());
725 }
726 
727 
729  arguments()->PrintNameTo(stream);
730  stream->Add("[");
731  index()->PrintNameTo(stream);
732  stream->Add("], length ");
733  length()->PrintNameTo(stream);
734 }
735 
736 
738  stream->Add(" goto (");
739  bool first_block = true;
740  for (HSuccessorIterator it(this); !it.Done(); it.Advance()) {
741  stream->Add(first_block ? "B%d" : ", B%d", it.Current()->block_id());
742  first_block = false;
743  }
744  stream->Add(")");
745 }
746 
747 
749  value()->PrintNameTo(stream);
751 }
752 
753 
755  value()->PrintNameTo(stream);
756  stream->Add(kind() == kStrictEquality ? " === " : " == ");
757  stream->Add(nil() == kNullValue ? "null" : "undefined");
759 }
760 
761 
763  value()->PrintNameTo(stream);
764 }
765 
766 
768  value()->PrintNameTo(stream);
769  stream->Add(" (%p)", *map());
771 }
772 
773 
774 const char* HUnaryMathOperation::OpName() const {
775  switch (op()) {
776  case kMathFloor: return "floor";
777  case kMathRound: return "round";
778  case kMathCeil: return "ceil";
779  case kMathAbs: return "abs";
780  case kMathLog: return "log";
781  case kMathSin: return "sin";
782  case kMathCos: return "cos";
783  case kMathTan: return "tan";
784  case kMathASin: return "asin";
785  case kMathACos: return "acos";
786  case kMathATan: return "atan";
787  case kMathExp: return "exp";
788  case kMathSqrt: return "sqrt";
789  default: break;
790  }
791  return "(unknown operation)";
792 }
793 
794 
796  const char* name = OpName();
797  stream->Add("%s ", name);
798  value()->PrintNameTo(stream);
799 }
800 
801 
803  value()->PrintNameTo(stream);
804 }
805 
806 
808  value()->PrintNameTo(stream);
809  switch (from_) {
811  if (to_ == LAST_TYPE) stream->Add(" spec_object");
812  break;
813  case JS_REGEXP_TYPE:
814  if (to_ == JS_REGEXP_TYPE) stream->Add(" reg_exp");
815  break;
816  case JS_ARRAY_TYPE:
817  if (to_ == JS_ARRAY_TYPE) stream->Add(" array");
818  break;
819  case JS_FUNCTION_TYPE:
820  if (to_ == JS_FUNCTION_TYPE) stream->Add(" function");
821  break;
822  default:
823  break;
824  }
825 }
826 
827 
829  value()->PrintNameTo(stream);
830  stream->Add(" == %o", *type_literal_);
832 }
833 
834 
836  value()->PrintNameTo(stream);
837  stream->Add(" ");
838  map()->PrintNameTo(stream);
839 }
840 
841 
843  enumerable()->PrintNameTo(stream);
844 }
845 
846 
848  enumerable()->PrintNameTo(stream);
849  stream->Add(" ");
850  map()->PrintNameTo(stream);
851  stream->Add("[%d]", idx_);
852 }
853 
854 
856  object()->PrintNameTo(stream);
857  stream->Add(" ");
858  index()->PrintNameTo(stream);
859 }
860 
861 
863  return HasNoUses() ? NULL : this;
864 }
865 
866 
868  return HasNoUses() ? NULL : this;
869 }
870 
871 
873  if (!representation().IsInteger32()) return this;
874  // If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x.
875  int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0;
876  if (left()->IsConstant() &&
877  HConstant::cast(left())->HasInteger32Value() &&
878  HConstant::cast(left())->Integer32Value() == nop_constant &&
879  !right()->CheckFlag(kUint32)) {
880  return right();
881  }
882  if (right()->IsConstant() &&
883  HConstant::cast(right())->HasInteger32Value() &&
884  HConstant::cast(right())->Integer32Value() == nop_constant &&
885  !left()->CheckFlag(kUint32)) {
886  return left();
887  }
888  return this;
889 }
890 
891 
893  // Optimize ~~x, a common pattern used for ToInt32(x).
894  if (value()->IsBitNot()) {
895  HValue* result = HBitNot::cast(value())->value();
896  ASSERT(result->representation().IsInteger32());
897  if (!result->CheckFlag(kUint32)) {
898  return result;
899  }
900  }
901  return this;
902 }
903 
904 
906  if (!representation().IsInteger32()) return this;
908  return this;
909 }
910 
911 
913  if (!representation().IsInteger32()) return this;
915  return this;
916 }
917 
918 
920  return (from().Equals(to())) ? value() : this;
921 }
922 
923 
925  if (HasNoUses()) return NULL;
926  if (receiver()->type().IsJSObject()) {
927  return receiver();
928  }
929  return this;
930 }
931 
932 
934  value()->PrintNameTo(stream);
935 }
936 
937 
940  stream->Add(" %s to %s", from().Mnemonic(), to().Mnemonic());
941 
942  if (CanTruncateToInt32()) stream->Add(" truncating-int32");
943  if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
944  if (CheckFlag(kDeoptimizeOnUndefined)) stream->Add(" deopt-on-undefined");
945 }
946 
947 
949  value()->PrintNameTo(stream);
950  stream->Add(" ");
951  typecheck()->PrintNameTo(stream);
952 }
953 
954 
956  if (op() == kMathFloor) {
957  // If the input is integer32 then we replace the floor instruction
958  // with its input. This happens before the representation changes are
959  // introduced.
960  if (value()->representation().IsInteger32()) return value();
961 
962 #if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_IA32) || \
963  defined(V8_TARGET_ARCH_X64)
964  if (value()->IsDiv() && (value()->UseCount() == 1)) {
965  // TODO(2038): Implement this optimization for non ARM architectures.
966  HDiv* hdiv = HDiv::cast(value());
967  HValue* left = hdiv->left();
968  HValue* right = hdiv->right();
969  // Try to simplify left and right values of the division.
970  HValue* new_left =
971  LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(left);
972  HValue* new_right =
973  LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(right);
974 
975  // Return if left or right are not optimizable.
976  if ((new_left == NULL) || (new_right == NULL)) return this;
977 
978  // Insert the new values in the graph.
979  if (new_left->IsInstruction() &&
980  !HInstruction::cast(new_left)->IsLinked()) {
981  HInstruction::cast(new_left)->InsertBefore(this);
982  }
983  if (new_right->IsInstruction() &&
984  !HInstruction::cast(new_right)->IsLinked()) {
985  HInstruction::cast(new_right)->InsertBefore(this);
986  }
987  HMathFloorOfDiv* instr = new(block()->zone()) HMathFloorOfDiv(context(),
988  new_left,
989  new_right);
990  // Replace this HMathFloor instruction by the new HMathFloorOfDiv.
991  instr->InsertBefore(this);
992  ReplaceAllUsesWith(instr);
993  Kill();
994  // We know the division had no other uses than this HMathFloor. Delete it.
995  // Also delete the arguments of the division if they are not used any
996  // more.
997  hdiv->DeleteAndReplaceWith(NULL);
998  ASSERT(left->IsChange() || left->IsConstant());
999  ASSERT(right->IsChange() || right->IsConstant());
1000  if (left->HasNoUses()) left->DeleteAndReplaceWith(NULL);
1001  if (right->HasNoUses()) right->DeleteAndReplaceWith(NULL);
1002 
1003  // Return NULL to remove this instruction from the graph.
1004  return NULL;
1005  }
1006 #endif // V8_TARGET_ARCH_ARM
1007  }
1008  return this;
1009 }
1010 
1011 
1013  if (check_ == IS_STRING &&
1014  !value()->type().IsUninitialized() &&
1015  value()->type().IsString()) {
1016  return NULL;
1017  }
1018  if (check_ == IS_SYMBOL &&
1019  value()->IsConstant() &&
1020  HConstant::cast(value())->handle()->IsSymbol()) {
1021  return NULL;
1022  }
1023  return this;
1024 }
1025 
1026 
1028  InstanceType* last) {
1030  switch (check_) {
1031  case IS_SPEC_OBJECT:
1032  *first = FIRST_SPEC_OBJECT_TYPE;
1033  *last = LAST_SPEC_OBJECT_TYPE;
1034  return;
1035  case IS_JS_ARRAY:
1036  *first = *last = JS_ARRAY_TYPE;
1037  return;
1038  default:
1039  UNREACHABLE();
1040  }
1041 }
1042 
1043 
1044 void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) {
1046  switch (check_) {
1047  case IS_STRING:
1048  *mask = kIsNotStringMask;
1049  *tag = kStringTag;
1050  return;
1051  case IS_SYMBOL:
1052  *mask = kIsSymbolMask;
1053  *tag = kSymbolTag;
1054  return;
1055  default:
1056  UNREACHABLE();
1057  }
1058 }
1059 
1060 
1062  value()->PrintNameTo(stream);
1063  stream->Add(" ");
1064  typecheck()->PrintNameTo(stream);
1065 }
1066 
1067 
1069  value()->PrintNameTo(stream);
1070  stream->Add(" [%p", *map_set()->first());
1071  for (int i = 1; i < map_set()->length(); ++i) {
1072  stream->Add(",%p", *map_set()->at(i));
1073  }
1074  stream->Add("]");
1075 }
1076 
1077 
1079  value()->PrintNameTo(stream);
1080  stream->Add(" %p", *target());
1081 }
1082 
1083 
1084 const char* HCheckInstanceType::GetCheckName() {
1085  switch (check_) {
1086  case IS_SPEC_OBJECT: return "object";
1087  case IS_JS_ARRAY: return "array";
1088  case IS_STRING: return "string";
1089  case IS_SYMBOL: return "symbol";
1090  }
1091  UNREACHABLE();
1092  return "";
1093 }
1094 
1096  stream->Add("%s ", GetCheckName());
1098 }
1099 
1100 
1102  stream->Add("[receiver_prototype=%p,holder=%p]", *prototype(), *holder());
1103 }
1104 
1105 
1107  stream->Add("%s ",
1108  CodeStub::MajorName(major_key_, false));
1109  HUnaryCall::PrintDataTo(stream);
1110 }
1111 
1112 
1114  left()->PrintNameTo(stream);
1115  stream->Add(" ");
1116  right()->PrintNameTo(stream);
1117  stream->Add(" ");
1118  context()->PrintNameTo(stream);
1119 }
1120 
1121 
1123  // Untagged integer32 cannot be -0, all other representations can.
1124  Range* result = new(zone) Range();
1125  result->set_can_be_minus_zero(!representation().IsInteger32());
1126  return result;
1127 }
1128 
1129 
1131  Range* input_range = value()->range();
1132  if (from().IsInteger32() &&
1133  to().IsTagged() &&
1135  input_range != NULL && input_range->IsInSmiRange()) {
1136  set_type(HType::Smi());
1137  }
1138  Range* result = (input_range != NULL)
1139  ? input_range->Copy(zone)
1140  : HValue::InferRange(zone);
1141  if (to().IsInteger32()) result->set_can_be_minus_zero(false);
1142  return result;
1143 }
1144 
1145 
1147  if (has_int32_value_) {
1148  Range* result = new(zone) Range(int32_value_, int32_value_);
1149  result->set_can_be_minus_zero(false);
1150  return result;
1151  }
1152  return HValue::InferRange(zone);
1153 }
1154 
1155 
1157  if (representation().IsInteger32()) {
1158  if (block()->IsLoopHeader()) {
1159  Range* range = new(zone) Range(kMinInt, kMaxInt);
1160  return range;
1161  } else {
1162  Range* range = OperandAt(0)->range()->Copy(zone);
1163  for (int i = 1; i < OperandCount(); ++i) {
1164  range->Union(OperandAt(i)->range());
1165  }
1166  return range;
1167  }
1168  } else {
1169  return HValue::InferRange(zone);
1170  }
1171 }
1172 
1173 
1175  if (representation().IsInteger32()) {
1176  Range* a = left()->range();
1177  Range* b = right()->range();
1178  Range* res = a->Copy(zone);
1179  if (!res->AddAndCheckOverflow(b)) {
1181  }
1182  bool m0 = a->CanBeMinusZero() && b->CanBeMinusZero();
1183  res->set_can_be_minus_zero(m0);
1184  return res;
1185  } else {
1186  return HValue::InferRange(zone);
1187  }
1188 }
1189 
1190 
1192  if (representation().IsInteger32()) {
1193  Range* a = left()->range();
1194  Range* b = right()->range();
1195  Range* res = a->Copy(zone);
1196  if (!res->SubAndCheckOverflow(b)) {
1198  }
1199  res->set_can_be_minus_zero(a->CanBeMinusZero() && b->CanBeZero());
1200  return res;
1201  } else {
1202  return HValue::InferRange(zone);
1203  }
1204 }
1205 
1206 
1208  if (representation().IsInteger32()) {
1209  Range* a = left()->range();
1210  Range* b = right()->range();
1211  Range* res = a->Copy(zone);
1212  if (!res->MulAndCheckOverflow(b)) {
1214  }
1215  bool m0 = (a->CanBeZero() && b->CanBeNegative()) ||
1216  (a->CanBeNegative() && b->CanBeZero());
1217  res->set_can_be_minus_zero(m0);
1218  return res;
1219  } else {
1220  return HValue::InferRange(zone);
1221  }
1222 }
1223 
1224 
1226  if (representation().IsInteger32()) {
1227  Range* result = new(zone) Range();
1228  if (left()->range()->CanBeMinusZero()) {
1229  result->set_can_be_minus_zero(true);
1230  }
1231 
1232  if (left()->range()->CanBeZero() && right()->range()->CanBeNegative()) {
1233  result->set_can_be_minus_zero(true);
1234  }
1235 
1236  if (right()->range()->Includes(-1) && left()->range()->Includes(kMinInt)) {
1238  }
1239 
1240  if (!right()->range()->CanBeZero()) {
1242  }
1243  return result;
1244  } else {
1245  return HValue::InferRange(zone);
1246  }
1247 }
1248 
1249 
1251  if (representation().IsInteger32()) {
1252  Range* a = left()->range();
1253  Range* result = new(zone) Range();
1254  if (a->CanBeMinusZero() || a->CanBeNegative()) {
1255  result->set_can_be_minus_zero(true);
1256  }
1257  if (!right()->range()->CanBeZero()) {
1259  }
1260  return result;
1261  } else {
1262  return HValue::InferRange(zone);
1263  }
1264 }
1265 
1266 
1268  if (representation().IsInteger32()) {
1269  Range* a = left()->range();
1270  Range* b = right()->range();
1271  Range* res = a->Copy(zone);
1272  if (operation_ == kMathMax) {
1273  res->CombinedMax(b);
1274  } else {
1275  ASSERT(operation_ == kMathMin);
1276  res->CombinedMin(b);
1277  }
1278  return res;
1279  } else {
1280  return HValue::InferRange(zone);
1281  }
1282 }
1283 
1284 
1286  stream->Add("[");
1287  for (int i = 0; i < OperandCount(); ++i) {
1288  HValue* value = OperandAt(i);
1289  stream->Add(" ");
1290  value->PrintNameTo(stream);
1291  stream->Add(" ");
1292  }
1293  stream->Add(" uses%d_%di_%dd_%dt",
1294  UseCount(),
1298  stream->Add("%s%s]",
1299  is_live() ? "_live" : "",
1300  IsConvertibleToInteger() ? "" : "_ncti");
1301 }
1302 
1303 
1304 void HPhi::AddInput(HValue* value) {
1305  inputs_.Add(NULL, value->block()->zone());
1306  SetOperandAt(OperandCount() - 1, value);
1307  // Mark phis that may have 'arguments' directly or indirectly as an operand.
1308  if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) {
1310  }
1311 }
1312 
1313 
1315  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1316  if (!it.value()->IsPhi()) return true;
1317  }
1318  return false;
1319 }
1320 
1321 
1323  HValue* candidate = NULL;
1324  int count = OperandCount();
1325  int position = 0;
1326  while (position < count && candidate == NULL) {
1327  HValue* current = OperandAt(position++);
1328  if (current != this) candidate = current;
1329  }
1330  while (position < count) {
1331  HValue* current = OperandAt(position++);
1332  if (current != this && current != candidate) return NULL;
1333  }
1334  ASSERT(candidate != this);
1335  return candidate;
1336 }
1337 
1338 
1340  ASSERT(block() != NULL);
1341  block()->RemovePhi(this);
1342  ASSERT(block() == NULL);
1343 }
1344 
1345 
1346 void HPhi::InitRealUses(int phi_id) {
1347  // Initialize real uses.
1348  phi_id_ = phi_id;
1349  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1350  HValue* value = it.value();
1351  if (!value->IsPhi()) {
1352  Representation rep = value->ObservedInputRepresentation(it.index());
1353  non_phi_uses_[rep.kind()] += value->LoopWeight();
1354  if (FLAG_trace_representation) {
1355  PrintF("%d %s is used by %d %s as %s\n",
1356  this->id(),
1357  this->Mnemonic(),
1358  value->id(),
1359  value->Mnemonic(),
1360  rep.Mnemonic());
1361  }
1362  }
1363  }
1364 }
1365 
1366 
1368  if (FLAG_trace_representation) {
1369  PrintF("adding to %d %s uses of %d %s: i%d d%d t%d\n",
1370  this->id(),
1371  this->Mnemonic(),
1372  other->id(),
1373  other->Mnemonic(),
1374  other->non_phi_uses_[Representation::kInteger32],
1375  other->non_phi_uses_[Representation::kDouble],
1376  other->non_phi_uses_[Representation::kTagged]);
1377  }
1378 
1379  for (int i = 0; i < Representation::kNumRepresentations; i++) {
1380  indirect_uses_[i] += other->non_phi_uses_[i];
1381  }
1382 }
1383 
1384 
1385 void HPhi::AddIndirectUsesTo(int* dest) {
1386  for (int i = 0; i < Representation::kNumRepresentations; i++) {
1387  dest[i] += indirect_uses_[i];
1388  }
1389 }
1390 
1391 
1393  non_phi_uses_[Representation::kInteger32] = 0;
1394  indirect_uses_[Representation::kInteger32] = 0;
1395 }
1396 
1397 
1399  stream->Add("id=%d", ast_id().ToInt());
1400  if (pop_count_ > 0) stream->Add(" pop %d", pop_count_);
1401  if (values_.length() > 0) {
1402  if (pop_count_ > 0) stream->Add(" /");
1403  for (int i = 0; i < values_.length(); ++i) {
1404  if (i > 0) stream->Add(",");
1405  if (HasAssignedIndexAt(i)) {
1406  stream->Add(" var[%d] = ", GetAssignedIndexAt(i));
1407  } else {
1408  stream->Add(" push ");
1409  }
1410  values_[i]->PrintNameTo(stream);
1411  }
1412  }
1413 }
1414 
1415 
1417  if (OperandCount() == 0) return;
1418  OperandAt(0)->PrintNameTo(stream);
1419  for (int i = 1; i < OperandCount(); ++i) {
1420  stream->Add(" ");
1421  OperandAt(i)->PrintNameTo(stream);
1422  }
1423 }
1424 
1425 
1427  SmartArrayPointer<char> name = function()->debug_name()->ToCString();
1428  stream->Add("%s, id=%d", *name, function()->id().ToInt());
1429 }
1430 
1431 
1432 static bool IsInteger32(double value) {
1433  double roundtrip_value = static_cast<double>(static_cast<int32_t>(value));
1434  return BitCast<int64_t>(roundtrip_value) == BitCast<int64_t>(value);
1435 }
1436 
1437 
1439  : handle_(handle),
1440  has_int32_value_(false),
1441  has_double_value_(false) {
1442  set_representation(r);
1443  SetFlag(kUseGVN);
1444  if (handle_->IsNumber()) {
1445  double n = handle_->Number();
1446  has_int32_value_ = IsInteger32(n);
1447  int32_value_ = DoubleToInt32(n);
1448  double_value_ = n;
1449  has_double_value_ = true;
1450  }
1451 }
1452 
1453 
1455  : has_int32_value_(true),
1456  has_double_value_(true),
1457  int32_value_(integer_value),
1458  double_value_(FastI2D(integer_value)) {
1459  set_representation(r);
1460  SetFlag(kUseGVN);
1461 }
1462 
1463 
1464 HConstant::HConstant(double double_value, Representation r)
1465  : has_int32_value_(IsInteger32(double_value)),
1466  has_double_value_(true),
1467  int32_value_(DoubleToInt32(double_value)),
1468  double_value_(double_value) {
1469  set_representation(r);
1470  SetFlag(kUseGVN);
1471 }
1472 
1473 
1475  if (r.IsInteger32() && !has_int32_value_) return NULL;
1476  if (r.IsDouble() && !has_double_value_) return NULL;
1477  if (handle_.is_null()) {
1478  ASSERT(has_int32_value_ || has_double_value_);
1479  if (has_int32_value_) return new(zone) HConstant(int32_value_, r);
1480  return new(zone) HConstant(double_value_, r);
1481  }
1482  return new(zone) HConstant(handle_, r);
1483 }
1484 
1485 
1487  if (has_int32_value_) {
1488  if (handle_.is_null()) {
1489  return new(zone) HConstant(int32_value_, Representation::Integer32());
1490  } else {
1491  // Re-use the existing Handle if possible.
1492  return new(zone) HConstant(handle_, Representation::Integer32());
1493  }
1494  } else if (has_double_value_) {
1495  return new(zone) HConstant(DoubleToInt32(double_value_),
1497  } else {
1498  return NULL;
1499  }
1500 }
1501 
1502 
1504  // Converts the constant's boolean value according to
1505  // ECMAScript section 9.2 ToBoolean conversion.
1506  if (HasInteger32Value()) return Integer32Value() != 0;
1507  if (HasDoubleValue()) {
1508  double v = DoubleValue();
1509  return v != 0 && !isnan(v);
1510  }
1511  Handle<Object> literal = handle();
1512  if (literal->IsTrue()) return true;
1513  if (literal->IsFalse()) return false;
1514  if (literal->IsUndefined()) return false;
1515  if (literal->IsNull()) return false;
1516  if (literal->IsString() && String::cast(*literal)->length() == 0) {
1517  return false;
1518  }
1519  return true;
1520 }
1521 
1523  if (has_int32_value_) {
1524  stream->Add("%d ", int32_value_);
1525  } else if (has_double_value_) {
1526  stream->Add("%f ", FmtElm(double_value_));
1527  } else {
1528  handle()->ShortPrint(stream);
1529  }
1530 }
1531 
1532 
1534  if (!boilerplate_object_->IsJSObject()) return false;
1535  return Handle<JSObject>::cast(boilerplate_object_)->elements()->map() ==
1536  HEAP->fixed_cow_array_map();
1537 }
1538 
1539 
1541  left()->PrintNameTo(stream);
1542  stream->Add(" ");
1543  right()->PrintNameTo(stream);
1544  if (CheckFlag(kCanOverflow)) stream->Add(" !");
1545  if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
1546 }
1547 
1548 
1550  if (op() == Token::BIT_XOR) return HValue::InferRange(zone);
1551  const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff);
1552  int32_t left_mask = (left()->range() != NULL)
1553  ? left()->range()->Mask()
1554  : kDefaultMask;
1555  int32_t right_mask = (right()->range() != NULL)
1556  ? right()->range()->Mask()
1557  : kDefaultMask;
1558  int32_t result_mask = (op() == Token::BIT_AND)
1559  ? left_mask & right_mask
1560  : left_mask | right_mask;
1561  return (result_mask >= 0)
1562  ? new(zone) Range(0, result_mask)
1563  : HValue::InferRange(zone);
1564 }
1565 
1566 
1568  if (right()->IsConstant()) {
1570  if (c->HasInteger32Value()) {
1571  Range* result = (left()->range() != NULL)
1572  ? left()->range()->Copy(zone)
1573  : new(zone) Range();
1574  result->Sar(c->Integer32Value());
1575  result->set_can_be_minus_zero(false);
1576  return result;
1577  }
1578  }
1579  return HValue::InferRange(zone);
1580 }
1581 
1582 
1584  if (right()->IsConstant()) {
1586  if (c->HasInteger32Value()) {
1587  int shift_count = c->Integer32Value() & 0x1f;
1588  if (left()->range()->CanBeNegative()) {
1589  // Only compute bounds if the result always fits into an int32.
1590  return (shift_count >= 1)
1591  ? new(zone) Range(0,
1592  static_cast<uint32_t>(0xffffffff) >> shift_count)
1593  : new(zone) Range();
1594  } else {
1595  // For positive inputs we can use the >> operator.
1596  Range* result = (left()->range() != NULL)
1597  ? left()->range()->Copy(zone)
1598  : new(zone) Range();
1599  result->Sar(c->Integer32Value());
1600  result->set_can_be_minus_zero(false);
1601  return result;
1602  }
1603  }
1604  }
1605  return HValue::InferRange(zone);
1606 }
1607 
1608 
1610  if (right()->IsConstant()) {
1612  if (c->HasInteger32Value()) {
1613  Range* result = (left()->range() != NULL)
1614  ? left()->range()->Copy(zone)
1615  : new(zone) Range();
1616  result->Shl(c->Integer32Value());
1617  result->set_can_be_minus_zero(false);
1618  return result;
1619  }
1620  }
1621  return HValue::InferRange(zone);
1622 }
1623 
1624 
1626  switch (elements_kind()) {
1628  return new(zone) Range(0, 255);
1630  return new(zone) Range(-128, 127);
1632  return new(zone) Range(0, 255);
1634  return new(zone) Range(-32768, 32767);
1636  return new(zone) Range(0, 65535);
1637  default:
1638  return HValue::InferRange(zone);
1639  }
1640 }
1641 
1642 
1644  stream->Add(Token::Name(token()));
1645  stream->Add(" ");
1647 }
1648 
1649 
1651  stream->Add(Token::Name(token()));
1652  stream->Add(" ");
1654 }
1655 
1656 
1658  stream->Add(Token::Name(token()));
1659  stream->Add(" ");
1660  left()->PrintNameTo(stream);
1661  stream->Add(" ");
1662  right()->PrintNameTo(stream);
1664 }
1665 
1666 
1668  left()->PrintNameTo(stream);
1669  stream->Add(" ");
1670  right()->PrintNameTo(stream);
1672 }
1673 
1674 
1676  stream->Add("B%d", SuccessorAt(0)->block_id());
1677 }
1678 
1679 
1681  input_representation_ = r;
1682  if (r.IsDouble()) {
1683  // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, ===
1684  // and !=) have special handling of undefined, e.g. undefined == undefined
1685  // is 'true'. Relational comparisons have a different semantic, first
1686  // calling ToPrimitive() on their arguments. The standard Crankshaft
1687  // tagged-to-double conversion to ensure the HCompareIDAndBranch's inputs
1688  // are doubles caused 'undefined' to be converted to NaN. That's compatible
1689  // out-of-the box with ordered relational comparisons (<, >, <=,
1690  // >=). However, for equality comparisons (and for 'in' and 'instanceof'),
1691  // it is not consistent with the spec. For example, it would cause undefined
1692  // == undefined (should be true) to be evaluated as NaN == NaN
1693  // (false). Therefore, any comparisons other than ordered relational
1694  // comparisons must cause a deopt when one of their arguments is undefined.
1695  // See also v8:1434
1696  if (!Token::IsOrderedRelationalCompareOp(token_)) {
1698  }
1699  } else {
1700  ASSERT(r.IsInteger32());
1701  }
1702 }
1703 
1704 
1706  stream->Add("%u", index());
1707 }
1708 
1709 
1711  object()->PrintNameTo(stream);
1712  stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
1713 }
1714 
1715 
1716 // Returns true if an instance of this map can never find a property with this
1717 // name in its prototype chain. This means all prototypes up to the top are
1718 // fast and don't have the name in them. It would be good if we could optimize
1719 // polymorphic loads where the property is sometimes found in the prototype
1720 // chain.
1721 static bool PrototypeChainCanNeverResolve(
1722  Handle<Map> map, Handle<String> name) {
1723  Isolate* isolate = map->GetIsolate();
1724  Object* current = map->prototype();
1725  while (current != isolate->heap()->null_value()) {
1726  if (current->IsJSGlobalProxy() ||
1727  current->IsGlobalObject() ||
1728  !current->IsJSObject() ||
1729  JSObject::cast(current)->map()->has_named_interceptor() ||
1730  JSObject::cast(current)->IsAccessCheckNeeded() ||
1731  !JSObject::cast(current)->HasFastProperties()) {
1732  return false;
1733  }
1734 
1735  LookupResult lookup(isolate);
1736  Map* map = JSObject::cast(current)->map();
1737  map->LookupDescriptor(NULL, *name, &lookup);
1738  if (lookup.IsFound()) return false;
1739  if (!lookup.IsCacheable()) return false;
1740  current = JSObject::cast(current)->GetPrototype();
1741  }
1742  return true;
1743 }
1744 
1745 
1747  HValue* object,
1748  SmallMapList* types,
1749  Handle<String> name,
1750  Zone* zone)
1751  : types_(Min(types->length(), kMaxLoadPolymorphism), zone),
1752  name_(name),
1753  need_generic_(false) {
1754  SetOperandAt(0, context);
1755  SetOperandAt(1, object);
1757  SetGVNFlag(kDependsOnMaps);
1758  SmallMapList negative_lookups;
1759  for (int i = 0;
1760  i < types->length() && types_.length() < kMaxLoadPolymorphism;
1761  ++i) {
1762  Handle<Map> map = types->at(i);
1763  LookupResult lookup(map->GetIsolate());
1764  map->LookupDescriptor(NULL, *name, &lookup);
1765  if (lookup.IsFound()) {
1766  switch (lookup.type()) {
1767  case FIELD: {
1768  int index = lookup.GetLocalFieldIndexFromMap(*map);
1769  if (index < 0) {
1770  SetGVNFlag(kDependsOnInobjectFields);
1771  } else {
1772  SetGVNFlag(kDependsOnBackingStoreFields);
1773  }
1774  types_.Add(types->at(i), zone);
1775  break;
1776  }
1777  case CONSTANT_FUNCTION:
1778  types_.Add(types->at(i), zone);
1779  break;
1780  case CALLBACKS:
1781  break;
1782  case TRANSITION:
1783  case INTERCEPTOR:
1784  case NONEXISTENT:
1785  case NORMAL:
1786  case HANDLER:
1787  UNREACHABLE();
1788  break;
1789  }
1790  } else if (lookup.IsCacheable() &&
1791  // For dicts the lookup on the map will fail, but the object may
1792  // contain the property so we cannot generate a negative lookup
1793  // (which would just be a map check and return undefined).
1794  !map->is_dictionary_map() &&
1795  !map->has_named_interceptor() &&
1796  PrototypeChainCanNeverResolve(map, name)) {
1797  negative_lookups.Add(types->at(i), zone);
1798  }
1799  }
1800 
1801  bool need_generic =
1802  (types->length() != negative_lookups.length() + types_.length());
1803  if (!need_generic && FLAG_deoptimize_uncommon_cases) {
1804  SetFlag(kUseGVN);
1805  for (int i = 0; i < negative_lookups.length(); i++) {
1806  types_.Add(negative_lookups.at(i), zone);
1807  }
1808  } else {
1809  // We don't have an easy way to handle both a call (to the generic stub) and
1810  // a deopt in the same hydrogen instruction, so in this case we don't add
1811  // the negative lookups which can deopt - just let the generic stub handle
1812  // them.
1814  need_generic_ = true;
1815  }
1816 }
1817 
1818 
1821  if (types_.length() != other->types()->length()) return false;
1822  if (!name_.is_identical_to(other->name())) return false;
1823  if (need_generic_ != other->need_generic_) return false;
1824  for (int i = 0; i < types_.length(); i++) {
1825  bool found = false;
1826  for (int j = 0; j < types_.length(); j++) {
1827  if (types_.at(j).is_identical_to(other->types()->at(i))) {
1828  found = true;
1829  break;
1830  }
1831  }
1832  if (!found) return false;
1833  }
1834  return true;
1835 }
1836 
1837 
1839  object()->PrintNameTo(stream);
1840  stream->Add(".");
1841  stream->Add(*String::cast(*name())->ToCString());
1842 }
1843 
1844 
1846  object()->PrintNameTo(stream);
1847  stream->Add(".");
1848  stream->Add(*String::cast(*name())->ToCString());
1849 }
1850 
1851 
1853  object()->PrintNameTo(stream);
1854  stream->Add("[");
1855  key()->PrintNameTo(stream);
1856  stream->Add("] ");
1857  dependency()->PrintNameTo(stream);
1858  if (RequiresHoleCheck()) {
1859  stream->Add(" check_hole");
1860  }
1861 }
1862 
1863 
1866  return false;
1867  }
1868 
1869  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1870  HValue* use = it.value();
1871  if (!use->IsChange()) return true;
1872  }
1873 
1874  return false;
1875 }
1876 
1877 
1879  elements()->PrintNameTo(stream);
1880  stream->Add("[");
1881  key()->PrintNameTo(stream);
1882  stream->Add("] ");
1883  dependency()->PrintNameTo(stream);
1884 }
1885 
1886 
1888  object()->PrintNameTo(stream);
1889  stream->Add("[");
1890  key()->PrintNameTo(stream);
1891  stream->Add("]");
1892 }
1893 
1894 
1896  // Recognize generic keyed loads that use property name generated
1897  // by for-in statement as a key and rewrite them into fast property load
1898  // by index.
1899  if (key()->IsLoadKeyedFastElement()) {
1901  if (key_load->object()->IsForInCacheArray()) {
1902  HForInCacheArray* names_cache =
1903  HForInCacheArray::cast(key_load->object());
1904 
1905  if (names_cache->enumerable() == object()) {
1906  HForInCacheArray* index_cache =
1907  names_cache->index_cache();
1908  HCheckMapValue* map_check =
1909  new(block()->zone()) HCheckMapValue(object(), names_cache->map());
1910  HInstruction* index = new(block()->zone()) HLoadKeyedFastElement(
1911  index_cache,
1912  key_load->key(),
1913  key_load->key());
1914  map_check->InsertBefore(this);
1915  index->InsertBefore(this);
1916  HLoadFieldByIndex* load = new(block()->zone()) HLoadFieldByIndex(
1917  object(), index);
1918  load->InsertBefore(this);
1919  return load;
1920  }
1921  }
1922  }
1923 
1924  return this;
1925 }
1926 
1927 
1929  StringStream* stream) {
1930  external_pointer()->PrintNameTo(stream);
1931  stream->Add(".");
1932  switch (elements_kind()) {
1934  stream->Add("byte");
1935  break;
1937  stream->Add("u_byte");
1938  break;
1940  stream->Add("short");
1941  break;
1943  stream->Add("u_short");
1944  break;
1945  case EXTERNAL_INT_ELEMENTS:
1946  stream->Add("int");
1947  break;
1949  stream->Add("u_int");
1950  break;
1952  stream->Add("float");
1953  break;
1955  stream->Add("double");
1956  break;
1958  stream->Add("pixel");
1959  break;
1960  case FAST_ELEMENTS:
1961  case FAST_SMI_ELEMENTS:
1962  case FAST_DOUBLE_ELEMENTS:
1963  case FAST_HOLEY_ELEMENTS:
1966  case DICTIONARY_ELEMENTS:
1968  UNREACHABLE();
1969  break;
1970  }
1971  stream->Add("[");
1972  key()->PrintNameTo(stream);
1973  stream->Add("] ");
1974  dependency()->PrintNameTo(stream);
1975 }
1976 
1977 
1979  object()->PrintNameTo(stream);
1980  stream->Add(".");
1981  ASSERT(name()->IsString());
1982  stream->Add(*String::cast(*name())->ToCString());
1983  stream->Add(" = ");
1984  value()->PrintNameTo(stream);
1985 }
1986 
1987 
1989  object()->PrintNameTo(stream);
1990  stream->Add(".");
1991  stream->Add(*String::cast(*name())->ToCString());
1992  stream->Add(" = ");
1993  value()->PrintNameTo(stream);
1994  stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
1995  if (NeedsWriteBarrier()) {
1996  stream->Add(" (write-barrier)");
1997  }
1998  if (!transition().is_null()) {
1999  stream->Add(" (transition map %p)", *transition());
2000  }
2001 }
2002 
2003 
2005  object()->PrintNameTo(stream);
2006  stream->Add("[");
2007  key()->PrintNameTo(stream);
2008  stream->Add("] = ");
2009  value()->PrintNameTo(stream);
2010 }
2011 
2012 
2014  elements()->PrintNameTo(stream);
2015  stream->Add("[");
2016  key()->PrintNameTo(stream);
2017  stream->Add("] = ");
2018  value()->PrintNameTo(stream);
2019 }
2020 
2021 
2023  object()->PrintNameTo(stream);
2024  stream->Add("[");
2025  key()->PrintNameTo(stream);
2026  stream->Add("] = ");
2027  value()->PrintNameTo(stream);
2028 }
2029 
2030 
2032  StringStream* stream) {
2033  external_pointer()->PrintNameTo(stream);
2034  stream->Add(".");
2035  switch (elements_kind()) {
2037  stream->Add("byte");
2038  break;
2040  stream->Add("u_byte");
2041  break;
2043  stream->Add("short");
2044  break;
2046  stream->Add("u_short");
2047  break;
2048  case EXTERNAL_INT_ELEMENTS:
2049  stream->Add("int");
2050  break;
2052  stream->Add("u_int");
2053  break;
2055  stream->Add("float");
2056  break;
2058  stream->Add("double");
2059  break;
2061  stream->Add("pixel");
2062  break;
2063  case FAST_SMI_ELEMENTS:
2064  case FAST_ELEMENTS:
2065  case FAST_DOUBLE_ELEMENTS:
2067  case FAST_HOLEY_ELEMENTS:
2069  case DICTIONARY_ELEMENTS:
2071  UNREACHABLE();
2072  break;
2073  }
2074  stream->Add("[");
2075  key()->PrintNameTo(stream);
2076  stream->Add("] = ");
2077  value()->PrintNameTo(stream);
2078 }
2079 
2080 
2082  object()->PrintNameTo(stream);
2083  ElementsKind from_kind = original_map()->elements_kind();
2084  ElementsKind to_kind = transitioned_map()->elements_kind();
2085  stream->Add(" %p [%s] -> %p [%s]",
2086  *original_map(),
2087  ElementsAccessor::ForKind(from_kind)->name(),
2088  *transitioned_map(),
2089  ElementsAccessor::ForKind(to_kind)->name());
2090 }
2091 
2092 
2094  stream->Add("[%p]", *cell());
2095  if (!details_.IsDontDelete()) stream->Add(" (deleteable)");
2096  if (details_.IsReadOnly()) stream->Add(" (read-only)");
2097 }
2098 
2099 
2101  if (details_.IsDontDelete() && !details_.IsReadOnly()) return false;
2102  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
2103  HValue* use = it.value();
2104  if (!use->IsChange()) return true;
2105  }
2106  return false;
2107 }
2108 
2109 
2111  stream->Add("%o ", *name());
2112 }
2113 
2114 
2116  stream->Add("[%p] = ", *cell());
2117  value()->PrintNameTo(stream);
2118  if (!details_.IsDontDelete()) stream->Add(" (deleteable)");
2119  if (details_.IsReadOnly()) stream->Add(" (read-only)");
2120 }
2121 
2122 
2124  stream->Add("%o = ", *name());
2125  value()->PrintNameTo(stream);
2126 }
2127 
2128 
2130  value()->PrintNameTo(stream);
2131  stream->Add("[%d]", slot_index());
2132 }
2133 
2134 
2136  context()->PrintNameTo(stream);
2137  stream->Add("[%d] = ", slot_index());
2138  value()->PrintNameTo(stream);
2139 }
2140 
2141 
2142 // Implementation of type inference and type conversions. Calculates
2143 // the inferred type of this instruction based on the input operands.
2144 
2146  return type_;
2147 }
2148 
2149 
2151  return value()->type();
2152 }
2153 
2154 
2156  return value()->type();
2157 }
2158 
2159 
2161  // TODO(kasperl): Is there any way to signal that this isn't a smi?
2162  return HType::Tagged();
2163 }
2164 
2165 
2167  return HType::Smi();
2168 }
2169 
2170 
2172  HType result = HType::Uninitialized();
2173  for (int i = 0; i < OperandCount(); ++i) {
2174  HType current = OperandAt(i)->type();
2175  result = result.Combine(current);
2176  }
2177  return result;
2178 }
2179 
2180 
2182  if (has_int32_value_) {
2183  return Smi::IsValid(int32_value_) ? HType::Smi() : HType::HeapNumber();
2184  }
2185  if (has_double_value_) return HType::HeapNumber();
2186  return HType::TypeFromValue(handle_);
2187 }
2188 
2189 
2191  return HType::Boolean();
2192 }
2193 
2194 
2196  return HType::Boolean();
2197 }
2198 
2199 
2201  return HType::Boolean();
2202 }
2203 
2204 
2206  return HType::Boolean();
2207 }
2208 
2209 
2211  if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber();
2212  return type();
2213 }
2214 
2215 
2217  return HType::TaggedNumber();
2218 }
2219 
2220 
2222  return HType::TaggedNumber();
2223 }
2224 
2225 
2227  return HType::Tagged();
2228 }
2229 
2230 
2232  return HType::TaggedNumber();
2233 }
2234 
2235 
2237  return HType::TaggedNumber();
2238 }
2239 
2240 
2242  return HType::String();
2243 }
2244 
2245 
2247  return HType::JSObject();
2248 }
2249 
2250 
2252  // TODO(mstarzinger): Be smarter, could also be JSArray here.
2253  return HType::JSObject();
2254 }
2255 
2256 
2258  return HType::JSArray();
2259 }
2260 
2261 
2263  return HType::JSObject();
2264 }
2265 
2266 
2268  return HType::JSObject();
2269 }
2270 
2271 
2273  return HType::JSObject();
2274 }
2275 
2276 
2278  BitVector* visited) {
2279  visited->Add(id());
2280  if (representation().IsInteger32() &&
2281  !value()->representation().IsInteger32()) {
2282  if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
2284  }
2285  }
2286  if (RequiredInputRepresentation(0).IsInteger32() &&
2287  representation().IsInteger32()) {
2288  return value();
2289  }
2290  return NULL;
2291 }
2292 
2293 
2294 
2296  visited->Add(id());
2297  if (from().IsInteger32()) return NULL;
2298  if (CanTruncateToInt32()) return NULL;
2299  if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
2301  }
2302  ASSERT(!from().IsInteger32() || !to().IsInteger32());
2303  return NULL;
2304 }
2305 
2306 
2308  BitVector* visited) {
2309  visited->Add(id());
2310  return value();
2311 }
2312 
2313 
2315  visited->Add(id());
2316  if (range() == NULL || range()->CanBeMinusZero()) {
2318  return left();
2319  }
2320  return NULL;
2321 }
2322 
2323 
2325  visited->Add(id());
2326  if (range() == NULL || range()->CanBeMinusZero()) {
2328  }
2329  return NULL;
2330 }
2331 
2332 
2334  visited->Add(id());
2336  return NULL;
2337 }
2338 
2339 
2341  visited->Add(id());
2342  if (range() == NULL || range()->CanBeMinusZero()) {
2344  }
2345  return NULL;
2346 }
2347 
2348 
2350  visited->Add(id());
2351  // Propagate to the left argument. If the left argument cannot be -0, then
2352  // the result of the add operation cannot be either.
2353  if (range() == NULL || range()->CanBeMinusZero()) {
2354  return left();
2355  }
2356  return NULL;
2357 }
2358 
2359 
2361  visited->Add(id());
2362  // Propagate to the left argument. If the left argument cannot be -0, then
2363  // the result of the sub operation cannot be either.
2364  if (range() == NULL || range()->CanBeMinusZero()) {
2365  return left();
2366  }
2367  return NULL;
2368 }
2369 
2370 
2372  // If value was loaded from unboxed double backing store or
2373  // converted from an integer then we don't have to canonicalize it.
2374  if (value()->IsLoadKeyedFastDoubleElement() ||
2375  (value()->IsChange() && HChange::cast(value())->from().IsInteger32())) {
2376  return false;
2377  }
2378  return true;
2379 }
2380 
2381 
2382 #define H_CONSTANT_INT32(val) \
2383 new(zone) HConstant(FACTORY->NewNumberFromInt(val, TENURED), \
2384  Representation::Integer32())
2385 #define H_CONSTANT_DOUBLE(val) \
2386 new(zone) HConstant(FACTORY->NewNumber(val, TENURED), \
2387  Representation::Double())
2388 
2389 #define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op) \
2390 HInstruction* HInstr::New##HInstr(Zone* zone, \
2391  HValue* context, \
2392  HValue* left, \
2393  HValue* right) { \
2394  if (left->IsConstant() && right->IsConstant()) { \
2395  HConstant* c_left = HConstant::cast(left); \
2396  HConstant* c_right = HConstant::cast(right); \
2397  if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
2398  double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \
2399  if (TypeInfo::IsInt32Double(double_res)) { \
2400  return H_CONSTANT_INT32(static_cast<int32_t>(double_res)); \
2401  } \
2402  return H_CONSTANT_DOUBLE(double_res); \
2403  } \
2404  } \
2405  return new(zone) HInstr(context, left, right); \
2406 }
2407 
2408 
2412 
2413 #undef DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR
2414 
2415 
2417  HValue* context,
2418  HValue* left,
2419  HValue* right) {
2420  if (left->IsConstant() && right->IsConstant()) {
2421  HConstant* c_left = HConstant::cast(left);
2422  HConstant* c_right = HConstant::cast(right);
2423  if (c_left->HasInteger32Value() && c_right->HasInteger32Value()) {
2424  int32_t dividend = c_left->Integer32Value();
2425  int32_t divisor = c_right->Integer32Value();
2426  if (divisor != 0) {
2427  int32_t res = dividend % divisor;
2428  if ((res == 0) && (dividend < 0)) {
2429  return H_CONSTANT_DOUBLE(-0.0);
2430  }
2431  return H_CONSTANT_INT32(res);
2432  }
2433  }
2434  }
2435  return new(zone) HMod(context, left, right);
2436 }
2437 
2438 
2440  HValue* context,
2441  HValue* left,
2442  HValue* right) {
2443  // If left and right are constant values, try to return a constant value.
2444  if (left->IsConstant() && right->IsConstant()) {
2445  HConstant* c_left = HConstant::cast(left);
2446  HConstant* c_right = HConstant::cast(right);
2447  if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
2448  if (c_right->DoubleValue() != 0) {
2449  double double_res = c_left->DoubleValue() / c_right->DoubleValue();
2450  if (TypeInfo::IsInt32Double(double_res)) {
2451  return H_CONSTANT_INT32(static_cast<int32_t>(double_res));
2452  }
2453  return H_CONSTANT_DOUBLE(double_res);
2454  }
2455  }
2456  }
2457  return new(zone) HDiv(context, left, right);
2458 }
2459 
2460 
2462  Token::Value op,
2463  HValue* context,
2464  HValue* left,
2465  HValue* right) {
2466  if (left->IsConstant() && right->IsConstant()) {
2467  HConstant* c_left = HConstant::cast(left);
2468  HConstant* c_right = HConstant::cast(right);
2469  if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
2470  int32_t result;
2471  int32_t v_left = c_left->NumberValueAsInteger32();
2472  int32_t v_right = c_right->NumberValueAsInteger32();
2473  switch (op) {
2474  case Token::BIT_XOR:
2475  result = v_left ^ v_right;
2476  break;
2477  case Token::BIT_AND:
2478  result = v_left & v_right;
2479  break;
2480  case Token::BIT_OR:
2481  result = v_left | v_right;
2482  break;
2483  default:
2484  result = 0; // Please the compiler.
2485  UNREACHABLE();
2486  }
2487  return H_CONSTANT_INT32(result);
2488  }
2489  }
2490  return new(zone) HBitwise(op, context, left, right);
2491 }
2492 
2493 
2494 #define DEFINE_NEW_H_BITWISE_INSTR(HInstr, result) \
2495 HInstruction* HInstr::New##HInstr(Zone* zone, \
2496  HValue* context, \
2497  HValue* left, \
2498  HValue* right) { \
2499  if (left->IsConstant() && right->IsConstant()) { \
2500  HConstant* c_left = HConstant::cast(left); \
2501  HConstant* c_right = HConstant::cast(right); \
2502  if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
2503  return H_CONSTANT_INT32(result); \
2504  } \
2505  } \
2506  return new(zone) HInstr(context, left, right); \
2507 }
2508 
2509 
2511 c_left->NumberValueAsInteger32() >> (c_right->NumberValueAsInteger32() & 0x1f))
2513 c_left->NumberValueAsInteger32() << (c_right->NumberValueAsInteger32() & 0x1f))
2514 
2515 #undef DEFINE_NEW_H_BITWISE_INSTR
2516 
2517 
2519  HValue* context,
2520  HValue* left,
2521  HValue* right) {
2522  if (left->IsConstant() && right->IsConstant()) {
2523  HConstant* c_left = HConstant::cast(left);
2524  HConstant* c_right = HConstant::cast(right);
2525  if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
2526  int32_t left_val = c_left->NumberValueAsInteger32();
2527  int32_t right_val = c_right->NumberValueAsInteger32() & 0x1f;
2528  if ((right_val == 0) && (left_val < 0)) {
2529  return H_CONSTANT_DOUBLE(
2530  static_cast<double>(static_cast<uint32_t>(left_val)));
2531  }
2532  return H_CONSTANT_INT32(static_cast<uint32_t>(left_val) >> right_val);
2533  }
2534  }
2535  return new(zone) HShr(context, left, right);
2536 }
2537 
2538 
2539 #undef H_CONSTANT_INT32
2540 #undef H_CONSTANT_DOUBLE
2541 
2542 
2544  key()->PrintNameTo(stream);
2545  stream->Add(" ");
2546  object()->PrintNameTo(stream);
2547 }
2548 
2549 
2551  stream->Add(Token::Name(op_));
2552  stream->Add(" ");
2554 }
2555 
2556 
2558  bool double_occurred = false;
2559  bool int32_occurred = false;
2560  for (int i = 0; i < OperandCount(); ++i) {
2561  HValue* value = OperandAt(i);
2562  if (value->IsUnknownOSRValue()) {
2563  HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value();
2564  if (hint_value != NULL) {
2565  Representation hint = hint_value->representation();
2566  if (hint.IsDouble()) double_occurred = true;
2567  if (hint.IsInteger32()) int32_occurred = true;
2568  }
2569  continue;
2570  }
2571  if (value->representation().IsDouble()) double_occurred = true;
2572  if (value->representation().IsInteger32()) int32_occurred = true;
2573  if (value->representation().IsTagged()) {
2574  if (value->IsConstant()) {
2575  HConstant* constant = HConstant::cast(value);
2576  if (constant->IsConvertibleToInteger()) {
2577  int32_occurred = true;
2578  } else if (constant->HasNumberValue()) {
2579  double_occurred = true;
2580  } else {
2581  return Representation::Tagged();
2582  }
2583  } else {
2584  return Representation::Tagged();
2585  }
2586  }
2587  }
2588 
2589  if (double_occurred) return Representation::Double();
2590 
2591  if (int32_occurred) return Representation::Integer32();
2592 
2593  return Representation::None();
2594 }
2595 
2596 
2597 // Node-specific verification code is only included in debug mode.
2598 #ifdef DEBUG
2599 
2600 void HPhi::Verify() {
2601  ASSERT(OperandCount() == block()->predecessors()->length());
2602  for (int i = 0; i < OperandCount(); ++i) {
2603  HValue* value = OperandAt(i);
2604  HBasicBlock* defining_block = value->block();
2605  HBasicBlock* predecessor_block = block()->predecessors()->at(i);
2606  ASSERT(defining_block == predecessor_block ||
2607  defining_block->Dominates(predecessor_block));
2608  }
2609 }
2610 
2611 
2612 void HSimulate::Verify() {
2613  HInstruction::Verify();
2614  ASSERT(HasAstId());
2615 }
2616 
2617 
2618 void HCheckSmi::Verify() {
2619  HInstruction::Verify();
2620  ASSERT(HasNoUses());
2621 }
2622 
2623 
2624 void HCheckNonSmi::Verify() {
2625  HInstruction::Verify();
2626  ASSERT(HasNoUses());
2627 }
2628 
2629 
2630 void HCheckFunction::Verify() {
2631  HInstruction::Verify();
2632  ASSERT(HasNoUses());
2633 }
2634 
2635 
2636 void HCheckPrototypeMaps::Verify() {
2637  HInstruction::Verify();
2638  ASSERT(HasNoUses());
2639 }
2640 
2641 #endif
2642 
2643 } } // namespace v8::internal
virtual void PrintDataTo(StringStream *stream)
bool HasObservableSideEffects() const
void set_can_be_minus_zero(bool b)
void CombinedMin(Range *other)
virtual HValue * EnsureAndPropagateNotMinusZero(BitVector *visited)
const int kMinInt
Definition: globals.h:211
virtual bool IsConvertibleToInteger() const
Handle< String > name() const
bool IsFinished() const
Definition: hydrogen.h:101
virtual void PrintDataTo(StringStream *stream)
Handle< Map > at(int i) const
Definition: ast.h:278
virtual HValue * EnsureAndPropagateNotMinusZero(BitVector *visited)
static bool IsInt32Double(double value)
Definition: type-info.h:106
HType Combine(HType other)
const char * ToCString(const v8::String::Utf8Value &value)
virtual HValue * EnsureAndPropagateNotMinusZero(BitVector *visited)
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
void PrintF(const char *format,...)
Definition: v8utils.cc:40
HDiv(HValue *context, HValue *left, HValue *right)
virtual bool DataEquals(HValue *other)
static String * cast(Object *obj)
bool Equals(const HType &other)
virtual void PrintDataTo(StringStream *stream)
HConstant * CopyToRepresentation(Representation r, Zone *zone) const
virtual void PrintDataTo(StringStream *stream)
HUseListNode * RemoveUse(HValue *value, int index)
#define PRINT_DO(type)
HInstruction * previous() const
static const char * Name(Value tok)
Definition: token.h:196
Representation from() const
HLoadNamedFieldPolymorphic(HValue *context, HValue *object, SmallMapList *types, Handle< String > name, Zone *zone)
virtual void PrintDataTo(StringStream *stream)
void CombinedMax(Range *other)
int current_
bool Dominates(HBasicBlock *other) const
Definition: hydrogen.cc:222
virtual void PrintDataTo(StringStream *stream)
void Intersect(Range *other)
virtual void PrintDataTo(StringStream *stream)
virtual HType CalculateInferredType()
HBitwise(Token::Value op, HValue *context, HValue *left, HValue *right)
HBasicBlock * block() const
static Handle< T > cast(Handle< S > that)
Definition: handles.h:81
static Representation Integer32()
Handle< JSGlobalPropertyCell > cell() const
T Max(T a, T b)
Definition: utils.h:222
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
bool is_identical_to(const Handle< T > other) const
Definition: handles.h:67
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
Handle< String > name() const
virtual void PrintDataTo(StringStream *stream)
HInstruction * first() const
Definition: hydrogen.h:65
HGraph * graph() const
Definition: hydrogen.h:63
int int32_t
Definition: unicode.cc:47
Token::Value op() const
void AssumeRepresentation(Representation r)
const int kMaxInt
Definition: globals.h:210
virtual void PrintDataTo(StringStream *stream)
void AddConstant(int32_t value)
#define ASSERT(condition)
Definition: checks.h:270
Handle< JSObject > prototype() const
virtual Range * InferRange(Zone *zone)
static HInstruction * NewHMod(Zone *zone, HValue *context, HValue *left, HValue *right)
const ZoneList< HBasicBlock * > * predecessors() const
Definition: hydrogen.h:71
bool IsEmpty() const
Definition: utils.h:968
virtual void PrintDataTo(StringStream *stream)
HControlInstruction * end() const
Definition: hydrogen.h:69
virtual Representation InferredRepresentation()
virtual HValue * OperandAt(int index) const
static Representation Double()
bool Equals(const Representation &other)
virtual void PrintDataTo(StringStream *stream)
int isnan(double x)
virtual void PrintDataTo(StringStream *stream)
Representation representation() const
virtual void PrintDataTo(StringStream *stream)
DEFINE_NEW_H_BITWISE_INSTR(HSar, c_left->NumberValueAsInteger32() >>(c_right->NumberValueAsInteger32()&0x1f)) DEFINE_NEW_H_BITWISE_INSTR(HShl
virtual void PrintDataTo(StringStream *stream)
void set_representation(Representation r)
virtual void PrintDataTo(StringStream *stream)
virtual int argument_count() const
virtual Range * InferRange(Zone *zone)
virtual void PrintDataTo(StringStream *stream)
void Add(Vector< const char > format, Vector< FmtElm > elms)
void LookupDescriptor(JSObject *holder, String *name, LookupResult *result)
Definition: objects-inl.h:2061
virtual void PrintDataTo(StringStream *stream)
Handle< JSFunction > target() const
virtual HType CalculateInferredType()
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
Handle< JSFunction > target() const
#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V)
virtual HType CalculateInferredType()
void AddNewRange(Range *r, Zone *zone)
void RemovePhi(HPhi *phi)
Definition: hydrogen.cc:96
virtual int OperandCount()=0
#define UNREACHABLE()
Definition: checks.h:50
bool Equals(HValue *other)
void PrintRangeTo(StringStream *stream)
const uint32_t kIsSymbolMask
Definition: objects.h:462
virtual HType CalculateInferredType()
virtual void PrintDataTo(StringStream *stream)
static GVNFlagSet AllSideEffectsFlagSet()
HMod(HValue *context, HValue *left, HValue *right)
bool IsFastPackedElementsKind(ElementsKind kind)
void PrintChangesTo(StringStream *stream)
#define DEFINE_COMPILE(type)
static HUnaryOperation * cast(HValue *value)
virtual void PrintDataTo(StringStream *stream)
virtual Range * InferRange(Zone *zone)
virtual void PrintDataTo(StringStream *stream)
virtual Range * InferRange(Zone *zone)
Handle< String > name() const
static bool IsValid(intptr_t value)
Definition: objects-inl.h:1059
Range * Copy(Zone *zone) const
int length() const
Definition: ast.h:272
virtual HValue * OperandAt(int index) const
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
bool IsDefinedAfter(HBasicBlock *other) const
int GetAssignedIndexAt(int index) const
virtual void PrintDataTo(StringStream *stream)
void ComputeInitialRange(Zone *zone)
#define GVN_TRACKED_FLAG_LIST(V)
virtual void PrintDataTo(StringStream *stream)
void AddInput(HValue *value)
virtual Range * InferRange(Zone *zone)
GVNFlagSet ChangesFlags() const
virtual HValue * Canonicalize()
virtual Range * InferRange(Zone *zone)
virtual Range * InferRange(Zone *zone)
HInstruction * next() const
virtual bool IsConvertibleToInteger() const
virtual HValue * Canonicalize()
virtual HValue * EnsureAndPropagateNotMinusZero(BitVector *visited)
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
void set_type(HType new_type)
virtual void PrintDataTo(StringStream *stream)
virtual Range * InferRange(Zone *zone)
virtual void PrintDataTo(StringStream *stream)
static HInstruction * NewHShr(Zone *zone, HValue *context, HValue *left, HValue *right)
#define MAKE_CASE(type)
static HInstruction * NewHBitwise(Zone *zone, Token::Value op, HValue *context, HValue *left, HValue *right)
const uint32_t kStringTag
Definition: objects.h:456
virtual void PrintDataTo(StringStream *stream)
HInstruction * last() const
Definition: hydrogen.h:66
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
virtual void PrintTo(StringStream *stream)
activate correct semantics for inheriting readonliness false
Definition: flags.cc:141
virtual HValue * Canonicalize()
void AddNonPhiUsesFrom(HPhi *other)
void DeleteAndReplaceWith(HValue *other)
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
static HInstruction * NewHDiv(Zone *zone, HValue *context, HValue *left, HValue *right)
virtual void PrintDataTo(StringStream *stream)
#define GVN_UNTRACKED_FLAG_LIST(V)
virtual void PrintDataTo(StringStream *stream)
void set_last(HInstruction *instr)
Definition: hydrogen.h:67
virtual intptr_t Hashcode()
bool SubAndCheckOverflow(Range *other)
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
static ElementsAccessor * ForKind(ElementsKind elements_kind)
Definition: elements.h:134
virtual Representation ObservedInputRepresentation(int index)
void PrintNameTo(StringStream *stream)
HConstant(Handle< Object > handle, Representation r)
void InsertAfter(HInstruction *previous)
virtual Opcode opcode() const =0
virtual void DeleteFromGraph()=0
virtual void PrintTo(StringStream *stream)
bool has_named_interceptor()
Definition: objects.h:4734
virtual void PrintDataTo(StringStream *stream)
Representation to() const
int32_t DoubleToInt32(double x)
const uint32_t kIsNotStringMask
Definition: objects.h:455
virtual void PrintDataTo(StringStream *stream)
void ChangeRepresentation(Representation r)
virtual HValue * EnsureAndPropagateNotMinusZero(BitVector *visited)
bool is_null() const
Definition: handles.h:87
HShr(HValue *context, HValue *left, HValue *right)
virtual HType CalculateInferredType()
void SetOperandAt(int index, HValue *value)
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
virtual Range * InferRange(Zone *zone)
bool CheckFlag(Flag f) const
virtual void PrintDataTo(StringStream *stream)
virtual HValue * Canonicalize()
#define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op)
int32_t NumberValueAsInteger32() const
void InsertBefore(HInstruction *next)
static HType TypeFromValue(Handle< Object > value)
virtual Range * InferRange(Zone *zone)
#define H_CONSTANT_DOUBLE(val)
virtual HValue * EnsureAndPropagateNotMinusZero(BitVector *visited)
bool IsStartBlock() const
Definition: hydrogen.h:98
virtual void PrintDataTo(StringStream *stream)
#define HEAP
Definition: isolate.h:1433
void SetBlock(HBasicBlock *block)
void Sar(int32_t value)
virtual void PrintDataTo(StringStream *stream)
virtual HValue * EnsureAndPropagateNotMinusZero(BitVector *visited)
virtual HValue * OperandAt(int index) const =0
virtual void PrintDataTo(StringStream *stream)
virtual void PrintDataTo(StringStream *stream)
double FastI2D(int x)
Definition: conversions.h:76
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Definition: flags.cc:301
virtual Range * InferRange(Zone *zone)
int GetNextValueID(HValue *value)
Definition: hydrogen.h:305
void Shl(int32_t value)
virtual void PrintDataTo(StringStream *stream)
virtual HValue * EnsureAndPropagateNotMinusZero(BitVector *visited)
HConstant * CopyToTruncatedInt32(Zone *zone) const
virtual void PrintDataTo(StringStream *stream)
const char * Mnemonic() const
Handle< JSObject > holder() const
void AddIndirectUsesTo(int *use_count)
virtual void PrintDataTo(StringStream *stream)
virtual Range * InferRange(Zone *zone)
virtual void InternalSetOperandAt(int index, HValue *value)=0
virtual void PrintDataTo(StringStream *stream)
int block_id() const
Definition: hydrogen.h:61
const uint32_t kSymbolTag
Definition: objects.h:464
virtual void PrintDataTo(StringStream *stream)
void set_tail(HUseListNode *list)
virtual Range * InferRange(Zone *zone)
static Representation Tagged()
void GetCheckMaskAndTag(uint8_t *mask, uint8_t *tag)
void PrintTypeTo(StringStream *stream)
Handle< JSGlobalPropertyCell > cell() const
void StackUpon(Range *other)
virtual void PrintDataTo(StringStream *stream)
void Add(Handle< Map > handle, Zone *zone)
Definition: ast.h:274
T Min(T a, T b)
Definition: utils.h:229
Zone * zone() const
Definition: hydrogen.h:418
#define H_CONSTANT_INT32(val)
void RegisterUse(int index, HValue *new_value)
bool HasAssignedIndexAt(int index) const
virtual Representation RequiredInputRepresentation(int index)
void Union(Range *other)
void GetCheckInterval(InstanceType *first, InstanceType *last)
virtual void PrintDataTo(StringStream *stream)
static HValue * cast(HValue *value)
void ReplaceAllUsesWith(HValue *other)
#define ARRAY_SIZE(a)
Definition: globals.h:281
bool AddAndCheckOverflow(Range *other)
virtual void PrintDataTo(StringStream *stream)
static JSObject * cast(Object *obj)
c_left NumberValueAsInteger32()<< (c_right-> NumberValueAsInteger32()&0x1f)) HInstruction *HShr::NewHShr(Zone *zone, HValue *context, HValue *left, HValue *right)
virtual HValue * Canonicalize()
virtual HValue * EnsureAndPropagateNotMinusZero(BitVector *visited)
bool MulAndCheckOverflow(Range *other)
static bool IsOrderedRelationalCompareOp(Value op)
Definition: token.h:218
HUseIterator uses() const
virtual Range * InferRange(Zone *zone)
virtual void PrintDataTo(StringStream *stream)
virtual HValue * Canonicalize()