diff options
Diffstat (limited to 'deps/v8/test/unittests')
39 files changed, 3266 insertions, 2731 deletions
diff --git a/deps/v8/test/unittests/base/bits-unittest.cc b/deps/v8/test/unittests/base/bits-unittest.cc index 9caba8484e..3d17a050db 100644 --- a/deps/v8/test/unittests/base/bits-unittest.cc +++ b/deps/v8/test/unittests/base/bits-unittest.cc @@ -255,6 +255,25 @@ TEST(Bits, SignedMod32) { } +TEST(Bits, UnsignedAddOverflow32) { + uint32_t val = 0; + EXPECT_FALSE(UnsignedAddOverflow32(0, 0, &val)); + EXPECT_EQ(0u, val); + EXPECT_TRUE( + UnsignedAddOverflow32(std::numeric_limits<uint32_t>::max(), 1u, &val)); + EXPECT_EQ(std::numeric_limits<uint32_t>::min(), val); + EXPECT_TRUE(UnsignedAddOverflow32(std::numeric_limits<uint32_t>::max(), + std::numeric_limits<uint32_t>::max(), + &val)); + TRACED_FORRANGE(uint32_t, i, 1, 50) { + TRACED_FORRANGE(uint32_t, j, 1, i) { + EXPECT_FALSE(UnsignedAddOverflow32(i, j, &val)); + EXPECT_EQ(i + j, val); + } + } +} + + TEST(Bits, UnsignedDiv32) { TRACED_FORRANGE(uint32_t, i, 0, 50) { EXPECT_EQ(0u, UnsignedDiv32(i, 0)); 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 744f18f0bd..7e67b31616 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 @@ -47,7 +47,7 @@ Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type, int64_t value) { switch (type) { case kMachInt32: - return m.Int32Constant(value); + return m.Int32Constant(static_cast<int32_t>(value)); break; case kMachInt64: @@ -642,7 +642,9 @@ TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) { if (shift.mi.machine_type != kMachInt32) continue; if (shift.mi.arch_opcode == kArm64Ror32) continue; - TRACED_FORRANGE(int, imm, 0, 31) { + // The available shift operand range is `0 <= imm < 32`, but we also test + // that immediates outside this range are handled properly (modulo-32). + TRACED_FORRANGE(int, imm, -32, 63) { StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); m.Return((m.Int32Add)( (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)), @@ -663,7 +665,9 @@ TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) { if (shift.mi.machine_type != kMachInt64) continue; if (shift.mi.arch_opcode == kArm64Ror) continue; - TRACED_FORRANGE(int, imm, 0, 63) { + // The available shift operand range is `0 <= imm < 64`, but we also test + // that immediates outside this range are handled properly (modulo-64). + TRACED_FORRANGE(int, imm, -64, 127) { StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); m.Return((m.Int64Add)( (m.*shift.mi.constructor)(m.Parameter(1), m.Int64Constant(imm)), @@ -1641,6 +1645,102 @@ TEST_F(InstructionSelectorTest, Int32MulWithImmediate) { EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); EXPECT_EQ(1U, s[0]->OutputCount()); } + // x * (2^k + 1) + c -> x + (x << k) + c + TRACED_FORRANGE(int32_t, k, 1, 30) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return( + m.Int32Add(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Add32, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // (2^k + 1) * x + c -> x + (x << k) + c + TRACED_FORRANGE(int32_t, k, 1, 30) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return( + m.Int32Add(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Add32, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // c + x * (2^k + 1) -> c + x + (x << k) + TRACED_FORRANGE(int32_t, k, 1, 30) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return( + m.Int32Add(m.Parameter(0), + m.Int32Mul(m.Parameter(1), m.Int32Constant((1 << k) + 1)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Add32, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // c + (2^k + 1) * x -> c + x + (x << k) + TRACED_FORRANGE(int32_t, k, 1, 30) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return( + m.Int32Add(m.Parameter(0), + m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Add32, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // c - x * (2^k + 1) -> c - x + (x << k) + TRACED_FORRANGE(int32_t, k, 1, 30) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return( + m.Int32Sub(m.Parameter(0), + m.Int32Mul(m.Parameter(1), m.Int32Constant((1 << k) + 1)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Sub32, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // c - (2^k + 1) * x -> c - x + (x << k) + TRACED_FORRANGE(int32_t, k, 1, 30) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return( + m.Int32Sub(m.Parameter(0), + m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Sub32, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } } @@ -1671,6 +1771,102 @@ TEST_F(InstructionSelectorTest, Int64MulWithImmediate) { EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); EXPECT_EQ(1U, s[0]->OutputCount()); } + // x * (2^k + 1) + c -> x + (x << k) + c + TRACED_FORRANGE(int64_t, k, 1, 62) { + StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); + m.Return( + m.Int64Add(m.Int64Mul(m.Parameter(0), m.Int64Constant((1L << k) + 1)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // (2^k + 1) * x + c -> x + (x << k) + c + TRACED_FORRANGE(int64_t, k, 1, 62) { + StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); + m.Return( + m.Int64Add(m.Int64Mul(m.Int64Constant((1L << k) + 1), m.Parameter(0)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // c + x * (2^k + 1) -> c + x + (x << k) + TRACED_FORRANGE(int64_t, k, 1, 62) { + StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); + m.Return( + m.Int64Add(m.Parameter(0), + m.Int64Mul(m.Parameter(1), m.Int64Constant((1L << k) + 1)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // c + (2^k + 1) * x -> c + x + (x << k) + TRACED_FORRANGE(int64_t, k, 1, 62) { + StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); + m.Return( + m.Int64Add(m.Parameter(0), + m.Int64Mul(m.Int64Constant((1L << k) + 1), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // c - x * (2^k + 1) -> c - x + (x << k) + TRACED_FORRANGE(int64_t, k, 1, 62) { + StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); + m.Return( + m.Int64Sub(m.Parameter(0), + m.Int64Mul(m.Parameter(1), m.Int64Constant((1L << k) + 1)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Sub, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } + // c - (2^k + 1) * x -> c - x + (x << k) + TRACED_FORRANGE(int64_t, k, 1, 62) { + StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64); + m.Return( + m.Int64Sub(m.Parameter(0), + m.Int64Mul(m.Int64Constant((1L << k) + 1), m.Parameter(1)))); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kArm64Sub, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(k, s.ToInt64(s[0]->InputAt(2))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } } @@ -2041,6 +2237,190 @@ TEST_F(InstructionSelectorTest, Word64EqualWithZero) { } +TEST_F(InstructionSelectorTest, Word32EqualWithWord32Shift) { + TRACED_FOREACH(Shift, shift, kShiftInstructions) { + // Skip non 32-bit shifts or ror operations. + if (shift.mi.machine_type != kMachInt32 || + shift.mi.arch_opcode == kArm64Ror32) { + continue; + } + + TRACED_FORRANGE(int32_t, imm, -32, 63) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = (m.*shift.mi.constructor)(p1, m.Int32Constant(imm)); + m.Return(m.Word32Equal(p0, r)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(shift.mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, 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(imm, s.ToInt32(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + TRACED_FORRANGE(int32_t, imm, -32, 63) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = (m.*shift.mi.constructor)(p1, m.Int32Constant(imm)); + m.Return(m.Word32Equal(r, p0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(shift.mode, s[0]->addressing_mode()); + ASSERT_EQ(3U, 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(imm, s.ToInt32(s[0]->InputAt(2))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + } +} + + +TEST_F(InstructionSelectorTest, Word32EqualWithUnsignedExtendByte) { + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = m.Word32And(p1, m.Int32Constant(0xff)); + m.Return(m.Word32Equal(p0, r)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); + 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = m.Word32And(p1, m.Int32Constant(0xff)); + m.Return(m.Word32Equal(r, p0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); + 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_F(InstructionSelectorTest, Word32EqualWithUnsignedExtendHalfword) { + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = m.Word32And(p1, m.Int32Constant(0xffff)); + m.Return(m.Word32Equal(p0, r)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); + 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = m.Word32And(p1, m.Int32Constant(0xffff)); + m.Return(m.Word32Equal(r, p0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); + 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_F(InstructionSelectorTest, Word32EqualWithSignedExtendByte) { + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = + m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(24)), m.Int32Constant(24)); + m.Return(m.Word32Equal(p0, r)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); + 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = + m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(24)), m.Int32Constant(24)); + m.Return(m.Word32Equal(r, p0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); + 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_F(InstructionSelectorTest, Word32EqualWithSignedExtendHalfword) { + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = + m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(16)), m.Int32Constant(16)); + m.Return(m.Word32Equal(p0, r)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); + 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* r = + m.Word32Sar(m.Word32Shl(p1, m.Int32Constant(16)), m.Int32Constant(16)); + m.Return(m.Word32Equal(r, p0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); + 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + } +} + + // ----------------------------------------------------------------------------- // Miscellaneous @@ -2202,14 +2582,17 @@ TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) { TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) { - TRACED_FORRANGE(int32_t, lsb, 1, 31) { + // The available shift operand range is `0 <= imm < 32`, but we also test + // that immediates outside this range are handled properly (modulo-32). + TRACED_FORRANGE(int32_t, shift, -32, 63) { + int32_t lsb = shift & 0x1f; TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { uint32_t jnk = rng()->NextInt(); - jnk >>= 32 - lsb; + jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0; uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk; StreamBuilder m(this, kMachInt32, kMachInt32); m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)), - m.Int32Constant(lsb))); + m.Int32Constant(shift))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode()); @@ -2218,14 +2601,15 @@ TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) { EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); } } - TRACED_FORRANGE(int32_t, lsb, 1, 31) { + TRACED_FORRANGE(int32_t, shift, -32, 63) { + int32_t lsb = shift & 0x1f; TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { uint32_t jnk = rng()->NextInt(); - jnk >>= 32 - lsb; + jnk = (lsb > 0) ? (jnk >> (32 - lsb)) : 0; uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk; StreamBuilder m(this, kMachInt32, kMachInt32); m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)), - m.Int32Constant(lsb))); + m.Int32Constant(shift))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode()); @@ -2238,15 +2622,18 @@ TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) { TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) { - TRACED_FORRANGE(int32_t, lsb, 1, 63) { + // The available shift operand range is `0 <= imm < 64`, but we also test + // that immediates outside this range are handled properly (modulo-64). + TRACED_FORRANGE(int32_t, shift, -64, 127) { + int32_t lsb = shift & 0x3f; TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) { uint64_t jnk = rng()->NextInt64(); - jnk >>= 64 - lsb; + jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0; uint64_t msk = ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk; StreamBuilder m(this, kMachInt64, kMachInt64); m.Return(m.Word64Shr(m.Word64And(m.Parameter(0), m.Int64Constant(msk)), - m.Int64Constant(lsb))); + m.Int64Constant(shift))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode()); @@ -2255,15 +2642,16 @@ TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) { EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2))); } } - TRACED_FORRANGE(int32_t, lsb, 1, 63) { + TRACED_FORRANGE(int32_t, shift, -64, 127) { + int32_t lsb = shift & 0x3f; TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) { uint64_t jnk = rng()->NextInt64(); - jnk >>= 64 - lsb; + jnk = (lsb > 0) ? (jnk >> (64 - lsb)) : 0; uint64_t msk = ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk; StreamBuilder m(this, kMachInt64, kMachInt64); m.Return(m.Word64Shr(m.Word64And(m.Int64Constant(msk), m.Parameter(0)), - m.Int64Constant(lsb))); + m.Int64Constant(shift))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode()); @@ -2276,11 +2664,14 @@ TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) { TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) { - TRACED_FORRANGE(int32_t, lsb, 1, 31) { + // The available shift operand range is `0 <= imm < 32`, but we also test + // that immediates outside this range are handled properly (modulo-32). + TRACED_FORRANGE(int32_t, shift, -32, 63) { + int32_t lsb = shift & 0x1f; TRACED_FORRANGE(int32_t, width, 1, 31) { uint32_t msk = (1 << width) - 1; StreamBuilder m(this, kMachInt32, kMachInt32); - m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)), + m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)), m.Int32Constant(msk))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); @@ -2291,12 +2682,14 @@ TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) { EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2))); } } - TRACED_FORRANGE(int32_t, lsb, 1, 31) { + TRACED_FORRANGE(int32_t, shift, -32, 63) { + int32_t lsb = shift & 0x1f; TRACED_FORRANGE(int32_t, width, 1, 31) { uint32_t msk = (1 << width) - 1; StreamBuilder m(this, kMachInt32, kMachInt32); - m.Return(m.Word32And(m.Int32Constant(msk), - m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)))); + m.Return( + m.Word32And(m.Int32Constant(msk), + m.Word32Shr(m.Parameter(0), m.Int32Constant(shift)))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode()); @@ -2310,11 +2703,14 @@ TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) { TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) { - TRACED_FORRANGE(int64_t, lsb, 1, 63) { + // The available shift operand range is `0 <= imm < 64`, but we also test + // that immediates outside this range are handled properly (modulo-64). + TRACED_FORRANGE(int64_t, shift, -64, 127) { + int64_t lsb = shift & 0x3f; TRACED_FORRANGE(int64_t, width, 1, 63) { uint64_t msk = (V8_UINT64_C(1) << width) - 1; StreamBuilder m(this, kMachInt64, kMachInt64); - m.Return(m.Word64And(m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb)), + m.Return(m.Word64And(m.Word64Shr(m.Parameter(0), m.Int64Constant(shift)), m.Int64Constant(msk))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); @@ -2325,12 +2721,14 @@ TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) { EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2))); } } - TRACED_FORRANGE(int64_t, lsb, 1, 63) { + TRACED_FORRANGE(int64_t, shift, -64, 127) { + int64_t lsb = shift & 0x3f; TRACED_FORRANGE(int64_t, width, 1, 63) { uint64_t msk = (V8_UINT64_C(1) << width) - 1; StreamBuilder m(this, kMachInt64, kMachInt64); - m.Return(m.Word64And(m.Int64Constant(msk), - m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb)))); + m.Return( + m.Word64And(m.Int64Constant(msk), + m.Word64Shr(m.Parameter(0), m.Int64Constant(shift)))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode()); @@ -2365,6 +2763,87 @@ TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) { } +TEST_F(InstructionSelectorTest, Int32MulHighWithSar) { + TRACED_FORRANGE(int32_t, shift, -32, 63) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const n = m.Word32Sar(m.Int32MulHigh(p0, p1), m.Int32Constant(shift)); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Smull, 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kArm64Asr, s[1]->arch_opcode()); + ASSERT_EQ(2U, s[1]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ((shift & 0x1f) + 32, s.ToInt64(s[1]->InputAt(1))); + ASSERT_EQ(1U, s[1]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output())); + } +} + + +TEST_F(InstructionSelectorTest, Int32MulHighWithAdd) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const a = m.Int32Add(m.Int32MulHigh(p0, p1), p0); + // Test only one shift constant here, as we're only interested in it being a + // 32-bit operation; the shift amount is irrelevant. + Node* const n = m.Word32Sar(a, m.Int32Constant(1)); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(3U, s.size()); + EXPECT_EQ(kArm64Smull, 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kArm64Add, s[1]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_ASR_I, s[1]->addressing_mode()); + ASSERT_EQ(3U, s[1]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1))); + EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(2))); + ASSERT_EQ(1U, s[1]->OutputCount()); + EXPECT_EQ(kArm64Asr32, s[2]->arch_opcode()); + ASSERT_EQ(2U, s[2]->InputCount()); + EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(0))); + EXPECT_EQ(1, s.ToInt64(s[2]->InputAt(1))); + ASSERT_EQ(1U, s[2]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[2]->Output())); +} + + +TEST_F(InstructionSelectorTest, Uint32MulHighWithShr) { + TRACED_FORRANGE(int32_t, shift, -32, 63) { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + Node* const n = + m.Word32Shr(m.Uint32MulHigh(p0, p1), m.Int32Constant(shift)); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(kArm64Umull, 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))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(kArm64Lsr, s[1]->arch_opcode()); + ASSERT_EQ(2U, s[1]->InputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ((shift & 0x1f) + 32, s.ToInt64(s[1]->InputAt(1))); + ASSERT_EQ(1U, s[1]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output())); + } +} + + TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) { TRACED_FORRANGE(int32_t, shift, 1, 31) { StreamBuilder m(this, kMachInt32, kMachInt32); @@ -2429,6 +2908,40 @@ TEST_F(InstructionSelectorTest, Word32ShrWithWord32Shl) { } +TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) { + TRACED_FORRANGE(int32_t, shift, 1, 30) { + StreamBuilder m(this, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Shl(m.Word32And(p0, m.Int32Constant((1 << (31 - shift)) - 1)), + m.Int32Constant(shift)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Ubfiz32, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } + TRACED_FORRANGE(int32_t, shift, 0, 30) { + StreamBuilder m(this, kMachInt32, kMachInt32); + Node* const p0 = m.Parameter(0); + Node* const r = + m.Word32Shl(m.Word32And(p0, m.Int32Constant((1 << (31 - shift)) - 1)), + m.Int32Constant(shift + 1)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Lsl32, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output())); + } +} + + TEST_F(InstructionSelectorTest, Word32Clz) { StreamBuilder m(this, kMachUint32, kMachUint32); Node* const p0 = m.Parameter(0); diff --git a/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc index d6822e8b09..13d2d6707a 100644 --- a/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc @@ -4,14 +4,16 @@ #include "src/compiler/common-operator.h" #include "src/compiler/common-operator-reducer.h" -#include "src/compiler/js-graph.h" -#include "src/compiler/js-operator.h" #include "src/compiler/machine-operator.h" #include "src/compiler/machine-type.h" #include "src/compiler/operator.h" +#include "src/compiler/simplified-operator.h" +#include "test/unittests/compiler/graph-reducer-unittest.h" #include "test/unittests/compiler/graph-unittest.h" #include "test/unittests/compiler/node-test-utils.h" +using testing::StrictMock; + namespace v8 { namespace internal { namespace compiler { @@ -19,23 +21,30 @@ namespace compiler { class CommonOperatorReducerTest : public GraphTest { public: explicit CommonOperatorReducerTest(int num_parameters = 1) - : GraphTest(num_parameters), machine_(zone()) {} + : GraphTest(num_parameters), machine_(zone()), simplified_(zone()) {} ~CommonOperatorReducerTest() override {} protected: - Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags = - MachineOperatorBuilder::kNoFlags) { - JSOperatorBuilder javascript(zone()); + Reduction Reduce( + AdvancedReducer::Editor* editor, Node* node, + MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags) { MachineOperatorBuilder machine(zone(), kMachPtr, flags); - JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine); - CommonOperatorReducer reducer(&jsgraph); + CommonOperatorReducer reducer(editor, graph(), common(), &machine); return reducer.Reduce(node); } + Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags = + MachineOperatorBuilder::kNoFlags) { + StrictMock<MockAdvancedReducerEditor> editor; + return Reduce(&editor, node, flags); + } + MachineOperatorBuilder* machine() { return &machine_; } + SimplifiedOperatorBuilder* simplified() { return &simplified_; } private: MachineOperatorBuilder machine_; + SimplifiedOperatorBuilder simplified_; }; @@ -58,32 +67,213 @@ const Operator kOp0(0, Operator::kNoProperties, "Op0", 0, 0, 0, 1, 1, 0); // ----------------------------------------------------------------------------- +// Branch + + +TEST_F(CommonOperatorReducerTest, BranchWithInt32ZeroConstant) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { + Node* const control = graph()->start(); + Node* const branch = + graph()->NewNode(common()->Branch(hint), Int32Constant(0), control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Replace(if_true, IsDead())); + EXPECT_CALL(editor, Replace(if_false, control)); + Reduction const r = Reduce(&editor, branch); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +TEST_F(CommonOperatorReducerTest, BranchWithInt32OneConstant) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { + Node* const control = graph()->start(); + Node* const branch = + graph()->NewNode(common()->Branch(hint), Int32Constant(1), control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Replace(if_true, control)); + EXPECT_CALL(editor, Replace(if_false, IsDead())); + Reduction const r = Reduce(&editor, branch); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +TEST_F(CommonOperatorReducerTest, BranchWithInt64ZeroConstant) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { + Node* const control = graph()->start(); + Node* const branch = + graph()->NewNode(common()->Branch(hint), Int64Constant(0), control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Replace(if_true, IsDead())); + EXPECT_CALL(editor, Replace(if_false, control)); + Reduction const r = Reduce(&editor, branch); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +TEST_F(CommonOperatorReducerTest, BranchWithInt64OneConstant) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { + Node* const control = graph()->start(); + Node* const branch = + graph()->NewNode(common()->Branch(hint), Int64Constant(1), control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Replace(if_true, control)); + EXPECT_CALL(editor, Replace(if_false, IsDead())); + Reduction const r = Reduce(&editor, branch); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +TEST_F(CommonOperatorReducerTest, BranchWithFalseConstant) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { + Node* const control = graph()->start(); + Node* const branch = + graph()->NewNode(common()->Branch(hint), FalseConstant(), control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Replace(if_true, IsDead())); + EXPECT_CALL(editor, Replace(if_false, control)); + Reduction const r = Reduce(&editor, branch); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +TEST_F(CommonOperatorReducerTest, BranchWithTrueConstant) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { + Node* const control = graph()->start(); + Node* const branch = + graph()->NewNode(common()->Branch(hint), TrueConstant(), control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Replace(if_true, control)); + EXPECT_CALL(editor, Replace(if_false, IsDead())); + Reduction const r = Reduce(&editor, branch); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +TEST_F(CommonOperatorReducerTest, BranchWithBooleanNot) { + Node* const value = Parameter(0); + TRACED_FOREACH(BranchHint, hint, kBranchHints) { + Node* const control = graph()->start(); + Node* const branch = graph()->NewNode( + common()->Branch(hint), + graph()->NewNode(simplified()->BooleanNot(), value), control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + Reduction const r = Reduce(branch); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(branch, r.replacement()); + EXPECT_THAT(branch, IsBranch(value, control)); + EXPECT_THAT(if_false, IsIfTrue(branch)); + EXPECT_THAT(if_true, IsIfFalse(branch)); + EXPECT_EQ(NegateBranchHint(hint), BranchHintOf(branch->op())); + } +} + + +// ----------------------------------------------------------------------------- +// Merge + + +TEST_F(CommonOperatorReducerTest, MergeOfUnusedDiamond0) { + Node* const value = Parameter(0); + Node* const control = graph()->start(); + Node* const branch = graph()->NewNode(common()->Branch(), value, control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + Reduction const r = + Reduce(graph()->NewNode(common()->Merge(2), if_true, if_false)); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(control, r.replacement()); + EXPECT_THAT(branch, IsDead()); +} + + +TEST_F(CommonOperatorReducerTest, MergeOfUnusedDiamond1) { + Node* const value = Parameter(0); + Node* const control = graph()->start(); + Node* const branch = graph()->NewNode(common()->Branch(), value, control); + Node* const if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* const if_false = graph()->NewNode(common()->IfFalse(), branch); + Reduction const r = + Reduce(graph()->NewNode(common()->Merge(2), if_false, if_true)); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(control, r.replacement()); + EXPECT_THAT(branch, IsDead()); +} + + +// ----------------------------------------------------------------------------- // EffectPhi -TEST_F(CommonOperatorReducerTest, RedundantEffectPhi) { +TEST_F(CommonOperatorReducerTest, EffectPhiWithMerge) { const int kMaxInputs = 64; Node* inputs[kMaxInputs]; Node* const input = graph()->NewNode(&kOp0); TRACED_FORRANGE(int, input_count, 2, kMaxInputs - 1) { int const value_input_count = input_count - 1; for (int i = 0; i < value_input_count; ++i) { + inputs[i] = graph()->start(); + } + Node* const merge = graph()->NewNode(common()->Merge(value_input_count), + value_input_count, inputs); + for (int i = 0; i < value_input_count; ++i) { inputs[i] = input; } - inputs[value_input_count] = graph()->start(); - Reduction r = Reduce(graph()->NewNode( - common()->EffectPhi(value_input_count), input_count, inputs)); + inputs[value_input_count] = merge; + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(merge)); + Reduction r = + Reduce(&editor, graph()->NewNode(common()->EffectPhi(value_input_count), + input_count, inputs)); ASSERT_TRUE(r.Changed()); EXPECT_EQ(input, r.replacement()); } } +TEST_F(CommonOperatorReducerTest, EffectPhiWithLoop) { + Node* const e0 = graph()->NewNode(&kOp0); + Node* const loop = + graph()->NewNode(common()->Loop(2), graph()->start(), graph()->start()); + loop->ReplaceInput(1, loop); + Node* const ephi = graph()->NewNode(common()->EffectPhi(2), e0, e0, loop); + ephi->ReplaceInput(1, ephi); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(loop)); + Reduction const r = Reduce(&editor, ephi); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(e0, r.replacement()); +} + + // ----------------------------------------------------------------------------- // Phi -TEST_F(CommonOperatorReducerTest, RedundantPhi) { +TEST_F(CommonOperatorReducerTest, PhiWithMerge) { const int kMaxInputs = 64; Node* inputs[kMaxInputs]; Node* const input = graph()->NewNode(&kOp0); @@ -93,14 +283,17 @@ TEST_F(CommonOperatorReducerTest, RedundantPhi) { for (int i = 0; i < value_input_count; ++i) { inputs[i] = graph()->start(); } - Node* merge = graph()->NewNode(common()->Merge(value_input_count), - value_input_count, inputs); + Node* const merge = graph()->NewNode(common()->Merge(value_input_count), + value_input_count, inputs); for (int i = 0; i < value_input_count; ++i) { inputs[i] = input; } inputs[value_input_count] = merge; - Reduction r = Reduce(graph()->NewNode( - common()->Phi(type, value_input_count), input_count, inputs)); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(merge)); + Reduction r = Reduce( + &editor, graph()->NewNode(common()->Phi(type, value_input_count), + input_count, inputs)); ASSERT_TRUE(r.Changed()); EXPECT_EQ(input, r.replacement()); } @@ -108,6 +301,22 @@ TEST_F(CommonOperatorReducerTest, RedundantPhi) { } +TEST_F(CommonOperatorReducerTest, PhiWithLoop) { + Node* const p0 = Parameter(0); + Node* const loop = + graph()->NewNode(common()->Loop(2), graph()->start(), graph()->start()); + loop->ReplaceInput(1, loop); + Node* const phi = + graph()->NewNode(common()->Phi(kMachAnyTagged, 2), p0, p0, loop); + phi->ReplaceInput(1, phi); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(loop)); + Reduction const r = Reduce(&editor, phi); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(p0, r.replacement()); +} + + TEST_F(CommonOperatorReducerTest, PhiToFloat32Abs) { Node* p0 = Parameter(0); Node* c0 = Float32Constant(0.0); @@ -120,7 +329,9 @@ TEST_F(CommonOperatorReducerTest, PhiToFloat32Abs) { Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); Node* phi = graph()->NewNode(common()->Phi(kMachFloat32, 2), vtrue, vfalse, merge); - Reduction r = Reduce(phi); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(merge)); + Reduction r = Reduce(&editor, phi); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFloat32Abs(p0)); } @@ -138,7 +349,9 @@ TEST_F(CommonOperatorReducerTest, PhiToFloat64Abs) { Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); Node* phi = graph()->NewNode(common()->Phi(kMachFloat64, 2), vtrue, vfalse, merge); - Reduction r = Reduce(phi); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(merge)); + Reduction r = Reduce(&editor, phi); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFloat64Abs(p0)); } @@ -153,7 +366,9 @@ TEST_F(CommonOperatorReducerTest, PhiToFloat32Max) { Node* if_false = graph()->NewNode(common()->IfFalse(), branch); Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); Node* phi = graph()->NewNode(common()->Phi(kMachFloat32, 2), p1, p0, merge); - Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat32Max); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(merge)); + Reduction r = Reduce(&editor, phi, MachineOperatorBuilder::kFloat32Max); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFloat32Max(p1, p0)); } @@ -168,7 +383,9 @@ TEST_F(CommonOperatorReducerTest, PhiToFloat64Max) { Node* if_false = graph()->NewNode(common()->IfFalse(), branch); Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); Node* phi = graph()->NewNode(common()->Phi(kMachFloat64, 2), p1, p0, merge); - Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat64Max); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(merge)); + Reduction r = Reduce(&editor, phi, MachineOperatorBuilder::kFloat64Max); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFloat64Max(p1, p0)); } @@ -183,7 +400,9 @@ TEST_F(CommonOperatorReducerTest, PhiToFloat32Min) { Node* if_false = graph()->NewNode(common()->IfFalse(), branch); Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); Node* phi = graph()->NewNode(common()->Phi(kMachFloat32, 2), p0, p1, merge); - Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat32Min); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(merge)); + Reduction r = Reduce(&editor, phi, MachineOperatorBuilder::kFloat32Min); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFloat32Min(p0, p1)); } @@ -198,17 +417,48 @@ TEST_F(CommonOperatorReducerTest, PhiToFloat64Min) { Node* if_false = graph()->NewNode(common()->IfFalse(), branch); Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); Node* phi = graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge); - Reduction r = Reduce(phi, MachineOperatorBuilder::kFloat64Min); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(merge)); + Reduction r = Reduce(&editor, phi, MachineOperatorBuilder::kFloat64Min); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFloat64Min(p0, p1)); } // ----------------------------------------------------------------------------- +// Return + + +TEST_F(CommonOperatorReducerTest, ReturnWithPhiAndEffectPhiAndMerge) { + Node* cond = Parameter(2); + Node* branch = graph()->NewNode(common()->Branch(), cond, graph()->start()); + Node* if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* etrue = graph()->start(); + Node* vtrue = Parameter(0); + Node* if_false = graph()->NewNode(common()->IfFalse(), branch); + Node* efalse = graph()->start(); + Node* vfalse = Parameter(1); + Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); + Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge); + Node* phi = + graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse, merge); + Node* ret = graph()->NewNode(common()->Return(), phi, ephi, merge); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Replace(merge, IsDead())); + Reduction const r = Reduce(&editor, ret); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + EXPECT_THAT(graph()->end(), IsEnd(ret, IsReturn(vtrue, etrue, if_true), + IsReturn(vfalse, efalse, if_false))); +} + + +// ----------------------------------------------------------------------------- // Select -TEST_F(CommonOperatorReducerTest, RedundantSelect) { +TEST_F(CommonOperatorReducerTest, SelectWithSameThenAndElse) { Node* const input = graph()->NewNode(&kOp0); TRACED_FOREACH(BranchHint, hint, kBranchHints) { TRACED_FOREACH(MachineType, type, kMachineTypes) { @@ -221,6 +471,50 @@ TEST_F(CommonOperatorReducerTest, RedundantSelect) { } +TEST_F(CommonOperatorReducerTest, SelectWithInt32ZeroConstant) { + Node* p0 = Parameter(0); + Node* p1 = Parameter(1); + Node* select = graph()->NewNode(common()->Select(kMachAnyTagged), + Int32Constant(0), p0, p1); + Reduction r = Reduce(select); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(p1, r.replacement()); +} + + +TEST_F(CommonOperatorReducerTest, SelectWithInt32OneConstant) { + Node* p0 = Parameter(0); + Node* p1 = Parameter(1); + Node* select = graph()->NewNode(common()->Select(kMachAnyTagged), + Int32Constant(1), p0, p1); + Reduction r = Reduce(select); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(p0, r.replacement()); +} + + +TEST_F(CommonOperatorReducerTest, SelectWithInt64ZeroConstant) { + Node* p0 = Parameter(0); + Node* p1 = Parameter(1); + Node* select = graph()->NewNode(common()->Select(kMachAnyTagged), + Int64Constant(0), p0, p1); + Reduction r = Reduce(select); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(p1, r.replacement()); +} + + +TEST_F(CommonOperatorReducerTest, SelectWithInt64OneConstant) { + Node* p0 = Parameter(0); + Node* p1 = Parameter(1); + Node* select = graph()->NewNode(common()->Select(kMachAnyTagged), + Int64Constant(1), p0, p1); + Reduction r = Reduce(select); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(p0, r.replacement()); +} + + TEST_F(CommonOperatorReducerTest, SelectWithFalseConstant) { Node* p0 = Parameter(0); Node* p1 = Parameter(1); diff --git a/deps/v8/test/unittests/compiler/common-operator-unittest.cc b/deps/v8/test/unittests/compiler/common-operator-unittest.cc index 4f4d9f70d0..8765c13271 100644 --- a/deps/v8/test/unittests/compiler/common-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/common-operator-unittest.cc @@ -48,15 +48,13 @@ const SharedOperator kSharedOperators[] = { value_input_count, effect_input_count, control_input_count, \ value_output_count, effect_output_count, control_output_count \ } - SHARED(Dead, Operator::kFoldable, 0, 0, 0, 0, 0, 1), - SHARED(End, Operator::kKontrol, 0, 0, 1, 0, 0, 0), + SHARED(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1), SHARED(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1), SHARED(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1), SHARED(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1), - SHARED(IfException, Operator::kKontrol, 0, 0, 1, 1, 0, 1), SHARED(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1), SHARED(Return, Operator::kNoThrow, 1, 1, 1, 0, 0, 1), - SHARED(Terminate, Operator::kNoThrow, 0, 1, 1, 0, 0, 1) + SHARED(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) #undef SHARED }; @@ -162,6 +160,9 @@ const double kDoubleValues[] = {-std::numeric_limits<double>::infinity(), std::numeric_limits<double>::signaling_NaN()}; +const size_t kInputCounts[] = {3, 4, 100, 255, 1024, 65000}; + + const int32_t kInt32Values[] = { std::numeric_limits<int32_t>::min(), -1914954528, -1698749618, -1578693386, -1577976073, -1573998034, -1529085059, -1499540537, -1299205097, @@ -176,14 +177,31 @@ const int32_t kInt32Values[] = { 2008792749, 2045320228, std::numeric_limits<int32_t>::max()}; -const BranchHint kHints[] = {BranchHint::kNone, BranchHint::kTrue, - BranchHint::kFalse}; +const BranchHint kBranchHints[] = {BranchHint::kNone, BranchHint::kTrue, + BranchHint::kFalse}; } // namespace +TEST_F(CommonOperatorTest, End) { + TRACED_FOREACH(size_t, input_count, kInputCounts) { + const Operator* const op = common()->End(input_count); + EXPECT_EQ(IrOpcode::kEnd, op->opcode()); + EXPECT_EQ(Operator::kKontrol, op->properties()); + EXPECT_EQ(0, op->ValueInputCount()); + EXPECT_EQ(0, op->EffectInputCount()); + EXPECT_EQ(input_count, static_cast<uint32_t>(op->ControlInputCount())); + EXPECT_EQ(input_count, static_cast<uint32_t>( + OperatorProperties::GetTotalInputCount(op))); + EXPECT_EQ(0, op->ValueOutputCount()); + EXPECT_EQ(0, op->EffectOutputCount()); + EXPECT_EQ(0, op->ControlOutputCount()); + } +} + + TEST_F(CommonOperatorTest, Branch) { - TRACED_FOREACH(BranchHint, hint, kHints) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { const Operator* const op = common()->Branch(hint); EXPECT_EQ(IrOpcode::kBranch, op->opcode()); EXPECT_EQ(Operator::kKontrol, op->properties()); @@ -199,6 +217,24 @@ TEST_F(CommonOperatorTest, Branch) { } +TEST_F(CommonOperatorTest, IfException) { + static const IfExceptionHint kIfExceptionHints[] = { + IfExceptionHint::kLocallyCaught, IfExceptionHint::kLocallyUncaught}; + TRACED_FOREACH(IfExceptionHint, hint, kIfExceptionHints) { + const Operator* const op = common()->IfException(hint); + EXPECT_EQ(IrOpcode::kIfException, op->opcode()); + EXPECT_EQ(Operator::kKontrol, op->properties()); + EXPECT_EQ(0, op->ValueInputCount()); + EXPECT_EQ(1, op->EffectInputCount()); + EXPECT_EQ(1, op->ControlInputCount()); + EXPECT_EQ(2, OperatorProperties::GetTotalInputCount(op)); + EXPECT_EQ(1, op->ValueOutputCount()); + EXPECT_EQ(1, op->EffectOutputCount()); + EXPECT_EQ(1, op->ControlOutputCount()); + } +} + + TEST_F(CommonOperatorTest, Switch) { TRACED_FOREACH(size_t, cases, kCases) { const Operator* const op = common()->Switch(cases); @@ -238,7 +274,7 @@ TEST_F(CommonOperatorTest, Select) { kMachInt32, kMachUint32, kMachInt64, kMachUint64, kMachFloat32, kMachFloat64, kMachAnyTagged}; TRACED_FOREACH(MachineType, type, kTypes) { - TRACED_FOREACH(BranchHint, hint, kHints) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { const Operator* const op = common()->Select(type, hint); EXPECT_EQ(IrOpcode::kSelect, op->opcode()); EXPECT_EQ(Operator::kPure, op->properties()); diff --git a/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc b/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc index 515bd061ef..47be5407f7 100644 --- a/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc +++ b/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc @@ -27,7 +27,7 @@ class ControlEquivalenceTest : public GraphTest { protected: void ComputeEquivalence(Node* node) { - graph()->SetEnd(graph()->NewNode(common()->End(), node)); + graph()->SetEnd(graph()->NewNode(common()->End(1), node)); if (FLAG_trace_turbo) { OFStream os(stdout); os << AsDOT(*graph()); @@ -41,7 +41,7 @@ class ControlEquivalenceTest : public GraphTest { } bool IsEquivalenceClass(size_t length, Node** nodes) { - BitVector in_class(graph()->NodeCount(), zone()); + BitVector in_class(static_cast<int>(graph()->NodeCount()), zone()); size_t expected_class = classes_[nodes[0]->id()]; for (size_t i = 0; i < length; ++i) { in_class.Add(nodes[i]->id()); @@ -79,7 +79,7 @@ class ControlEquivalenceTest : public GraphTest { } Node* End(Node* control) { - return Store(graph()->NewNode(common()->End(), control)); + return Store(graph()->NewNode(common()->End(1), control)); } private: diff --git a/deps/v8/test/unittests/compiler/control-flow-optimizer-unittest.cc b/deps/v8/test/unittests/compiler/control-flow-optimizer-unittest.cc index 190930edac..444f5f5fee 100644 --- a/deps/v8/test/unittests/compiler/control-flow-optimizer-unittest.cc +++ b/deps/v8/test/unittests/compiler/control-flow-optimizer-unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "src/compiler/control-flow-optimizer.h" -#include "src/compiler/js-graph.h" #include "src/compiler/js-operator.h" #include "src/compiler/machine-operator.h" #include "test/unittests/compiler/graph-unittest.h" @@ -21,28 +20,21 @@ namespace compiler { class ControlFlowOptimizerTest : public GraphTest { public: explicit ControlFlowOptimizerTest(int num_parameters = 3) - : GraphTest(num_parameters), - machine_(zone()), - javascript_(zone()), - jsgraph_(isolate(), graph(), common(), javascript(), machine()) {} + : GraphTest(num_parameters), machine_(zone()), javascript_(zone()) {} ~ControlFlowOptimizerTest() override {} protected: void Optimize() { - ControlFlowOptimizer optimizer(jsgraph(), zone()); + ControlFlowOptimizer optimizer(graph(), common(), machine(), zone()); optimizer.Optimize(); } - Node* EmptyFrameState() { return jsgraph()->EmptyFrameState(); } - - JSGraph* jsgraph() { return &jsgraph_; } JSOperatorBuilder* javascript() { return &javascript_; } MachineOperatorBuilder* machine() { return &machine_; } private: MachineOperatorBuilder machine_; JSOperatorBuilder javascript_; - JSGraph jsgraph_; }; @@ -62,7 +54,7 @@ TEST_F(ControlFlowOptimizerTest, BuildSwitch1) { Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); Node* merge = graph()->NewNode(common()->Merge(3), if_true0, if_true1, if_false1); - graph()->SetEnd(graph()->NewNode(common()->End(), merge)); + graph()->SetEnd(graph()->NewNode(common()->End(1), merge)); Optimize(); Capture<Node*> switch_capture; EXPECT_THAT(end(), @@ -77,7 +69,7 @@ TEST_F(ControlFlowOptimizerTest, BuildSwitch2) { Node* input = Parameter(0); Node* context = Parameter(1); Node* index = graph()->NewNode(javascript()->ToNumber(), input, context, - EmptyFrameState(), start(), start()); + start(), start(), start()); Node* if_success = graph()->NewNode(common()->IfSuccess(), index); Node* branch0 = graph()->NewNode( common()->Branch(), @@ -93,7 +85,7 @@ TEST_F(ControlFlowOptimizerTest, BuildSwitch2) { Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); Node* merge = graph()->NewNode(common()->Merge(3), if_true0, if_true1, if_false1); - graph()->SetEnd(graph()->NewNode(common()->End(), merge)); + graph()->SetEnd(graph()->NewNode(common()->End(1), merge)); Optimize(); Capture<Node*> switch_capture; EXPECT_THAT( @@ -119,7 +111,7 @@ TEST_F(ControlFlowOptimizerTest, CloneBranch) { Node* if_true = graph()->NewNode(common()->IfTrue(), branch); Node* if_false = graph()->NewNode(common()->IfFalse(), branch); Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); - graph()->SetEnd(graph()->NewNode(common()->End(), merge)); + graph()->SetEnd(graph()->NewNode(common()->End(1), merge)); Optimize(); Capture<Node*> branch1_capture, branch2_capture; EXPECT_THAT( diff --git a/deps/v8/test/unittests/compiler/control-reducer-unittest.cc b/deps/v8/test/unittests/compiler/control-reducer-unittest.cc deleted file mode 100644 index 2f65caadc3..0000000000 --- a/deps/v8/test/unittests/compiler/control-reducer-unittest.cc +++ /dev/null @@ -1,326 +0,0 @@ -// 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/control-reducer.h" -#include "src/compiler/diamond.h" -#include "src/compiler/graph-visualizer.h" -#include "src/compiler/js-graph.h" -#include "src/compiler/js-operator.h" -#include "src/compiler/machine-operator.h" -#include "src/compiler/node.h" -#include "test/unittests/compiler/graph-unittest.h" -#include "test/unittests/compiler/node-test-utils.h" -#include "testing/gmock-support.h" - -using testing::_; -using testing::AllOf; -using testing::Capture; -using testing::CaptureEq; - -namespace v8 { -namespace internal { -namespace compiler { - -class ControlReducerTest : public TypedGraphTest { - public: - ControlReducerTest() - : TypedGraphTest(1), - machine_(zone()), - javascript_(zone()), - jsgraph_(isolate(), graph(), common(), &javascript_, &machine_) {} - - protected: - MachineOperatorBuilder machine_; - JSOperatorBuilder javascript_; - JSGraph jsgraph_; - - void ReduceGraph(int max_phis_for_select = 0) { - if (FLAG_trace_turbo_graph) { - OFStream os(stdout); - os << "-- Graph before control reduction" << std::endl; - os << AsRPO(*graph()); - } - ControlReducer::ReduceGraph(zone(), jsgraph(), max_phis_for_select); - if (FLAG_trace_turbo_graph) { - OFStream os(stdout); - os << "-- Graph after control reduction" << std::endl; - os << AsRPO(*graph()); - } - } - - JSGraph* jsgraph() { return &jsgraph_; } -}; - - -TEST_F(ControlReducerTest, NonTerminatingLoop) { - Node* loop = graph()->NewNode(common()->Loop(2), graph()->start()); - loop->AppendInput(graph()->zone(), loop); - ReduceGraph(); - EXPECT_THAT( - graph()->end(), - IsEnd(IsMerge(graph()->start(), - IsTerminate(graph()->start(), - AllOf(loop, IsLoop(graph()->start(), loop)))))); -} - - -TEST_F(ControlReducerTest, NonTerminatingLoopWithEffectPhi) { - Node* loop = graph()->NewNode(common()->Loop(2), graph()->start()); - loop->AppendInput(graph()->zone(), loop); - Node* ephi = graph()->NewNode(common()->EffectPhi(2), graph()->start()); - ephi->AppendInput(graph()->zone(), ephi); - ephi->AppendInput(graph()->zone(), loop); - ReduceGraph(); - EXPECT_THAT( - graph()->end(), - IsEnd(IsMerge( - graph()->start(), - IsTerminate(AllOf(ephi, IsEffectPhi(graph()->start(), ephi, loop)), - AllOf(loop, IsLoop(graph()->start(), loop)))))); -} - - -TEST_F(ControlReducerTest, NonTerminatingLoopWithTwoEffectPhis) { - Node* loop = graph()->NewNode(common()->Loop(2), graph()->start()); - loop->AppendInput(graph()->zone(), loop); - Node* ephi1 = graph()->NewNode(common()->EffectPhi(2), graph()->start()); - ephi1->AppendInput(graph()->zone(), ephi1); - ephi1->AppendInput(graph()->zone(), loop); - Node* ephi2 = graph()->NewNode(common()->EffectPhi(2), graph()->start()); - ephi2->AppendInput(graph()->zone(), ephi2); - ephi2->AppendInput(graph()->zone(), loop); - ReduceGraph(); - EXPECT_THAT( - graph()->end(), - IsEnd(IsMerge( - graph()->start(), - IsTerminate( - IsEffectSet( - AllOf(ephi1, IsEffectPhi(graph()->start(), ephi1, loop)), - AllOf(ephi2, IsEffectPhi(graph()->start(), ephi2, loop))), - AllOf(loop, IsLoop(graph()->start(), loop)))))); -} - - -TEST_F(ControlReducerTest, NonTerminatingLoopWithDeadEnd) { - Node* loop = graph()->NewNode(common()->Loop(2), graph()->start()); - loop->AppendInput(graph()->zone(), loop); - graph()->end()->ReplaceInput(0, graph()->NewNode(common()->Dead())); - ReduceGraph(); - EXPECT_THAT(graph()->end(), - IsEnd(IsTerminate(graph()->start(), - AllOf(loop, IsLoop(graph()->start(), loop))))); -} - - -TEST_F(ControlReducerTest, PhiAsInputToBranch_true) { - Node* p0 = Parameter(0); - Node* branch1 = graph()->NewNode(common()->Branch(), p0, graph()->start()); - Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); - Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); - Node* merge1 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); - Node* phi1 = graph()->NewNode(common()->Phi(kMachInt32, 2), - jsgraph()->Int32Constant(1), - jsgraph()->Int32Constant(2), merge1); - - Node* branch2 = graph()->NewNode(common()->Branch(), phi1, merge1); - Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); - Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); - Node* merge2 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); - Node* result = graph()->NewNode(common()->Phi(kMachInt32, 2), - jsgraph()->Int32Constant(11), - jsgraph()->Int32Constant(22), merge2); - - Node* ret = - graph()->NewNode(common()->Return(), result, graph()->start(), merge2); - graph()->end()->ReplaceInput(0, ret); - - ReduceGraph(); - - // First diamond is not reduced. - EXPECT_THAT(merge1, IsMerge(IsIfTrue(branch1), IsIfFalse(branch1))); - - // Second diamond should be folded away. - EXPECT_THAT(graph()->end(), - IsEnd(IsReturn(IsInt32Constant(11), graph()->start(), merge1))); -} - - -TEST_F(ControlReducerTest, PhiAsInputToBranch_false) { - Node* p0 = Parameter(0); - Node* branch1 = graph()->NewNode(common()->Branch(), p0, graph()->start()); - Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); - Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); - Node* merge1 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); - Node* phi1 = graph()->NewNode(common()->Phi(kMachInt32, 2), - jsgraph()->Int32Constant(0), - jsgraph()->BooleanConstant(false), merge1); - - Node* branch2 = graph()->NewNode(common()->Branch(), phi1, merge1); - Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); - Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); - Node* merge2 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); - Node* result = graph()->NewNode(common()->Phi(kMachInt32, 2), - jsgraph()->Int32Constant(11), - jsgraph()->Int32Constant(22), merge2); - - Node* ret = - graph()->NewNode(common()->Return(), result, graph()->start(), merge2); - graph()->end()->ReplaceInput(0, ret); - - ReduceGraph(); - - // First diamond is not reduced. - EXPECT_THAT(merge1, IsMerge(IsIfTrue(branch1), IsIfFalse(branch1))); - - // Second diamond should be folded away. - EXPECT_THAT(graph()->end(), - IsEnd(IsReturn(IsInt32Constant(22), graph()->start(), merge1))); -} - - -TEST_F(ControlReducerTest, PhiAsInputToBranch_unknown_true) { - Node* p0 = Parameter(0); - Node* phi0 = graph()->NewNode(common()->Phi(kMachInt32, 2), p0, - jsgraph()->Int32Constant(1), graph()->start()); - Node* branch1 = graph()->NewNode(common()->Branch(), phi0, graph()->start()); - Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); - Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); - Node* merge1 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); - Node* phi1 = graph()->NewNode(common()->Phi(kMachInt32, 2), - jsgraph()->Int32Constant(111), - jsgraph()->Int32Constant(222), merge1); - - Node* ret = - graph()->NewNode(common()->Return(), phi1, graph()->start(), merge1); - graph()->end()->ReplaceInput(0, ret); - - ReduceGraph(); - - // Branch should not be folded. - EXPECT_THAT(phi1, - IsPhi(kMachInt32, IsInt32Constant(111), IsInt32Constant(222), - IsMerge(IsIfTrue(branch1), IsIfFalse(branch1)))); - EXPECT_THAT(graph()->end(), IsEnd(IsReturn(phi1, graph()->start(), merge1))); -} - - -TEST_F(ControlReducerTest, RangeAsInputToBranch_true1) { - Node* p0 = Parameter(Type::Range(1, 2, zone()), 0); - Node* branch1 = graph()->NewNode(common()->Branch(), p0, graph()->start()); - Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); - Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); - Node* merge1 = graph()->NewNode(common()->Merge(1), if_true1, if_false1); - Node* result = graph()->NewNode(common()->Phi(kMachInt32, 2), - jsgraph()->Int32Constant(11), - jsgraph()->Int32Constant(44), merge1); - - Node* ret = - graph()->NewNode(common()->Return(), result, graph()->start(), merge1); - graph()->end()->ReplaceInput(0, ret); - - ReduceGraph(); - - // Diamond should be folded away. - EXPECT_THAT( - graph()->end(), - IsEnd(IsReturn(IsInt32Constant(11), graph()->start(), graph()->start()))); -} - - -TEST_F(ControlReducerTest, RangeAsInputToBranch_true2) { - Node* p0 = Parameter(Type::Range(-2, -1, zone()), 0); - Node* branch1 = graph()->NewNode(common()->Branch(), p0, graph()->start()); - Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); - Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); - Node* merge1 = graph()->NewNode(common()->Merge(1), if_true1, if_false1); - Node* result = graph()->NewNode(common()->Phi(kMachInt32, 2), - jsgraph()->Int32Constant(11), - jsgraph()->Int32Constant(44), merge1); - - Node* ret = - graph()->NewNode(common()->Return(), result, graph()->start(), merge1); - graph()->end()->ReplaceInput(0, ret); - - ReduceGraph(); - - // Diamond should be folded away. - EXPECT_THAT( - graph()->end(), - IsEnd(IsReturn(IsInt32Constant(11), graph()->start(), graph()->start()))); -} - - -TEST_F(ControlReducerTest, SelectPhi) { - Node* p0 = Parameter(0); - const MachineType kType = kMachInt32; - Diamond d(graph(), common(), p0); - Node* phi = - d.Phi(kType, jsgraph()->Int32Constant(1), jsgraph()->Int32Constant(2)); - - Node* ret = - graph()->NewNode(common()->Return(), phi, graph()->start(), d.merge); - graph()->end()->ReplaceInput(0, ret); - - ReduceGraph(1); - - // Phi should be replaced with a select. - EXPECT_THAT(graph()->end(), - IsEnd(IsReturn( - IsSelect(kType, p0, IsInt32Constant(1), IsInt32Constant(2)), - graph()->start(), graph()->start()))); -} - - -TEST_F(ControlReducerTest, SelectPhis_fail) { - Node* p0 = Parameter(0); - const MachineType kType = kMachInt32; - Diamond d(graph(), common(), p0); - Node* phi = - d.Phi(kType, jsgraph()->Int32Constant(1), jsgraph()->Int32Constant(2)); - Node* phi2 = - d.Phi(kType, jsgraph()->Int32Constant(11), jsgraph()->Int32Constant(22)); - USE(phi2); - Node* ret = - graph()->NewNode(common()->Return(), phi, graph()->start(), d.merge); - graph()->end()->ReplaceInput(0, ret); - - ReduceGraph(1); - - // Diamond should not be replaced with a select (too many phis). - EXPECT_THAT(ret, IsReturn(phi, graph()->start(), d.merge)); - EXPECT_THAT(graph()->end(), IsEnd(ret)); -} - - -TEST_F(ControlReducerTest, SelectTwoPhis) { - Node* p0 = Parameter(0); - const MachineType kType = kMachInt32; - Diamond d(graph(), common(), p0); - Node* phi1 = - d.Phi(kType, jsgraph()->Int32Constant(1), jsgraph()->Int32Constant(2)); - Node* phi2 = - d.Phi(kType, jsgraph()->Int32Constant(2), jsgraph()->Int32Constant(3)); - MachineOperatorBuilder machine(zone()); - Node* add = graph()->NewNode(machine.Int32Add(), phi1, phi2); - Node* ret = - graph()->NewNode(common()->Return(), add, graph()->start(), d.merge); - graph()->end()->ReplaceInput(0, ret); - - ReduceGraph(2); - - // Phis should be replaced with two selects. - EXPECT_THAT( - ret, - IsReturn(IsInt32Add( - IsSelect(kType, p0, IsInt32Constant(1), IsInt32Constant(2)), - IsSelect(kType, p0, IsInt32Constant(2), IsInt32Constant(3))), - graph()->start(), graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); -} - - -} // namespace compiler -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/dead-code-elimination-unittest.cc b/deps/v8/test/unittests/compiler/dead-code-elimination-unittest.cc new file mode 100644 index 0000000000..8284fd8775 --- /dev/null +++ b/deps/v8/test/unittests/compiler/dead-code-elimination-unittest.cc @@ -0,0 +1,375 @@ +// 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/common-operator.h" +#include "src/compiler/dead-code-elimination.h" +#include "test/unittests/compiler/graph-reducer-unittest.h" +#include "test/unittests/compiler/graph-unittest.h" +#include "test/unittests/compiler/node-test-utils.h" +#include "testing/gmock-support.h" + +using testing::StrictMock; + +namespace v8 { +namespace internal { +namespace compiler { + +class DeadCodeEliminationTest : public GraphTest { + public: + explicit DeadCodeEliminationTest(int num_parameters = 4) + : GraphTest(num_parameters) {} + ~DeadCodeEliminationTest() override {} + + protected: + Reduction Reduce(AdvancedReducer::Editor* editor, Node* node) { + DeadCodeElimination reducer(editor, graph(), common()); + return reducer.Reduce(node); + } + + Reduction Reduce(Node* node) { + StrictMock<MockAdvancedReducerEditor> editor; + return Reduce(&editor, node); + } +}; + + +namespace { + +const MachineType kMachineTypes[] = { + kMachFloat32, kMachFloat64, kMachInt8, kMachUint8, kMachInt16, + kMachUint16, kMachInt32, kMachUint32, kMachInt64, kMachUint64, + kMachPtr, kMachAnyTagged, kRepBit, kRepWord8, kRepWord16, + kRepWord32, kRepWord64, kRepFloat32, kRepFloat64, kRepTagged}; + + +const int kMaxInputs = 16; + + +const Operator kOp0(0, Operator::kNoProperties, "Op0", 1, 1, 1, 1, 1, 1); + +} // namespace + + +// ----------------------------------------------------------------------------- +// General dead propagation + + +TEST_F(DeadCodeEliminationTest, GeneralDeadPropagation) { + Node* const value = Parameter(0); + Node* const effect = graph()->start(); + Node* const dead = graph()->NewNode(common()->Dead()); + Node* const node = graph()->NewNode(&kOp0, value, effect, dead); + Reduction const r = Reduce(node); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); +} + + +// ----------------------------------------------------------------------------- +// Branch + + +TEST_F(DeadCodeEliminationTest, BranchWithDeadControlInput) { + BranchHint const kHints[] = {BranchHint::kNone, BranchHint::kTrue, + BranchHint::kFalse}; + TRACED_FOREACH(BranchHint, hint, kHints) { + Reduction const r = + Reduce(graph()->NewNode(common()->Branch(hint), Parameter(0), + graph()->NewNode(common()->Dead()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +// ----------------------------------------------------------------------------- +// IfTrue + + +TEST_F(DeadCodeEliminationTest, IfTrueWithDeadInput) { + Reduction const r = Reduce( + graph()->NewNode(common()->IfTrue(), graph()->NewNode(common()->Dead()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); +} + + +// ----------------------------------------------------------------------------- +// IfFalse + + +TEST_F(DeadCodeEliminationTest, IfFalseWithDeadInput) { + Reduction const r = Reduce(graph()->NewNode( + common()->IfFalse(), graph()->NewNode(common()->Dead()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); +} + + +// ----------------------------------------------------------------------------- +// IfSuccess + + +TEST_F(DeadCodeEliminationTest, IfSuccessWithDeadInput) { + Reduction const r = Reduce(graph()->NewNode( + common()->IfSuccess(), graph()->NewNode(common()->Dead()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); +} + + +// ----------------------------------------------------------------------------- +// IfException + + +TEST_F(DeadCodeEliminationTest, IfExceptionWithDeadControlInput) { + IfExceptionHint const kHints[] = {IfExceptionHint::kLocallyCaught, + IfExceptionHint::kLocallyUncaught}; + TRACED_FOREACH(IfExceptionHint, hint, kHints) { + Reduction const r = + Reduce(graph()->NewNode(common()->IfException(hint), graph()->start(), + graph()->NewNode(common()->Dead()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +// ----------------------------------------------------------------------------- +// End + + +TEST_F(DeadCodeEliminationTest, EndWithDeadAndStart) { + Node* const dead = graph()->NewNode(common()->Dead()); + Node* const start = graph()->start(); + Reduction const r = Reduce(graph()->NewNode(common()->End(2), dead, start)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsEnd(start)); +} + + +TEST_F(DeadCodeEliminationTest, EndWithOnlyDeadInputs) { + Node* inputs[kMaxInputs]; + TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) { + for (int i = 0; i < input_count; ++i) { + inputs[i] = graph()->NewNode(common()->Dead()); + } + Reduction const r = Reduce( + graph()->NewNode(common()->End(input_count), input_count, inputs)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +// ----------------------------------------------------------------------------- +// Merge + + +TEST_F(DeadCodeEliminationTest, MergeWithOnlyDeadInputs) { + Node* inputs[kMaxInputs + 1]; + TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) { + for (int i = 0; i < input_count; ++i) { + inputs[i] = graph()->NewNode(common()->Dead()); + } + Reduction const r = Reduce( + graph()->NewNode(common()->Merge(input_count), input_count, inputs)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +TEST_F(DeadCodeEliminationTest, MergeWithOneLiveAndOneDeadInput) { + Node* const v0 = Parameter(0); + Node* const v1 = Parameter(1); + Node* const c0 = + graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start()); + Node* const c1 = graph()->NewNode(common()->Dead()); + Node* const e0 = graph()->NewNode(&kOp0, v0, graph()->start(), c0); + Node* const e1 = graph()->NewNode(&kOp0, v1, graph()->start(), c1); + Node* const merge = graph()->NewNode(common()->Merge(2), c0, c1); + Node* const phi = + graph()->NewNode(common()->Phi(kMachAnyTagged, 2), v0, v1, merge); + Node* const ephi = graph()->NewNode(common()->EffectPhi(2), e0, e1, merge); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Replace(phi, v0)); + EXPECT_CALL(editor, Replace(ephi, e0)); + Reduction const r = Reduce(&editor, merge); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(c0, r.replacement()); +} + + +TEST_F(DeadCodeEliminationTest, MergeWithTwoLiveAndTwoDeadInputs) { + Node* const v0 = Parameter(0); + Node* const v1 = Parameter(1); + Node* const v2 = Parameter(2); + Node* const v3 = Parameter(3); + Node* const c0 = + graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start()); + Node* const c1 = graph()->NewNode(common()->Dead()); + Node* const c2 = graph()->NewNode(common()->Dead()); + Node* const c3 = graph()->NewNode(&kOp0, v3, graph()->start(), c0); + Node* const e0 = graph()->start(); + Node* const e1 = graph()->NewNode(&kOp0, v1, e0, c0); + Node* const e2 = graph()->NewNode(&kOp0, v2, e1, c0); + Node* const e3 = graph()->NewNode(&kOp0, v3, graph()->start(), c3); + Node* const merge = graph()->NewNode(common()->Merge(4), c0, c1, c2, c3); + Node* const phi = + graph()->NewNode(common()->Phi(kMachAnyTagged, 4), v0, v1, v2, v3, merge); + Node* const ephi = + graph()->NewNode(common()->EffectPhi(4), e0, e1, e2, e3, merge); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(phi)); + EXPECT_CALL(editor, Revisit(ephi)); + Reduction const r = Reduce(&editor, merge); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsMerge(c0, c3)); + EXPECT_THAT(phi, IsPhi(kMachAnyTagged, v0, v3, r.replacement())); + EXPECT_THAT(ephi, IsEffectPhi(e0, e3, r.replacement())); +} + + +// ----------------------------------------------------------------------------- +// Loop + + +TEST_F(DeadCodeEliminationTest, LoopWithDeadFirstInput) { + Node* inputs[kMaxInputs + 1]; + TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) { + inputs[0] = graph()->NewNode(common()->Dead()); + for (int i = 1; i < input_count; ++i) { + inputs[i] = graph()->start(); + } + Reduction const r = Reduce( + graph()->NewNode(common()->Loop(input_count), input_count, inputs)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +TEST_F(DeadCodeEliminationTest, LoopWithOnlyDeadInputs) { + Node* inputs[kMaxInputs + 1]; + TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) { + for (int i = 0; i < input_count; ++i) { + inputs[i] = graph()->NewNode(common()->Dead()); + } + Reduction const r = Reduce( + graph()->NewNode(common()->Loop(input_count), input_count, inputs)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +TEST_F(DeadCodeEliminationTest, LoopWithOneLiveAndOneDeadInput) { + Node* const v0 = Parameter(0); + Node* const v1 = Parameter(1); + Node* const c0 = + graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start()); + Node* const c1 = graph()->NewNode(common()->Dead()); + Node* const e0 = graph()->NewNode(&kOp0, v0, graph()->start(), c0); + Node* const e1 = graph()->NewNode(&kOp0, v1, graph()->start(), c1); + Node* const loop = graph()->NewNode(common()->Loop(2), c0, c1); + Node* const phi = + graph()->NewNode(common()->Phi(kMachAnyTagged, 2), v0, v1, loop); + Node* const ephi = graph()->NewNode(common()->EffectPhi(2), e0, e1, loop); + Node* const terminate = graph()->NewNode(common()->Terminate(), ephi, loop); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Replace(phi, v0)); + EXPECT_CALL(editor, Replace(ephi, e0)); + EXPECT_CALL(editor, Replace(terminate, IsDead())); + Reduction const r = Reduce(&editor, loop); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(c0, r.replacement()); +} + + +TEST_F(DeadCodeEliminationTest, LoopWithTwoLiveAndTwoDeadInputs) { + Node* const v0 = Parameter(0); + Node* const v1 = Parameter(1); + Node* const v2 = Parameter(2); + Node* const v3 = Parameter(3); + Node* const c0 = + graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start()); + Node* const c1 = graph()->NewNode(common()->Dead()); + Node* const c2 = graph()->NewNode(common()->Dead()); + Node* const c3 = graph()->NewNode(&kOp0, v3, graph()->start(), c0); + Node* const e0 = graph()->start(); + Node* const e1 = graph()->NewNode(&kOp0, v1, e0, c0); + Node* const e2 = graph()->NewNode(&kOp0, v2, e1, c0); + Node* const e3 = graph()->NewNode(&kOp0, v3, graph()->start(), c3); + Node* const loop = graph()->NewNode(common()->Loop(4), c0, c1, c2, c3); + Node* const phi = + graph()->NewNode(common()->Phi(kMachAnyTagged, 4), v0, v1, v2, v3, loop); + Node* const ephi = + graph()->NewNode(common()->EffectPhi(4), e0, e1, e2, e3, loop); + StrictMock<MockAdvancedReducerEditor> editor; + EXPECT_CALL(editor, Revisit(phi)); + EXPECT_CALL(editor, Revisit(ephi)); + Reduction const r = Reduce(&editor, loop); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsLoop(c0, c3)); + EXPECT_THAT(phi, IsPhi(kMachAnyTagged, v0, v3, r.replacement())); + EXPECT_THAT(ephi, IsEffectPhi(e0, e3, r.replacement())); +} + + +// ----------------------------------------------------------------------------- +// Phi + + +TEST_F(DeadCodeEliminationTest, PhiWithDeadControlInput) { + Node* inputs[kMaxInputs + 1]; + TRACED_FOREACH(MachineType, type, kMachineTypes) { + TRACED_FORRANGE(int, input_count, 1, kMaxInputs) { + for (int i = 0; i < input_count; ++i) { + inputs[i] = Parameter(i); + } + inputs[input_count] = graph()->NewNode(common()->Dead()); + Reduction const r = Reduce(graph()->NewNode( + common()->Phi(type, input_count), input_count + 1, inputs)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } + } +} + + +// ----------------------------------------------------------------------------- +// EffectPhi + + +TEST_F(DeadCodeEliminationTest, EffectPhiWithDeadControlInput) { + Node* inputs[kMaxInputs + 1]; + TRACED_FORRANGE(int, input_count, 1, kMaxInputs) { + for (int i = 0; i < input_count; ++i) { + inputs[i] = graph()->start(); + } + inputs[input_count] = graph()->NewNode(common()->Dead()); + Reduction const r = Reduce(graph()->NewNode( + common()->EffectPhi(input_count), input_count + 1, inputs)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); + } +} + + +// ----------------------------------------------------------------------------- +// Terminate + + +TEST_F(DeadCodeEliminationTest, TerminateWithDeadControlInput) { + Reduction const r = + Reduce(graph()->NewNode(common()->Terminate(), graph()->start(), + graph()->NewNode(common()->Dead()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsDead()); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/graph-reducer-unittest.cc b/deps/v8/test/unittests/compiler/graph-reducer-unittest.cc index ea981ccaf3..3ca6052af9 100644 --- a/deps/v8/test/unittests/compiler/graph-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/graph-reducer-unittest.cc @@ -2,6 +2,7 @@ // 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/node.h" #include "src/compiler/operator.h" @@ -10,9 +11,11 @@ using testing::_; using testing::DefaultValue; +using testing::ElementsAre; using testing::Return; using testing::Sequence; using testing::StrictMock; +using testing::UnorderedElementsAre; namespace v8 { namespace internal { @@ -264,6 +267,124 @@ TEST_F(AdvancedReducerTest, Revisit) { } +namespace { + +struct ReplaceWithValueReducer final : public AdvancedReducer { + explicit ReplaceWithValueReducer(Editor* editor) : AdvancedReducer(editor) {} + Reduction Reduce(Node* node) final { return NoChange(); } + using AdvancedReducer::ReplaceWithValue; +}; + +const Operator kMockOperator(IrOpcode::kDead, Operator::kNoProperties, + "MockOperator", 0, 0, 0, 1, 0, 0); +const Operator kMockOpEffect(IrOpcode::kDead, Operator::kNoProperties, + "MockOpEffect", 0, 1, 0, 1, 1, 0); +const Operator kMockOpControl(IrOpcode::kDead, Operator::kNoProperties, + "MockOpControl", 0, 0, 1, 1, 0, 1); + +const IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught; + +} // namespace + + +TEST_F(AdvancedReducerTest, ReplaceWithValue_ValueUse) { + CommonOperatorBuilder common(zone()); + Node* node = graph()->NewNode(&kMockOperator); + Node* use_value = graph()->NewNode(common.Return(), node); + Node* replacement = graph()->NewNode(&kMockOperator); + GraphReducer graph_reducer(zone(), graph(), nullptr); + ReplaceWithValueReducer r(&graph_reducer); + r.ReplaceWithValue(node, replacement); + EXPECT_EQ(replacement, use_value->InputAt(0)); + EXPECT_EQ(0, node->UseCount()); + EXPECT_EQ(1, replacement->UseCount()); + EXPECT_THAT(replacement->uses(), ElementsAre(use_value)); +} + + +TEST_F(AdvancedReducerTest, ReplaceWithValue_EffectUse) { + CommonOperatorBuilder common(zone()); + Node* start = graph()->NewNode(common.Start(1)); + Node* node = graph()->NewNode(&kMockOpEffect, start); + Node* use_effect = graph()->NewNode(common.EffectPhi(1), node); + Node* replacement = graph()->NewNode(&kMockOperator); + GraphReducer graph_reducer(zone(), graph(), nullptr); + ReplaceWithValueReducer r(&graph_reducer); + r.ReplaceWithValue(node, replacement); + EXPECT_EQ(start, use_effect->InputAt(0)); + EXPECT_EQ(0, node->UseCount()); + EXPECT_EQ(2, start->UseCount()); + EXPECT_EQ(0, replacement->UseCount()); + EXPECT_THAT(start->uses(), UnorderedElementsAre(use_effect, node)); +} + + +TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse1) { + CommonOperatorBuilder common(zone()); + Node* start = graph()->NewNode(common.Start(1)); + Node* node = graph()->NewNode(&kMockOpControl, start); + Node* success = graph()->NewNode(common.IfSuccess(), node); + Node* use_control = graph()->NewNode(common.Merge(1), success); + Node* replacement = graph()->NewNode(&kMockOperator); + GraphReducer graph_reducer(zone(), graph(), nullptr); + ReplaceWithValueReducer r(&graph_reducer); + r.ReplaceWithValue(node, replacement); + EXPECT_EQ(start, use_control->InputAt(0)); + EXPECT_EQ(0, node->UseCount()); + EXPECT_EQ(2, start->UseCount()); + EXPECT_EQ(0, replacement->UseCount()); + EXPECT_THAT(start->uses(), UnorderedElementsAre(use_control, node)); +} + + +TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse2) { + CommonOperatorBuilder common(zone()); + Node* start = graph()->NewNode(common.Start(1)); + Node* effect = graph()->NewNode(&kMockOperator); + Node* dead = graph()->NewNode(&kMockOperator); + Node* node = graph()->NewNode(&kMockOpControl, start); + Node* success = graph()->NewNode(common.IfSuccess(), node); + Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node); + Node* use_control = graph()->NewNode(common.Merge(1), success); + Node* replacement = graph()->NewNode(&kMockOperator); + GraphReducer graph_reducer(zone(), graph(), dead); + ReplaceWithValueReducer r(&graph_reducer); + r.ReplaceWithValue(node, replacement); + EXPECT_EQ(start, use_control->InputAt(0)); + EXPECT_EQ(dead, exception->InputAt(1)); + EXPECT_EQ(0, node->UseCount()); + EXPECT_EQ(2, start->UseCount()); + EXPECT_EQ(1, dead->UseCount()); + EXPECT_EQ(0, replacement->UseCount()); + EXPECT_THAT(start->uses(), UnorderedElementsAre(use_control, node)); + EXPECT_THAT(dead->uses(), ElementsAre(exception)); +} + + +TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse3) { + CommonOperatorBuilder common(zone()); + Node* start = graph()->NewNode(common.Start(1)); + Node* effect = graph()->NewNode(&kMockOperator); + Node* dead = graph()->NewNode(&kMockOperator); + Node* node = graph()->NewNode(&kMockOpControl, start); + Node* success = graph()->NewNode(common.IfSuccess(), node); + Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node); + Node* use_control = graph()->NewNode(common.Merge(1), success); + Node* replacement = graph()->NewNode(&kMockOperator); + GraphReducer graph_reducer(zone(), graph(), dead); + ReplaceWithValueReducer r(&graph_reducer); + r.ReplaceWithValue(node, replacement); + EXPECT_EQ(start, use_control->InputAt(0)); + EXPECT_EQ(dead, exception->InputAt(1)); + EXPECT_EQ(0, node->UseCount()); + EXPECT_EQ(2, start->UseCount()); + EXPECT_EQ(1, dead->UseCount()); + EXPECT_EQ(0, replacement->UseCount()); + EXPECT_THAT(start->uses(), UnorderedElementsAre(use_control, node)); + EXPECT_THAT(dead->uses(), ElementsAre(exception)); +} + + class GraphReducerTest : public TestWithZone { public: GraphReducerTest() : graph_(zone()) {} @@ -280,20 +401,20 @@ class GraphReducerTest : public TestWithZone { protected: void ReduceNode(Node* node, Reducer* r) { - GraphReducer reducer(graph(), zone()); + GraphReducer reducer(zone(), graph()); reducer.AddReducer(r); reducer.ReduceNode(node); } void ReduceNode(Node* node, Reducer* r1, Reducer* r2) { - GraphReducer reducer(graph(), zone()); + GraphReducer reducer(zone(), graph()); reducer.AddReducer(r1); reducer.AddReducer(r2); reducer.ReduceNode(node); } void ReduceNode(Node* node, Reducer* r1, Reducer* r2, Reducer* r3) { - GraphReducer reducer(graph(), zone()); + GraphReducer reducer(zone(), graph()); reducer.AddReducer(r1); reducer.AddReducer(r2); reducer.AddReducer(r3); @@ -301,20 +422,20 @@ class GraphReducerTest : public TestWithZone { } void ReduceGraph(Reducer* r1) { - GraphReducer reducer(graph(), zone()); + GraphReducer reducer(zone(), graph()); reducer.AddReducer(r1); reducer.ReduceGraph(); } void ReduceGraph(Reducer* r1, Reducer* r2) { - GraphReducer reducer(graph(), zone()); + GraphReducer reducer(zone(), graph()); reducer.AddReducer(r1); reducer.AddReducer(r2); reducer.ReduceGraph(); } void ReduceGraph(Reducer* r1, Reducer* r2, Reducer* r3) { - GraphReducer reducer(graph(), zone()); + GraphReducer reducer(zone(), graph()); reducer.AddReducer(r1); reducer.AddReducer(r2); reducer.AddReducer(r3); @@ -401,7 +522,7 @@ TEST_F(GraphReducerTest, ReduceInPlace1) { // Tests A* => B* with in-place updates. InPlaceABReducer r; for (int i = 0; i < 3; i++) { - int before = graph()->NodeCount(); + size_t before = graph()->NodeCount(); ReduceGraph(&r); EXPECT_EQ(before, graph()->NodeCount()); EXPECT_EQ(&kOpB0, n1->op()); @@ -421,7 +542,7 @@ TEST_F(GraphReducerTest, ReduceInPlace2) { // Tests A* => B* with in-place updates. InPlaceABReducer r; for (int i = 0; i < 3; i++) { - int before = graph()->NodeCount(); + size_t before = graph()->NodeCount(); ReduceGraph(&r); EXPECT_EQ(before, graph()->NodeCount()); EXPECT_EQ(&kOpB0, n1->op()); @@ -446,7 +567,7 @@ TEST_F(GraphReducerTest, ReduceNew1) { NewABReducer r(graph()); // Tests A* => B* while creating new nodes. for (int i = 0; i < 3; i++) { - int before = graph()->NodeCount(); + size_t before = graph()->NodeCount(); ReduceGraph(&r); if (i == 0) { EXPECT_NE(before, graph()->NodeCount()); @@ -473,12 +594,12 @@ TEST_F(GraphReducerTest, ReduceNew1) { TEST_F(GraphReducerTest, Wrapping1) { Node* end = graph()->NewNode(&kOpA0); graph()->SetEnd(end); - EXPECT_EQ(1, graph()->NodeCount()); + EXPECT_EQ(1U, graph()->NodeCount()); A0Wrapper r(graph()); ReduceGraph(&r); - EXPECT_EQ(2, graph()->NodeCount()); + EXPECT_EQ(2U, graph()->NodeCount()); Node* nend = graph()->end(); EXPECT_NE(end, nend); @@ -491,12 +612,12 @@ TEST_F(GraphReducerTest, Wrapping1) { TEST_F(GraphReducerTest, Wrapping2) { Node* end = graph()->NewNode(&kOpB0); graph()->SetEnd(end); - EXPECT_EQ(1, graph()->NodeCount()); + EXPECT_EQ(1U, graph()->NodeCount()); B0Wrapper r(graph()); ReduceGraph(&r); - EXPECT_EQ(3, graph()->NodeCount()); + EXPECT_EQ(3U, graph()->NodeCount()); Node* nend = graph()->end(); EXPECT_NE(end, nend); @@ -520,7 +641,7 @@ TEST_F(GraphReducerTest, Forwarding1) { // Tests A1(x) => x for (int i = 0; i < 3; i++) { - int before = graph()->NodeCount(); + size_t before = graph()->NodeCount(); ReduceGraph(&r); EXPECT_EQ(before, graph()->NodeCount()); EXPECT_EQ(&kOpA0, n1->op()); @@ -540,7 +661,7 @@ TEST_F(GraphReducerTest, Forwarding2) { // Tests reducing A2(A1(x), A1(y)) => A2(x, y). for (int i = 0; i < 3; i++) { - int before = graph()->NodeCount(); + size_t before = graph()->NodeCount(); ReduceGraph(&r); EXPECT_EQ(before, graph()->NodeCount()); EXPECT_EQ(&kOpA0, n1->op()); @@ -565,8 +686,8 @@ TEST_F(GraphReducerTest, Forwarding3) { A1Forwarder r; - for (int i = 0; i < 3; i++) { - int before = graph()->NodeCount(); + for (size_t i = 0; i < 3; i++) { + size_t before = graph()->NodeCount(); ReduceGraph(&r); EXPECT_EQ(before, graph()->NodeCount()); EXPECT_EQ(&kOpA0, n1->op()); @@ -587,8 +708,8 @@ TEST_F(GraphReducerTest, ReduceForward1) { B1Forwarder f; // Tests first reducing A => B, then B1(x) => x. - for (int i = 0; i < 3; i++) { - int before = graph()->NodeCount(); + for (size_t i = 0; i < 3; i++) { + size_t before = graph()->NodeCount(); ReduceGraph(&r, &f); EXPECT_EQ(before, graph()->NodeCount()); EXPECT_EQ(&kOpB0, n1->op()); @@ -620,7 +741,7 @@ TEST_F(GraphReducerTest, Sorter1) { graph()->SetEnd(end); - int before = graph()->NodeCount(); + size_t before = graph()->NodeCount(); ReduceGraph(&r); EXPECT_EQ(before, graph()->NodeCount()); EXPECT_EQ(&kOpA0, n1->op()); @@ -715,8 +836,8 @@ TEST_F(GraphReducerTest, Order) { InPlaceBCReducer bcr; // Tests A* => C* with in-place updates. - for (int j = 0; j < 3; j++) { - int before = graph()->NodeCount(); + for (size_t j = 0; j < 3; j++) { + size_t before = graph()->NodeCount(); if (i == 0) { ReduceGraph(&abr, &bcr); } else { diff --git a/deps/v8/test/unittests/compiler/graph-reducer-unittest.h b/deps/v8/test/unittests/compiler/graph-reducer-unittest.h index 4cde964709..2b0651da13 100644 --- a/deps/v8/test/unittests/compiler/graph-reducer-unittest.h +++ b/deps/v8/test/unittests/compiler/graph-reducer-unittest.h @@ -15,6 +15,7 @@ namespace compiler { struct MockAdvancedReducerEditor : public AdvancedReducer::Editor { MOCK_METHOD1(Revisit, void(Node*)); MOCK_METHOD2(Replace, void(Node*, Node*)); + MOCK_METHOD4(ReplaceWithValue, void(Node*, Node*, Node*, Node*)); }; } // namespace compiler diff --git a/deps/v8/test/unittests/compiler/graph-trimmer-unittest.cc b/deps/v8/test/unittests/compiler/graph-trimmer-unittest.cc new file mode 100644 index 0000000000..36892e6ee8 --- /dev/null +++ b/deps/v8/test/unittests/compiler/graph-trimmer-unittest.cc @@ -0,0 +1,85 @@ +// 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/graph-trimmer.h" +#include "test/unittests/compiler/graph-unittest.h" +#include "testing/gmock-support.h" + +using testing::ElementsAre; +using testing::UnorderedElementsAre; + +namespace v8 { +namespace internal { +namespace compiler { + +class GraphTrimmerTest : public GraphTest { + public: + GraphTrimmerTest() : GraphTest(1) {} + + protected: + void TrimGraph(Node* root) { + Node* const roots[1] = {root}; + GraphTrimmer trimmer(zone(), graph()); + trimmer.TrimGraph(&roots[0], &roots[arraysize(roots)]); + } + void TrimGraph() { + GraphTrimmer trimmer(zone(), graph()); + trimmer.TrimGraph(); + } +}; + + +namespace { + +const Operator kDead0(IrOpcode::kDead, Operator::kNoProperties, "Dead0", 0, 0, + 1, 0, 0, 0); +const Operator kLive0(IrOpcode::kDead, Operator::kNoProperties, "Live0", 0, 0, + 1, 0, 0, 1); + +} // namespace + + +TEST_F(GraphTrimmerTest, Empty) { + Node* const start = graph()->NewNode(common()->Start(0)); + Node* const end = graph()->NewNode(common()->End(1), start); + graph()->SetStart(start); + graph()->SetEnd(end); + TrimGraph(); + EXPECT_EQ(end, graph()->end()); + EXPECT_EQ(start, graph()->start()); + EXPECT_EQ(start, end->InputAt(0)); +} + + +TEST_F(GraphTrimmerTest, DeadUseOfStart) { + Node* const dead0 = graph()->NewNode(&kDead0, graph()->start()); + graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start())); + TrimGraph(); + EXPECT_THAT(dead0->inputs(), ElementsAre(nullptr)); + EXPECT_THAT(graph()->start()->uses(), ElementsAre(graph()->end())); +} + + +TEST_F(GraphTrimmerTest, DeadAndLiveUsesOfStart) { + Node* const dead0 = graph()->NewNode(&kDead0, graph()->start()); + Node* const live0 = graph()->NewNode(&kLive0, graph()->start()); + graph()->SetEnd(graph()->NewNode(common()->End(1), live0)); + TrimGraph(); + EXPECT_THAT(dead0->inputs(), ElementsAre(nullptr)); + EXPECT_THAT(graph()->start()->uses(), ElementsAre(live0)); + EXPECT_THAT(live0->uses(), ElementsAre(graph()->end())); +} + + +TEST_F(GraphTrimmerTest, Roots) { + Node* const live0 = graph()->NewNode(&kLive0, graph()->start()); + Node* const live1 = graph()->NewNode(&kLive0, graph()->start()); + graph()->SetEnd(graph()->NewNode(common()->End(1), live0)); + TrimGraph(live1); + EXPECT_THAT(graph()->start()->uses(), UnorderedElementsAre(live0, live1)); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/graph-unittest.cc b/deps/v8/test/unittests/compiler/graph-unittest.cc index 9da3950e54..6b8546b95a 100644 --- a/deps/v8/test/unittests/compiler/graph-unittest.cc +++ b/deps/v8/test/unittests/compiler/graph-unittest.cc @@ -13,7 +13,7 @@ namespace compiler { GraphTest::GraphTest(int num_parameters) : common_(zone()), graph_(zone()) { graph()->SetStart(graph()->NewNode(common()->Start(num_parameters))); - graph()->SetEnd(graph()->NewNode(common()->End(), graph()->start())); + graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start())); } @@ -81,6 +81,16 @@ Node* GraphTest::UndefinedConstant() { } +Node* GraphTest::EmptyFrameState() { + Node* state_values = graph()->NewNode(common()->StateValues(0)); + return graph()->NewNode( + common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(), + nullptr), + state_values, state_values, state_values, NumberConstant(0), + UndefinedConstant(), graph()->start()); +} + + Matcher<Node*> GraphTest::IsFalseConstant() { return IsHeapConstant( Unique<HeapObject>::CreateImmovable(factory()->false_value())); @@ -100,8 +110,7 @@ Matcher<Node*> GraphTest::IsUndefinedConstant() { TypedGraphTest::TypedGraphTest(int num_parameters) - : GraphTest(num_parameters), - typer_(isolate(), graph(), MaybeHandle<Context>()) {} + : GraphTest(num_parameters), typer_(isolate(), graph()) {} TypedGraphTest::~TypedGraphTest() {} @@ -126,8 +135,8 @@ TEST_F(GraphTest, NewNode) { Node* n0 = graph()->NewNode(&kDummyOperator); Node* n1 = graph()->NewNode(&kDummyOperator); EXPECT_NE(n0, n1); - EXPECT_LT(0, n0->id()); - EXPECT_LT(0, n1->id()); + EXPECT_LT(0u, n0->id()); + EXPECT_LT(0u, n1->id()); EXPECT_NE(n0->id(), n1->id()); EXPECT_EQ(&kDummyOperator, n0->op()); EXPECT_EQ(&kDummyOperator, n1->op()); diff --git a/deps/v8/test/unittests/compiler/graph-unittest.h b/deps/v8/test/unittests/compiler/graph-unittest.h index c905f30c6a..2318fa61f8 100644 --- a/deps/v8/test/unittests/compiler/graph-unittest.h +++ b/deps/v8/test/unittests/compiler/graph-unittest.h @@ -50,6 +50,8 @@ class GraphTest : public TestWithContext, public TestWithIsolateAndZone { Node* TrueConstant(); Node* UndefinedConstant(); + Node* EmptyFrameState(); + Matcher<Node*> IsFalseConstant(); Matcher<Node*> IsTrueConstant(); Matcher<Node*> IsUndefinedConstant(); diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc index dfdb4c2b1f..acab91b009 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc +++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc @@ -148,6 +148,15 @@ bool InstructionSelectorTest::Stream::IsUsedAtStart( } +const FrameStateFunctionInfo* +InstructionSelectorTest::StreamBuilder::GetFrameStateFunctionInfo( + int parameter_count, int local_count) { + return common()->CreateFrameStateFunctionInfo( + FrameStateType::kJavaScriptFunction, parameter_count, local_count, + Handle<SharedFunctionInfo>()); +} + + // ----------------------------------------------------------------------------- // Return. @@ -198,7 +207,8 @@ TARGET_TEST_F(InstructionSelectorTest, ReturnZero) { TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) { StreamBuilder m(this, kMachInt32, kMachFloat64); - m.Return(m.TruncateFloat64ToInt32(m.Parameter(0))); + m.Return( + m.TruncateFloat64ToInt32(TruncationMode::kJavaScript, m.Parameter(0))); Stream s = m.Build(kAllInstructions); ASSERT_EQ(4U, s.size()); EXPECT_EQ(kArchNop, s[0]->arch_opcode()); @@ -363,9 +373,10 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { Node* context_dummy = m.Int32Constant(0); Node* state_node = m.NewNode( - m.common()->FrameState(JS_FRAME, bailout_id, - OutputFrameStateCombine::Push()), - parameters, locals, stack, context_dummy, m.UndefinedConstant()); + m.common()->FrameState(bailout_id, OutputFrameStateCombine::Push(), + m.GetFrameStateFunctionInfo(1, 0)), + parameters, locals, stack, context_dummy, function_node, + m.UndefinedConstant()); Node* call = m.CallJS0(function_node, receiver, context, state_node); m.Return(call); @@ -411,9 +422,10 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { Node* context_sentinel = m.Int32Constant(0); Node* frame_state_before = m.NewNode( - m.common()->FrameState(JS_FRAME, bailout_id_before, - OutputFrameStateCombine::Push()), - parameters, locals, stack, context_sentinel, m.UndefinedConstant()); + m.common()->FrameState(bailout_id_before, OutputFrameStateCombine::Push(), + m.GetFrameStateFunctionInfo(1, 1)), + parameters, locals, stack, context_sentinel, function_node, + m.UndefinedConstant()); // Build the call. Node* call = m.CallFunctionStub0(function_node, receiver, context, @@ -437,7 +449,7 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { size_t num_operands = 1 + // Code object. 1 + - 4 + // Frame state deopt id + one input for each value in frame state. + 5 + // Frame state deopt id + one input for each value in frame state. 1 + // Function. 1; // Context. ASSERT_EQ(num_operands, call_instr->InputCount()); @@ -455,21 +467,23 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { EXPECT_EQ(1u, desc_before->parameters_count()); EXPECT_EQ(1u, desc_before->locals_count()); EXPECT_EQ(1u, desc_before->stack_count()); - EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2))); - EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3))); // This should be a context. + EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(3))); + EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(4))); // This should be a context. // We inserted 0 here. - EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(4))); - EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(5))->IsUndefined()); - EXPECT_EQ(kMachInt32, desc_before->GetType(0)); - EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1)); // context is always + EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(5))); + EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(6))->IsUndefined()); + EXPECT_EQ(kMachAnyTagged, desc_before->GetType(0)); // function is always // tagged/any. - EXPECT_EQ(kMachFloat64, desc_before->GetType(2)); - EXPECT_EQ(kMachAnyTagged, desc_before->GetType(3)); + EXPECT_EQ(kMachInt32, desc_before->GetType(1)); + EXPECT_EQ(kMachAnyTagged, desc_before->GetType(2)); // context is always + // tagged/any. + EXPECT_EQ(kMachFloat64, desc_before->GetType(3)); + EXPECT_EQ(kMachAnyTagged, desc_before->GetType(4)); // Function. - EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(6))); + EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(7))); // Context. - EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(7))); + EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(8))); EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); @@ -501,10 +515,11 @@ TARGET_TEST_F(InstructionSelectorTest, m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(64)); Node* stack = m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(65)); - Node* frame_state_parent = - m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent, - OutputFrameStateCombine::Ignore()), - parameters, locals, stack, context, m.UndefinedConstant()); + Node* frame_state_parent = m.NewNode( + m.common()->FrameState(bailout_id_parent, + OutputFrameStateCombine::Ignore(), + m.GetFrameStateFunctionInfo(1, 1)), + parameters, locals, stack, context, function_node, m.UndefinedConstant()); Node* context2 = m.Int32Constant(46); Node* parameters2 = @@ -513,10 +528,11 @@ TARGET_TEST_F(InstructionSelectorTest, m.Float64Constant(0.25)); Node* stack2 = m.NewNode(m.common()->TypedStateValues(&int32x2_type), m.Int32Constant(44), m.Int32Constant(45)); - Node* frame_state_before = - m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before, - OutputFrameStateCombine::Push()), - parameters2, locals2, stack2, context2, frame_state_parent); + Node* frame_state_before = m.NewNode( + m.common()->FrameState(bailout_id_before, OutputFrameStateCombine::Push(), + m.GetFrameStateFunctionInfo(1, 1)), + parameters2, locals2, stack2, context2, function_node, + frame_state_parent); // Build the call. Node* call = m.CallFunctionStub0(function_node, receiver, context2, @@ -540,8 +556,8 @@ TARGET_TEST_F(InstructionSelectorTest, size_t num_operands = 1 + // Code object. 1 + // Frame state deopt id - 5 + // One input for each value in frame state + context. - 4 + // One input for each value in the parent frame state + context. + 6 + // One input for each value in frame state + context. + 5 + // One input for each value in the parent frame state + context. 1 + // Function. 1; // Context. EXPECT_EQ(num_operands, call_instr->InputCount()); @@ -558,34 +574,36 @@ TARGET_TEST_F(InstructionSelectorTest, EXPECT_EQ(1u, desc_before_outer->locals_count()); EXPECT_EQ(1u, desc_before_outer->stack_count()); // Values from parent environment. - EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2))); - EXPECT_EQ(kMachInt32, desc_before_outer->GetType(0)); + EXPECT_EQ(kMachAnyTagged, desc_before->GetType(0)); + EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(3))); + EXPECT_EQ(kMachInt32, desc_before_outer->GetType(1)); // Context: - EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3))); - EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(1)); - EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4))); - EXPECT_EQ(kMachInt32, desc_before_outer->GetType(2)); - EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5))); + EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(4))); + EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(2)); + EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(5))); EXPECT_EQ(kMachInt32, desc_before_outer->GetType(3)); + EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(6))); + EXPECT_EQ(kMachInt32, desc_before_outer->GetType(4)); // Values from the nested frame. EXPECT_EQ(1u, desc_before->parameters_count()); EXPECT_EQ(1u, desc_before->locals_count()); EXPECT_EQ(2u, desc_before->stack_count()); - EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6))); - EXPECT_EQ(kMachInt32, desc_before->GetType(0)); - EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7))); - EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1)); - EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(8))); - EXPECT_EQ(kMachFloat64, desc_before->GetType(2)); - EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(9))); - EXPECT_EQ(kMachInt32, desc_before->GetType(3)); - EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(10))); + EXPECT_EQ(kMachAnyTagged, desc_before->GetType(0)); + EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(8))); + EXPECT_EQ(kMachInt32, desc_before->GetType(1)); + EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(9))); + EXPECT_EQ(kMachAnyTagged, desc_before->GetType(2)); + EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(10))); + EXPECT_EQ(kMachFloat64, desc_before->GetType(3)); + EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(11))); EXPECT_EQ(kMachInt32, desc_before->GetType(4)); + EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(12))); + EXPECT_EQ(kMachInt32, desc_before->GetType(5)); // Function. - EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(11))); + EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(13))); // Context. - EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(12))); + EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(14))); // Continuation. EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h b/deps/v8/test/unittests/compiler/instruction-selector-unittest.h index a23d531a3a..15d3b2005f 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h +++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.h @@ -37,22 +37,25 @@ class InstructionSelectorTest : public TestWithContext, class StreamBuilder final : public RawMachineAssembler { public: StreamBuilder(InstructionSelectorTest* test, MachineType return_type) - : RawMachineAssembler(test->isolate(), - new (test->zone()) Graph(test->zone()), - MakeMachineSignature(test->zone(), return_type)), + : RawMachineAssembler( + test->isolate(), new (test->zone()) Graph(test->zone()), + MakeMachineSignature(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)), + MakeMachineSignature(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)), + parameter1_type), + kMachPtr, MachineOperatorBuilder::kAllOptionalOps), test_(test) {} StreamBuilder(InstructionSelectorTest* test, MachineType return_type, MachineType parameter0_type, MachineType parameter1_type, @@ -60,7 +63,8 @@ class InstructionSelectorTest : public TestWithContext, : RawMachineAssembler( test->isolate(), new (test->zone()) Graph(test->zone()), MakeMachineSignature(test->zone(), return_type, parameter0_type, - parameter1_type, parameter2_type)), + parameter1_type, parameter2_type), + kMachPtr, MachineOperatorBuilder::kAllOptionalOps), test_(test) {} Stream Build(CpuFeature feature) { @@ -77,6 +81,9 @@ class InstructionSelectorTest : public TestWithContext, InstructionSelector::SourcePositionMode source_position_mode = InstructionSelector::kAllSourcePositions); + const FrameStateFunctionInfo* GetFrameStateFunctionInfo(int parameter_count, + int local_count); + private: MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type) { diff --git a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc index f659b07887..1ff441f746 100644 --- a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc +++ b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc @@ -429,8 +429,8 @@ InstructionBlock* InstructionSequenceTest::NewBlock() { } } // Construct instruction block. - auto instruction_block = - new (zone()) InstructionBlock(zone(), rpo, loop_header, loop_end, false); + auto instruction_block = new (zone()) + InstructionBlock(zone(), rpo, loop_header, loop_end, false, false); instruction_blocks_.push_back(instruction_block); current_block_ = instruction_block; sequence()->StartBlock(rpo); diff --git a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc index 090f610066..b452ba56c5 100644 --- a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc @@ -26,7 +26,9 @@ class JSBuiltinReducerTest : public TypedGraphTest { MachineOperatorBuilder::Flag::kNoFlags) { MachineOperatorBuilder machine(zone(), kMachPtr, flags); JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); - JSBuiltinReducer reducer(&jsgraph); + // TODO(titzer): mock the GraphReducer here for better unit testing. + GraphReducer graph_reducer(zone(), graph()); + JSBuiltinReducer reducer(&graph_reducer, &jsgraph); return reducer.Reduce(node); } @@ -77,10 +79,14 @@ Type* const kNumberTypes[] = { TEST_F(JSBuiltinReducerTest, MathMax0) { Node* function = MathFunction("max"); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* frame_state = graph()->start(); TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { Node* call = graph()->NewNode( javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS, language_mode), - function, UndefinedConstant()); + function, UndefinedConstant(), frame_state, frame_state, effect, + control); Reduction r = Reduce(call); ASSERT_TRUE(r.Changed()); @@ -92,12 +98,16 @@ TEST_F(JSBuiltinReducerTest, MathMax0) { TEST_F(JSBuiltinReducerTest, MathMax1) { Node* function = MathFunction("max"); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* frame_state = graph()->start(); TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(Type*, t0, kNumberTypes) { Node* p0 = Parameter(t0, 0); Node* call = graph()->NewNode( javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS, language_mode), - function, UndefinedConstant(), p0); + function, UndefinedConstant(), p0, frame_state, frame_state, effect, + control); Reduction r = Reduce(call); ASSERT_TRUE(r.Changed()); @@ -110,6 +120,9 @@ TEST_F(JSBuiltinReducerTest, MathMax1) { TEST_F(JSBuiltinReducerTest, MathMax2) { Node* function = MathFunction("max"); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* frame_state = graph()->start(); TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(Type*, t0, kIntegral32Types) { TRACED_FOREACH(Type*, t1, kIntegral32Types) { @@ -118,7 +131,8 @@ TEST_F(JSBuiltinReducerTest, MathMax2) { Node* call = graph()->NewNode(javascript()->CallFunction( 4, NO_CALL_FUNCTION_FLAGS, language_mode), - function, UndefinedConstant(), p0, p1); + function, UndefinedConstant(), p0, p1, frame_state, + frame_state, effect, control); Reduction r = Reduce(call); ASSERT_TRUE(r.Changed()); @@ -137,6 +151,9 @@ TEST_F(JSBuiltinReducerTest, MathMax2) { TEST_F(JSBuiltinReducerTest, MathImul) { Node* function = MathFunction("imul"); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* frame_state = graph()->start(); TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(Type*, t0, kIntegral32Types) { TRACED_FOREACH(Type*, t1, kIntegral32Types) { @@ -145,7 +162,8 @@ TEST_F(JSBuiltinReducerTest, MathImul) { Node* call = graph()->NewNode(javascript()->CallFunction( 4, NO_CALL_FUNCTION_FLAGS, language_mode), - function, UndefinedConstant(), p0, p1); + function, UndefinedConstant(), p0, p1, frame_state, + frame_state, effect, control); Reduction r = Reduce(call); ASSERT_TRUE(r.Changed()); @@ -163,12 +181,16 @@ TEST_F(JSBuiltinReducerTest, MathImul) { TEST_F(JSBuiltinReducerTest, MathFround) { Node* function = MathFunction("fround"); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Node* frame_state = graph()->start(); TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(Type*, t0, kNumberTypes) { Node* p0 = Parameter(t0, 0); Node* call = graph()->NewNode( javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS, language_mode), - function, UndefinedConstant(), p0); + function, UndefinedConstant(), p0, frame_state, frame_state, effect, + control); Reduction r = Reduce(call); ASSERT_TRUE(r.Changed()); diff --git a/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc index bc343060ca..92be4e43e0 100644 --- a/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc @@ -33,7 +33,10 @@ class JSIntrinsicLoweringTest : public GraphTest { MachineOperatorBuilder::kNoFlags) { MachineOperatorBuilder machine(zone(), kMachPtr, flags); JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); - JSIntrinsicLowering reducer(&jsgraph); + // TODO(titzer): mock the GraphReducer here for better unit testing. + GraphReducer graph_reducer(zone(), graph()); + JSIntrinsicLowering reducer(&graph_reducer, &jsgraph, + JSIntrinsicLowering::kDeoptimizationEnabled); return reducer.Reduce(node); } @@ -171,6 +174,68 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsArray) { // ----------------------------------------------------------------------------- +// %_IsDate + + +TEST_F(JSIntrinsicLoweringTest, InlineIsDate) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce( + graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsDate, 1), + input, context, effect, control)); + ASSERT_TRUE(r.Changed()); + + Node* phi = r.replacement(); + Capture<Node*> branch, if_false; + EXPECT_THAT( + phi, + IsPhi( + static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(), + IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(), + IsLoadField(AccessBuilder::ForMap(), input, + effect, CaptureEq(&if_false)), + effect, _), + IsInt32Constant(JS_DATE_TYPE)), + IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), + IsBranch(IsObjectIsSmi(input), control))), + AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); +} + + +// ----------------------------------------------------------------------------- +// %_IsTypedArray + + +TEST_F(JSIntrinsicLoweringTest, InlineIsTypedArray) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce(graph()->NewNode( + javascript()->CallRuntime(Runtime::kInlineIsTypedArray, 1), input, + context, effect, control)); + ASSERT_TRUE(r.Changed()); + + Node* phi = r.replacement(); + Capture<Node*> branch, if_false; + EXPECT_THAT( + phi, + IsPhi( + static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(), + IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(), + IsLoadField(AccessBuilder::ForMap(), input, + effect, CaptureEq(&if_false)), + effect, _), + IsInt32Constant(JS_TYPED_ARRAY_TYPE)), + IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), + IsBranch(IsObjectIsSmi(input), control))), + AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); +} + + +// ----------------------------------------------------------------------------- // %_IsFunction @@ -264,7 +329,7 @@ TEST_F(JSIntrinsicLoweringTest, Likely) { Node* const to_boolean = graph()->NewNode(javascript()->ToBoolean(), likely, context); Diamond d(graph(), common(), to_boolean); - graph()->SetEnd(graph()->NewNode(common()->End(), d.merge)); + graph()->SetEnd(graph()->NewNode(common()->End(1), d.merge)); ASSERT_EQ(BranchHint::kNone, BranchHintOf(d.branch->op())); Reduction const r = Reduce(likely); @@ -359,7 +424,7 @@ TEST_F(JSIntrinsicLoweringTest, Unlikely) { Node* const to_boolean = graph()->NewNode(javascript()->ToBoolean(), unlikely, context); Diamond d(graph(), common(), to_boolean); - graph()->SetEnd(graph()->NewNode(common()->End(), d.merge)); + graph()->SetEnd(graph()->NewNode(common()->End(1), d.merge)); ASSERT_EQ(BranchHint::kNone, BranchHintOf(d.branch->op())); Reduction const r = Reduce(unlikely); diff --git a/deps/v8/test/unittests/compiler/js-operator-unittest.cc b/deps/v8/test/unittests/compiler/js-operator-unittest.cc index a8a2d8c38a..0f33ddea8d 100644 --- a/deps/v8/test/unittests/compiler/js-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-operator-unittest.cc @@ -186,10 +186,10 @@ const SharedOperatorWithLanguageMode kSharedOperatorsWithLanguageMode[] = { control_input_count, value_output_count, effect_output_count, \ control_output_count \ } - SHARED(LessThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), - SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), - SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), - SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(LessThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(GreaterThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(BitwiseOr, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(BitwiseXor, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(BitwiseAnd, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), @@ -201,7 +201,6 @@ const SharedOperatorWithLanguageMode kSharedOperatorsWithLanguageMode[] = { SHARED(Multiply, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(Divide, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(Modulus, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), - SHARED(StoreProperty, Operator::kNoProperties, 3, 2, 1, 1, 0, 1, 2), #undef SHARED }; 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 08fe68a8ba..d52242ec7d 100644 --- a/deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-type-feedback-unittest.cc @@ -34,15 +34,18 @@ class JSTypeFeedbackTest : public TypedGraphTest { ~JSTypeFeedbackTest() override { dependencies_.Rollback(); } protected: - Reduction Reduce(Node* node) { + Reduction Reduce(Node* node, + JSTypeFeedbackSpecializer::DeoptimizationMode mode) { Handle<GlobalObject> global_object( isolate()->native_context()->global_object(), isolate()); MachineOperatorBuilder machine(zone()); JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); JSTypeFeedbackTable table(zone()); - JSTypeFeedbackSpecializer reducer(&jsgraph, &table, nullptr, global_object, - &dependencies_); + // TODO(titzer): mock the GraphReducer here for better unit testing. + GraphReducer graph_reducer(zone(), graph()); + JSTypeFeedbackSpecializer reducer(&graph_reducer, &jsgraph, &table, nullptr, + global_object, mode, &dependencies_); return reducer.Reduce(node); } @@ -71,19 +74,23 @@ class JSTypeFeedbackTest : public TypedGraphTest { result.Assert(); } - Node* ReturnLoadNamedFromGlobal(const char* string, Node* effect, - Node* control) { - VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(), - FeedbackVectorICSlot::Invalid()); - Node* global = Parameter(Type::GlobalObject()); + Node* ReturnLoadNamedFromGlobal( + const char* string, Node* effect, Node* control, + JSTypeFeedbackSpecializer::DeoptimizationMode mode) { + VectorSlotPair feedback; + Node* global = UndefinedConstant(); + Node* vector = UndefinedConstant(); Node* context = UndefinedConstant(); Unique<Name> name = Unique<Name>::CreateUninitialized( - isolate()->factory()->NewStringFromAsciiChecked(string)); - Node* load = graph()->NewNode(javascript()->LoadNamed(name, feedback), - global, context); - if (FLAG_turbo_deoptimization) { - load->AppendInput(zone(), EmptyFrameState()); + isolate()->factory()->InternalizeUtf8String(string)); + const Operator* op = javascript()->LoadGlobal(name, feedback); + Node* load = graph()->NewNode(op, global, vector, context); + if (mode == JSTypeFeedbackSpecializer::kDeoptimizationEnabled) { + for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); + i++) { + load->AppendInput(zone(), EmptyFrameState()); + } } load->AppendInput(zone(), effect); load->AppendInput(zone(), control); @@ -98,180 +105,240 @@ class JSTypeFeedbackTest : public TypedGraphTest { CompilationDependencies dependencies_; }; -#define WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION \ - for (int i = FLAG_turbo_deoptimization = 0; i < 2; \ - FLAG_turbo_deoptimization = ++i) +TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstSmi) { + const int kValue = 111; + const char* kName = "banana"; + SetGlobalProperty(kName, kValue); -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConst_smi) { - const int const_value = 111; - const char* property_name = "banana"; - SetGlobalProperty(property_name, const_value); + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { - Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), - graph()->start()); - graph()->SetEnd(graph()->NewNode(common()->End(), ret)); + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); + EXPECT_FALSE(r.Changed()); + EXPECT_TRUE(dependencies()->IsEmpty()); +} - Reduction r = Reduce(ret->InputAt(0)); - if (FLAG_turbo_deoptimization) { - // Check LoadNamed(global) => HeapConstant[const_value] - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(const_value)); +TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstSmiWithDeoptimization) { + const int kValue = 111; + const char* kName = "banana"; + SetGlobalProperty(kName, kValue); - EXPECT_THAT(ret, IsReturn(IsNumberConstant(const_value), graph()->start(), - graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - EXPECT_FALSE(dependencies()->IsEmpty()); - dependencies()->Rollback(); - } else { - ASSERT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); - } - } + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + + // Check LoadNamed(global) => HeapConstant[kValue] + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(kValue)); + + EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), graph()->start(), + graph()->start())); + EXPECT_THAT(graph()->end(), IsEnd(ret)); + + EXPECT_FALSE(dependencies()->IsEmpty()); + dependencies()->Rollback(); } -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConst_derble) { - const double const_value = -11.25; - const char* property_name = "kiwi"; - SetGlobalProperty(property_name, const_value); +TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstNumber) { + const double kValue = -11.25; + const char* kName = "kiwi"; + SetGlobalProperty(kName, kValue); - WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { - Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), - graph()->start()); - graph()->SetEnd(graph()->NewNode(common()->End(), ret)); + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); - Reduction r = Reduce(ret->InputAt(0)); + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); - if (FLAG_turbo_deoptimization) { - // Check LoadNamed(global) => HeapConstant[const_value] - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(const_value)); + EXPECT_FALSE(r.Changed()); + EXPECT_TRUE(dependencies()->IsEmpty()); +} - EXPECT_THAT(ret, IsReturn(IsNumberConstant(const_value), graph()->start(), - graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); - EXPECT_FALSE(dependencies()->IsEmpty()); - } else { - ASSERT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); - } - } +TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstNumberWithDeoptimization) { + const double kValue = -11.25; + const char* kName = "kiwi"; + SetGlobalProperty(kName, kValue); + + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); + + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + + // Check LoadNamed(global) => HeapConstant[kValue] + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(kValue)); + + EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), graph()->start(), + graph()->start())); + EXPECT_THAT(graph()->end(), IsEnd(ret)); + + EXPECT_FALSE(dependencies()->IsEmpty()); } -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConst_string) { - Unique<HeapObject> const_value = Unique<HeapObject>::CreateImmovable( +TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstString) { + Unique<HeapObject> kValue = Unique<HeapObject>::CreateImmovable( isolate()->factory()->undefined_string()); - const char* property_name = "mango"; - SetGlobalProperty(property_name, const_value.handle()); - - WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { - Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), - graph()->start()); - graph()->SetEnd(graph()->NewNode(common()->End(), ret)); - - Reduction r = Reduce(ret->InputAt(0)); - - if (FLAG_turbo_deoptimization) { - // Check LoadNamed(global) => HeapConstant[const_value] - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsHeapConstant(const_value)); - - EXPECT_THAT(ret, IsReturn(IsHeapConstant(const_value), graph()->start(), - graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); - - EXPECT_FALSE(dependencies()->IsEmpty()); - dependencies()->Rollback(); - } else { - ASSERT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); - } - } + const char* kName = "mango"; + SetGlobalProperty(kName, kValue.handle()); + + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); + + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); + ASSERT_FALSE(r.Changed()); + EXPECT_TRUE(dependencies()->IsEmpty()); } -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCell_smi) { - const char* property_name = "melon"; - SetGlobalProperty(property_name, 123); - SetGlobalProperty(property_name, 124); - - WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { - Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), - graph()->start()); - graph()->SetEnd(graph()->NewNode(common()->End(), ret)); - - Reduction r = Reduce(ret->InputAt(0)); - - if (FLAG_turbo_deoptimization) { - // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) - ASSERT_TRUE(r.Changed()); - FieldAccess access = AccessBuilder::ForPropertyCellValue(); - Capture<Node*> cell_capture; - Matcher<Node*> load_field_match = IsLoadField( - access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); - EXPECT_THAT(r.replacement(), load_field_match); - - HeapObjectMatcher<PropertyCell> cell(cell_capture.value()); - EXPECT_TRUE(cell.HasValue()); - EXPECT_TRUE(cell.Value().handle()->IsPropertyCell()); - - EXPECT_THAT( - ret, IsReturn(load_field_match, load_field_match, graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); - - EXPECT_FALSE(dependencies()->IsEmpty()); - dependencies()->Rollback(); - } else { - ASSERT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); - } - } +TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstStringWithDeoptimization) { + Unique<HeapObject> kValue = Unique<HeapObject>::CreateImmovable( + isolate()->factory()->undefined_string()); + const char* kName = "mango"; + SetGlobalProperty(kName, kValue.handle()); + + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); + + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + + // Check LoadNamed(global) => HeapConstant[kValue] + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsHeapConstant(kValue)); + + EXPECT_THAT(ret, IsReturn(IsHeapConstant(kValue), graph()->start(), + graph()->start())); + EXPECT_THAT(graph()->end(), IsEnd(ret)); + + EXPECT_FALSE(dependencies()->IsEmpty()); + dependencies()->Rollback(); } -TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCell_string) { - const char* property_name = "pineapple"; - SetGlobalProperty(property_name, isolate()->factory()->undefined_string()); - SetGlobalProperty(property_name, isolate()->factory()->undefined_value()); - - WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { - Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), - graph()->start()); - graph()->SetEnd(graph()->NewNode(common()->End(), ret)); - - Reduction r = Reduce(ret->InputAt(0)); - - if (FLAG_turbo_deoptimization) { - // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) - ASSERT_TRUE(r.Changed()); - FieldAccess access = AccessBuilder::ForPropertyCellValue(); - Capture<Node*> cell_capture; - Matcher<Node*> load_field_match = IsLoadField( - access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); - EXPECT_THAT(r.replacement(), load_field_match); - - HeapObjectMatcher<PropertyCell> cell(cell_capture.value()); - EXPECT_TRUE(cell.HasValue()); - EXPECT_TRUE(cell.Value().handle()->IsPropertyCell()); - - EXPECT_THAT( - ret, IsReturn(load_field_match, load_field_match, graph()->start())); - EXPECT_THAT(graph()->end(), IsEnd(ret)); - - EXPECT_FALSE(dependencies()->IsEmpty()); - dependencies()->Rollback(); - } else { - ASSERT_FALSE(r.Changed()); - EXPECT_TRUE(dependencies()->IsEmpty()); - } - } +TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCellSmi) { + const char* kName = "melon"; + SetGlobalProperty(kName, 123); + SetGlobalProperty(kName, 124); + + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); + + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); + ASSERT_FALSE(r.Changed()); + EXPECT_TRUE(dependencies()->IsEmpty()); } + + +TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCellSmiWithDeoptimization) { + const char* kName = "melon"; + SetGlobalProperty(kName, 123); + SetGlobalProperty(kName, 124); + + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); + + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + + // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) + ASSERT_TRUE(r.Changed()); + FieldAccess access = AccessBuilder::ForPropertyCellValue(); + Capture<Node*> cell_capture; + Matcher<Node*> load_field_match = IsLoadField( + access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); + EXPECT_THAT(r.replacement(), load_field_match); + + HeapObjectMatcher cell(cell_capture.value()); + EXPECT_TRUE(cell.HasValue()); + EXPECT_TRUE(cell.Value().handle()->IsPropertyCell()); + + EXPECT_THAT(ret, + IsReturn(load_field_match, load_field_match, graph()->start())); + EXPECT_THAT(graph()->end(), IsEnd(ret)); + + EXPECT_FALSE(dependencies()->IsEmpty()); + dependencies()->Rollback(); } + + +TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCellString) { + const char* kName = "pineapple"; + SetGlobalProperty(kName, isolate()->factory()->undefined_string()); + SetGlobalProperty(kName, isolate()->factory()->undefined_value()); + + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); + + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationDisabled); + ASSERT_FALSE(r.Changed()); + EXPECT_TRUE(dependencies()->IsEmpty()); } + + +TEST_F(JSTypeFeedbackTest, + JSLoadNamedGlobalPropertyCellStringWithDeoptimization) { + const char* kName = "pineapple"; + SetGlobalProperty(kName, isolate()->factory()->undefined_string()); + SetGlobalProperty(kName, isolate()->factory()->undefined_value()); + + Node* ret = ReturnLoadNamedFromGlobal( + kName, graph()->start(), graph()->start(), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); + + Reduction r = Reduce(ret->InputAt(0), + JSTypeFeedbackSpecializer::kDeoptimizationEnabled); + + // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) + ASSERT_TRUE(r.Changed()); + FieldAccess access = AccessBuilder::ForPropertyCellValue(); + Capture<Node*> cell_capture; + Matcher<Node*> load_field_match = IsLoadField( + access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); + EXPECT_THAT(r.replacement(), load_field_match); + + HeapObjectMatcher cell(cell_capture.value()); + EXPECT_TRUE(cell.HasValue()); + EXPECT_TRUE(cell.Value().handle()->IsPropertyCell()); + + EXPECT_THAT(ret, + IsReturn(load_field_match, load_field_match, graph()->start())); + EXPECT_THAT(graph()->end(), IsEnd(ret)); + + EXPECT_FALSE(dependencies()->IsEmpty()); + dependencies()->Rollback(); } + +} // namespace compiler +} // namespace internal +} // namespace v8 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 9e7b1eecbd..a12d79f02b 100644 --- a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -80,16 +80,12 @@ class JSTypedLoweringTest : public TypedGraphTest { Reduction Reduce(Node* node) { MachineOperatorBuilder machine(zone()); JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); - JSTypedLowering reducer(&jsgraph, zone()); + // TODO(titzer): mock the GraphReducer here for better unit testing. + GraphReducer graph_reducer(zone(), graph()); + JSTypedLowering reducer(&graph_reducer, &jsgraph, zone()); return reducer.Reduce(node); } - Node* EmptyFrameState() { - MachineOperatorBuilder machine(zone()); - JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); - return jsgraph.EmptyFrameState(); - } - Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) { Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer(); Runtime::SetupArrayBuffer(isolate(), buffer, true, bytes, byte_length); @@ -434,18 +430,27 @@ TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) { TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) { Node* const the_hole = HeapConstant(factory()->the_hole_value()); Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); TRACED_FOREACH(Type*, type, kJSTypes) { Node* const lhs = Parameter(type); - Reduction r = Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs, - the_hole, context, effect, control)); + Reduction r = Reduce( + graph()->NewNode(javascript()->StrictEqual(), lhs, the_hole, context)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFalseConstant()); } } +TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) { + Node* const lhs = Parameter(Type::Unique(), 0); + Node* const rhs = Parameter(Type::Unique(), 1); + Node* const context = Parameter(Type::Any(), 2); + Reduction r = + Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs, rhs, context)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsReferenceEqual(Type::Unique(), lhs, rhs)); +} + + // ----------------------------------------------------------------------------- // JSShiftLeft @@ -457,13 +462,12 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) { Node* const control = graph()->start(); TRACED_FORRANGE(double, rhs, 0, 31) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = - Reduce(graph()->NewNode(javascript()->ShiftLeft(language_mode), lhs, - NumberConstant(rhs), context, effect, - control)); + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftLeft(language_mode), lhs, NumberConstant(rhs), + context, EmptyFrameState(), EmptyFrameState(), effect, control)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), - IsWord32Shl(lhs, IsNumberConstant(BitEq(rhs)))); + IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs)))); } } } @@ -476,12 +480,11 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) { Node* const effect = graph()->start(); Node* const control = graph()->start(); TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = - Reduce(graph()->NewNode(javascript()->ShiftLeft(language_mode), lhs, - rhs, context, effect, control)); + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftLeft(language_mode), lhs, rhs, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsWord32Shl(lhs, IsWord32And(rhs, IsInt32Constant(0x1f)))); + EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs)); } } @@ -497,13 +500,12 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) { Node* const control = graph()->start(); TRACED_FORRANGE(double, rhs, 0, 31) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = - Reduce(graph()->NewNode(javascript()-> ShiftRight(language_mode), lhs, - NumberConstant(rhs), context, effect, - control)); + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftRight(language_mode), lhs, NumberConstant(rhs), + context, EmptyFrameState(), EmptyFrameState(), effect, control)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), - IsWord32Sar(lhs, IsNumberConstant(BitEq(rhs)))); + IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs)))); } } } @@ -516,12 +518,11 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) { Node* const effect = graph()->start(); Node* const control = graph()->start(); TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode(javascript()-> - ShiftRight(language_mode), lhs, rhs, - context, effect, control)); + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftRight(language_mode), lhs, rhs, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsWord32Sar(lhs, IsWord32And(rhs, IsInt32Constant(0x1f)))); + EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs)); } } @@ -538,14 +539,13 @@ TEST_F(JSTypedLoweringTest, Node* const control = graph()->start(); TRACED_FORRANGE(double, rhs, 0, 31) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = - Reduce(graph()->NewNode(javascript()-> - ShiftRightLogical(language_mode), lhs, - NumberConstant(rhs), context, effect, - control)); + Reduction r = Reduce( + graph()->NewNode(javascript()->ShiftRightLogical(language_mode), lhs, + NumberConstant(rhs), context, EmptyFrameState(), + EmptyFrameState(), effect, control)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), - IsWord32Shr(lhs, IsNumberConstant(BitEq(rhs)))); + IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs)))); } } } @@ -559,12 +559,11 @@ TEST_F(JSTypedLoweringTest, Node* const effect = graph()->start(); Node* const control = graph()->start(); TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode(javascript()-> - ShiftRightLogical(language_mode), lhs, - rhs, context, effect, control)); + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftRightLogical(language_mode), lhs, rhs, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsWord32Shr(lhs, IsWord32And(rhs, IsInt32Constant(0x1f)))); + EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs)); } } @@ -646,36 +645,39 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) { double backing_store[kLength]; Handle<JSArrayBuffer> buffer = NewArrayBuffer(backing_store, sizeof(backing_store)); - VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(), - FeedbackVectorICSlot::Invalid()); + VectorSlotPair feedback; TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { - Handle<JSTypedArray> array = - factory()->NewJSTypedArray(type, buffer, 0, kLength); - int const element_size = static_cast<int>(array->element_size()); - - Node* key = Parameter( - Type::Range(kMinInt / element_size, kMaxInt / element_size, zone())); - Node* base = HeapConstant(array); - Node* context = UndefinedConstant(); - Node* effect = graph()->start(); - Node* control = graph()->start(); - Reduction r = - Reduce(graph()->NewNode(javascript()->LoadProperty(feedback), base, key, - context, EmptyFrameState(), effect, control)); + TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { + Handle<JSTypedArray> array = + factory()->NewJSTypedArray(type, buffer, 0, kLength); + int const element_size = static_cast<int>(array->element_size()); + + Node* key = Parameter( + Type::Range(kMinInt / element_size, kMaxInt / element_size, zone())); + Node* base = HeapConstant(array); + Node* vector = UndefinedConstant(); + Node* context = UndefinedConstant(); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Reduction r = Reduce( + graph()->NewNode(javascript()->LoadProperty(feedback, language_mode), + base, key, vector, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); - Matcher<Node*> offset_matcher = - element_size == 1 - ? key - : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); + Matcher<Node*> offset_matcher = + element_size == 1 + ? key + : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsLoadBuffer(BufferAccess(type), - IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), - offset_matcher, - IsNumberConstant(array->byte_length()->Number()), effect, - control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsLoadBuffer(BufferAccess(type), + IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), + offset_matcher, + IsNumberConstant(array->byte_length()->Number()), effect, + control)); + } } } @@ -685,31 +687,34 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) { double backing_store[kLength]; Handle<JSArrayBuffer> buffer = NewArrayBuffer(backing_store, sizeof(backing_store)); - VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(), - FeedbackVectorICSlot::Invalid()); + VectorSlotPair feedback; TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { - Handle<JSTypedArray> array = - factory()->NewJSTypedArray(type, buffer, 0, kLength); - ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); - - int min = random_number_generator()->NextInt(static_cast<int>(kLength)); - int max = random_number_generator()->NextInt(static_cast<int>(kLength)); - if (min > max) std::swap(min, max); - Node* key = Parameter(Type::Range(min, max, zone())); - Node* base = HeapConstant(array); - Node* context = UndefinedConstant(); - Node* effect = graph()->start(); - Node* control = graph()->start(); - Reduction r = - Reduce(graph()->NewNode(javascript()->LoadProperty(feedback), base, key, - context, EmptyFrameState(), effect, control)); + TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { + Handle<JSTypedArray> array = + factory()->NewJSTypedArray(type, buffer, 0, kLength); + ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsLoadElement(access, - IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), - key, effect, control)); + int min = random_number_generator()->NextInt(static_cast<int>(kLength)); + int max = random_number_generator()->NextInt(static_cast<int>(kLength)); + if (min > max) std::swap(min, max); + Node* key = Parameter(Type::Range(min, max, zone())); + Node* base = HeapConstant(array); + Node* vector = UndefinedConstant(); + Node* context = UndefinedConstant(); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Reduction r = Reduce( + graph()->NewNode(javascript()->LoadProperty(feedback, language_mode), + base, key, vector, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsLoadElement(access, + IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), + key, effect, control)); + } } } @@ -734,11 +739,13 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) { Node* base = HeapConstant(array); Node* value = Parameter(AccessBuilder::ForTypedArrayElement(type, true).type); + Node* vector = UndefinedConstant(); Node* context = UndefinedConstant(); Node* effect = graph()->start(); Node* control = graph()->start(); - Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode), - base, key, value, context); + VectorSlotPair feedback; + const Operator* op = javascript()->StoreProperty(language_mode, feedback); + Node* node = graph()->NewNode(op, base, key, value, vector, context); for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) { node->AppendInput(zone(), EmptyFrameState()); @@ -780,11 +787,13 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) { Type::Range(kMinInt / element_size, kMaxInt / element_size, zone())); Node* base = HeapConstant(array); Node* value = Parameter(Type::Any()); + Node* vector = UndefinedConstant(); Node* context = UndefinedConstant(); Node* effect = graph()->start(); Node* control = graph()->start(); - Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode), - base, key, value, context); + VectorSlotPair feedback; + const Operator* op = javascript()->StoreProperty(language_mode, feedback); + Node* node = graph()->NewNode(op, base, key, value, vector, context); for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) { node->AppendInput(zone(), EmptyFrameState()); @@ -839,11 +848,13 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) { Node* key = Parameter(Type::Range(min, max, zone())); Node* base = HeapConstant(array); Node* value = Parameter(access.type); + Node* vector = UndefinedConstant(); Node* context = UndefinedConstant(); Node* effect = graph()->start(); Node* control = graph()->start(); - Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode), - base, key, value, context); + VectorSlotPair feedback; + const Operator* op = javascript()->StoreProperty(language_mode, feedback); + Node* node = graph()->NewNode(op, base, key, value, vector, context); for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) { node->AppendInput(zone(), EmptyFrameState()); @@ -876,18 +887,18 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) { IsNumberConstant(IsNaN()) // -- }; - VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(), - FeedbackVectorICSlot::Invalid()); - Node* global = Parameter(Type::GlobalObject()); + VectorSlotPair feedback; + Node* global = UndefinedConstant(); + Node* vector = UndefinedConstant(); Node* context = UndefinedConstant(); Node* effect = graph()->start(); Node* control = graph()->start(); for (size_t i = 0; i < arraysize(names); i++) { Unique<Name> name = Unique<Name>::CreateImmovable(names[i]); - Reduction r = - Reduce(graph()->NewNode(javascript()->LoadNamed(name, feedback), global, - context, EmptyFrameState(), effect, control)); + Reduction r = Reduce(graph()->NewNode( + javascript()->LoadGlobal(name, feedback), global, vector, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), matches[i]); @@ -896,9 +907,106 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) { // ----------------------------------------------------------------------------- -// JSCreateClosure +// JSLoadDynamicGlobal + + +TEST_F(JSTypedLoweringTest, JSLoadDynamicGlobal) { + Node* const context = Parameter(Type::Any()); + Node* const vector = UndefinedConstant(); + Node* const frame_state = EmptyFrameState(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<String> name = factory()->object_string(); + VectorSlotPair feedback; + 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), + vector, context, context, frame_state, frame_state, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsPhi(kMachAnyTagged, _, _, + IsMerge( + IsIfTrue(IsBranch( + IsReferenceEqual( + Type::Tagged(), + IsLoadContext( + ContextAccess(i, Context::EXTENSION_INDEX, false), + context), + IsNumberConstant(BitEq(0.0))), + control)), + _))); + } +} + + +// ----------------------------------------------------------------------------- +// JSLoadDynamicContext + + +TEST_F(JSTypedLoweringTest, JSLoadDynamicContext) { + Node* const context = Parameter(Type::Any()); + Node* const frame_state = EmptyFrameState(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<String> name = factory()->object_string(); + for (int i = 0; i < DynamicContextAccess::kMaxCheckDepth; ++i) { + uint32_t bitset = 1 << i; // Only single check. + Reduction r = Reduce( + graph()->NewNode(javascript()->LoadDynamicContext(name, bitset, 23, 42), + context, context, frame_state, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsPhi(kMachAnyTagged, + IsLoadContext(ContextAccess(23, 42, false), context), _, + IsMerge( + IsIfTrue(IsBranch( + IsReferenceEqual( + Type::Tagged(), + IsLoadContext( + ContextAccess(i, Context::EXTENSION_INDEX, false), + context), + IsNumberConstant(BitEq(0.0))), + control)), + _))); + } +} #if V8_TURBOFAN_TARGET + +// ----------------------------------------------------------------------------- +// JSAdd + + +TEST_F(JSTypedLoweringTest, JSAddWithString) { + TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { + Node* lhs = Parameter(Type::String(), 0); + Node* rhs = Parameter(Type::String(), 1); + Node* context = Parameter(Type::Any(), 2); + Node* frame_state0 = EmptyFrameState(); + Node* frame_state1 = EmptyFrameState(); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Reduction r = Reduce(graph()->NewNode(javascript()->Add(language_mode), lhs, + rhs, context, frame_state0, + frame_state1, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable( + CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, + NOT_TENURED).code())), + lhs, rhs, context, frame_state0, effect, control)); + } +} + + +// ----------------------------------------------------------------------------- +// JSCreateClosure + + TEST_F(JSTypedLoweringTest, JSCreateClosure) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); @@ -965,7 +1073,8 @@ TEST_F(JSTypedLoweringTest, JSCreateLiteralObject) { CodeFactory::FastCloneShallowObject(isolate(), 6).code())), input0, input1, input2, _, context, frame_state, effect, control)); } -#endif + +#endif // V8_TURBOFAN_TARGET // ----------------------------------------------------------------------------- diff --git a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc index d5a95ccd1d..1e142550d5 100644 --- a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc +++ b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc @@ -57,8 +57,13 @@ class LivenessAnalysisTest : public GraphTest { Node* locals = graph()->NewNode(locals_op, locals_count_, &local_inputs.front()); + const FrameStateFunctionInfo* state_info = + common()->CreateFrameStateFunctionInfo( + FrameStateType::kJavaScriptFunction, 0, locals_count_, + Handle<SharedFunctionInfo>()); + const Operator* op = common()->FrameState( - JS_FRAME, BailoutId(ast_num), OutputFrameStateCombine::Ignore()); + BailoutId(ast_num), OutputFrameStateCombine::Ignore(), state_info); Node* result = graph()->NewNode(op, empty_values_, locals, empty_values_, jsgraph()->UndefinedConstant(), jsgraph()->UndefinedConstant()); @@ -93,8 +98,7 @@ class LivenessAnalysisTest : public GraphTest { } DCHECK(frame_state->opcode() == IrOpcode::kFrameState); - FrameStateCallInfo state_info = - OpParameter<FrameStateCallInfo>(frame_state); + FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); int ast_num = state_info.bailout_id().ToInt(); int first_const = intconst_from_bailout_id(ast_num, locals_count_); diff --git a/deps/v8/test/unittests/compiler/load-elimination-unittest.cc b/deps/v8/test/unittests/compiler/load-elimination-unittest.cc index 52c3143e2a..3ad11cf43f 100644 --- a/deps/v8/test/unittests/compiler/load-elimination-unittest.cc +++ b/deps/v8/test/unittests/compiler/load-elimination-unittest.cc @@ -19,7 +19,9 @@ class LoadEliminationTest : public GraphTest { protected: Reduction Reduce(Node* node) { - LoadElimination reducer; + // TODO(titzer): mock the GraphReducer here for better unit testing. + GraphReducer graph_reducer(zone(), graph()); + LoadElimination reducer(&graph_reducer); return reducer.Reduce(node); } diff --git a/deps/v8/test/unittests/compiler/loop-peeling-unittest.cc b/deps/v8/test/unittests/compiler/loop-peeling-unittest.cc index d3eff716a7..c725a27cc0 100644 --- a/deps/v8/test/unittests/compiler/loop-peeling-unittest.cc +++ b/deps/v8/test/unittests/compiler/loop-peeling-unittest.cc @@ -478,7 +478,8 @@ TEST_F(LoopPeelingTest, TwoExitLoopWithCall_nope) { Node* call = graph()->NewNode(&kMockCall, b1.if_true); Node* if_success = graph()->NewNode(common()->IfSuccess(), call); - Node* if_exception = graph()->NewNode(common()->IfException(), call); + Node* if_exception = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), call); loop->ReplaceInput(1, if_success); Node* merge = graph()->NewNode(common()->Merge(2), b1.if_false, if_exception); 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 9836be4fb2..ce11fdef81 100644 --- a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -234,6 +234,10 @@ const uint32_t kUint32Values[] = { 0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff}; +const TruncationMode kTruncationModes[] = {TruncationMode::kJavaScript, + TruncationMode::kRoundToZero}; + + struct ComparisonBinaryOperator { const Operator* (MachineOperatorBuilder::*constructor)(); const char* constructor_name; @@ -258,53 +262,6 @@ const ComparisonBinaryOperator kComparisonBinaryOperators[] = { // ----------------------------------------------------------------------------- -// Unary operators - - -namespace { - -struct UnaryOperator { - const Operator* (MachineOperatorBuilder::*constructor)(); - const char* constructor_name; -}; - - -std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) { - return os << unop.constructor_name; -} - - -static const UnaryOperator kUnaryOperators[] = { - {&MachineOperatorBuilder::ChangeInt32ToFloat64, "ChangeInt32ToFloat64"}, - {&MachineOperatorBuilder::ChangeUint32ToFloat64, "ChangeUint32ToFloat64"}, - {&MachineOperatorBuilder::ChangeFloat64ToInt32, "ChangeFloat64ToInt32"}, - {&MachineOperatorBuilder::ChangeFloat64ToUint32, "ChangeFloat64ToUint32"}, - {&MachineOperatorBuilder::ChangeInt32ToInt64, "ChangeInt32ToInt64"}, - {&MachineOperatorBuilder::ChangeUint32ToUint64, "ChangeUint32ToUint64"}, - {&MachineOperatorBuilder::TruncateFloat64ToInt32, "TruncateFloat64ToInt32"}, - {&MachineOperatorBuilder::TruncateInt64ToInt32, "TruncateInt64ToInt32"}}; - -} // namespace - - -typedef MachineOperatorReducerTestWithParam<UnaryOperator> - MachineUnaryOperatorReducerTest; - - -TEST_P(MachineUnaryOperatorReducerTest, Parameter) { - const UnaryOperator unop = GetParam(); - Reduction reduction = - Reduce(graph()->NewNode((machine()->*unop.constructor)(), Parameter(0))); - EXPECT_FALSE(reduction.Changed()); -} - - -INSTANTIATE_TEST_CASE_P(MachineOperatorReducerTest, - MachineUnaryOperatorReducerTest, - ::testing::ValuesIn(kUnaryOperators)); - - -// ----------------------------------------------------------------------------- // ChangeFloat64ToFloat32 @@ -459,19 +416,22 @@ TEST_F(MachineOperatorReducerTest, TruncateFloat64ToFloat32WithConstant) { TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithChangeInt32ToFloat64) { - Node* value = Parameter(0); - Reduction reduction = Reduce(graph()->NewNode( - machine()->TruncateFloat64ToInt32(), - graph()->NewNode(machine()->ChangeInt32ToFloat64(), value))); - ASSERT_TRUE(reduction.Changed()); - EXPECT_EQ(value, reduction.replacement()); + TRACED_FOREACH(TruncationMode, mode, kTruncationModes) { + Node* value = Parameter(0); + Reduction reduction = Reduce(graph()->NewNode( + machine()->TruncateFloat64ToInt32(mode), + graph()->NewNode(machine()->ChangeInt32ToFloat64(), value))); + ASSERT_TRUE(reduction.Changed()); + EXPECT_EQ(value, reduction.replacement()); + } } TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithConstant) { TRACED_FOREACH(double, x, kFloat64Values) { Reduction reduction = Reduce(graph()->NewNode( - machine()->TruncateFloat64ToInt32(), Float64Constant(x))); + machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript), + Float64Constant(x))); ASSERT_TRUE(reduction.Changed()); EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(x))); } @@ -482,13 +442,15 @@ TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithPhi) { Node* const p0 = Parameter(0); Node* const p1 = Parameter(1); Node* const merge = graph()->start(); - Reduction reduction = Reduce(graph()->NewNode( - machine()->TruncateFloat64ToInt32(), - graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge))); - ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), - IsPhi(kMachInt32, IsTruncateFloat64ToInt32(p0), - IsTruncateFloat64ToInt32(p1), merge)); + TRACED_FOREACH(TruncationMode, mode, kTruncationModes) { + Reduction reduction = Reduce(graph()->NewNode( + machine()->TruncateFloat64ToInt32(mode), + graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge))); + ASSERT_TRUE(reduction.Changed()); + EXPECT_THAT(reduction.replacement(), + IsPhi(kMachInt32, IsTruncateFloat64ToInt32(p0), + IsTruncateFloat64ToInt32(p1), merge)); + } } diff --git a/deps/v8/test/unittests/compiler/machine-operator-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-unittest.cc index 31f55793c3..fca53e2bd8 100644 --- a/deps/v8/test/unittests/compiler/machine-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/machine-operator-unittest.cc @@ -149,130 +149,199 @@ INSTANTIATE_TEST_CASE_P( ::testing::Combine(::testing::ValuesIn(kMachineTypes), ::testing::Values(kNoWriteBarrier, kFullWriteBarrier)))); - +#endif // ----------------------------------------------------------------------------- // Pure operators. - namespace { struct PureOperator { const Operator* (MachineOperatorBuilder::*constructor)(); - IrOpcode::Value opcode; + char const* const constructor_name; int value_input_count; int control_input_count; int value_output_count; }; -std::ostream& operator<<(std::ostream& os, const PureOperator& pop) { - return os << IrOpcode::Mnemonic(pop.opcode); +std::ostream& operator<<(std::ostream& os, PureOperator const& pop) { + return os << pop.constructor_name; } - const PureOperator kPureOperators[] = { #define PURE(Name, value_input_count, control_input_count, value_output_count) \ { \ - &MachineOperatorBuilder::Name, IrOpcode::k##Name, value_input_count, \ + &MachineOperatorBuilder::Name, #Name, value_input_count, \ control_input_count, value_output_count \ } - PURE(Word32And, 2, 0, 1), PURE(Word32Or, 2, 0, 1), PURE(Word32Xor, 2, 0, 1), - PURE(Word32Shl, 2, 0, 1), PURE(Word32Shr, 2, 0, 1), - PURE(Word32Sar, 2, 0, 1), PURE(Word32Ror, 2, 0, 1), - PURE(Word32Equal, 2, 0, 1), PURE(Word32Clz, 1, 0, 1), - PURE(Word64And, 2, 0, 1), PURE(Word64Or, 2, 0, 1), PURE(Word64Xor, 2, 0, 1), - PURE(Word64Shl, 2, 0, 1), PURE(Word64Shr, 2, 0, 1), - PURE(Word64Sar, 2, 0, 1), PURE(Word64Ror, 2, 0, 1), - PURE(Word64Equal, 2, 0, 1), PURE(Int32Add, 2, 0, 1), - PURE(Int32AddWithOverflow, 2, 0, 2), PURE(Int32Sub, 2, 0, 1), - PURE(Int32SubWithOverflow, 2, 0, 2), PURE(Int32Mul, 2, 0, 1), - PURE(Int32MulHigh, 2, 0, 1), PURE(Int32Div, 2, 1, 1), - PURE(Uint32Div, 2, 1, 1), PURE(Int32Mod, 2, 1, 1), PURE(Uint32Mod, 2, 1, 1), - PURE(Int32LessThan, 2, 0, 1), PURE(Int32LessThanOrEqual, 2, 0, 1), - PURE(Uint32LessThan, 2, 0, 1), PURE(Uint32LessThanOrEqual, 2, 0, 1), - PURE(Int64Add, 2, 0, 1), PURE(Int64Sub, 2, 0, 1), PURE(Int64Mul, 2, 0, 1), - PURE(Int64Div, 2, 0, 1), PURE(Uint64Div, 2, 0, 1), PURE(Int64Mod, 2, 0, 1), - PURE(Uint64Mod, 2, 0, 1), PURE(Int64LessThan, 2, 0, 1), - PURE(Int64LessThanOrEqual, 2, 0, 1), PURE(Uint64LessThan, 2, 0, 1), - PURE(ChangeFloat32ToFloat64, 1, 0, 1), PURE(ChangeFloat64ToInt32, 1, 0, 1), - PURE(ChangeFloat64ToUint32, 1, 0, 1), PURE(ChangeInt32ToInt64, 1, 0, 1), - PURE(ChangeUint32ToFloat64, 1, 0, 1), PURE(ChangeUint32ToUint64, 1, 0, 1), - PURE(TruncateFloat64ToFloat32, 1, 0, 1), - PURE(TruncateFloat64ToInt32, 1, 0, 1), PURE(TruncateInt64ToInt32, 1, 0, 1), - PURE(Float32Add, 2, 0, 1), PURE(Float32Sub, 2, 0, 1), - PURE(Float32Mul, 2, 0, 1), PURE(Float32Div, 2, 0, 1), - PURE(Float32Abs, 1, 0, 1), PURE(Float32Sqrt, 1, 0, 1), - PURE(Float32Equal, 2, 0, 1), PURE(Float32LessThan, 2, 0, 1), - PURE(Float32LessThanOrEqual, 2, 0, 1), PURE(Float32Max, 2, 0, 1), - PURE(Float32Min, 2, 0, 1), PURE(Float64Add, 2, 0, 1), - PURE(Float64Sub, 2, 0, 1), PURE(Float64Mul, 2, 0, 1), - PURE(Float64Div, 2, 0, 1), PURE(Float64Mod, 2, 0, 1), - PURE(Float64Abs, 1, 0, 1), PURE(Float64Sqrt, 1, 0, 1), - PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1), - PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(Float64Max, 2, 0, 1), - PURE(Float64Min, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1), - PURE(Float64RoundDown, 1, 0, 1), PURE(Float64RoundTruncate, 1, 0, 1), - PURE(Float64RoundTiesAway, 1, 0, 1), PURE(Float64ExtractLowWord32, 1, 0, 1), - PURE(Float64ExtractHighWord32, 1, 0, 1), - PURE(Float64InsertLowWord32, 2, 0, 1), - PURE(Float64InsertHighWord32, 2, 0, 1) + PURE(Word32And, 2, 0, 1), // -- + PURE(Word32Or, 2, 0, 1), // -- + PURE(Word32Xor, 2, 0, 1), // -- + PURE(Word32Shl, 2, 0, 1), // -- + PURE(Word32Shr, 2, 0, 1), // -- + PURE(Word32Sar, 2, 0, 1), // -- + PURE(Word32Ror, 2, 0, 1), // -- + PURE(Word32Equal, 2, 0, 1), // -- + PURE(Word32Clz, 1, 0, 1), // -- + PURE(Word64And, 2, 0, 1), // -- + PURE(Word64Or, 2, 0, 1), // -- + PURE(Word64Xor, 2, 0, 1), // -- + PURE(Word64Shl, 2, 0, 1), // -- + PURE(Word64Shr, 2, 0, 1), // -- + PURE(Word64Sar, 2, 0, 1), // -- + PURE(Word64Ror, 2, 0, 1), // -- + PURE(Word64Equal, 2, 0, 1), // -- + PURE(Int32Add, 2, 0, 1), // -- + PURE(Int32AddWithOverflow, 2, 0, 2), // -- + PURE(Int32Sub, 2, 0, 1), // -- + PURE(Int32SubWithOverflow, 2, 0, 2), // -- + PURE(Int32Mul, 2, 0, 1), // -- + PURE(Int32MulHigh, 2, 0, 1), // -- + PURE(Int32Div, 2, 1, 1), // -- + PURE(Uint32Div, 2, 1, 1), // -- + PURE(Int32Mod, 2, 1, 1), // -- + PURE(Uint32Mod, 2, 1, 1), // -- + PURE(Int32LessThan, 2, 0, 1), // -- + PURE(Int32LessThanOrEqual, 2, 0, 1), // -- + PURE(Uint32LessThan, 2, 0, 1), // -- + PURE(Uint32LessThanOrEqual, 2, 0, 1), // -- + PURE(Int64Add, 2, 0, 1), // -- + PURE(Int64Sub, 2, 0, 1), // -- + PURE(Int64Mul, 2, 0, 1), // -- + PURE(Int64Div, 2, 1, 1), // -- + PURE(Uint64Div, 2, 1, 1), // -- + PURE(Int64Mod, 2, 1, 1), // -- + PURE(Uint64Mod, 2, 1, 1), // -- + PURE(Int64LessThan, 2, 0, 1), // -- + PURE(Int64LessThanOrEqual, 2, 0, 1), // -- + PURE(Uint64LessThan, 2, 0, 1), // -- + PURE(Uint64LessThanOrEqual, 2, 0, 1), // -- + PURE(ChangeFloat32ToFloat64, 1, 0, 1), // -- + PURE(ChangeFloat64ToInt32, 1, 0, 1), // -- + PURE(ChangeFloat64ToUint32, 1, 0, 1), // -- + PURE(ChangeInt32ToInt64, 1, 0, 1), // -- + PURE(ChangeUint32ToFloat64, 1, 0, 1), // -- + PURE(ChangeUint32ToUint64, 1, 0, 1), // -- + PURE(TruncateFloat64ToFloat32, 1, 0, 1), // -- + PURE(TruncateInt64ToInt32, 1, 0, 1), // -- + PURE(Float32Abs, 1, 0, 1), // -- + PURE(Float32Add, 2, 0, 1), // -- + PURE(Float32Sub, 2, 0, 1), // -- + PURE(Float32Mul, 2, 0, 1), // -- + PURE(Float32Div, 2, 0, 1), // -- + PURE(Float32Sqrt, 1, 0, 1), // -- + PURE(Float32Equal, 2, 0, 1), // -- + PURE(Float32LessThan, 2, 0, 1), // -- + PURE(Float32LessThanOrEqual, 2, 0, 1), // -- + PURE(Float64Abs, 1, 0, 1), // -- + PURE(Float64Add, 2, 0, 1), // -- + PURE(Float64Sub, 2, 0, 1), // -- + PURE(Float64Mul, 2, 0, 1), // -- + PURE(Float64Div, 2, 0, 1), // -- + PURE(Float64Mod, 2, 0, 1), // -- + PURE(Float64Sqrt, 1, 0, 1), // -- + PURE(Float64Equal, 2, 0, 1), // -- + PURE(Float64LessThan, 2, 0, 1), // -- + PURE(Float64LessThanOrEqual, 2, 0, 1), // -- + PURE(LoadStackPointer, 0, 0, 1), // -- + PURE(Float64ExtractLowWord32, 1, 0, 1), // -- + PURE(Float64ExtractHighWord32, 1, 0, 1), // -- + PURE(Float64InsertLowWord32, 2, 0, 1), // -- + PURE(Float64InsertHighWord32, 2, 0, 1), // -- #undef PURE }; - -typedef MachineOperatorTestWithParam<PureOperator> MachinePureOperatorTest; - } // namespace +class MachinePureOperatorTest : public TestWithZone { + protected: + MachineType word_type() { return kMachPtr; } +}; -TEST_P(MachinePureOperatorTest, InstancesAreGloballyShared) { - const PureOperator& pop = GetParam(); - MachineOperatorBuilder machine1(zone(), type()); - MachineOperatorBuilder machine2(zone(), type()); - EXPECT_EQ((machine1.*pop.constructor)(), (machine2.*pop.constructor)()); + +TEST_F(MachinePureOperatorTest, PureOperators) { + TRACED_FOREACH(MachineType, machine_rep1, kMachineReps) { + MachineOperatorBuilder machine1(zone(), machine_rep1); + TRACED_FOREACH(MachineType, machine_rep2, kMachineReps) { + MachineOperatorBuilder machine2(zone(), machine_rep2); + TRACED_FOREACH(PureOperator, pop, kPureOperators) { + const Operator* op1 = (machine1.*pop.constructor)(); + const Operator* op2 = (machine2.*pop.constructor)(); + EXPECT_EQ(op1, op2); + EXPECT_EQ(pop.value_input_count, op1->ValueInputCount()); + EXPECT_EQ(pop.control_input_count, op1->ControlInputCount()); + EXPECT_EQ(pop.value_output_count, op1->ValueOutputCount()); + } + } + } } -TEST_P(MachinePureOperatorTest, NumberOfInputsAndOutputs) { - MachineOperatorBuilder machine(zone(), type()); - const PureOperator& pop = GetParam(); - const Operator* op = (machine.*pop.constructor)(); +// Optional operators. - EXPECT_EQ(pop.value_input_count, op->ValueInputCount()); - EXPECT_EQ(0, op->EffectInputCount()); - EXPECT_EQ(pop.control_input_count, op->ControlInputCount()); - EXPECT_EQ(pop.value_input_count + pop.control_input_count, - OperatorProperties::GetTotalInputCount(op)); +namespace { - EXPECT_EQ(pop.value_output_count, op->ValueOutputCount()); - EXPECT_EQ(0, op->EffectOutputCount()); - EXPECT_EQ(0, op->ControlOutputCount()); -} +struct OptionalOperatorEntry { + const OptionalOperator (MachineOperatorBuilder::*constructor)(); + MachineOperatorBuilder::Flag enabling_flag; + char const* const constructor_name; + int value_input_count; + int control_input_count; + int value_output_count; +}; -TEST_P(MachinePureOperatorTest, MarkedAsPure) { - MachineOperatorBuilder machine(zone(), type()); - const PureOperator& pop = GetParam(); - const Operator* op = (machine.*pop.constructor)(); - EXPECT_TRUE(op->HasProperty(Operator::kPure)); +std::ostream& operator<<(std::ostream& os, OptionalOperatorEntry const& pop) { + return os << pop.constructor_name; } +const OptionalOperatorEntry kOptionalOperators[] = { +#define OPTIONAL_ENTRY(Name, value_input_count, control_input_count, \ + value_output_count) \ + { \ + &MachineOperatorBuilder::Name, MachineOperatorBuilder::k##Name, #Name, \ + value_input_count, control_input_count, value_output_count \ + } + OPTIONAL_ENTRY(Float32Max, 2, 0, 1), // -- + OPTIONAL_ENTRY(Float32Min, 2, 0, 1), // -- + OPTIONAL_ENTRY(Float64Max, 2, 0, 1), // -- + OPTIONAL_ENTRY(Float64Min, 2, 0, 1), // -- + OPTIONAL_ENTRY(Float64RoundDown, 1, 0, 1), // -- + OPTIONAL_ENTRY(Float64RoundTruncate, 1, 0, 1), // -- + OPTIONAL_ENTRY(Float64RoundTiesAway, 1, 0, 1), // -- +#undef OPTIONAL_ENTRY +}; +} // namespace -TEST_P(MachinePureOperatorTest, OpcodeIsCorrect) { - MachineOperatorBuilder machine(zone(), type()); - const PureOperator& pop = GetParam(); - const Operator* op = (machine.*pop.constructor)(); - EXPECT_EQ(pop.opcode, op->opcode()); -} +class MachineOptionalOperatorTest : public TestWithZone { + protected: + MachineType word_type() { return kMachPtr; } +}; -INSTANTIATE_TEST_CASE_P( - MachineOperatorTest, MachinePureOperatorTest, - ::testing::Combine(::testing::ValuesIn(kMachineReps), - ::testing::ValuesIn(kPureOperators))); -#endif // GTEST_HAS_COMBINE +TEST_F(MachineOptionalOperatorTest, OptionalOperators) { + TRACED_FOREACH(OptionalOperatorEntry, pop, kOptionalOperators) { + TRACED_FOREACH(MachineType, machine_rep1, kMachineReps) { + MachineOperatorBuilder machine1(zone(), machine_rep1, pop.enabling_flag); + TRACED_FOREACH(MachineType, machine_rep2, kMachineReps) { + MachineOperatorBuilder machine2(zone(), machine_rep2, + pop.enabling_flag); + const Operator* op1 = (machine1.*pop.constructor)().op(); + const Operator* op2 = (machine2.*pop.constructor)().op(); + EXPECT_EQ(op1, op2); + EXPECT_EQ(pop.value_input_count, op1->ValueInputCount()); + EXPECT_EQ(pop.control_input_count, op1->ControlInputCount()); + EXPECT_EQ(pop.value_output_count, op1->ValueOutputCount()); + + MachineOperatorBuilder machine3(zone(), word_type()); + EXPECT_TRUE((machine1.*pop.constructor)().IsSupported()); + EXPECT_FALSE((machine3.*pop.constructor)().IsSupported()); + } + } + } +} // ----------------------------------------------------------------------------- diff --git a/deps/v8/test/unittests/compiler/node-properties-unittest.cc b/deps/v8/test/unittests/compiler/node-properties-unittest.cc index 2bec4faf4d..463948d43f 100644 --- a/deps/v8/test/unittests/compiler/node-properties-unittest.cc +++ b/deps/v8/test/unittests/compiler/node-properties-unittest.cc @@ -10,78 +10,72 @@ using testing::AnyOf; using testing::ElementsAre; using testing::IsNull; -using testing::UnorderedElementsAre; namespace v8 { namespace internal { namespace compiler { -typedef TestWithZone NodePropertiesTest; - +class NodePropertiesTest : public TestWithZone { + public: + Node* NewMockNode(const Operator* op) { + return Node::New(zone(), 0, op, 0, nullptr, false); + } + Node* NewMockNode(const Operator* op, Node* n1) { + Node* nodes[] = {n1}; + return Node::New(zone(), 0, op, arraysize(nodes), nodes, false); + } + Node* NewMockNode(const Operator* op, Node* n1, Node* n2) { + Node* nodes[] = {n1, n2}; + return Node::New(zone(), 0, op, arraysize(nodes), nodes, false); + } +}; namespace { const Operator kMockOperator(IrOpcode::kDead, Operator::kNoProperties, - "MockOperator", 0, 0, 0, 1, 0, 0); -const Operator kMockOpEffect(IrOpcode::kDead, Operator::kNoProperties, - "MockOpEffect", 0, 1, 0, 1, 1, 0); -const Operator kMockOpControl(IrOpcode::kDead, Operator::kNoProperties, - "MockOpControl", 0, 0, 1, 1, 0, 1); + "MockOperator", 0, 0, 0, 1, 1, 2); const Operator kMockCallOperator(IrOpcode::kCall, Operator::kNoProperties, "MockCallOperator", 0, 0, 0, 0, 0, 2); -} // namespace - - -TEST_F(NodePropertiesTest, ReplaceWithValue_ValueUse) { - CommonOperatorBuilder common(zone()); - Node* node = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false); - Node* use_value = Node::New(zone(), 0, common.Return(), 1, &node, false); - Node* replacement = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false); - NodeProperties::ReplaceWithValue(node, replacement); - EXPECT_EQ(replacement, use_value->InputAt(0)); - EXPECT_EQ(0, node->UseCount()); - EXPECT_EQ(1, replacement->UseCount()); - EXPECT_THAT(replacement->uses(), ElementsAre(use_value)); -} - +const IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught; -TEST_F(NodePropertiesTest, ReplaceWithValue_EffectUse) { - CommonOperatorBuilder common(zone()); - Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false); - Node* node = Node::New(zone(), 0, &kMockOpEffect, 1, &start, false); - Node* use_effect = Node::New(zone(), 0, common.EffectPhi(1), 1, &node, false); - Node* replacement = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false); - NodeProperties::ReplaceWithValue(node, replacement); - EXPECT_EQ(start, use_effect->InputAt(0)); - EXPECT_EQ(0, node->UseCount()); - EXPECT_EQ(2, start->UseCount()); - EXPECT_EQ(0, replacement->UseCount()); - EXPECT_THAT(start->uses(), UnorderedElementsAre(use_effect, node)); -} +} // namespace -TEST_F(NodePropertiesTest, ReplaceWithValue_ControlUse) { +TEST_F(NodePropertiesTest, ReplaceUses) { CommonOperatorBuilder common(zone()); - Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false); - Node* node = Node::New(zone(), 0, &kMockOpControl, 1, &start, false); - Node* success = Node::New(zone(), 0, common.IfSuccess(), 1, &node, false); - Node* use_control = Node::New(zone(), 0, common.Merge(1), 1, &success, false); - Node* replacement = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false); - NodeProperties::ReplaceWithValue(node, replacement); - EXPECT_EQ(start, use_control->InputAt(0)); + Node* node = NewMockNode(&kMockOperator); + Node* effect = NewMockNode(&kMockOperator); + Node* use_value = NewMockNode(common.Return(), node); + Node* use_effect = NewMockNode(common.EffectPhi(1), node); + Node* use_success = NewMockNode(common.IfSuccess(), node); + Node* use_exception = NewMockNode(common.IfException(kNoHint), effect, node); + Node* r_value = NewMockNode(&kMockOperator); + Node* r_effect = NewMockNode(&kMockOperator); + Node* r_success = NewMockNode(&kMockOperator); + Node* r_exception = NewMockNode(&kMockOperator); + NodeProperties::ReplaceUses(node, r_value, r_effect, r_success, r_exception); + EXPECT_EQ(r_value, use_value->InputAt(0)); + EXPECT_EQ(r_effect, use_effect->InputAt(0)); + EXPECT_EQ(r_success, use_success->InputAt(0)); + EXPECT_EQ(r_exception, use_exception->InputAt(1)); EXPECT_EQ(0, node->UseCount()); - EXPECT_EQ(2, start->UseCount()); - EXPECT_EQ(0, replacement->UseCount()); - EXPECT_THAT(start->uses(), UnorderedElementsAre(use_control, node)); + EXPECT_EQ(1, r_value->UseCount()); + EXPECT_EQ(1, r_effect->UseCount()); + EXPECT_EQ(1, r_success->UseCount()); + EXPECT_EQ(1, r_exception->UseCount()); + EXPECT_THAT(r_value->uses(), ElementsAre(use_value)); + EXPECT_THAT(r_effect->uses(), ElementsAre(use_effect)); + EXPECT_THAT(r_success->uses(), ElementsAre(use_success)); + EXPECT_THAT(r_exception->uses(), ElementsAre(use_exception)); } TEST_F(NodePropertiesTest, FindProjection) { CommonOperatorBuilder common(zone()); - Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false); - Node* proj0 = Node::New(zone(), 1, common.Projection(0), 1, &start, false); - Node* proj1 = Node::New(zone(), 2, common.Projection(1), 1, &start, false); + Node* start = NewMockNode(common.Start(1)); + Node* proj0 = NewMockNode(common.Projection(0), start); + Node* proj1 = NewMockNode(common.Projection(1), start); EXPECT_EQ(proj0, NodeProperties::FindProjection(start, 0)); EXPECT_EQ(proj1, NodeProperties::FindProjection(start, 1)); EXPECT_THAT(NodeProperties::FindProjection(start, 2), IsNull()); @@ -92,9 +86,9 @@ TEST_F(NodePropertiesTest, FindProjection) { TEST_F(NodePropertiesTest, CollectControlProjections_Branch) { Node* result[2]; CommonOperatorBuilder common(zone()); - Node* branch = Node::New(zone(), 1, common.Branch(), 0, nullptr, false); - Node* if_false = Node::New(zone(), 2, common.IfFalse(), 1, &branch, false); - Node* if_true = Node::New(zone(), 3, common.IfTrue(), 1, &branch, false); + Node* branch = NewMockNode(common.Branch()); + Node* if_false = NewMockNode(common.IfFalse(), branch); + Node* if_true = NewMockNode(common.IfTrue(), branch); NodeProperties::CollectControlProjections(branch, result, arraysize(result)); EXPECT_EQ(if_true, result[0]); EXPECT_EQ(if_false, result[1]); @@ -104,9 +98,9 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Branch) { TEST_F(NodePropertiesTest, CollectControlProjections_Call) { Node* result[2]; CommonOperatorBuilder common(zone()); - Node* call = Node::New(zone(), 1, &kMockCallOperator, 0, nullptr, false); - Node* if_ex = Node::New(zone(), 2, common.IfException(), 1, &call, false); - Node* if_ok = Node::New(zone(), 3, common.IfSuccess(), 1, &call, false); + Node* call = NewMockNode(&kMockCallOperator); + Node* if_ex = NewMockNode(common.IfException(kNoHint), call, call); + Node* if_ok = NewMockNode(common.IfSuccess(), call); NodeProperties::CollectControlProjections(call, result, arraysize(result)); EXPECT_EQ(if_ok, result[0]); EXPECT_EQ(if_ex, result[1]); @@ -116,10 +110,10 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Call) { TEST_F(NodePropertiesTest, CollectControlProjections_Switch) { Node* result[3]; CommonOperatorBuilder common(zone()); - Node* sw = Node::New(zone(), 1, common.Switch(3), 0, nullptr, false); - Node* if_default = Node::New(zone(), 2, common.IfDefault(), 1, &sw, false); - Node* if_value1 = Node::New(zone(), 3, common.IfValue(1), 1, &sw, false); - Node* if_value2 = Node::New(zone(), 4, common.IfValue(2), 1, &sw, false); + Node* sw = NewMockNode(common.Switch(3)); + Node* if_default = NewMockNode(common.IfDefault(), sw); + Node* if_value1 = NewMockNode(common.IfValue(1), sw); + Node* if_value2 = NewMockNode(common.IfValue(2), sw); NodeProperties::CollectControlProjections(sw, result, arraysize(result)); EXPECT_THAT(result[0], AnyOf(if_value1, if_value2)); EXPECT_THAT(result[1], AnyOf(if_value1, if_value2)); diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc index e6201ec67f..520ce0159e 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/js-operator.h" #include "src/compiler/node-properties.h" #include "src/compiler/simplified-operator.h" #include "src/unique.h" @@ -748,6 +749,32 @@ class IsTailCallMatcher final : public NodeMatcher { }; +class IsReferenceEqualMatcher final : public NodeMatcher { + public: + IsReferenceEqualMatcher(const Matcher<Type*>& type_matcher, + const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher) + : NodeMatcher(IrOpcode::kReferenceEqual), + type_matcher_(type_matcher), + lhs_matcher_(lhs_matcher), + rhs_matcher_(rhs_matcher) {} + + bool MatchAndExplain(Node* node, MatchResultListener* listener) const final { + return (NodeMatcher::MatchAndExplain(node, listener) && + // TODO(bmeurer): The type parameter is currently ignored. + PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs", + lhs_matcher_, listener) && + PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "rhs", + rhs_matcher_, listener)); + } + + private: + const Matcher<Type*> type_matcher_; + const Matcher<Node*> lhs_matcher_; + const Matcher<Node*> rhs_matcher_; +}; + + class IsAllocateMatcher final : public NodeMatcher { public: IsAllocateMatcher(const Matcher<Node*>& size_matcher, @@ -1160,24 +1187,32 @@ class IsLoadMatcher final : public NodeMatcher { }; -class IsToNumberMatcher final : public NodeMatcher { +class IsStoreMatcher final : public NodeMatcher { public: - IsToNumberMatcher(const Matcher<Node*>& base_matcher, - const Matcher<Node*>& context_matcher, - const Matcher<Node*>& effect_matcher, - const Matcher<Node*>& control_matcher) - : NodeMatcher(IrOpcode::kJSToNumber), + IsStoreMatcher(const Matcher<StoreRepresentation>& rep_matcher, + const Matcher<Node*>& base_matcher, + const Matcher<Node*>& index_matcher, + const Matcher<Node*>& value_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher) + : NodeMatcher(IrOpcode::kStore), + rep_matcher_(rep_matcher), base_matcher_(base_matcher), - context_matcher_(context_matcher), + index_matcher_(index_matcher), + value_matcher_(value_matcher), effect_matcher_(effect_matcher), control_matcher_(control_matcher) {} void DescribeTo(std::ostream* os) const final { NodeMatcher::DescribeTo(os); - *os << " whose base ("; + *os << " whose rep ("; + rep_matcher_.DescribeTo(os); + *os << "), base ("; base_matcher_.DescribeTo(os); - *os << "), context ("; - context_matcher_.DescribeTo(os); + *os << "), index ("; + index_matcher_.DescribeTo(os); + *os << "), value ("; + value_matcher_.DescribeTo(os); *os << "), effect ("; effect_matcher_.DescribeTo(os); *os << ") and control ("; @@ -1187,10 +1222,14 @@ class IsToNumberMatcher final : public NodeMatcher { bool MatchAndExplain(Node* node, MatchResultListener* listener) const final { return (NodeMatcher::MatchAndExplain(node, listener) && + PrintMatchAndExplain(OpParameter<StoreRepresentation>(node), "rep", + rep_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base", base_matcher_, listener) && - PrintMatchAndExplain(NodeProperties::GetContextInput(node), - "context", context_matcher_, listener) && + PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), + "index", index_matcher_, listener) && + PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2), + "value", value_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect", effect_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetControlInput(node), @@ -1198,39 +1237,33 @@ class IsToNumberMatcher final : public NodeMatcher { } private: + const Matcher<StoreRepresentation> rep_matcher_; const Matcher<Node*> base_matcher_; - const Matcher<Node*> context_matcher_; + const Matcher<Node*> index_matcher_; + const Matcher<Node*> value_matcher_; const Matcher<Node*> effect_matcher_; const Matcher<Node*> control_matcher_; }; -class IsStoreMatcher final : public NodeMatcher { +class IsToNumberMatcher final : public NodeMatcher { public: - IsStoreMatcher(const Matcher<StoreRepresentation>& rep_matcher, - const Matcher<Node*>& base_matcher, - const Matcher<Node*>& index_matcher, - const Matcher<Node*>& value_matcher, - const Matcher<Node*>& effect_matcher, - const Matcher<Node*>& control_matcher) - : NodeMatcher(IrOpcode::kStore), - rep_matcher_(rep_matcher), + IsToNumberMatcher(const Matcher<Node*>& base_matcher, + const Matcher<Node*>& context_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher) + : NodeMatcher(IrOpcode::kJSToNumber), base_matcher_(base_matcher), - index_matcher_(index_matcher), - value_matcher_(value_matcher), + context_matcher_(context_matcher), effect_matcher_(effect_matcher), control_matcher_(control_matcher) {} void DescribeTo(std::ostream* os) const final { NodeMatcher::DescribeTo(os); - *os << " whose rep ("; - rep_matcher_.DescribeTo(os); - *os << "), base ("; + *os << " whose base ("; base_matcher_.DescribeTo(os); - *os << "), index ("; - index_matcher_.DescribeTo(os); - *os << "), value ("; - value_matcher_.DescribeTo(os); + *os << "), context ("; + context_matcher_.DescribeTo(os); *os << "), effect ("; effect_matcher_.DescribeTo(os); *os << ") and control ("; @@ -1240,14 +1273,10 @@ class IsStoreMatcher final : public NodeMatcher { bool MatchAndExplain(Node* node, MatchResultListener* listener) const final { return (NodeMatcher::MatchAndExplain(node, listener) && - PrintMatchAndExplain(OpParameter<StoreRepresentation>(node), "rep", - rep_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base", base_matcher_, listener) && - PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), - "index", index_matcher_, listener) && - PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2), - "value", value_matcher_, listener) && + PrintMatchAndExplain(NodeProperties::GetContextInput(node), + "context", context_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect", effect_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetControlInput(node), @@ -1255,15 +1284,44 @@ class IsStoreMatcher final : public NodeMatcher { } private: - const Matcher<StoreRepresentation> rep_matcher_; const Matcher<Node*> base_matcher_; - const Matcher<Node*> index_matcher_; - const Matcher<Node*> value_matcher_; + const Matcher<Node*> context_matcher_; const Matcher<Node*> effect_matcher_; const Matcher<Node*> control_matcher_; }; +class IsLoadContextMatcher final : public NodeMatcher { + public: + IsLoadContextMatcher(const Matcher<ContextAccess>& access_matcher, + const Matcher<Node*>& context_matcher) + : NodeMatcher(IrOpcode::kJSLoadContext), + access_matcher_(access_matcher), + context_matcher_(context_matcher) {} + + void DescribeTo(std::ostream* os) const final { + NodeMatcher::DescribeTo(os); + *os << " whose access ("; + access_matcher_.DescribeTo(os); + *os << ") and context ("; + context_matcher_.DescribeTo(os); + *os << ")"; + } + + bool MatchAndExplain(Node* node, MatchResultListener* listener) const final { + return (NodeMatcher::MatchAndExplain(node, listener) && + PrintMatchAndExplain(OpParameter<ContextAccess>(node), "access", + access_matcher_, listener) && + PrintMatchAndExplain(NodeProperties::GetContextInput(node), + "context", context_matcher_, listener)); + } + + private: + const Matcher<ContextAccess> access_matcher_; + const Matcher<Node*> context_matcher_; +}; + + class IsBinopMatcher final : public NodeMatcher { public: IsBinopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher, @@ -1320,8 +1378,28 @@ class IsUnopMatcher final : public NodeMatcher { } // namespace -Matcher<Node*> IsEnd(const Matcher<Node*>& control_matcher) { - return MakeMatcher(new IsControl1Matcher(IrOpcode::kEnd, control_matcher)); +Matcher<Node*> IsDead() { + return MakeMatcher(new NodeMatcher(IrOpcode::kDead)); +} + + +Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher) { + return MakeMatcher(new IsControl1Matcher(IrOpcode::kEnd, control0_matcher)); +} + + +Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher, + const Matcher<Node*>& control1_matcher) { + return MakeMatcher(new IsControl2Matcher(IrOpcode::kEnd, control0_matcher, + control1_matcher)); +} + + +Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher, + const Matcher<Node*>& control1_matcher, + const Matcher<Node*>& control2_matcher) { + return MakeMatcher(new IsControl3Matcher(IrOpcode::kEnd, control0_matcher, + control1_matcher, control2_matcher)); } @@ -1600,6 +1678,14 @@ Matcher<Node*> IsTailCall( } +Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher, + const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher) { + return MakeMatcher( + new IsReferenceEqualMatcher(type_matcher, lhs_matcher, rhs_matcher)); +} + + Matcher<Node*> IsAllocate(const Matcher<Node*>& size_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher) { @@ -1686,15 +1772,6 @@ Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher, } -Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher, - const Matcher<Node*>& context_matcher, - const Matcher<Node*>& effect_matcher, - const Matcher<Node*>& control_matcher) { - return MakeMatcher(new IsToNumberMatcher(base_matcher, context_matcher, - effect_matcher, control_matcher)); -} - - Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher, const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher, @@ -1707,6 +1784,21 @@ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher, } +Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher, + const Matcher<Node*>& context_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher) { + return MakeMatcher(new IsToNumberMatcher(base_matcher, context_matcher, + effect_matcher, control_matcher)); +} + + +Matcher<Node*> IsLoadContext(const Matcher<ContextAccess>& access_matcher, + const Matcher<Node*>& context_matcher) { + return MakeMatcher(new IsLoadContextMatcher(access_matcher, context_matcher)); +} + + #define IS_BINOP_MATCHER(Name) \ Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher, \ const Matcher<Node*>& rhs_matcher) { \ @@ -1717,6 +1809,9 @@ IS_BINOP_MATCHER(NumberEqual) IS_BINOP_MATCHER(NumberLessThan) IS_BINOP_MATCHER(NumberSubtract) IS_BINOP_MATCHER(NumberMultiply) +IS_BINOP_MATCHER(NumberShiftLeft) +IS_BINOP_MATCHER(NumberShiftRight) +IS_BINOP_MATCHER(NumberShiftRightLogical) IS_BINOP_MATCHER(Word32And) IS_BINOP_MATCHER(Word32Sar) IS_BINOP_MATCHER(Word32Shl) diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h index 9c4646b2f0..a64d9f009a 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.h +++ b/deps/v8/test/unittests/compiler/node-test-utils.h @@ -17,12 +17,17 @@ class ExternalReference; class HeapObject; template <class T> class Unique; +template <class> +class TypeImpl; +struct ZoneTypeConfig; +typedef TypeImpl<ZoneTypeConfig> Type; namespace compiler { // Forward declarations. class BufferAccess; class CallDescriptor; +class ContextAccess; struct ElementAccess; struct FieldAccess; class Node; @@ -31,7 +36,13 @@ class Node; using ::testing::Matcher; -Matcher<Node*> IsEnd(const Matcher<Node*>& control_matcher); +Matcher<Node*> IsDead(); +Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher); +Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher, + const Matcher<Node*>& control1_matcher); +Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher, + const Matcher<Node*>& control1_matcher, + const Matcher<Node*>& control2_matcher); Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher, const Matcher<Node*>& control_matcher); Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher, @@ -125,6 +136,9 @@ Matcher<Node*> IsTailCall( const Matcher<Node*>& control_matcher); Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher); +Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher, + const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher, @@ -133,6 +147,12 @@ Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsNumberMultiply(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsNumberShiftLeft(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsNumberShiftRight(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsNumberShiftRightLogical(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsAllocate(const Matcher<Node*>& size_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); @@ -255,6 +275,8 @@ Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher, const Matcher<Node*>& context_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); +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); diff --git a/deps/v8/test/unittests/compiler/node-unittest.cc b/deps/v8/test/unittests/compiler/node-unittest.cc index 6b61bd5c1c..5341f69716 100644 --- a/deps/v8/test/unittests/compiler/node-unittest.cc +++ b/deps/v8/test/unittests/compiler/node-unittest.cc @@ -32,7 +32,7 @@ const Operator kOp2(kOpcode2, Operator::kNoProperties, "Op2", 2, 0, 0, 1, 0, 0); TEST_F(NodeTest, New) { Node* const node = Node::New(zone(), 1, &kOp0, 0, nullptr, false); - EXPECT_EQ(1, node->id()); + EXPECT_EQ(1U, node->id()); EXPECT_EQ(0, node->UseCount()); EXPECT_TRUE(node->uses().empty()); EXPECT_EQ(0, node->InputCount()); @@ -166,6 +166,96 @@ TEST_F(NodeTest, AppendInput) { EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0, n0, n1)); } + +TEST_F(NodeTest, TrimThenAppend) { + Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false); + Node* n1 = Node::New(zone(), 1, &kOp0, 0, nullptr, false); + Node* n2 = Node::New(zone(), 2, &kOp0, 0, nullptr, false); + Node* n3 = Node::New(zone(), 3, &kOp0, 0, nullptr, false); + Node* n4 = Node::New(zone(), 4, &kOp0, 0, nullptr, false); + Node* n5 = Node::New(zone(), 5, &kOp0, 0, nullptr, false); + Node* n6 = Node::New(zone(), 6, &kOp0, 0, nullptr, false); + Node* n7 = Node::New(zone(), 7, &kOp0, 0, nullptr, false); + Node* n8 = Node::New(zone(), 8, &kOp0, 0, nullptr, false); + Node* n9 = Node::New(zone(), 9, &kOp0, 0, nullptr, false); + Node* node = Node::New(zone(), 12345, &kOp0, 0, nullptr, true); + + EXPECT_TRUE(node->inputs().empty()); + + node->AppendInput(zone(), n0); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n0)); + + node->TrimInputCount(0); + EXPECT_TRUE(node->inputs().empty()); + + node->AppendInput(zone(), n1); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1)); + + node->AppendInput(zone(), n2); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1, n2)); + + node->TrimInputCount(1); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1)); + + node->AppendInput(zone(), n3); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1, n3)); + + node->AppendInput(zone(), n4); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4)); + + node->AppendInput(zone(), n5); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5)); + + node->AppendInput(zone(), n6); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5, n6)); + + node->AppendInput(zone(), n7); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5, n6, n7)); + + node->TrimInputCount(4); + EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5)); + + node->AppendInput(zone(), n8); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5, n8)); + + node->AppendInput(zone(), n9); + EXPECT_FALSE(node->inputs().empty()); + EXPECT_THAT(node->inputs(), ElementsAre(n1, n3, n4, n5, n8, n9)); +} + + +TEST_F(NodeTest, BigNodes) { + static const int kMaxSize = 512; + Node* inputs[kMaxSize]; + + Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false); + Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false); + + for (int i = 0; i < kMaxSize; i++) { + inputs[i] = i & 1 ? n0 : n1; + } + + for (int size = 13; size <= kMaxSize; size += 9) { + Node* node = Node::New(zone(), 12345, &kOp0, size, inputs, false); + EXPECT_EQ(size, node->InputCount()); + + for (int i = 0; i < size; i++) { + EXPECT_EQ(inputs[i], node->InputAt(i)); + } + } +} + + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/scheduler-unittest.cc b/deps/v8/test/unittests/compiler/scheduler-unittest.cc index 4de15492b2..45c636b27a 100644 --- a/deps/v8/test/unittests/compiler/scheduler-unittest.cc +++ b/deps/v8/test/unittests/compiler/scheduler-unittest.cc @@ -631,7 +631,7 @@ TEST_F(SchedulerRPOTest, LoopMultibackedge) { TEST_F(SchedulerTest, BuildScheduleEmpty) { graph()->SetStart(graph()->NewNode(common()->Start(0))); - graph()->SetEnd(graph()->NewNode(common()->End(), graph()->start())); + graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start())); USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags)); } @@ -643,22 +643,23 @@ TEST_F(SchedulerTest, BuildScheduleOneParameter) { Node* ret = graph()->NewNode(common()->Return(), p1, graph()->start(), graph()->start()); - graph()->SetEnd(graph()->NewNode(common()->End(), ret)); + graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags)); } TEST_F(SchedulerTest, BuildScheduleIfSplit) { - graph()->SetStart(graph()->NewNode(common()->Start(3))); + graph()->SetStart(graph()->NewNode(common()->Start(5))); Node* p1 = graph()->NewNode(common()->Parameter(0), graph()->start()); Node* p2 = graph()->NewNode(common()->Parameter(1), graph()->start()); Node* p3 = graph()->NewNode(common()->Parameter(2), graph()->start()); Node* p4 = graph()->NewNode(common()->Parameter(3), graph()->start()); Node* p5 = graph()->NewNode(common()->Parameter(4), graph()->start()); - Node* cmp = graph()->NewNode(js()->LessThanOrEqual(LanguageMode::SLOPPY), p1, - p2, p3, graph()->start(), graph()->start()); + Node* cmp = + graph()->NewNode(js()->LessThanOrEqual(LanguageMode::SLOPPY), p1, p2, p3, + p4, p5, graph()->start(), graph()->start()); Node* branch = graph()->NewNode(common()->Branch(), cmp, graph()->start()); Node* true_branch = graph()->NewNode(common()->IfTrue(), branch); Node* false_branch = graph()->NewNode(common()->IfFalse(), branch); @@ -667,1341 +668,12 @@ TEST_F(SchedulerTest, BuildScheduleIfSplit) { graph()->NewNode(common()->Return(), p4, graph()->start(), true_branch); Node* ret2 = graph()->NewNode(common()->Return(), p5, graph()->start(), false_branch); - Node* merge = graph()->NewNode(common()->Merge(2), ret1, ret2); - graph()->SetEnd(graph()->NewNode(common()->End(), merge)); + graph()->SetEnd(graph()->NewNode(common()->End(2), ret1, ret2)); ComputeAndVerifySchedule(13); } -TEST_F(SchedulerTest, BuildScheduleIfSplitWithEffects) { - const Operator* op; - Unique<HeapObject> unique_constant = - Unique<HeapObject>::CreateImmovable(factory()->undefined_value()); - - // Manually transcripted code for: - // function turbo_fan_test(a, b, c, y) { - // if (a < b) { - // return a + b - c * c - a + y; - // } else { - // return c * c - a; - // } - // } - Node* nil = graph()->NewNode(common()->Dead()); - op = common()->End(); - Node* n39 = graph()->NewNode(op, nil); - USE(n39); - op = common()->Merge(2); - Node* n37 = graph()->NewNode(op, nil, nil); - USE(n37); - op = common()->Return(); - Node* n29 = graph()->NewNode(op, nil, nil, nil); - USE(n29); - op = common()->Return(); - Node* n36 = graph()->NewNode(op, nil, nil, nil); - USE(n36); - op = js()->Add(LanguageMode::SLOPPY); - Node* n27 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n27); - op = common()->IfSuccess(); - Node* n28 = graph()->NewNode(op, nil); - USE(n28); - op = js()->Subtract(LanguageMode::SLOPPY); - Node* n34 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n34); - op = common()->IfSuccess(); - Node* n35 = graph()->NewNode(op, nil); - USE(n35); - op = js()->Subtract(LanguageMode::SLOPPY); - Node* n25 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n25); - op = common()->Parameter(4); - Node* n5 = graph()->NewNode(op, nil); - USE(n5); - op = common()->Parameter(5); - Node* n7 = graph()->NewNode(op, nil); - USE(n7); - op = common()->FrameState(JS_FRAME, BailoutId(-1), - OutputFrameStateCombine::Ignore()); - Node* n13 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n13); - op = common()->IfSuccess(); - Node* n26 = graph()->NewNode(op, nil); - USE(n26); - op = js()->Multiply(LanguageMode::SLOPPY); - Node* n32 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n32); - op = common()->Parameter(1); - Node* n2 = graph()->NewNode(op, nil); - USE(n2); - op = common()->IfSuccess(); - Node* n33 = graph()->NewNode(op, nil); - USE(n33); - op = js()->Subtract(LanguageMode::SLOPPY); - Node* n23 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n23); - op = common()->IfSuccess(); - Node* n24 = graph()->NewNode(op, nil); - USE(n24); - op = common()->Start(4); - Node* n0 = graph()->NewNode(op); - USE(n0); - op = common()->StateValues(0); - Node* n11 = graph()->NewNode(op); - USE(n11); - op = common()->NumberConstant(0); - Node* n12 = graph()->NewNode(op); - USE(n12); - op = common()->HeapConstant(unique_constant); - Node* n6 = graph()->NewNode(op); - USE(n6); - op = common()->Parameter(3); - Node* n4 = graph()->NewNode(op, nil); - USE(n4); - op = js()->LessThan(LanguageMode::SLOPPY); - Node* n15 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n15); - op = common()->IfFalse(); - Node* n31 = graph()->NewNode(op, nil); - USE(n31); - op = js()->Add(LanguageMode::SLOPPY); - Node* n19 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n19); - op = js()->Multiply(LanguageMode::SLOPPY); - Node* n21 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n21); - op = common()->IfSuccess(); - Node* n22 = graph()->NewNode(op, nil); - USE(n22); - op = common()->Parameter(2); - Node* n3 = graph()->NewNode(op, nil); - USE(n3); - op = js()->StackCheck(); - Node* n9 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n9); - op = common()->IfSuccess(); - Node* n10 = graph()->NewNode(op, nil); - USE(n10); - op = common()->Branch(); - Node* n17 = graph()->NewNode(op, nil, nil); - USE(n17); - op = common()->IfTrue(); - Node* n18 = graph()->NewNode(op, nil); - USE(n18); - op = common()->IfSuccess(); - Node* n20 = graph()->NewNode(op, nil); - USE(n20); - op = common()->IfSuccess(); - Node* n16 = graph()->NewNode(op, nil); - USE(n16); - n39->ReplaceInput(0, n37); - n37->ReplaceInput(0, n29); - n37->ReplaceInput(1, n36); - n29->ReplaceInput(0, n27); - n29->ReplaceInput(1, n27); - n29->ReplaceInput(2, n28); - n36->ReplaceInput(0, n34); - n36->ReplaceInput(1, n34); - n36->ReplaceInput(2, n35); - n27->ReplaceInput(0, n25); - n27->ReplaceInput(1, n5); - n27->ReplaceInput(2, n7); - n27->ReplaceInput(3, n13); - n27->ReplaceInput(4, n13); - n27->ReplaceInput(5, n25); - n27->ReplaceInput(6, n26); - n28->ReplaceInput(0, n27); - n34->ReplaceInput(0, n32); - n34->ReplaceInput(1, n2); - n34->ReplaceInput(2, n7); - n34->ReplaceInput(3, n13); - n34->ReplaceInput(4, n13); - n34->ReplaceInput(5, n32); - n34->ReplaceInput(6, n33); - n35->ReplaceInput(0, n34); - n25->ReplaceInput(0, n23); - n25->ReplaceInput(1, n2); - n25->ReplaceInput(2, n7); - n25->ReplaceInput(3, n13); - n25->ReplaceInput(4, n13); - n25->ReplaceInput(5, n23); - n25->ReplaceInput(6, n24); - n5->ReplaceInput(0, n0); - n7->ReplaceInput(0, n0); - n13->ReplaceInput(0, n11); - n13->ReplaceInput(1, n11); - n13->ReplaceInput(2, n11); - n13->ReplaceInput(3, n12); - n13->ReplaceInput(4, n6); - n26->ReplaceInput(0, n25); - n32->ReplaceInput(0, n4); - n32->ReplaceInput(1, n4); - n32->ReplaceInput(2, n7); - n32->ReplaceInput(3, n13); - n32->ReplaceInput(4, n13); - n32->ReplaceInput(5, n15); - n32->ReplaceInput(6, n31); - n2->ReplaceInput(0, n0); - n33->ReplaceInput(0, n32); - n23->ReplaceInput(0, n19); - n23->ReplaceInput(1, n21); - n23->ReplaceInput(2, n7); - n23->ReplaceInput(3, n13); - n23->ReplaceInput(4, n13); - n23->ReplaceInput(5, n21); - n23->ReplaceInput(6, n22); - n24->ReplaceInput(0, n23); - n4->ReplaceInput(0, n0); - n15->ReplaceInput(0, n2); - n15->ReplaceInput(1, n3); - n15->ReplaceInput(2, n7); - n15->ReplaceInput(3, n13); - n15->ReplaceInput(4, n9); - n15->ReplaceInput(5, n10); - n31->ReplaceInput(0, n17); - n19->ReplaceInput(0, n2); - n19->ReplaceInput(1, n3); - n19->ReplaceInput(2, n7); - n19->ReplaceInput(3, n13); - n19->ReplaceInput(4, n13); - n19->ReplaceInput(5, n15); - n19->ReplaceInput(6, n18); - n21->ReplaceInput(0, n4); - n21->ReplaceInput(1, n4); - n21->ReplaceInput(2, n7); - n21->ReplaceInput(3, n13); - n21->ReplaceInput(4, n13); - n21->ReplaceInput(5, n19); - n21->ReplaceInput(6, n20); - n22->ReplaceInput(0, n21); - n3->ReplaceInput(0, n0); - n9->ReplaceInput(0, n7); - n9->ReplaceInput(1, n13); - n9->ReplaceInput(2, n0); - n9->ReplaceInput(3, n0); - n10->ReplaceInput(0, n9); - n17->ReplaceInput(0, n15); - n17->ReplaceInput(1, n16); - n18->ReplaceInput(0, n17); - n20->ReplaceInput(0, n19); - n16->ReplaceInput(0, n15); - - graph()->SetStart(n0); - graph()->SetEnd(n39); - - ComputeAndVerifySchedule(34); -} - - -TEST_F(SchedulerTest, BuildScheduleSimpleLoop) { - const Operator* op; - Unique<HeapObject> unique_constant = - Unique<HeapObject>::CreateImmovable(factory()->undefined_value()); - - // Manually transcripted code for: - // function turbo_fan_test(a, b) { - // while (a < b) { - // a++; - // } - // return a; - // } - Node* nil = graph()->NewNode(common()->Dead()); - op = common()->End(); - Node* n34 = graph()->NewNode(op, nil); - USE(n34); - op = common()->Return(); - Node* n32 = graph()->NewNode(op, nil, nil, nil); - USE(n32); - op = common()->Phi(kMachAnyTagged, 2); - Node* n13 = graph()->NewNode(op, nil, nil, nil); - USE(n13); - op = js()->LessThan(LanguageMode::SLOPPY); - Node* n16 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n16); - op = common()->IfFalse(); - Node* n22 = graph()->NewNode(op, nil); - USE(n22); - op = common()->Parameter(1); - Node* n2 = graph()->NewNode(op, nil); - USE(n2); - op = js()->Add(LanguageMode::SLOPPY); - Node* n29 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n29); - op = common()->Loop(2); - Node* n12 = graph()->NewNode(op, nil, nil); - USE(n12); - op = common()->Parameter(2); - Node* n3 = graph()->NewNode(op, nil); - USE(n3); - op = common()->Parameter(3); - Node* n5 = graph()->NewNode(op, nil); - USE(n5); - op = common()->FrameState(JS_FRAME, BailoutId(-1), - OutputFrameStateCombine::Ignore()); - Node* n11 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n11); - op = common()->EffectPhi(2); - Node* n14 = graph()->NewNode(op, nil, nil, nil); - USE(n14); - op = common()->Branch(); - Node* n19 = graph()->NewNode(op, nil, nil); - USE(n19); - op = common()->Start(2); - Node* n0 = graph()->NewNode(op); - USE(n0); - op = js()->ToNumber(); - Node* n26 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n26); - op = common()->NumberConstant(1); - Node* n28 = graph()->NewNode(op); - USE(n28); - op = common()->IfSuccess(); - Node* n27 = graph()->NewNode(op, nil); - USE(n27); - op = common()->IfSuccess(); - Node* n8 = graph()->NewNode(op, nil); - USE(n8); - op = common()->IfSuccess(); - Node* n30 = graph()->NewNode(op, nil); - USE(n30); - op = common()->StateValues(0); - Node* n9 = graph()->NewNode(op); - USE(n9); - op = common()->NumberConstant(0); - Node* n10 = graph()->NewNode(op); - USE(n10); - op = common()->HeapConstant(unique_constant); - Node* n4 = graph()->NewNode(op); - USE(n4); - op = js()->StackCheck(); - Node* n7 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n7); - op = js()->ToBoolean(); - Node* n18 = graph()->NewNode(op, nil, nil); - USE(n18); - op = common()->IfSuccess(); - Node* n17 = graph()->NewNode(op, nil); - USE(n17); - op = js()->StackCheck(); - Node* n24 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n24); - op = common()->IfSuccess(); - Node* n25 = graph()->NewNode(op, nil); - USE(n25); - op = common()->IfTrue(); - Node* n20 = graph()->NewNode(op, nil); - USE(n20); - n34->ReplaceInput(0, n32); - n32->ReplaceInput(0, n13); - n32->ReplaceInput(1, n16); - n32->ReplaceInput(2, n22); - n13->ReplaceInput(0, n2); - n13->ReplaceInput(1, n29); - n13->ReplaceInput(2, n12); - n16->ReplaceInput(0, n13); - n16->ReplaceInput(1, n3); - n16->ReplaceInput(2, n5); - n16->ReplaceInput(3, n11); - n16->ReplaceInput(4, n14); - n16->ReplaceInput(5, n12); - n22->ReplaceInput(0, n19); - n2->ReplaceInput(0, n0); - n29->ReplaceInput(0, n26); - n29->ReplaceInput(1, n28); - n29->ReplaceInput(2, n5); - n29->ReplaceInput(3, n11); - n29->ReplaceInput(4, n11); - n29->ReplaceInput(5, n26); - n29->ReplaceInput(6, n27); - n12->ReplaceInput(0, n8); - n12->ReplaceInput(1, n30); - n3->ReplaceInput(0, n0); - n5->ReplaceInput(0, n0); - n11->ReplaceInput(0, n9); - n11->ReplaceInput(1, n9); - n11->ReplaceInput(2, n9); - n11->ReplaceInput(3, n10); - n11->ReplaceInput(4, n4); - n14->ReplaceInput(0, n7); - n14->ReplaceInput(1, n29); - n14->ReplaceInput(2, n12); - n19->ReplaceInput(0, n18); - n19->ReplaceInput(1, n17); - n26->ReplaceInput(0, n13); - n26->ReplaceInput(1, n5); - n26->ReplaceInput(2, n11); - n26->ReplaceInput(3, n24); - n26->ReplaceInput(4, n25); - n27->ReplaceInput(0, n26); - n8->ReplaceInput(0, n7); - n30->ReplaceInput(0, n29); - n7->ReplaceInput(0, n5); - n7->ReplaceInput(1, n11); - n7->ReplaceInput(2, n0); - n7->ReplaceInput(3, n0); - n18->ReplaceInput(0, n16); - n18->ReplaceInput(1, n5); - n17->ReplaceInput(0, n16); - n24->ReplaceInput(0, n5); - n24->ReplaceInput(1, n11); - n24->ReplaceInput(2, n16); - n24->ReplaceInput(3, n20); - n25->ReplaceInput(0, n24); - n20->ReplaceInput(0, n19); - - graph()->SetStart(n0); - graph()->SetEnd(n34); - - ComputeAndVerifySchedule(30); -} - - -TEST_F(SchedulerTest, BuildScheduleComplexLoops) { - const Operator* op; - Unique<HeapObject> unique_constant = - Unique<HeapObject>::CreateImmovable(factory()->undefined_value()); - - // Manually transcripted code for: - // function turbo_fan_test(a, b, c) { - // while (a < b) { - // a++; - // while (c < b) { - // c++; - // } - // } - // while (a < b) { - // a += 2; - // } - // return a; - // } - Node* nil = graph()->NewNode(common()->Dead()); - op = common()->End(); - Node* n71 = graph()->NewNode(op, nil); - USE(n71); - op = common()->Return(); - Node* n69 = graph()->NewNode(op, nil, nil, nil); - USE(n69); - op = common()->Phi(kMachAnyTagged, 2); - Node* n53 = graph()->NewNode(op, nil, nil, nil); - USE(n53); - op = js()->LessThan(LanguageMode::SLOPPY); - Node* n55 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n55); - op = common()->IfFalse(); - Node* n61 = graph()->NewNode(op, nil); - USE(n61); - op = common()->Phi(kMachAnyTagged, 2); - Node* n14 = graph()->NewNode(op, nil, nil, nil); - USE(n14); - op = js()->Add(LanguageMode::SLOPPY); - Node* n66 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n66); - op = common()->Loop(2); - Node* n52 = graph()->NewNode(op, nil, nil); - USE(n52); - op = common()->Parameter(2); - Node* n3 = graph()->NewNode(op, nil); - USE(n3); - op = common()->Parameter(4); - Node* n6 = graph()->NewNode(op, nil); - USE(n6); - op = common()->FrameState(JS_FRAME, BailoutId(-1), - OutputFrameStateCombine::Ignore()); - Node* n12 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n12); - op = common()->EffectPhi(2); - Node* n54 = graph()->NewNode(op, nil, nil, nil); - USE(n54); - op = common()->Branch(); - Node* n58 = graph()->NewNode(op, nil, nil); - USE(n58); - op = common()->Parameter(1); - Node* n2 = graph()->NewNode(op, nil); - USE(n2); - op = js()->Add(LanguageMode::SLOPPY); - Node* n31 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n31); - op = common()->Loop(2); - Node* n13 = graph()->NewNode(op, nil, nil); - USE(n13); - op = common()->NumberConstant(2); - Node* n65 = graph()->NewNode(op); - USE(n65); - op = js()->StackCheck(); - Node* n63 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n63); - op = common()->IfSuccess(); - Node* n64 = graph()->NewNode(op, nil); - USE(n64); - op = common()->IfFalse(); - Node* n24 = graph()->NewNode(op, nil); - USE(n24); - op = common()->IfSuccess(); - Node* n67 = graph()->NewNode(op, nil); - USE(n67); - op = common()->Start(3); - Node* n0 = graph()->NewNode(op); - USE(n0); - op = common()->StateValues(0); - Node* n10 = graph()->NewNode(op); - USE(n10); - op = common()->NumberConstant(0); - Node* n11 = graph()->NewNode(op); - USE(n11); - op = common()->HeapConstant(unique_constant); - Node* n5 = graph()->NewNode(op); - USE(n5); - op = js()->LessThan(LanguageMode::SLOPPY); - Node* n18 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n18); - op = js()->ToBoolean(); - Node* n57 = graph()->NewNode(op, nil, nil); - USE(n57); - op = common()->IfSuccess(); - Node* n56 = graph()->NewNode(op, nil); - USE(n56); - op = js()->ToNumber(); - Node* n28 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n28); - op = common()->NumberConstant(1); - Node* n30 = graph()->NewNode(op); - USE(n30); - op = common()->IfSuccess(); - Node* n29 = graph()->NewNode(op, nil); - USE(n29); - op = common()->IfSuccess(); - Node* n9 = graph()->NewNode(op, nil); - USE(n9); - op = common()->IfFalse(); - Node* n42 = graph()->NewNode(op, nil); - USE(n42); - op = common()->IfTrue(); - Node* n59 = graph()->NewNode(op, nil); - USE(n59); - op = common()->Branch(); - Node* n21 = graph()->NewNode(op, nil, nil); - USE(n21); - op = common()->EffectPhi(2); - Node* n16 = graph()->NewNode(op, nil, nil, nil); - USE(n16); - op = js()->StackCheck(); - Node* n26 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n26); - op = common()->IfSuccess(); - Node* n27 = graph()->NewNode(op, nil); - USE(n27); - op = js()->StackCheck(); - Node* n8 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n8); - op = common()->Branch(); - Node* n39 = graph()->NewNode(op, nil, nil); - USE(n39); - op = js()->ToBoolean(); - Node* n20 = graph()->NewNode(op, nil, nil); - USE(n20); - op = common()->IfSuccess(); - Node* n19 = graph()->NewNode(op, nil); - USE(n19); - op = js()->LessThan(LanguageMode::SLOPPY); - Node* n36 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n36); - op = common()->IfTrue(); - Node* n22 = graph()->NewNode(op, nil); - USE(n22); - op = js()->ToBoolean(); - Node* n38 = graph()->NewNode(op, nil, nil); - USE(n38); - op = common()->IfSuccess(); - Node* n37 = graph()->NewNode(op, nil); - USE(n37); - op = common()->Phi(kMachAnyTagged, 2); - Node* n34 = graph()->NewNode(op, nil, nil, nil); - USE(n34); - op = common()->EffectPhi(2); - Node* n35 = graph()->NewNode(op, nil, nil, nil); - USE(n35); - op = common()->Loop(2); - Node* n33 = graph()->NewNode(op, nil, nil); - USE(n33); - op = common()->Phi(kMachAnyTagged, 2); - Node* n15 = graph()->NewNode(op, nil, nil, nil); - USE(n15); - op = js()->Add(LanguageMode::SLOPPY); - Node* n48 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n48); - op = common()->IfSuccess(); - Node* n32 = graph()->NewNode(op, nil); - USE(n32); - op = common()->IfSuccess(); - Node* n49 = graph()->NewNode(op, nil); - USE(n49); - op = common()->Parameter(3); - Node* n4 = graph()->NewNode(op, nil); - USE(n4); - op = js()->ToNumber(); - Node* n46 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n46); - op = common()->IfSuccess(); - Node* n47 = graph()->NewNode(op, nil); - USE(n47); - op = js()->StackCheck(); - Node* n44 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n44); - op = common()->IfSuccess(); - Node* n45 = graph()->NewNode(op, nil); - USE(n45); - op = common()->IfTrue(); - Node* n40 = graph()->NewNode(op, nil); - USE(n40); - n71->ReplaceInput(0, n69); - n69->ReplaceInput(0, n53); - n69->ReplaceInput(1, n55); - n69->ReplaceInput(2, n61); - n53->ReplaceInput(0, n14); - n53->ReplaceInput(1, n66); - n53->ReplaceInput(2, n52); - n55->ReplaceInput(0, n53); - n55->ReplaceInput(1, n3); - n55->ReplaceInput(2, n6); - n55->ReplaceInput(3, n12); - n55->ReplaceInput(4, n54); - n55->ReplaceInput(5, n52); - n61->ReplaceInput(0, n58); - n14->ReplaceInput(0, n2); - n14->ReplaceInput(1, n31); - n14->ReplaceInput(2, n13); - n66->ReplaceInput(0, n53); - n66->ReplaceInput(1, n65); - n66->ReplaceInput(2, n6); - n66->ReplaceInput(3, n12); - n66->ReplaceInput(4, n12); - n66->ReplaceInput(5, n63); - n66->ReplaceInput(6, n64); - n52->ReplaceInput(0, n24); - n52->ReplaceInput(1, n67); - n3->ReplaceInput(0, n0); - n6->ReplaceInput(0, n0); - n12->ReplaceInput(0, n10); - n12->ReplaceInput(1, n10); - n12->ReplaceInput(2, n10); - n12->ReplaceInput(3, n11); - n12->ReplaceInput(4, n5); - n54->ReplaceInput(0, n18); - n54->ReplaceInput(1, n66); - n54->ReplaceInput(2, n52); - n58->ReplaceInput(0, n57); - n58->ReplaceInput(1, n56); - n2->ReplaceInput(0, n0); - n31->ReplaceInput(0, n28); - n31->ReplaceInput(1, n30); - n31->ReplaceInput(2, n6); - n31->ReplaceInput(3, n12); - n31->ReplaceInput(4, n12); - n31->ReplaceInput(5, n28); - n31->ReplaceInput(6, n29); - n13->ReplaceInput(0, n9); - n13->ReplaceInput(1, n42); - n63->ReplaceInput(0, n6); - n63->ReplaceInput(1, n12); - n63->ReplaceInput(2, n55); - n63->ReplaceInput(3, n59); - n64->ReplaceInput(0, n63); - n24->ReplaceInput(0, n21); - n67->ReplaceInput(0, n66); - n18->ReplaceInput(0, n14); - n18->ReplaceInput(1, n3); - n18->ReplaceInput(2, n6); - n18->ReplaceInput(3, n12); - n18->ReplaceInput(4, n16); - n18->ReplaceInput(5, n13); - n57->ReplaceInput(0, n55); - n57->ReplaceInput(1, n6); - n56->ReplaceInput(0, n55); - n28->ReplaceInput(0, n14); - n28->ReplaceInput(1, n6); - n28->ReplaceInput(2, n12); - n28->ReplaceInput(3, n26); - n28->ReplaceInput(4, n27); - n29->ReplaceInput(0, n28); - n9->ReplaceInput(0, n8); - n42->ReplaceInput(0, n39); - n59->ReplaceInput(0, n58); - n21->ReplaceInput(0, n20); - n21->ReplaceInput(1, n19); - n16->ReplaceInput(0, n8); - n16->ReplaceInput(1, n36); - n16->ReplaceInput(2, n13); - n26->ReplaceInput(0, n6); - n26->ReplaceInput(1, n12); - n26->ReplaceInput(2, n18); - n26->ReplaceInput(3, n22); - n27->ReplaceInput(0, n26); - n8->ReplaceInput(0, n6); - n8->ReplaceInput(1, n12); - n8->ReplaceInput(2, n0); - n8->ReplaceInput(3, n0); - n39->ReplaceInput(0, n38); - n39->ReplaceInput(1, n37); - n20->ReplaceInput(0, n18); - n20->ReplaceInput(1, n6); - n19->ReplaceInput(0, n18); - n36->ReplaceInput(0, n34); - n36->ReplaceInput(1, n3); - n36->ReplaceInput(2, n6); - n36->ReplaceInput(3, n12); - n36->ReplaceInput(4, n35); - n36->ReplaceInput(5, n33); - n22->ReplaceInput(0, n21); - n38->ReplaceInput(0, n36); - n38->ReplaceInput(1, n6); - n37->ReplaceInput(0, n36); - n34->ReplaceInput(0, n15); - n34->ReplaceInput(1, n48); - n34->ReplaceInput(2, n33); - n35->ReplaceInput(0, n31); - n35->ReplaceInput(1, n48); - n35->ReplaceInput(2, n33); - n33->ReplaceInput(0, n32); - n33->ReplaceInput(1, n49); - n15->ReplaceInput(0, n4); - n15->ReplaceInput(1, n34); - n15->ReplaceInput(2, n13); - n48->ReplaceInput(0, n46); - n48->ReplaceInput(1, n30); - n48->ReplaceInput(2, n6); - n48->ReplaceInput(3, n12); - n48->ReplaceInput(4, n12); - n48->ReplaceInput(5, n46); - n48->ReplaceInput(6, n47); - n32->ReplaceInput(0, n31); - n49->ReplaceInput(0, n48); - n4->ReplaceInput(0, n0); - n46->ReplaceInput(0, n34); - n46->ReplaceInput(1, n6); - n46->ReplaceInput(2, n12); - n46->ReplaceInput(3, n44); - n46->ReplaceInput(4, n45); - n47->ReplaceInput(0, n46); - n44->ReplaceInput(0, n6); - n44->ReplaceInput(1, n12); - n44->ReplaceInput(2, n36); - n44->ReplaceInput(3, n40); - n45->ReplaceInput(0, n44); - n40->ReplaceInput(0, n39); - - graph()->SetStart(n0); - graph()->SetEnd(n71); - - ComputeAndVerifySchedule(65); -} - - -TEST_F(SchedulerTest, BuildScheduleBreakAndContinue) { - const Operator* op; - Unique<HeapObject> unique_constant = - Unique<HeapObject>::CreateImmovable(factory()->undefined_value()); - - // Manually transcripted code for: - // function turbo_fan_test(a, b, c) { - // var d = 0; - // while (a < b) { - // a++; - // while (c < b) { - // c++; - // if (d == 0) break; - // a++; - // } - // if (a == 1) continue; - // d++; - // } - // return a + d; - // } - Node* nil = graph()->NewNode(common()->Dead()); - op = common()->End(); - Node* n86 = graph()->NewNode(op, nil); - USE(n86); - op = common()->Return(); - Node* n84 = graph()->NewNode(op, nil, nil, nil); - USE(n84); - op = js()->Add(LanguageMode::SLOPPY); - Node* n82 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n82); - op = common()->IfSuccess(); - Node* n83 = graph()->NewNode(op, nil); - USE(n83); - op = common()->Phi(kMachAnyTagged, 2); - Node* n15 = graph()->NewNode(op, nil, nil, nil); - USE(n15); - op = common()->Phi(kMachAnyTagged, 2); - Node* n17 = graph()->NewNode(op, nil, nil, nil); - USE(n17); - op = common()->Parameter(4); - Node* n6 = graph()->NewNode(op, nil); - USE(n6); - op = common()->FrameState(JS_FRAME, BailoutId(-1), - OutputFrameStateCombine::Ignore()); - Node* n12 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n12); - op = js()->LessThan(LanguageMode::SLOPPY); - Node* n19 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n19); - op = common()->IfFalse(); - Node* n25 = graph()->NewNode(op, nil); - USE(n25); - op = common()->Parameter(1); - Node* n2 = graph()->NewNode(op, nil); - USE(n2); - op = common()->Phi(kMachAnyTagged, 2); - Node* n35 = graph()->NewNode(op, nil, nil, nil); - USE(n35); - op = common()->Loop(2); - Node* n14 = graph()->NewNode(op, nil, nil); - USE(n14); - op = common()->NumberConstant(0); - Node* n11 = graph()->NewNode(op); - USE(n11); - op = common()->Phi(kMachAnyTagged, 2); - Node* n81 = graph()->NewNode(op, nil, nil, nil); - USE(n81); - op = common()->Start(3); - Node* n0 = graph()->NewNode(op); - USE(n0); - op = common()->StateValues(0); - Node* n10 = graph()->NewNode(op); - USE(n10); - op = common()->HeapConstant(unique_constant); - Node* n5 = graph()->NewNode(op); - USE(n5); - op = common()->Parameter(2); - Node* n3 = graph()->NewNode(op, nil); - USE(n3); - op = common()->EffectPhi(2); - Node* n18 = graph()->NewNode(op, nil, nil, nil); - USE(n18); - op = common()->Branch(); - Node* n22 = graph()->NewNode(op, nil, nil); - USE(n22); - op = js()->Add(LanguageMode::SLOPPY); - Node* n32 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n32); - op = js()->Add(LanguageMode::SLOPPY); - Node* n64 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n64); - op = common()->Loop(2); - Node* n34 = graph()->NewNode(op, nil, nil); - USE(n34); - op = common()->IfSuccess(); - Node* n9 = graph()->NewNode(op, nil); - USE(n9); - op = common()->Merge(2); - Node* n72 = graph()->NewNode(op, nil, nil); - USE(n72); - op = js()->Add(LanguageMode::SLOPPY); - Node* n78 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n78); - op = js()->StackCheck(); - Node* n8 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n8); - op = common()->EffectPhi(2); - Node* n80 = graph()->NewNode(op, nil, nil, nil); - USE(n80); - op = js()->ToBoolean(); - Node* n21 = graph()->NewNode(op, nil, nil); - USE(n21); - op = common()->IfSuccess(); - Node* n20 = graph()->NewNode(op, nil); - USE(n20); - op = js()->ToNumber(); - Node* n29 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n29); - op = common()->NumberConstant(1); - Node* n31 = graph()->NewNode(op); - USE(n31); - op = common()->IfSuccess(); - Node* n30 = graph()->NewNode(op, nil); - USE(n30); - op = js()->ToNumber(); - Node* n62 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n62); - op = common()->IfSuccess(); - Node* n63 = graph()->NewNode(op, nil); - USE(n63); - op = common()->IfSuccess(); - Node* n33 = graph()->NewNode(op, nil); - USE(n33); - op = common()->IfSuccess(); - Node* n65 = graph()->NewNode(op, nil); - USE(n65); - op = common()->IfTrue(); - Node* n71 = graph()->NewNode(op, nil); - USE(n71); - op = common()->IfSuccess(); - Node* n79 = graph()->NewNode(op, nil); - USE(n79); - op = js()->ToNumber(); - Node* n76 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n76); - op = common()->IfSuccess(); - Node* n77 = graph()->NewNode(op, nil); - USE(n77); - op = js()->Equal(); - Node* n67 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n67); - op = js()->StackCheck(); - Node* n27 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n27); - op = common()->IfSuccess(); - Node* n28 = graph()->NewNode(op, nil); - USE(n28); - op = js()->Equal(); - Node* n52 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n52); - op = common()->IfFalse(); - Node* n60 = graph()->NewNode(op, nil); - USE(n60); - op = common()->Branch(); - Node* n70 = graph()->NewNode(op, nil, nil); - USE(n70); - op = common()->IfFalse(); - Node* n74 = graph()->NewNode(op, nil); - USE(n74); - op = common()->EffectPhi(2); - Node* n57 = graph()->NewNode(op, nil, nil, nil); - USE(n57); - op = common()->Merge(2); - Node* n45 = graph()->NewNode(op, nil, nil); - USE(n45); - op = common()->IfTrue(); - Node* n23 = graph()->NewNode(op, nil); - USE(n23); - op = js()->Add(LanguageMode::SLOPPY); - Node* n50 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n50); - op = common()->IfSuccess(); - Node* n51 = graph()->NewNode(op, nil); - USE(n51); - op = common()->Branch(); - Node* n55 = graph()->NewNode(op, nil, nil); - USE(n55); - op = js()->ToBoolean(); - Node* n69 = graph()->NewNode(op, nil, nil); - USE(n69); - op = common()->IfSuccess(); - Node* n68 = graph()->NewNode(op, nil); - USE(n68); - op = js()->LessThan(LanguageMode::SLOPPY); - Node* n38 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n38); - op = common()->IfFalse(); - Node* n44 = graph()->NewNode(op, nil); - USE(n44); - op = common()->IfTrue(); - Node* n56 = graph()->NewNode(op, nil); - USE(n56); - op = js()->ToNumber(); - Node* n48 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n48); - op = common()->IfSuccess(); - Node* n49 = graph()->NewNode(op, nil); - USE(n49); - op = js()->ToBoolean(); - Node* n54 = graph()->NewNode(op, nil, nil); - USE(n54); - op = common()->IfSuccess(); - Node* n53 = graph()->NewNode(op, nil); - USE(n53); - op = common()->Phi(kMachAnyTagged, 2); - Node* n36 = graph()->NewNode(op, nil, nil, nil); - USE(n36); - op = common()->EffectPhi(2); - Node* n37 = graph()->NewNode(op, nil, nil, nil); - USE(n37); - op = common()->Branch(); - Node* n41 = graph()->NewNode(op, nil, nil); - USE(n41); - op = js()->StackCheck(); - Node* n46 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n46); - op = common()->IfSuccess(); - Node* n47 = graph()->NewNode(op, nil); - USE(n47); - op = common()->Phi(kMachAnyTagged, 2); - Node* n16 = graph()->NewNode(op, nil, nil, nil); - USE(n16); - op = js()->ToBoolean(); - Node* n40 = graph()->NewNode(op, nil, nil); - USE(n40); - op = common()->IfSuccess(); - Node* n39 = graph()->NewNode(op, nil); - USE(n39); - op = common()->IfTrue(); - Node* n42 = graph()->NewNode(op, nil); - USE(n42); - op = common()->Parameter(3); - Node* n4 = graph()->NewNode(op, nil); - USE(n4); - op = common()->Phi(kMachAnyTagged, 2); - Node* n58 = graph()->NewNode(op, nil, nil, nil); - USE(n58); - n86->ReplaceInput(0, n84); - n84->ReplaceInput(0, n82); - n84->ReplaceInput(1, n82); - n84->ReplaceInput(2, n83); - n82->ReplaceInput(0, n15); - n82->ReplaceInput(1, n17); - n82->ReplaceInput(2, n6); - n82->ReplaceInput(3, n12); - n82->ReplaceInput(4, n12); - n82->ReplaceInput(5, n19); - n82->ReplaceInput(6, n25); - n83->ReplaceInput(0, n82); - n15->ReplaceInput(0, n2); - n15->ReplaceInput(1, n35); - n15->ReplaceInput(2, n14); - n17->ReplaceInput(0, n11); - n17->ReplaceInput(1, n81); - n17->ReplaceInput(2, n14); - n6->ReplaceInput(0, n0); - n12->ReplaceInput(0, n10); - n12->ReplaceInput(1, n10); - n12->ReplaceInput(2, n10); - n12->ReplaceInput(3, n11); - n12->ReplaceInput(4, n5); - n19->ReplaceInput(0, n15); - n19->ReplaceInput(1, n3); - n19->ReplaceInput(2, n6); - n19->ReplaceInput(3, n12); - n19->ReplaceInput(4, n18); - n19->ReplaceInput(5, n14); - n25->ReplaceInput(0, n22); - n2->ReplaceInput(0, n0); - n35->ReplaceInput(0, n32); - n35->ReplaceInput(1, n64); - n35->ReplaceInput(2, n34); - n14->ReplaceInput(0, n9); - n14->ReplaceInput(1, n72); - n81->ReplaceInput(0, n17); - n81->ReplaceInput(1, n78); - n81->ReplaceInput(2, n72); - n3->ReplaceInput(0, n0); - n18->ReplaceInput(0, n8); - n18->ReplaceInput(1, n80); - n18->ReplaceInput(2, n14); - n22->ReplaceInput(0, n21); - n22->ReplaceInput(1, n20); - n32->ReplaceInput(0, n29); - n32->ReplaceInput(1, n31); - n32->ReplaceInput(2, n6); - n32->ReplaceInput(3, n12); - n32->ReplaceInput(4, n12); - n32->ReplaceInput(5, n29); - n32->ReplaceInput(6, n30); - n64->ReplaceInput(0, n62); - n64->ReplaceInput(1, n31); - n64->ReplaceInput(2, n6); - n64->ReplaceInput(3, n12); - n64->ReplaceInput(4, n12); - n64->ReplaceInput(5, n62); - n64->ReplaceInput(6, n63); - n34->ReplaceInput(0, n33); - n34->ReplaceInput(1, n65); - n9->ReplaceInput(0, n8); - n72->ReplaceInput(0, n71); - n72->ReplaceInput(1, n79); - n78->ReplaceInput(0, n76); - n78->ReplaceInput(1, n31); - n78->ReplaceInput(2, n6); - n78->ReplaceInput(3, n12); - n78->ReplaceInput(4, n12); - n78->ReplaceInput(5, n76); - n78->ReplaceInput(6, n77); - n8->ReplaceInput(0, n6); - n8->ReplaceInput(1, n12); - n8->ReplaceInput(2, n0); - n8->ReplaceInput(3, n0); - n80->ReplaceInput(0, n67); - n80->ReplaceInput(1, n78); - n80->ReplaceInput(2, n72); - n21->ReplaceInput(0, n19); - n21->ReplaceInput(1, n6); - n20->ReplaceInput(0, n19); - n29->ReplaceInput(0, n15); - n29->ReplaceInput(1, n6); - n29->ReplaceInput(2, n12); - n29->ReplaceInput(3, n27); - n29->ReplaceInput(4, n28); - n30->ReplaceInput(0, n29); - n62->ReplaceInput(0, n35); - n62->ReplaceInput(1, n6); - n62->ReplaceInput(2, n12); - n62->ReplaceInput(3, n52); - n62->ReplaceInput(4, n60); - n63->ReplaceInput(0, n62); - n33->ReplaceInput(0, n32); - n65->ReplaceInput(0, n64); - n71->ReplaceInput(0, n70); - n79->ReplaceInput(0, n78); - n76->ReplaceInput(0, n17); - n76->ReplaceInput(1, n6); - n76->ReplaceInput(2, n12); - n76->ReplaceInput(3, n67); - n76->ReplaceInput(4, n74); - n77->ReplaceInput(0, n76); - n67->ReplaceInput(0, n35); - n67->ReplaceInput(1, n31); - n67->ReplaceInput(2, n6); - n67->ReplaceInput(3, n12); - n67->ReplaceInput(4, n57); - n67->ReplaceInput(5, n45); - n27->ReplaceInput(0, n6); - n27->ReplaceInput(1, n12); - n27->ReplaceInput(2, n19); - n27->ReplaceInput(3, n23); - n28->ReplaceInput(0, n27); - n52->ReplaceInput(0, n17); - n52->ReplaceInput(1, n11); - n52->ReplaceInput(2, n6); - n52->ReplaceInput(3, n12); - n52->ReplaceInput(4, n50); - n52->ReplaceInput(5, n51); - n60->ReplaceInput(0, n55); - n70->ReplaceInput(0, n69); - n70->ReplaceInput(1, n68); - n74->ReplaceInput(0, n70); - n57->ReplaceInput(0, n38); - n57->ReplaceInput(1, n52); - n57->ReplaceInput(2, n45); - n45->ReplaceInput(0, n44); - n45->ReplaceInput(1, n56); - n23->ReplaceInput(0, n22); - n50->ReplaceInput(0, n48); - n50->ReplaceInput(1, n31); - n50->ReplaceInput(2, n6); - n50->ReplaceInput(3, n12); - n50->ReplaceInput(4, n12); - n50->ReplaceInput(5, n48); - n50->ReplaceInput(6, n49); - n51->ReplaceInput(0, n50); - n55->ReplaceInput(0, n54); - n55->ReplaceInput(1, n53); - n69->ReplaceInput(0, n67); - n69->ReplaceInput(1, n6); - n68->ReplaceInput(0, n67); - n38->ReplaceInput(0, n36); - n38->ReplaceInput(1, n3); - n38->ReplaceInput(2, n6); - n38->ReplaceInput(3, n12); - n38->ReplaceInput(4, n37); - n38->ReplaceInput(5, n34); - n44->ReplaceInput(0, n41); - n56->ReplaceInput(0, n55); - n48->ReplaceInput(0, n36); - n48->ReplaceInput(1, n6); - n48->ReplaceInput(2, n12); - n48->ReplaceInput(3, n46); - n48->ReplaceInput(4, n47); - n49->ReplaceInput(0, n48); - n54->ReplaceInput(0, n52); - n54->ReplaceInput(1, n6); - n53->ReplaceInput(0, n52); - n36->ReplaceInput(0, n16); - n36->ReplaceInput(1, n50); - n36->ReplaceInput(2, n34); - n37->ReplaceInput(0, n32); - n37->ReplaceInput(1, n64); - n37->ReplaceInput(2, n34); - n41->ReplaceInput(0, n40); - n41->ReplaceInput(1, n39); - n46->ReplaceInput(0, n6); - n46->ReplaceInput(1, n12); - n46->ReplaceInput(2, n38); - n46->ReplaceInput(3, n42); - n47->ReplaceInput(0, n46); - n16->ReplaceInput(0, n4); - n16->ReplaceInput(1, n58); - n16->ReplaceInput(2, n14); - n40->ReplaceInput(0, n38); - n40->ReplaceInput(1, n6); - n39->ReplaceInput(0, n38); - n42->ReplaceInput(0, n41); - n4->ReplaceInput(0, n0); - n58->ReplaceInput(0, n36); - n58->ReplaceInput(1, n50); - n58->ReplaceInput(2, n45); - - graph()->SetStart(n0); - graph()->SetEnd(n86); - - ComputeAndVerifySchedule(83); -} - - -TEST_F(SchedulerTest, BuildScheduleSimpleLoopWithCodeMotion) { - const Operator* op; - Unique<HeapObject> unique_constant = - Unique<HeapObject>::CreateImmovable(factory()->undefined_value()); - - // Manually transcripted code for: - // function turbo_fan_test(a, b, c) { - // while (a < b) { - // a += b + c; - // } - // return a; - // } - Node* nil = graph()->NewNode(common()->Dead()); - op = common()->End(); - Node* n34 = graph()->NewNode(op, nil); - USE(n34); - op = common()->Return(); - Node* n32 = graph()->NewNode(op, nil, nil, nil); - USE(n32); - op = common()->Phi(kMachAnyTagged, 2); - Node* n14 = graph()->NewNode(op, nil, nil, nil); - USE(n14); - op = js()->LessThan(LanguageMode::SLOPPY); - Node* n17 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil); - USE(n17); - op = common()->IfFalse(); - Node* n23 = graph()->NewNode(op, nil); - USE(n23); - op = common()->Parameter(1); - Node* n2 = graph()->NewNode(op, nil); - USE(n2); - op = js()->Add(LanguageMode::SLOPPY); - Node* n29 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n29); - op = common()->Loop(2); - Node* n13 = graph()->NewNode(op, nil, nil); - USE(n13); - op = common()->Parameter(2); - Node* n3 = graph()->NewNode(op, nil); - USE(n3); - op = common()->Parameter(4); - Node* n6 = graph()->NewNode(op, nil); - USE(n6); - op = common()->FrameState(JS_FRAME, BailoutId(-1), - OutputFrameStateCombine::Ignore()); - Node* n12 = graph()->NewNode(op, nil, nil, nil, nil, nil); - USE(n12); - op = common()->EffectPhi(2); - Node* n15 = graph()->NewNode(op, nil, nil, nil); - USE(n15); - op = common()->Branch(); - Node* n20 = graph()->NewNode(op, nil, nil); - USE(n20); - op = common()->Start(3); - Node* n0 = graph()->NewNode(op); - USE(n0); - op = js()->Add(LanguageMode::SLOPPY); - Node* n27 = graph()->NewNode(op, nil, nil, nil, nil, nil, nil, nil); - USE(n27); - op = common()->IfSuccess(); - Node* n28 = graph()->NewNode(op, nil); - USE(n28); - op = common()->IfSuccess(); - Node* n9 = graph()->NewNode(op, nil); - USE(n9); - op = common()->IfSuccess(); - Node* n30 = graph()->NewNode(op, nil); - USE(n30); - op = common()->StateValues(0); - Node* n10 = graph()->NewNode(op); - USE(n10); - op = common()->NumberConstant(0); - Node* n11 = graph()->NewNode(op); - USE(n11); - op = common()->HeapConstant(unique_constant); - Node* n5 = graph()->NewNode(op); - USE(n5); - op = js()->StackCheck(); - Node* n8 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n8); - op = js()->ToBoolean(); - Node* n19 = graph()->NewNode(op, nil, nil); - USE(n19); - op = common()->IfSuccess(); - Node* n18 = graph()->NewNode(op, nil); - USE(n18); - op = common()->Parameter(3); - Node* n4 = graph()->NewNode(op, nil); - USE(n4); - op = js()->StackCheck(); - Node* n25 = graph()->NewNode(op, nil, nil, nil, nil); - USE(n25); - op = common()->IfSuccess(); - Node* n26 = graph()->NewNode(op, nil); - USE(n26); - op = common()->IfTrue(); - Node* n21 = graph()->NewNode(op, nil); - USE(n21); - n34->ReplaceInput(0, n32); - n32->ReplaceInput(0, n14); - n32->ReplaceInput(1, n17); - n32->ReplaceInput(2, n23); - n14->ReplaceInput(0, n2); - n14->ReplaceInput(1, n29); - n14->ReplaceInput(2, n13); - n17->ReplaceInput(0, n14); - n17->ReplaceInput(1, n3); - n17->ReplaceInput(2, n6); - n17->ReplaceInput(3, n12); - n17->ReplaceInput(4, n15); - n17->ReplaceInput(5, n13); - n23->ReplaceInput(0, n20); - n2->ReplaceInput(0, n0); - n29->ReplaceInput(0, n14); - n29->ReplaceInput(1, n27); - n29->ReplaceInput(2, n6); - n29->ReplaceInput(3, n12); - n29->ReplaceInput(4, n12); - n29->ReplaceInput(5, n27); - n29->ReplaceInput(6, n28); - n13->ReplaceInput(0, n9); - n13->ReplaceInput(1, n30); - n3->ReplaceInput(0, n0); - n6->ReplaceInput(0, n0); - n12->ReplaceInput(0, n10); - n12->ReplaceInput(1, n10); - n12->ReplaceInput(2, n10); - n12->ReplaceInput(3, n11); - n12->ReplaceInput(4, n5); - n15->ReplaceInput(0, n8); - n15->ReplaceInput(1, n29); - n15->ReplaceInput(2, n13); - n20->ReplaceInput(0, n19); - n20->ReplaceInput(1, n18); - n27->ReplaceInput(0, n3); - n27->ReplaceInput(1, n4); - n27->ReplaceInput(2, n6); - n27->ReplaceInput(3, n12); - n27->ReplaceInput(4, n12); - n27->ReplaceInput(5, n25); - n27->ReplaceInput(6, n26); - n28->ReplaceInput(0, n27); - n9->ReplaceInput(0, n8); - n30->ReplaceInput(0, n29); - n8->ReplaceInput(0, n6); - n8->ReplaceInput(1, n12); - n8->ReplaceInput(2, n0); - n8->ReplaceInput(3, n0); - n19->ReplaceInput(0, n17); - n19->ReplaceInput(1, n6); - n18->ReplaceInput(0, n17); - n4->ReplaceInput(0, n0); - n25->ReplaceInput(0, n6); - n25->ReplaceInput(1, n12); - n25->ReplaceInput(2, n17); - n25->ReplaceInput(3, n21); - n26->ReplaceInput(0, n25); - n21->ReplaceInput(0, n20); - - graph()->SetStart(n0); - graph()->SetEnd(n34); - - ComputeAndVerifySchedule(30); -} - - namespace { Node* CreateDiamond(Graph* graph, CommonOperatorBuilder* common, Node* cond) { @@ -2025,7 +697,7 @@ TARGET_TEST_F(SchedulerTest, FloatingDiamond1) { Node* p0 = graph()->NewNode(common()->Parameter(0), start); Node* d1 = CreateDiamond(graph(), common(), p0); Node* ret = graph()->NewNode(common()->Return(), d1, start, start); - Node* end = graph()->NewNode(common()->End(), ret, start); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2043,7 +715,7 @@ TARGET_TEST_F(SchedulerTest, FloatingDiamond2) { Node* d2 = CreateDiamond(graph(), common(), p1); Node* add = graph()->NewNode(&kIntAdd, d1, d2); Node* ret = graph()->NewNode(common()->Return(), add, start, start); - Node* end = graph()->NewNode(common()->End(), ret, start); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2062,7 +734,7 @@ TARGET_TEST_F(SchedulerTest, FloatingDiamond3) { Node* add = graph()->NewNode(&kIntAdd, d1, d2); Node* d3 = CreateDiamond(graph(), common(), add); Node* ret = graph()->NewNode(common()->Return(), d3, start, start); - Node* end = graph()->NewNode(common()->End(), ret, start); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2099,7 +771,7 @@ TARGET_TEST_F(SchedulerTest, NestedFloatingDiamonds) { Node* ephi1 = graph()->NewNode(common()->EffectPhi(2), start, map, m); Node* ret = graph()->NewNode(common()->Return(), phi, ephi1, start); - Node* end = graph()->NewNode(common()->End(), ret, start); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2143,7 +815,7 @@ TARGET_TEST_F(SchedulerTest, NestedFloatingDiamondWithChain) { Node* add = graph()->NewNode(&kIntAdd, phiA2, phiB2); Node* ret = graph()->NewNode(common()->Return(), add, start, start); - Node* end = graph()->NewNode(common()->End(), ret, start); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2177,7 +849,7 @@ TARGET_TEST_F(SchedulerTest, NestedFloatingDiamondWithLoop) { Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), fv, ind, m); Node* ret = graph()->NewNode(common()->Return(), phi, start, start); - Node* end = graph()->NewNode(common()->End(), ret, start); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2210,7 +882,7 @@ TARGET_TEST_F(SchedulerTest, LoopedFloatingDiamond1) { ind->ReplaceInput(1, phi1); // close induction variable. Node* ret = graph()->NewNode(common()->Return(), ind, start, f); - Node* end = graph()->NewNode(common()->End(), ret, f); + Node* end = graph()->NewNode(common()->End(2), ret, f); graph()->SetEnd(end); @@ -2244,7 +916,7 @@ TARGET_TEST_F(SchedulerTest, LoopedFloatingDiamond2) { ind->ReplaceInput(1, add); // close induction variable. Node* ret = graph()->NewNode(common()->Return(), ind, start, f); - Node* end = graph()->NewNode(common()->End(), ret, f); + Node* end = graph()->NewNode(common()->End(2), ret, f); graph()->SetEnd(end); @@ -2290,7 +962,7 @@ TARGET_TEST_F(SchedulerTest, LoopedFloatingDiamond3) { ind->ReplaceInput(1, add); // close induction variable. Node* ret = graph()->NewNode(common()->Return(), ind, start, f); - Node* end = graph()->NewNode(common()->End(), ret, f); + Node* end = graph()->NewNode(common()->End(2), ret, f); graph()->SetEnd(end); @@ -2324,7 +996,7 @@ TARGET_TEST_F(SchedulerTest, PhisPushedDownToDifferentBranches) { graph()->NewNode(common()->Phi(kMachAnyTagged, 2), phi, phi2, m2); Node* ret = graph()->NewNode(common()->Return(), phi3, start, start); - Node* end = graph()->NewNode(common()->End(), ret, start); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2345,7 +1017,7 @@ TARGET_TEST_F(SchedulerTest, BranchHintTrue) { Node* m = graph()->NewNode(common()->Merge(2), t, f); Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), tv, fv, m); Node* ret = graph()->NewNode(common()->Return(), phi, start, start); - Node* end = graph()->NewNode(common()->End(), ret, start); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2369,7 +1041,7 @@ TARGET_TEST_F(SchedulerTest, BranchHintFalse) { Node* m = graph()->NewNode(common()->Merge(2), t, f); Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), tv, fv, m); Node* ret = graph()->NewNode(common()->Return(), phi, start, start); - Node* end = graph()->NewNode(common()->End(), ret, start); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2387,15 +1059,17 @@ TARGET_TEST_F(SchedulerTest, CallException) { Node* p0 = graph()->NewNode(common()->Parameter(0), start); Node* c1 = graph()->NewNode(&kMockCall, start); Node* ok1 = graph()->NewNode(common()->IfSuccess(), c1); - Node* ex1 = graph()->NewNode(common()->IfException(), c1); + Node* ex1 = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), c1, c1); Node* c2 = graph()->NewNode(&kMockCall, ok1); Node* ok2 = graph()->NewNode(common()->IfSuccess(), c2); - Node* ex2 = graph()->NewNode(common()->IfException(), c2); + Node* ex2 = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), c2, c2); Node* hdl = graph()->NewNode(common()->Merge(2), ex1, ex2); Node* m = graph()->NewNode(common()->Merge(2), ok2, hdl); Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), c2, p0, m); Node* ret = graph()->NewNode(common()->Return(), phi, start, m); - Node* end = graph()->NewNode(common()->End(), ret); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2414,7 +1088,7 @@ TARGET_TEST_F(SchedulerTest, TailCall) { Node* p0 = graph()->NewNode(common()->Parameter(0), start); Node* call = graph()->NewNode(&kMockTailCall, p0, start, start); - Node* end = graph()->NewNode(common()->End(), call); + Node* end = graph()->NewNode(common()->End(1), call); graph()->SetEnd(end); @@ -2437,7 +1111,7 @@ TARGET_TEST_F(SchedulerTest, Switch) { Node* m = graph()->NewNode(common()->Merge(3), c0, c1, d); Node* phi = graph()->NewNode(common()->Phi(kMachInt32, 3), v0, v1, vd, m); Node* ret = graph()->NewNode(common()->Return(), phi, start, m); - Node* end = graph()->NewNode(common()->End(), ret); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2460,7 +1134,7 @@ TARGET_TEST_F(SchedulerTest, FloatingSwitch) { Node* m = graph()->NewNode(common()->Merge(3), c0, c1, d); Node* phi = graph()->NewNode(common()->Phi(kMachInt32, 3), v0, v1, vd, m); Node* ret = graph()->NewNode(common()->Return(), phi, start, start); - Node* end = graph()->NewNode(common()->End(), ret); + Node* end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); @@ -2480,7 +1154,7 @@ TARGET_TEST_F(SchedulerTest, Terminate) { Node* terminate = graph()->NewNode(common()->Terminate(), effect, loop); effect->ReplaceInput(1, terminate); - Node* end = graph()->NewNode(common()->End(), terminate); + Node* end = graph()->NewNode(common()->End(1), terminate); graph()->SetEnd(end); diff --git a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc index a5dad5a415..07728913b1 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc @@ -54,7 +54,6 @@ const PureOperator kPureOperators[] = { PURE(StringEqual, Operator::kCommutative, 2), PURE(StringLessThan, Operator::kNoProperties, 2), PURE(StringLessThanOrEqual, Operator::kNoProperties, 2), - PURE(StringAdd, Operator::kNoProperties, 2), PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1), PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1), PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1), 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 5ac1f8e796..449299bb1d 100644 --- a/deps/v8/test/unittests/compiler/tail-call-optimization-unittest.cc +++ b/deps/v8/test/unittests/compiler/tail-call-optimization-unittest.cc @@ -33,7 +33,7 @@ TEST_F(TailCallOptimizationTest, CallCodeObject0) { CallDescriptor::kCallCodeObject, kMachAnyTagged, LinkageLocation(0), new (zone()) MachineSignature(1, 1, kMachineSignature), new (zone()) LocationSignature(1, 1, kLocationSignature), 0, - Operator::kNoProperties, 0, CallDescriptor::kNoFlags); + Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags); Node* p0 = Parameter(0); Node* p1 = Parameter(1); Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, @@ -53,15 +53,16 @@ TEST_F(TailCallOptimizationTest, CallCodeObject1) { CallDescriptor::kCallCodeObject, kMachAnyTagged, LinkageLocation(0), new (zone()) MachineSignature(1, 1, kMachineSignature), new (zone()) LocationSignature(1, 1, kLocationSignature), 0, - Operator::kNoProperties, 0, CallDescriptor::kSupportsTailCalls); + Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls); Node* p0 = Parameter(0); Node* p1 = Parameter(1); Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, graph()->start(), graph()->start()); Node* if_success = graph()->NewNode(common()->IfSuccess(), call); - Node* if_exception = graph()->NewNode(common()->IfException(), call); + Node* if_exception = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), call, call); Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); - Node* end = graph()->NewNode(common()->End(), if_exception); + Node* end = graph()->NewNode(common()->End(1), if_exception); graph()->SetEnd(end); Reduction r = Reduce(ret); ASSERT_FALSE(r.Changed()); @@ -76,7 +77,7 @@ TEST_F(TailCallOptimizationTest, CallCodeObject2) { CallDescriptor::kCallCodeObject, kMachAnyTagged, LinkageLocation(0), new (zone()) MachineSignature(1, 1, kMachineSignature), new (zone()) LocationSignature(1, 1, kLocationSignature), 0, - Operator::kNoProperties, 0, CallDescriptor::kSupportsTailCalls); + Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls); Node* p0 = Parameter(0); Node* p1 = Parameter(1); Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, @@ -98,7 +99,7 @@ TEST_F(TailCallOptimizationTest, CallJSFunction0) { CallDescriptor::kCallJSFunction, kMachAnyTagged, LinkageLocation(0), new (zone()) MachineSignature(1, 1, kMachineSignature), new (zone()) LocationSignature(1, 1, kLocationSignature), 0, - Operator::kNoProperties, 0, CallDescriptor::kNoFlags); + Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags); Node* p0 = Parameter(0); Node* p1 = Parameter(1); Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, @@ -118,15 +119,16 @@ TEST_F(TailCallOptimizationTest, CallJSFunction1) { CallDescriptor::kCallJSFunction, kMachAnyTagged, LinkageLocation(0), new (zone()) MachineSignature(1, 1, kMachineSignature), new (zone()) LocationSignature(1, 1, kLocationSignature), 0, - Operator::kNoProperties, 0, CallDescriptor::kSupportsTailCalls); + Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls); Node* p0 = Parameter(0); Node* p1 = Parameter(1); Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, graph()->start(), graph()->start()); Node* if_success = graph()->NewNode(common()->IfSuccess(), call); - Node* if_exception = graph()->NewNode(common()->IfException(), call); + Node* if_exception = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), call, call); Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); - Node* end = graph()->NewNode(common()->End(), if_exception); + Node* end = graph()->NewNode(common()->End(1), if_exception); graph()->SetEnd(end); Reduction r = Reduce(ret); ASSERT_FALSE(r.Changed()); @@ -141,7 +143,7 @@ TEST_F(TailCallOptimizationTest, CallJSFunction2) { CallDescriptor::kCallJSFunction, kMachAnyTagged, LinkageLocation(0), new (zone()) MachineSignature(1, 1, kMachineSignature), new (zone()) LocationSignature(1, 1, kLocationSignature), 0, - Operator::kNoProperties, 0, CallDescriptor::kSupportsTailCalls); + Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls); Node* p0 = Parameter(0); Node* p1 = Parameter(1); Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, diff --git a/deps/v8/test/unittests/counters-unittest.cc b/deps/v8/test/unittests/counters-unittest.cc index dd60a0d9c1..822a5c552e 100644 --- a/deps/v8/test/unittests/counters-unittest.cc +++ b/deps/v8/test/unittests/counters-unittest.cc @@ -49,7 +49,7 @@ TEST_F(AggregatedMemoryHistogramTest, OneSample1) { FLAG_histogram_interval = 10; AddSample(10, 1000); AddSample(20, 1000); - EXPECT_EQ(1, samples()->size()); + EXPECT_EQ(1U, samples()->size()); EXPECT_EQ(1000, (*samples())[0]); } @@ -58,7 +58,7 @@ TEST_F(AggregatedMemoryHistogramTest, OneSample2) { FLAG_histogram_interval = 10; AddSample(10, 500); AddSample(20, 1000); - EXPECT_EQ(1, samples()->size()); + EXPECT_EQ(1U, samples()->size()); EXPECT_EQ(750, (*samples())[0]); } @@ -69,7 +69,7 @@ TEST_F(AggregatedMemoryHistogramTest, OneSample3) { AddSample(15, 500); AddSample(15, 1000); AddSample(20, 1000); - EXPECT_EQ(1, samples()->size()); + EXPECT_EQ(1U, samples()->size()); EXPECT_EQ(750, (*samples())[0]); } @@ -79,7 +79,7 @@ TEST_F(AggregatedMemoryHistogramTest, OneSample4) { AddSample(10, 500); AddSample(15, 750); AddSample(20, 1000); - EXPECT_EQ(1, samples()->size()); + EXPECT_EQ(1U, samples()->size()); EXPECT_EQ(750, (*samples())[0]); } @@ -88,7 +88,7 @@ TEST_F(AggregatedMemoryHistogramTest, TwoSamples1) { FLAG_histogram_interval = 10; AddSample(10, 1000); AddSample(30, 1000); - EXPECT_EQ(2, samples()->size()); + EXPECT_EQ(2U, samples()->size()); EXPECT_EQ(1000, (*samples())[0]); EXPECT_EQ(1000, (*samples())[1]); } @@ -99,7 +99,7 @@ TEST_F(AggregatedMemoryHistogramTest, TwoSamples2) { AddSample(10, 1000); AddSample(20, 1000); AddSample(30, 1000); - EXPECT_EQ(2, samples()->size()); + EXPECT_EQ(2U, samples()->size()); EXPECT_EQ(1000, (*samples())[0]); EXPECT_EQ(1000, (*samples())[1]); } @@ -111,7 +111,7 @@ TEST_F(AggregatedMemoryHistogramTest, TwoSamples3) { AddSample(20, 1000); AddSample(20, 500); AddSample(30, 500); - EXPECT_EQ(2, samples()->size()); + EXPECT_EQ(2U, samples()->size()); EXPECT_EQ(1000, (*samples())[0]); EXPECT_EQ(500, (*samples())[1]); } @@ -121,7 +121,7 @@ TEST_F(AggregatedMemoryHistogramTest, TwoSamples4) { FLAG_histogram_interval = 10; AddSample(10, 1000); AddSample(30, 0); - EXPECT_EQ(2, samples()->size()); + EXPECT_EQ(2U, samples()->size()); EXPECT_EQ(750, (*samples())[0]); EXPECT_EQ(250, (*samples())[1]); } @@ -131,7 +131,7 @@ TEST_F(AggregatedMemoryHistogramTest, TwoSamples5) { FLAG_histogram_interval = 10; AddSample(10, 0); AddSample(30, 1000); - EXPECT_EQ(2, samples()->size()); + EXPECT_EQ(2U, samples()->size()); EXPECT_EQ(250, (*samples())[0]); EXPECT_EQ(750, (*samples())[1]); } @@ -142,7 +142,7 @@ TEST_F(AggregatedMemoryHistogramTest, TwoSamples6) { AddSample(10, 0); AddSample(15, 1000); AddSample(30, 1000); - EXPECT_EQ(2, samples()->size()); + EXPECT_EQ(2U, samples()->size()); EXPECT_EQ((500 + 1000) / 2, (*samples())[0]); EXPECT_EQ(1000, (*samples())[1]); } @@ -154,7 +154,7 @@ TEST_F(AggregatedMemoryHistogramTest, TwoSamples7) { AddSample(15, 1000); AddSample(25, 0); AddSample(30, 1000); - EXPECT_EQ(2, samples()->size()); + EXPECT_EQ(2U, samples()->size()); EXPECT_EQ((500 + 750) / 2, (*samples())[0]); EXPECT_EQ((250 + 500) / 2, (*samples())[1]); } @@ -166,7 +166,7 @@ TEST_F(AggregatedMemoryHistogramTest, TwoSamples8) { AddSample(15, 0); AddSample(25, 1000); AddSample(30, 0); - EXPECT_EQ(2, samples()->size()); + EXPECT_EQ(2U, samples()->size()); EXPECT_EQ((500 + 250) / 2, (*samples())[0]); EXPECT_EQ((750 + 500) / 2, (*samples())[1]); } @@ -177,7 +177,7 @@ TEST_F(AggregatedMemoryHistogramTest, ManySamples1) { const int kMaxSamples = 1000; AddSample(0, 0); AddSample(10 * kMaxSamples, 10 * kMaxSamples); - EXPECT_EQ(kMaxSamples, samples()->size()); + EXPECT_EQ(static_cast<unsigned>(kMaxSamples), samples()->size()); for (int i = 0; i < kMaxSamples; i++) { EXPECT_EQ(i * 10 + 5, (*samples())[i]); } @@ -189,7 +189,7 @@ TEST_F(AggregatedMemoryHistogramTest, ManySamples2) { const int kMaxSamples = 1000; AddSample(0, 0); AddSample(10 * (2 * kMaxSamples), 10 * (2 * kMaxSamples)); - EXPECT_EQ(kMaxSamples, samples()->size()); + EXPECT_EQ(static_cast<unsigned>(kMaxSamples), samples()->size()); for (int i = 0; i < kMaxSamples; i++) { EXPECT_EQ(i * 10 + 5, (*samples())[i]); } diff --git a/deps/v8/test/unittests/heap/gc-idle-time-handler-unittest.cc b/deps/v8/test/unittests/heap/gc-idle-time-handler-unittest.cc index 54d3bd52bb..c75fde492e 100644 --- a/deps/v8/test/unittests/heap/gc-idle-time-handler-unittest.cc +++ b/deps/v8/test/unittests/heap/gc-idle-time-handler-unittest.cc @@ -25,7 +25,6 @@ class GCIdleTimeHandlerTest : public ::testing::Test { result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate; result.size_of_objects = kSizeOfObjects; result.incremental_marking_stopped = false; - result.can_start_incremental_marking = true; result.sweeping_in_progress = false; result.sweeping_completed = false; result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed; @@ -38,56 +37,6 @@ class GCIdleTimeHandlerTest : public ::testing::Test { return result; } - void TransitionToReduceMemoryMode( - const GCIdleTimeHandler::HeapState& heap_state) { - handler()->NotifyScavenge(); - EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); - double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; - int limit = GCIdleTimeHandler::kLongIdleNotificationsBeforeMutatorIsIdle; - bool incremental = !heap_state.incremental_marking_stopped || - heap_state.can_start_incremental_marking; - for (int i = 0; i < limit; i++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - if (incremental) { - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - } else { - EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); - } - } - handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); - } - - void TransitionToDoneMode(const GCIdleTimeHandler::HeapState& heap_state, - double idle_time_ms, - GCIdleTimeActionType expected) { - EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); - int limit = GCIdleTimeHandler::kMaxIdleMarkCompacts; - for (int i = 0; i < limit; i++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(expected, action.type); - EXPECT_TRUE(action.reduce_memory); - handler()->NotifyMarkCompact(); - handler()->NotifyIdleMarkCompact(); - } - handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(GCIdleTimeHandler::kDone, handler()->mode()); - } - - void TransitionToReduceLatencyMode( - const GCIdleTimeHandler::HeapState& heap_state) { - EXPECT_EQ(GCIdleTimeHandler::kDone, handler()->mode()); - int limit = GCIdleTimeHandler::kMarkCompactsBeforeMutatorIsActive; - double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; - for (int i = 0; i < limit; i++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DONE, action.type); - handler()->NotifyMarkCompact(); - } - handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); - } - static const size_t kSizeOfObjects = 100 * MB; static const size_t kMarkCompactSpeed = 200 * KB; static const size_t kMarkingSpeed = 200 * KB; @@ -219,6 +168,18 @@ TEST_F(GCIdleTimeHandlerTest, DoScavengeHighScavengeSpeed) { } +TEST_F(GCIdleTimeHandlerTest, DoNotScavengeSmallNewSpaceSize) { + GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); + heap_state.used_new_space_size = (MB / 2) - 1; + heap_state.scavenge_speed_in_bytes_per_ms = kNewSpaceCapacity; + int idle_time_ms = 16; + EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge( + idle_time_ms, heap_state.new_space_capacity, + heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms, + heap_state.new_space_allocation_throughput_in_bytes_per_ms)); +} + + TEST_F(GCIdleTimeHandlerTest, ShouldDoMarkCompact) { size_t idle_time_ms = GCIdleTimeHandler::kMaxScheduledIdleTime; EXPECT_TRUE(GCIdleTimeHandler::ShouldDoMarkCompact(idle_time_ms, 0, 0)); @@ -251,11 +212,8 @@ TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) { heap_state.contexts_disposed = 1; heap_state.incremental_marking_stopped = true; double idle_time_ms = 0; - for (int mode = 0; mode < 1; mode++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_NOTHING, action.type); - TransitionToReduceMemoryMode(heap_state); - } + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_NOTHING, action.type); } @@ -266,11 +224,8 @@ TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) { GCIdleTimeHandler::kHighContextDisposalRate - 1; heap_state.incremental_marking_stopped = true; double idle_time_ms = 0; - for (int mode = 0; mode < 1; mode++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_FULL_GC, action.type); - TransitionToReduceMemoryMode(heap_state); - } + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_FULL_GC, action.type); } @@ -280,42 +235,34 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) { heap_state.contexts_disposal_rate = 1.0; heap_state.incremental_marking_stopped = true; double idle_time_ms = 0; - for (int mode = 0; mode < 1; mode++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_FULL_GC, action.type); - TransitionToReduceMemoryMode(heap_state); - } + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_FULL_GC, action.type); } TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.contexts_disposed = 1; - heap_state.contexts_disposal_rate = 1.0; - heap_state.incremental_marking_stopped = true; + heap_state.contexts_disposal_rate = + GCIdleTimeHandler::kHighContextDisposalRate; size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; double idle_time_ms = static_cast<double>(heap_state.size_of_objects / speed - 1); - for (int mode = 0; mode < 1; mode++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - TransitionToReduceMemoryMode(heap_state); - } + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); } TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.contexts_disposed = 1; - heap_state.contexts_disposal_rate = 1.0; + heap_state.contexts_disposal_rate = + GCIdleTimeHandler::kHighContextDisposalRate; size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; double idle_time_ms = static_cast<double>(heap_state.size_of_objects / speed - 1); - for (int mode = 0; mode < 1; mode++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - TransitionToReduceMemoryMode(heap_state); - } + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); } @@ -323,197 +270,106 @@ TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms; double idle_time_ms = 10; - for (int mode = 0; mode < 1; mode++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_GT(speed * static_cast<size_t>(idle_time_ms), - static_cast<size_t>(action.parameter)); - EXPECT_LT(0, action.parameter); - TransitionToReduceMemoryMode(heap_state); - } + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); + EXPECT_GT(speed * static_cast<size_t>(idle_time_ms), + static_cast<size_t>(action.parameter)); + EXPECT_LT(0, action.parameter); } TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = true; size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms; double idle_time_ms = 10; - for (int mode = 0; mode < 1; mode++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_GT(speed * static_cast<size_t>(idle_time_ms), - static_cast<size_t>(action.parameter)); - EXPECT_LT(0, action.parameter); - TransitionToReduceMemoryMode(heap_state); - } + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); + EXPECT_GT(speed * static_cast<size_t>(idle_time_ms), + static_cast<size_t>(action.parameter)); + EXPECT_LT(0, action.parameter); } TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; double idle_time_ms = static_cast<double>(heap_state.size_of_objects / speed - 1); GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_NOTHING, action.type); - TransitionToReduceMemoryMode(heap_state); - action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); + EXPECT_EQ(DONE, action.type); } TEST_F(GCIdleTimeHandlerTest, FinalizeSweeping) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - for (int mode = 0; mode < 1; mode++) { - heap_state.sweeping_in_progress = true; - heap_state.sweeping_completed = true; - double idle_time_ms = 10.0; - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_FINALIZE_SWEEPING, action.type); - heap_state.sweeping_in_progress = false; - heap_state.sweeping_completed = false; - TransitionToReduceMemoryMode(heap_state); - } + heap_state.sweeping_in_progress = true; + heap_state.sweeping_completed = true; + double idle_time_ms = 10.0; + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_FINALIZE_SWEEPING, action.type); } TEST_F(GCIdleTimeHandlerTest, CannotFinalizeSweeping) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - for (int mode = 0; mode < 1; mode++) { - heap_state.sweeping_in_progress = true; - heap_state.sweeping_completed = false; - double idle_time_ms = 10.0; - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_NOTHING, action.type); - heap_state.sweeping_in_progress = false; - heap_state.sweeping_completed = false; - TransitionToReduceMemoryMode(heap_state); - } + heap_state.sweeping_in_progress = true; + heap_state.sweeping_completed = false; + double idle_time_ms = 10.0; + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_NOTHING, action.type); } TEST_F(GCIdleTimeHandlerTest, Scavenge) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); int idle_time_ms = 10; - for (int mode = 0; mode < 1; mode++) { - heap_state.used_new_space_size = - heap_state.new_space_capacity - - (kNewSpaceAllocationThroughput * idle_time_ms); - GCIdleTimeAction action = - handler()->Compute(static_cast<double>(idle_time_ms), heap_state); - EXPECT_EQ(DO_SCAVENGE, action.type); - heap_state.used_new_space_size = 0; - TransitionToReduceMemoryMode(heap_state); - } + heap_state.used_new_space_size = + heap_state.new_space_capacity - + (kNewSpaceAllocationThroughput * idle_time_ms); + GCIdleTimeAction action = + handler()->Compute(static_cast<double>(idle_time_ms), heap_state); + EXPECT_EQ(DO_SCAVENGE, action.type); + heap_state.used_new_space_size = 0; } TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); int idle_time_ms = 10; - heap_state.can_start_incremental_marking = false; - heap_state.incremental_marking_stopped = true; - for (int mode = 0; mode < 1; mode++) { - heap_state.used_new_space_size = - heap_state.new_space_capacity - - (kNewSpaceAllocationThroughput * idle_time_ms); - GCIdleTimeAction action = - handler()->Compute(static_cast<double>(idle_time_ms), heap_state); - EXPECT_EQ(DO_SCAVENGE, action.type); - heap_state.used_new_space_size = 0; - action = handler()->Compute(static_cast<double>(idle_time_ms), heap_state); - EXPECT_EQ(DO_NOTHING, action.type); - TransitionToReduceMemoryMode(heap_state); - } -} - - -TEST_F(GCIdleTimeHandlerTest, StopEventually1) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; - bool stopped = false; - for (int i = 0; i < kMaxNotifications && !stopped; i++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - if (action.type == DO_INCREMENTAL_MARKING || action.type == DO_FULL_GC) { - handler()->NotifyMarkCompact(); - handler()->NotifyIdleMarkCompact(); - } - if (action.type == DONE) stopped = true; - } - EXPECT_TRUE(stopped); -} - - -TEST_F(GCIdleTimeHandlerTest, StopEventually2) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; - double idle_time_ms = - static_cast<double>(heap_state.size_of_objects / speed + 1); - TransitionToReduceMemoryMode(heap_state); - TransitionToDoneMode(heap_state, idle_time_ms, DO_FULL_GC); - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + heap_state.used_new_space_size = + heap_state.new_space_capacity - + (kNewSpaceAllocationThroughput * idle_time_ms); + GCIdleTimeAction action = + handler()->Compute(static_cast<double>(idle_time_ms), heap_state); + EXPECT_EQ(DO_SCAVENGE, action.type); + heap_state.used_new_space_size = 0; + action = handler()->Compute(static_cast<double>(idle_time_ms), heap_state); EXPECT_EQ(DONE, action.type); } -TEST_F(GCIdleTimeHandlerTest, StopEventually3) { +TEST_F(GCIdleTimeHandlerTest, DoNotStartIncrementalMarking) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - double idle_time_ms = 10; - TransitionToReduceMemoryMode(heap_state); - TransitionToDoneMode(heap_state, idle_time_ms, DO_INCREMENTAL_MARKING); - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DONE, action.type); -} - - -TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop1) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; - double idle_time_ms = - static_cast<double>(heap_state.size_of_objects / speed + 1); - TransitionToReduceMemoryMode(heap_state); - TransitionToDoneMode(heap_state, idle_time_ms, DO_FULL_GC); + double idle_time_ms = 10.0; GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(DONE, action.type); - TransitionToReduceLatencyMode(heap_state); - heap_state.can_start_incremental_marking = true; - action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_FALSE(action.reduce_memory); - EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); } -TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop2) { +TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - double idle_time_ms = 10; - TransitionToReduceMemoryMode(heap_state); - TransitionToDoneMode(heap_state, idle_time_ms, DO_INCREMENTAL_MARKING); + double idle_time_ms = 10.0; GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(DONE, action.type); - TransitionToReduceLatencyMode(heap_state); - heap_state.can_start_incremental_marking = true; + heap_state.incremental_marking_stopped = false; action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_FALSE(action.reduce_memory); - EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); } @@ -529,7 +385,6 @@ TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) { TEST_F(GCIdleTimeHandlerTest, SmallIdleTimeNothingToDo) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; for (int i = 0; i < kMaxNotifications; i++) { GCIdleTimeAction action = handler()->Compute(10, heap_state); EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); @@ -537,105 +392,16 @@ TEST_F(GCIdleTimeHandlerTest, SmallIdleTimeNothingToDo) { } -TEST_F(GCIdleTimeHandlerTest, StayInReduceLatencyModeBecauseOfScavenges) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; - int limit = GCIdleTimeHandler::kLongIdleNotificationsBeforeMutatorIsIdle; - for (int i = 0; i < kMaxNotifications; i++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); - if ((i + 1) % limit == 0) handler()->NotifyScavenge(); - EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); - } -} - - -TEST_F(GCIdleTimeHandlerTest, StayInReduceLatencyModeBecauseOfMarkCompacts) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; - int limit = GCIdleTimeHandler::kLongIdleNotificationsBeforeMutatorIsIdle; - for (int i = 0; i < kMaxNotifications; i++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); - if ((i + 1) % limit == 0) handler()->NotifyMarkCompact(); - EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); - } -} - - -TEST_F(GCIdleTimeHandlerTest, ReduceMemoryToReduceLatency) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; - int limit = GCIdleTimeHandler::kMaxIdleMarkCompacts; - for (int idle_gc = 0; idle_gc < limit; idle_gc++) { - TransitionToReduceMemoryMode(heap_state); - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_TRUE(action.reduce_memory); - EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); - for (int i = 0; i < idle_gc; i++) { - action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_TRUE(action.reduce_memory); - // ReduceMemory mode should tolerate one mutator GC per idle GC. - handler()->NotifyScavenge(); - // Notify idle GC. - handler()->NotifyMarkCompact(); - handler()->NotifyIdleMarkCompact(); - } - // Transition to ReduceLatency mode after doing |idle_gc| idle GCs. - handler()->NotifyScavenge(); - action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_NOTHING, action.type); - EXPECT_FALSE(action.reduce_memory); - EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); - } -} - - -TEST_F(GCIdleTimeHandlerTest, ReduceMemoryToDone) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; - double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; - int limit = GCIdleTimeHandler::kMaxIdleMarkCompacts; - TransitionToReduceMemoryMode(heap_state); - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_TRUE(action.reduce_memory); - for (int i = 0; i < limit; i++) { - action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_TRUE(action.reduce_memory); - EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); - // ReduceMemory mode should tolerate one mutator GC per idle GC. - handler()->NotifyScavenge(); - // Notify idle GC. - handler()->NotifyMarkCompact(); - handler()->NotifyIdleMarkCompact(); - } - action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DONE, action.type); -} - - TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnSweeping) { // Regression test for crbug.com/489323. GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); // Simulate sweeping being in-progress but not complete. heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; heap_state.sweeping_in_progress = true; heap_state.sweeping_completed = false; double idle_time_ms = 10.0; - for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerMode; i++) { + for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimes; i++) { GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(DO_NOTHING, action.type); } @@ -651,34 +417,11 @@ TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) { // Simulate incremental marking stopped and not eligible to start. heap_state.incremental_marking_stopped = true; - heap_state.can_start_incremental_marking = false; double idle_time_ms = 10.0; - for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerMode; i++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_NOTHING, action.type); - } - // We should return DONE after not making progress for some time. + // We should return DONE if we cannot start incremental marking. GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(DONE, action.type); } - -TEST_F(GCIdleTimeHandlerTest, BackgroundReduceLatencyToReduceMemory) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = false; - heap_state.can_start_incremental_marking = true; - double idle_time_ms = GCIdleTimeHandler::kMinBackgroundIdleTime; - handler()->NotifyScavenge(); - EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); - int limit = - GCIdleTimeHandler::kBackgroundIdleNotificationsBeforeMutatorIsIdle; - for (int i = 0; i < limit; i++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - } - handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); -} - } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/heap/heap-unittest.cc b/deps/v8/test/unittests/heap/heap-unittest.cc new file mode 100644 index 0000000000..9492faf9f3 --- /dev/null +++ b/deps/v8/test/unittests/heap/heap-unittest.cc @@ -0,0 +1,48 @@ +// 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 <cmath> +#include <limits> + +#include "src/objects.h" +#include "src/objects-inl.h" + +#include "src/handles.h" +#include "src/handles-inl.h" + +#include "src/heap/heap.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8 { +namespace internal { + +double Round(double x) { + // Round to three digits. + return floor(x * 1000 + 0.5) / 1000; +} + + +void CheckEqualRounded(double expected, double actual) { + expected = Round(expected); + actual = Round(actual); + EXPECT_DOUBLE_EQ(expected, actual); +} + + +TEST(Heap, HeapGrowingFactor) { + CheckEqualRounded(Heap::kMaxHeapGrowingFactor, + Heap::HeapGrowingFactor(34, 1)); + CheckEqualRounded(3.553, Heap::HeapGrowingFactor(45, 1)); + CheckEqualRounded(2.830, Heap::HeapGrowingFactor(50, 1)); + CheckEqualRounded(1.478, Heap::HeapGrowingFactor(100, 1)); + CheckEqualRounded(1.193, Heap::HeapGrowingFactor(200, 1)); + CheckEqualRounded(1.121, Heap::HeapGrowingFactor(300, 1)); + CheckEqualRounded(Heap::HeapGrowingFactor(300, 1), + Heap::HeapGrowingFactor(600, 2)); + CheckEqualRounded(Heap::kMinHeapGrowingFactor, + Heap::HeapGrowingFactor(400, 1)); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/heap/memory-reducer-unittest.cc b/deps/v8/test/unittests/heap/memory-reducer-unittest.cc new file mode 100644 index 0000000000..3301d13b7e --- /dev/null +++ b/deps/v8/test/unittests/heap/memory-reducer-unittest.cc @@ -0,0 +1,331 @@ +// 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 <limits> + +#include "src/flags.h" +#include "src/heap/memory-reducer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8 { +namespace internal { + +MemoryReducer::State DoneState() { + return MemoryReducer::State(MemoryReducer::kDone, 0, 0.0, 1.0); +} + + +MemoryReducer::State WaitState(int started_gcs, double next_gc_start_ms) { + return MemoryReducer::State(MemoryReducer::kWait, started_gcs, + next_gc_start_ms, 1.0); +} + + +MemoryReducer::State RunState(int started_gcs, double next_gc_start_ms) { + return MemoryReducer::State(MemoryReducer::kRun, started_gcs, + next_gc_start_ms, 1.0); +} + + +MemoryReducer::Event MarkCompactEvent(double time_ms, + bool next_gc_likely_to_collect_more) { + MemoryReducer::Event event; + event.type = MemoryReducer::kMarkCompact; + event.time_ms = time_ms; + event.next_gc_likely_to_collect_more = next_gc_likely_to_collect_more; + return event; +} + + +MemoryReducer::Event MarkCompactEventGarbageLeft(double time_ms) { + return MarkCompactEvent(time_ms, true); +} + + +MemoryReducer::Event MarkCompactEventNoGarbageLeft(double time_ms) { + return MarkCompactEvent(time_ms, false); +} + + +MemoryReducer::Event TimerEvent(double time_ms, bool low_allocation_rate, + bool can_start_incremental_gc) { + MemoryReducer::Event event; + event.type = MemoryReducer::kTimer; + event.time_ms = time_ms; + event.low_allocation_rate = low_allocation_rate; + event.can_start_incremental_gc = can_start_incremental_gc; + return event; +} + + +MemoryReducer::Event TimerEventLowAllocationRate(double time_ms) { + return TimerEvent(time_ms, true, true); +} + + +MemoryReducer::Event TimerEventHighAllocationRate(double time_ms) { + return TimerEvent(time_ms, false, true); +} + + +MemoryReducer::Event TimerEventPendingGC(double time_ms) { + return TimerEvent(time_ms, true, false); +} + + +MemoryReducer::Event ContextDisposedEvent(double time_ms) { + MemoryReducer::Event event; + event.type = MemoryReducer::kContextDisposed; + event.time_ms = time_ms; + return event; +} + + +MemoryReducer::Event BackgroundIdleNotificationEvent( + double time_ms, bool can_start_incremental_gc = true) { + MemoryReducer::Event event; + event.type = MemoryReducer::kBackgroundIdleNotification; + event.time_ms = time_ms; + event.can_start_incremental_gc = can_start_incremental_gc; + return event; +} + + +TEST(MemoryReducer, FromDoneToDone) { + MemoryReducer::State state0(DoneState()), state1(DoneState()); + + state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(0)); + EXPECT_EQ(MemoryReducer::kDone, state1.action); + + state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(0)); + EXPECT_EQ(MemoryReducer::kDone, state1.action); + + state1 = MemoryReducer::Step(state0, TimerEventPendingGC(0)); + EXPECT_EQ(MemoryReducer::kDone, state1.action); + + state1 = MemoryReducer::Step(state0, BackgroundIdleNotificationEvent(0)); + EXPECT_EQ(MemoryReducer::kDone, state1.action); +} + + +TEST(MemoryReducer, FromDoneToWait) { + if (!FLAG_incremental_marking) return; + + MemoryReducer::State state0(DoneState()), state1(DoneState()); + + state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(MemoryReducer::kLongDelayMs + 2, state1.next_gc_start_ms); + EXPECT_EQ(0, state1.started_gcs); + EXPECT_EQ(2, state1.last_gc_time_ms); + + state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(MemoryReducer::kLongDelayMs + 2, state1.next_gc_start_ms); + EXPECT_EQ(0, state1.started_gcs); + EXPECT_EQ(2, state1.last_gc_time_ms); + + state1 = MemoryReducer::Step(state0, ContextDisposedEvent(0)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); + EXPECT_EQ(0, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); +} + + +TEST(MemoryReducer, FromWaitToWait) { + if (!FLAG_incremental_marking) return; + + MemoryReducer::State state0(WaitState(2, 1000.0)), state1(DoneState()); + + state1 = MemoryReducer::Step(state0, ContextDisposedEvent(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + + state1 = MemoryReducer::Step( + state0, TimerEventLowAllocationRate(state0.next_gc_start_ms - 1)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + + state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + + state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + + state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(2000, state1.last_gc_time_ms); + + state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(2000, state1.last_gc_time_ms); + + state1 = MemoryReducer::Step(state0, BackgroundIdleNotificationEvent(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs); + + state1 = + MemoryReducer::Step(state0, BackgroundIdleNotificationEvent(2000, false)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + + state0.last_gc_time_ms = 0; + state1 = MemoryReducer::Step( + state0, + TimerEventHighAllocationRate(MemoryReducer::kWatchdogDelayMs + 1)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(MemoryReducer::kWatchdogDelayMs + 1 + MemoryReducer::kLongDelayMs, + state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); + + state0.last_gc_time_ms = 1; + state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); + + state0.started_gcs = MemoryReducer::kMaxNumberOfGCs; + state1 = MemoryReducer::Step(state0, BackgroundIdleNotificationEvent(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); +} + + +TEST(MemoryReducer, FromWaitToRun) { + if (!FLAG_incremental_marking) return; + + MemoryReducer::State state0(WaitState(0, 1000.0)), state1(DoneState()); + + state1 = MemoryReducer::Step( + state0, TimerEventLowAllocationRate(state0.next_gc_start_ms + 1)); + EXPECT_EQ(MemoryReducer::kRun, state1.action); + EXPECT_EQ(0, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs); + + state1 = MemoryReducer::Step( + state0, + TimerEventHighAllocationRate(MemoryReducer::kWatchdogDelayMs + 2)); + EXPECT_EQ(MemoryReducer::kRun, state1.action); + EXPECT_EQ(0, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); +} + + +TEST(MemoryReducer, FromWaitToDone) { + if (!FLAG_incremental_marking) return; + + MemoryReducer::State state0(WaitState(2, 0.0)), state1(DoneState()); + + state0.started_gcs = MemoryReducer::kMaxNumberOfGCs; + + state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(2000)); + EXPECT_EQ(MemoryReducer::kDone, state1.action); + EXPECT_EQ(0, state1.next_gc_start_ms); + EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); + + state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); + EXPECT_EQ(MemoryReducer::kDone, state1.action); + EXPECT_EQ(0, state1.next_gc_start_ms); + EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); + + state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000)); + EXPECT_EQ(MemoryReducer::kDone, state1.action); + EXPECT_EQ(0, state1.next_gc_start_ms); + EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); +} + + +TEST(MemoryReducer, FromRunToRun) { + if (!FLAG_incremental_marking) return; + + MemoryReducer::State state0(RunState(1, 0.0)), state1(DoneState()); + + state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(2000)); + EXPECT_EQ(MemoryReducer::kRun, state1.action); + EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); + + state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); + EXPECT_EQ(MemoryReducer::kRun, state1.action); + EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); + + state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000)); + EXPECT_EQ(MemoryReducer::kRun, state1.action); + EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); + + state1 = MemoryReducer::Step(state0, ContextDisposedEvent(2000)); + EXPECT_EQ(MemoryReducer::kRun, state1.action); + EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); +} + + +TEST(MemoryReducer, FromRunToDone) { + if (!FLAG_incremental_marking) return; + + MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState()); + + state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000)); + EXPECT_EQ(MemoryReducer::kDone, state1.action); + EXPECT_EQ(0, state1.next_gc_start_ms); + EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); + EXPECT_EQ(2000, state1.last_gc_time_ms); + + state0.started_gcs = MemoryReducer::kMaxNumberOfGCs; + + state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000)); + EXPECT_EQ(MemoryReducer::kDone, state1.action); + EXPECT_EQ(0, state1.next_gc_start_ms); + EXPECT_EQ(2000, state1.last_gc_time_ms); +} + + +TEST(MemoryReducer, FromRunToWait) { + if (!FLAG_incremental_marking) return; + + MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState()); + + state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(2000, state1.last_gc_time_ms); + + state0.started_gcs = 1; + + state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000)); + EXPECT_EQ(MemoryReducer::kWait, state1.action); + EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms); + EXPECT_EQ(state0.started_gcs, state1.started_gcs); + EXPECT_EQ(2000, state1.last_gc_time_ms); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/libplatform/default-platform-unittest.cc b/deps/v8/test/unittests/libplatform/default-platform-unittest.cc index d2c160e558..814b27bc51 100644 --- a/deps/v8/test/unittests/libplatform/default-platform-unittest.cc +++ b/deps/v8/test/unittests/libplatform/default-platform-unittest.cc @@ -19,6 +19,17 @@ struct MockTask : public Task { MOCK_METHOD0(Die, void()); }; + +class DefaultPlatformWithMockTime : public DefaultPlatform { + public: + DefaultPlatformWithMockTime() : time_(0) {} + double MonotonicallyIncreasingTime() override { return time_; } + void IncreaseTime(double seconds) { time_ += seconds; } + + private: + double time_; +}; + } // namespace @@ -39,5 +50,82 @@ TEST(DefaultPlatformTest, PumpMessageLoop) { EXPECT_FALSE(platform.PumpMessageLoop(isolate)); } + +TEST(DefaultPlatformTest, PumpMessageLoopDelayed) { + InSequence s; + + int dummy; + Isolate* isolate = reinterpret_cast<Isolate*>(&dummy); + + DefaultPlatformWithMockTime platform; + EXPECT_FALSE(platform.PumpMessageLoop(isolate)); + + StrictMock<MockTask>* task1 = new StrictMock<MockTask>; + StrictMock<MockTask>* task2 = new StrictMock<MockTask>; + platform.CallDelayedOnForegroundThread(isolate, task2, 100); + platform.CallDelayedOnForegroundThread(isolate, task1, 10); + + EXPECT_FALSE(platform.PumpMessageLoop(isolate)); + + platform.IncreaseTime(11); + EXPECT_CALL(*task1, Run()); + EXPECT_CALL(*task1, Die()); + EXPECT_TRUE(platform.PumpMessageLoop(isolate)); + + EXPECT_FALSE(platform.PumpMessageLoop(isolate)); + + platform.IncreaseTime(90); + EXPECT_CALL(*task2, Run()); + EXPECT_CALL(*task2, Die()); + EXPECT_TRUE(platform.PumpMessageLoop(isolate)); +} + + +TEST(DefaultPlatformTest, PumpMessageLoopNoStarvation) { + InSequence s; + + int dummy; + Isolate* isolate = reinterpret_cast<Isolate*>(&dummy); + + DefaultPlatformWithMockTime platform; + EXPECT_FALSE(platform.PumpMessageLoop(isolate)); + + StrictMock<MockTask>* task1 = new StrictMock<MockTask>; + StrictMock<MockTask>* task2 = new StrictMock<MockTask>; + StrictMock<MockTask>* task3 = new StrictMock<MockTask>; + platform.CallOnForegroundThread(isolate, task1); + platform.CallDelayedOnForegroundThread(isolate, task2, 10); + platform.IncreaseTime(11); + + EXPECT_CALL(*task1, Run()); + EXPECT_CALL(*task1, Die()); + EXPECT_TRUE(platform.PumpMessageLoop(isolate)); + + platform.CallOnForegroundThread(isolate, task3); + + EXPECT_CALL(*task2, Run()); + EXPECT_CALL(*task2, Die()); + EXPECT_TRUE(platform.PumpMessageLoop(isolate)); + EXPECT_CALL(*task3, Run()); + EXPECT_CALL(*task3, Die()); + EXPECT_TRUE(platform.PumpMessageLoop(isolate)); +} + + +TEST(DefaultPlatformTest, PendingDelayedTasksAreDestroyedOnShutdown) { + InSequence s; + + int dummy; + Isolate* isolate = reinterpret_cast<Isolate*>(&dummy); + + { + DefaultPlatformWithMockTime platform; + StrictMock<MockTask>* task = new StrictMock<MockTask>; + platform.CallDelayedOnForegroundThread(isolate, task, 10); + EXPECT_CALL(*task, Die()); + } +} + + } // namespace platform } // namespace v8 diff --git a/deps/v8/test/unittests/unittests.gyp b/deps/v8/test/unittests/unittests.gyp index 7a298a9074..00658b3fda 100644 --- a/deps/v8/test/unittests/unittests.gyp +++ b/deps/v8/test/unittests/unittests.gyp @@ -44,10 +44,11 @@ 'compiler/compiler-test-utils.h', 'compiler/control-equivalence-unittest.cc', 'compiler/control-flow-optimizer-unittest.cc', - 'compiler/control-reducer-unittest.cc', + 'compiler/dead-code-elimination-unittest.cc', 'compiler/diamond-unittest.cc', 'compiler/graph-reducer-unittest.cc', 'compiler/graph-reducer-unittest.h', + 'compiler/graph-trimmer-unittest.cc', 'compiler/graph-unittest.cc', 'compiler/graph-unittest.h', 'compiler/instruction-selector-unittest.cc', @@ -88,6 +89,8 @@ 'libplatform/task-queue-unittest.cc', 'libplatform/worker-thread-unittest.cc', 'heap/gc-idle-time-handler-unittest.cc', + 'heap/memory-reducer-unittest.cc', + 'heap/heap-unittest.cc', 'run-all-unittests.cc', 'test-utils.h', 'test-utils.cc', |