1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/crankshaft/hydrogen-instructions.h"
6
7 #include "src/base/bits.h"
8 #include "src/base/ieee754.h"
9 #include "src/base/safe_math.h"
10 #include "src/codegen.h"
11 #include "src/crankshaft/hydrogen-infer-representation.h"
12 #include "src/double.h"
13 #include "src/elements.h"
14 #include "src/factory.h"
15
16 #if V8_TARGET_ARCH_IA32
17 #include "src/crankshaft/ia32/lithium-ia32.h" // NOLINT
18 #elif V8_TARGET_ARCH_X64
19 #include "src/crankshaft/x64/lithium-x64.h" // NOLINT
20 #elif V8_TARGET_ARCH_ARM64
21 #include "src/crankshaft/arm64/lithium-arm64.h" // NOLINT
22 #elif V8_TARGET_ARCH_ARM
23 #include "src/crankshaft/arm/lithium-arm.h" // NOLINT
24 #elif V8_TARGET_ARCH_PPC
25 #include "src/crankshaft/ppc/lithium-ppc.h" // NOLINT
26 #elif V8_TARGET_ARCH_MIPS
27 #include "src/crankshaft/mips/lithium-mips.h" // NOLINT
28 #elif V8_TARGET_ARCH_MIPS64
29 #include "src/crankshaft/mips64/lithium-mips64.h" // NOLINT
30 #elif V8_TARGET_ARCH_S390
31 #include "src/crankshaft/s390/lithium-s390.h" // NOLINT
32 #elif V8_TARGET_ARCH_X87
33 #include "src/crankshaft/x87/lithium-x87.h" // NOLINT
34 #else
35 #error Unsupported target architecture.
36 #endif
37
38 namespace v8 {
39 namespace internal {
40
41 #define DEFINE_COMPILE(type) \
42 LInstruction* H##type::CompileToLithium(LChunkBuilder* builder) { \
43 return builder->Do##type(this); \
44 }
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)45 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
46 #undef DEFINE_COMPILE
47
48 Representation RepresentationFromMachineType(MachineType type) {
49 if (type == MachineType::Int32()) {
50 return Representation::Integer32();
51 }
52
53 if (type == MachineType::TaggedSigned()) {
54 return Representation::Smi();
55 }
56
57 if (type == MachineType::Pointer()) {
58 return Representation::External();
59 }
60
61 return Representation::Tagged();
62 }
63
isolate() const64 Isolate* HValue::isolate() const {
65 DCHECK(block() != NULL);
66 return block()->isolate();
67 }
68
69
AssumeRepresentation(Representation r)70 void HValue::AssumeRepresentation(Representation r) {
71 if (CheckFlag(kFlexibleRepresentation)) {
72 ChangeRepresentation(r);
73 // The representation of the value is dictated by type feedback and
74 // will not be changed later.
75 ClearFlag(kFlexibleRepresentation);
76 }
77 }
78
79
InferRepresentation(HInferRepresentationPhase * h_infer)80 void HValue::InferRepresentation(HInferRepresentationPhase* h_infer) {
81 DCHECK(CheckFlag(kFlexibleRepresentation));
82 Representation new_rep = RepresentationFromInputs();
83 UpdateRepresentation(new_rep, h_infer, "inputs");
84 new_rep = RepresentationFromUses();
85 UpdateRepresentation(new_rep, h_infer, "uses");
86 if (representation().IsSmi() && HasNonSmiUse()) {
87 UpdateRepresentation(
88 Representation::Integer32(), h_infer, "use requirements");
89 }
90 }
91
92
RepresentationFromUses()93 Representation HValue::RepresentationFromUses() {
94 if (HasNoUses()) return Representation::None();
95 Representation result = Representation::None();
96
97 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
98 HValue* use = it.value();
99 Representation rep = use->observed_input_representation(it.index());
100 result = result.generalize(rep);
101
102 if (FLAG_trace_representation) {
103 PrintF("#%d %s is used by #%d %s as %s%s\n",
104 id(), Mnemonic(), use->id(), use->Mnemonic(), rep.Mnemonic(),
105 (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : ""));
106 }
107 }
108 if (IsPhi()) {
109 result = result.generalize(
110 HPhi::cast(this)->representation_from_indirect_uses());
111 }
112
113 // External representations are dealt with separately.
114 return result.IsExternal() ? Representation::None() : result;
115 }
116
117
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)118 void HValue::UpdateRepresentation(Representation new_rep,
119 HInferRepresentationPhase* h_infer,
120 const char* reason) {
121 Representation r = representation();
122 if (new_rep.is_more_general_than(r)) {
123 if (CheckFlag(kCannotBeTagged) && new_rep.IsTagged()) return;
124 if (FLAG_trace_representation) {
125 PrintF("Changing #%d %s representation %s -> %s based on %s\n",
126 id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason);
127 }
128 ChangeRepresentation(new_rep);
129 AddDependantsToWorklist(h_infer);
130 }
131 }
132
133
AddDependantsToWorklist(HInferRepresentationPhase * h_infer)134 void HValue::AddDependantsToWorklist(HInferRepresentationPhase* h_infer) {
135 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
136 h_infer->AddToWorklist(it.value());
137 }
138 for (int i = 0; i < OperandCount(); ++i) {
139 h_infer->AddToWorklist(OperandAt(i));
140 }
141 }
142
143
ConvertAndSetOverflow(Representation r,int64_t result,bool * overflow)144 static int32_t ConvertAndSetOverflow(Representation r,
145 int64_t result,
146 bool* overflow) {
147 if (r.IsSmi()) {
148 if (result > Smi::kMaxValue) {
149 *overflow = true;
150 return Smi::kMaxValue;
151 }
152 if (result < Smi::kMinValue) {
153 *overflow = true;
154 return Smi::kMinValue;
155 }
156 } else {
157 if (result > kMaxInt) {
158 *overflow = true;
159 return kMaxInt;
160 }
161 if (result < kMinInt) {
162 *overflow = true;
163 return kMinInt;
164 }
165 }
166 return static_cast<int32_t>(result);
167 }
168
169
AddWithoutOverflow(Representation r,int32_t a,int32_t b,bool * overflow)170 static int32_t AddWithoutOverflow(Representation r,
171 int32_t a,
172 int32_t b,
173 bool* overflow) {
174 int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b);
175 return ConvertAndSetOverflow(r, result, overflow);
176 }
177
178
SubWithoutOverflow(Representation r,int32_t a,int32_t b,bool * overflow)179 static int32_t SubWithoutOverflow(Representation r,
180 int32_t a,
181 int32_t b,
182 bool* overflow) {
183 int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b);
184 return ConvertAndSetOverflow(r, result, overflow);
185 }
186
187
MulWithoutOverflow(const Representation & r,int32_t a,int32_t b,bool * overflow)188 static int32_t MulWithoutOverflow(const Representation& r,
189 int32_t a,
190 int32_t b,
191 bool* overflow) {
192 int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b);
193 return ConvertAndSetOverflow(r, result, overflow);
194 }
195
196
Mask() const197 int32_t Range::Mask() const {
198 if (lower_ == upper_) return lower_;
199 if (lower_ >= 0) {
200 int32_t res = 1;
201 while (res < upper_) {
202 res = (res << 1) | 1;
203 }
204 return res;
205 }
206 return 0xffffffff;
207 }
208
209
AddConstant(int32_t value)210 void Range::AddConstant(int32_t value) {
211 if (value == 0) return;
212 bool may_overflow = false; // Overflow is ignored here.
213 Representation r = Representation::Integer32();
214 lower_ = AddWithoutOverflow(r, lower_, value, &may_overflow);
215 upper_ = AddWithoutOverflow(r, upper_, value, &may_overflow);
216 #ifdef DEBUG
217 Verify();
218 #endif
219 }
220
221
Intersect(Range * other)222 void Range::Intersect(Range* other) {
223 upper_ = Min(upper_, other->upper_);
224 lower_ = Max(lower_, other->lower_);
225 bool b = CanBeMinusZero() && other->CanBeMinusZero();
226 set_can_be_minus_zero(b);
227 }
228
229
Union(Range * other)230 void Range::Union(Range* other) {
231 upper_ = Max(upper_, other->upper_);
232 lower_ = Min(lower_, other->lower_);
233 bool b = CanBeMinusZero() || other->CanBeMinusZero();
234 set_can_be_minus_zero(b);
235 }
236
237
CombinedMax(Range * other)238 void Range::CombinedMax(Range* other) {
239 upper_ = Max(upper_, other->upper_);
240 lower_ = Max(lower_, other->lower_);
241 set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero());
242 }
243
244
CombinedMin(Range * other)245 void Range::CombinedMin(Range* other) {
246 upper_ = Min(upper_, other->upper_);
247 lower_ = Min(lower_, other->lower_);
248 set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero());
249 }
250
251
Sar(int32_t value)252 void Range::Sar(int32_t value) {
253 int32_t bits = value & 0x1F;
254 lower_ = lower_ >> bits;
255 upper_ = upper_ >> bits;
256 set_can_be_minus_zero(false);
257 }
258
259
Shl(int32_t value)260 void Range::Shl(int32_t value) {
261 int32_t bits = value & 0x1F;
262 int old_lower = lower_;
263 int old_upper = upper_;
264 lower_ = lower_ << bits;
265 upper_ = upper_ << bits;
266 if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) {
267 upper_ = kMaxInt;
268 lower_ = kMinInt;
269 }
270 set_can_be_minus_zero(false);
271 }
272
273
AddAndCheckOverflow(const Representation & r,Range * other)274 bool Range::AddAndCheckOverflow(const Representation& r, Range* other) {
275 bool may_overflow = false;
276 lower_ = AddWithoutOverflow(r, lower_, other->lower(), &may_overflow);
277 upper_ = AddWithoutOverflow(r, upper_, other->upper(), &may_overflow);
278 if (may_overflow) {
279 Clear();
280 } else {
281 KeepOrder();
282 }
283 #ifdef DEBUG
284 Verify();
285 #endif
286 return may_overflow;
287 }
288
289
SubAndCheckOverflow(const Representation & r,Range * other)290 bool Range::SubAndCheckOverflow(const Representation& r, Range* other) {
291 bool may_overflow = false;
292 lower_ = SubWithoutOverflow(r, lower_, other->upper(), &may_overflow);
293 upper_ = SubWithoutOverflow(r, upper_, other->lower(), &may_overflow);
294 if (may_overflow) {
295 Clear();
296 } else {
297 KeepOrder();
298 }
299 #ifdef DEBUG
300 Verify();
301 #endif
302 return may_overflow;
303 }
304
Clear()305 void Range::Clear() {
306 lower_ = kMinInt;
307 upper_ = kMaxInt;
308 }
309
KeepOrder()310 void Range::KeepOrder() {
311 if (lower_ > upper_) {
312 int32_t tmp = lower_;
313 lower_ = upper_;
314 upper_ = tmp;
315 }
316 }
317
318
319 #ifdef DEBUG
Verify() const320 void Range::Verify() const {
321 DCHECK(lower_ <= upper_);
322 }
323 #endif
324
325
MulAndCheckOverflow(const Representation & r,Range * other)326 bool Range::MulAndCheckOverflow(const Representation& r, Range* other) {
327 bool may_overflow = false;
328 int v1 = MulWithoutOverflow(r, lower_, other->lower(), &may_overflow);
329 int v2 = MulWithoutOverflow(r, lower_, other->upper(), &may_overflow);
330 int v3 = MulWithoutOverflow(r, upper_, other->lower(), &may_overflow);
331 int v4 = MulWithoutOverflow(r, upper_, other->upper(), &may_overflow);
332 if (may_overflow) {
333 Clear();
334 } else {
335 lower_ = Min(Min(v1, v2), Min(v3, v4));
336 upper_ = Max(Max(v1, v2), Max(v3, v4));
337 }
338 #ifdef DEBUG
339 Verify();
340 #endif
341 return may_overflow;
342 }
343
344
IsDefinedAfter(HBasicBlock * other) const345 bool HValue::IsDefinedAfter(HBasicBlock* other) const {
346 return block()->block_id() > other->block_id();
347 }
348
349
tail()350 HUseListNode* HUseListNode::tail() {
351 // Skip and remove dead items in the use list.
352 while (tail_ != NULL && tail_->value()->CheckFlag(HValue::kIsDead)) {
353 tail_ = tail_->tail_;
354 }
355 return tail_;
356 }
357
358
CheckUsesForFlag(Flag f) const359 bool HValue::CheckUsesForFlag(Flag f) const {
360 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
361 if (it.value()->IsSimulate()) continue;
362 if (!it.value()->CheckFlag(f)) return false;
363 }
364 return true;
365 }
366
367
CheckUsesForFlag(Flag f,HValue ** value) const368 bool HValue::CheckUsesForFlag(Flag f, HValue** value) const {
369 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
370 if (it.value()->IsSimulate()) continue;
371 if (!it.value()->CheckFlag(f)) {
372 *value = it.value();
373 return false;
374 }
375 }
376 return true;
377 }
378
379
HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const380 bool HValue::HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const {
381 bool return_value = false;
382 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
383 if (it.value()->IsSimulate()) continue;
384 if (!it.value()->CheckFlag(f)) return false;
385 return_value = true;
386 }
387 return return_value;
388 }
389
390
HUseIterator(HUseListNode * head)391 HUseIterator::HUseIterator(HUseListNode* head) : next_(head) {
392 Advance();
393 }
394
395
Advance()396 void HUseIterator::Advance() {
397 current_ = next_;
398 if (current_ != NULL) {
399 next_ = current_->tail();
400 value_ = current_->value();
401 index_ = current_->index();
402 }
403 }
404
405
UseCount() const406 int HValue::UseCount() const {
407 int count = 0;
408 for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count;
409 return count;
410 }
411
412
RemoveUse(HValue * value,int index)413 HUseListNode* HValue::RemoveUse(HValue* value, int index) {
414 HUseListNode* previous = NULL;
415 HUseListNode* current = use_list_;
416 while (current != NULL) {
417 if (current->value() == value && current->index() == index) {
418 if (previous == NULL) {
419 use_list_ = current->tail();
420 } else {
421 previous->set_tail(current->tail());
422 }
423 break;
424 }
425
426 previous = current;
427 current = current->tail();
428 }
429
430 #ifdef DEBUG
431 // Do not reuse use list nodes in debug mode, zap them.
432 if (current != NULL) {
433 HUseListNode* temp =
434 new(block()->zone())
435 HUseListNode(current->value(), current->index(), NULL);
436 current->Zap();
437 current = temp;
438 }
439 #endif
440 return current;
441 }
442
443
Equals(HValue * other)444 bool HValue::Equals(HValue* other) {
445 if (other->opcode() != opcode()) return false;
446 if (!other->representation().Equals(representation())) return false;
447 if (!other->type_.Equals(type_)) return false;
448 if (other->flags() != flags()) return false;
449 if (OperandCount() != other->OperandCount()) return false;
450 for (int i = 0; i < OperandCount(); ++i) {
451 if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false;
452 }
453 bool result = DataEquals(other);
454 DCHECK(!result || Hashcode() == other->Hashcode());
455 return result;
456 }
457
458
Hashcode()459 intptr_t HValue::Hashcode() {
460 intptr_t result = opcode();
461 int count = OperandCount();
462 for (int i = 0; i < count; ++i) {
463 result = result * 19 + OperandAt(i)->id() + (result >> 7);
464 }
465 return result;
466 }
467
468
Mnemonic() const469 const char* HValue::Mnemonic() const {
470 switch (opcode()) {
471 #define MAKE_CASE(type) case k##type: return #type;
472 HYDROGEN_CONCRETE_INSTRUCTION_LIST(MAKE_CASE)
473 #undef MAKE_CASE
474 case kPhi: return "Phi";
475 default: return "";
476 }
477 }
478
479
CanReplaceWithDummyUses()480 bool HValue::CanReplaceWithDummyUses() {
481 return FLAG_unreachable_code_elimination &&
482 !(block()->IsReachable() ||
483 IsBlockEntry() ||
484 IsControlInstruction() ||
485 IsArgumentsObject() ||
486 IsCapturedObject() ||
487 IsSimulate() ||
488 IsEnterInlined() ||
489 IsLeaveInlined());
490 }
491
492
IsInteger32Constant()493 bool HValue::IsInteger32Constant() {
494 return IsConstant() && HConstant::cast(this)->HasInteger32Value();
495 }
496
497
GetInteger32Constant()498 int32_t HValue::GetInteger32Constant() {
499 return HConstant::cast(this)->Integer32Value();
500 }
501
502
EqualsInteger32Constant(int32_t value)503 bool HValue::EqualsInteger32Constant(int32_t value) {
504 return IsInteger32Constant() && GetInteger32Constant() == value;
505 }
506
507
SetOperandAt(int index,HValue * value)508 void HValue::SetOperandAt(int index, HValue* value) {
509 RegisterUse(index, value);
510 InternalSetOperandAt(index, value);
511 }
512
513
DeleteAndReplaceWith(HValue * other)514 void HValue::DeleteAndReplaceWith(HValue* other) {
515 // We replace all uses first, so Delete can assert that there are none.
516 if (other != NULL) ReplaceAllUsesWith(other);
517 Kill();
518 DeleteFromGraph();
519 }
520
521
ReplaceAllUsesWith(HValue * other)522 void HValue::ReplaceAllUsesWith(HValue* other) {
523 while (use_list_ != NULL) {
524 HUseListNode* list_node = use_list_;
525 HValue* value = list_node->value();
526 DCHECK(!value->block()->IsStartBlock());
527 value->InternalSetOperandAt(list_node->index(), other);
528 use_list_ = list_node->tail();
529 list_node->set_tail(other->use_list_);
530 other->use_list_ = list_node;
531 }
532 }
533
534
Kill()535 void HValue::Kill() {
536 // Instead of going through the entire use list of each operand, we only
537 // check the first item in each use list and rely on the tail() method to
538 // skip dead items, removing them lazily next time we traverse the list.
539 SetFlag(kIsDead);
540 for (int i = 0; i < OperandCount(); ++i) {
541 HValue* operand = OperandAt(i);
542 if (operand == NULL) continue;
543 HUseListNode* first = operand->use_list_;
544 if (first != NULL && first->value()->CheckFlag(kIsDead)) {
545 operand->use_list_ = first->tail();
546 }
547 }
548 }
549
550
SetBlock(HBasicBlock * block)551 void HValue::SetBlock(HBasicBlock* block) {
552 DCHECK(block_ == NULL || block == NULL);
553 block_ = block;
554 if (id_ == kNoNumber && block != NULL) {
555 id_ = block->graph()->GetNextValueID(this);
556 }
557 }
558
559
operator <<(std::ostream & os,const HValue & v)560 std::ostream& operator<<(std::ostream& os, const HValue& v) {
561 return v.PrintTo(os);
562 }
563
564
operator <<(std::ostream & os,const TypeOf & t)565 std::ostream& operator<<(std::ostream& os, const TypeOf& t) {
566 if (t.value->representation().IsTagged() &&
567 !t.value->type().Equals(HType::Tagged()))
568 return os;
569 return os << " type:" << t.value->type();
570 }
571
572
operator <<(std::ostream & os,const ChangesOf & c)573 std::ostream& operator<<(std::ostream& os, const ChangesOf& c) {
574 GVNFlagSet changes_flags = c.value->ChangesFlags();
575 if (changes_flags.IsEmpty()) return os;
576 os << " changes[";
577 if (changes_flags == c.value->AllSideEffectsFlagSet()) {
578 os << "*";
579 } else {
580 bool add_comma = false;
581 #define PRINT_DO(Type) \
582 if (changes_flags.Contains(k##Type)) { \
583 if (add_comma) os << ","; \
584 add_comma = true; \
585 os << #Type; \
586 }
587 GVN_TRACKED_FLAG_LIST(PRINT_DO);
588 GVN_UNTRACKED_FLAG_LIST(PRINT_DO);
589 #undef PRINT_DO
590 }
591 return os << "]";
592 }
593
594
HasMonomorphicJSObjectType()595 bool HValue::HasMonomorphicJSObjectType() {
596 return !GetMonomorphicJSObjectMap().is_null();
597 }
598
599
UpdateInferredType()600 bool HValue::UpdateInferredType() {
601 HType type = CalculateInferredType();
602 bool result = (!type.Equals(type_));
603 type_ = type;
604 return result;
605 }
606
607
RegisterUse(int index,HValue * new_value)608 void HValue::RegisterUse(int index, HValue* new_value) {
609 HValue* old_value = OperandAt(index);
610 if (old_value == new_value) return;
611
612 HUseListNode* removed = NULL;
613 if (old_value != NULL) {
614 removed = old_value->RemoveUse(this, index);
615 }
616
617 if (new_value != NULL) {
618 if (removed == NULL) {
619 new_value->use_list_ = new(new_value->block()->zone()) HUseListNode(
620 this, index, new_value->use_list_);
621 } else {
622 removed->set_tail(new_value->use_list_);
623 new_value->use_list_ = removed;
624 }
625 }
626 }
627
628
AddNewRange(Range * r,Zone * zone)629 void HValue::AddNewRange(Range* r, Zone* zone) {
630 if (!HasRange()) ComputeInitialRange(zone);
631 if (!HasRange()) range_ = new(zone) Range();
632 DCHECK(HasRange());
633 r->StackUpon(range_);
634 range_ = r;
635 }
636
637
RemoveLastAddedRange()638 void HValue::RemoveLastAddedRange() {
639 DCHECK(HasRange());
640 DCHECK(range_->next() != NULL);
641 range_ = range_->next();
642 }
643
644
ComputeInitialRange(Zone * zone)645 void HValue::ComputeInitialRange(Zone* zone) {
646 DCHECK(!HasRange());
647 range_ = InferRange(zone);
648 DCHECK(HasRange());
649 }
650
651
PrintTo(std::ostream & os) const652 std::ostream& HInstruction::PrintTo(std::ostream& os) const { // NOLINT
653 os << Mnemonic() << " ";
654 PrintDataTo(os) << ChangesOf(this) << TypeOf(this);
655 if (CheckFlag(HValue::kHasNoObservableSideEffects)) os << " [noOSE]";
656 if (CheckFlag(HValue::kIsDead)) os << " [dead]";
657 return os;
658 }
659
660
PrintDataTo(std::ostream & os) const661 std::ostream& HInstruction::PrintDataTo(std::ostream& os) const { // NOLINT
662 for (int i = 0; i < OperandCount(); ++i) {
663 if (i > 0) os << " ";
664 os << NameOf(OperandAt(i));
665 }
666 return os;
667 }
668
669
Unlink()670 void HInstruction::Unlink() {
671 DCHECK(IsLinked());
672 DCHECK(!IsControlInstruction()); // Must never move control instructions.
673 DCHECK(!IsBlockEntry()); // Doesn't make sense to delete these.
674 DCHECK(previous_ != NULL);
675 previous_->next_ = next_;
676 if (next_ == NULL) {
677 DCHECK(block()->last() == this);
678 block()->set_last(previous_);
679 } else {
680 next_->previous_ = previous_;
681 }
682 clear_block();
683 }
684
685
InsertBefore(HInstruction * next)686 void HInstruction::InsertBefore(HInstruction* next) {
687 DCHECK(!IsLinked());
688 DCHECK(!next->IsBlockEntry());
689 DCHECK(!IsControlInstruction());
690 DCHECK(!next->block()->IsStartBlock());
691 DCHECK(next->previous_ != NULL);
692 HInstruction* prev = next->previous();
693 prev->next_ = this;
694 next->previous_ = this;
695 next_ = next;
696 previous_ = prev;
697 SetBlock(next->block());
698 if (!has_position() && next->has_position()) {
699 set_position(next->position());
700 }
701 }
702
703
InsertAfter(HInstruction * previous)704 void HInstruction::InsertAfter(HInstruction* previous) {
705 DCHECK(!IsLinked());
706 DCHECK(!previous->IsControlInstruction());
707 DCHECK(!IsControlInstruction() || previous->next_ == NULL);
708 HBasicBlock* block = previous->block();
709 // Never insert anything except constants into the start block after finishing
710 // it.
711 if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) {
712 DCHECK(block->end()->SecondSuccessor() == NULL);
713 InsertAfter(block->end()->FirstSuccessor()->first());
714 return;
715 }
716
717 // If we're inserting after an instruction with side-effects that is
718 // followed by a simulate instruction, we need to insert after the
719 // simulate instruction instead.
720 HInstruction* next = previous->next_;
721 if (previous->HasObservableSideEffects() && next != NULL) {
722 DCHECK(next->IsSimulate());
723 previous = next;
724 next = previous->next_;
725 }
726
727 previous_ = previous;
728 next_ = next;
729 SetBlock(block);
730 previous->next_ = this;
731 if (next != NULL) next->previous_ = this;
732 if (block->last() == previous) {
733 block->set_last(this);
734 }
735 if (!has_position() && previous->has_position()) {
736 set_position(previous->position());
737 }
738 }
739
740
Dominates(HInstruction * other)741 bool HInstruction::Dominates(HInstruction* other) {
742 if (block() != other->block()) {
743 return block()->Dominates(other->block());
744 }
745 // Both instructions are in the same basic block. This instruction
746 // should precede the other one in order to dominate it.
747 for (HInstruction* instr = next(); instr != NULL; instr = instr->next()) {
748 if (instr == other) {
749 return true;
750 }
751 }
752 return false;
753 }
754
755
756 #ifdef DEBUG
Verify()757 void HInstruction::Verify() {
758 // Verify that input operands are defined before use.
759 HBasicBlock* cur_block = block();
760 for (int i = 0; i < OperandCount(); ++i) {
761 HValue* other_operand = OperandAt(i);
762 if (other_operand == NULL) continue;
763 HBasicBlock* other_block = other_operand->block();
764 if (cur_block == other_block) {
765 if (!other_operand->IsPhi()) {
766 HInstruction* cur = this->previous();
767 while (cur != NULL) {
768 if (cur == other_operand) break;
769 cur = cur->previous();
770 }
771 // Must reach other operand in the same block!
772 DCHECK(cur == other_operand);
773 }
774 } else {
775 // If the following assert fires, you may have forgotten an
776 // AddInstruction.
777 DCHECK(other_block->Dominates(cur_block));
778 }
779 }
780
781 // Verify that instructions that may have side-effects are followed
782 // by a simulate instruction.
783 if (HasObservableSideEffects() && !IsOsrEntry()) {
784 DCHECK(next()->IsSimulate());
785 }
786
787 // Verify that instructions that can be eliminated by GVN have overridden
788 // HValue::DataEquals. The default implementation is UNREACHABLE. We
789 // don't actually care whether DataEquals returns true or false here.
790 if (CheckFlag(kUseGVN)) DataEquals(this);
791
792 // Verify that all uses are in the graph.
793 for (HUseIterator use = uses(); !use.Done(); use.Advance()) {
794 if (use.value()->IsInstruction()) {
795 DCHECK(HInstruction::cast(use.value())->IsLinked());
796 }
797 }
798 }
799 #endif
800
801
CanDeoptimize()802 bool HInstruction::CanDeoptimize() {
803 switch (opcode()) {
804 case HValue::kAbnormalExit:
805 case HValue::kAccessArgumentsAt:
806 case HValue::kAllocate:
807 case HValue::kArgumentsElements:
808 case HValue::kArgumentsLength:
809 case HValue::kArgumentsObject:
810 case HValue::kBlockEntry:
811 case HValue::kCallNewArray:
812 case HValue::kCapturedObject:
813 case HValue::kClassOfTestAndBranch:
814 case HValue::kCompareGeneric:
815 case HValue::kCompareHoleAndBranch:
816 case HValue::kCompareMap:
817 case HValue::kCompareNumericAndBranch:
818 case HValue::kCompareObjectEqAndBranch:
819 case HValue::kConstant:
820 case HValue::kContext:
821 case HValue::kDebugBreak:
822 case HValue::kDeclareGlobals:
823 case HValue::kDummyUse:
824 case HValue::kEnterInlined:
825 case HValue::kEnvironmentMarker:
826 case HValue::kForceRepresentation:
827 case HValue::kGoto:
828 case HValue::kHasInstanceTypeAndBranch:
829 case HValue::kInnerAllocatedObject:
830 case HValue::kIsSmiAndBranch:
831 case HValue::kIsStringAndBranch:
832 case HValue::kIsUndetectableAndBranch:
833 case HValue::kLeaveInlined:
834 case HValue::kLoadFieldByIndex:
835 case HValue::kLoadNamedField:
836 case HValue::kLoadRoot:
837 case HValue::kMathMinMax:
838 case HValue::kParameter:
839 case HValue::kPhi:
840 case HValue::kPushArguments:
841 case HValue::kReturn:
842 case HValue::kSeqStringGetChar:
843 case HValue::kStoreCodeEntry:
844 case HValue::kStoreKeyed:
845 case HValue::kStoreNamedField:
846 case HValue::kStringCharCodeAt:
847 case HValue::kStringCharFromCode:
848 case HValue::kThisFunction:
849 case HValue::kTypeofIsAndBranch:
850 case HValue::kUnknownOSRValue:
851 case HValue::kUseConst:
852 return false;
853
854 case HValue::kAdd:
855 case HValue::kApplyArguments:
856 case HValue::kBitwise:
857 case HValue::kBoundsCheck:
858 case HValue::kBranch:
859 case HValue::kCallRuntime:
860 case HValue::kCallWithDescriptor:
861 case HValue::kChange:
862 case HValue::kCheckArrayBufferNotNeutered:
863 case HValue::kCheckHeapObject:
864 case HValue::kCheckInstanceType:
865 case HValue::kCheckMapValue:
866 case HValue::kCheckMaps:
867 case HValue::kCheckSmi:
868 case HValue::kCheckValue:
869 case HValue::kClampToUint8:
870 case HValue::kDeoptimize:
871 case HValue::kDiv:
872 case HValue::kForInCacheArray:
873 case HValue::kForInPrepareMap:
874 case HValue::kHasInPrototypeChainAndBranch:
875 case HValue::kInvokeFunction:
876 case HValue::kLoadContextSlot:
877 case HValue::kLoadFunctionPrototype:
878 case HValue::kLoadKeyed:
879 case HValue::kMathFloorOfDiv:
880 case HValue::kMaybeGrowElements:
881 case HValue::kMod:
882 case HValue::kMul:
883 case HValue::kOsrEntry:
884 case HValue::kPower:
885 case HValue::kPrologue:
886 case HValue::kRor:
887 case HValue::kSar:
888 case HValue::kSeqStringSetChar:
889 case HValue::kShl:
890 case HValue::kShr:
891 case HValue::kSimulate:
892 case HValue::kStackCheck:
893 case HValue::kStoreContextSlot:
894 case HValue::kStringAdd:
895 case HValue::kStringCompareAndBranch:
896 case HValue::kSub:
897 case HValue::kTransitionElementsKind:
898 case HValue::kTrapAllocationMemento:
899 case HValue::kTypeof:
900 case HValue::kUnaryMathOperation:
901 case HValue::kWrapReceiver:
902 return true;
903 }
904 UNREACHABLE();
905 return true;
906 }
907
908
operator <<(std::ostream & os,const NameOf & v)909 std::ostream& operator<<(std::ostream& os, const NameOf& v) {
910 return os << v.value->representation().Mnemonic() << v.value->id();
911 }
912
PrintDataTo(std::ostream & os) const913 std::ostream& HDummyUse::PrintDataTo(std::ostream& os) const { // NOLINT
914 return os << NameOf(value());
915 }
916
917
PrintDataTo(std::ostream & os) const918 std::ostream& HEnvironmentMarker::PrintDataTo(
919 std::ostream& os) const { // NOLINT
920 return os << (kind() == BIND ? "bind" : "lookup") << " var[" << index()
921 << "]";
922 }
923
924
PrintDataTo(std::ostream & os) const925 std::ostream& HUnaryCall::PrintDataTo(std::ostream& os) const { // NOLINT
926 return os << NameOf(value()) << " #" << argument_count();
927 }
928
929
PrintDataTo(std::ostream & os) const930 std::ostream& HBinaryCall::PrintDataTo(std::ostream& os) const { // NOLINT
931 return os << NameOf(first()) << " " << NameOf(second()) << " #"
932 << argument_count();
933 }
934
PrintTo(std::ostream & os) const935 std::ostream& HInvokeFunction::PrintTo(std::ostream& os) const { // NOLINT
936 if (tail_call_mode() == TailCallMode::kAllow) os << "Tail";
937 return HBinaryCall::PrintTo(os);
938 }
939
PrintDataTo(std::ostream & os) const940 std::ostream& HInvokeFunction::PrintDataTo(std::ostream& os) const { // NOLINT
941 HBinaryCall::PrintDataTo(os);
942 if (syntactic_tail_call_mode() == TailCallMode::kAllow) {
943 os << ", JSTailCall";
944 }
945 return os;
946 }
947
PrintDataTo(std::ostream & os) const948 std::ostream& HBoundsCheck::PrintDataTo(std::ostream& os) const { // NOLINT
949 os << NameOf(index()) << " " << NameOf(length());
950 if (base() != NULL && (offset() != 0 || scale() != 0)) {
951 os << " base: ((";
952 if (base() != index()) {
953 os << NameOf(index());
954 } else {
955 os << "index";
956 }
957 os << " + " << offset() << ") >> " << scale() << ")";
958 }
959 if (skip_check()) os << " [DISABLED]";
960 return os;
961 }
962
963
InferRepresentation(HInferRepresentationPhase * h_infer)964 void HBoundsCheck::InferRepresentation(HInferRepresentationPhase* h_infer) {
965 DCHECK(CheckFlag(kFlexibleRepresentation));
966 HValue* actual_index = index()->ActualValue();
967 HValue* actual_length = length()->ActualValue();
968 Representation index_rep = actual_index->representation();
969 Representation length_rep = actual_length->representation();
970 if (index_rep.IsTagged() && actual_index->type().IsSmi()) {
971 index_rep = Representation::Smi();
972 }
973 if (length_rep.IsTagged() && actual_length->type().IsSmi()) {
974 length_rep = Representation::Smi();
975 }
976 Representation r = index_rep.generalize(length_rep);
977 if (r.is_more_general_than(Representation::Integer32())) {
978 r = Representation::Integer32();
979 }
980 UpdateRepresentation(r, h_infer, "boundscheck");
981 }
982
983
InferRange(Zone * zone)984 Range* HBoundsCheck::InferRange(Zone* zone) {
985 Representation r = representation();
986 if (r.IsSmiOrInteger32() && length()->HasRange()) {
987 int upper = length()->range()->upper() - (allow_equality() ? 0 : 1);
988 int lower = 0;
989
990 Range* result = new(zone) Range(lower, upper);
991 if (index()->HasRange()) {
992 result->Intersect(index()->range());
993 }
994
995 // In case of Smi representation, clamp result to Smi::kMaxValue.
996 if (r.IsSmi()) result->ClampToSmi();
997 return result;
998 }
999 return HValue::InferRange(zone);
1000 }
1001
1002
PrintDataTo(std::ostream & os) const1003 std::ostream& HCallWithDescriptor::PrintDataTo(
1004 std::ostream& os) const { // NOLINT
1005 for (int i = 0; i < OperandCount(); i++) {
1006 os << NameOf(OperandAt(i)) << " ";
1007 }
1008 os << "#" << argument_count();
1009 if (syntactic_tail_call_mode() == TailCallMode::kAllow) {
1010 os << ", JSTailCall";
1011 }
1012 return os;
1013 }
1014
1015
PrintDataTo(std::ostream & os) const1016 std::ostream& HCallNewArray::PrintDataTo(std::ostream& os) const { // NOLINT
1017 os << ElementsKindToString(elements_kind()) << " ";
1018 return HBinaryCall::PrintDataTo(os);
1019 }
1020
1021
PrintDataTo(std::ostream & os) const1022 std::ostream& HCallRuntime::PrintDataTo(std::ostream& os) const { // NOLINT
1023 os << function()->name << " ";
1024 if (save_doubles() == kSaveFPRegs) os << "[save doubles] ";
1025 return os << "#" << argument_count();
1026 }
1027
1028
PrintDataTo(std::ostream & os) const1029 std::ostream& HClassOfTestAndBranch::PrintDataTo(
1030 std::ostream& os) const { // NOLINT
1031 return os << "class_of_test(" << NameOf(value()) << ", \""
1032 << class_name()->ToCString().get() << "\")";
1033 }
1034
1035
PrintDataTo(std::ostream & os) const1036 std::ostream& HWrapReceiver::PrintDataTo(std::ostream& os) const { // NOLINT
1037 return os << NameOf(receiver()) << " " << NameOf(function());
1038 }
1039
1040
PrintDataTo(std::ostream & os) const1041 std::ostream& HAccessArgumentsAt::PrintDataTo(
1042 std::ostream& os) const { // NOLINT
1043 return os << NameOf(arguments()) << "[" << NameOf(index()) << "], length "
1044 << NameOf(length());
1045 }
1046
1047
PrintDataTo(std::ostream & os) const1048 std::ostream& HControlInstruction::PrintDataTo(
1049 std::ostream& os) const { // NOLINT
1050 os << " goto (";
1051 bool first_block = true;
1052 for (HSuccessorIterator it(this); !it.Done(); it.Advance()) {
1053 if (!first_block) os << ", ";
1054 os << *it.Current();
1055 first_block = false;
1056 }
1057 return os << ")";
1058 }
1059
1060
PrintDataTo(std::ostream & os) const1061 std::ostream& HUnaryControlInstruction::PrintDataTo(
1062 std::ostream& os) const { // NOLINT
1063 os << NameOf(value());
1064 return HControlInstruction::PrintDataTo(os);
1065 }
1066
1067
PrintDataTo(std::ostream & os) const1068 std::ostream& HReturn::PrintDataTo(std::ostream& os) const { // NOLINT
1069 return os << NameOf(value()) << " (pop " << NameOf(parameter_count())
1070 << " values)";
1071 }
1072
1073
observed_input_representation(int index)1074 Representation HBranch::observed_input_representation(int index) {
1075 if (expected_input_types_ & (ToBooleanHint::kNull | ToBooleanHint::kReceiver |
1076 ToBooleanHint::kString | ToBooleanHint::kSymbol |
1077 ToBooleanHint::kSimdValue)) {
1078 return Representation::Tagged();
1079 }
1080 if (expected_input_types_ & ToBooleanHint::kUndefined) {
1081 if (expected_input_types_ & ToBooleanHint::kHeapNumber) {
1082 return Representation::Double();
1083 }
1084 return Representation::Tagged();
1085 }
1086 if (expected_input_types_ & ToBooleanHint::kHeapNumber) {
1087 return Representation::Double();
1088 }
1089 if (expected_input_types_ & ToBooleanHint::kSmallInteger) {
1090 return Representation::Smi();
1091 }
1092 return Representation::None();
1093 }
1094
1095
KnownSuccessorBlock(HBasicBlock ** block)1096 bool HBranch::KnownSuccessorBlock(HBasicBlock** block) {
1097 HValue* value = this->value();
1098 if (value->EmitAtUses()) {
1099 DCHECK(value->IsConstant());
1100 DCHECK(!value->representation().IsDouble());
1101 *block = HConstant::cast(value)->BooleanValue()
1102 ? FirstSuccessor()
1103 : SecondSuccessor();
1104 return true;
1105 }
1106 *block = NULL;
1107 return false;
1108 }
1109
1110
PrintDataTo(std::ostream & os) const1111 std::ostream& HBranch::PrintDataTo(std::ostream& os) const { // NOLINT
1112 return HUnaryControlInstruction::PrintDataTo(os) << " "
1113 << expected_input_types();
1114 }
1115
1116
PrintDataTo(std::ostream & os) const1117 std::ostream& HCompareMap::PrintDataTo(std::ostream& os) const { // NOLINT
1118 os << NameOf(value()) << " (" << *map().handle() << ")";
1119 HControlInstruction::PrintDataTo(os);
1120 if (known_successor_index() == 0) {
1121 os << " [true]";
1122 } else if (known_successor_index() == 1) {
1123 os << " [false]";
1124 }
1125 return os;
1126 }
1127
1128
OpName() const1129 const char* HUnaryMathOperation::OpName() const {
1130 switch (op()) {
1131 case kMathFloor:
1132 return "floor";
1133 case kMathFround:
1134 return "fround";
1135 case kMathRound:
1136 return "round";
1137 case kMathAbs:
1138 return "abs";
1139 case kMathCos:
1140 return "cos";
1141 case kMathLog:
1142 return "log";
1143 case kMathExp:
1144 return "exp";
1145 case kMathSin:
1146 return "sin";
1147 case kMathSqrt:
1148 return "sqrt";
1149 case kMathPowHalf:
1150 return "pow-half";
1151 case kMathClz32:
1152 return "clz32";
1153 default:
1154 UNREACHABLE();
1155 return NULL;
1156 }
1157 }
1158
1159
InferRange(Zone * zone)1160 Range* HUnaryMathOperation::InferRange(Zone* zone) {
1161 Representation r = representation();
1162 if (op() == kMathClz32) return new(zone) Range(0, 32);
1163 if (r.IsSmiOrInteger32() && value()->HasRange()) {
1164 if (op() == kMathAbs) {
1165 int upper = value()->range()->upper();
1166 int lower = value()->range()->lower();
1167 bool spans_zero = value()->range()->CanBeZero();
1168 // Math.abs(kMinInt) overflows its representation, on which the
1169 // instruction deopts. Hence clamp it to kMaxInt.
1170 int abs_upper = upper == kMinInt ? kMaxInt : abs(upper);
1171 int abs_lower = lower == kMinInt ? kMaxInt : abs(lower);
1172 Range* result =
1173 new(zone) Range(spans_zero ? 0 : Min(abs_lower, abs_upper),
1174 Max(abs_lower, abs_upper));
1175 // In case of Smi representation, clamp Math.abs(Smi::kMinValue) to
1176 // Smi::kMaxValue.
1177 if (r.IsSmi()) result->ClampToSmi();
1178 return result;
1179 }
1180 }
1181 return HValue::InferRange(zone);
1182 }
1183
1184
PrintDataTo(std::ostream & os) const1185 std::ostream& HUnaryMathOperation::PrintDataTo(
1186 std::ostream& os) const { // NOLINT
1187 return os << OpName() << " " << NameOf(value());
1188 }
1189
1190
PrintDataTo(std::ostream & os) const1191 std::ostream& HUnaryOperation::PrintDataTo(std::ostream& os) const { // NOLINT
1192 return os << NameOf(value());
1193 }
1194
1195
PrintDataTo(std::ostream & os) const1196 std::ostream& HHasInstanceTypeAndBranch::PrintDataTo(
1197 std::ostream& os) const { // NOLINT
1198 os << NameOf(value());
1199 switch (from_) {
1200 case FIRST_JS_RECEIVER_TYPE:
1201 if (to_ == LAST_TYPE) os << " spec_object";
1202 break;
1203 case JS_REGEXP_TYPE:
1204 if (to_ == JS_REGEXP_TYPE) os << " reg_exp";
1205 break;
1206 case JS_ARRAY_TYPE:
1207 if (to_ == JS_ARRAY_TYPE) os << " array";
1208 break;
1209 case JS_FUNCTION_TYPE:
1210 if (to_ == JS_FUNCTION_TYPE) os << " function";
1211 break;
1212 default:
1213 break;
1214 }
1215 return os;
1216 }
1217
1218
PrintDataTo(std::ostream & os) const1219 std::ostream& HTypeofIsAndBranch::PrintDataTo(
1220 std::ostream& os) const { // NOLINT
1221 os << NameOf(value()) << " == " << type_literal()->ToCString().get();
1222 return HControlInstruction::PrintDataTo(os);
1223 }
1224
1225
1226 namespace {
1227
TypeOfString(HConstant * constant,Isolate * isolate)1228 String* TypeOfString(HConstant* constant, Isolate* isolate) {
1229 Heap* heap = isolate->heap();
1230 if (constant->HasNumberValue()) return heap->number_string();
1231 if (constant->HasStringValue()) return heap->string_string();
1232 switch (constant->GetInstanceType()) {
1233 case ODDBALL_TYPE: {
1234 Unique<Object> unique = constant->GetUnique();
1235 if (unique.IsKnownGlobal(heap->true_value()) ||
1236 unique.IsKnownGlobal(heap->false_value())) {
1237 return heap->boolean_string();
1238 }
1239 if (unique.IsKnownGlobal(heap->null_value())) {
1240 return heap->object_string();
1241 }
1242 DCHECK(unique.IsKnownGlobal(heap->undefined_value()));
1243 return heap->undefined_string();
1244 }
1245 case SYMBOL_TYPE:
1246 return heap->symbol_string();
1247 case SIMD128_VALUE_TYPE: {
1248 Unique<Map> map = constant->ObjectMap();
1249 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
1250 if (map.IsKnownGlobal(heap->type##_map())) { \
1251 return heap->type##_string(); \
1252 }
1253 SIMD128_TYPES(SIMD128_TYPE)
1254 #undef SIMD128_TYPE
1255 UNREACHABLE();
1256 return nullptr;
1257 }
1258 default:
1259 if (constant->IsUndetectable()) return heap->undefined_string();
1260 if (constant->IsCallable()) return heap->function_string();
1261 return heap->object_string();
1262 }
1263 }
1264
1265 } // namespace
1266
1267
KnownSuccessorBlock(HBasicBlock ** block)1268 bool HTypeofIsAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
1269 if (FLAG_fold_constants && value()->IsConstant()) {
1270 HConstant* constant = HConstant::cast(value());
1271 String* type_string = TypeOfString(constant, isolate());
1272 bool same_type = type_literal_.IsKnownGlobal(type_string);
1273 *block = same_type ? FirstSuccessor() : SecondSuccessor();
1274 return true;
1275 } else if (value()->representation().IsSpecialization()) {
1276 bool number_type =
1277 type_literal_.IsKnownGlobal(isolate()->heap()->number_string());
1278 *block = number_type ? FirstSuccessor() : SecondSuccessor();
1279 return true;
1280 }
1281 *block = NULL;
1282 return false;
1283 }
1284
1285
PrintDataTo(std::ostream & os) const1286 std::ostream& HCheckMapValue::PrintDataTo(std::ostream& os) const { // NOLINT
1287 return os << NameOf(value()) << " " << NameOf(map());
1288 }
1289
1290
Canonicalize()1291 HValue* HCheckMapValue::Canonicalize() {
1292 if (map()->IsConstant()) {
1293 HConstant* c_map = HConstant::cast(map());
1294 return HCheckMaps::CreateAndInsertAfter(
1295 block()->graph()->zone(), value(), c_map->MapValue(),
1296 c_map->HasStableMapValue(), this);
1297 }
1298 return this;
1299 }
1300
1301
PrintDataTo(std::ostream & os) const1302 std::ostream& HForInPrepareMap::PrintDataTo(std::ostream& os) const { // NOLINT
1303 return os << NameOf(enumerable());
1304 }
1305
1306
PrintDataTo(std::ostream & os) const1307 std::ostream& HForInCacheArray::PrintDataTo(std::ostream& os) const { // NOLINT
1308 return os << NameOf(enumerable()) << " " << NameOf(map()) << "[" << idx_
1309 << "]";
1310 }
1311
1312
PrintDataTo(std::ostream & os) const1313 std::ostream& HLoadFieldByIndex::PrintDataTo(
1314 std::ostream& os) const { // NOLINT
1315 return os << NameOf(object()) << " " << NameOf(index());
1316 }
1317
1318
MatchLeftIsOnes(HValue * l,HValue * r,HValue ** negated)1319 static bool MatchLeftIsOnes(HValue* l, HValue* r, HValue** negated) {
1320 if (!l->EqualsInteger32Constant(~0)) return false;
1321 *negated = r;
1322 return true;
1323 }
1324
1325
MatchNegationViaXor(HValue * instr,HValue ** negated)1326 static bool MatchNegationViaXor(HValue* instr, HValue** negated) {
1327 if (!instr->IsBitwise()) return false;
1328 HBitwise* b = HBitwise::cast(instr);
1329 return (b->op() == Token::BIT_XOR) &&
1330 (MatchLeftIsOnes(b->left(), b->right(), negated) ||
1331 MatchLeftIsOnes(b->right(), b->left(), negated));
1332 }
1333
1334
MatchDoubleNegation(HValue * instr,HValue ** arg)1335 static bool MatchDoubleNegation(HValue* instr, HValue** arg) {
1336 HValue* negated;
1337 return MatchNegationViaXor(instr, &negated) &&
1338 MatchNegationViaXor(negated, arg);
1339 }
1340
1341
Canonicalize()1342 HValue* HBitwise::Canonicalize() {
1343 if (!representation().IsSmiOrInteger32()) return this;
1344 // If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x.
1345 int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0;
1346 if (left()->EqualsInteger32Constant(nop_constant) &&
1347 !right()->CheckFlag(kUint32)) {
1348 return right();
1349 }
1350 if (right()->EqualsInteger32Constant(nop_constant) &&
1351 !left()->CheckFlag(kUint32)) {
1352 return left();
1353 }
1354 // Optimize double negation, a common pattern used for ToInt32(x).
1355 HValue* arg;
1356 if (MatchDoubleNegation(this, &arg) && !arg->CheckFlag(kUint32)) {
1357 return arg;
1358 }
1359 return this;
1360 }
1361
1362
1363 // static
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right,ExternalAddType external_add_type)1364 HInstruction* HAdd::New(Isolate* isolate, Zone* zone, HValue* context,
1365 HValue* left, HValue* right,
1366 ExternalAddType external_add_type) {
1367 // For everything else, you should use the other factory method without
1368 // ExternalAddType.
1369 DCHECK_EQ(external_add_type, AddOfExternalAndTagged);
1370 return new (zone) HAdd(context, left, right, external_add_type);
1371 }
1372
1373
RepresentationFromInputs()1374 Representation HAdd::RepresentationFromInputs() {
1375 Representation left_rep = left()->representation();
1376 if (left_rep.IsExternal()) {
1377 return Representation::External();
1378 }
1379 return HArithmeticBinaryOperation::RepresentationFromInputs();
1380 }
1381
1382
RequiredInputRepresentation(int index)1383 Representation HAdd::RequiredInputRepresentation(int index) {
1384 if (index == 2) {
1385 Representation left_rep = left()->representation();
1386 if (left_rep.IsExternal()) {
1387 if (external_add_type_ == AddOfExternalAndTagged) {
1388 return Representation::Tagged();
1389 } else {
1390 return Representation::Integer32();
1391 }
1392 }
1393 }
1394 return HArithmeticBinaryOperation::RequiredInputRepresentation(index);
1395 }
1396
1397
IsIdentityOperation(HValue * arg1,HValue * arg2,int32_t identity)1398 static bool IsIdentityOperation(HValue* arg1, HValue* arg2, int32_t identity) {
1399 return arg1->representation().IsSpecialization() &&
1400 arg2->EqualsInteger32Constant(identity);
1401 }
1402
1403
Canonicalize()1404 HValue* HAdd::Canonicalize() {
1405 // Adding 0 is an identity operation except in case of -0: -0 + 0 = +0
1406 if (IsIdentityOperation(left(), right(), 0) &&
1407 !left()->representation().IsDouble()) { // Left could be -0.
1408 return left();
1409 }
1410 if (IsIdentityOperation(right(), left(), 0) &&
1411 !left()->representation().IsDouble()) { // Right could be -0.
1412 return right();
1413 }
1414 return this;
1415 }
1416
1417
Canonicalize()1418 HValue* HSub::Canonicalize() {
1419 if (IsIdentityOperation(left(), right(), 0)) return left();
1420 return this;
1421 }
1422
1423
Canonicalize()1424 HValue* HMul::Canonicalize() {
1425 if (IsIdentityOperation(left(), right(), 1)) return left();
1426 if (IsIdentityOperation(right(), left(), 1)) return right();
1427 return this;
1428 }
1429
1430
MulMinusOne()1431 bool HMul::MulMinusOne() {
1432 if (left()->EqualsInteger32Constant(-1) ||
1433 right()->EqualsInteger32Constant(-1)) {
1434 return true;
1435 }
1436
1437 return false;
1438 }
1439
1440
Canonicalize()1441 HValue* HMod::Canonicalize() {
1442 return this;
1443 }
1444
1445
Canonicalize()1446 HValue* HDiv::Canonicalize() {
1447 if (IsIdentityOperation(left(), right(), 1)) return left();
1448 return this;
1449 }
1450
1451
Canonicalize()1452 HValue* HChange::Canonicalize() {
1453 return (from().Equals(to())) ? value() : this;
1454 }
1455
1456
Canonicalize()1457 HValue* HWrapReceiver::Canonicalize() {
1458 if (HasNoUses()) return NULL;
1459 if (receiver()->type().IsJSReceiver()) {
1460 return receiver();
1461 }
1462 return this;
1463 }
1464
1465
PrintDataTo(std::ostream & os) const1466 std::ostream& HTypeof::PrintDataTo(std::ostream& os) const { // NOLINT
1467 return os << NameOf(value());
1468 }
1469
1470
New(Isolate * isolate,Zone * zone,HValue * context,HValue * value,Representation representation)1471 HInstruction* HForceRepresentation::New(Isolate* isolate, Zone* zone,
1472 HValue* context, HValue* value,
1473 Representation representation) {
1474 if (FLAG_fold_constants && value->IsConstant()) {
1475 HConstant* c = HConstant::cast(value);
1476 c = c->CopyToRepresentation(representation, zone);
1477 if (c != NULL) return c;
1478 }
1479 return new(zone) HForceRepresentation(value, representation);
1480 }
1481
1482
PrintDataTo(std::ostream & os) const1483 std::ostream& HForceRepresentation::PrintDataTo(
1484 std::ostream& os) const { // NOLINT
1485 return os << representation().Mnemonic() << " " << NameOf(value());
1486 }
1487
1488
PrintDataTo(std::ostream & os) const1489 std::ostream& HChange::PrintDataTo(std::ostream& os) const { // NOLINT
1490 HUnaryOperation::PrintDataTo(os);
1491 os << " " << from().Mnemonic() << " to " << to().Mnemonic();
1492
1493 if (CanTruncateToSmi()) os << " truncating-smi";
1494 if (CanTruncateToInt32()) os << " truncating-int32";
1495 if (CanTruncateToNumber()) os << " truncating-number";
1496 if (CheckFlag(kBailoutOnMinusZero)) os << " -0?";
1497 return os;
1498 }
1499
1500
Canonicalize()1501 HValue* HUnaryMathOperation::Canonicalize() {
1502 if (op() == kMathRound || op() == kMathFloor) {
1503 HValue* val = value();
1504 if (val->IsChange()) val = HChange::cast(val)->value();
1505 if (val->representation().IsSmiOrInteger32()) {
1506 if (val->representation().Equals(representation())) return val;
1507 return Prepend(new (block()->zone())
1508 HChange(val, representation(), false, false, true));
1509 }
1510 }
1511 if (op() == kMathFloor && representation().IsSmiOrInteger32() &&
1512 value()->IsDiv() && value()->HasOneUse()) {
1513 HDiv* hdiv = HDiv::cast(value());
1514
1515 HValue* left = hdiv->left();
1516 if (left->representation().IsInteger32() && !left->CheckFlag(kUint32)) {
1517 // A value with an integer representation does not need to be transformed.
1518 } else if (left->IsChange() && HChange::cast(left)->from().IsInteger32() &&
1519 !HChange::cast(left)->value()->CheckFlag(kUint32)) {
1520 // A change from an integer32 can be replaced by the integer32 value.
1521 left = HChange::cast(left)->value();
1522 } else if (hdiv->observed_input_representation(1).IsSmiOrInteger32()) {
1523 left = Prepend(new (block()->zone()) HChange(
1524 left, Representation::Integer32(), false, false, true));
1525 } else {
1526 return this;
1527 }
1528
1529 HValue* right = hdiv->right();
1530 if (right->IsInteger32Constant()) {
1531 right = Prepend(HConstant::cast(right)->CopyToRepresentation(
1532 Representation::Integer32(), right->block()->zone()));
1533 } else if (right->representation().IsInteger32() &&
1534 !right->CheckFlag(kUint32)) {
1535 // A value with an integer representation does not need to be transformed.
1536 } else if (right->IsChange() &&
1537 HChange::cast(right)->from().IsInteger32() &&
1538 !HChange::cast(right)->value()->CheckFlag(kUint32)) {
1539 // A change from an integer32 can be replaced by the integer32 value.
1540 right = HChange::cast(right)->value();
1541 } else if (hdiv->observed_input_representation(2).IsSmiOrInteger32()) {
1542 right = Prepend(new (block()->zone()) HChange(
1543 right, Representation::Integer32(), false, false, true));
1544 } else {
1545 return this;
1546 }
1547
1548 return Prepend(HMathFloorOfDiv::New(
1549 block()->graph()->isolate(), block()->zone(), context(), left, right));
1550 }
1551 return this;
1552 }
1553
1554
Canonicalize()1555 HValue* HCheckInstanceType::Canonicalize() {
1556 if ((check_ == IS_JS_RECEIVER && value()->type().IsJSReceiver()) ||
1557 (check_ == IS_JS_ARRAY && value()->type().IsJSArray()) ||
1558 (check_ == IS_STRING && value()->type().IsString())) {
1559 return value();
1560 }
1561
1562 if (check_ == IS_INTERNALIZED_STRING && value()->IsConstant()) {
1563 if (HConstant::cast(value())->HasInternalizedStringValue()) {
1564 return value();
1565 }
1566 }
1567 return this;
1568 }
1569
1570
GetCheckInterval(InstanceType * first,InstanceType * last)1571 void HCheckInstanceType::GetCheckInterval(InstanceType* first,
1572 InstanceType* last) {
1573 DCHECK(is_interval_check());
1574 switch (check_) {
1575 case IS_JS_RECEIVER:
1576 *first = FIRST_JS_RECEIVER_TYPE;
1577 *last = LAST_JS_RECEIVER_TYPE;
1578 return;
1579 case IS_JS_ARRAY:
1580 *first = *last = JS_ARRAY_TYPE;
1581 return;
1582 case IS_JS_FUNCTION:
1583 *first = *last = JS_FUNCTION_TYPE;
1584 return;
1585 case IS_JS_DATE:
1586 *first = *last = JS_DATE_TYPE;
1587 return;
1588 default:
1589 UNREACHABLE();
1590 }
1591 }
1592
1593
GetCheckMaskAndTag(uint8_t * mask,uint8_t * tag)1594 void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) {
1595 DCHECK(!is_interval_check());
1596 switch (check_) {
1597 case IS_STRING:
1598 *mask = kIsNotStringMask;
1599 *tag = kStringTag;
1600 return;
1601 case IS_INTERNALIZED_STRING:
1602 *mask = kIsNotStringMask | kIsNotInternalizedMask;
1603 *tag = kInternalizedTag;
1604 return;
1605 default:
1606 UNREACHABLE();
1607 }
1608 }
1609
1610
PrintDataTo(std::ostream & os) const1611 std::ostream& HCheckMaps::PrintDataTo(std::ostream& os) const { // NOLINT
1612 os << NameOf(value()) << " [" << *maps()->at(0).handle();
1613 for (int i = 1; i < maps()->size(); ++i) {
1614 os << "," << *maps()->at(i).handle();
1615 }
1616 os << "]";
1617 if (IsStabilityCheck()) os << "(stability-check)";
1618 return os;
1619 }
1620
1621
Canonicalize()1622 HValue* HCheckMaps::Canonicalize() {
1623 if (!IsStabilityCheck() && maps_are_stable() && value()->IsConstant()) {
1624 HConstant* c_value = HConstant::cast(value());
1625 if (c_value->HasObjectMap()) {
1626 for (int i = 0; i < maps()->size(); ++i) {
1627 if (c_value->ObjectMap() == maps()->at(i)) {
1628 if (maps()->size() > 1) {
1629 set_maps(new(block()->graph()->zone()) UniqueSet<Map>(
1630 maps()->at(i), block()->graph()->zone()));
1631 }
1632 MarkAsStabilityCheck();
1633 break;
1634 }
1635 }
1636 }
1637 }
1638 return this;
1639 }
1640
1641
PrintDataTo(std::ostream & os) const1642 std::ostream& HCheckValue::PrintDataTo(std::ostream& os) const { // NOLINT
1643 return os << NameOf(value()) << " " << Brief(*object().handle());
1644 }
1645
1646
Canonicalize()1647 HValue* HCheckValue::Canonicalize() {
1648 return (value()->IsConstant() &&
1649 HConstant::cast(value())->EqualsUnique(object_)) ? NULL : this;
1650 }
1651
1652
GetCheckName() const1653 const char* HCheckInstanceType::GetCheckName() const {
1654 switch (check_) {
1655 case IS_JS_RECEIVER: return "object";
1656 case IS_JS_ARRAY: return "array";
1657 case IS_JS_FUNCTION:
1658 return "function";
1659 case IS_JS_DATE:
1660 return "date";
1661 case IS_STRING: return "string";
1662 case IS_INTERNALIZED_STRING: return "internalized_string";
1663 }
1664 UNREACHABLE();
1665 return "";
1666 }
1667
1668
PrintDataTo(std::ostream & os) const1669 std::ostream& HCheckInstanceType::PrintDataTo(
1670 std::ostream& os) const { // NOLINT
1671 os << GetCheckName() << " ";
1672 return HUnaryOperation::PrintDataTo(os);
1673 }
1674
1675
PrintDataTo(std::ostream & os) const1676 std::ostream& HUnknownOSRValue::PrintDataTo(std::ostream& os) const { // NOLINT
1677 const char* type = "expression";
1678 if (environment_->is_local_index(index_)) type = "local";
1679 if (environment_->is_special_index(index_)) type = "special";
1680 if (environment_->is_parameter_index(index_)) type = "parameter";
1681 return os << type << " @ " << index_;
1682 }
1683
1684
InferRange(Zone * zone)1685 Range* HValue::InferRange(Zone* zone) {
1686 Range* result;
1687 if (representation().IsSmi() || type().IsSmi()) {
1688 result = new(zone) Range(Smi::kMinValue, Smi::kMaxValue);
1689 result->set_can_be_minus_zero(false);
1690 } else {
1691 result = new(zone) Range();
1692 result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32));
1693 // TODO(jkummerow): The range cannot be minus zero when the upper type
1694 // bound is Integer32.
1695 }
1696 return result;
1697 }
1698
1699
InferRange(Zone * zone)1700 Range* HChange::InferRange(Zone* zone) {
1701 Range* input_range = value()->range();
1702 if (from().IsInteger32() && !value()->CheckFlag(HInstruction::kUint32) &&
1703 (to().IsSmi() ||
1704 (to().IsTagged() &&
1705 input_range != NULL &&
1706 input_range->IsInSmiRange()))) {
1707 set_type(HType::Smi());
1708 ClearChangesFlag(kNewSpacePromotion);
1709 }
1710 if (to().IsSmiOrTagged() &&
1711 input_range != NULL &&
1712 input_range->IsInSmiRange() &&
1713 (!SmiValuesAre32Bits() ||
1714 !value()->CheckFlag(HValue::kUint32) ||
1715 input_range->upper() != kMaxInt)) {
1716 // The Range class can't express upper bounds in the (kMaxInt, kMaxUint32]
1717 // interval, so we treat kMaxInt as a sentinel for this entire interval.
1718 ClearFlag(kCanOverflow);
1719 }
1720 Range* result = (input_range != NULL)
1721 ? input_range->Copy(zone)
1722 : HValue::InferRange(zone);
1723 result->set_can_be_minus_zero(!to().IsSmiOrInteger32() ||
1724 !(CheckFlag(kAllUsesTruncatingToInt32) ||
1725 CheckFlag(kAllUsesTruncatingToSmi)));
1726 if (to().IsSmi()) result->ClampToSmi();
1727 return result;
1728 }
1729
1730
InferRange(Zone * zone)1731 Range* HConstant::InferRange(Zone* zone) {
1732 if (HasInteger32Value()) {
1733 Range* result = new(zone) Range(int32_value_, int32_value_);
1734 result->set_can_be_minus_zero(false);
1735 return result;
1736 }
1737 return HValue::InferRange(zone);
1738 }
1739
1740
position() const1741 SourcePosition HPhi::position() const { return block()->first()->position(); }
1742
1743
InferRange(Zone * zone)1744 Range* HPhi::InferRange(Zone* zone) {
1745 Representation r = representation();
1746 if (r.IsSmiOrInteger32()) {
1747 if (block()->IsLoopHeader()) {
1748 Range* range = r.IsSmi()
1749 ? new(zone) Range(Smi::kMinValue, Smi::kMaxValue)
1750 : new(zone) Range(kMinInt, kMaxInt);
1751 return range;
1752 } else {
1753 Range* range = OperandAt(0)->range()->Copy(zone);
1754 for (int i = 1; i < OperandCount(); ++i) {
1755 range->Union(OperandAt(i)->range());
1756 }
1757 return range;
1758 }
1759 } else {
1760 return HValue::InferRange(zone);
1761 }
1762 }
1763
1764
InferRange(Zone * zone)1765 Range* HAdd::InferRange(Zone* zone) {
1766 Representation r = representation();
1767 if (r.IsSmiOrInteger32()) {
1768 Range* a = left()->range();
1769 Range* b = right()->range();
1770 Range* res = a->Copy(zone);
1771 if (!res->AddAndCheckOverflow(r, b) ||
1772 (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) ||
1773 (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) {
1774 ClearFlag(kCanOverflow);
1775 }
1776 res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) &&
1777 !CheckFlag(kAllUsesTruncatingToInt32) &&
1778 a->CanBeMinusZero() && b->CanBeMinusZero());
1779 return res;
1780 } else {
1781 return HValue::InferRange(zone);
1782 }
1783 }
1784
1785
InferRange(Zone * zone)1786 Range* HSub::InferRange(Zone* zone) {
1787 Representation r = representation();
1788 if (r.IsSmiOrInteger32()) {
1789 Range* a = left()->range();
1790 Range* b = right()->range();
1791 Range* res = a->Copy(zone);
1792 if (!res->SubAndCheckOverflow(r, b) ||
1793 (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) ||
1794 (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) {
1795 ClearFlag(kCanOverflow);
1796 }
1797 res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) &&
1798 !CheckFlag(kAllUsesTruncatingToInt32) &&
1799 a->CanBeMinusZero() && b->CanBeZero());
1800 return res;
1801 } else {
1802 return HValue::InferRange(zone);
1803 }
1804 }
1805
1806
InferRange(Zone * zone)1807 Range* HMul::InferRange(Zone* zone) {
1808 Representation r = representation();
1809 if (r.IsSmiOrInteger32()) {
1810 Range* a = left()->range();
1811 Range* b = right()->range();
1812 Range* res = a->Copy(zone);
1813 if (!res->MulAndCheckOverflow(r, b) ||
1814 (((r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) ||
1815 (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) &&
1816 MulMinusOne())) {
1817 // Truncated int multiplication is too precise and therefore not the
1818 // same as converting to Double and back.
1819 // Handle truncated integer multiplication by -1 special.
1820 ClearFlag(kCanOverflow);
1821 }
1822 res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) &&
1823 !CheckFlag(kAllUsesTruncatingToInt32) &&
1824 ((a->CanBeZero() && b->CanBeNegative()) ||
1825 (a->CanBeNegative() && b->CanBeZero())));
1826 return res;
1827 } else {
1828 return HValue::InferRange(zone);
1829 }
1830 }
1831
1832
InferRange(Zone * zone)1833 Range* HDiv::InferRange(Zone* zone) {
1834 if (representation().IsInteger32()) {
1835 Range* a = left()->range();
1836 Range* b = right()->range();
1837 Range* result = new(zone) Range();
1838 result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) &&
1839 (a->CanBeMinusZero() ||
1840 (a->CanBeZero() && b->CanBeNegative())));
1841 if (!a->Includes(kMinInt) || !b->Includes(-1)) {
1842 ClearFlag(kCanOverflow);
1843 }
1844
1845 if (!b->CanBeZero()) {
1846 ClearFlag(kCanBeDivByZero);
1847 }
1848 return result;
1849 } else {
1850 return HValue::InferRange(zone);
1851 }
1852 }
1853
1854
InferRange(Zone * zone)1855 Range* HMathFloorOfDiv::InferRange(Zone* zone) {
1856 if (representation().IsInteger32()) {
1857 Range* a = left()->range();
1858 Range* b = right()->range();
1859 Range* result = new(zone) Range();
1860 result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) &&
1861 (a->CanBeMinusZero() ||
1862 (a->CanBeZero() && b->CanBeNegative())));
1863 if (!a->Includes(kMinInt)) {
1864 ClearFlag(kLeftCanBeMinInt);
1865 }
1866
1867 if (!a->CanBeNegative()) {
1868 ClearFlag(HValue::kLeftCanBeNegative);
1869 }
1870
1871 if (!a->CanBePositive()) {
1872 ClearFlag(HValue::kLeftCanBePositive);
1873 }
1874
1875 if (!a->Includes(kMinInt) || !b->Includes(-1)) {
1876 ClearFlag(kCanOverflow);
1877 }
1878
1879 if (!b->CanBeZero()) {
1880 ClearFlag(kCanBeDivByZero);
1881 }
1882 return result;
1883 } else {
1884 return HValue::InferRange(zone);
1885 }
1886 }
1887
1888
1889 // Returns the absolute value of its argument minus one, avoiding undefined
1890 // behavior at kMinInt.
AbsMinus1(int32_t a)1891 static int32_t AbsMinus1(int32_t a) { return a < 0 ? -(a + 1) : (a - 1); }
1892
1893
InferRange(Zone * zone)1894 Range* HMod::InferRange(Zone* zone) {
1895 if (representation().IsInteger32()) {
1896 Range* a = left()->range();
1897 Range* b = right()->range();
1898
1899 // The magnitude of the modulus is bounded by the right operand.
1900 int32_t positive_bound = Max(AbsMinus1(b->lower()), AbsMinus1(b->upper()));
1901
1902 // The result of the modulo operation has the sign of its left operand.
1903 bool left_can_be_negative = a->CanBeMinusZero() || a->CanBeNegative();
1904 Range* result = new(zone) Range(left_can_be_negative ? -positive_bound : 0,
1905 a->CanBePositive() ? positive_bound : 0);
1906
1907 result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) &&
1908 left_can_be_negative);
1909
1910 if (!a->CanBeNegative()) {
1911 ClearFlag(HValue::kLeftCanBeNegative);
1912 }
1913
1914 if (!a->Includes(kMinInt) || !b->Includes(-1)) {
1915 ClearFlag(HValue::kCanOverflow);
1916 }
1917
1918 if (!b->CanBeZero()) {
1919 ClearFlag(HValue::kCanBeDivByZero);
1920 }
1921 return result;
1922 } else {
1923 return HValue::InferRange(zone);
1924 }
1925 }
1926
1927
InferRange(Zone * zone)1928 Range* HMathMinMax::InferRange(Zone* zone) {
1929 if (representation().IsSmiOrInteger32()) {
1930 Range* a = left()->range();
1931 Range* b = right()->range();
1932 Range* res = a->Copy(zone);
1933 if (operation_ == kMathMax) {
1934 res->CombinedMax(b);
1935 } else {
1936 DCHECK(operation_ == kMathMin);
1937 res->CombinedMin(b);
1938 }
1939 return res;
1940 } else {
1941 return HValue::InferRange(zone);
1942 }
1943 }
1944
1945
AddInput(HValue * value)1946 void HPushArguments::AddInput(HValue* value) {
1947 inputs_.Add(NULL, value->block()->zone());
1948 SetOperandAt(OperandCount() - 1, value);
1949 }
1950
1951
PrintTo(std::ostream & os) const1952 std::ostream& HPhi::PrintTo(std::ostream& os) const { // NOLINT
1953 os << "[";
1954 for (int i = 0; i < OperandCount(); ++i) {
1955 os << " " << NameOf(OperandAt(i)) << " ";
1956 }
1957 return os << " uses" << UseCount()
1958 << representation_from_indirect_uses().Mnemonic() << " "
1959 << TypeOf(this) << "]";
1960 }
1961
1962
AddInput(HValue * value)1963 void HPhi::AddInput(HValue* value) {
1964 inputs_.Add(NULL, value->block()->zone());
1965 SetOperandAt(OperandCount() - 1, value);
1966 // Mark phis that may have 'arguments' directly or indirectly as an operand.
1967 if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) {
1968 SetFlag(kIsArguments);
1969 }
1970 }
1971
1972
HasRealUses()1973 bool HPhi::HasRealUses() {
1974 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1975 if (!it.value()->IsPhi()) return true;
1976 }
1977 return false;
1978 }
1979
1980
GetRedundantReplacement()1981 HValue* HPhi::GetRedundantReplacement() {
1982 HValue* candidate = NULL;
1983 int count = OperandCount();
1984 int position = 0;
1985 while (position < count && candidate == NULL) {
1986 HValue* current = OperandAt(position++);
1987 if (current != this) candidate = current;
1988 }
1989 while (position < count) {
1990 HValue* current = OperandAt(position++);
1991 if (current != this && current != candidate) return NULL;
1992 }
1993 DCHECK(candidate != this);
1994 return candidate;
1995 }
1996
1997
DeleteFromGraph()1998 void HPhi::DeleteFromGraph() {
1999 DCHECK(block() != NULL);
2000 block()->RemovePhi(this);
2001 DCHECK(block() == NULL);
2002 }
2003
2004
InitRealUses(int phi_id)2005 void HPhi::InitRealUses(int phi_id) {
2006 // Initialize real uses.
2007 phi_id_ = phi_id;
2008 // Compute a conservative approximation of truncating uses before inferring
2009 // representations. The proper, exact computation will be done later, when
2010 // inserting representation changes.
2011 SetFlag(kTruncatingToSmi);
2012 SetFlag(kTruncatingToInt32);
2013 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
2014 HValue* value = it.value();
2015 if (!value->IsPhi()) {
2016 Representation rep = value->observed_input_representation(it.index());
2017 representation_from_non_phi_uses_ =
2018 representation_from_non_phi_uses().generalize(rep);
2019 if (rep.IsSmi() || rep.IsInteger32() || rep.IsDouble()) {
2020 has_type_feedback_from_uses_ = true;
2021 }
2022
2023 if (FLAG_trace_representation) {
2024 PrintF("#%d Phi is used by real #%d %s as %s\n",
2025 id(), value->id(), value->Mnemonic(), rep.Mnemonic());
2026 }
2027 if (!value->IsSimulate()) {
2028 if (!value->CheckFlag(kTruncatingToSmi)) {
2029 ClearFlag(kTruncatingToSmi);
2030 }
2031 if (!value->CheckFlag(kTruncatingToInt32)) {
2032 ClearFlag(kTruncatingToInt32);
2033 }
2034 }
2035 }
2036 }
2037 }
2038
2039
AddNonPhiUsesFrom(HPhi * other)2040 void HPhi::AddNonPhiUsesFrom(HPhi* other) {
2041 if (FLAG_trace_representation) {
2042 PrintF(
2043 "generalizing use representation '%s' of #%d Phi "
2044 "with uses of #%d Phi '%s'\n",
2045 representation_from_indirect_uses().Mnemonic(), id(), other->id(),
2046 other->representation_from_non_phi_uses().Mnemonic());
2047 }
2048
2049 representation_from_indirect_uses_ =
2050 representation_from_indirect_uses().generalize(
2051 other->representation_from_non_phi_uses());
2052 }
2053
2054
MergeWith(ZoneList<HSimulate * > * list)2055 void HSimulate::MergeWith(ZoneList<HSimulate*>* list) {
2056 while (!list->is_empty()) {
2057 HSimulate* from = list->RemoveLast();
2058 ZoneList<HValue*>* from_values = &from->values_;
2059 for (int i = 0; i < from_values->length(); ++i) {
2060 if (from->HasAssignedIndexAt(i)) {
2061 int index = from->GetAssignedIndexAt(i);
2062 if (HasValueForIndex(index)) continue;
2063 AddAssignedValue(index, from_values->at(i));
2064 } else {
2065 if (pop_count_ > 0) {
2066 pop_count_--;
2067 } else {
2068 AddPushedValue(from_values->at(i));
2069 }
2070 }
2071 }
2072 pop_count_ += from->pop_count_;
2073 from->DeleteAndReplaceWith(NULL);
2074 }
2075 }
2076
2077
PrintDataTo(std::ostream & os) const2078 std::ostream& HSimulate::PrintDataTo(std::ostream& os) const { // NOLINT
2079 os << "id=" << ast_id().ToInt();
2080 if (pop_count_ > 0) os << " pop " << pop_count_;
2081 if (values_.length() > 0) {
2082 if (pop_count_ > 0) os << " /";
2083 for (int i = values_.length() - 1; i >= 0; --i) {
2084 if (HasAssignedIndexAt(i)) {
2085 os << " var[" << GetAssignedIndexAt(i) << "] = ";
2086 } else {
2087 os << " push ";
2088 }
2089 os << NameOf(values_[i]);
2090 if (i > 0) os << ",";
2091 }
2092 }
2093 return os;
2094 }
2095
2096
ReplayEnvironment(HEnvironment * env)2097 void HSimulate::ReplayEnvironment(HEnvironment* env) {
2098 if (is_done_with_replay()) return;
2099 DCHECK(env != NULL);
2100 env->set_ast_id(ast_id());
2101 env->Drop(pop_count());
2102 for (int i = values()->length() - 1; i >= 0; --i) {
2103 HValue* value = values()->at(i);
2104 if (HasAssignedIndexAt(i)) {
2105 env->Bind(GetAssignedIndexAt(i), value);
2106 } else {
2107 env->Push(value);
2108 }
2109 }
2110 set_done_with_replay();
2111 }
2112
2113
ReplayEnvironmentNested(const ZoneList<HValue * > * values,HCapturedObject * other)2114 static void ReplayEnvironmentNested(const ZoneList<HValue*>* values,
2115 HCapturedObject* other) {
2116 for (int i = 0; i < values->length(); ++i) {
2117 HValue* value = values->at(i);
2118 if (value->IsCapturedObject()) {
2119 if (HCapturedObject::cast(value)->capture_id() == other->capture_id()) {
2120 values->at(i) = other;
2121 } else {
2122 ReplayEnvironmentNested(HCapturedObject::cast(value)->values(), other);
2123 }
2124 }
2125 }
2126 }
2127
2128
2129 // Replay captured objects by replacing all captured objects with the
2130 // same capture id in the current and all outer environments.
ReplayEnvironment(HEnvironment * env)2131 void HCapturedObject::ReplayEnvironment(HEnvironment* env) {
2132 DCHECK(env != NULL);
2133 while (env != NULL) {
2134 ReplayEnvironmentNested(env->values(), this);
2135 env = env->outer();
2136 }
2137 }
2138
2139
PrintDataTo(std::ostream & os) const2140 std::ostream& HCapturedObject::PrintDataTo(std::ostream& os) const { // NOLINT
2141 os << "#" << capture_id() << " ";
2142 return HDematerializedObject::PrintDataTo(os);
2143 }
2144
2145
RegisterReturnTarget(HBasicBlock * return_target,Zone * zone)2146 void HEnterInlined::RegisterReturnTarget(HBasicBlock* return_target,
2147 Zone* zone) {
2148 DCHECK(return_target->IsInlineReturnTarget());
2149 return_targets_.Add(return_target, zone);
2150 }
2151
2152
PrintDataTo(std::ostream & os) const2153 std::ostream& HEnterInlined::PrintDataTo(std::ostream& os) const { // NOLINT
2154 os << function()->debug_name()->ToCString().get();
2155 if (syntactic_tail_call_mode() == TailCallMode::kAllow) {
2156 os << ", JSTailCall";
2157 }
2158 return os;
2159 }
2160
2161
IsInteger32(double value)2162 static bool IsInteger32(double value) {
2163 if (value >= std::numeric_limits<int32_t>::min() &&
2164 value <= std::numeric_limits<int32_t>::max()) {
2165 double roundtrip_value = static_cast<double>(static_cast<int32_t>(value));
2166 return bit_cast<int64_t>(roundtrip_value) == bit_cast<int64_t>(value);
2167 }
2168 return false;
2169 }
2170
2171
HConstant(Special special)2172 HConstant::HConstant(Special special)
2173 : HTemplateInstruction<0>(HType::TaggedNumber()),
2174 object_(Handle<Object>::null()),
2175 object_map_(Handle<Map>::null()),
2176 bit_field_(HasDoubleValueField::encode(true) |
2177 InstanceTypeField::encode(kUnknownInstanceType)),
2178 int32_value_(0) {
2179 DCHECK_EQ(kHoleNaN, special);
2180 std::memcpy(&double_value_, &kHoleNanInt64, sizeof(double_value_));
2181 Initialize(Representation::Double());
2182 }
2183
2184
HConstant(Handle<Object> object,Representation r)2185 HConstant::HConstant(Handle<Object> object, Representation r)
2186 : HTemplateInstruction<0>(HType::FromValue(object)),
2187 object_(Unique<Object>::CreateUninitialized(object)),
2188 object_map_(Handle<Map>::null()),
2189 bit_field_(
2190 HasStableMapValueField::encode(false) |
2191 HasSmiValueField::encode(false) | HasInt32ValueField::encode(false) |
2192 HasDoubleValueField::encode(false) |
2193 HasExternalReferenceValueField::encode(false) |
2194 IsNotInNewSpaceField::encode(true) |
2195 BooleanValueField::encode(object->BooleanValue()) |
2196 IsUndetectableField::encode(false) | IsCallableField::encode(false) |
2197 InstanceTypeField::encode(kUnknownInstanceType)) {
2198 if (object->IsNumber()) {
2199 double n = object->Number();
2200 bool has_int32_value = IsInteger32(n);
2201 bit_field_ = HasInt32ValueField::update(bit_field_, has_int32_value);
2202 int32_value_ = DoubleToInt32(n);
2203 bit_field_ = HasSmiValueField::update(
2204 bit_field_, has_int32_value && Smi::IsValid(int32_value_));
2205 if (std::isnan(n)) {
2206 double_value_ = std::numeric_limits<double>::quiet_NaN();
2207 // Canonicalize object with NaN value.
2208 DCHECK(object->IsHeapObject()); // NaN can't be a Smi.
2209 Isolate* isolate = HeapObject::cast(*object)->GetIsolate();
2210 object = isolate->factory()->nan_value();
2211 object_ = Unique<Object>::CreateUninitialized(object);
2212 } else {
2213 double_value_ = n;
2214 // Canonicalize object with -0.0 value.
2215 if (bit_cast<int64_t>(n) == bit_cast<int64_t>(-0.0)) {
2216 DCHECK(object->IsHeapObject()); // -0.0 can't be a Smi.
2217 Isolate* isolate = HeapObject::cast(*object)->GetIsolate();
2218 object = isolate->factory()->minus_zero_value();
2219 object_ = Unique<Object>::CreateUninitialized(object);
2220 }
2221 }
2222 bit_field_ = HasDoubleValueField::update(bit_field_, true);
2223 }
2224 if (object->IsHeapObject()) {
2225 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2226 Isolate* isolate = heap_object->GetIsolate();
2227 Handle<Map> map(heap_object->map(), isolate);
2228 bit_field_ = IsNotInNewSpaceField::update(
2229 bit_field_, !isolate->heap()->InNewSpace(*object));
2230 bit_field_ = InstanceTypeField::update(bit_field_, map->instance_type());
2231 bit_field_ =
2232 IsUndetectableField::update(bit_field_, map->is_undetectable());
2233 bit_field_ = IsCallableField::update(bit_field_, map->is_callable());
2234 if (map->is_stable()) object_map_ = Unique<Map>::CreateImmovable(map);
2235 bit_field_ = HasStableMapValueField::update(
2236 bit_field_,
2237 HasMapValue() && Handle<Map>::cast(heap_object)->is_stable());
2238 }
2239
2240 Initialize(r);
2241 }
2242
2243
HConstant(Unique<Object> object,Unique<Map> object_map,bool has_stable_map_value,Representation r,HType type,bool is_not_in_new_space,bool boolean_value,bool is_undetectable,InstanceType instance_type)2244 HConstant::HConstant(Unique<Object> object, Unique<Map> object_map,
2245 bool has_stable_map_value, Representation r, HType type,
2246 bool is_not_in_new_space, bool boolean_value,
2247 bool is_undetectable, InstanceType instance_type)
2248 : HTemplateInstruction<0>(type),
2249 object_(object),
2250 object_map_(object_map),
2251 bit_field_(HasStableMapValueField::encode(has_stable_map_value) |
2252 HasSmiValueField::encode(false) |
2253 HasInt32ValueField::encode(false) |
2254 HasDoubleValueField::encode(false) |
2255 HasExternalReferenceValueField::encode(false) |
2256 IsNotInNewSpaceField::encode(is_not_in_new_space) |
2257 BooleanValueField::encode(boolean_value) |
2258 IsUndetectableField::encode(is_undetectable) |
2259 InstanceTypeField::encode(instance_type)) {
2260 DCHECK(!object.handle().is_null());
2261 DCHECK(!type.IsTaggedNumber() || type.IsNone());
2262 Initialize(r);
2263 }
2264
2265
HConstant(int32_t integer_value,Representation r,bool is_not_in_new_space,Unique<Object> object)2266 HConstant::HConstant(int32_t integer_value, Representation r,
2267 bool is_not_in_new_space, Unique<Object> object)
2268 : object_(object),
2269 object_map_(Handle<Map>::null()),
2270 bit_field_(HasStableMapValueField::encode(false) |
2271 HasSmiValueField::encode(Smi::IsValid(integer_value)) |
2272 HasInt32ValueField::encode(true) |
2273 HasDoubleValueField::encode(true) |
2274 HasExternalReferenceValueField::encode(false) |
2275 IsNotInNewSpaceField::encode(is_not_in_new_space) |
2276 BooleanValueField::encode(integer_value != 0) |
2277 IsUndetectableField::encode(false) |
2278 InstanceTypeField::encode(kUnknownInstanceType)),
2279 int32_value_(integer_value),
2280 double_value_(FastI2D(integer_value)) {
2281 // It's possible to create a constant with a value in Smi-range but stored
2282 // in a (pre-existing) HeapNumber. See crbug.com/349878.
2283 bool could_be_heapobject = r.IsTagged() && !object.handle().is_null();
2284 bool is_smi = HasSmiValue() && !could_be_heapobject;
2285 set_type(is_smi ? HType::Smi() : HType::TaggedNumber());
2286 Initialize(r);
2287 }
2288
HConstant(double double_value,Representation r,bool is_not_in_new_space,Unique<Object> object)2289 HConstant::HConstant(double double_value, Representation r,
2290 bool is_not_in_new_space, Unique<Object> object)
2291 : object_(object),
2292 object_map_(Handle<Map>::null()),
2293 bit_field_(HasStableMapValueField::encode(false) |
2294 HasInt32ValueField::encode(IsInteger32(double_value)) |
2295 HasDoubleValueField::encode(true) |
2296 HasExternalReferenceValueField::encode(false) |
2297 IsNotInNewSpaceField::encode(is_not_in_new_space) |
2298 BooleanValueField::encode(double_value != 0 &&
2299 !std::isnan(double_value)) |
2300 IsUndetectableField::encode(false) |
2301 InstanceTypeField::encode(kUnknownInstanceType)),
2302 int32_value_(DoubleToInt32(double_value)) {
2303 bit_field_ = HasSmiValueField::update(
2304 bit_field_, HasInteger32Value() && Smi::IsValid(int32_value_));
2305 // It's possible to create a constant with a value in Smi-range but stored
2306 // in a (pre-existing) HeapNumber. See crbug.com/349878.
2307 bool could_be_heapobject = r.IsTagged() && !object.handle().is_null();
2308 bool is_smi = HasSmiValue() && !could_be_heapobject;
2309 set_type(is_smi ? HType::Smi() : HType::TaggedNumber());
2310 if (std::isnan(double_value)) {
2311 double_value_ = std::numeric_limits<double>::quiet_NaN();
2312 } else {
2313 double_value_ = double_value;
2314 }
2315 Initialize(r);
2316 }
2317
2318
HConstant(ExternalReference reference)2319 HConstant::HConstant(ExternalReference reference)
2320 : HTemplateInstruction<0>(HType::Any()),
2321 object_(Unique<Object>(Handle<Object>::null())),
2322 object_map_(Handle<Map>::null()),
2323 bit_field_(
2324 HasStableMapValueField::encode(false) |
2325 HasSmiValueField::encode(false) | HasInt32ValueField::encode(false) |
2326 HasDoubleValueField::encode(false) |
2327 HasExternalReferenceValueField::encode(true) |
2328 IsNotInNewSpaceField::encode(true) | BooleanValueField::encode(true) |
2329 IsUndetectableField::encode(false) |
2330 InstanceTypeField::encode(kUnknownInstanceType)),
2331 external_reference_value_(reference) {
2332 Initialize(Representation::External());
2333 }
2334
2335
Initialize(Representation r)2336 void HConstant::Initialize(Representation r) {
2337 if (r.IsNone()) {
2338 if (HasSmiValue() && SmiValuesAre31Bits()) {
2339 r = Representation::Smi();
2340 } else if (HasInteger32Value()) {
2341 r = Representation::Integer32();
2342 } else if (HasDoubleValue()) {
2343 r = Representation::Double();
2344 } else if (HasExternalReferenceValue()) {
2345 r = Representation::External();
2346 } else {
2347 Handle<Object> object = object_.handle();
2348 if (object->IsJSObject()) {
2349 // Try to eagerly migrate JSObjects that have deprecated maps.
2350 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
2351 if (js_object->map()->is_deprecated()) {
2352 JSObject::TryMigrateInstance(js_object);
2353 }
2354 }
2355 r = Representation::Tagged();
2356 }
2357 }
2358 if (r.IsSmi()) {
2359 // If we have an existing handle, zap it, because it might be a heap
2360 // number which we must not re-use when copying this HConstant to
2361 // Tagged representation later, because having Smi representation now
2362 // could cause heap object checks not to get emitted.
2363 object_ = Unique<Object>(Handle<Object>::null());
2364 }
2365 if (r.IsSmiOrInteger32() && object_.handle().is_null()) {
2366 // If it's not a heap object, it can't be in new space.
2367 bit_field_ = IsNotInNewSpaceField::update(bit_field_, true);
2368 }
2369 set_representation(r);
2370 SetFlag(kUseGVN);
2371 }
2372
2373
ImmortalImmovable() const2374 bool HConstant::ImmortalImmovable() const {
2375 if (HasInteger32Value()) {
2376 return false;
2377 }
2378 if (HasDoubleValue()) {
2379 if (IsSpecialDouble()) {
2380 return true;
2381 }
2382 return false;
2383 }
2384 if (HasExternalReferenceValue()) {
2385 return false;
2386 }
2387
2388 DCHECK(!object_.handle().is_null());
2389 Heap* heap = isolate()->heap();
2390 DCHECK(!object_.IsKnownGlobal(heap->minus_zero_value()));
2391 DCHECK(!object_.IsKnownGlobal(heap->nan_value()));
2392 return
2393 #define IMMORTAL_IMMOVABLE_ROOT(name) \
2394 object_.IsKnownGlobal(heap->root(Heap::k##name##RootIndex)) ||
2395 IMMORTAL_IMMOVABLE_ROOT_LIST(IMMORTAL_IMMOVABLE_ROOT)
2396 #undef IMMORTAL_IMMOVABLE_ROOT
2397 #define INTERNALIZED_STRING(name, value) \
2398 object_.IsKnownGlobal(heap->name()) ||
2399 INTERNALIZED_STRING_LIST(INTERNALIZED_STRING)
2400 #undef INTERNALIZED_STRING
2401 #define STRING_TYPE(NAME, size, name, Name) \
2402 object_.IsKnownGlobal(heap->name##_map()) ||
2403 STRING_TYPE_LIST(STRING_TYPE)
2404 #undef STRING_TYPE
2405 false;
2406 }
2407
2408
EmitAtUses()2409 bool HConstant::EmitAtUses() {
2410 DCHECK(IsLinked());
2411 if (block()->graph()->has_osr() &&
2412 block()->graph()->IsStandardConstant(this)) {
2413 return true;
2414 }
2415 if (HasNoUses()) return true;
2416 if (IsCell()) return false;
2417 if (representation().IsDouble()) return false;
2418 if (representation().IsExternal()) return false;
2419 return true;
2420 }
2421
2422
CopyToRepresentation(Representation r,Zone * zone) const2423 HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const {
2424 if (r.IsSmi() && !HasSmiValue()) return NULL;
2425 if (r.IsInteger32() && !HasInteger32Value()) return NULL;
2426 if (r.IsDouble() && !HasDoubleValue()) return NULL;
2427 if (r.IsExternal() && !HasExternalReferenceValue()) return NULL;
2428 if (HasInteger32Value()) {
2429 return new (zone) HConstant(int32_value_, r, NotInNewSpace(), object_);
2430 }
2431 if (HasDoubleValue()) {
2432 return new (zone) HConstant(double_value_, r, NotInNewSpace(), object_);
2433 }
2434 if (HasExternalReferenceValue()) {
2435 return new(zone) HConstant(external_reference_value_);
2436 }
2437 DCHECK(!object_.handle().is_null());
2438 return new (zone) HConstant(object_, object_map_, HasStableMapValue(), r,
2439 type_, NotInNewSpace(), BooleanValue(),
2440 IsUndetectable(), GetInstanceType());
2441 }
2442
2443
CopyToTruncatedInt32(Zone * zone)2444 Maybe<HConstant*> HConstant::CopyToTruncatedInt32(Zone* zone) {
2445 HConstant* res = NULL;
2446 if (HasInteger32Value()) {
2447 res = new (zone) HConstant(int32_value_, Representation::Integer32(),
2448 NotInNewSpace(), object_);
2449 } else if (HasDoubleValue()) {
2450 res = new (zone)
2451 HConstant(DoubleToInt32(double_value_), Representation::Integer32(),
2452 NotInNewSpace(), object_);
2453 }
2454 return res != NULL ? Just(res) : Nothing<HConstant*>();
2455 }
2456
2457
CopyToTruncatedNumber(Isolate * isolate,Zone * zone)2458 Maybe<HConstant*> HConstant::CopyToTruncatedNumber(Isolate* isolate,
2459 Zone* zone) {
2460 HConstant* res = NULL;
2461 Handle<Object> handle = this->handle(isolate);
2462 if (handle->IsBoolean()) {
2463 res = handle->BooleanValue() ?
2464 new(zone) HConstant(1) : new(zone) HConstant(0);
2465 } else if (handle->IsUndefined(isolate)) {
2466 res = new (zone) HConstant(std::numeric_limits<double>::quiet_NaN());
2467 } else if (handle->IsNull(isolate)) {
2468 res = new(zone) HConstant(0);
2469 } else if (handle->IsString()) {
2470 res = new(zone) HConstant(String::ToNumber(Handle<String>::cast(handle)));
2471 }
2472 return res != NULL ? Just(res) : Nothing<HConstant*>();
2473 }
2474
2475
PrintDataTo(std::ostream & os) const2476 std::ostream& HConstant::PrintDataTo(std::ostream& os) const { // NOLINT
2477 if (HasInteger32Value()) {
2478 os << int32_value_ << " ";
2479 } else if (HasDoubleValue()) {
2480 os << double_value_ << " ";
2481 } else if (HasExternalReferenceValue()) {
2482 os << reinterpret_cast<void*>(external_reference_value_.address()) << " ";
2483 } else {
2484 // The handle() method is silently and lazily mutating the object.
2485 Handle<Object> h = const_cast<HConstant*>(this)->handle(isolate());
2486 os << Brief(*h) << " ";
2487 if (HasStableMapValue()) os << "[stable-map] ";
2488 if (HasObjectMap()) os << "[map " << *ObjectMap().handle() << "] ";
2489 }
2490 if (!NotInNewSpace()) os << "[new space] ";
2491 return os;
2492 }
2493
2494
PrintDataTo(std::ostream & os) const2495 std::ostream& HBinaryOperation::PrintDataTo(std::ostream& os) const { // NOLINT
2496 os << NameOf(left()) << " " << NameOf(right());
2497 if (CheckFlag(kCanOverflow)) os << " !";
2498 if (CheckFlag(kBailoutOnMinusZero)) os << " -0?";
2499 return os;
2500 }
2501
2502
InferRepresentation(HInferRepresentationPhase * h_infer)2503 void HBinaryOperation::InferRepresentation(HInferRepresentationPhase* h_infer) {
2504 DCHECK(CheckFlag(kFlexibleRepresentation));
2505 Representation new_rep = RepresentationFromInputs();
2506 UpdateRepresentation(new_rep, h_infer, "inputs");
2507
2508 if (representation().IsSmi() && HasNonSmiUse()) {
2509 UpdateRepresentation(
2510 Representation::Integer32(), h_infer, "use requirements");
2511 }
2512
2513 if (observed_output_representation_.IsNone()) {
2514 new_rep = RepresentationFromUses();
2515 UpdateRepresentation(new_rep, h_infer, "uses");
2516 } else {
2517 new_rep = RepresentationFromOutput();
2518 UpdateRepresentation(new_rep, h_infer, "output");
2519 }
2520 }
2521
2522
RepresentationFromInputs()2523 Representation HBinaryOperation::RepresentationFromInputs() {
2524 // Determine the worst case of observed input representations and
2525 // the currently assumed output representation.
2526 Representation rep = representation();
2527 for (int i = 1; i <= 2; ++i) {
2528 rep = rep.generalize(observed_input_representation(i));
2529 }
2530 // If any of the actual input representation is more general than what we
2531 // have so far but not Tagged, use that representation instead.
2532 Representation left_rep = left()->representation();
2533 Representation right_rep = right()->representation();
2534 if (!left_rep.IsTagged()) rep = rep.generalize(left_rep);
2535 if (!right_rep.IsTagged()) rep = rep.generalize(right_rep);
2536
2537 return rep;
2538 }
2539
2540
IgnoreObservedOutputRepresentation(Representation current_rep)2541 bool HBinaryOperation::IgnoreObservedOutputRepresentation(
2542 Representation current_rep) {
2543 return ((current_rep.IsInteger32() && CheckUsesForFlag(kTruncatingToInt32)) ||
2544 (current_rep.IsSmi() && CheckUsesForFlag(kTruncatingToSmi))) &&
2545 // Mul in Integer32 mode would be too precise.
2546 (!this->IsMul() || HMul::cast(this)->MulMinusOne());
2547 }
2548
2549
RepresentationFromOutput()2550 Representation HBinaryOperation::RepresentationFromOutput() {
2551 Representation rep = representation();
2552 // Consider observed output representation, but ignore it if it's Double,
2553 // this instruction is not a division, and all its uses are truncating
2554 // to Integer32.
2555 if (observed_output_representation_.is_more_general_than(rep) &&
2556 !IgnoreObservedOutputRepresentation(rep)) {
2557 return observed_output_representation_;
2558 }
2559 return Representation::None();
2560 }
2561
2562
AssumeRepresentation(Representation r)2563 void HBinaryOperation::AssumeRepresentation(Representation r) {
2564 set_observed_input_representation(1, r);
2565 set_observed_input_representation(2, r);
2566 HValue::AssumeRepresentation(r);
2567 }
2568
2569
InferRepresentation(HInferRepresentationPhase * h_infer)2570 void HMathMinMax::InferRepresentation(HInferRepresentationPhase* h_infer) {
2571 DCHECK(CheckFlag(kFlexibleRepresentation));
2572 Representation new_rep = RepresentationFromInputs();
2573 UpdateRepresentation(new_rep, h_infer, "inputs");
2574 // Do not care about uses.
2575 }
2576
2577
InferRange(Zone * zone)2578 Range* HBitwise::InferRange(Zone* zone) {
2579 if (op() == Token::BIT_XOR) {
2580 if (left()->HasRange() && right()->HasRange()) {
2581 // The maximum value has the high bit, and all bits below, set:
2582 // (1 << high) - 1.
2583 // If the range can be negative, the minimum int is a negative number with
2584 // the high bit, and all bits below, unset:
2585 // -(1 << high).
2586 // If it cannot be negative, conservatively choose 0 as minimum int.
2587 int64_t left_upper = left()->range()->upper();
2588 int64_t left_lower = left()->range()->lower();
2589 int64_t right_upper = right()->range()->upper();
2590 int64_t right_lower = right()->range()->lower();
2591
2592 if (left_upper < 0) left_upper = ~left_upper;
2593 if (left_lower < 0) left_lower = ~left_lower;
2594 if (right_upper < 0) right_upper = ~right_upper;
2595 if (right_lower < 0) right_lower = ~right_lower;
2596
2597 int high = MostSignificantBit(
2598 static_cast<uint32_t>(
2599 left_upper | left_lower | right_upper | right_lower));
2600
2601 int64_t limit = 1;
2602 limit <<= high;
2603 int32_t min = (left()->range()->CanBeNegative() ||
2604 right()->range()->CanBeNegative())
2605 ? static_cast<int32_t>(-limit) : 0;
2606 return new(zone) Range(min, static_cast<int32_t>(limit - 1));
2607 }
2608 Range* result = HValue::InferRange(zone);
2609 result->set_can_be_minus_zero(false);
2610 return result;
2611 }
2612 const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff);
2613 int32_t left_mask = (left()->range() != NULL)
2614 ? left()->range()->Mask()
2615 : kDefaultMask;
2616 int32_t right_mask = (right()->range() != NULL)
2617 ? right()->range()->Mask()
2618 : kDefaultMask;
2619 int32_t result_mask = (op() == Token::BIT_AND)
2620 ? left_mask & right_mask
2621 : left_mask | right_mask;
2622 if (result_mask >= 0) return new(zone) Range(0, result_mask);
2623
2624 Range* result = HValue::InferRange(zone);
2625 result->set_can_be_minus_zero(false);
2626 return result;
2627 }
2628
2629
InferRange(Zone * zone)2630 Range* HSar::InferRange(Zone* zone) {
2631 if (right()->IsConstant()) {
2632 HConstant* c = HConstant::cast(right());
2633 if (c->HasInteger32Value()) {
2634 Range* result = (left()->range() != NULL)
2635 ? left()->range()->Copy(zone)
2636 : new(zone) Range();
2637 result->Sar(c->Integer32Value());
2638 return result;
2639 }
2640 }
2641 return HValue::InferRange(zone);
2642 }
2643
2644
InferRange(Zone * zone)2645 Range* HShr::InferRange(Zone* zone) {
2646 if (right()->IsConstant()) {
2647 HConstant* c = HConstant::cast(right());
2648 if (c->HasInteger32Value()) {
2649 int shift_count = c->Integer32Value() & 0x1f;
2650 if (left()->range()->CanBeNegative()) {
2651 // Only compute bounds if the result always fits into an int32.
2652 return (shift_count >= 1)
2653 ? new(zone) Range(0,
2654 static_cast<uint32_t>(0xffffffff) >> shift_count)
2655 : new(zone) Range();
2656 } else {
2657 // For positive inputs we can use the >> operator.
2658 Range* result = (left()->range() != NULL)
2659 ? left()->range()->Copy(zone)
2660 : new(zone) Range();
2661 result->Sar(c->Integer32Value());
2662 return result;
2663 }
2664 }
2665 }
2666 return HValue::InferRange(zone);
2667 }
2668
2669
InferRange(Zone * zone)2670 Range* HShl::InferRange(Zone* zone) {
2671 if (right()->IsConstant()) {
2672 HConstant* c = HConstant::cast(right());
2673 if (c->HasInteger32Value()) {
2674 Range* result = (left()->range() != NULL)
2675 ? left()->range()->Copy(zone)
2676 : new(zone) Range();
2677 result->Shl(c->Integer32Value());
2678 return result;
2679 }
2680 }
2681 return HValue::InferRange(zone);
2682 }
2683
2684
InferRange(Zone * zone)2685 Range* HLoadNamedField::InferRange(Zone* zone) {
2686 if (access().representation().IsInteger8()) {
2687 return new(zone) Range(kMinInt8, kMaxInt8);
2688 }
2689 if (access().representation().IsUInteger8()) {
2690 return new(zone) Range(kMinUInt8, kMaxUInt8);
2691 }
2692 if (access().representation().IsInteger16()) {
2693 return new(zone) Range(kMinInt16, kMaxInt16);
2694 }
2695 if (access().representation().IsUInteger16()) {
2696 return new(zone) Range(kMinUInt16, kMaxUInt16);
2697 }
2698 if (access().IsStringLength()) {
2699 return new(zone) Range(0, String::kMaxLength);
2700 }
2701 return HValue::InferRange(zone);
2702 }
2703
2704
InferRange(Zone * zone)2705 Range* HLoadKeyed::InferRange(Zone* zone) {
2706 switch (elements_kind()) {
2707 case INT8_ELEMENTS:
2708 return new(zone) Range(kMinInt8, kMaxInt8);
2709 case UINT8_ELEMENTS:
2710 case UINT8_CLAMPED_ELEMENTS:
2711 return new(zone) Range(kMinUInt8, kMaxUInt8);
2712 case INT16_ELEMENTS:
2713 return new(zone) Range(kMinInt16, kMaxInt16);
2714 case UINT16_ELEMENTS:
2715 return new(zone) Range(kMinUInt16, kMaxUInt16);
2716 default:
2717 return HValue::InferRange(zone);
2718 }
2719 }
2720
2721
PrintDataTo(std::ostream & os) const2722 std::ostream& HCompareGeneric::PrintDataTo(std::ostream& os) const { // NOLINT
2723 os << Token::Name(token()) << " ";
2724 return HBinaryOperation::PrintDataTo(os);
2725 }
2726
2727
PrintDataTo(std::ostream & os) const2728 std::ostream& HStringCompareAndBranch::PrintDataTo(
2729 std::ostream& os) const { // NOLINT
2730 os << Token::Name(token()) << " ";
2731 return HControlInstruction::PrintDataTo(os);
2732 }
2733
2734
PrintDataTo(std::ostream & os) const2735 std::ostream& HCompareNumericAndBranch::PrintDataTo(
2736 std::ostream& os) const { // NOLINT
2737 os << Token::Name(token()) << " " << NameOf(left()) << " " << NameOf(right());
2738 return HControlInstruction::PrintDataTo(os);
2739 }
2740
2741
PrintDataTo(std::ostream & os) const2742 std::ostream& HCompareObjectEqAndBranch::PrintDataTo(
2743 std::ostream& os) const { // NOLINT
2744 os << NameOf(left()) << " " << NameOf(right());
2745 return HControlInstruction::PrintDataTo(os);
2746 }
2747
2748
KnownSuccessorBlock(HBasicBlock ** block)2749 bool HCompareObjectEqAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
2750 if (known_successor_index() != kNoKnownSuccessorIndex) {
2751 *block = SuccessorAt(known_successor_index());
2752 return true;
2753 }
2754 if (FLAG_fold_constants && left()->IsConstant() && right()->IsConstant()) {
2755 *block = HConstant::cast(left())->DataEquals(HConstant::cast(right()))
2756 ? FirstSuccessor() : SecondSuccessor();
2757 return true;
2758 }
2759 *block = NULL;
2760 return false;
2761 }
2762
2763
KnownSuccessorBlock(HBasicBlock ** block)2764 bool HIsStringAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
2765 if (known_successor_index() != kNoKnownSuccessorIndex) {
2766 *block = SuccessorAt(known_successor_index());
2767 return true;
2768 }
2769 if (FLAG_fold_constants && value()->IsConstant()) {
2770 *block = HConstant::cast(value())->HasStringValue()
2771 ? FirstSuccessor() : SecondSuccessor();
2772 return true;
2773 }
2774 if (value()->type().IsString()) {
2775 *block = FirstSuccessor();
2776 return true;
2777 }
2778 if (value()->type().IsSmi() ||
2779 value()->type().IsNull() ||
2780 value()->type().IsBoolean() ||
2781 value()->type().IsUndefined() ||
2782 value()->type().IsJSReceiver()) {
2783 *block = SecondSuccessor();
2784 return true;
2785 }
2786 *block = NULL;
2787 return false;
2788 }
2789
2790
KnownSuccessorBlock(HBasicBlock ** block)2791 bool HIsUndetectableAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
2792 if (FLAG_fold_constants && value()->IsConstant()) {
2793 *block = HConstant::cast(value())->IsUndetectable()
2794 ? FirstSuccessor() : SecondSuccessor();
2795 return true;
2796 }
2797 if (value()->type().IsNull() || value()->type().IsUndefined()) {
2798 *block = FirstSuccessor();
2799 return true;
2800 }
2801 if (value()->type().IsBoolean() ||
2802 value()->type().IsSmi() ||
2803 value()->type().IsString() ||
2804 value()->type().IsJSReceiver()) {
2805 *block = SecondSuccessor();
2806 return true;
2807 }
2808 *block = NULL;
2809 return false;
2810 }
2811
2812
KnownSuccessorBlock(HBasicBlock ** block)2813 bool HHasInstanceTypeAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
2814 if (FLAG_fold_constants && value()->IsConstant()) {
2815 InstanceType type = HConstant::cast(value())->GetInstanceType();
2816 *block = (from_ <= type) && (type <= to_)
2817 ? FirstSuccessor() : SecondSuccessor();
2818 return true;
2819 }
2820 *block = NULL;
2821 return false;
2822 }
2823
2824
InferRepresentation(HInferRepresentationPhase * h_infer)2825 void HCompareHoleAndBranch::InferRepresentation(
2826 HInferRepresentationPhase* h_infer) {
2827 ChangeRepresentation(value()->representation());
2828 }
2829
2830
KnownSuccessorBlock(HBasicBlock ** block)2831 bool HCompareNumericAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
2832 if (left() == right() &&
2833 left()->representation().IsSmiOrInteger32()) {
2834 *block = (token() == Token::EQ ||
2835 token() == Token::EQ_STRICT ||
2836 token() == Token::LTE ||
2837 token() == Token::GTE)
2838 ? FirstSuccessor() : SecondSuccessor();
2839 return true;
2840 }
2841 *block = NULL;
2842 return false;
2843 }
2844
2845
PrintDataTo(std::ostream & os) const2846 std::ostream& HGoto::PrintDataTo(std::ostream& os) const { // NOLINT
2847 return os << *SuccessorAt(0);
2848 }
2849
2850
InferRepresentation(HInferRepresentationPhase * h_infer)2851 void HCompareNumericAndBranch::InferRepresentation(
2852 HInferRepresentationPhase* h_infer) {
2853 Representation left_rep = left()->representation();
2854 Representation right_rep = right()->representation();
2855 Representation observed_left = observed_input_representation(0);
2856 Representation observed_right = observed_input_representation(1);
2857
2858 Representation rep = Representation::None();
2859 rep = rep.generalize(observed_left);
2860 rep = rep.generalize(observed_right);
2861 if (rep.IsNone() || rep.IsSmiOrInteger32()) {
2862 if (!left_rep.IsTagged()) rep = rep.generalize(left_rep);
2863 if (!right_rep.IsTagged()) rep = rep.generalize(right_rep);
2864 } else {
2865 rep = Representation::Double();
2866 }
2867
2868 if (rep.IsDouble()) {
2869 // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, ===
2870 // and !=) have special handling of undefined, e.g. undefined == undefined
2871 // is 'true'. Relational comparisons have a different semantic, first
2872 // calling ToPrimitive() on their arguments. The standard Crankshaft
2873 // tagged-to-double conversion to ensure the HCompareNumericAndBranch's
2874 // inputs are doubles caused 'undefined' to be converted to NaN. That's
2875 // compatible out-of-the box with ordered relational comparisons (<, >, <=,
2876 // >=). However, for equality comparisons (and for 'in' and 'instanceof'),
2877 // it is not consistent with the spec. For example, it would cause undefined
2878 // == undefined (should be true) to be evaluated as NaN == NaN
2879 // (false). Therefore, any comparisons other than ordered relational
2880 // comparisons must cause a deopt when one of their arguments is undefined.
2881 // See also v8:1434
2882 if (Token::IsOrderedRelationalCompareOp(token_)) {
2883 SetFlag(kTruncatingToNumber);
2884 }
2885 }
2886 ChangeRepresentation(rep);
2887 }
2888
2889
PrintDataTo(std::ostream & os) const2890 std::ostream& HParameter::PrintDataTo(std::ostream& os) const { // NOLINT
2891 return os << index();
2892 }
2893
2894
PrintDataTo(std::ostream & os) const2895 std::ostream& HLoadNamedField::PrintDataTo(std::ostream& os) const { // NOLINT
2896 os << NameOf(object()) << access_;
2897
2898 if (maps() != NULL) {
2899 os << " [" << *maps()->at(0).handle();
2900 for (int i = 1; i < maps()->size(); ++i) {
2901 os << "," << *maps()->at(i).handle();
2902 }
2903 os << "]";
2904 }
2905
2906 if (HasDependency()) os << " " << NameOf(dependency());
2907 return os;
2908 }
2909
2910
PrintDataTo(std::ostream & os) const2911 std::ostream& HLoadKeyed::PrintDataTo(std::ostream& os) const { // NOLINT
2912 if (!is_fixed_typed_array()) {
2913 os << NameOf(elements());
2914 } else {
2915 DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND &&
2916 elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
2917 os << NameOf(elements()) << "." << ElementsKindToString(elements_kind());
2918 }
2919
2920 os << "[" << NameOf(key());
2921 if (IsDehoisted()) os << " + " << base_offset();
2922 os << "]";
2923
2924 if (HasDependency()) os << " " << NameOf(dependency());
2925 if (RequiresHoleCheck()) os << " check_hole";
2926 return os;
2927 }
2928
2929
TryIncreaseBaseOffset(uint32_t increase_by_value)2930 bool HLoadKeyed::TryIncreaseBaseOffset(uint32_t increase_by_value) {
2931 // The base offset is usually simply the size of the array header, except
2932 // with dehoisting adds an addition offset due to a array index key
2933 // manipulation, in which case it becomes (array header size +
2934 // constant-offset-from-key * kPointerSize)
2935 uint32_t base_offset = BaseOffsetField::decode(bit_field_);
2936 v8::base::internal::CheckedNumeric<uint32_t> addition_result = base_offset;
2937 addition_result += increase_by_value;
2938 if (!addition_result.IsValid()) return false;
2939 base_offset = addition_result.ValueOrDie();
2940 if (!BaseOffsetField::is_valid(base_offset)) return false;
2941 bit_field_ = BaseOffsetField::update(bit_field_, base_offset);
2942 return true;
2943 }
2944
2945
UsesMustHandleHole() const2946 bool HLoadKeyed::UsesMustHandleHole() const {
2947 if (IsFastPackedElementsKind(elements_kind())) {
2948 return false;
2949 }
2950
2951 if (IsFixedTypedArrayElementsKind(elements_kind())) {
2952 return false;
2953 }
2954
2955 if (hole_mode() == ALLOW_RETURN_HOLE) {
2956 if (IsFastDoubleElementsKind(elements_kind())) {
2957 return AllUsesCanTreatHoleAsNaN();
2958 }
2959 return true;
2960 }
2961
2962 if (IsFastDoubleElementsKind(elements_kind())) {
2963 return false;
2964 }
2965
2966 // Holes are only returned as tagged values.
2967 if (!representation().IsTagged()) {
2968 return false;
2969 }
2970
2971 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
2972 HValue* use = it.value();
2973 if (!use->IsChange()) return false;
2974 }
2975
2976 return true;
2977 }
2978
2979
AllUsesCanTreatHoleAsNaN() const2980 bool HLoadKeyed::AllUsesCanTreatHoleAsNaN() const {
2981 return IsFastDoubleElementsKind(elements_kind()) &&
2982 CheckUsesForFlag(HValue::kTruncatingToNumber);
2983 }
2984
2985
RequiresHoleCheck() const2986 bool HLoadKeyed::RequiresHoleCheck() const {
2987 if (IsFastPackedElementsKind(elements_kind())) {
2988 return false;
2989 }
2990
2991 if (IsFixedTypedArrayElementsKind(elements_kind())) {
2992 return false;
2993 }
2994
2995 if (hole_mode() == CONVERT_HOLE_TO_UNDEFINED) {
2996 return false;
2997 }
2998
2999 return !UsesMustHandleHole();
3000 }
3001
Canonicalize()3002 HValue* HCallWithDescriptor::Canonicalize() {
3003 if (kind() != Code::KEYED_LOAD_IC) return this;
3004
3005 // Recognize generic keyed loads that use property name generated
3006 // by for-in statement as a key and rewrite them into fast property load
3007 // by index.
3008 typedef LoadWithVectorDescriptor Descriptor;
3009 HValue* key = parameter(Descriptor::kName);
3010 if (key->IsLoadKeyed()) {
3011 HLoadKeyed* key_load = HLoadKeyed::cast(key);
3012 if (key_load->elements()->IsForInCacheArray()) {
3013 HForInCacheArray* names_cache =
3014 HForInCacheArray::cast(key_load->elements());
3015
3016 HValue* object = parameter(Descriptor::kReceiver);
3017 if (names_cache->enumerable() == object) {
3018 HForInCacheArray* index_cache =
3019 names_cache->index_cache();
3020 HCheckMapValue* map_check = HCheckMapValue::New(
3021 block()->graph()->isolate(), block()->graph()->zone(),
3022 block()->graph()->GetInvalidContext(), object, names_cache->map());
3023 HInstruction* index = HLoadKeyed::New(
3024 block()->graph()->isolate(), block()->graph()->zone(),
3025 block()->graph()->GetInvalidContext(), index_cache, key_load->key(),
3026 key_load->key(), nullptr, key_load->elements_kind());
3027 map_check->InsertBefore(this);
3028 index->InsertBefore(this);
3029 return Prepend(new (block()->zone()) HLoadFieldByIndex(object, index));
3030 }
3031 }
3032 }
3033 return this;
3034 }
3035
PrintDataTo(std::ostream & os) const3036 std::ostream& HStoreNamedField::PrintDataTo(std::ostream& os) const { // NOLINT
3037 os << NameOf(object()) << access_ << " = " << NameOf(value());
3038 if (NeedsWriteBarrier()) os << " (write-barrier)";
3039 if (has_transition()) os << " (transition map " << *transition_map() << ")";
3040 return os;
3041 }
3042
3043
PrintDataTo(std::ostream & os) const3044 std::ostream& HStoreKeyed::PrintDataTo(std::ostream& os) const { // NOLINT
3045 if (!is_fixed_typed_array()) {
3046 os << NameOf(elements());
3047 } else {
3048 DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND &&
3049 elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
3050 os << NameOf(elements()) << "." << ElementsKindToString(elements_kind());
3051 }
3052
3053 os << "[" << NameOf(key());
3054 if (IsDehoisted()) os << " + " << base_offset();
3055 return os << "] = " << NameOf(value());
3056 }
3057
3058
PrintDataTo(std::ostream & os) const3059 std::ostream& HTransitionElementsKind::PrintDataTo(
3060 std::ostream& os) const { // NOLINT
3061 os << NameOf(object());
3062 ElementsKind from_kind = original_map().handle()->elements_kind();
3063 ElementsKind to_kind = transitioned_map().handle()->elements_kind();
3064 os << " " << *original_map().handle() << " ["
3065 << ElementsAccessor::ForKind(from_kind)->name() << "] -> "
3066 << *transitioned_map().handle() << " ["
3067 << ElementsAccessor::ForKind(to_kind)->name() << "]";
3068 if (IsSimpleMapChangeTransition(from_kind, to_kind)) os << " (simple)";
3069 return os;
3070 }
3071
3072
PrintDataTo(std::ostream & os) const3073 std::ostream& HInnerAllocatedObject::PrintDataTo(
3074 std::ostream& os) const { // NOLINT
3075 os << NameOf(base_object()) << " offset ";
3076 return offset()->PrintTo(os);
3077 }
3078
3079
PrintDataTo(std::ostream & os) const3080 std::ostream& HLoadContextSlot::PrintDataTo(std::ostream& os) const { // NOLINT
3081 return os << NameOf(value()) << "[" << slot_index() << "]";
3082 }
3083
3084
PrintDataTo(std::ostream & os) const3085 std::ostream& HStoreContextSlot::PrintDataTo(
3086 std::ostream& os) const { // NOLINT
3087 return os << NameOf(context()) << "[" << slot_index()
3088 << "] = " << NameOf(value());
3089 }
3090
3091
3092 // Implementation of type inference and type conversions. Calculates
3093 // the inferred type of this instruction based on the input operands.
3094
CalculateInferredType()3095 HType HValue::CalculateInferredType() {
3096 return type_;
3097 }
3098
3099
CalculateInferredType()3100 HType HPhi::CalculateInferredType() {
3101 if (OperandCount() == 0) return HType::Tagged();
3102 HType result = OperandAt(0)->type();
3103 for (int i = 1; i < OperandCount(); ++i) {
3104 HType current = OperandAt(i)->type();
3105 result = result.Combine(current);
3106 }
3107 return result;
3108 }
3109
3110
CalculateInferredType()3111 HType HChange::CalculateInferredType() {
3112 if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber();
3113 return type();
3114 }
3115
3116
RepresentationFromInputs()3117 Representation HUnaryMathOperation::RepresentationFromInputs() {
3118 if (SupportsFlexibleFloorAndRound() &&
3119 (op_ == kMathFloor || op_ == kMathRound)) {
3120 // Floor and Round always take a double input. The integral result can be
3121 // used as an integer or a double. Infer the representation from the uses.
3122 return Representation::None();
3123 }
3124 Representation rep = representation();
3125 // If any of the actual input representation is more general than what we
3126 // have so far but not Tagged, use that representation instead.
3127 Representation input_rep = value()->representation();
3128 if (!input_rep.IsTagged()) {
3129 rep = rep.generalize(input_rep);
3130 }
3131 return rep;
3132 }
3133
3134
HandleSideEffectDominator(GVNFlag side_effect,HValue * dominator)3135 bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
3136 HValue* dominator) {
3137 DCHECK(side_effect == kNewSpacePromotion);
3138 DCHECK(!IsAllocationFolded());
3139 Zone* zone = block()->zone();
3140 Isolate* isolate = block()->isolate();
3141 if (!FLAG_use_allocation_folding) return false;
3142
3143 // Try to fold allocations together with their dominating allocations.
3144 if (!dominator->IsAllocate()) {
3145 if (FLAG_trace_allocation_folding) {
3146 PrintF("#%d (%s) cannot fold into #%d (%s)\n",
3147 id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
3148 }
3149 return false;
3150 }
3151
3152 // Check whether we are folding within the same block for local folding.
3153 if (FLAG_use_local_allocation_folding && dominator->block() != block()) {
3154 if (FLAG_trace_allocation_folding) {
3155 PrintF("#%d (%s) cannot fold into #%d (%s), crosses basic blocks\n",
3156 id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
3157 }
3158 return false;
3159 }
3160
3161 HAllocate* dominator_allocate = HAllocate::cast(dominator);
3162 HValue* dominator_size = dominator_allocate->size();
3163 HValue* current_size = size();
3164
3165 // TODO(hpayer): Add support for non-constant allocation in dominator.
3166 if (!current_size->IsInteger32Constant() ||
3167 !dominator_size->IsInteger32Constant()) {
3168 if (FLAG_trace_allocation_folding) {
3169 PrintF("#%d (%s) cannot fold into #%d (%s), "
3170 "dynamic allocation size in dominator\n",
3171 id(), Mnemonic(), dominator->id(), dominator->Mnemonic());
3172 }
3173 return false;
3174 }
3175
3176 if (IsAllocationFoldingDominator()) {
3177 if (FLAG_trace_allocation_folding) {
3178 PrintF("#%d (%s) cannot fold into #%d (%s), already dominator\n", id(),
3179 Mnemonic(), dominator->id(), dominator->Mnemonic());
3180 }
3181 return false;
3182 }
3183
3184 if (!IsFoldable(dominator_allocate)) {
3185 if (FLAG_trace_allocation_folding) {
3186 PrintF("#%d (%s) cannot fold into #%d (%s), different spaces\n", id(),
3187 Mnemonic(), dominator->id(), dominator->Mnemonic());
3188 }
3189 return false;
3190 }
3191
3192 DCHECK(
3193 (IsNewSpaceAllocation() && dominator_allocate->IsNewSpaceAllocation()) ||
3194 (IsOldSpaceAllocation() && dominator_allocate->IsOldSpaceAllocation()));
3195
3196 // First update the size of the dominator allocate instruction.
3197 dominator_size = dominator_allocate->size();
3198 int32_t original_object_size =
3199 HConstant::cast(dominator_size)->GetInteger32Constant();
3200 int32_t dominator_size_constant = original_object_size;
3201
3202 if (MustAllocateDoubleAligned()) {
3203 if ((dominator_size_constant & kDoubleAlignmentMask) != 0) {
3204 dominator_size_constant += kDoubleSize / 2;
3205 }
3206 }
3207
3208 int32_t current_size_max_value = size()->GetInteger32Constant();
3209 int32_t new_dominator_size = dominator_size_constant + current_size_max_value;
3210
3211 // Since we clear the first word after folded memory, we cannot use the
3212 // whole kMaxRegularHeapObjectSize memory.
3213 if (new_dominator_size > kMaxRegularHeapObjectSize - kPointerSize) {
3214 if (FLAG_trace_allocation_folding) {
3215 PrintF("#%d (%s) cannot fold into #%d (%s) due to size: %d\n",
3216 id(), Mnemonic(), dominator_allocate->id(),
3217 dominator_allocate->Mnemonic(), new_dominator_size);
3218 }
3219 return false;
3220 }
3221
3222 HInstruction* new_dominator_size_value = HConstant::CreateAndInsertBefore(
3223 isolate, zone, context(), new_dominator_size, Representation::None(),
3224 dominator_allocate);
3225
3226 dominator_allocate->UpdateSize(new_dominator_size_value);
3227
3228 if (MustAllocateDoubleAligned()) {
3229 if (!dominator_allocate->MustAllocateDoubleAligned()) {
3230 dominator_allocate->MakeDoubleAligned();
3231 }
3232 }
3233
3234 if (!dominator_allocate->IsAllocationFoldingDominator()) {
3235 HAllocate* first_alloc =
3236 HAllocate::New(isolate, zone, dominator_allocate->context(),
3237 dominator_size, dominator_allocate->type(),
3238 IsNewSpaceAllocation() ? NOT_TENURED : TENURED,
3239 JS_OBJECT_TYPE, block()->graph()->GetConstant0());
3240 first_alloc->InsertAfter(dominator_allocate);
3241 dominator_allocate->ReplaceAllUsesWith(first_alloc);
3242 dominator_allocate->MakeAllocationFoldingDominator();
3243 first_alloc->MakeFoldedAllocation(dominator_allocate);
3244 if (FLAG_trace_allocation_folding) {
3245 PrintF("#%d (%s) inserted for dominator #%d (%s)\n", first_alloc->id(),
3246 first_alloc->Mnemonic(), dominator_allocate->id(),
3247 dominator_allocate->Mnemonic());
3248 }
3249 }
3250
3251 MakeFoldedAllocation(dominator_allocate);
3252
3253 if (FLAG_trace_allocation_folding) {
3254 PrintF("#%d (%s) folded into #%d (%s), new dominator size: %d\n", id(),
3255 Mnemonic(), dominator_allocate->id(), dominator_allocate->Mnemonic(),
3256 new_dominator_size);
3257 }
3258 return true;
3259 }
3260
3261
PrintDataTo(std::ostream & os) const3262 std::ostream& HAllocate::PrintDataTo(std::ostream& os) const { // NOLINT
3263 os << NameOf(size()) << " (";
3264 if (IsNewSpaceAllocation()) os << "N";
3265 if (IsOldSpaceAllocation()) os << "P";
3266 if (MustAllocateDoubleAligned()) os << "A";
3267 if (MustPrefillWithFiller()) os << "F";
3268 if (IsAllocationFoldingDominator()) os << "d";
3269 if (IsAllocationFolded()) os << "f";
3270 return os << ")";
3271 }
3272
3273
TryIncreaseBaseOffset(uint32_t increase_by_value)3274 bool HStoreKeyed::TryIncreaseBaseOffset(uint32_t increase_by_value) {
3275 // The base offset is usually simply the size of the array header, except
3276 // with dehoisting adds an addition offset due to a array index key
3277 // manipulation, in which case it becomes (array header size +
3278 // constant-offset-from-key * kPointerSize)
3279 v8::base::internal::CheckedNumeric<uint32_t> addition_result = base_offset_;
3280 addition_result += increase_by_value;
3281 if (!addition_result.IsValid()) return false;
3282 base_offset_ = addition_result.ValueOrDie();
3283 return true;
3284 }
3285
3286
NeedsCanonicalization()3287 bool HStoreKeyed::NeedsCanonicalization() {
3288 switch (value()->opcode()) {
3289 case kLoadKeyed: {
3290 ElementsKind load_kind = HLoadKeyed::cast(value())->elements_kind();
3291 return IsFixedFloatElementsKind(load_kind);
3292 }
3293 case kChange: {
3294 Representation from = HChange::cast(value())->from();
3295 return from.IsTagged() || from.IsHeapObject();
3296 }
3297 case kConstant:
3298 // Double constants are canonicalized upon construction.
3299 return false;
3300 default:
3301 return !value()->IsBinaryOperation();
3302 }
3303 }
3304
3305
3306 #define H_CONSTANT_INT(val) \
3307 HConstant::New(isolate, zone, context, static_cast<int32_t>(val))
3308 #define H_CONSTANT_DOUBLE(val) \
3309 HConstant::New(isolate, zone, context, static_cast<double>(val))
3310
3311 #define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op) \
3312 HInstruction* HInstr::New(Isolate* isolate, Zone* zone, HValue* context, \
3313 HValue* left, HValue* right) { \
3314 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \
3315 HConstant* c_left = HConstant::cast(left); \
3316 HConstant* c_right = HConstant::cast(right); \
3317 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
3318 double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \
3319 if (IsInt32Double(double_res)) { \
3320 return H_CONSTANT_INT(double_res); \
3321 } \
3322 return H_CONSTANT_DOUBLE(double_res); \
3323 } \
3324 } \
3325 return new (zone) HInstr(context, left, right); \
3326 }
3327
3328 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HAdd, +)
3329 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HMul, *)
3330 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HSub, -)
3331
3332 #undef DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR
3333
3334
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right,PretenureFlag pretenure_flag,StringAddFlags flags,Handle<AllocationSite> allocation_site)3335 HInstruction* HStringAdd::New(Isolate* isolate, Zone* zone, HValue* context,
3336 HValue* left, HValue* right,
3337 PretenureFlag pretenure_flag,
3338 StringAddFlags flags,
3339 Handle<AllocationSite> allocation_site) {
3340 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
3341 HConstant* c_right = HConstant::cast(right);
3342 HConstant* c_left = HConstant::cast(left);
3343 if (c_left->HasStringValue() && c_right->HasStringValue()) {
3344 Handle<String> left_string = c_left->StringValue();
3345 Handle<String> right_string = c_right->StringValue();
3346 // Prevent possible exception by invalid string length.
3347 if (left_string->length() + right_string->length() < String::kMaxLength) {
3348 MaybeHandle<String> concat = isolate->factory()->NewConsString(
3349 c_left->StringValue(), c_right->StringValue());
3350 return HConstant::New(isolate, zone, context, concat.ToHandleChecked());
3351 }
3352 }
3353 }
3354 return new (zone)
3355 HStringAdd(context, left, right, pretenure_flag, flags, allocation_site);
3356 }
3357
3358
PrintDataTo(std::ostream & os) const3359 std::ostream& HStringAdd::PrintDataTo(std::ostream& os) const { // NOLINT
3360 if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
3361 os << "_CheckBoth";
3362 } else if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_LEFT) {
3363 os << "_CheckLeft";
3364 } else if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_RIGHT) {
3365 os << "_CheckRight";
3366 }
3367 HBinaryOperation::PrintDataTo(os);
3368 os << " (";
3369 if (pretenure_flag() == NOT_TENURED)
3370 os << "N";
3371 else if (pretenure_flag() == TENURED)
3372 os << "D";
3373 return os << ")";
3374 }
3375
3376
New(Isolate * isolate,Zone * zone,HValue * context,HValue * char_code)3377 HInstruction* HStringCharFromCode::New(Isolate* isolate, Zone* zone,
3378 HValue* context, HValue* char_code) {
3379 if (FLAG_fold_constants && char_code->IsConstant()) {
3380 HConstant* c_code = HConstant::cast(char_code);
3381 if (c_code->HasNumberValue()) {
3382 if (std::isfinite(c_code->DoubleValue())) {
3383 uint32_t code = c_code->NumberValueAsInteger32() & 0xffff;
3384 return HConstant::New(
3385 isolate, zone, context,
3386 isolate->factory()->LookupSingleCharacterStringFromCode(code));
3387 }
3388 return HConstant::New(isolate, zone, context,
3389 isolate->factory()->empty_string());
3390 }
3391 }
3392 return new(zone) HStringCharFromCode(context, char_code);
3393 }
3394
3395
New(Isolate * isolate,Zone * zone,HValue * context,HValue * value,BuiltinFunctionId op)3396 HInstruction* HUnaryMathOperation::New(Isolate* isolate, Zone* zone,
3397 HValue* context, HValue* value,
3398 BuiltinFunctionId op) {
3399 do {
3400 if (!FLAG_fold_constants) break;
3401 if (!value->IsConstant()) break;
3402 HConstant* constant = HConstant::cast(value);
3403 if (!constant->HasNumberValue()) break;
3404 double d = constant->DoubleValue();
3405 if (std::isnan(d)) { // NaN poisons everything.
3406 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN());
3407 }
3408 if (std::isinf(d)) { // +Infinity and -Infinity.
3409 switch (op) {
3410 case kMathCos:
3411 case kMathSin:
3412 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN());
3413 case kMathExp:
3414 return H_CONSTANT_DOUBLE((d > 0.0) ? d : 0.0);
3415 case kMathLog:
3416 case kMathSqrt:
3417 return H_CONSTANT_DOUBLE(
3418 (d > 0.0) ? d : std::numeric_limits<double>::quiet_NaN());
3419 case kMathPowHalf:
3420 case kMathAbs:
3421 return H_CONSTANT_DOUBLE((d > 0.0) ? d : -d);
3422 case kMathRound:
3423 case kMathFround:
3424 case kMathFloor:
3425 return H_CONSTANT_DOUBLE(d);
3426 case kMathClz32:
3427 return H_CONSTANT_INT(32);
3428 default:
3429 UNREACHABLE();
3430 break;
3431 }
3432 }
3433 switch (op) {
3434 case kMathCos:
3435 return H_CONSTANT_DOUBLE(base::ieee754::cos(d));
3436 case kMathExp:
3437 return H_CONSTANT_DOUBLE(base::ieee754::exp(d));
3438 case kMathLog:
3439 return H_CONSTANT_DOUBLE(base::ieee754::log(d));
3440 case kMathSin:
3441 return H_CONSTANT_DOUBLE(base::ieee754::sin(d));
3442 case kMathSqrt:
3443 lazily_initialize_fast_sqrt(isolate);
3444 return H_CONSTANT_DOUBLE(fast_sqrt(d, isolate));
3445 case kMathPowHalf:
3446 return H_CONSTANT_DOUBLE(power_double_double(d, 0.5));
3447 case kMathAbs:
3448 return H_CONSTANT_DOUBLE((d >= 0.0) ? d + 0.0 : -d);
3449 case kMathRound:
3450 // -0.5 .. -0.0 round to -0.0.
3451 if ((d >= -0.5 && Double(d).Sign() < 0)) return H_CONSTANT_DOUBLE(-0.0);
3452 // Doubles are represented as Significant * 2 ^ Exponent. If the
3453 // Exponent is not negative, the double value is already an integer.
3454 if (Double(d).Exponent() >= 0) return H_CONSTANT_DOUBLE(d);
3455 return H_CONSTANT_DOUBLE(Floor(d + 0.5));
3456 case kMathFround:
3457 return H_CONSTANT_DOUBLE(static_cast<double>(static_cast<float>(d)));
3458 case kMathFloor:
3459 return H_CONSTANT_DOUBLE(Floor(d));
3460 case kMathClz32: {
3461 uint32_t i = DoubleToUint32(d);
3462 return H_CONSTANT_INT(base::bits::CountLeadingZeros32(i));
3463 }
3464 default:
3465 UNREACHABLE();
3466 break;
3467 }
3468 } while (false);
3469 return new(zone) HUnaryMathOperation(context, value, op);
3470 }
3471
3472
RepresentationFromUses()3473 Representation HUnaryMathOperation::RepresentationFromUses() {
3474 if (op_ != kMathFloor && op_ != kMathRound) {
3475 return HValue::RepresentationFromUses();
3476 }
3477
3478 // The instruction can have an int32 or double output. Prefer a double
3479 // representation if there are double uses.
3480 bool use_double = false;
3481
3482 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
3483 HValue* use = it.value();
3484 int use_index = it.index();
3485 Representation rep_observed = use->observed_input_representation(use_index);
3486 Representation rep_required = use->RequiredInputRepresentation(use_index);
3487 use_double |= (rep_observed.IsDouble() || rep_required.IsDouble());
3488 if (use_double && !FLAG_trace_representation) {
3489 // Having seen one double is enough.
3490 break;
3491 }
3492 if (FLAG_trace_representation) {
3493 if (!rep_required.IsDouble() || rep_observed.IsDouble()) {
3494 PrintF("#%d %s is used by #%d %s as %s%s\n",
3495 id(), Mnemonic(), use->id(),
3496 use->Mnemonic(), rep_observed.Mnemonic(),
3497 (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : ""));
3498 } else {
3499 PrintF("#%d %s is required by #%d %s as %s%s\n",
3500 id(), Mnemonic(), use->id(),
3501 use->Mnemonic(), rep_required.Mnemonic(),
3502 (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : ""));
3503 }
3504 }
3505 }
3506 return use_double ? Representation::Double() : Representation::Integer32();
3507 }
3508
3509
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right)3510 HInstruction* HPower::New(Isolate* isolate, Zone* zone, HValue* context,
3511 HValue* left, HValue* right) {
3512 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
3513 HConstant* c_left = HConstant::cast(left);
3514 HConstant* c_right = HConstant::cast(right);
3515 if (c_left->HasNumberValue() && c_right->HasNumberValue()) {
3516 double result =
3517 power_helper(isolate, c_left->DoubleValue(), c_right->DoubleValue());
3518 return H_CONSTANT_DOUBLE(std::isnan(result)
3519 ? std::numeric_limits<double>::quiet_NaN()
3520 : result);
3521 }
3522 }
3523 return new(zone) HPower(left, right);
3524 }
3525
3526
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right,Operation op)3527 HInstruction* HMathMinMax::New(Isolate* isolate, Zone* zone, HValue* context,
3528 HValue* left, HValue* right, Operation op) {
3529 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
3530 HConstant* c_left = HConstant::cast(left);
3531 HConstant* c_right = HConstant::cast(right);
3532 if (c_left->HasNumberValue() && c_right->HasNumberValue()) {
3533 double d_left = c_left->DoubleValue();
3534 double d_right = c_right->DoubleValue();
3535 if (op == kMathMin) {
3536 if (d_left > d_right) return H_CONSTANT_DOUBLE(d_right);
3537 if (d_left < d_right) return H_CONSTANT_DOUBLE(d_left);
3538 if (d_left == d_right) {
3539 // Handle +0 and -0.
3540 return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_left
3541 : d_right);
3542 }
3543 } else {
3544 if (d_left < d_right) return H_CONSTANT_DOUBLE(d_right);
3545 if (d_left > d_right) return H_CONSTANT_DOUBLE(d_left);
3546 if (d_left == d_right) {
3547 // Handle +0 and -0.
3548 return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_right
3549 : d_left);
3550 }
3551 }
3552 // All comparisons failed, must be NaN.
3553 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN());
3554 }
3555 }
3556 return new(zone) HMathMinMax(context, left, right, op);
3557 }
3558
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right)3559 HInstruction* HMod::New(Isolate* isolate, Zone* zone, HValue* context,
3560 HValue* left, HValue* right) {
3561 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
3562 HConstant* c_left = HConstant::cast(left);
3563 HConstant* c_right = HConstant::cast(right);
3564 if (c_left->HasInteger32Value() && c_right->HasInteger32Value()) {
3565 int32_t dividend = c_left->Integer32Value();
3566 int32_t divisor = c_right->Integer32Value();
3567 if (dividend == kMinInt && divisor == -1) {
3568 return H_CONSTANT_DOUBLE(-0.0);
3569 }
3570 if (divisor != 0) {
3571 int32_t res = dividend % divisor;
3572 if ((res == 0) && (dividend < 0)) {
3573 return H_CONSTANT_DOUBLE(-0.0);
3574 }
3575 return H_CONSTANT_INT(res);
3576 }
3577 }
3578 }
3579 return new (zone) HMod(context, left, right);
3580 }
3581
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right)3582 HInstruction* HDiv::New(Isolate* isolate, Zone* zone, HValue* context,
3583 HValue* left, HValue* right) {
3584 // If left and right are constant values, try to return a constant value.
3585 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
3586 HConstant* c_left = HConstant::cast(left);
3587 HConstant* c_right = HConstant::cast(right);
3588 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
3589 if (std::isnan(c_left->DoubleValue()) ||
3590 std::isnan(c_right->DoubleValue())) {
3591 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN());
3592 } else if (c_right->DoubleValue() != 0) {
3593 double double_res = c_left->DoubleValue() / c_right->DoubleValue();
3594 if (IsInt32Double(double_res)) {
3595 return H_CONSTANT_INT(double_res);
3596 }
3597 return H_CONSTANT_DOUBLE(double_res);
3598 } else if (c_left->DoubleValue() != 0) {
3599 int sign = Double(c_left->DoubleValue()).Sign() *
3600 Double(c_right->DoubleValue()).Sign(); // Right could be -0.
3601 return H_CONSTANT_DOUBLE(sign * V8_INFINITY);
3602 } else {
3603 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN());
3604 }
3605 }
3606 }
3607 return new (zone) HDiv(context, left, right);
3608 }
3609
New(Isolate * isolate,Zone * zone,HValue * context,Token::Value op,HValue * left,HValue * right)3610 HInstruction* HBitwise::New(Isolate* isolate, Zone* zone, HValue* context,
3611 Token::Value op, HValue* left, HValue* right) {
3612 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
3613 HConstant* c_left = HConstant::cast(left);
3614 HConstant* c_right = HConstant::cast(right);
3615 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
3616 int32_t result;
3617 int32_t v_left = c_left->NumberValueAsInteger32();
3618 int32_t v_right = c_right->NumberValueAsInteger32();
3619 switch (op) {
3620 case Token::BIT_XOR:
3621 result = v_left ^ v_right;
3622 break;
3623 case Token::BIT_AND:
3624 result = v_left & v_right;
3625 break;
3626 case Token::BIT_OR:
3627 result = v_left | v_right;
3628 break;
3629 default:
3630 result = 0; // Please the compiler.
3631 UNREACHABLE();
3632 }
3633 return H_CONSTANT_INT(result);
3634 }
3635 }
3636 return new (zone) HBitwise(context, op, left, right);
3637 }
3638
3639 #define DEFINE_NEW_H_BITWISE_INSTR(HInstr, result) \
3640 HInstruction* HInstr::New(Isolate* isolate, Zone* zone, HValue* context, \
3641 HValue* left, HValue* right) { \
3642 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \
3643 HConstant* c_left = HConstant::cast(left); \
3644 HConstant* c_right = HConstant::cast(right); \
3645 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
3646 return H_CONSTANT_INT(result); \
3647 } \
3648 } \
3649 return new (zone) HInstr(context, left, right); \
3650 }
3651
3652 DEFINE_NEW_H_BITWISE_INSTR(HSar,
3653 c_left->NumberValueAsInteger32() >> (c_right->NumberValueAsInteger32() & 0x1f))
3654 DEFINE_NEW_H_BITWISE_INSTR(HShl,
3655 c_left->NumberValueAsInteger32() << (c_right->NumberValueAsInteger32() & 0x1f))
3656
3657 #undef DEFINE_NEW_H_BITWISE_INSTR
3658
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right)3659 HInstruction* HShr::New(Isolate* isolate, Zone* zone, HValue* context,
3660 HValue* left, HValue* right) {
3661 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
3662 HConstant* c_left = HConstant::cast(left);
3663 HConstant* c_right = HConstant::cast(right);
3664 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
3665 int32_t left_val = c_left->NumberValueAsInteger32();
3666 int32_t right_val = c_right->NumberValueAsInteger32() & 0x1f;
3667 if ((right_val == 0) && (left_val < 0)) {
3668 return H_CONSTANT_DOUBLE(static_cast<uint32_t>(left_val));
3669 }
3670 return H_CONSTANT_INT(static_cast<uint32_t>(left_val) >> right_val);
3671 }
3672 }
3673 return new (zone) HShr(context, left, right);
3674 }
3675
3676
New(Isolate * isolate,Zone * zone,HValue * context,String::Encoding encoding,HValue * string,HValue * index)3677 HInstruction* HSeqStringGetChar::New(Isolate* isolate, Zone* zone,
3678 HValue* context, String::Encoding encoding,
3679 HValue* string, HValue* index) {
3680 if (FLAG_fold_constants && string->IsConstant() && index->IsConstant()) {
3681 HConstant* c_string = HConstant::cast(string);
3682 HConstant* c_index = HConstant::cast(index);
3683 if (c_string->HasStringValue() && c_index->HasInteger32Value()) {
3684 Handle<String> s = c_string->StringValue();
3685 int32_t i = c_index->Integer32Value();
3686 DCHECK_LE(0, i);
3687 DCHECK_LT(i, s->length());
3688 return H_CONSTANT_INT(s->Get(i));
3689 }
3690 }
3691 return new(zone) HSeqStringGetChar(encoding, string, index);
3692 }
3693
3694
3695 #undef H_CONSTANT_INT
3696 #undef H_CONSTANT_DOUBLE
3697
3698
PrintDataTo(std::ostream & os) const3699 std::ostream& HBitwise::PrintDataTo(std::ostream& os) const { // NOLINT
3700 os << Token::Name(op_) << " ";
3701 return HBitwiseBinaryOperation::PrintDataTo(os);
3702 }
3703
3704
SimplifyConstantInputs()3705 void HPhi::SimplifyConstantInputs() {
3706 // Convert constant inputs to integers when all uses are truncating.
3707 // This must happen before representation inference takes place.
3708 if (!CheckUsesForFlag(kTruncatingToInt32)) return;
3709 for (int i = 0; i < OperandCount(); ++i) {
3710 if (!OperandAt(i)->IsConstant()) return;
3711 }
3712 HGraph* graph = block()->graph();
3713 for (int i = 0; i < OperandCount(); ++i) {
3714 HConstant* operand = HConstant::cast(OperandAt(i));
3715 if (operand->HasInteger32Value()) {
3716 continue;
3717 } else if (operand->HasDoubleValue()) {
3718 HConstant* integer_input = HConstant::New(
3719 graph->isolate(), graph->zone(), graph->GetInvalidContext(),
3720 DoubleToInt32(operand->DoubleValue()));
3721 integer_input->InsertAfter(operand);
3722 SetOperandAt(i, integer_input);
3723 } else if (operand->HasBooleanValue()) {
3724 SetOperandAt(i, operand->BooleanValue() ? graph->GetConstant1()
3725 : graph->GetConstant0());
3726 } else if (operand->ImmortalImmovable()) {
3727 SetOperandAt(i, graph->GetConstant0());
3728 }
3729 }
3730 // Overwrite observed input representations because they are likely Tagged.
3731 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
3732 HValue* use = it.value();
3733 if (use->IsBinaryOperation()) {
3734 HBinaryOperation::cast(use)->set_observed_input_representation(
3735 it.index(), Representation::Smi());
3736 }
3737 }
3738 }
3739
3740
InferRepresentation(HInferRepresentationPhase * h_infer)3741 void HPhi::InferRepresentation(HInferRepresentationPhase* h_infer) {
3742 DCHECK(CheckFlag(kFlexibleRepresentation));
3743 Representation new_rep = RepresentationFromUses();
3744 UpdateRepresentation(new_rep, h_infer, "uses");
3745 new_rep = RepresentationFromInputs();
3746 UpdateRepresentation(new_rep, h_infer, "inputs");
3747 new_rep = RepresentationFromUseRequirements();
3748 UpdateRepresentation(new_rep, h_infer, "use requirements");
3749 }
3750
3751
RepresentationFromInputs()3752 Representation HPhi::RepresentationFromInputs() {
3753 Representation r = representation();
3754 for (int i = 0; i < OperandCount(); ++i) {
3755 // Ignore conservative Tagged assumption of parameters if we have
3756 // reason to believe that it's too conservative.
3757 if (has_type_feedback_from_uses() && OperandAt(i)->IsParameter()) {
3758 continue;
3759 }
3760
3761 r = r.generalize(OperandAt(i)->KnownOptimalRepresentation());
3762 }
3763 return r;
3764 }
3765
3766
3767 // Returns a representation if all uses agree on the same representation.
3768 // Integer32 is also returned when some uses are Smi but others are Integer32.
RepresentationFromUseRequirements()3769 Representation HValue::RepresentationFromUseRequirements() {
3770 Representation rep = Representation::None();
3771 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
3772 // Ignore the use requirement from never run code
3773 if (it.value()->block()->IsUnreachable()) continue;
3774
3775 // We check for observed_input_representation elsewhere.
3776 Representation use_rep =
3777 it.value()->RequiredInputRepresentation(it.index());
3778 if (rep.IsNone()) {
3779 rep = use_rep;
3780 continue;
3781 }
3782 if (use_rep.IsNone() || rep.Equals(use_rep)) continue;
3783 if (rep.generalize(use_rep).IsInteger32()) {
3784 rep = Representation::Integer32();
3785 continue;
3786 }
3787 return Representation::None();
3788 }
3789 return rep;
3790 }
3791
3792
HasNonSmiUse()3793 bool HValue::HasNonSmiUse() {
3794 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
3795 // We check for observed_input_representation elsewhere.
3796 Representation use_rep =
3797 it.value()->RequiredInputRepresentation(it.index());
3798 if (!use_rep.IsNone() &&
3799 !use_rep.IsSmi() &&
3800 !use_rep.IsTagged()) {
3801 return true;
3802 }
3803 }
3804 return false;
3805 }
3806
3807
3808 // Node-specific verification code is only included in debug mode.
3809 #ifdef DEBUG
3810
Verify()3811 void HPhi::Verify() {
3812 DCHECK(OperandCount() == block()->predecessors()->length());
3813 for (int i = 0; i < OperandCount(); ++i) {
3814 HValue* value = OperandAt(i);
3815 HBasicBlock* defining_block = value->block();
3816 HBasicBlock* predecessor_block = block()->predecessors()->at(i);
3817 DCHECK(defining_block == predecessor_block ||
3818 defining_block->Dominates(predecessor_block));
3819 }
3820 }
3821
3822
Verify()3823 void HSimulate::Verify() {
3824 HInstruction::Verify();
3825 DCHECK(HasAstId() || next()->IsEnterInlined());
3826 }
3827
3828
Verify()3829 void HCheckHeapObject::Verify() {
3830 HInstruction::Verify();
3831 DCHECK(HasNoUses());
3832 }
3833
3834
Verify()3835 void HCheckValue::Verify() {
3836 HInstruction::Verify();
3837 DCHECK(HasNoUses());
3838 }
3839
3840 #endif
3841
3842
ForFixedArrayHeader(int offset)3843 HObjectAccess HObjectAccess::ForFixedArrayHeader(int offset) {
3844 DCHECK(offset >= 0);
3845 DCHECK(offset < FixedArray::kHeaderSize);
3846 if (offset == FixedArray::kLengthOffset) return ForFixedArrayLength();
3847 return HObjectAccess(kInobject, offset);
3848 }
3849
3850
ForMapAndOffset(Handle<Map> map,int offset,Representation representation)3851 HObjectAccess HObjectAccess::ForMapAndOffset(Handle<Map> map, int offset,
3852 Representation representation) {
3853 DCHECK(offset >= 0);
3854 Portion portion = kInobject;
3855
3856 if (offset == JSObject::kElementsOffset) {
3857 portion = kElementsPointer;
3858 } else if (offset == JSObject::kMapOffset) {
3859 portion = kMaps;
3860 }
3861 bool existing_inobject_property = true;
3862 if (!map.is_null()) {
3863 existing_inobject_property = (offset <
3864 map->instance_size() - map->unused_property_fields() * kPointerSize);
3865 }
3866 return HObjectAccess(portion, offset, representation, Handle<String>::null(),
3867 false, existing_inobject_property);
3868 }
3869
3870
ForAllocationSiteOffset(int offset)3871 HObjectAccess HObjectAccess::ForAllocationSiteOffset(int offset) {
3872 switch (offset) {
3873 case AllocationSite::kTransitionInfoOffset:
3874 return HObjectAccess(kInobject, offset, Representation::Tagged());
3875 case AllocationSite::kNestedSiteOffset:
3876 return HObjectAccess(kInobject, offset, Representation::Tagged());
3877 case AllocationSite::kPretenureDataOffset:
3878 return HObjectAccess(kInobject, offset, Representation::Smi());
3879 case AllocationSite::kPretenureCreateCountOffset:
3880 return HObjectAccess(kInobject, offset, Representation::Smi());
3881 case AllocationSite::kDependentCodeOffset:
3882 return HObjectAccess(kInobject, offset, Representation::Tagged());
3883 case AllocationSite::kWeakNextOffset:
3884 return HObjectAccess(kInobject, offset, Representation::Tagged());
3885 default:
3886 UNREACHABLE();
3887 }
3888 return HObjectAccess(kInobject, offset);
3889 }
3890
3891
ForContextSlot(int index)3892 HObjectAccess HObjectAccess::ForContextSlot(int index) {
3893 DCHECK(index >= 0);
3894 Portion portion = kInobject;
3895 int offset = Context::kHeaderSize + index * kPointerSize;
3896 DCHECK_EQ(offset, Context::SlotOffset(index) + kHeapObjectTag);
3897 return HObjectAccess(portion, offset, Representation::Tagged());
3898 }
3899
3900
ForScriptContext(int index)3901 HObjectAccess HObjectAccess::ForScriptContext(int index) {
3902 DCHECK(index >= 0);
3903 Portion portion = kInobject;
3904 int offset = ScriptContextTable::GetContextOffset(index);
3905 return HObjectAccess(portion, offset, Representation::Tagged());
3906 }
3907
3908
ForJSArrayOffset(int offset)3909 HObjectAccess HObjectAccess::ForJSArrayOffset(int offset) {
3910 DCHECK(offset >= 0);
3911 Portion portion = kInobject;
3912
3913 if (offset == JSObject::kElementsOffset) {
3914 portion = kElementsPointer;
3915 } else if (offset == JSArray::kLengthOffset) {
3916 portion = kArrayLengths;
3917 } else if (offset == JSObject::kMapOffset) {
3918 portion = kMaps;
3919 }
3920 return HObjectAccess(portion, offset);
3921 }
3922
3923
ForBackingStoreOffset(int offset,Representation representation)3924 HObjectAccess HObjectAccess::ForBackingStoreOffset(int offset,
3925 Representation representation) {
3926 DCHECK(offset >= 0);
3927 return HObjectAccess(kBackingStore, offset, representation,
3928 Handle<String>::null(), false, false);
3929 }
3930
3931
ForField(Handle<Map> map,int index,Representation representation,Handle<Name> name)3932 HObjectAccess HObjectAccess::ForField(Handle<Map> map, int index,
3933 Representation representation,
3934 Handle<Name> name) {
3935 if (index < 0) {
3936 // Negative property indices are in-object properties, indexed
3937 // from the end of the fixed part of the object.
3938 int offset = (index * kPointerSize) + map->instance_size();
3939 return HObjectAccess(kInobject, offset, representation, name, false, true);
3940 } else {
3941 // Non-negative property indices are in the properties array.
3942 int offset = (index * kPointerSize) + FixedArray::kHeaderSize;
3943 return HObjectAccess(kBackingStore, offset, representation, name,
3944 false, false);
3945 }
3946 }
3947
3948
SetGVNFlags(HValue * instr,PropertyAccessType access_type)3949 void HObjectAccess::SetGVNFlags(HValue *instr, PropertyAccessType access_type) {
3950 // set the appropriate GVN flags for a given load or store instruction
3951 if (access_type == STORE) {
3952 // track dominating allocations in order to eliminate write barriers
3953 instr->SetDependsOnFlag(::v8::internal::kNewSpacePromotion);
3954 instr->SetFlag(HValue::kTrackSideEffectDominators);
3955 } else {
3956 // try to GVN loads, but don't hoist above map changes
3957 instr->SetFlag(HValue::kUseGVN);
3958 instr->SetDependsOnFlag(::v8::internal::kMaps);
3959 }
3960
3961 switch (portion()) {
3962 case kArrayLengths:
3963 if (access_type == STORE) {
3964 instr->SetChangesFlag(::v8::internal::kArrayLengths);
3965 } else {
3966 instr->SetDependsOnFlag(::v8::internal::kArrayLengths);
3967 }
3968 break;
3969 case kStringLengths:
3970 if (access_type == STORE) {
3971 instr->SetChangesFlag(::v8::internal::kStringLengths);
3972 } else {
3973 instr->SetDependsOnFlag(::v8::internal::kStringLengths);
3974 }
3975 break;
3976 case kInobject:
3977 if (access_type == STORE) {
3978 instr->SetChangesFlag(::v8::internal::kInobjectFields);
3979 } else {
3980 instr->SetDependsOnFlag(::v8::internal::kInobjectFields);
3981 }
3982 break;
3983 case kDouble:
3984 if (access_type == STORE) {
3985 instr->SetChangesFlag(::v8::internal::kDoubleFields);
3986 } else {
3987 instr->SetDependsOnFlag(::v8::internal::kDoubleFields);
3988 }
3989 break;
3990 case kBackingStore:
3991 if (access_type == STORE) {
3992 instr->SetChangesFlag(::v8::internal::kBackingStoreFields);
3993 } else {
3994 instr->SetDependsOnFlag(::v8::internal::kBackingStoreFields);
3995 }
3996 break;
3997 case kElementsPointer:
3998 if (access_type == STORE) {
3999 instr->SetChangesFlag(::v8::internal::kElementsPointer);
4000 } else {
4001 instr->SetDependsOnFlag(::v8::internal::kElementsPointer);
4002 }
4003 break;
4004 case kMaps:
4005 if (access_type == STORE) {
4006 instr->SetChangesFlag(::v8::internal::kMaps);
4007 } else {
4008 instr->SetDependsOnFlag(::v8::internal::kMaps);
4009 }
4010 break;
4011 case kExternalMemory:
4012 if (access_type == STORE) {
4013 instr->SetChangesFlag(::v8::internal::kExternalMemory);
4014 } else {
4015 instr->SetDependsOnFlag(::v8::internal::kExternalMemory);
4016 }
4017 break;
4018 }
4019 }
4020
4021
operator <<(std::ostream & os,const HObjectAccess & access)4022 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access) {
4023 os << ".";
4024
4025 switch (access.portion()) {
4026 case HObjectAccess::kArrayLengths:
4027 case HObjectAccess::kStringLengths:
4028 os << "%length";
4029 break;
4030 case HObjectAccess::kElementsPointer:
4031 os << "%elements";
4032 break;
4033 case HObjectAccess::kMaps:
4034 os << "%map";
4035 break;
4036 case HObjectAccess::kDouble: // fall through
4037 case HObjectAccess::kInobject:
4038 if (!access.name().is_null() && access.name()->IsString()) {
4039 os << Handle<String>::cast(access.name())->ToCString().get();
4040 }
4041 os << "[in-object]";
4042 break;
4043 case HObjectAccess::kBackingStore:
4044 if (!access.name().is_null() && access.name()->IsString()) {
4045 os << Handle<String>::cast(access.name())->ToCString().get();
4046 }
4047 os << "[backing-store]";
4048 break;
4049 case HObjectAccess::kExternalMemory:
4050 os << "[external-memory]";
4051 break;
4052 }
4053
4054 return os << "@" << access.offset();
4055 }
4056
4057 } // namespace internal
4058 } // namespace v8
4059