Commit 2948696a authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

gc: Add public platform interface and provide test implementation

Adds a public/platform.h that is required to be implemented by
embedders to provide certain features.

Page-level allocation goes through this interface. This is used to
allow e.g.  Blink to provide their own OOM callbacks and page tags.

Provide a basic implementation of the PageAllocator using base
primitives that can be used for testing.

Bug: 1056170
Change-Id: Ib25269d6f8ed793d2b111dd750cef9d4a6d772a1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2083022Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarAnton Bikineev <bikineev@chromium.org>
Reviewed-by: default avatarOmer Katz <omerkatz@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747208}
parent 2274746a
...@@ -2,12 +2,14 @@ ...@@ -2,12 +2,14 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import("//build/config/allocator.gni")
import("//testing/test.gni") import("//testing/test.gni")
component("gc") { component("gc") {
sources = [ sources = [
"core/gc.cc", "core/gc.cc",
"core/gc_export.h", "core/gc_export.h",
"public/platform.h",
] ]
deps = [] deps = []
...@@ -15,13 +17,37 @@ component("gc") { ...@@ -15,13 +17,37 @@ component("gc") {
defines = [ "GC_IMPLEMENTATION=1" ] defines = [ "GC_IMPLEMENTATION=1" ]
} }
source_set("test_support") {
testonly = true
sources = []
if (use_partition_alloc) {
sources += [
"test/base_allocator.cc",
"test/base_allocator.h",
]
}
deps = [
":gc",
"//base",
]
}
source_set("unit_tests") { source_set("unit_tests") {
testonly = true testonly = true
sources = [] sources = []
if (use_partition_alloc) {
sources += [ "test/base_allocator_test.cc" ]
}
deps = [ deps = [
":gc", ":gc",
":test_support",
"//base",
"//testing/gtest", "//testing/gtest",
] ]
} }
......
...@@ -2,4 +2,9 @@ ...@@ -2,4 +2,9 @@
Oilpan is an open-source garbage collection library for C++ in Chromium. Oilpan is an open-source garbage collection library for C++ in Chromium.
Directory structure:
- `public`: Users should depend on interfaces in the `gc` namespace exposed through this directory.
- `test`: Test utilities that are needed to write unit tests using the garbage collection library.
- `core`: The implementation of the garbage collection library. Blink may temporarily depend on concepts found in here until the public interface is complete.
The library is currently under construction. The Blink-specific parts can be found in third_party/blink/renderer/platform/heap. The library is currently under construction. The Blink-specific parts can be found in third_party/blink/renderer/platform/heap.
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_GC_PUBLIC_PLATFORM_H_
#define COMPONENTS_GC_PUBLIC_PLATFORM_H_
#include <stddef.h>
#include "components/gc/core/gc_export.h"
namespace gc {
// Allocator used to get memory from the embedder.
class GC_EXPORT PageAllocator {
public:
// Memory permissions.
enum Permission { kNoAccess, kRead, kReadWrite, kReadExecute };
virtual ~PageAllocator() = default;
// Page granularity for |AllocatePages()| and |FreePages()|. Addresses and
// lengths must be multiples of |AllocatePageSize()|.
virtual size_t AllocatePageSize() const = 0;
// Page granularity for |SetPermissions()| and |DiscardSystemPages()|.
// Addresses and lengths must be multiples of |CommitPageSize()|.
virtual size_t CommitPageSize() const = 0;
// Allocates memory at the given |address| (hint) with the provided |length|,
// |alignment|, and |permissions|.
virtual void* AllocatePages(void* address,
size_t length,
size_t alignment,
Permission permissions) = 0;
// Frees memory in a range that was allocated by |AllocatedPages()|.
virtual bool FreePages(void* address, size_t length) = 0;
// Sets permissions in a range that was allocated by |AllocatedPages()|.
virtual bool SetPermissions(void* address,
size_t length,
Permission permissions) = 0;
// Potentially frees physical memory in the range [address, address+length).
// Address and size should be aligned with |CommitPageSize()|. Note that this
// call transparently brings back physical memory at an unknown state.
//
// Returns true on success, and false otherwise.
virtual bool DiscardSystemPages(void* address, size_t size) = 0;
};
} // namespace gc
#endif // COMPONENTS_GC_PUBLIC_PLATFORM_H_
// Copyright 2020 The Chromium 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 "components/gc/test/base_allocator.h"
#include "base/allocator/partition_allocator/page_allocator.h"
#include "base/allocator/partition_allocator/page_allocator_constants.h"
namespace gc {
namespace test {
namespace {
base::PageAccessibilityConfiguration GetPageAccessibility(
PageAllocator::Permission permission) {
switch (permission) {
case PageAllocator::Permission::kRead:
return base::PageRead;
case PageAllocator::Permission::kReadWrite:
return base::PageReadWrite;
case PageAllocator::Permission::kReadExecute:
return base::PageReadExecute;
case PageAllocator::Permission::kNoAccess:
return base::PageInaccessible;
}
}
} // namespace
size_t BaseAllocator::AllocatePageSize() const {
return base::kPageAllocationGranularity;
}
size_t BaseAllocator::CommitPageSize() const {
return base::kSystemPageSize;
}
void* BaseAllocator::AllocatePages(void* address,
size_t length,
size_t alignment,
Permission permissions) {
base::PageAccessibilityConfiguration config =
GetPageAccessibility(permissions);
const bool commit = (permissions != PageAllocator::Permission::kNoAccess);
// Use generic PartitionAlloc page tag as the allocator is only used for
// testing.
const base::PageTag page_tag = base::PageTag::kChromium;
return base::AllocPages(address, length, alignment, config, page_tag, commit);
}
bool BaseAllocator::FreePages(void* address, size_t length) {
base::FreePages(address, length);
return true;
}
// Sets permissions in a range that was allocated by |AllocatedPages()|.
bool BaseAllocator::SetPermissions(void* address,
size_t length,
Permission permissions) {
if (permissions == Permission::kNoAccess) {
base::DecommitSystemPages(address, length);
return true;
}
return base::TrySetSystemPagesAccess(address, length,
GetPageAccessibility(permissions));
}
bool BaseAllocator::DiscardSystemPages(void* address, size_t size) {
return false;
}
} // namespace test
} // namespace gc
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_GC_TEST_BASE_ALLOCATOR_H_
#define COMPONENTS_GC_TEST_BASE_ALLOCATOR_H_
#include "components/gc/public/platform.h"
namespace gc {
namespace test {
class BaseAllocator final : public PageAllocator {
public:
size_t AllocatePageSize() const final;
size_t CommitPageSize() const final;
void* AllocatePages(void*, size_t, size_t, Permission) final;
bool FreePages(void*, size_t) final;
bool SetPermissions(void*, size_t, Permission) final;
bool DiscardSystemPages(void*, size_t) final;
};
} // namespace test
} // namespace gc
#endif // COMPONENTS_GC_TEST_BASE_ALLOCATOR_H_
// Copyright 2020 The Chromium 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 "components/gc/test/base_allocator.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gc {
namespace test {
TEST(BaseAllocatorTest, AllocateAndFreePage) {
BaseAllocator alloc;
const size_t allocation_size = alloc.AllocatePageSize();
uint8_t* memory = static_cast<uint8_t*>(
alloc.AllocatePages(nullptr, allocation_size, alloc.AllocatePageSize(),
BaseAllocator::Permission::kReadWrite));
ASSERT_TRUE(memory);
memory[0] = 1;
ASSERT_EQ(1u, memory[0]);
memory[allocation_size - 1] = 2;
ASSERT_EQ(2u, memory[allocation_size - 1]);
ASSERT_TRUE(alloc.FreePages(memory, allocation_size));
}
} // namespace test
} // namespace gc
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment