Add SlabAllocator and tests
Bug: dawn:340
Change-Id: I6fa1948261e8e6f91324464dade3e9954bd833e5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15861
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/src/tests/unittests/PlacementAllocatedTests.cpp b/src/tests/unittests/PlacementAllocatedTests.cpp
new file mode 100644
index 0000000..d483d6e
--- /dev/null
+++ b/src/tests/unittests/PlacementAllocatedTests.cpp
@@ -0,0 +1,115 @@
+// Copyright 2020 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "common/PlacementAllocated.h"
+
+using namespace testing;
+
+namespace {
+
+ enum class DestructedClass {
+ Foo,
+ Bar,
+ };
+
+ class MockDestructor {
+ public:
+ MOCK_METHOD2(Call, void(void*, DestructedClass));
+ };
+
+ std::unique_ptr<StrictMock<MockDestructor>> mockDestructor;
+
+ class PlacementAllocatedTests : public Test {
+ void SetUp() override {
+ mockDestructor = std::make_unique<StrictMock<MockDestructor>>();
+ }
+
+ void TearDown() override {
+ mockDestructor = nullptr;
+ }
+ };
+
+ struct Foo : PlacementAllocated {
+ virtual ~Foo() {
+ mockDestructor->Call(this, DestructedClass::Foo);
+ }
+ };
+
+ struct Bar : Foo {
+ ~Bar() override {
+ mockDestructor->Call(this, DestructedClass::Bar);
+ }
+ };
+} // namespace
+
+// Test that deletion calls the destructor and does not free memory.
+TEST_F(PlacementAllocatedTests, DeletionDoesNotFreeMemory) {
+ void* ptr = malloc(sizeof(Foo));
+
+ Foo* foo = new (ptr) Foo();
+
+ EXPECT_CALL(*mockDestructor, Call(foo, DestructedClass::Foo));
+ delete foo;
+
+ // Touch the memory, this shouldn't crash.
+ static_assert(sizeof(Foo) >= sizeof(uint32_t), "");
+ *reinterpret_cast<uint32_t*>(foo) = 42;
+
+ free(ptr);
+}
+
+// Test that destructing an instance of a derived class calls the derived, then base destructor, and
+// does not free memory.
+TEST_F(PlacementAllocatedTests, DeletingDerivedClassCallsBaseDestructor) {
+ void* ptr = malloc(sizeof(Bar));
+
+ Bar* bar = new (ptr) Bar();
+
+ {
+ InSequence s;
+ EXPECT_CALL(*mockDestructor, Call(bar, DestructedClass::Bar));
+ EXPECT_CALL(*mockDestructor, Call(bar, DestructedClass::Foo));
+ delete bar;
+ }
+
+ // Touch the memory, this shouldn't crash.
+ static_assert(sizeof(Bar) >= sizeof(uint32_t), "");
+ *reinterpret_cast<uint32_t*>(bar) = 42;
+
+ free(ptr);
+}
+
+// Test that destructing an instance of a base class calls the derived, then base destructor, and
+// does not free memory.
+TEST_F(PlacementAllocatedTests, DeletingBaseClassCallsDerivedDestructor) {
+ void* ptr = malloc(sizeof(Bar));
+
+ Foo* foo = new (ptr) Bar();
+
+ {
+ InSequence s;
+ EXPECT_CALL(*mockDestructor, Call(foo, DestructedClass::Bar));
+ EXPECT_CALL(*mockDestructor, Call(foo, DestructedClass::Foo));
+ delete foo;
+ }
+
+ // Touch the memory, this shouldn't crash.
+ static_assert(sizeof(Bar) >= sizeof(uint32_t), "");
+ *reinterpret_cast<uint32_t*>(foo) = 42;
+
+ free(ptr);
+}