summaryrefslogtreecommitdiff
path: root/deps/v8/test/unittests/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/unittests/compiler')
-rw-r--r--deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc34
-rw-r--r--deps/v8/test/unittests/compiler/coalesced-live-ranges-unittest.cc309
-rw-r--r--deps/v8/test/unittests/compiler/compiler-test-utils.h16
-rw-r--r--deps/v8/test/unittests/compiler/instruction-selector-unittest.cc2
-rw-r--r--deps/v8/test/unittests/compiler/instruction-selector-unittest.h41
-rw-r--r--deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc8
-rw-r--r--deps/v8/test/unittests/compiler/instruction-sequence-unittest.h6
-rw-r--r--deps/v8/test/unittests/compiler/interpreter-assembler-unittest.cc262
-rw-r--r--deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h56
-rw-r--r--deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc306
-rw-r--r--deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc2
-rw-r--r--deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc41
-rw-r--r--deps/v8/test/unittests/compiler/linkage-tail-call-unittest.cc324
-rw-r--r--deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc2
-rw-r--r--deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc49
-rw-r--r--deps/v8/test/unittests/compiler/node-test-utils.cc103
-rw-r--r--deps/v8/test/unittests/compiler/node-test-utils.h37
-rw-r--r--deps/v8/test/unittests/compiler/ppc/OWNERS1
-rw-r--r--deps/v8/test/unittests/compiler/register-allocator-unittest.cc207
-rw-r--r--deps/v8/test/unittests/compiler/scheduler-unittest.cc28
-rw-r--r--deps/v8/test/unittests/compiler/tail-call-optimization-unittest.cc42
21 files changed, 1790 insertions, 86 deletions
diff --git a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
index 7e67b31616..71c2d44d2f 100644
--- a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
+++ b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
@@ -2421,6 +2421,40 @@ TEST_F(InstructionSelectorTest, Word32EqualWithSignedExtendHalfword) {
}
+TEST_F(InstructionSelectorTest, Word32EqualZeroWithWord32Equal) {
+ {
+ StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+ Node* const p0 = m.Parameter(0);
+ Node* const p1 = m.Parameter(1);
+ m.Return(m.Word32Equal(m.Word32Equal(p0, p1), m.Int32Constant(0)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
+ ASSERT_EQ(2U, s[0]->InputCount());
+ EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+ EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+ }
+ {
+ StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+ Node* const p0 = m.Parameter(0);
+ Node* const p1 = m.Parameter(1);
+ m.Return(m.Word32Equal(m.Int32Constant(0), m.Word32Equal(p0, p1)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
+ ASSERT_EQ(2U, s[0]->InputCount());
+ EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+ EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+ EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+ }
+}
+
+
// -----------------------------------------------------------------------------
// Miscellaneous
diff --git a/deps/v8/test/unittests/compiler/coalesced-live-ranges-unittest.cc b/deps/v8/test/unittests/compiler/coalesced-live-ranges-unittest.cc
new file mode 100644
index 0000000000..ea9ebdb20b
--- /dev/null
+++ b/deps/v8/test/unittests/compiler/coalesced-live-ranges-unittest.cc
@@ -0,0 +1,309 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/coalesced-live-ranges.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+
+// Utility offering shorthand syntax for building up a range by providing its ID
+// and pairs (start, end) specifying intervals. Circumvents current incomplete
+// support for C++ features such as instantiation lists, on OS X and Android.
+class TestRangeBuilder {
+ public:
+ explicit TestRangeBuilder(Zone* zone) : id_(-1), pairs_(), zone_(zone) {}
+
+ TestRangeBuilder& Id(int id) {
+ id_ = id;
+ return *this;
+ }
+ TestRangeBuilder& Add(int start, int end) {
+ pairs_.push_back({start, end});
+ return *this;
+ }
+
+ LiveRange* Build(int start, int end) { return Add(start, end).Build(); }
+
+ LiveRange* Build() {
+ LiveRange* range = new (zone_) LiveRange(id_, MachineType::kRepTagged);
+ // Traverse the provided interval specifications backwards, because that is
+ // what LiveRange expects.
+ for (int i = static_cast<int>(pairs_.size()) - 1; i >= 0; --i) {
+ Interval pair = pairs_[i];
+ LifetimePosition start = LifetimePosition::FromInt(pair.first);
+ LifetimePosition end = LifetimePosition::FromInt(pair.second);
+ CHECK(start < end);
+ range->AddUseInterval(start, end, zone_);
+ }
+
+ pairs_.clear();
+ return range;
+ }
+
+ private:
+ typedef std::pair<int, int> Interval;
+ typedef std::vector<Interval> IntervalList;
+ int id_;
+ IntervalList pairs_;
+ Zone* zone_;
+};
+
+
+class CoalescedLiveRangesTest : public TestWithZone {
+ public:
+ CoalescedLiveRangesTest() : TestWithZone(), ranges_(zone()) {}
+ bool HasNoConflicts(const LiveRange* range);
+ bool ConflictsPreciselyWith(const LiveRange* range, int id);
+ bool ConflictsPreciselyWith(const LiveRange* range, int id1, int id2);
+
+ CoalescedLiveRanges& ranges() { return ranges_; }
+ const CoalescedLiveRanges& ranges() const { return ranges_; }
+ bool AllocationsAreValid() const;
+ void RemoveConflicts(LiveRange* range);
+
+ private:
+ typedef ZoneSet<int> LiveRangeIDs;
+ bool IsRangeConflictingWith(const LiveRange* range, const LiveRangeIDs& ids);
+ CoalescedLiveRanges ranges_;
+};
+
+
+bool CoalescedLiveRangesTest::ConflictsPreciselyWith(const LiveRange* range,
+ int id) {
+ LiveRangeIDs set(zone());
+ set.insert(id);
+ return IsRangeConflictingWith(range, set);
+}
+
+
+bool CoalescedLiveRangesTest::ConflictsPreciselyWith(const LiveRange* range,
+ int id1, int id2) {
+ LiveRangeIDs set(zone());
+ set.insert(id1);
+ set.insert(id2);
+ return IsRangeConflictingWith(range, set);
+}
+
+
+bool CoalescedLiveRangesTest::HasNoConflicts(const LiveRange* range) {
+ LiveRangeIDs set(zone());
+ return IsRangeConflictingWith(range, set);
+}
+
+
+void CoalescedLiveRangesTest::RemoveConflicts(LiveRange* range) {
+ auto conflicts = ranges().GetConflicts(range);
+ LiveRangeIDs seen(zone());
+ for (auto c = conflicts.Current(); c != nullptr;
+ c = conflicts.RemoveCurrentAndGetNext()) {
+ EXPECT_FALSE(seen.count(c->id()) > 0);
+ seen.insert(c->id());
+ }
+}
+
+
+bool CoalescedLiveRangesTest::AllocationsAreValid() const {
+ return ranges().VerifyAllocationsAreValidForTesting();
+}
+
+
+bool CoalescedLiveRangesTest::IsRangeConflictingWith(const LiveRange* range,
+ const LiveRangeIDs& ids) {
+ LiveRangeIDs found_ids(zone());
+
+ auto conflicts = ranges().GetConflicts(range);
+ for (auto conflict = conflicts.Current(); conflict != nullptr;
+ conflict = conflicts.GetNext()) {
+ found_ids.insert(conflict->id());
+ }
+ return found_ids == ids;
+}
+
+
+TEST_F(CoalescedLiveRangesTest, VisitEmptyAllocations) {
+ LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(1, 5);
+ ASSERT_TRUE(ranges().empty());
+ ASSERT_TRUE(AllocationsAreValid());
+ ASSERT_TRUE(HasNoConflicts(range));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, CandidateBeforeAfterAllocations) {
+ LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(5, 6);
+ ranges().AllocateRange(range);
+ ASSERT_FALSE(ranges().empty());
+ ASSERT_TRUE(AllocationsAreValid());
+ LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(1, 2);
+ ASSERT_TRUE(HasNoConflicts(query));
+ query = TestRangeBuilder(zone()).Id(3).Build(1, 5);
+ ASSERT_TRUE(HasNoConflicts(query));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, CandidateBeforeAfterManyAllocations) {
+ LiveRange* range =
+ TestRangeBuilder(zone()).Id(1).Add(5, 7).Add(10, 12).Build();
+ ranges().AllocateRange(range);
+ ASSERT_FALSE(ranges().empty());
+ ASSERT_TRUE(AllocationsAreValid());
+ LiveRange* query =
+ TestRangeBuilder(zone()).Id(2).Add(1, 2).Add(13, 15).Build();
+ ASSERT_TRUE(HasNoConflicts(query));
+ query = TestRangeBuilder(zone()).Id(3).Add(1, 5).Add(12, 15).Build();
+ ASSERT_TRUE(HasNoConflicts(query));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, SelfConflictsPreciselyWithSelf) {
+ LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(1, 5);
+ ranges().AllocateRange(range);
+ ASSERT_FALSE(ranges().empty());
+ ASSERT_TRUE(AllocationsAreValid());
+ ASSERT_TRUE(ConflictsPreciselyWith(range, 1));
+ range = TestRangeBuilder(zone()).Id(2).Build(8, 10);
+ ranges().AllocateRange(range);
+ ASSERT_TRUE(ConflictsPreciselyWith(range, 2));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, QueryStartsBeforeConflict) {
+ LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(2, 5);
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(1, 3);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 1));
+ range = TestRangeBuilder(zone()).Id(3).Build(8, 10);
+ ranges().AllocateRange(range);
+ query = TestRangeBuilder(zone()).Id(4).Build(6, 9);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 3));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, QueryStartsInConflict) {
+ LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(2, 5);
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(3, 6);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 1));
+ range = TestRangeBuilder(zone()).Id(3).Build(8, 10);
+ ranges().AllocateRange(range);
+ query = TestRangeBuilder(zone()).Id(4).Build(9, 11);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 3));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, QueryContainedInConflict) {
+ LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(1, 5);
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(2, 3);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 1));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, QueryContainsConflict) {
+ LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(2, 3);
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(1, 5);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 1));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, QueryCoversManyIntervalsSameRange) {
+ LiveRange* range =
+ TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(7, 9).Add(20, 25).Build();
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(2, 8);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 1));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, QueryCoversManyIntervalsDifferentRanges) {
+ LiveRange* range =
+ TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(20, 25).Build();
+ ranges().AllocateRange(range);
+ range = TestRangeBuilder(zone()).Id(2).Build(7, 10);
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(2, 22);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 1, 2));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, QueryFitsInGaps) {
+ LiveRange* range =
+ TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(10, 15).Add(20, 25).Build();
+ ranges().AllocateRange(range);
+ LiveRange* query =
+ TestRangeBuilder(zone()).Id(3).Add(5, 10).Add(16, 19).Add(27, 30).Build();
+ ASSERT_TRUE(HasNoConflicts(query));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, DeleteConflictBefore) {
+ LiveRange* range = TestRangeBuilder(zone()).Id(1).Add(1, 4).Add(5, 6).Build();
+ ranges().AllocateRange(range);
+ range = TestRangeBuilder(zone()).Id(2).Build(40, 50);
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(3, 7);
+ RemoveConflicts(query);
+ query = TestRangeBuilder(zone()).Id(4).Build(0, 60);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 2));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, DeleteConflictAfter) {
+ LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(1, 5);
+ ranges().AllocateRange(range);
+ range = TestRangeBuilder(zone()).Id(2).Add(40, 50).Add(60, 70).Build();
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(45, 60);
+ RemoveConflicts(query);
+ query = TestRangeBuilder(zone()).Id(4).Build(0, 60);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 1));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, DeleteConflictStraddle) {
+ LiveRange* range =
+ TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(10, 20).Build();
+ ranges().AllocateRange(range);
+ range = TestRangeBuilder(zone()).Id(2).Build(40, 50);
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(4, 15);
+ RemoveConflicts(query);
+ query = TestRangeBuilder(zone()).Id(4).Build(0, 60);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 2));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, DeleteConflictManyOverlapsBefore) {
+ LiveRange* range =
+ TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(6, 10).Add(10, 20).Build();
+ ranges().AllocateRange(range);
+ range = TestRangeBuilder(zone()).Id(2).Build(40, 50);
+ ranges().AllocateRange(range);
+ LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(4, 15);
+ RemoveConflicts(query);
+ query = TestRangeBuilder(zone()).Id(4).Build(0, 60);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 2));
+}
+
+
+TEST_F(CoalescedLiveRangesTest, DeleteWhenConflictRepeatsAfterNonConflict) {
+ LiveRange* range =
+ TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(6, 10).Add(20, 30).Build();
+ ranges().AllocateRange(range);
+ range = TestRangeBuilder(zone()).Id(2).Build(12, 15);
+ ranges().AllocateRange(range);
+ LiveRange* query =
+ TestRangeBuilder(zone()).Id(3).Add(1, 8).Add(22, 25).Build();
+ RemoveConflicts(query);
+ query = TestRangeBuilder(zone()).Id(4).Build(0, 60);
+ ASSERT_TRUE(ConflictsPreciselyWith(query, 2));
+}
+
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/unittests/compiler/compiler-test-utils.h b/deps/v8/test/unittests/compiler/compiler-test-utils.h
index 6ce28f9f94..7873c961b1 100644
--- a/deps/v8/test/unittests/compiler/compiler-test-utils.h
+++ b/deps/v8/test/unittests/compiler/compiler-test-utils.h
@@ -14,41 +14,25 @@ namespace compiler {
// The TARGET_TEST(Case, Name) macro works just like
// TEST(Case, Name), except that the test is disabled
// if the platform is not a supported TurboFan target.
-#if V8_TURBOFAN_TARGET
#define TARGET_TEST(Case, Name) TEST(Case, Name)
-#else
-#define TARGET_TEST(Case, Name) TEST(Case, DISABLED_##Name)
-#endif
// The TARGET_TEST_F(Case, Name) macro works just like
// TEST_F(Case, Name), except that the test is disabled
// if the platform is not a supported TurboFan target.
-#if V8_TURBOFAN_TARGET
#define TARGET_TEST_F(Case, Name) TEST_F(Case, Name)
-#else
-#define TARGET_TEST_F(Case, Name) TEST_F(Case, DISABLED_##Name)
-#endif
// The TARGET_TEST_P(Case, Name) macro works just like
// TEST_P(Case, Name), except that the test is disabled
// if the platform is not a supported TurboFan target.
-#if V8_TURBOFAN_TARGET
#define TARGET_TEST_P(Case, Name) TEST_P(Case, Name)
-#else
-#define TARGET_TEST_P(Case, Name) TEST_P(Case, DISABLED_##Name)
-#endif
// The TARGET_TYPED_TEST(Case, Name) macro works just like
// TYPED_TEST(Case, Name), except that the test is disabled
// if the platform is not a supported TurboFan target.
-#if V8_TURBOFAN_TARGET
#define TARGET_TYPED_TEST(Case, Name) TYPED_TEST(Case, Name)
-#else
-#define TARGET_TYPED_TEST(Case, Name) TYPED_TEST(Case, DISABLED_##Name)
-#endif
} // namespace compiler
} // namespace internal
diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc
index acab91b009..1636b7ee5b 100644
--- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc
+++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc
@@ -153,7 +153,7 @@ InstructionSelectorTest::StreamBuilder::GetFrameStateFunctionInfo(
int parameter_count, int local_count) {
return common()->CreateFrameStateFunctionInfo(
FrameStateType::kJavaScriptFunction, parameter_count, local_count,
- Handle<SharedFunctionInfo>());
+ Handle<SharedFunctionInfo>(), CALL_MAINTAINS_NATIVE_CONTEXT);
}
diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h b/deps/v8/test/unittests/compiler/instruction-selector-unittest.h
index 15d3b2005f..574864edf5 100644
--- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h
+++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.h
@@ -39,22 +39,22 @@ class InstructionSelectorTest : public TestWithContext,
StreamBuilder(InstructionSelectorTest* test, MachineType return_type)
: RawMachineAssembler(
test->isolate(), new (test->zone()) Graph(test->zone()),
- MakeMachineSignature(test->zone(), return_type), kMachPtr,
+ MakeCallDescriptor(test->zone(), return_type), kMachPtr,
MachineOperatorBuilder::kAllOptionalOps),
test_(test) {}
StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
MachineType parameter0_type)
: RawMachineAssembler(
test->isolate(), new (test->zone()) Graph(test->zone()),
- MakeMachineSignature(test->zone(), return_type, parameter0_type),
+ MakeCallDescriptor(test->zone(), return_type, parameter0_type),
kMachPtr, MachineOperatorBuilder::kAllOptionalOps),
test_(test) {}
StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
MachineType parameter0_type, MachineType parameter1_type)
: RawMachineAssembler(
test->isolate(), new (test->zone()) Graph(test->zone()),
- MakeMachineSignature(test->zone(), return_type, parameter0_type,
- parameter1_type),
+ MakeCallDescriptor(test->zone(), return_type, parameter0_type,
+ parameter1_type),
kMachPtr, MachineOperatorBuilder::kAllOptionalOps),
test_(test) {}
StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
@@ -62,8 +62,8 @@ class InstructionSelectorTest : public TestWithContext,
MachineType parameter2_type)
: RawMachineAssembler(
test->isolate(), new (test->zone()) Graph(test->zone()),
- MakeMachineSignature(test->zone(), return_type, parameter0_type,
- parameter1_type, parameter2_type),
+ MakeCallDescriptor(test->zone(), return_type, parameter0_type,
+ parameter1_type, parameter2_type),
kMachPtr, MachineOperatorBuilder::kAllOptionalOps),
test_(test) {}
@@ -85,41 +85,40 @@ class InstructionSelectorTest : public TestWithContext,
int local_count);
private:
- MachineSignature* MakeMachineSignature(Zone* zone,
- MachineType return_type) {
+ CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type) {
MachineSignature::Builder builder(zone, 1, 0);
builder.AddReturn(return_type);
- return builder.Build();
+ return Linkage::GetSimplifiedCDescriptor(zone, builder.Build());
}
- MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
- MachineType parameter0_type) {
+ CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type,
+ MachineType parameter0_type) {
MachineSignature::Builder builder(zone, 1, 1);
builder.AddReturn(return_type);
builder.AddParam(parameter0_type);
- return builder.Build();
+ return Linkage::GetSimplifiedCDescriptor(zone, builder.Build());
}
- MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
- MachineType parameter0_type,
- MachineType parameter1_type) {
+ CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type,
+ MachineType parameter0_type,
+ MachineType parameter1_type) {
MachineSignature::Builder builder(zone, 1, 2);
builder.AddReturn(return_type);
builder.AddParam(parameter0_type);
builder.AddParam(parameter1_type);
- return builder.Build();
+ return Linkage::GetSimplifiedCDescriptor(zone, builder.Build());
}
- MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
- MachineType parameter0_type,
- MachineType parameter1_type,
- MachineType parameter2_type) {
+ CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type,
+ MachineType parameter0_type,
+ MachineType parameter1_type,
+ MachineType parameter2_type) {
MachineSignature::Builder builder(zone, 1, 3);
builder.AddReturn(return_type);
builder.AddParam(parameter0_type);
builder.AddParam(parameter1_type);
builder.AddParam(parameter2_type);
- return builder.Build();
+ return Linkage::GetSimplifiedCDescriptor(zone, builder.Build());
}
private:
diff --git a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc
index 1ff441f746..65a7f299c5 100644
--- a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc
+++ b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc
@@ -93,9 +93,9 @@ void InstructionSequenceTest::EndLoop() {
}
-void InstructionSequenceTest::StartBlock() {
+void InstructionSequenceTest::StartBlock(bool deferred) {
block_returns_ = false;
- NewBlock();
+ NewBlock(deferred);
}
@@ -408,7 +408,7 @@ InstructionOperand InstructionSequenceTest::ConvertOutputOp(VReg vreg,
}
-InstructionBlock* InstructionSequenceTest::NewBlock() {
+InstructionBlock* InstructionSequenceTest::NewBlock(bool deferred) {
CHECK(current_block_ == nullptr);
Rpo rpo = Rpo::FromInt(static_cast<int>(instruction_blocks_.size()));
Rpo loop_header = Rpo::Invalid();
@@ -430,7 +430,7 @@ InstructionBlock* InstructionSequenceTest::NewBlock() {
}
// Construct instruction block.
auto instruction_block = new (zone())
- InstructionBlock(zone(), rpo, loop_header, loop_end, false, false);
+ InstructionBlock(zone(), rpo, loop_header, loop_end, deferred, false);
instruction_blocks_.push_back(instruction_block);
current_block_ = instruction_block;
sequence()->StartBlock(rpo);
diff --git a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h
index 2d75da7e47..54317ede21 100644
--- a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h
+++ b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h
@@ -126,7 +126,7 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
void StartLoop(int loop_blocks);
void EndLoop();
- void StartBlock();
+ void StartBlock(bool deferred = false);
Instruction* EndBlock(BlockCompletion completion = FallThrough());
TestOperand Imm(int32_t imm = 0);
@@ -203,7 +203,7 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
InstructionOperand* ConvertInputs(size_t input_size, TestOperand* inputs);
InstructionOperand ConvertInputOp(TestOperand op);
InstructionOperand ConvertOutputOp(VReg vreg, TestOperand op);
- InstructionBlock* NewBlock();
+ InstructionBlock* NewBlock(bool deferred = false);
void WireBlock(size_t block_offset, int jump_offset);
Instruction* Emit(InstructionCode code, size_t outputs_size = 0,
@@ -223,7 +223,7 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
typedef std::map<int, const Instruction*> Instructions;
typedef std::vector<BlockCompletion> Completions;
- SmartPointer<RegisterConfiguration> config_;
+ base::SmartPointer<RegisterConfiguration> config_;
InstructionSequence* sequence_;
int num_general_registers_;
int num_double_registers_;
diff --git a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.cc b/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.cc
new file mode 100644
index 0000000000..a869f7ebb1
--- /dev/null
+++ b/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.cc
@@ -0,0 +1,262 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/interpreter-assembler-unittest.h"
+
+#include "src/compiler/graph.h"
+#include "src/compiler/node.h"
+#include "src/unique.h"
+#include "test/unittests/compiler/compiler-test-utils.h"
+#include "test/unittests/compiler/node-test-utils.h"
+
+using ::testing::_;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+const interpreter::Bytecode kBytecodes[] = {
+#define DEFINE_BYTECODE(Name, ...) interpreter::Bytecode::k##Name,
+ BYTECODE_LIST(DEFINE_BYTECODE)
+#undef DEFINE_BYTECODE
+};
+
+
+Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher,
+ const Matcher<Node*>& rhs_matcher) {
+ return kPointerSize == 8 ? IsInt64Add(lhs_matcher, rhs_matcher)
+ : IsInt32Add(lhs_matcher, rhs_matcher);
+}
+
+
+Matcher<Node*> IsIntPtrSub(const Matcher<Node*>& lhs_matcher,
+ const Matcher<Node*>& rhs_matcher) {
+ return kPointerSize == 8 ? IsInt64Sub(lhs_matcher, rhs_matcher)
+ : IsInt32Sub(lhs_matcher, rhs_matcher);
+}
+
+
+Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher,
+ const Matcher<Node*>& rhs_matcher) {
+ return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher)
+ : IsWord32Shl(lhs_matcher, rhs_matcher);
+}
+
+
+Matcher<Node*> IsWordSar(const Matcher<Node*>& lhs_matcher,
+ const Matcher<Node*>& rhs_matcher) {
+ return kPointerSize == 8 ? IsWord64Sar(lhs_matcher, rhs_matcher)
+ : IsWord32Sar(lhs_matcher, rhs_matcher);
+}
+
+
+Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoad(
+ const Matcher<LoadRepresentation>& rep_matcher,
+ const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher) {
+ return ::i::compiler::IsLoad(rep_matcher, base_matcher, index_matcher,
+ graph()->start(), graph()->start());
+}
+
+
+Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore(
+ const Matcher<StoreRepresentation>& rep_matcher,
+ const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher,
+ const Matcher<Node*>& value_matcher) {
+ return ::i::compiler::IsStore(rep_matcher, base_matcher, index_matcher,
+ value_matcher, graph()->start(),
+ graph()->start());
+}
+
+
+Matcher<Node*>
+InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand(
+ int operand) {
+ return IsLoad(
+ kMachUint8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
+ IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
+ IsInt32Constant(1 + operand)));
+}
+
+
+Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::
+ IsBytecodeOperandSignExtended(int operand) {
+ Matcher<Node*> load_matcher = IsLoad(
+ kMachInt8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
+ IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
+ IsInt32Constant(1 + operand)));
+ if (kPointerSize == 8) {
+ load_matcher = IsChangeInt32ToInt64(load_matcher);
+ }
+ return load_matcher;
+}
+
+
+Graph*
+InterpreterAssemblerTest::InterpreterAssemblerForTest::GetCompletedGraph() {
+ End();
+ return graph();
+}
+
+
+TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) {
+ TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+ InterpreterAssemblerForTest m(this, bytecode);
+ m.Dispatch();
+ Graph* graph = m.GetCompletedGraph();
+
+ Node* end = graph->end();
+ EXPECT_EQ(1, end->InputCount());
+ Node* tail_call_node = end->InputAt(0);
+
+ Matcher<Node*> next_bytecode_offset_matcher =
+ IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
+ IsInt32Constant(interpreter::Bytecodes::Size(bytecode)));
+ Matcher<Node*> target_bytecode_matcher = m.IsLoad(
+ kMachUint8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
+ next_bytecode_offset_matcher);
+ Matcher<Node*> code_target_matcher = m.IsLoad(
+ kMachPtr, IsParameter(Linkage::kInterpreterDispatchTableParameter),
+ IsWord32Shl(target_bytecode_matcher,
+ IsInt32Constant(kPointerSizeLog2)));
+
+ EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind());
+ EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots);
+ EXPECT_THAT(
+ tail_call_node,
+ IsTailCall(m.call_descriptor(), code_target_matcher,
+ IsParameter(Linkage::kInterpreterAccumulatorParameter),
+ IsParameter(Linkage::kInterpreterRegisterFileParameter),
+ next_bytecode_offset_matcher,
+ IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
+ IsParameter(Linkage::kInterpreterDispatchTableParameter),
+ graph->start(), graph->start()));
+ }
+}
+
+
+TARGET_TEST_F(InterpreterAssemblerTest, Return) {
+ TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+ InterpreterAssemblerForTest m(this, bytecode);
+ m.Return();
+ Graph* graph = m.GetCompletedGraph();
+
+ Node* end = graph->end();
+ EXPECT_EQ(1, end->InputCount());
+ Node* tail_call_node = end->InputAt(0);
+
+ EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind());
+ EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots);
+ Matcher<Unique<HeapObject>> exit_trampoline(
+ Unique<HeapObject>::CreateImmovable(
+ isolate()->builtins()->InterpreterExitTrampoline()));
+ EXPECT_THAT(
+ tail_call_node,
+ IsTailCall(m.call_descriptor(), IsHeapConstant(exit_trampoline),
+ IsParameter(Linkage::kInterpreterAccumulatorParameter),
+ IsParameter(Linkage::kInterpreterRegisterFileParameter),
+ IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
+ IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
+ IsParameter(Linkage::kInterpreterDispatchTableParameter),
+ graph->start(), graph->start()));
+ }
+}
+
+
+TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
+ TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+ InterpreterAssemblerForTest m(this, bytecode);
+ int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode);
+ for (int i = 0; i < number_of_operands; i++) {
+ switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) {
+ case interpreter::OperandType::kImm8:
+ EXPECT_THAT(m.BytecodeOperandImm8(i),
+ m.IsBytecodeOperandSignExtended(i));
+ break;
+ case interpreter::OperandType::kReg:
+ EXPECT_THAT(m.BytecodeOperandReg(i),
+ m.IsBytecodeOperandSignExtended(i));
+ break;
+ case interpreter::OperandType::kNone:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+}
+
+
+TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) {
+ TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+ InterpreterAssemblerForTest m(this, bytecode);
+ // Should be incoming accumulator if not set.
+ EXPECT_THAT(m.GetAccumulator(),
+ IsParameter(Linkage::kInterpreterAccumulatorParameter));
+
+ // Should be set by SedtAccumulator.
+ Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef);
+ m.SetAccumulator(accumulator_value_1);
+ EXPECT_THAT(m.GetAccumulator(), accumulator_value_1);
+ Node* accumulator_value_2 = m.Int32Constant(42);
+ m.SetAccumulator(accumulator_value_2);
+ EXPECT_THAT(m.GetAccumulator(), accumulator_value_2);
+
+ // Should be passed to next bytecode handler on dispatch.
+ m.Dispatch();
+ Graph* graph = m.GetCompletedGraph();
+
+ Node* end = graph->end();
+ EXPECT_EQ(1, end->InputCount());
+ Node* tail_call_node = end->InputAt(0);
+
+ EXPECT_THAT(tail_call_node,
+ IsTailCall(m.call_descriptor(), _, accumulator_value_2, _, _, _,
+ _, graph->start(), graph->start()));
+ }
+}
+
+
+TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) {
+ TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+ InterpreterAssemblerForTest m(this, bytecode);
+ Node* reg_index_node = m.Int32Constant(44);
+ Node* load_reg_node = m.LoadRegister(reg_index_node);
+ EXPECT_THAT(
+ load_reg_node,
+ m.IsLoad(kMachPtr,
+ IsParameter(Linkage::kInterpreterRegisterFileParameter),
+ IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2))));
+ }
+}
+
+
+TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) {
+ TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+ InterpreterAssemblerForTest m(this, bytecode);
+ Node* store_value = m.Int32Constant(0xdeadbeef);
+ Node* reg_index_node = m.Int32Constant(44);
+ Node* store_reg_node = m.StoreRegister(store_value, reg_index_node);
+ EXPECT_THAT(
+ store_reg_node,
+ m.IsStore(StoreRepresentation(kMachPtr, kNoWriteBarrier),
+ IsParameter(Linkage::kInterpreterRegisterFileParameter),
+ IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)),
+ store_value));
+ }
+}
+
+
+TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) {
+ TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+ InterpreterAssemblerForTest m(this, bytecode);
+ Node* value = m.Int32Constant(44);
+ EXPECT_THAT(m.SmiTag(value),
+ IsWordShl(value, IsInt32Constant(kSmiShiftSize + kSmiTagSize)));
+ EXPECT_THAT(m.SmiUntag(value),
+ IsWordSar(value, IsInt32Constant(kSmiShiftSize + kSmiTagSize)));
+ }
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h b/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h
new file mode 100644
index 0000000000..64353ae128
--- /dev/null
+++ b/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h
@@ -0,0 +1,56 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_INTERPRETER_ASSEMBLER_UNITTEST_H_
+#define V8_UNITTESTS_COMPILER_INTERPRETER_ASSEMBLER_UNITTEST_H_
+
+#include "src/compiler/interpreter-assembler.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/machine-operator.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock-support.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+using ::testing::Matcher;
+
+class InterpreterAssemblerTest : public TestWithIsolateAndZone {
+ public:
+ InterpreterAssemblerTest() {}
+ ~InterpreterAssemblerTest() override {}
+
+ class InterpreterAssemblerForTest final : public InterpreterAssembler {
+ public:
+ InterpreterAssemblerForTest(InterpreterAssemblerTest* test,
+ interpreter::Bytecode bytecode)
+ : InterpreterAssembler(test->isolate(), test->zone(), bytecode) {}
+ ~InterpreterAssemblerForTest() override {}
+
+ Graph* GetCompletedGraph();
+
+ Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& index_matcher);
+ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
+ const Matcher<Node*>& base_matcher,
+ const Matcher<Node*>& index_matcher,
+ const Matcher<Node*>& value_matcher);
+ Matcher<Node*> IsBytecodeOperand(int operand);
+ Matcher<Node*> IsBytecodeOperandSignExtended(int operand);
+
+ using InterpreterAssembler::call_descriptor;
+ using InterpreterAssembler::graph;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InterpreterAssemblerForTest);
+ };
+};
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
+
+#endif // V8_UNITTESTS_COMPILER_INTERPRETER_ASSEMBLER_UNITTEST_H_
diff --git a/deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc b/deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc
new file mode 100644
index 0000000000..b52417de2f
--- /dev/null
+++ b/deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc
@@ -0,0 +1,306 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/js-context-relaxation.h"
+#include "src/compiler/js-graph.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class JSContextRelaxationTest : public GraphTest {
+ public:
+ JSContextRelaxationTest() : GraphTest(3), javascript_(zone()) {}
+ ~JSContextRelaxationTest() override {}
+
+ protected:
+ Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
+ MachineOperatorBuilder::kNoFlags) {
+ MachineOperatorBuilder machine(zone(), kMachPtr, flags);
+ JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
+ // TODO(titzer): mock the GraphReducer here for better unit testing.
+ GraphReducer graph_reducer(zone(), graph());
+ JSContextRelaxation reducer;
+ return reducer.Reduce(node);
+ }
+
+ Node* EmptyFrameState() {
+ MachineOperatorBuilder machine(zone());
+ JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
+ return jsgraph.EmptyFrameState();
+ }
+
+ Node* ShallowFrameStateChain(Node* outer_context,
+ ContextCallingMode context_calling_mode) {
+ const FrameStateFunctionInfo* const frame_state_function_info =
+ common()->CreateFrameStateFunctionInfo(
+ FrameStateType::kJavaScriptFunction, 3, 0,
+ Handle<SharedFunctionInfo>(), context_calling_mode);
+ const Operator* op = common()->FrameState(BailoutId::None(),
+ OutputFrameStateCombine::Ignore(),
+ frame_state_function_info);
+ return graph()->NewNode(op, graph()->start(), graph()->start(),
+ graph()->start(), outer_context, graph()->start(),
+ graph()->start());
+ }
+
+ Node* DeepFrameStateChain(Node* outer_context,
+ ContextCallingMode context_calling_mode) {
+ const FrameStateFunctionInfo* const frame_state_function_info =
+ common()->CreateFrameStateFunctionInfo(
+ FrameStateType::kJavaScriptFunction, 3, 0,
+ Handle<SharedFunctionInfo>(), context_calling_mode);
+ const Operator* op = common()->FrameState(BailoutId::None(),
+ OutputFrameStateCombine::Ignore(),
+ frame_state_function_info);
+ Node* shallow_frame_state =
+ ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ return graph()->NewNode(op, graph()->start(), graph()->start(),
+ graph()->start(), graph()->start(),
+ graph()->start(), shallow_frame_state);
+ }
+
+ JSOperatorBuilder* javascript() { return &javascript_; }
+
+ private:
+ JSOperatorBuilder javascript_;
+};
+
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionShallowFrameStateChainNoCrossCtx) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ Node* const frame_state =
+ ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_TRUE(r.Changed());
+ EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
+}
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionShallowFrameStateChainCrossCtx) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ Node* const frame_state =
+ ShallowFrameStateChain(outer_context, CALL_CHANGES_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_FALSE(r.Changed());
+ EXPECT_EQ(context, NodeProperties::GetContextInput(node));
+}
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionDeepFrameStateChainNoCrossCtx) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ Node* const frame_state =
+ DeepFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_TRUE(r.Changed());
+ EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
+}
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionDeepFrameStateChainCrossCtx) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ Node* const frame_state =
+ DeepFrameStateChain(outer_context, CALL_CHANGES_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_FALSE(r.Changed());
+ EXPECT_EQ(context, NodeProperties::GetContextInput(node));
+}
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionDeepContextChainFullRelaxForCatch) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ const Operator* op = javascript()->CreateCatchContext(Unique<String>());
+ Node* const frame_state_1 =
+ ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* nested_context =
+ graph()->NewNode(op, graph()->start(), graph()->start(), outer_context,
+ frame_state_1, effect, control);
+ Node* const frame_state_2 =
+ ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state_2, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_TRUE(r.Changed());
+ EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
+}
+
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionDeepContextChainFullRelaxForWith) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ const Operator* op = javascript()->CreateWithContext();
+ Node* const frame_state_1 =
+ ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* nested_context =
+ graph()->NewNode(op, graph()->start(), graph()->start(), outer_context,
+ frame_state_1, effect, control);
+ Node* const frame_state_2 =
+ ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state_2, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_TRUE(r.Changed());
+ EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
+}
+
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionDeepContextChainFullRelaxForBlock) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ const Operator* op = javascript()->CreateBlockContext();
+ Node* const frame_state_1 =
+ ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* nested_context =
+ graph()->NewNode(op, graph()->start(), graph()->start(), outer_context,
+ frame_state_1, effect, control);
+ Node* const frame_state_2 =
+ ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state_2, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_TRUE(r.Changed());
+ EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
+}
+
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionDeepContextChainPartialRelaxForScript) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ const Operator* op = javascript()->CreateScriptContext();
+ Node* const frame_state_1 =
+ ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* nested_context =
+ graph()->NewNode(op, graph()->start(), graph()->start(), outer_context,
+ frame_state_1, effect, control);
+ Node* const frame_state_2 =
+ ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state_2, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_TRUE(r.Changed());
+ EXPECT_EQ(nested_context, NodeProperties::GetContextInput(node));
+}
+
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionDeepContextChainPartialRelaxForModule) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ const Operator* op = javascript()->CreateModuleContext();
+ Node* const frame_state_1 =
+ ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* nested_context =
+ graph()->NewNode(op, graph()->start(), graph()->start(), outer_context,
+ frame_state_1, effect, control);
+ Node* const frame_state_2 =
+ ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state_2, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_TRUE(r.Changed());
+ EXPECT_EQ(nested_context, NodeProperties::GetContextInput(node));
+}
+
+
+TEST_F(JSContextRelaxationTest,
+ RelaxJSCallFunctionDeepContextChainPartialNoRelax) {
+ Node* const input0 = Parameter(0);
+ Node* const input1 = Parameter(1);
+ Node* const context = Parameter(2);
+ Node* const outer_context = Parameter(3);
+ const Operator* op = javascript()->CreateFunctionContext();
+ Node* const frame_state_1 =
+ ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Node* nested_context =
+ graph()->NewNode(op, graph()->start(), graph()->start(), outer_context,
+ frame_state_1, effect, control);
+ Node* const frame_state_2 =
+ ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
+ Node* node =
+ graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS,
+ STRICT, VectorSlotPair()),
+ input0, input1, context, frame_state_2, effect, control);
+ Reduction const r = Reduce(node);
+ EXPECT_FALSE(r.Changed());
+ EXPECT_EQ(context, NodeProperties::GetContextInput(node));
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc b/deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc
index d52242ec7d..251293ddcf 100644
--- a/deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc
+++ b/deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc
@@ -85,7 +85,7 @@ class JSTypeFeedbackTest : public TypedGraphTest {
Unique<Name> name = Unique<Name>::CreateUninitialized(
isolate()->factory()->InternalizeUtf8String(string));
const Operator* op = javascript()->LoadGlobal(name, feedback);
- Node* load = graph()->NewNode(op, global, vector, context);
+ Node* load = graph()->NewNode(op, context, global, vector, context);
if (mode == JSTypeFeedbackSpecializer::kDeoptimizationEnabled) {
for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op);
i++) {
diff --git a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc
index a12d79f02b..9d6cca3dbc 100644
--- a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc
+++ b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc
@@ -874,7 +874,11 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
}
-TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) {
+// -----------------------------------------------------------------------------
+// JSLoadGlobal
+
+
+TEST_F(JSTypedLoweringTest, JSLoadGlobalConstants) {
Handle<String> names[] = {
Handle<String>(isolate()->heap()->undefined_string(), isolate()),
Handle<String>(isolate()->heap()->infinity_string(), isolate()),
@@ -897,8 +901,8 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) {
for (size_t i = 0; i < arraysize(names); i++) {
Unique<Name> name = Unique<Name>::CreateImmovable(names[i]);
Reduction r = Reduce(graph()->NewNode(
- javascript()->LoadGlobal(name, feedback), global, vector, context,
- EmptyFrameState(), EmptyFrameState(), effect, control));
+ javascript()->LoadGlobal(name, feedback), context, global, vector,
+ context, EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), matches[i]);
@@ -907,6 +911,31 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) {
// -----------------------------------------------------------------------------
+// JSLoadNamed
+
+
+TEST_F(JSTypedLoweringTest, JSLoadNamedStringLength) {
+ VectorSlotPair feedback;
+ Unique<Name> name = Unique<Name>::CreateImmovable(factory()->length_string());
+ Node* const receiver = Parameter(Type::String(), 0);
+ Node* const vector = Parameter(Type::Internal(), 1);
+ Node* const context = UndefinedConstant();
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
+ Reduction const r = Reduce(
+ graph()->NewNode(javascript()->LoadNamed(name, feedback, language_mode),
+ receiver, vector, context, EmptyFrameState(),
+ EmptyFrameState(), effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsLoadField(AccessBuilder::ForStringLength(zone()), receiver,
+ effect, control));
+ }
+}
+
+
+// -----------------------------------------------------------------------------
// JSLoadDynamicGlobal
@@ -921,7 +950,8 @@ TEST_F(JSTypedLoweringTest, JSLoadDynamicGlobal) {
for (int i = 0; i < DynamicGlobalAccess::kMaxCheckDepth; ++i) {
uint32_t bitset = 1 << i; // Only single check.
Reduction r = Reduce(graph()->NewNode(
- javascript()->LoadDynamicGlobal(name, bitset, feedback, NOT_CONTEXTUAL),
+ javascript()->LoadDynamicGlobal(name, bitset, feedback,
+ NOT_INSIDE_TYPEOF),
vector, context, context, frame_state, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
@@ -974,7 +1004,6 @@ TEST_F(JSTypedLoweringTest, JSLoadDynamicContext) {
}
}
-#if V8_TURBOFAN_TARGET
// -----------------------------------------------------------------------------
// JSAdd
@@ -1074,8 +1103,6 @@ TEST_F(JSTypedLoweringTest, JSCreateLiteralObject) {
input0, input1, input2, _, context, frame_state, effect, control));
}
-#endif // V8_TURBOFAN_TARGET
-
// -----------------------------------------------------------------------------
// JSCreateWithContext
diff --git a/deps/v8/test/unittests/compiler/linkage-tail-call-unittest.cc b/deps/v8/test/unittests/compiler/linkage-tail-call-unittest.cc
new file mode 100644
index 0000000000..5d24a3bd1d
--- /dev/null
+++ b/deps/v8/test/unittests/compiler/linkage-tail-call-unittest.cc
@@ -0,0 +1,324 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/node.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+MachineType kMachineTypes[] = {kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
+ kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
+ kMachAnyTagged, kMachAnyTagged};
+}
+
+class LinkageTailCall : public TestWithZone {
+ protected:
+ CallDescriptor* NewStandardCallDescriptor(LocationSignature* locations) {
+ DCHECK(arraysize(kMachineTypes) >=
+ locations->return_count() + locations->parameter_count());
+ MachineSignature* types = new (zone()) MachineSignature(
+ locations->return_count(), locations->parameter_count(), kMachineTypes);
+ return new (zone())
+ CallDescriptor(CallDescriptor::kCallCodeObject, kMachAnyTagged,
+ LinkageLocation::ForAnyRegister(),
+ types, // machine_sig
+ locations, // location_sig
+ 0, // js_parameter_count
+ Operator::kNoProperties, // properties
+ 0, // callee-saved
+ 0, // callee-saved fp
+ CallDescriptor::kNoFlags, // flags,
+ "");
+ }
+
+ LinkageLocation StackLocation(int loc) {
+ return LinkageLocation::ForCallerFrameSlot(-loc);
+ }
+
+ LinkageLocation RegisterLocation(int loc) {
+ return LinkageLocation::ForRegister(loc);
+ }
+};
+
+
+TEST_F(LinkageTailCall, EmptyToEmpty) {
+ LocationSignature locations(0, 0, nullptr);
+ CallDescriptor* desc = NewStandardCallDescriptor(&locations);
+ CommonOperatorBuilder common(zone());
+ const Operator* op = common.Call(desc);
+ Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
+ EXPECT_TRUE(desc->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, SameReturn) {
+ // Caller
+ LinkageLocation location_array[] = {RegisterLocation(0)};
+ LocationSignature locations1(1, 0, location_array);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Callee
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
+
+ CommonOperatorBuilder common(zone());
+ const Operator* op = common.Call(desc2);
+ Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
+ EXPECT_TRUE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, DifferingReturn) {
+ // Caller
+ LinkageLocation location_array1[] = {RegisterLocation(0)};
+ LocationSignature locations1(1, 0, location_array1);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Callee
+ LinkageLocation location_array2[] = {RegisterLocation(1)};
+ LocationSignature locations2(1, 0, location_array2);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
+
+ CommonOperatorBuilder common(zone());
+ const Operator* op = common.Call(desc2);
+ Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
+ EXPECT_FALSE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, MoreRegisterParametersCallee) {
+ // Caller
+ LinkageLocation location_array1[] = {RegisterLocation(0)};
+ LocationSignature locations1(1, 0, location_array1);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Callee
+ LinkageLocation location_array2[] = {RegisterLocation(0),
+ RegisterLocation(0)};
+ LocationSignature locations2(1, 1, location_array2);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
+
+ CommonOperatorBuilder common(zone());
+ const Operator* op = common.Call(desc2);
+ Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
+ EXPECT_TRUE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, MoreRegisterParametersCaller) {
+ // Caller
+ LinkageLocation location_array1[] = {RegisterLocation(0),
+ RegisterLocation(0)};
+ LocationSignature locations1(1, 1, location_array1);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Callee
+ LinkageLocation location_array2[] = {RegisterLocation(0)};
+ LocationSignature locations2(1, 0, location_array2);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
+
+ CommonOperatorBuilder common(zone());
+ const Operator* op = common.Call(desc2);
+ Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
+ EXPECT_TRUE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, MoreRegisterAndStackParametersCallee) {
+ // Caller
+ LinkageLocation location_array1[] = {RegisterLocation(0)};
+ LocationSignature locations1(1, 0, location_array1);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Callee
+ LinkageLocation location_array2[] = {RegisterLocation(0), RegisterLocation(0),
+ RegisterLocation(1), StackLocation(1)};
+ LocationSignature locations2(1, 3, location_array2);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
+
+ CommonOperatorBuilder common(zone());
+ const Operator* op = common.Call(desc2);
+ Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
+ EXPECT_FALSE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, MoreRegisterAndStackParametersCaller) {
+ // Caller
+ LinkageLocation location_array[] = {RegisterLocation(0), RegisterLocation(0),
+ RegisterLocation(1), StackLocation(1)};
+ LocationSignature locations1(1, 3, location_array);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Callee
+ LinkageLocation location_array2[] = {RegisterLocation(0)};
+ LocationSignature locations2(1, 0, location_array2);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
+
+ CommonOperatorBuilder common(zone());
+ const Operator* op = common.Call(desc2);
+ Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
+ EXPECT_FALSE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, MatchingStackParameters) {
+ // Caller
+ LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
+ StackLocation(2), StackLocation(1)};
+ LocationSignature locations1(1, 3, location_array);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Caller
+ LocationSignature locations2(1, 3, location_array);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
+
+ CommonOperatorBuilder common(zone());
+ Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
+ Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
+ Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
+ Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
+ Node* parameters[] = {p0, p1, p2, p3};
+ const Operator* op = common.Call(desc2);
+ Node* const node =
+ Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
+ EXPECT_TRUE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, NonMatchingStackParameters) {
+ // Caller
+ LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
+ StackLocation(2), StackLocation(1)};
+ LocationSignature locations1(1, 3, location_array);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Caller
+ LocationSignature locations2(1, 3, location_array);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
+
+ CommonOperatorBuilder common(zone());
+ Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
+ Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
+ Node* p2 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
+ Node* p3 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
+ Node* parameters[] = {p0, p1, p2, p3};
+ const Operator* op = common.Call(desc2);
+ Node* const node =
+ Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
+ EXPECT_FALSE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, MatchingStackParametersExtraCallerRegisters) {
+ // Caller
+ LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
+ StackLocation(2), StackLocation(1),
+ RegisterLocation(0), RegisterLocation(1)};
+ LocationSignature locations1(1, 5, location_array);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Caller
+ LocationSignature locations2(1, 3, location_array);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
+
+ CommonOperatorBuilder common(zone());
+ Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
+ Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
+ Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
+ Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
+ Node* parameters[] = {p0, p1, p2, p3};
+ const Operator* op = common.Call(desc2);
+ Node* const node =
+ Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
+ EXPECT_TRUE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, MatchingStackParametersExtraCalleeRegisters) {
+ // Caller
+ LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
+ StackLocation(2), StackLocation(1),
+ RegisterLocation(0), RegisterLocation(1)};
+ LocationSignature locations1(1, 3, location_array);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Caller
+ LocationSignature locations2(1, 5, location_array);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
+
+ CommonOperatorBuilder common(zone());
+ Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
+ Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
+ Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
+ Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
+ Node* p4 = Node::New(zone(), 0, common.Parameter(3), 0, nullptr, false);
+ Node* parameters[] = {p0, p1, p2, p3, p4};
+ const Operator* op = common.Call(desc2);
+ Node* const node =
+ Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
+ EXPECT_TRUE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, MatchingStackParametersExtraCallerRegistersAndStack) {
+ // Caller
+ LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
+ StackLocation(2), StackLocation(1),
+ RegisterLocation(0), StackLocation(4)};
+ LocationSignature locations1(1, 5, location_array);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Caller
+ LocationSignature locations2(1, 3, location_array);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
+
+ CommonOperatorBuilder common(zone());
+ Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
+ Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
+ Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
+ Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
+ Node* p4 = Node::New(zone(), 0, common.Parameter(3), 0, nullptr, false);
+ Node* parameters[] = {p0, p1, p2, p3, p4};
+ const Operator* op = common.Call(desc2);
+ Node* const node =
+ Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
+ EXPECT_FALSE(desc1->CanTailCall(node));
+}
+
+
+TEST_F(LinkageTailCall, MatchingStackParametersExtraCalleeRegistersAndStack) {
+ // Caller
+ LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
+ StackLocation(2), RegisterLocation(0),
+ RegisterLocation(1), StackLocation(4)};
+ LocationSignature locations1(1, 3, location_array);
+ CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
+
+ // Caller
+ LocationSignature locations2(1, 5, location_array);
+ CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
+
+ CommonOperatorBuilder common(zone());
+ Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
+ Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
+ Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
+ Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
+ Node* p4 = Node::New(zone(), 0, common.Parameter(3), 0, nullptr, false);
+ Node* parameters[] = {p0, p1, p2, p3, p4};
+ const Operator* op = common.Call(desc2);
+ Node* const node =
+ Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
+ EXPECT_FALSE(desc1->CanTailCall(node));
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc
index 1e142550d5..3c94c25887 100644
--- a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc
+++ b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc
@@ -60,7 +60,7 @@ class LivenessAnalysisTest : public GraphTest {
const FrameStateFunctionInfo* state_info =
common()->CreateFrameStateFunctionInfo(
FrameStateType::kJavaScriptFunction, 0, locals_count_,
- Handle<SharedFunctionInfo>());
+ Handle<SharedFunctionInfo>(), CALL_MAINTAINS_NATIVE_CONTEXT);
const Operator* op = common()->FrameState(
BailoutId(ast_num), OutputFrameStateCombine::Ignore(), state_info);
diff --git a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc
index ce11fdef81..b14e9d392d 100644
--- a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc
+++ b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc
@@ -1438,6 +1438,55 @@ TEST_F(MachineOperatorReducerTest, Float64InsertHighWord32WithConstant) {
// -----------------------------------------------------------------------------
+// Float64Equal
+
+
+TEST_F(MachineOperatorReducerTest, Float64EqualWithFloat32Conversions) {
+ Node* const p0 = Parameter(0);
+ Node* const p1 = Parameter(1);
+ Reduction const r = Reduce(graph()->NewNode(
+ machine()->Float64Equal(),
+ graph()->NewNode(machine()->ChangeFloat32ToFloat64(), p0),
+ graph()->NewNode(machine()->ChangeFloat32ToFloat64(), p1)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsFloat32Equal(p0, p1));
+}
+
+
+// -----------------------------------------------------------------------------
+// Float64LessThan
+
+
+TEST_F(MachineOperatorReducerTest, Float64LessThanWithFloat32Conversions) {
+ Node* const p0 = Parameter(0);
+ Node* const p1 = Parameter(1);
+ Reduction const r = Reduce(graph()->NewNode(
+ machine()->Float64LessThan(),
+ graph()->NewNode(machine()->ChangeFloat32ToFloat64(), p0),
+ graph()->NewNode(machine()->ChangeFloat32ToFloat64(), p1)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsFloat32LessThan(p0, p1));
+}
+
+
+// -----------------------------------------------------------------------------
+// Float64LessThanOrEqual
+
+
+TEST_F(MachineOperatorReducerTest,
+ Float64LessThanOrEqualWithFloat32Conversions) {
+ Node* const p0 = Parameter(0);
+ Node* const p1 = Parameter(1);
+ Reduction const r = Reduce(graph()->NewNode(
+ machine()->Float64LessThanOrEqual(),
+ graph()->NewNode(machine()->ChangeFloat32ToFloat64(), p0),
+ graph()->NewNode(machine()->ChangeFloat32ToFloat64(), p1)));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsFloat32LessThanOrEqual(p0, p1));
+}
+
+
+// -----------------------------------------------------------------------------
// Store
diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc
index 520ce0159e..d097ee4b66 100644
--- a/deps/v8/test/unittests/compiler/node-test-utils.cc
+++ b/deps/v8/test/unittests/compiler/node-test-utils.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "src/assembler.h"
+#include "src/compiler/common-operator.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/simplified-operator.h"
@@ -1375,6 +1376,27 @@ class IsUnopMatcher final : public NodeMatcher {
const Matcher<Node*> input_matcher_;
};
+class IsParameterMatcher final : public NodeMatcher {
+ public:
+ explicit IsParameterMatcher(const Matcher<int>& index_matcher)
+ : NodeMatcher(IrOpcode::kParameter), index_matcher_(index_matcher) {}
+
+ void DescribeTo(std::ostream* os) const override {
+ *os << "is a Parameter node with index(";
+ index_matcher_.DescribeTo(os);
+ *os << ")";
+ }
+
+ bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
+ return (NodeMatcher::MatchAndExplain(node, listener) &&
+ PrintMatchAndExplain(ParameterIndexOf(node->op()), "index",
+ index_matcher_, listener));
+ }
+
+ private:
+ const Matcher<int> index_matcher_;
+};
+
} // namespace
@@ -1678,6 +1700,72 @@ Matcher<Node*> IsTailCall(
}
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ std::vector<Matcher<Node*>> value_matchers;
+ value_matchers.push_back(value0_matcher);
+ value_matchers.push_back(value1_matcher);
+ value_matchers.push_back(value2_matcher);
+ return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
+ effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ std::vector<Matcher<Node*>> value_matchers;
+ value_matchers.push_back(value0_matcher);
+ value_matchers.push_back(value1_matcher);
+ value_matchers.push_back(value2_matcher);
+ value_matchers.push_back(value3_matcher);
+ return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
+ effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& value4_matcher, const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ std::vector<Matcher<Node*>> value_matchers;
+ value_matchers.push_back(value0_matcher);
+ value_matchers.push_back(value1_matcher);
+ value_matchers.push_back(value2_matcher);
+ value_matchers.push_back(value3_matcher);
+ value_matchers.push_back(value4_matcher);
+ return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
+ effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ std::vector<Matcher<Node*>> value_matchers;
+ value_matchers.push_back(value0_matcher);
+ value_matchers.push_back(value1_matcher);
+ value_matchers.push_back(value2_matcher);
+ value_matchers.push_back(value3_matcher);
+ value_matchers.push_back(value4_matcher);
+ value_matchers.push_back(value5_matcher);
+ return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
+ effect_matcher, control_matcher));
+}
+
+
Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
@@ -1799,6 +1887,16 @@ Matcher<Node*> IsLoadContext(const Matcher<ContextAccess>& access_matcher,
}
+Matcher<Node*> IsParameter(const Matcher<int> index_matcher) {
+ return MakeMatcher(new IsParameterMatcher(index_matcher));
+}
+
+
+Matcher<Node*> IsLoadFramePointer() {
+ return MakeMatcher(new NodeMatcher(IrOpcode::kLoadFramePointer));
+}
+
+
#define IS_BINOP_MATCHER(Name) \
Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher, \
const Matcher<Node*>& rhs_matcher) { \
@@ -1830,8 +1928,13 @@ IS_BINOP_MATCHER(Int32MulHigh)
IS_BINOP_MATCHER(Int32LessThan)
IS_BINOP_MATCHER(Uint32LessThan)
IS_BINOP_MATCHER(Uint32LessThanOrEqual)
+IS_BINOP_MATCHER(Int64Add)
+IS_BINOP_MATCHER(Int64Sub)
IS_BINOP_MATCHER(Float32Max)
IS_BINOP_MATCHER(Float32Min)
+IS_BINOP_MATCHER(Float32Equal)
+IS_BINOP_MATCHER(Float32LessThan)
+IS_BINOP_MATCHER(Float32LessThanOrEqual)
IS_BINOP_MATCHER(Float64Max)
IS_BINOP_MATCHER(Float64Min)
IS_BINOP_MATCHER(Float64Sub)
diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h
index a64d9f009a..149dcfc439 100644
--- a/deps/v8/test/unittests/compiler/node-test-utils.h
+++ b/deps/v8/test/unittests/compiler/node-test-utils.h
@@ -134,6 +134,31 @@ Matcher<Node*> IsTailCall(
const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& value4_matcher, const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
+
Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
@@ -240,6 +265,10 @@ Matcher<Node*> IsUint32LessThan(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsUint32LessThanOrEqual(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt64Add(const Matcher<Node*>& lhs_matcher,
+ const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt64Sub(const Matcher<Node*>& lhs_matcher,
+ const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsChangeFloat64ToInt32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsChangeFloat64ToUint32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);
@@ -254,6 +283,12 @@ Matcher<Node*> IsFloat32Max(const Matcher<Node*>& lhs_matcher,
Matcher<Node*> IsFloat32Min(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsFloat32Abs(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat32Equal(const Matcher<Node*>& lhs_matcher,
+ const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat32LessThan(const Matcher<Node*>& lhs_matcher,
+ const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat32LessThanOrEqual(const Matcher<Node*>& lhs_matcher,
+ const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsFloat64Max(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsFloat64Min(const Matcher<Node*>& lhs_matcher,
@@ -279,6 +314,8 @@ Matcher<Node*> IsLoadContext(const Matcher<ContextAccess>& access_matcher,
const Matcher<Node*>& context_matcher);
Matcher<Node*> IsNumberToInt32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsParameter(const Matcher<int> index_matcher);
+Matcher<Node*> IsLoadFramePointer();
} // namespace compiler
} // namespace internal
diff --git a/deps/v8/test/unittests/compiler/ppc/OWNERS b/deps/v8/test/unittests/compiler/ppc/OWNERS
index a04d29a94f..eb007cb908 100644
--- a/deps/v8/test/unittests/compiler/ppc/OWNERS
+++ b/deps/v8/test/unittests/compiler/ppc/OWNERS
@@ -1,3 +1,4 @@
+jyan@ca.ibm.com
dstence@us.ibm.com
joransiu@ca.ibm.com
mbrandy@us.ibm.com
diff --git a/deps/v8/test/unittests/compiler/register-allocator-unittest.cc b/deps/v8/test/unittests/compiler/register-allocator-unittest.cc
index 873b4ecd2a..23a118b6ad 100644
--- a/deps/v8/test/unittests/compiler/register-allocator-unittest.cc
+++ b/deps/v8/test/unittests/compiler/register-allocator-unittest.cc
@@ -9,6 +9,75 @@ namespace v8 {
namespace internal {
namespace compiler {
+
+namespace {
+
+// We can't just use the size of the moves collection, because of
+// redundant moves which need to be discounted.
+int GetMoveCount(const ParallelMove& moves) {
+ int move_count = 0;
+ for (auto move : moves) {
+ if (move->IsEliminated() || move->IsRedundant()) continue;
+ ++move_count;
+ }
+ return move_count;
+}
+
+
+bool AreOperandsOfSameType(
+ const AllocatedOperand& op,
+ const InstructionSequenceTest::TestOperand& test_op) {
+ bool test_op_is_reg =
+ (test_op.type_ ==
+ InstructionSequenceTest::TestOperandType::kFixedRegister ||
+ test_op.type_ == InstructionSequenceTest::TestOperandType::kRegister);
+
+ return (op.IsRegister() && test_op_is_reg) ||
+ (op.IsStackSlot() && !test_op_is_reg);
+}
+
+
+bool AllocatedOperandMatches(
+ const AllocatedOperand& op,
+ const InstructionSequenceTest::TestOperand& test_op) {
+ return AreOperandsOfSameType(op, test_op) &&
+ (op.index() == test_op.value_ ||
+ test_op.value_ == InstructionSequenceTest::kNoValue);
+}
+
+
+int GetParallelMoveCount(int instr_index, Instruction::GapPosition gap_pos,
+ const InstructionSequence* sequence) {
+ const ParallelMove* moves =
+ sequence->InstructionAt(instr_index)->GetParallelMove(gap_pos);
+ if (moves == nullptr) return 0;
+ return GetMoveCount(*moves);
+}
+
+
+bool IsParallelMovePresent(int instr_index, Instruction::GapPosition gap_pos,
+ const InstructionSequence* sequence,
+ const InstructionSequenceTest::TestOperand& src,
+ const InstructionSequenceTest::TestOperand& dest) {
+ const ParallelMove* moves =
+ sequence->InstructionAt(instr_index)->GetParallelMove(gap_pos);
+ EXPECT_NE(nullptr, moves);
+
+ bool found_match = false;
+ for (auto move : *moves) {
+ if (move->IsEliminated() || move->IsRedundant()) continue;
+ if (AllocatedOperandMatches(AllocatedOperand::cast(move->source()), src) &&
+ AllocatedOperandMatches(AllocatedOperand::cast(move->destination()),
+ dest)) {
+ found_match = true;
+ break;
+ }
+ }
+ return found_match;
+}
+}
+
+
class RegisterAllocatorTest : public InstructionSequenceTest {
public:
void Allocate() {
@@ -492,6 +561,144 @@ TEST_F(RegisterAllocatorTest, RegressionLoadConstantBeforeSpill) {
}
+TEST_F(RegisterAllocatorTest, DiamondWithCallFirstBlock) {
+ StartBlock();
+ auto x = EmitOI(Reg(0));
+ EndBlock(Branch(Reg(x), 1, 2));
+
+ StartBlock();
+ EmitCall(Slot(-1));
+ auto occupy = EmitOI(Reg(0));
+ EndBlock(Jump(2));
+
+ StartBlock();
+ EndBlock(FallThrough());
+
+ StartBlock();
+ Use(occupy);
+ Return(Reg(x));
+ EndBlock();
+ Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, DiamondWithCallSecondBlock) {
+ StartBlock();
+ auto x = EmitOI(Reg(0));
+ EndBlock(Branch(Reg(x), 1, 2));
+
+ StartBlock();
+ EndBlock(Jump(2));
+
+ StartBlock();
+ EmitCall(Slot(-1));
+ auto occupy = EmitOI(Reg(0));
+ EndBlock(FallThrough());
+
+ StartBlock();
+ Use(occupy);
+ Return(Reg(x));
+ EndBlock();
+ Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SingleDeferredBlockSpill) {
+ StartBlock(); // B0
+ auto var = EmitOI(Reg(0));
+ EndBlock(Branch(Reg(var), 1, 2));
+
+ StartBlock(); // B1
+ EndBlock(Jump(2));
+
+ StartBlock(true); // B2
+ EmitCall(Slot(-1), Slot(var));
+ EndBlock();
+
+ StartBlock(); // B3
+ EmitNop();
+ EndBlock();
+
+ StartBlock(); // B4
+ Return(Reg(var, 0));
+ EndBlock();
+
+ Allocate();
+
+ const int var_def_index = 1;
+ const int call_index = 3;
+ int expect_no_moves =
+ FLAG_turbo_preprocess_ranges ? var_def_index : call_index;
+ int expect_spill_move =
+ FLAG_turbo_preprocess_ranges ? call_index : var_def_index;
+
+ // We should have no parallel moves at the "expect_no_moves" position.
+ EXPECT_EQ(
+ 0, GetParallelMoveCount(expect_no_moves, Instruction::START, sequence()));
+
+ // The spill should be performed at the position expect_spill_move.
+ EXPECT_TRUE(IsParallelMovePresent(expect_spill_move, Instruction::START,
+ sequence(), Reg(0), Slot(0)));
+}
+
+
+TEST_F(RegisterAllocatorTest, MultipleDeferredBlockSpills) {
+ if (!FLAG_turbo_preprocess_ranges) return;
+
+ StartBlock(); // B0
+ auto var1 = EmitOI(Reg(0));
+ auto var2 = EmitOI(Reg(1));
+ auto var3 = EmitOI(Reg(2));
+ EndBlock(Branch(Reg(var1, 0), 1, 2));
+
+ StartBlock(true); // B1
+ EmitCall(Slot(-2), Slot(var1));
+ EndBlock(Jump(2));
+
+ StartBlock(true); // B2
+ EmitCall(Slot(-1), Slot(var2));
+ EndBlock();
+
+ StartBlock(); // B3
+ EmitNop();
+ EndBlock();
+
+ StartBlock(); // B4
+ Return(Reg(var3, 2));
+ EndBlock();
+
+ const int def_of_v2 = 3;
+ const int call_in_b1 = 4;
+ const int call_in_b2 = 6;
+ const int end_of_b1 = 5;
+ const int end_of_b2 = 7;
+ const int start_of_b3 = 8;
+
+ Allocate();
+ // TODO(mtrofin): at the moment, the linear allocator spills var1 and var2,
+ // so only var3 is spilled in deferred blocks. Greedy avoids spilling 1&2.
+ // Expand the test once greedy is back online with this facility.
+ const int var3_reg = 2;
+ const int var3_slot = 2;
+
+ EXPECT_FALSE(IsParallelMovePresent(def_of_v2, Instruction::START, sequence(),
+ Reg(var3_reg), Slot()));
+ EXPECT_TRUE(IsParallelMovePresent(call_in_b1, Instruction::START, sequence(),
+ Reg(var3_reg), Slot(var3_slot)));
+ EXPECT_TRUE(IsParallelMovePresent(end_of_b1, Instruction::START, sequence(),
+ Slot(var3_slot), Reg()));
+
+ EXPECT_TRUE(IsParallelMovePresent(call_in_b2, Instruction::START, sequence(),
+ Reg(var3_reg), Slot(var3_slot)));
+ EXPECT_TRUE(IsParallelMovePresent(end_of_b2, Instruction::START, sequence(),
+ Slot(var3_slot), Reg()));
+
+
+ EXPECT_EQ(0,
+ GetParallelMoveCount(start_of_b3, Instruction::START, sequence()));
+}
+
+
namespace {
enum class ParameterType { kFixedSlot, kSlot, kRegister, kFixedRegister };
diff --git a/deps/v8/test/unittests/compiler/scheduler-unittest.cc b/deps/v8/test/unittests/compiler/scheduler-unittest.cc
index 45c636b27a..954541b721 100644
--- a/deps/v8/test/unittests/compiler/scheduler-unittest.cc
+++ b/deps/v8/test/unittests/compiler/scheduler-unittest.cc
@@ -215,7 +215,7 @@ TEST_F(SchedulerRPOTest, EntryLoop) {
TEST_F(SchedulerRPOTest, EndLoop) {
Schedule schedule(zone());
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
CheckRPONumbers(order, 3, true);
@@ -225,7 +225,7 @@ TEST_F(SchedulerRPOTest, EndLoop) {
TEST_F(SchedulerRPOTest, EndLoopNested) {
Schedule schedule(zone());
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
schedule.AddSuccessorForTesting(loop1->last(), schedule.start());
BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
@@ -406,8 +406,8 @@ TEST_F(SchedulerRPOTest, LoopNest2) {
TEST_F(SchedulerRPOTest, LoopFollow1) {
Schedule schedule(zone());
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1));
- SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1));
+ base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1));
BasicBlock* A = schedule.start();
BasicBlock* E = schedule.end();
@@ -427,8 +427,8 @@ TEST_F(SchedulerRPOTest, LoopFollow1) {
TEST_F(SchedulerRPOTest, LoopFollow2) {
Schedule schedule(zone());
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1));
- SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1));
+ base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1));
BasicBlock* A = schedule.start();
BasicBlock* S = schedule.NewBasicBlock();
@@ -451,8 +451,8 @@ TEST_F(SchedulerRPOTest, LoopFollowN) {
for (int size = 1; size < 5; size++) {
for (int exit = 0; exit < size; exit++) {
Schedule schedule(zone());
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
- SmartPointer<TestLoop> loop2(CreateLoop(&schedule, size));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
+ base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, size));
BasicBlock* A = schedule.start();
BasicBlock* E = schedule.end();
@@ -472,8 +472,8 @@ TEST_F(SchedulerRPOTest, LoopFollowN) {
TEST_F(SchedulerRPOTest, NestedLoopFollow1) {
Schedule schedule(zone());
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1));
- SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1));
+ base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1));
BasicBlock* A = schedule.start();
BasicBlock* B = schedule.NewBasicBlock();
@@ -506,7 +506,7 @@ TEST_F(SchedulerRPOTest, LoopBackedges1) {
BasicBlock* A = schedule.start();
BasicBlock* E = schedule.end();
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
schedule.AddSuccessorForTesting(A, loop1->header());
schedule.AddSuccessorForTesting(loop1->last(), E);
@@ -530,7 +530,7 @@ TEST_F(SchedulerRPOTest, LoopOutedges1) {
BasicBlock* D = schedule.NewBasicBlock();
BasicBlock* E = schedule.end();
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
schedule.AddSuccessorForTesting(A, loop1->header());
schedule.AddSuccessorForTesting(loop1->last(), E);
@@ -553,7 +553,7 @@ TEST_F(SchedulerRPOTest, LoopOutedges2) {
BasicBlock* A = schedule.start();
BasicBlock* E = schedule.end();
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
schedule.AddSuccessorForTesting(A, loop1->header());
schedule.AddSuccessorForTesting(loop1->last(), E);
@@ -576,7 +576,7 @@ TEST_F(SchedulerRPOTest, LoopOutloops1) {
Schedule schedule(zone());
BasicBlock* A = schedule.start();
BasicBlock* E = schedule.end();
- SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
+ base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
schedule.AddSuccessorForTesting(A, loop1->header());
schedule.AddSuccessorForTesting(loop1->last(), E);
diff --git a/deps/v8/test/unittests/compiler/tail-call-optimization-unittest.cc b/deps/v8/test/unittests/compiler/tail-call-optimization-unittest.cc
index 449299bb1d..7257cc9802 100644
--- a/deps/v8/test/unittests/compiler/tail-call-optimization-unittest.cc
+++ b/deps/v8/test/unittests/compiler/tail-call-optimization-unittest.cc
@@ -27,10 +27,11 @@ class TailCallOptimizationTest : public GraphTest {
TEST_F(TailCallOptimizationTest, CallCodeObject0) {
MachineType kMachineSignature[] = {kMachAnyTagged, kMachAnyTagged};
- LinkageLocation kLocationSignature[] = {LinkageLocation(0),
- LinkageLocation(1)};
+ LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
+ LinkageLocation::ForRegister(1)};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
- CallDescriptor::kCallCodeObject, kMachAnyTagged, LinkageLocation(0),
+ CallDescriptor::kCallCodeObject, kMachAnyTagged,
+ LinkageLocation::ForRegister(0),
new (zone()) MachineSignature(1, 1, kMachineSignature),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags);
@@ -47,10 +48,11 @@ TEST_F(TailCallOptimizationTest, CallCodeObject0) {
TEST_F(TailCallOptimizationTest, CallCodeObject1) {
MachineType kMachineSignature[] = {kMachAnyTagged, kMachAnyTagged};
- LinkageLocation kLocationSignature[] = {LinkageLocation(0),
- LinkageLocation(1)};
+ LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
+ LinkageLocation::ForRegister(1)};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
- CallDescriptor::kCallCodeObject, kMachAnyTagged, LinkageLocation(0),
+ CallDescriptor::kCallCodeObject, kMachAnyTagged,
+ LinkageLocation::ForRegister(0),
new (zone()) MachineSignature(1, 1, kMachineSignature),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
@@ -71,10 +73,11 @@ TEST_F(TailCallOptimizationTest, CallCodeObject1) {
TEST_F(TailCallOptimizationTest, CallCodeObject2) {
MachineType kMachineSignature[] = {kMachAnyTagged, kMachAnyTagged};
- LinkageLocation kLocationSignature[] = {LinkageLocation(0),
- LinkageLocation(1)};
+ LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
+ LinkageLocation::ForRegister(1)};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
- CallDescriptor::kCallCodeObject, kMachAnyTagged, LinkageLocation(0),
+ CallDescriptor::kCallCodeObject, kMachAnyTagged,
+ LinkageLocation::ForRegister(0),
new (zone()) MachineSignature(1, 1, kMachineSignature),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
@@ -93,10 +96,11 @@ TEST_F(TailCallOptimizationTest, CallCodeObject2) {
TEST_F(TailCallOptimizationTest, CallJSFunction0) {
MachineType kMachineSignature[] = {kMachAnyTagged, kMachAnyTagged};
- LinkageLocation kLocationSignature[] = {LinkageLocation(0),
- LinkageLocation(1)};
+ LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
+ LinkageLocation::ForRegister(1)};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
- CallDescriptor::kCallJSFunction, kMachAnyTagged, LinkageLocation(0),
+ CallDescriptor::kCallJSFunction, kMachAnyTagged,
+ LinkageLocation::ForRegister(0),
new (zone()) MachineSignature(1, 1, kMachineSignature),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags);
@@ -113,10 +117,11 @@ TEST_F(TailCallOptimizationTest, CallJSFunction0) {
TEST_F(TailCallOptimizationTest, CallJSFunction1) {
MachineType kMachineSignature[] = {kMachAnyTagged, kMachAnyTagged};
- LinkageLocation kLocationSignature[] = {LinkageLocation(0),
- LinkageLocation(1)};
+ LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
+ LinkageLocation::ForRegister(1)};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
- CallDescriptor::kCallJSFunction, kMachAnyTagged, LinkageLocation(0),
+ CallDescriptor::kCallJSFunction, kMachAnyTagged,
+ LinkageLocation::ForRegister(0),
new (zone()) MachineSignature(1, 1, kMachineSignature),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
@@ -137,10 +142,11 @@ TEST_F(TailCallOptimizationTest, CallJSFunction1) {
TEST_F(TailCallOptimizationTest, CallJSFunction2) {
MachineType kMachineSignature[] = {kMachAnyTagged, kMachAnyTagged};
- LinkageLocation kLocationSignature[] = {LinkageLocation(0),
- LinkageLocation(1)};
+ LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
+ LinkageLocation::ForRegister(1)};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
- CallDescriptor::kCallJSFunction, kMachAnyTagged, LinkageLocation(0),
+ CallDescriptor::kCallJSFunction, kMachAnyTagged,
+ LinkageLocation::ForRegister(0),
new (zone()) MachineSignature(1, 1, kMachineSignature),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);