// Copyright 2021 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/frame.h" #include "src/codegen/aligned-slot-allocator.h" #include "testing/gmock/include/gmock/gmock.h" namespace v8 { namespace internal { namespace compiler { namespace { constexpr int kSlotSize = AlignedSlotAllocator::kSlotSize; constexpr int kFixed1 = 1; constexpr int kFixed3 = 3; } // namespace class FrameTest : public ::testing::Test { public: FrameTest() = default; ~FrameTest() override = default; }; TEST_F(FrameTest, Constructor) { Frame frame(kFixed3); EXPECT_EQ(kFixed3, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(0, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); } TEST_F(FrameTest, ReserveSpillSlots) { Frame frame(kFixed3); constexpr int kReserve2 = 2; frame.ReserveSpillSlots(kReserve2); EXPECT_EQ(kFixed3 + kReserve2, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(kReserve2, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); } TEST_F(FrameTest, EnsureReturnSlots) { Frame frame(kFixed3); constexpr int kReturn3 = 3; constexpr int kReturn5 = 5; constexpr int kReturn2 = 2; frame.EnsureReturnSlots(kReturn3); EXPECT_EQ(kFixed3 + kReturn3, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(0, frame.GetSpillSlotCount()); EXPECT_EQ(kReturn3, frame.GetReturnSlotCount()); // Returns should grow by 2 slots. frame.EnsureReturnSlots(kReturn5); EXPECT_EQ(kFixed3 + kReturn5, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(0, frame.GetSpillSlotCount()); EXPECT_EQ(kReturn5, frame.GetReturnSlotCount()); // Returns shouldn't grow. frame.EnsureReturnSlots(kReturn2); EXPECT_EQ(kFixed3 + kReturn5, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(0, frame.GetSpillSlotCount()); EXPECT_EQ(kReturn5, frame.GetReturnSlotCount()); } TEST_F(FrameTest, AllocateSavedCalleeRegisterSlots) { Frame frame(kFixed3); constexpr int kFirstSlots = 2; constexpr int kSecondSlots = 3; frame.AllocateSavedCalleeRegisterSlots(kFirstSlots); EXPECT_EQ(kFixed3 + kFirstSlots, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(0, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); frame.AllocateSavedCalleeRegisterSlots(kSecondSlots); EXPECT_EQ(kFixed3 + kFirstSlots + kSecondSlots, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(0, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); } TEST_F(FrameTest, AlignSavedCalleeRegisterSlots) { Frame frame(kFixed3); constexpr int kSlots = 2; // An even number leaves the slots misaligned. frame.AllocateSavedCalleeRegisterSlots(kSlots); // Align, which should add 1 padding slot. frame.AlignSavedCalleeRegisterSlots(2 * kSlotSize); EXPECT_EQ(kFixed3 + kSlots + 1, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(1, frame.GetSpillSlotCount()); // padding EXPECT_EQ(0, frame.GetReturnSlotCount()); // Align again, which should not add a padding slot. frame.AlignSavedCalleeRegisterSlots(2 * kSlotSize); EXPECT_EQ(kFixed3 + kSlots + 1, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(1, frame.GetSpillSlotCount()); // padding EXPECT_EQ(0, frame.GetReturnSlotCount()); } TEST_F(FrameTest, AllocateSpillSlotAligned) { Frame frame(kFixed1); // Allocate a quad slot, which must add 3 padding slots. Frame returns the // last index of the 4 slot allocation. int end = kFixed1 + 3 + 4; int slot = kFixed1 + 3 + 4 - 1; EXPECT_EQ(slot, frame.AllocateSpillSlot(4 * kSlotSize, 4 * kSlotSize)); EXPECT_EQ(end, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed1, frame.GetFixedSlotCount()); EXPECT_EQ(end - kFixed1, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); // Allocate a double slot, which should leave the first padding slot and // take the last two slots of padding. slot = kFixed1 + 1 + 2 - 1; EXPECT_EQ(slot, frame.AllocateSpillSlot(2 * kSlotSize, 2 * kSlotSize)); EXPECT_EQ(end, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed1, frame.GetFixedSlotCount()); EXPECT_EQ(end - kFixed1, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); // Allocate a single slot, which should take the last padding slot. slot = kFixed1; EXPECT_EQ(slot, frame.AllocateSpillSlot(kSlotSize, kSlotSize)); EXPECT_EQ(end, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed1, frame.GetFixedSlotCount()); EXPECT_EQ(end - kFixed1, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); } TEST_F(FrameTest, AllocateSpillSlotAlignedWithReturns) { Frame frame(kFixed3); constexpr int kReturn3 = 3; constexpr int kReturn5 = 5; frame.EnsureReturnSlots(kReturn3); // Allocate a double slot, which must add 1 padding slot. This should occupy // slots 4 and 5, and AllocateSpillSlot returns the last slot index. EXPECT_EQ(kFixed3 + 2, frame.AllocateSpillSlot(2 * kSlotSize, 2 * kSlotSize)); EXPECT_EQ(kFixed3 + kReturn3 + 3, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(3, frame.GetSpillSlotCount()); EXPECT_EQ(kReturn3, frame.GetReturnSlotCount()); frame.EnsureReturnSlots(kReturn5); // Allocate a single slot, which should take the padding slot. EXPECT_EQ(kFixed3, frame.AllocateSpillSlot(kSlotSize, kSlotSize)); EXPECT_EQ(kFixed3 + kReturn5 + 3, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(3, frame.GetSpillSlotCount()); EXPECT_EQ(kReturn5, frame.GetReturnSlotCount()); } TEST_F(FrameTest, AllocateSpillSlotAndEndSpillArea) { Frame frame(kFixed3); // Allocate a double slot, which must add 1 padding slot. EXPECT_EQ(kFixed3 + 2, frame.AllocateSpillSlot(2 * kSlotSize, 2 * kSlotSize)); // Allocate an unaligned double slot. This should be at the end. EXPECT_EQ(kFixed3 + 4, frame.AllocateSpillSlot(2 * kSlotSize)); EXPECT_EQ(kFixed3 + 5, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(5, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); // Allocate a single slot. This should not be the padding slot, since that // area has been closed by the unaligned allocation. EXPECT_EQ(kFixed3 + 5, frame.AllocateSpillSlot(kSlotSize, kSlotSize)); EXPECT_EQ(kFixed3 + 6, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(6, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); } TEST_F(FrameTest, AllocateSpillSlotOverAligned) { Frame frame(kFixed1); // Allocate a 4-aligned double slot, which must add 3 padding slots. This // also terminates the slot area. Returns the starting slot in this case. EXPECT_EQ(kFixed1 + 4, frame.AllocateSpillSlot(2 * kSlotSize, 4 * kSlotSize)); EXPECT_EQ(kFixed1 + 5, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed1, frame.GetFixedSlotCount()); EXPECT_EQ(5, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); // Allocate a single slot. This should not use any padding slot. EXPECT_EQ(kFixed1 + 5, frame.AllocateSpillSlot(kSlotSize, kSlotSize)); EXPECT_EQ(kFixed1 + 6, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed1, frame.GetFixedSlotCount()); EXPECT_EQ(6, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); } TEST_F(FrameTest, AllocateSpillSlotUnderAligned) { Frame frame(kFixed1); // Allocate a 1-aligned double slot. This also terminates the slot area. EXPECT_EQ(kFixed1 + 1, frame.AllocateSpillSlot(2 * kSlotSize, kSlotSize)); EXPECT_EQ(kFixed1 + 2, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed1, frame.GetFixedSlotCount()); EXPECT_EQ(2, frame.GetSpillSlotCount()); EXPECT_EQ(0, frame.GetReturnSlotCount()); } TEST_F(FrameTest, AlignFrame) { Frame frame(kFixed3); constexpr int kReturn3 = 3; frame.EnsureReturnSlots(kReturn3); // Allocate two single slots, which leaves spill slots not 2-aligned. EXPECT_EQ(kFixed3, frame.AllocateSpillSlot(kSlotSize, kSlotSize)); EXPECT_EQ(kFixed3 + 1, frame.AllocateSpillSlot(kSlotSize, kSlotSize)); // Align to 2 slots. This should pad the spill and return slot areas. frame.AlignFrame(2 * kSlotSize); EXPECT_EQ(kFixed3 + 3 + kReturn3 + 1, frame.GetTotalFrameSlotCount()); EXPECT_EQ(kFixed3, frame.GetFixedSlotCount()); EXPECT_EQ(3, frame.GetSpillSlotCount()); EXPECT_EQ(kReturn3 + 1, frame.GetReturnSlotCount()); } } // namespace compiler } // namespace internal } // namespace v8