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 }
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) const52 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
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
LoopWeight() const70 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
AssumeRepresentation(Representation r)78 void HValue::AssumeRepresentation(Representation r) {
79 if (CheckFlag(kFlexibleRepresentation)) {
80 ChangeRepresentation(r);
81 // The representation of the value is dictated by type feedback and
82 // will not be changed later.
83 ClearFlag(kFlexibleRepresentation);
84 }
85 }
86
87
ConvertAndSetOverflow(int64_t result,bool * overflow)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
AddWithoutOverflow(int32_t a,int32_t b,bool * overflow)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
SubWithoutOverflow(int32_t a,int32_t b,bool * overflow)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
MulWithoutOverflow(int32_t a,int32_t b,bool * overflow)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
Mask() const119 int32_t Range::Mask() const {
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
AddConstant(int32_t value)132 void Range::AddConstant(int32_t value) {
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
Intersect(Range * other)143 void Range::Intersect(Range* other) {
144 upper_ = Min(upper_, other->upper_);
145 lower_ = Max(lower_, other->lower_);
146 bool b = CanBeMinusZero() && other->CanBeMinusZero();
147 set_can_be_minus_zero(b);
148 }
149
150
Union(Range * other)151 void Range::Union(Range* other) {
152 upper_ = Max(upper_, other->upper_);
153 lower_ = Min(lower_, other->lower_);
154 bool b = CanBeMinusZero() || other->CanBeMinusZero();
155 set_can_be_minus_zero(b);
156 }
157
158
Sar(int32_t value)159 void Range::Sar(int32_t value) {
160 int32_t bits = value & 0x1F;
161 lower_ = lower_ >> bits;
162 upper_ = upper_ >> bits;
163 set_can_be_minus_zero(false);
164 }
165
166
Shl(int32_t value)167 void Range::Shl(int32_t value) {
168 int32_t bits = value & 0x1F;
169 int old_lower = lower_;
170 int old_upper = upper_;
171 lower_ = lower_ << bits;
172 upper_ = upper_ << bits;
173 if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) {
174 upper_ = kMaxInt;
175 lower_ = kMinInt;
176 }
177 set_can_be_minus_zero(false);
178 }
179
180
AddAndCheckOverflow(Range * other)181 bool Range::AddAndCheckOverflow(Range* other) {
182 bool may_overflow = false;
183 lower_ = AddWithoutOverflow(lower_, other->lower(), &may_overflow);
184 upper_ = AddWithoutOverflow(upper_, other->upper(), &may_overflow);
185 KeepOrder();
186 #ifdef DEBUG
187 Verify();
188 #endif
189 return may_overflow;
190 }
191
192
SubAndCheckOverflow(Range * other)193 bool Range::SubAndCheckOverflow(Range* other) {
194 bool may_overflow = false;
195 lower_ = SubWithoutOverflow(lower_, other->upper(), &may_overflow);
196 upper_ = SubWithoutOverflow(upper_, other->lower(), &may_overflow);
197 KeepOrder();
198 #ifdef DEBUG
199 Verify();
200 #endif
201 return may_overflow;
202 }
203
204
KeepOrder()205 void Range::KeepOrder() {
206 if (lower_ > upper_) {
207 int32_t tmp = lower_;
208 lower_ = upper_;
209 upper_ = tmp;
210 }
211 }
212
213
214 #ifdef DEBUG
Verify() const215 void Range::Verify() const {
216 ASSERT(lower_ <= upper_);
217 }
218 #endif
219
220
MulAndCheckOverflow(Range * other)221 bool Range::MulAndCheckOverflow(Range* other) {
222 bool may_overflow = false;
223 int v1 = MulWithoutOverflow(lower_, other->lower(), &may_overflow);
224 int v2 = MulWithoutOverflow(lower_, other->upper(), &may_overflow);
225 int v3 = MulWithoutOverflow(upper_, other->lower(), &may_overflow);
226 int v4 = MulWithoutOverflow(upper_, other->upper(), &may_overflow);
227 lower_ = Min(Min(v1, v2), Min(v3, v4));
228 upper_ = Max(Max(v1, v2), Max(v3, v4));
229 #ifdef DEBUG
230 Verify();
231 #endif
232 return may_overflow;
233 }
234
235
ToString()236 const char* HType::ToString() {
237 switch (type_) {
238 case kTagged: return "tagged";
239 case kTaggedPrimitive: return "primitive";
240 case kTaggedNumber: return "number";
241 case kSmi: return "smi";
242 case kHeapNumber: return "heap-number";
243 case kString: return "string";
244 case kBoolean: return "boolean";
245 case kNonPrimitive: return "non-primitive";
246 case kJSArray: return "array";
247 case kJSObject: return "object";
248 case kUninitialized: return "uninitialized";
249 }
250 UNREACHABLE();
251 return "Unreachable code";
252 }
253
254
TypeFromValue(Handle<Object> value)255 HType HType::TypeFromValue(Handle<Object> value) {
256 HType result = HType::Tagged();
257 if (value->IsSmi()) {
258 result = HType::Smi();
259 } else if (value->IsHeapNumber()) {
260 result = HType::HeapNumber();
261 } else if (value->IsString()) {
262 result = HType::String();
263 } else if (value->IsBoolean()) {
264 result = HType::Boolean();
265 } else if (value->IsJSObject()) {
266 result = HType::JSObject();
267 } else if (value->IsJSArray()) {
268 result = HType::JSArray();
269 }
270 return result;
271 }
272
273
IsDefinedAfter(HBasicBlock * other) const274 bool HValue::IsDefinedAfter(HBasicBlock* other) const {
275 return block()->block_id() > other->block_id();
276 }
277
278
tail()279 HUseListNode* HUseListNode::tail() {
280 // Skip and remove dead items in the use list.
281 while (tail_ != NULL && tail_->value()->CheckFlag(HValue::kIsDead)) {
282 tail_ = tail_->tail_;
283 }
284 return tail_;
285 }
286
287
CheckUsesForFlag(Flag f)288 bool HValue::CheckUsesForFlag(Flag f) {
289 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
290 if (!it.value()->CheckFlag(f)) return false;
291 }
292 return true;
293 }
294
295
HUseIterator(HUseListNode * head)296 HUseIterator::HUseIterator(HUseListNode* head) : next_(head) {
297 Advance();
298 }
299
300
Advance()301 void HUseIterator::Advance() {
302 current_ = next_;
303 if (current_ != NULL) {
304 next_ = current_->tail();
305 value_ = current_->value();
306 index_ = current_->index();
307 }
308 }
309
310
UseCount() const311 int HValue::UseCount() const {
312 int count = 0;
313 for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count;
314 return count;
315 }
316
317
RemoveUse(HValue * value,int index)318 HUseListNode* HValue::RemoveUse(HValue* value, int index) {
319 HUseListNode* previous = NULL;
320 HUseListNode* current = use_list_;
321 while (current != NULL) {
322 if (current->value() == value && current->index() == index) {
323 if (previous == NULL) {
324 use_list_ = current->tail();
325 } else {
326 previous->set_tail(current->tail());
327 }
328 break;
329 }
330
331 previous = current;
332 current = current->tail();
333 }
334
335 #ifdef DEBUG
336 // Do not reuse use list nodes in debug mode, zap them.
337 if (current != NULL) {
338 HUseListNode* temp =
339 new HUseListNode(current->value(), current->index(), NULL);
340 current->Zap();
341 current = temp;
342 }
343 #endif
344 return current;
345 }
346
347
Equals(HValue * other)348 bool HValue::Equals(HValue* other) {
349 if (other->opcode() != opcode()) return false;
350 if (!other->representation().Equals(representation())) return false;
351 if (!other->type_.Equals(type_)) return false;
352 if (other->flags() != flags()) return false;
353 if (OperandCount() != other->OperandCount()) return false;
354 for (int i = 0; i < OperandCount(); ++i) {
355 if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false;
356 }
357 bool result = DataEquals(other);
358 ASSERT(!result || Hashcode() == other->Hashcode());
359 return result;
360 }
361
362
Hashcode()363 intptr_t HValue::Hashcode() {
364 intptr_t result = opcode();
365 int count = OperandCount();
366 for (int i = 0; i < count; ++i) {
367 result = result * 19 + OperandAt(i)->id() + (result >> 7);
368 }
369 return result;
370 }
371
372
Mnemonic() const373 const char* HValue::Mnemonic() const {
374 switch (opcode()) {
375 #define MAKE_CASE(type) case k##type: return #type;
376 HYDROGEN_CONCRETE_INSTRUCTION_LIST(MAKE_CASE)
377 #undef MAKE_CASE
378 case kPhi: return "Phi";
379 default: return "";
380 }
381 }
382
383
SetOperandAt(int index,HValue * value)384 void HValue::SetOperandAt(int index, HValue* value) {
385 RegisterUse(index, value);
386 InternalSetOperandAt(index, value);
387 }
388
389
DeleteAndReplaceWith(HValue * other)390 void HValue::DeleteAndReplaceWith(HValue* other) {
391 // We replace all uses first, so Delete can assert that there are none.
392 if (other != NULL) ReplaceAllUsesWith(other);
393 ASSERT(HasNoUses());
394 Kill();
395 DeleteFromGraph();
396 }
397
398
ReplaceAllUsesWith(HValue * other)399 void HValue::ReplaceAllUsesWith(HValue* other) {
400 while (use_list_ != NULL) {
401 HUseListNode* list_node = use_list_;
402 HValue* value = list_node->value();
403 ASSERT(!value->block()->IsStartBlock());
404 value->InternalSetOperandAt(list_node->index(), other);
405 use_list_ = list_node->tail();
406 list_node->set_tail(other->use_list_);
407 other->use_list_ = list_node;
408 }
409 }
410
411
Kill()412 void HValue::Kill() {
413 // Instead of going through the entire use list of each operand, we only
414 // check the first item in each use list and rely on the tail() method to
415 // skip dead items, removing them lazily next time we traverse the list.
416 SetFlag(kIsDead);
417 for (int i = 0; i < OperandCount(); ++i) {
418 HValue* operand = OperandAt(i);
419 HUseListNode* first = operand->use_list_;
420 if (first != NULL && first->value() == this && first->index() == i) {
421 operand->use_list_ = first->tail();
422 }
423 }
424 }
425
426
SetBlock(HBasicBlock * block)427 void HValue::SetBlock(HBasicBlock* block) {
428 ASSERT(block_ == NULL || block == NULL);
429 block_ = block;
430 if (id_ == kNoNumber && block != NULL) {
431 id_ = block->graph()->GetNextValueID(this);
432 }
433 }
434
435
PrintTypeTo(StringStream * stream)436 void HValue::PrintTypeTo(StringStream* stream) {
437 if (!representation().IsTagged() || type().Equals(HType::Tagged())) return;
438 stream->Add(" type[%s]", type().ToString());
439 }
440
441
PrintRangeTo(StringStream * stream)442 void HValue::PrintRangeTo(StringStream* stream) {
443 if (range() == NULL || range()->IsMostGeneric()) return;
444 stream->Add(" range[%d,%d,m0=%d]",
445 range()->lower(),
446 range()->upper(),
447 static_cast<int>(range()->CanBeMinusZero()));
448 }
449
450
PrintChangesTo(StringStream * stream)451 void HValue::PrintChangesTo(StringStream* stream) {
452 GVNFlagSet changes_flags = ChangesFlags();
453 if (changes_flags.IsEmpty()) return;
454 stream->Add(" changes[");
455 if (changes_flags == AllSideEffectsFlagSet()) {
456 stream->Add("*");
457 } else {
458 bool add_comma = false;
459 #define PRINT_DO(type) \
460 if (changes_flags.Contains(kChanges##type)) { \
461 if (add_comma) stream->Add(","); \
462 add_comma = true; \
463 stream->Add(#type); \
464 }
465 GVN_FLAG_LIST(PRINT_DO);
466 #undef PRINT_DO
467 }
468 stream->Add("]");
469 }
470
471
PrintNameTo(StringStream * stream)472 void HValue::PrintNameTo(StringStream* stream) {
473 stream->Add("%s%d", representation_.Mnemonic(), id());
474 }
475
476
UpdateInferredType()477 bool HValue::UpdateInferredType() {
478 HType type = CalculateInferredType();
479 bool result = (!type.Equals(type_));
480 type_ = type;
481 return result;
482 }
483
484
RegisterUse(int index,HValue * new_value)485 void HValue::RegisterUse(int index, HValue* new_value) {
486 HValue* old_value = OperandAt(index);
487 if (old_value == new_value) return;
488
489 HUseListNode* removed = NULL;
490 if (old_value != NULL) {
491 removed = old_value->RemoveUse(this, index);
492 }
493
494 if (new_value != NULL) {
495 if (removed == NULL) {
496 new_value->use_list_ =
497 new HUseListNode(this, index, new_value->use_list_);
498 } else {
499 removed->set_tail(new_value->use_list_);
500 new_value->use_list_ = removed;
501 }
502 }
503 }
504
505
AddNewRange(Range * r,Zone * zone)506 void HValue::AddNewRange(Range* r, Zone* zone) {
507 if (!HasRange()) ComputeInitialRange(zone);
508 if (!HasRange()) range_ = new(zone) Range();
509 ASSERT(HasRange());
510 r->StackUpon(range_);
511 range_ = r;
512 }
513
514
RemoveLastAddedRange()515 void HValue::RemoveLastAddedRange() {
516 ASSERT(HasRange());
517 ASSERT(range_->next() != NULL);
518 range_ = range_->next();
519 }
520
521
ComputeInitialRange(Zone * zone)522 void HValue::ComputeInitialRange(Zone* zone) {
523 ASSERT(!HasRange());
524 range_ = InferRange(zone);
525 ASSERT(HasRange());
526 }
527
528
PrintTo(StringStream * stream)529 void HInstruction::PrintTo(StringStream* stream) {
530 PrintMnemonicTo(stream);
531 PrintDataTo(stream);
532 PrintRangeTo(stream);
533 PrintChangesTo(stream);
534 PrintTypeTo(stream);
535 }
536
537
PrintMnemonicTo(StringStream * stream)538 void HInstruction::PrintMnemonicTo(StringStream* stream) {
539 stream->Add("%s ", Mnemonic());
540 }
541
542
Unlink()543 void HInstruction::Unlink() {
544 ASSERT(IsLinked());
545 ASSERT(!IsControlInstruction()); // Must never move control instructions.
546 ASSERT(!IsBlockEntry()); // Doesn't make sense to delete these.
547 ASSERT(previous_ != NULL);
548 previous_->next_ = next_;
549 if (next_ == NULL) {
550 ASSERT(block()->last() == this);
551 block()->set_last(previous_);
552 } else {
553 next_->previous_ = previous_;
554 }
555 clear_block();
556 }
557
558
InsertBefore(HInstruction * next)559 void HInstruction::InsertBefore(HInstruction* next) {
560 ASSERT(!IsLinked());
561 ASSERT(!next->IsBlockEntry());
562 ASSERT(!IsControlInstruction());
563 ASSERT(!next->block()->IsStartBlock());
564 ASSERT(next->previous_ != NULL);
565 HInstruction* prev = next->previous();
566 prev->next_ = this;
567 next->previous_ = this;
568 next_ = next;
569 previous_ = prev;
570 SetBlock(next->block());
571 }
572
573
InsertAfter(HInstruction * previous)574 void HInstruction::InsertAfter(HInstruction* previous) {
575 ASSERT(!IsLinked());
576 ASSERT(!previous->IsControlInstruction());
577 ASSERT(!IsControlInstruction() || previous->next_ == NULL);
578 HBasicBlock* block = previous->block();
579 // Never insert anything except constants into the start block after finishing
580 // it.
581 if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) {
582 ASSERT(block->end()->SecondSuccessor() == NULL);
583 InsertAfter(block->end()->FirstSuccessor()->first());
584 return;
585 }
586
587 // If we're inserting after an instruction with side-effects that is
588 // followed by a simulate instruction, we need to insert after the
589 // simulate instruction instead.
590 HInstruction* next = previous->next_;
591 if (previous->HasObservableSideEffects() && next != NULL) {
592 ASSERT(next->IsSimulate());
593 previous = next;
594 next = previous->next_;
595 }
596
597 previous_ = previous;
598 next_ = next;
599 SetBlock(block);
600 previous->next_ = this;
601 if (next != NULL) next->previous_ = this;
602 }
603
604
605 #ifdef DEBUG
Verify()606 void HInstruction::Verify() {
607 // Verify that input operands are defined before use.
608 HBasicBlock* cur_block = block();
609 for (int i = 0; i < OperandCount(); ++i) {
610 HValue* other_operand = OperandAt(i);
611 HBasicBlock* other_block = other_operand->block();
612 if (cur_block == other_block) {
613 if (!other_operand->IsPhi()) {
614 HInstruction* cur = this->previous();
615 while (cur != NULL) {
616 if (cur == other_operand) break;
617 cur = cur->previous();
618 }
619 // Must reach other operand in the same block!
620 ASSERT(cur == other_operand);
621 }
622 } else {
623 // If the following assert fires, you may have forgotten an
624 // AddInstruction.
625 ASSERT(other_block->Dominates(cur_block));
626 }
627 }
628
629 // Verify that instructions that may have side-effects are followed
630 // by a simulate instruction.
631 if (HasObservableSideEffects() && !IsOsrEntry()) {
632 ASSERT(next()->IsSimulate());
633 }
634
635 // Verify that instructions that can be eliminated by GVN have overridden
636 // HValue::DataEquals. The default implementation is UNREACHABLE. We
637 // don't actually care whether DataEquals returns true or false here.
638 if (CheckFlag(kUseGVN)) DataEquals(this);
639 }
640 #endif
641
642
PrintDataTo(StringStream * stream)643 void HUnaryCall::PrintDataTo(StringStream* stream) {
644 value()->PrintNameTo(stream);
645 stream->Add(" ");
646 stream->Add("#%d", argument_count());
647 }
648
649
PrintDataTo(StringStream * stream)650 void HBinaryCall::PrintDataTo(StringStream* stream) {
651 first()->PrintNameTo(stream);
652 stream->Add(" ");
653 second()->PrintNameTo(stream);
654 stream->Add(" ");
655 stream->Add("#%d", argument_count());
656 }
657
658
PrintDataTo(StringStream * stream)659 void HBoundsCheck::PrintDataTo(StringStream* stream) {
660 index()->PrintNameTo(stream);
661 stream->Add(" ");
662 length()->PrintNameTo(stream);
663 }
664
665
PrintDataTo(StringStream * stream)666 void HCallConstantFunction::PrintDataTo(StringStream* stream) {
667 if (IsApplyFunction()) {
668 stream->Add("optimized apply ");
669 } else {
670 stream->Add("%o ", function()->shared()->DebugName());
671 }
672 stream->Add("#%d", argument_count());
673 }
674
675
PrintDataTo(StringStream * stream)676 void HCallNamed::PrintDataTo(StringStream* stream) {
677 stream->Add("%o ", *name());
678 HUnaryCall::PrintDataTo(stream);
679 }
680
681
PrintDataTo(StringStream * stream)682 void HCallGlobal::PrintDataTo(StringStream* stream) {
683 stream->Add("%o ", *name());
684 HUnaryCall::PrintDataTo(stream);
685 }
686
687
PrintDataTo(StringStream * stream)688 void HCallKnownGlobal::PrintDataTo(StringStream* stream) {
689 stream->Add("o ", target()->shared()->DebugName());
690 stream->Add("#%d", argument_count());
691 }
692
693
PrintDataTo(StringStream * stream)694 void HCallRuntime::PrintDataTo(StringStream* stream) {
695 stream->Add("%o ", *name());
696 stream->Add("#%d", argument_count());
697 }
698
699
PrintDataTo(StringStream * stream)700 void HClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
701 stream->Add("class_of_test(");
702 value()->PrintNameTo(stream);
703 stream->Add(", \"%o\")", *class_name());
704 }
705
706
PrintDataTo(StringStream * stream)707 void HAccessArgumentsAt::PrintDataTo(StringStream* stream) {
708 arguments()->PrintNameTo(stream);
709 stream->Add("[");
710 index()->PrintNameTo(stream);
711 stream->Add("], length ");
712 length()->PrintNameTo(stream);
713 }
714
715
PrintDataTo(StringStream * stream)716 void HControlInstruction::PrintDataTo(StringStream* stream) {
717 stream->Add(" goto (");
718 bool first_block = true;
719 for (HSuccessorIterator it(this); !it.Done(); it.Advance()) {
720 stream->Add(first_block ? "B%d" : ", B%d", it.Current()->block_id());
721 first_block = false;
722 }
723 stream->Add(")");
724 }
725
726
PrintDataTo(StringStream * stream)727 void HUnaryControlInstruction::PrintDataTo(StringStream* stream) {
728 value()->PrintNameTo(stream);
729 HControlInstruction::PrintDataTo(stream);
730 }
731
732
PrintDataTo(StringStream * stream)733 void HIsNilAndBranch::PrintDataTo(StringStream* stream) {
734 value()->PrintNameTo(stream);
735 stream->Add(kind() == kStrictEquality ? " === " : " == ");
736 stream->Add(nil() == kNullValue ? "null" : "undefined");
737 HControlInstruction::PrintDataTo(stream);
738 }
739
740
PrintDataTo(StringStream * stream)741 void HReturn::PrintDataTo(StringStream* stream) {
742 value()->PrintNameTo(stream);
743 }
744
745
PrintDataTo(StringStream * stream)746 void HCompareMap::PrintDataTo(StringStream* stream) {
747 value()->PrintNameTo(stream);
748 stream->Add(" (%p)", *map());
749 HControlInstruction::PrintDataTo(stream);
750 }
751
752
OpName() const753 const char* HUnaryMathOperation::OpName() const {
754 switch (op()) {
755 case kMathFloor: return "floor";
756 case kMathRound: return "round";
757 case kMathCeil: return "ceil";
758 case kMathAbs: return "abs";
759 case kMathLog: return "log";
760 case kMathSin: return "sin";
761 case kMathCos: return "cos";
762 case kMathTan: return "tan";
763 case kMathASin: return "asin";
764 case kMathACos: return "acos";
765 case kMathATan: return "atan";
766 case kMathExp: return "exp";
767 case kMathSqrt: return "sqrt";
768 default: break;
769 }
770 return "(unknown operation)";
771 }
772
773
PrintDataTo(StringStream * stream)774 void HUnaryMathOperation::PrintDataTo(StringStream* stream) {
775 const char* name = OpName();
776 stream->Add("%s ", name);
777 value()->PrintNameTo(stream);
778 }
779
780
PrintDataTo(StringStream * stream)781 void HUnaryOperation::PrintDataTo(StringStream* stream) {
782 value()->PrintNameTo(stream);
783 }
784
785
PrintDataTo(StringStream * stream)786 void HHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
787 value()->PrintNameTo(stream);
788 switch (from_) {
789 case FIRST_JS_RECEIVER_TYPE:
790 if (to_ == LAST_TYPE) stream->Add(" spec_object");
791 break;
792 case JS_REGEXP_TYPE:
793 if (to_ == JS_REGEXP_TYPE) stream->Add(" reg_exp");
794 break;
795 case JS_ARRAY_TYPE:
796 if (to_ == JS_ARRAY_TYPE) stream->Add(" array");
797 break;
798 case JS_FUNCTION_TYPE:
799 if (to_ == JS_FUNCTION_TYPE) stream->Add(" function");
800 break;
801 default:
802 break;
803 }
804 }
805
806
PrintDataTo(StringStream * stream)807 void HTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
808 value()->PrintNameTo(stream);
809 stream->Add(" == %o", *type_literal_);
810 HControlInstruction::PrintDataTo(stream);
811 }
812
813
PrintDataTo(StringStream * stream)814 void HCheckMapValue::PrintDataTo(StringStream* stream) {
815 value()->PrintNameTo(stream);
816 stream->Add(" ");
817 map()->PrintNameTo(stream);
818 }
819
820
PrintDataTo(StringStream * stream)821 void HForInPrepareMap::PrintDataTo(StringStream* stream) {
822 enumerable()->PrintNameTo(stream);
823 }
824
825
PrintDataTo(StringStream * stream)826 void HForInCacheArray::PrintDataTo(StringStream* stream) {
827 enumerable()->PrintNameTo(stream);
828 stream->Add(" ");
829 map()->PrintNameTo(stream);
830 stream->Add("[%d]", idx_);
831 }
832
833
PrintDataTo(StringStream * stream)834 void HLoadFieldByIndex::PrintDataTo(StringStream* stream) {
835 object()->PrintNameTo(stream);
836 stream->Add(" ");
837 index()->PrintNameTo(stream);
838 }
839
840
Canonicalize()841 HValue* HConstant::Canonicalize() {
842 return HasNoUses() ? NULL : this;
843 }
844
845
Canonicalize()846 HValue* HTypeof::Canonicalize() {
847 return HasNoUses() ? NULL : this;
848 }
849
850
Canonicalize()851 HValue* HBitwise::Canonicalize() {
852 if (!representation().IsInteger32()) return this;
853 // If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x.
854 int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0;
855 if (left()->IsConstant() &&
856 HConstant::cast(left())->HasInteger32Value() &&
857 HConstant::cast(left())->Integer32Value() == nop_constant) {
858 return right();
859 }
860 if (right()->IsConstant() &&
861 HConstant::cast(right())->HasInteger32Value() &&
862 HConstant::cast(right())->Integer32Value() == nop_constant) {
863 return left();
864 }
865 return this;
866 }
867
868
Canonicalize()869 HValue* HAdd::Canonicalize() {
870 if (!representation().IsInteger32()) return this;
871 if (CheckUsesForFlag(kTruncatingToInt32)) ClearFlag(kCanOverflow);
872 return this;
873 }
874
875
Canonicalize()876 HValue* HSub::Canonicalize() {
877 if (!representation().IsInteger32()) return this;
878 if (CheckUsesForFlag(kTruncatingToInt32)) ClearFlag(kCanOverflow);
879 return this;
880 }
881
882
Canonicalize()883 HValue* HChange::Canonicalize() {
884 return (from().Equals(to())) ? value() : this;
885 }
886
887
Canonicalize()888 HValue* HWrapReceiver::Canonicalize() {
889 if (HasNoUses()) return NULL;
890 if (receiver()->type().IsJSObject()) {
891 return receiver();
892 }
893 return this;
894 }
895
896
PrintDataTo(StringStream * stream)897 void HTypeof::PrintDataTo(StringStream* stream) {
898 value()->PrintNameTo(stream);
899 }
900
901
PrintDataTo(StringStream * stream)902 void HChange::PrintDataTo(StringStream* stream) {
903 HUnaryOperation::PrintDataTo(stream);
904 stream->Add(" %s to %s", from().Mnemonic(), to().Mnemonic());
905
906 if (CanTruncateToInt32()) stream->Add(" truncating-int32");
907 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
908 if (CheckFlag(kDeoptimizeOnUndefined)) stream->Add(" deopt-on-undefined");
909 }
910
911
PrintDataTo(StringStream * stream)912 void HJSArrayLength::PrintDataTo(StringStream* stream) {
913 value()->PrintNameTo(stream);
914 stream->Add(" ");
915 typecheck()->PrintNameTo(stream);
916 }
917
918
Canonicalize()919 HValue* HCheckInstanceType::Canonicalize() {
920 if (check_ == IS_STRING &&
921 !value()->type().IsUninitialized() &&
922 value()->type().IsString()) {
923 return NULL;
924 }
925 if (check_ == IS_SYMBOL &&
926 value()->IsConstant() &&
927 HConstant::cast(value())->handle()->IsSymbol()) {
928 return NULL;
929 }
930 return this;
931 }
932
933
GetCheckInterval(InstanceType * first,InstanceType * last)934 void HCheckInstanceType::GetCheckInterval(InstanceType* first,
935 InstanceType* last) {
936 ASSERT(is_interval_check());
937 switch (check_) {
938 case IS_SPEC_OBJECT:
939 *first = FIRST_SPEC_OBJECT_TYPE;
940 *last = LAST_SPEC_OBJECT_TYPE;
941 return;
942 case IS_JS_ARRAY:
943 *first = *last = JS_ARRAY_TYPE;
944 return;
945 default:
946 UNREACHABLE();
947 }
948 }
949
950
GetCheckMaskAndTag(uint8_t * mask,uint8_t * tag)951 void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) {
952 ASSERT(!is_interval_check());
953 switch (check_) {
954 case IS_STRING:
955 *mask = kIsNotStringMask;
956 *tag = kStringTag;
957 return;
958 case IS_SYMBOL:
959 *mask = kIsSymbolMask;
960 *tag = kSymbolTag;
961 return;
962 default:
963 UNREACHABLE();
964 }
965 }
966
967
PrintDataTo(StringStream * stream)968 void HCheckMap::PrintDataTo(StringStream* stream) {
969 value()->PrintNameTo(stream);
970 stream->Add(" %p", *map());
971 if (mode() == REQUIRE_EXACT_MAP) {
972 stream->Add(" [EXACT]");
973 } else if (!has_element_transitions_) {
974 stream->Add(" [EXACT*]");
975 } else {
976 stream->Add(" [MATCH ELEMENTS]");
977 }
978 }
979
980
PrintDataTo(StringStream * stream)981 void HCheckFunction::PrintDataTo(StringStream* stream) {
982 value()->PrintNameTo(stream);
983 stream->Add(" %p", *target());
984 }
985
986
GetCheckName()987 const char* HCheckInstanceType::GetCheckName() {
988 switch (check_) {
989 case IS_SPEC_OBJECT: return "object";
990 case IS_JS_ARRAY: return "array";
991 case IS_STRING: return "string";
992 case IS_SYMBOL: return "symbol";
993 }
994 UNREACHABLE();
995 return "";
996 }
997
PrintDataTo(StringStream * stream)998 void HCheckInstanceType::PrintDataTo(StringStream* stream) {
999 stream->Add("%s ", GetCheckName());
1000 HUnaryOperation::PrintDataTo(stream);
1001 }
1002
1003
PrintDataTo(StringStream * stream)1004 void HCallStub::PrintDataTo(StringStream* stream) {
1005 stream->Add("%s ",
1006 CodeStub::MajorName(major_key_, false));
1007 HUnaryCall::PrintDataTo(stream);
1008 }
1009
1010
PrintDataTo(StringStream * stream)1011 void HInstanceOf::PrintDataTo(StringStream* stream) {
1012 left()->PrintNameTo(stream);
1013 stream->Add(" ");
1014 right()->PrintNameTo(stream);
1015 stream->Add(" ");
1016 context()->PrintNameTo(stream);
1017 }
1018
1019
InferRange(Zone * zone)1020 Range* HValue::InferRange(Zone* zone) {
1021 // Untagged integer32 cannot be -0, all other representations can.
1022 Range* result = new(zone) Range();
1023 result->set_can_be_minus_zero(!representation().IsInteger32());
1024 return result;
1025 }
1026
1027
InferRange(Zone * zone)1028 Range* HChange::InferRange(Zone* zone) {
1029 Range* input_range = value()->range();
1030 if (from().IsInteger32() &&
1031 to().IsTagged() &&
1032 input_range != NULL && input_range->IsInSmiRange()) {
1033 set_type(HType::Smi());
1034 }
1035 Range* result = (input_range != NULL)
1036 ? input_range->Copy(zone)
1037 : HValue::InferRange(zone);
1038 if (to().IsInteger32()) result->set_can_be_minus_zero(false);
1039 return result;
1040 }
1041
1042
InferRange(Zone * zone)1043 Range* HConstant::InferRange(Zone* zone) {
1044 if (has_int32_value_) {
1045 Range* result = new(zone) Range(int32_value_, int32_value_);
1046 result->set_can_be_minus_zero(false);
1047 return result;
1048 }
1049 return HValue::InferRange(zone);
1050 }
1051
1052
InferRange(Zone * zone)1053 Range* HPhi::InferRange(Zone* zone) {
1054 if (representation().IsInteger32()) {
1055 if (block()->IsLoopHeader()) {
1056 Range* range = new(zone) Range(kMinInt, kMaxInt);
1057 return range;
1058 } else {
1059 Range* range = OperandAt(0)->range()->Copy(zone);
1060 for (int i = 1; i < OperandCount(); ++i) {
1061 range->Union(OperandAt(i)->range());
1062 }
1063 return range;
1064 }
1065 } else {
1066 return HValue::InferRange(zone);
1067 }
1068 }
1069
1070
InferRange(Zone * zone)1071 Range* HAdd::InferRange(Zone* zone) {
1072 if (representation().IsInteger32()) {
1073 Range* a = left()->range();
1074 Range* b = right()->range();
1075 Range* res = a->Copy(zone);
1076 if (!res->AddAndCheckOverflow(b)) {
1077 ClearFlag(kCanOverflow);
1078 }
1079 bool m0 = a->CanBeMinusZero() && b->CanBeMinusZero();
1080 res->set_can_be_minus_zero(m0);
1081 return res;
1082 } else {
1083 return HValue::InferRange(zone);
1084 }
1085 }
1086
1087
InferRange(Zone * zone)1088 Range* HSub::InferRange(Zone* zone) {
1089 if (representation().IsInteger32()) {
1090 Range* a = left()->range();
1091 Range* b = right()->range();
1092 Range* res = a->Copy(zone);
1093 if (!res->SubAndCheckOverflow(b)) {
1094 ClearFlag(kCanOverflow);
1095 }
1096 res->set_can_be_minus_zero(a->CanBeMinusZero() && b->CanBeZero());
1097 return res;
1098 } else {
1099 return HValue::InferRange(zone);
1100 }
1101 }
1102
1103
InferRange(Zone * zone)1104 Range* HMul::InferRange(Zone* zone) {
1105 if (representation().IsInteger32()) {
1106 Range* a = left()->range();
1107 Range* b = right()->range();
1108 Range* res = a->Copy(zone);
1109 if (!res->MulAndCheckOverflow(b)) {
1110 ClearFlag(kCanOverflow);
1111 }
1112 bool m0 = (a->CanBeZero() && b->CanBeNegative()) ||
1113 (a->CanBeNegative() && b->CanBeZero());
1114 res->set_can_be_minus_zero(m0);
1115 return res;
1116 } else {
1117 return HValue::InferRange(zone);
1118 }
1119 }
1120
1121
InferRange(Zone * zone)1122 Range* HDiv::InferRange(Zone* zone) {
1123 if (representation().IsInteger32()) {
1124 Range* result = new(zone) Range();
1125 if (left()->range()->CanBeMinusZero()) {
1126 result->set_can_be_minus_zero(true);
1127 }
1128
1129 if (left()->range()->CanBeZero() && right()->range()->CanBeNegative()) {
1130 result->set_can_be_minus_zero(true);
1131 }
1132
1133 if (right()->range()->Includes(-1) && left()->range()->Includes(kMinInt)) {
1134 SetFlag(HValue::kCanOverflow);
1135 }
1136
1137 if (!right()->range()->CanBeZero()) {
1138 ClearFlag(HValue::kCanBeDivByZero);
1139 }
1140 return result;
1141 } else {
1142 return HValue::InferRange(zone);
1143 }
1144 }
1145
1146
InferRange(Zone * zone)1147 Range* HMod::InferRange(Zone* zone) {
1148 if (representation().IsInteger32()) {
1149 Range* a = left()->range();
1150 Range* result = new(zone) Range();
1151 if (a->CanBeMinusZero() || a->CanBeNegative()) {
1152 result->set_can_be_minus_zero(true);
1153 }
1154 if (!right()->range()->CanBeZero()) {
1155 ClearFlag(HValue::kCanBeDivByZero);
1156 }
1157 return result;
1158 } else {
1159 return HValue::InferRange(zone);
1160 }
1161 }
1162
1163
PrintTo(StringStream * stream)1164 void HPhi::PrintTo(StringStream* stream) {
1165 stream->Add("[");
1166 for (int i = 0; i < OperandCount(); ++i) {
1167 HValue* value = OperandAt(i);
1168 stream->Add(" ");
1169 value->PrintNameTo(stream);
1170 stream->Add(" ");
1171 }
1172 stream->Add(" uses%d_%di_%dd_%dt",
1173 UseCount(),
1174 int32_non_phi_uses() + int32_indirect_uses(),
1175 double_non_phi_uses() + double_indirect_uses(),
1176 tagged_non_phi_uses() + tagged_indirect_uses());
1177 stream->Add("%s%s]",
1178 is_live() ? "_live" : "",
1179 IsConvertibleToInteger() ? "" : "_ncti");
1180 }
1181
1182
AddInput(HValue * value)1183 void HPhi::AddInput(HValue* value) {
1184 inputs_.Add(NULL);
1185 SetOperandAt(OperandCount() - 1, value);
1186 // Mark phis that may have 'arguments' directly or indirectly as an operand.
1187 if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) {
1188 SetFlag(kIsArguments);
1189 }
1190 }
1191
1192
HasRealUses()1193 bool HPhi::HasRealUses() {
1194 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1195 if (!it.value()->IsPhi()) return true;
1196 }
1197 return false;
1198 }
1199
1200
GetRedundantReplacement()1201 HValue* HPhi::GetRedundantReplacement() {
1202 HValue* candidate = NULL;
1203 int count = OperandCount();
1204 int position = 0;
1205 while (position < count && candidate == NULL) {
1206 HValue* current = OperandAt(position++);
1207 if (current != this) candidate = current;
1208 }
1209 while (position < count) {
1210 HValue* current = OperandAt(position++);
1211 if (current != this && current != candidate) return NULL;
1212 }
1213 ASSERT(candidate != this);
1214 return candidate;
1215 }
1216
1217
DeleteFromGraph()1218 void HPhi::DeleteFromGraph() {
1219 ASSERT(block() != NULL);
1220 block()->RemovePhi(this);
1221 ASSERT(block() == NULL);
1222 }
1223
1224
InitRealUses(int phi_id)1225 void HPhi::InitRealUses(int phi_id) {
1226 // Initialize real uses.
1227 phi_id_ = phi_id;
1228 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1229 HValue* value = it.value();
1230 if (!value->IsPhi()) {
1231 Representation rep = value->RequiredInputRepresentation(it.index());
1232 non_phi_uses_[rep.kind()] += value->LoopWeight();
1233 }
1234 }
1235 }
1236
1237
AddNonPhiUsesFrom(HPhi * other)1238 void HPhi::AddNonPhiUsesFrom(HPhi* other) {
1239 for (int i = 0; i < Representation::kNumRepresentations; i++) {
1240 indirect_uses_[i] += other->non_phi_uses_[i];
1241 }
1242 }
1243
1244
AddIndirectUsesTo(int * dest)1245 void HPhi::AddIndirectUsesTo(int* dest) {
1246 for (int i = 0; i < Representation::kNumRepresentations; i++) {
1247 dest[i] += indirect_uses_[i];
1248 }
1249 }
1250
1251
PrintDataTo(StringStream * stream)1252 void HSimulate::PrintDataTo(StringStream* stream) {
1253 stream->Add("id=%d", ast_id());
1254 if (pop_count_ > 0) stream->Add(" pop %d", pop_count_);
1255 if (values_.length() > 0) {
1256 if (pop_count_ > 0) stream->Add(" /");
1257 for (int i = 0; i < values_.length(); ++i) {
1258 if (i > 0) stream->Add(",");
1259 if (HasAssignedIndexAt(i)) {
1260 stream->Add(" var[%d] = ", GetAssignedIndexAt(i));
1261 } else {
1262 stream->Add(" push ");
1263 }
1264 values_[i]->PrintNameTo(stream);
1265 }
1266 }
1267 }
1268
1269
PrintDataTo(StringStream * stream)1270 void HDeoptimize::PrintDataTo(StringStream* stream) {
1271 if (OperandCount() == 0) return;
1272 OperandAt(0)->PrintNameTo(stream);
1273 for (int i = 1; i < OperandCount(); ++i) {
1274 stream->Add(" ");
1275 OperandAt(i)->PrintNameTo(stream);
1276 }
1277 }
1278
1279
PrintDataTo(StringStream * stream)1280 void HEnterInlined::PrintDataTo(StringStream* stream) {
1281 SmartArrayPointer<char> name = function()->debug_name()->ToCString();
1282 stream->Add("%s, id=%d", *name, function()->id());
1283 }
1284
1285
HConstant(Handle<Object> handle,Representation r)1286 HConstant::HConstant(Handle<Object> handle, Representation r)
1287 : handle_(handle),
1288 has_int32_value_(false),
1289 has_double_value_(false),
1290 int32_value_(0),
1291 double_value_(0) {
1292 set_representation(r);
1293 SetFlag(kUseGVN);
1294 if (handle_->IsNumber()) {
1295 double n = handle_->Number();
1296 double roundtrip_value = static_cast<double>(static_cast<int32_t>(n));
1297 has_int32_value_ = BitCast<int64_t>(roundtrip_value) == BitCast<int64_t>(n);
1298 if (has_int32_value_) int32_value_ = static_cast<int32_t>(n);
1299 double_value_ = n;
1300 has_double_value_ = true;
1301 }
1302 }
1303
1304
CopyToRepresentation(Representation r) const1305 HConstant* HConstant::CopyToRepresentation(Representation r) const {
1306 if (r.IsInteger32() && !has_int32_value_) return NULL;
1307 if (r.IsDouble() && !has_double_value_) return NULL;
1308 return new HConstant(handle_, r);
1309 }
1310
1311
CopyToTruncatedInt32() const1312 HConstant* HConstant::CopyToTruncatedInt32() const {
1313 if (!has_double_value_) return NULL;
1314 int32_t truncated = NumberToInt32(*handle_);
1315 return new HConstant(FACTORY->NewNumberFromInt(truncated),
1316 Representation::Integer32());
1317 }
1318
1319
ToBoolean() const1320 bool HConstant::ToBoolean() const {
1321 // Converts the constant's boolean value according to
1322 // ECMAScript section 9.2 ToBoolean conversion.
1323 if (HasInteger32Value()) return Integer32Value() != 0;
1324 if (HasDoubleValue()) {
1325 double v = DoubleValue();
1326 return v != 0 && !isnan(v);
1327 }
1328 if (handle()->IsTrue()) return true;
1329 if (handle()->IsFalse()) return false;
1330 if (handle()->IsUndefined()) return false;
1331 if (handle()->IsNull()) return false;
1332 if (handle()->IsString() &&
1333 String::cast(*handle())->length() == 0) return false;
1334 return true;
1335 }
1336
PrintDataTo(StringStream * stream)1337 void HConstant::PrintDataTo(StringStream* stream) {
1338 handle()->ShortPrint(stream);
1339 }
1340
1341
IsCopyOnWrite() const1342 bool HArrayLiteral::IsCopyOnWrite() const {
1343 if (!boilerplate_object_->IsJSObject()) return false;
1344 return Handle<JSObject>::cast(boilerplate_object_)->elements()->map() ==
1345 HEAP->fixed_cow_array_map();
1346 }
1347
1348
PrintDataTo(StringStream * stream)1349 void HBinaryOperation::PrintDataTo(StringStream* stream) {
1350 left()->PrintNameTo(stream);
1351 stream->Add(" ");
1352 right()->PrintNameTo(stream);
1353 if (CheckFlag(kCanOverflow)) stream->Add(" !");
1354 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
1355 }
1356
1357
InferRange(Zone * zone)1358 Range* HBitwise::InferRange(Zone* zone) {
1359 if (op() == Token::BIT_XOR) return HValue::InferRange(zone);
1360 const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff);
1361 int32_t left_mask = (left()->range() != NULL)
1362 ? left()->range()->Mask()
1363 : kDefaultMask;
1364 int32_t right_mask = (right()->range() != NULL)
1365 ? right()->range()->Mask()
1366 : kDefaultMask;
1367 int32_t result_mask = (op() == Token::BIT_AND)
1368 ? left_mask & right_mask
1369 : left_mask | right_mask;
1370 return (result_mask >= 0)
1371 ? new(zone) Range(0, result_mask)
1372 : HValue::InferRange(zone);
1373 }
1374
1375
InferRange(Zone * zone)1376 Range* HSar::InferRange(Zone* zone) {
1377 if (right()->IsConstant()) {
1378 HConstant* c = HConstant::cast(right());
1379 if (c->HasInteger32Value()) {
1380 Range* result = (left()->range() != NULL)
1381 ? left()->range()->Copy(zone)
1382 : new(zone) Range();
1383 result->Sar(c->Integer32Value());
1384 result->set_can_be_minus_zero(false);
1385 return result;
1386 }
1387 }
1388 return HValue::InferRange(zone);
1389 }
1390
1391
InferRange(Zone * zone)1392 Range* HShr::InferRange(Zone* zone) {
1393 if (right()->IsConstant()) {
1394 HConstant* c = HConstant::cast(right());
1395 if (c->HasInteger32Value()) {
1396 int shift_count = c->Integer32Value() & 0x1f;
1397 if (left()->range()->CanBeNegative()) {
1398 // Only compute bounds if the result always fits into an int32.
1399 return (shift_count >= 1)
1400 ? new(zone) Range(0,
1401 static_cast<uint32_t>(0xffffffff) >> shift_count)
1402 : new(zone) Range();
1403 } else {
1404 // For positive inputs we can use the >> operator.
1405 Range* result = (left()->range() != NULL)
1406 ? left()->range()->Copy(zone)
1407 : new(zone) Range();
1408 result->Sar(c->Integer32Value());
1409 result->set_can_be_minus_zero(false);
1410 return result;
1411 }
1412 }
1413 }
1414 return HValue::InferRange(zone);
1415 }
1416
1417
InferRange(Zone * zone)1418 Range* HShl::InferRange(Zone* zone) {
1419 if (right()->IsConstant()) {
1420 HConstant* c = HConstant::cast(right());
1421 if (c->HasInteger32Value()) {
1422 Range* result = (left()->range() != NULL)
1423 ? left()->range()->Copy(zone)
1424 : new(zone) Range();
1425 result->Shl(c->Integer32Value());
1426 result->set_can_be_minus_zero(false);
1427 return result;
1428 }
1429 }
1430 return HValue::InferRange(zone);
1431 }
1432
1433
InferRange(Zone * zone)1434 Range* HLoadKeyedSpecializedArrayElement::InferRange(Zone* zone) {
1435 switch (elements_kind()) {
1436 case EXTERNAL_PIXEL_ELEMENTS:
1437 return new(zone) Range(0, 255);
1438 case EXTERNAL_BYTE_ELEMENTS:
1439 return new(zone) Range(-128, 127);
1440 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
1441 return new(zone) Range(0, 255);
1442 case EXTERNAL_SHORT_ELEMENTS:
1443 return new(zone) Range(-32768, 32767);
1444 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
1445 return new(zone) Range(0, 65535);
1446 default:
1447 return HValue::InferRange(zone);
1448 }
1449 }
1450
1451
PrintDataTo(StringStream * stream)1452 void HCompareGeneric::PrintDataTo(StringStream* stream) {
1453 stream->Add(Token::Name(token()));
1454 stream->Add(" ");
1455 HBinaryOperation::PrintDataTo(stream);
1456 }
1457
1458
PrintDataTo(StringStream * stream)1459 void HStringCompareAndBranch::PrintDataTo(StringStream* stream) {
1460 stream->Add(Token::Name(token()));
1461 stream->Add(" ");
1462 HControlInstruction::PrintDataTo(stream);
1463 }
1464
1465
PrintDataTo(StringStream * stream)1466 void HCompareIDAndBranch::PrintDataTo(StringStream* stream) {
1467 stream->Add(Token::Name(token()));
1468 stream->Add(" ");
1469 left()->PrintNameTo(stream);
1470 stream->Add(" ");
1471 right()->PrintNameTo(stream);
1472 HControlInstruction::PrintDataTo(stream);
1473 }
1474
1475
PrintDataTo(StringStream * stream)1476 void HCompareObjectEqAndBranch::PrintDataTo(StringStream* stream) {
1477 left()->PrintNameTo(stream);
1478 stream->Add(" ");
1479 right()->PrintNameTo(stream);
1480 HControlInstruction::PrintDataTo(stream);
1481 }
1482
1483
PrintDataTo(StringStream * stream)1484 void HGoto::PrintDataTo(StringStream* stream) {
1485 stream->Add("B%d", SuccessorAt(0)->block_id());
1486 }
1487
1488
SetInputRepresentation(Representation r)1489 void HCompareIDAndBranch::SetInputRepresentation(Representation r) {
1490 input_representation_ = r;
1491 if (r.IsDouble()) {
1492 // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, ===
1493 // and !=) have special handling of undefined, e.g. undefined == undefined
1494 // is 'true'. Relational comparisons have a different semantic, first
1495 // calling ToPrimitive() on their arguments. The standard Crankshaft
1496 // tagged-to-double conversion to ensure the HCompareIDAndBranch's inputs
1497 // are doubles caused 'undefined' to be converted to NaN. That's compatible
1498 // out-of-the box with ordered relational comparisons (<, >, <=,
1499 // >=). However, for equality comparisons (and for 'in' and 'instanceof'),
1500 // it is not consistent with the spec. For example, it would cause undefined
1501 // == undefined (should be true) to be evaluated as NaN == NaN
1502 // (false). Therefore, any comparisons other than ordered relational
1503 // comparisons must cause a deopt when one of their arguments is undefined.
1504 // See also v8:1434
1505 if (!Token::IsOrderedRelationalCompareOp(token_)) {
1506 SetFlag(kDeoptimizeOnUndefined);
1507 }
1508 } else {
1509 ASSERT(r.IsInteger32());
1510 }
1511 }
1512
1513
PrintDataTo(StringStream * stream)1514 void HParameter::PrintDataTo(StringStream* stream) {
1515 stream->Add("%u", index());
1516 }
1517
1518
PrintDataTo(StringStream * stream)1519 void HLoadNamedField::PrintDataTo(StringStream* stream) {
1520 object()->PrintNameTo(stream);
1521 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
1522 }
1523
1524
HLoadNamedFieldPolymorphic(HValue * context,HValue * object,SmallMapList * types,Handle<String> name)1525 HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
1526 HValue* object,
1527 SmallMapList* types,
1528 Handle<String> name)
1529 : types_(Min(types->length(), kMaxLoadPolymorphism)),
1530 name_(name),
1531 need_generic_(false) {
1532 SetOperandAt(0, context);
1533 SetOperandAt(1, object);
1534 set_representation(Representation::Tagged());
1535 SetGVNFlag(kDependsOnMaps);
1536 for (int i = 0;
1537 i < types->length() && types_.length() < kMaxLoadPolymorphism;
1538 ++i) {
1539 Handle<Map> map = types->at(i);
1540 LookupResult lookup(map->GetIsolate());
1541 map->LookupInDescriptors(NULL, *name, &lookup);
1542 if (lookup.IsFound()) {
1543 switch (lookup.type()) {
1544 case FIELD: {
1545 int index = lookup.GetLocalFieldIndexFromMap(*map);
1546 if (index < 0) {
1547 SetGVNFlag(kDependsOnInobjectFields);
1548 } else {
1549 SetGVNFlag(kDependsOnBackingStoreFields);
1550 }
1551 types_.Add(types->at(i));
1552 break;
1553 }
1554 case CONSTANT_FUNCTION:
1555 types_.Add(types->at(i));
1556 break;
1557 default:
1558 break;
1559 }
1560 }
1561 }
1562
1563 if (types_.length() == types->length() && FLAG_deoptimize_uncommon_cases) {
1564 SetFlag(kUseGVN);
1565 } else {
1566 SetAllSideEffects();
1567 need_generic_ = true;
1568 }
1569 }
1570
1571
DataEquals(HValue * value)1572 bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
1573 HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
1574 if (types_.length() != other->types()->length()) return false;
1575 if (!name_.is_identical_to(other->name())) return false;
1576 if (need_generic_ != other->need_generic_) return false;
1577 for (int i = 0; i < types_.length(); i++) {
1578 bool found = false;
1579 for (int j = 0; j < types_.length(); j++) {
1580 if (types_.at(j).is_identical_to(other->types()->at(i))) {
1581 found = true;
1582 break;
1583 }
1584 }
1585 if (!found) return false;
1586 }
1587 return true;
1588 }
1589
1590
PrintDataTo(StringStream * stream)1591 void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) {
1592 object()->PrintNameTo(stream);
1593 stream->Add(".");
1594 stream->Add(*String::cast(*name())->ToCString());
1595 }
1596
1597
PrintDataTo(StringStream * stream)1598 void HLoadNamedGeneric::PrintDataTo(StringStream* stream) {
1599 object()->PrintNameTo(stream);
1600 stream->Add(".");
1601 stream->Add(*String::cast(*name())->ToCString());
1602 }
1603
1604
PrintDataTo(StringStream * stream)1605 void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
1606 object()->PrintNameTo(stream);
1607 stream->Add("[");
1608 key()->PrintNameTo(stream);
1609 stream->Add("]");
1610 }
1611
1612
RequiresHoleCheck()1613 bool HLoadKeyedFastElement::RequiresHoleCheck() {
1614 if (hole_check_mode_ == OMIT_HOLE_CHECK) {
1615 return false;
1616 }
1617
1618 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1619 HValue* use = it.value();
1620 if (!use->IsChange()) return true;
1621 }
1622
1623 return false;
1624 }
1625
1626
PrintDataTo(StringStream * stream)1627 void HLoadKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
1628 elements()->PrintNameTo(stream);
1629 stream->Add("[");
1630 key()->PrintNameTo(stream);
1631 stream->Add("]");
1632 }
1633
1634
PrintDataTo(StringStream * stream)1635 void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) {
1636 object()->PrintNameTo(stream);
1637 stream->Add("[");
1638 key()->PrintNameTo(stream);
1639 stream->Add("]");
1640 }
1641
1642
Canonicalize()1643 HValue* HLoadKeyedGeneric::Canonicalize() {
1644 // Recognize generic keyed loads that use property name generated
1645 // by for-in statement as a key and rewrite them into fast property load
1646 // by index.
1647 if (key()->IsLoadKeyedFastElement()) {
1648 HLoadKeyedFastElement* key_load = HLoadKeyedFastElement::cast(key());
1649 if (key_load->object()->IsForInCacheArray()) {
1650 HForInCacheArray* names_cache =
1651 HForInCacheArray::cast(key_load->object());
1652
1653 if (names_cache->enumerable() == object()) {
1654 HForInCacheArray* index_cache =
1655 names_cache->index_cache();
1656 HCheckMapValue* map_check =
1657 new(block()->zone()) HCheckMapValue(object(), names_cache->map());
1658 HInstruction* index = new(block()->zone()) HLoadKeyedFastElement(
1659 index_cache,
1660 key_load->key(),
1661 HLoadKeyedFastElement::OMIT_HOLE_CHECK);
1662 HLoadFieldByIndex* load = new(block()->zone()) HLoadFieldByIndex(
1663 object(), index);
1664 map_check->InsertBefore(this);
1665 index->InsertBefore(this);
1666 load->InsertBefore(this);
1667 return load;
1668 }
1669 }
1670 }
1671
1672 return this;
1673 }
1674
1675
PrintDataTo(StringStream * stream)1676 void HLoadKeyedSpecializedArrayElement::PrintDataTo(
1677 StringStream* stream) {
1678 external_pointer()->PrintNameTo(stream);
1679 stream->Add(".");
1680 switch (elements_kind()) {
1681 case EXTERNAL_BYTE_ELEMENTS:
1682 stream->Add("byte");
1683 break;
1684 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
1685 stream->Add("u_byte");
1686 break;
1687 case EXTERNAL_SHORT_ELEMENTS:
1688 stream->Add("short");
1689 break;
1690 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
1691 stream->Add("u_short");
1692 break;
1693 case EXTERNAL_INT_ELEMENTS:
1694 stream->Add("int");
1695 break;
1696 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
1697 stream->Add("u_int");
1698 break;
1699 case EXTERNAL_FLOAT_ELEMENTS:
1700 stream->Add("float");
1701 break;
1702 case EXTERNAL_DOUBLE_ELEMENTS:
1703 stream->Add("double");
1704 break;
1705 case EXTERNAL_PIXEL_ELEMENTS:
1706 stream->Add("pixel");
1707 break;
1708 case FAST_ELEMENTS:
1709 case FAST_SMI_ONLY_ELEMENTS:
1710 case FAST_DOUBLE_ELEMENTS:
1711 case DICTIONARY_ELEMENTS:
1712 case NON_STRICT_ARGUMENTS_ELEMENTS:
1713 UNREACHABLE();
1714 break;
1715 }
1716 stream->Add("[");
1717 key()->PrintNameTo(stream);
1718 stream->Add("]");
1719 }
1720
1721
PrintDataTo(StringStream * stream)1722 void HStoreNamedGeneric::PrintDataTo(StringStream* stream) {
1723 object()->PrintNameTo(stream);
1724 stream->Add(".");
1725 ASSERT(name()->IsString());
1726 stream->Add(*String::cast(*name())->ToCString());
1727 stream->Add(" = ");
1728 value()->PrintNameTo(stream);
1729 }
1730
1731
PrintDataTo(StringStream * stream)1732 void HStoreNamedField::PrintDataTo(StringStream* stream) {
1733 object()->PrintNameTo(stream);
1734 stream->Add(".");
1735 stream->Add(*String::cast(*name())->ToCString());
1736 stream->Add(" = ");
1737 value()->PrintNameTo(stream);
1738 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
1739 if (!transition().is_null()) {
1740 stream->Add(" (transition map %p)", *transition());
1741 }
1742 }
1743
1744
PrintDataTo(StringStream * stream)1745 void HStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
1746 object()->PrintNameTo(stream);
1747 stream->Add("[");
1748 key()->PrintNameTo(stream);
1749 stream->Add("] = ");
1750 value()->PrintNameTo(stream);
1751 }
1752
1753
PrintDataTo(StringStream * stream)1754 void HStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
1755 elements()->PrintNameTo(stream);
1756 stream->Add("[");
1757 key()->PrintNameTo(stream);
1758 stream->Add("] = ");
1759 value()->PrintNameTo(stream);
1760 }
1761
1762
PrintDataTo(StringStream * stream)1763 void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
1764 object()->PrintNameTo(stream);
1765 stream->Add("[");
1766 key()->PrintNameTo(stream);
1767 stream->Add("] = ");
1768 value()->PrintNameTo(stream);
1769 }
1770
1771
PrintDataTo(StringStream * stream)1772 void HStoreKeyedSpecializedArrayElement::PrintDataTo(
1773 StringStream* stream) {
1774 external_pointer()->PrintNameTo(stream);
1775 stream->Add(".");
1776 switch (elements_kind()) {
1777 case EXTERNAL_BYTE_ELEMENTS:
1778 stream->Add("byte");
1779 break;
1780 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
1781 stream->Add("u_byte");
1782 break;
1783 case EXTERNAL_SHORT_ELEMENTS:
1784 stream->Add("short");
1785 break;
1786 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
1787 stream->Add("u_short");
1788 break;
1789 case EXTERNAL_INT_ELEMENTS:
1790 stream->Add("int");
1791 break;
1792 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
1793 stream->Add("u_int");
1794 break;
1795 case EXTERNAL_FLOAT_ELEMENTS:
1796 stream->Add("float");
1797 break;
1798 case EXTERNAL_DOUBLE_ELEMENTS:
1799 stream->Add("double");
1800 break;
1801 case EXTERNAL_PIXEL_ELEMENTS:
1802 stream->Add("pixel");
1803 break;
1804 case FAST_SMI_ONLY_ELEMENTS:
1805 case FAST_ELEMENTS:
1806 case FAST_DOUBLE_ELEMENTS:
1807 case DICTIONARY_ELEMENTS:
1808 case NON_STRICT_ARGUMENTS_ELEMENTS:
1809 UNREACHABLE();
1810 break;
1811 }
1812 stream->Add("[");
1813 key()->PrintNameTo(stream);
1814 stream->Add("] = ");
1815 value()->PrintNameTo(stream);
1816 }
1817
1818
PrintDataTo(StringStream * stream)1819 void HTransitionElementsKind::PrintDataTo(StringStream* stream) {
1820 object()->PrintNameTo(stream);
1821 stream->Add(" %p -> %p", *original_map(), *transitioned_map());
1822 }
1823
1824
PrintDataTo(StringStream * stream)1825 void HLoadGlobalCell::PrintDataTo(StringStream* stream) {
1826 stream->Add("[%p]", *cell());
1827 if (!details_.IsDontDelete()) stream->Add(" (deleteable)");
1828 if (details_.IsReadOnly()) stream->Add(" (read-only)");
1829 }
1830
1831
RequiresHoleCheck()1832 bool HLoadGlobalCell::RequiresHoleCheck() {
1833 if (details_.IsDontDelete() && !details_.IsReadOnly()) return false;
1834 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1835 HValue* use = it.value();
1836 if (!use->IsChange()) return true;
1837 }
1838 return false;
1839 }
1840
1841
PrintDataTo(StringStream * stream)1842 void HLoadGlobalGeneric::PrintDataTo(StringStream* stream) {
1843 stream->Add("%o ", *name());
1844 }
1845
1846
PrintDataTo(StringStream * stream)1847 void HStoreGlobalCell::PrintDataTo(StringStream* stream) {
1848 stream->Add("[%p] = ", *cell());
1849 value()->PrintNameTo(stream);
1850 if (!details_.IsDontDelete()) stream->Add(" (deleteable)");
1851 if (details_.IsReadOnly()) stream->Add(" (read-only)");
1852 }
1853
1854
PrintDataTo(StringStream * stream)1855 void HStoreGlobalGeneric::PrintDataTo(StringStream* stream) {
1856 stream->Add("%o = ", *name());
1857 value()->PrintNameTo(stream);
1858 }
1859
1860
PrintDataTo(StringStream * stream)1861 void HLoadContextSlot::PrintDataTo(StringStream* stream) {
1862 value()->PrintNameTo(stream);
1863 stream->Add("[%d]", slot_index());
1864 }
1865
1866
PrintDataTo(StringStream * stream)1867 void HStoreContextSlot::PrintDataTo(StringStream* stream) {
1868 context()->PrintNameTo(stream);
1869 stream->Add("[%d] = ", slot_index());
1870 value()->PrintNameTo(stream);
1871 }
1872
1873
1874 // Implementation of type inference and type conversions. Calculates
1875 // the inferred type of this instruction based on the input operands.
1876
CalculateInferredType()1877 HType HValue::CalculateInferredType() {
1878 return type_;
1879 }
1880
1881
CalculateInferredType()1882 HType HCheckMap::CalculateInferredType() {
1883 return value()->type();
1884 }
1885
1886
CalculateInferredType()1887 HType HCheckFunction::CalculateInferredType() {
1888 return value()->type();
1889 }
1890
1891
CalculateInferredType()1892 HType HCheckNonSmi::CalculateInferredType() {
1893 // TODO(kasperl): Is there any way to signal that this isn't a smi?
1894 return HType::Tagged();
1895 }
1896
1897
CalculateInferredType()1898 HType HCheckSmi::CalculateInferredType() {
1899 return HType::Smi();
1900 }
1901
1902
CalculateInferredType()1903 HType HPhi::CalculateInferredType() {
1904 HType result = HType::Uninitialized();
1905 for (int i = 0; i < OperandCount(); ++i) {
1906 HType current = OperandAt(i)->type();
1907 result = result.Combine(current);
1908 }
1909 return result;
1910 }
1911
1912
CalculateInferredType()1913 HType HConstant::CalculateInferredType() {
1914 return HType::TypeFromValue(handle_);
1915 }
1916
1917
CalculateInferredType()1918 HType HCompareGeneric::CalculateInferredType() {
1919 return HType::Boolean();
1920 }
1921
1922
CalculateInferredType()1923 HType HInstanceOf::CalculateInferredType() {
1924 return HType::Boolean();
1925 }
1926
1927
CalculateInferredType()1928 HType HDeleteProperty::CalculateInferredType() {
1929 return HType::Boolean();
1930 }
1931
1932
CalculateInferredType()1933 HType HInstanceOfKnownGlobal::CalculateInferredType() {
1934 return HType::Boolean();
1935 }
1936
1937
CalculateInferredType()1938 HType HChange::CalculateInferredType() {
1939 if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber();
1940 return type();
1941 }
1942
1943
CalculateInferredType()1944 HType HBitwiseBinaryOperation::CalculateInferredType() {
1945 return HType::TaggedNumber();
1946 }
1947
1948
CalculateInferredType()1949 HType HArithmeticBinaryOperation::CalculateInferredType() {
1950 return HType::TaggedNumber();
1951 }
1952
1953
CalculateInferredType()1954 HType HAdd::CalculateInferredType() {
1955 return HType::Tagged();
1956 }
1957
1958
CalculateInferredType()1959 HType HBitNot::CalculateInferredType() {
1960 return HType::TaggedNumber();
1961 }
1962
1963
CalculateInferredType()1964 HType HUnaryMathOperation::CalculateInferredType() {
1965 return HType::TaggedNumber();
1966 }
1967
1968
CalculateInferredType()1969 HType HStringCharFromCode::CalculateInferredType() {
1970 return HType::String();
1971 }
1972
1973
CalculateInferredType()1974 HType HAllocateObject::CalculateInferredType() {
1975 return HType::JSObject();
1976 }
1977
1978
CalculateInferredType()1979 HType HFastLiteral::CalculateInferredType() {
1980 // TODO(mstarzinger): Be smarter, could also be JSArray here.
1981 return HType::JSObject();
1982 }
1983
1984
CalculateInferredType()1985 HType HArrayLiteral::CalculateInferredType() {
1986 return HType::JSArray();
1987 }
1988
1989
CalculateInferredType()1990 HType HObjectLiteral::CalculateInferredType() {
1991 return HType::JSObject();
1992 }
1993
1994
CalculateInferredType()1995 HType HRegExpLiteral::CalculateInferredType() {
1996 return HType::JSObject();
1997 }
1998
1999
CalculateInferredType()2000 HType HFunctionLiteral::CalculateInferredType() {
2001 return HType::JSObject();
2002 }
2003
2004
EnsureAndPropagateNotMinusZero(BitVector * visited)2005 HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero(
2006 BitVector* visited) {
2007 visited->Add(id());
2008 if (representation().IsInteger32() &&
2009 !value()->representation().IsInteger32()) {
2010 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
2011 SetFlag(kBailoutOnMinusZero);
2012 }
2013 }
2014 if (RequiredInputRepresentation(0).IsInteger32() &&
2015 representation().IsInteger32()) {
2016 return value();
2017 }
2018 return NULL;
2019 }
2020
2021
2022
EnsureAndPropagateNotMinusZero(BitVector * visited)2023 HValue* HChange::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2024 visited->Add(id());
2025 if (from().IsInteger32()) return NULL;
2026 if (CanTruncateToInt32()) return NULL;
2027 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
2028 SetFlag(kBailoutOnMinusZero);
2029 }
2030 ASSERT(!from().IsInteger32() || !to().IsInteger32());
2031 return NULL;
2032 }
2033
2034
EnsureAndPropagateNotMinusZero(BitVector * visited)2035 HValue* HForceRepresentation::EnsureAndPropagateNotMinusZero(
2036 BitVector* visited) {
2037 visited->Add(id());
2038 return value();
2039 }
2040
2041
EnsureAndPropagateNotMinusZero(BitVector * visited)2042 HValue* HMod::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2043 visited->Add(id());
2044 if (range() == NULL || range()->CanBeMinusZero()) {
2045 SetFlag(kBailoutOnMinusZero);
2046 return left();
2047 }
2048 return NULL;
2049 }
2050
2051
EnsureAndPropagateNotMinusZero(BitVector * visited)2052 HValue* HDiv::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2053 visited->Add(id());
2054 if (range() == NULL || range()->CanBeMinusZero()) {
2055 SetFlag(kBailoutOnMinusZero);
2056 }
2057 return NULL;
2058 }
2059
2060
EnsureAndPropagateNotMinusZero(BitVector * visited)2061 HValue* HMul::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2062 visited->Add(id());
2063 if (range() == NULL || range()->CanBeMinusZero()) {
2064 SetFlag(kBailoutOnMinusZero);
2065 }
2066 return NULL;
2067 }
2068
2069
EnsureAndPropagateNotMinusZero(BitVector * visited)2070 HValue* HSub::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2071 visited->Add(id());
2072 // Propagate to the left argument. If the left argument cannot be -0, then
2073 // the result of the add operation cannot be either.
2074 if (range() == NULL || range()->CanBeMinusZero()) {
2075 return left();
2076 }
2077 return NULL;
2078 }
2079
2080
EnsureAndPropagateNotMinusZero(BitVector * visited)2081 HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2082 visited->Add(id());
2083 // Propagate to the left argument. If the left argument cannot be -0, then
2084 // the result of the sub operation cannot be either.
2085 if (range() == NULL || range()->CanBeMinusZero()) {
2086 return left();
2087 }
2088 return NULL;
2089 }
2090
2091
2092 #define H_CONSTANT_INT32(val) \
2093 new(zone) HConstant(FACTORY->NewNumberFromInt(val, TENURED), \
2094 Representation::Integer32())
2095 #define H_CONSTANT_DOUBLE(val) \
2096 new(zone) HConstant(FACTORY->NewNumber(val, TENURED), \
2097 Representation::Double())
2098
2099 #define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op) \
2100 HInstruction* HInstr::New##HInstr(Zone* zone, \
2101 HValue* context, \
2102 HValue* left, \
2103 HValue* right) { \
2104 if (left->IsConstant() && right->IsConstant()) { \
2105 HConstant* c_left = HConstant::cast(left); \
2106 HConstant* c_right = HConstant::cast(right); \
2107 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
2108 double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \
2109 if (TypeInfo::IsInt32Double(double_res)) { \
2110 return H_CONSTANT_INT32(static_cast<int32_t>(double_res)); \
2111 } \
2112 return H_CONSTANT_DOUBLE(double_res); \
2113 } \
2114 } \
2115 return new(zone) HInstr(context, left, right); \
2116 }
2117
2118
2119 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HAdd, +)
2120 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HMul, *)
2121 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HSub, -)
2122
2123 #undef DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR
2124
2125
NewHMod(Zone * zone,HValue * context,HValue * left,HValue * right)2126 HInstruction* HMod::NewHMod(Zone* zone,
2127 HValue* context,
2128 HValue* left,
2129 HValue* right) {
2130 if (left->IsConstant() && right->IsConstant()) {
2131 HConstant* c_left = HConstant::cast(left);
2132 HConstant* c_right = HConstant::cast(right);
2133 if (c_left->HasInteger32Value() && c_right->HasInteger32Value()) {
2134 int32_t dividend = c_left->Integer32Value();
2135 int32_t divisor = c_right->Integer32Value();
2136 if (divisor != 0) {
2137 int32_t res = dividend % divisor;
2138 if ((res == 0) && (dividend < 0)) {
2139 return H_CONSTANT_DOUBLE(-0.0);
2140 }
2141 return H_CONSTANT_INT32(res);
2142 }
2143 }
2144 }
2145 return new(zone) HMod(context, left, right);
2146 }
2147
2148
NewHDiv(Zone * zone,HValue * context,HValue * left,HValue * right)2149 HInstruction* HDiv::NewHDiv(Zone* zone,
2150 HValue* context,
2151 HValue* left,
2152 HValue* right) {
2153 // If left and right are constant values, try to return a constant value.
2154 if (left->IsConstant() && right->IsConstant()) {
2155 HConstant* c_left = HConstant::cast(left);
2156 HConstant* c_right = HConstant::cast(right);
2157 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
2158 if (c_right->DoubleValue() != 0) {
2159 double double_res = c_left->DoubleValue() / c_right->DoubleValue();
2160 if (TypeInfo::IsInt32Double(double_res)) {
2161 return H_CONSTANT_INT32(static_cast<int32_t>(double_res));
2162 }
2163 return H_CONSTANT_DOUBLE(double_res);
2164 }
2165 }
2166 }
2167 return new(zone) HDiv(context, left, right);
2168 }
2169
2170
NewHBitwise(Zone * zone,Token::Value op,HValue * context,HValue * left,HValue * right)2171 HInstruction* HBitwise::NewHBitwise(Zone* zone,
2172 Token::Value op,
2173 HValue* context,
2174 HValue* left,
2175 HValue* right) {
2176 if (left->IsConstant() && right->IsConstant()) {
2177 HConstant* c_left = HConstant::cast(left);
2178 HConstant* c_right = HConstant::cast(right);
2179 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
2180 int32_t result;
2181 int32_t v_left = c_left->NumberValueAsInteger32();
2182 int32_t v_right = c_right->NumberValueAsInteger32();
2183 switch (op) {
2184 case Token::BIT_XOR:
2185 result = v_left ^ v_right;
2186 break;
2187 case Token::BIT_AND:
2188 result = v_left & v_right;
2189 break;
2190 case Token::BIT_OR:
2191 result = v_left | v_right;
2192 break;
2193 default:
2194 result = 0; // Please the compiler.
2195 UNREACHABLE();
2196 }
2197 return H_CONSTANT_INT32(result);
2198 }
2199 }
2200 return new(zone) HBitwise(op, context, left, right);
2201 }
2202
2203
2204 #define DEFINE_NEW_H_BITWISE_INSTR(HInstr, result) \
2205 HInstruction* HInstr::New##HInstr(Zone* zone, \
2206 HValue* context, \
2207 HValue* left, \
2208 HValue* right) { \
2209 if (left->IsConstant() && right->IsConstant()) { \
2210 HConstant* c_left = HConstant::cast(left); \
2211 HConstant* c_right = HConstant::cast(right); \
2212 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
2213 return H_CONSTANT_INT32(result); \
2214 } \
2215 } \
2216 return new(zone) HInstr(context, left, right); \
2217 }
2218
2219
2220 DEFINE_NEW_H_BITWISE_INSTR(HSar,
2221 c_left->NumberValueAsInteger32() >> (c_right->NumberValueAsInteger32() & 0x1f))
2222 DEFINE_NEW_H_BITWISE_INSTR(HShl,
2223 c_left->NumberValueAsInteger32() << (c_right->NumberValueAsInteger32() & 0x1f))
2224
2225 #undef DEFINE_NEW_H_BITWISE_INSTR
2226
2227
NewHShr(Zone * zone,HValue * context,HValue * left,HValue * right)2228 HInstruction* HShr::NewHShr(Zone* zone,
2229 HValue* context,
2230 HValue* left,
2231 HValue* right) {
2232 if (left->IsConstant() && right->IsConstant()) {
2233 HConstant* c_left = HConstant::cast(left);
2234 HConstant* c_right = HConstant::cast(right);
2235 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
2236 int32_t left_val = c_left->NumberValueAsInteger32();
2237 int32_t right_val = c_right->NumberValueAsInteger32() & 0x1f;
2238 if ((right_val == 0) && (left_val < 0)) {
2239 return H_CONSTANT_DOUBLE(
2240 static_cast<double>(static_cast<uint32_t>(left_val)));
2241 }
2242 return H_CONSTANT_INT32(static_cast<uint32_t>(left_val) >> right_val);
2243 }
2244 }
2245 return new(zone) HShr(context, left, right);
2246 }
2247
2248
2249 #undef H_CONSTANT_INT32
2250 #undef H_CONSTANT_DOUBLE
2251
2252
PrintDataTo(StringStream * stream)2253 void HIn::PrintDataTo(StringStream* stream) {
2254 key()->PrintNameTo(stream);
2255 stream->Add(" ");
2256 object()->PrintNameTo(stream);
2257 }
2258
2259
InferredRepresentation()2260 Representation HPhi::InferredRepresentation() {
2261 bool double_occurred = false;
2262 bool int32_occurred = false;
2263 for (int i = 0; i < OperandCount(); ++i) {
2264 HValue* value = OperandAt(i);
2265 if (value->IsUnknownOSRValue()) {
2266 HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value();
2267 if (hint_value != NULL) {
2268 Representation hint = hint_value->representation();
2269 if (hint.IsDouble()) double_occurred = true;
2270 if (hint.IsInteger32()) int32_occurred = true;
2271 }
2272 continue;
2273 }
2274 if (value->representation().IsDouble()) double_occurred = true;
2275 if (value->representation().IsInteger32()) int32_occurred = true;
2276 if (value->representation().IsTagged()) {
2277 if (value->IsConstant()) {
2278 HConstant* constant = HConstant::cast(value);
2279 if (constant->IsConvertibleToInteger()) {
2280 int32_occurred = true;
2281 } else if (constant->HasNumberValue()) {
2282 double_occurred = true;
2283 } else {
2284 return Representation::Tagged();
2285 }
2286 } else {
2287 return Representation::Tagged();
2288 }
2289 }
2290 }
2291
2292 if (double_occurred) return Representation::Double();
2293
2294 if (int32_occurred) return Representation::Integer32();
2295
2296 return Representation::None();
2297 }
2298
2299
2300 // Node-specific verification code is only included in debug mode.
2301 #ifdef DEBUG
2302
Verify()2303 void HPhi::Verify() {
2304 ASSERT(OperandCount() == block()->predecessors()->length());
2305 for (int i = 0; i < OperandCount(); ++i) {
2306 HValue* value = OperandAt(i);
2307 HBasicBlock* defining_block = value->block();
2308 HBasicBlock* predecessor_block = block()->predecessors()->at(i);
2309 ASSERT(defining_block == predecessor_block ||
2310 defining_block->Dominates(predecessor_block));
2311 }
2312 }
2313
2314
Verify()2315 void HSimulate::Verify() {
2316 HInstruction::Verify();
2317 ASSERT(HasAstId());
2318 }
2319
2320
Verify()2321 void HCheckSmi::Verify() {
2322 HInstruction::Verify();
2323 ASSERT(HasNoUses());
2324 }
2325
2326
Verify()2327 void HCheckNonSmi::Verify() {
2328 HInstruction::Verify();
2329 ASSERT(HasNoUses());
2330 }
2331
2332
Verify()2333 void HCheckFunction::Verify() {
2334 HInstruction::Verify();
2335 ASSERT(HasNoUses());
2336 }
2337
2338
Verify()2339 void HCheckPrototypeMaps::Verify() {
2340 HInstruction::Verify();
2341 ASSERT(HasNoUses());
2342 }
2343
2344 #endif
2345
2346 } } // namespace v8::internal
2347