v8/test/unittests/objects/wasm-backing-store-unittest.cc
Clemens Backes 965e688d12 [wasm] Do not allocate guard regions for memory64
Memory64 currently does not use trap handling, so we should not allocate
a guard region (10GB total reservation).
This is implemented by adding a {WasmMemoryFlag} enum in the backing
store header, which replaces the previous {MemoryIndexType}. The flag is
not stored with the backing store, as the backing store does not care
about the index type, and we might want to share the same backing store
for memory32 and memory64 (if sizes permit this).
Instead, we (still) store the flag with the WasmMemoryObject and pass it
to the backing store methods.

R=jkummerow@chromium.org

Bug: v8:10949
Change-Id: I284b85b98d181ba5e8d454b24bfa48f6ac201be5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3789506
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82038}
2022-07-28 14:41:45 +00:00

136 lines
4.7 KiB
C++

// Copyright 2019 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/base/platform/platform.h"
#include "src/objects/backing-store.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
class BackingStoreTest : public TestWithIsolate {};
TEST_F(BackingStoreTest, GrowWasmMemoryInPlace) {
auto backing_store = BackingStore::AllocateWasmMemory(
isolate(), 1, 2, WasmMemoryFlag::kWasmMemory32, SharedFlag::kNotShared);
CHECK(backing_store);
EXPECT_TRUE(backing_store->is_wasm_memory());
EXPECT_EQ(1 * wasm::kWasmPageSize, backing_store->byte_length());
EXPECT_EQ(2 * wasm::kWasmPageSize, backing_store->byte_capacity());
base::Optional<size_t> result =
backing_store->GrowWasmMemoryInPlace(isolate(), 1, 2);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(result.value(), 1u);
EXPECT_EQ(2 * wasm::kWasmPageSize, backing_store->byte_length());
}
TEST_F(BackingStoreTest, GrowWasmMemoryInPlace_neg) {
auto backing_store = BackingStore::AllocateWasmMemory(
isolate(), 1, 2, WasmMemoryFlag::kWasmMemory32, SharedFlag::kNotShared);
CHECK(backing_store);
EXPECT_TRUE(backing_store->is_wasm_memory());
EXPECT_EQ(1 * wasm::kWasmPageSize, backing_store->byte_length());
EXPECT_EQ(2 * wasm::kWasmPageSize, backing_store->byte_capacity());
base::Optional<size_t> result =
backing_store->GrowWasmMemoryInPlace(isolate(), 2, 2);
EXPECT_FALSE(result.has_value());
EXPECT_EQ(1 * wasm::kWasmPageSize, backing_store->byte_length());
}
TEST_F(BackingStoreTest, GrowSharedWasmMemoryInPlace) {
auto backing_store = BackingStore::AllocateWasmMemory(
isolate(), 2, 3, WasmMemoryFlag::kWasmMemory32, SharedFlag::kShared);
CHECK(backing_store);
EXPECT_TRUE(backing_store->is_wasm_memory());
EXPECT_EQ(2 * wasm::kWasmPageSize, backing_store->byte_length());
EXPECT_EQ(3 * wasm::kWasmPageSize, backing_store->byte_capacity());
base::Optional<size_t> result =
backing_store->GrowWasmMemoryInPlace(isolate(), 1, 3);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(result.value(), 2u);
EXPECT_EQ(3 * wasm::kWasmPageSize, backing_store->byte_length());
}
TEST_F(BackingStoreTest, CopyWasmMemory) {
auto bs1 = BackingStore::AllocateWasmMemory(
isolate(), 1, 2, WasmMemoryFlag::kWasmMemory32, SharedFlag::kNotShared);
CHECK(bs1);
EXPECT_TRUE(bs1->is_wasm_memory());
EXPECT_EQ(1 * wasm::kWasmPageSize, bs1->byte_length());
EXPECT_EQ(2 * wasm::kWasmPageSize, bs1->byte_capacity());
auto bs2 =
bs1->CopyWasmMemory(isolate(), 3, 3, WasmMemoryFlag::kWasmMemory32);
EXPECT_TRUE(bs2->is_wasm_memory());
EXPECT_EQ(3 * wasm::kWasmPageSize, bs2->byte_length());
EXPECT_EQ(3 * wasm::kWasmPageSize, bs2->byte_capacity());
}
class GrowerThread : public base::Thread {
public:
GrowerThread(Isolate* isolate, uint32_t increment, uint32_t max,
std::shared_ptr<BackingStore> backing_store)
: base::Thread(base::Thread::Options("GrowerThread")),
isolate_(isolate),
increment_(increment),
max_(max),
backing_store_(backing_store) {}
void Run() override {
size_t max_length = max_ * wasm::kWasmPageSize;
while (true) {
size_t current_length = backing_store_->byte_length();
if (current_length >= max_length) break;
base::Optional<size_t> result =
backing_store_->GrowWasmMemoryInPlace(isolate_, increment_, max_);
size_t new_length = backing_store_->byte_length();
if (result.has_value()) {
CHECK_LE(current_length / wasm::kWasmPageSize, result.value());
CHECK_GE(new_length, current_length + increment_);
} else {
CHECK_EQ(max_length, new_length);
}
}
}
private:
Isolate* isolate_;
uint32_t increment_;
uint32_t max_;
std::shared_ptr<BackingStore> backing_store_;
};
TEST_F(BackingStoreTest, RacyGrowWasmMemoryInPlace) {
constexpr int kNumThreads = 10;
constexpr int kMaxPages = 1024;
GrowerThread* threads[kNumThreads];
std::shared_ptr<BackingStore> backing_store =
BackingStore::AllocateWasmMemory(isolate(), 0, kMaxPages,
WasmMemoryFlag::kWasmMemory32,
SharedFlag::kShared);
for (int i = 0; i < kNumThreads; i++) {
threads[i] = new GrowerThread(isolate(), 1, kMaxPages, backing_store);
CHECK(threads[i]->Start());
}
for (int i = 0; i < kNumThreads; i++) {
threads[i]->Join();
}
EXPECT_EQ(kMaxPages * wasm::kWasmPageSize, backing_store->byte_length());
for (int i = 0; i < kNumThreads; i++) {
delete threads[i];
}
}
} // namespace internal
} // namespace v8