Commit cfc4bba0 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[test][wasm] Allow testing of huge memories

This patch maintains the previous default value of the flag controlling
the max size of Wasm memories, but allows the limit to be raised on the
command line.
Bonus content: improve the multi-mapped mock allocator by falling back
to regular allocation for small requests.
More bonus content: make debug-mode Wasm tests faster.

Bug: v8:6306
Change-Id: Idabae5734794b06e65d45b3a6165dbd488847f3f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1981157
Auto-Submit: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65681}
parent bb4425c0
...@@ -219,11 +219,17 @@ class MockArrayBufferAllocatiorWithLimit : public MockArrayBufferAllocator { ...@@ -219,11 +219,17 @@ class MockArrayBufferAllocatiorWithLimit : public MockArrayBufferAllocator {
class MultiMappedAllocator : public ArrayBufferAllocatorBase { class MultiMappedAllocator : public ArrayBufferAllocatorBase {
protected: protected:
void* Allocate(size_t length) override { void* Allocate(size_t length) override {
if (length < kChunkSize) {
return ArrayBufferAllocatorBase::Allocate(length);
}
// We use mmap, which initializes pages to zero anyway. // We use mmap, which initializes pages to zero anyway.
return AllocateUninitialized(length); return AllocateUninitialized(length);
} }
void* AllocateUninitialized(size_t length) override { void* AllocateUninitialized(size_t length) override {
if (length < kChunkSize) {
return ArrayBufferAllocatorBase::AllocateUninitialized(length);
}
size_t rounded_length = RoundUp(length, kChunkSize); size_t rounded_length = RoundUp(length, kChunkSize);
int prot = PROT_READ | PROT_WRITE; int prot = PROT_READ | PROT_WRITE;
// We have to specify MAP_SHARED to make {mremap} below do what we want. // We have to specify MAP_SHARED to make {mremap} below do what we want.
...@@ -250,6 +256,9 @@ class MultiMappedAllocator : public ArrayBufferAllocatorBase { ...@@ -250,6 +256,9 @@ class MultiMappedAllocator : public ArrayBufferAllocatorBase {
} }
void Free(void* data, size_t length) override { void Free(void* data, size_t length) override {
if (length < kChunkSize) {
return ArrayBufferAllocatorBase::Free(data, length);
}
void* real_alloc = regions_[data]; void* real_alloc = regions_[data];
munmap(real_alloc, kChunkSize); munmap(real_alloc, kChunkSize);
size_t rounded_length = RoundUp(length, kChunkSize); size_t rounded_length = RoundUp(length, kChunkSize);
......
...@@ -670,7 +670,8 @@ DEFINE_BOOL(wasm_async_compilation, true, ...@@ -670,7 +670,8 @@ DEFINE_BOOL(wasm_async_compilation, true,
"enable actual asynchronous compilation for WebAssembly.compile") "enable actual asynchronous compilation for WebAssembly.compile")
DEFINE_BOOL(wasm_test_streaming, false, DEFINE_BOOL(wasm_test_streaming, false,
"use streaming compilation instead of async compilation for tests") "use streaming compilation instead of async compilation for tests")
DEFINE_UINT(wasm_max_mem_pages, v8::internal::wasm::kV8MaxWasmMemoryPages, // TODO(4153): Set this back to v8::internal::wasm::kV8MaxWasmMemoryPages
DEFINE_UINT(wasm_max_mem_pages, 32767,
"maximum number of 64KiB memory pages of a wasm instance") "maximum number of 64KiB memory pages of a wasm instance")
DEFINE_UINT(wasm_max_table_size, v8::internal::wasm::kV8MaxWasmTableSize, DEFINE_UINT(wasm_max_table_size, v8::internal::wasm::kV8MaxWasmTableSize,
"maximum table size of a wasm instance") "maximum table size of a wasm instance")
......
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/objects/backing-store.h" #include "src/objects/backing-store.h"
#include <cstring>
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/handles/global-handles.h" #include "src/handles/global-handles.h"
#include "src/logging/counters.h" #include "src/logging/counters.h"
...@@ -103,11 +106,20 @@ void RecordStatus(Isolate* isolate, AllocationStatus status) { ...@@ -103,11 +106,20 @@ void RecordStatus(Isolate* isolate, AllocationStatus status) {
inline void DebugCheckZero(void* start, size_t byte_length) { inline void DebugCheckZero(void* start, size_t byte_length) {
#if DEBUG #if DEBUG
// Double check memory is zero-initialized. // Double check memory is zero-initialized. Despite being DEBUG-only,
// this function is somewhat optimized for the benefit of test suite
// execution times (some tests allocate several gigabytes).
const byte* bytes = reinterpret_cast<const byte*>(start); const byte* bytes = reinterpret_cast<const byte*>(start);
for (size_t i = 0; i < byte_length; i++) { const size_t kBaseCase = 32;
for (size_t i = 0; i < kBaseCase && i < byte_length; i++) {
DCHECK_EQ(0, bytes[i]); DCHECK_EQ(0, bytes[i]);
} }
// Having checked the first kBaseCase bytes to be zero, we can now use
// {memcmp} to compare the range against itself shifted by that amount,
// thereby inductively checking the remaining bytes.
if (byte_length > kBaseCase) {
DCHECK_EQ(0, memcmp(bytes, bytes + kBaseCase, byte_length - kBaseCase));
}
#endif #endif
} }
} // namespace } // namespace
......
...@@ -72,7 +72,7 @@ struct CompilationEnv { ...@@ -72,7 +72,7 @@ struct CompilationEnv {
: 0), : 0),
max_memory_size((module && module->has_maximum_pages max_memory_size((module && module->has_maximum_pages
? module->maximum_pages ? module->maximum_pages
: kV8MaxWasmMemoryPages) * : max_mem_pages()) *
uint64_t{kWasmPageSize}), uint64_t{kWasmPageSize}),
enabled_features(enabled_features), enabled_features(enabled_features),
lower_simd(lower_simd) {} lower_simd(lower_simd) {}
......
...@@ -28,7 +28,7 @@ constexpr size_t kV8MaxWasmExceptions = 1000000; ...@@ -28,7 +28,7 @@ constexpr size_t kV8MaxWasmExceptions = 1000000;
constexpr size_t kV8MaxWasmExceptionTypes = 1000000; constexpr size_t kV8MaxWasmExceptionTypes = 1000000;
constexpr size_t kV8MaxWasmDataSegments = 100000; constexpr size_t kV8MaxWasmDataSegments = 100000;
// Don't use this limit directly, but use the value of {max_mem_pages()}. // Don't use this limit directly, but use the value of {max_mem_pages()}.
constexpr size_t kV8MaxWasmMemoryPages = 32767; // = ~ 2 GiB constexpr size_t kV8MaxWasmMemoryPages = 65536; // = 4 GiB
constexpr size_t kV8MaxWasmStringSize = 100000; constexpr size_t kV8MaxWasmStringSize = 100000;
constexpr size_t kV8MaxWasmModuleSize = 1024 * 1024 * 1024; // = 1 GiB constexpr size_t kV8MaxWasmModuleSize = 1024 * 1024 * 1024; // = 1 GiB
constexpr size_t kV8MaxWasmFunctionSize = 7654321; constexpr size_t kV8MaxWasmFunctionSize = 7654321;
...@@ -58,7 +58,7 @@ constexpr uint64_t kWasmMaxHeapOffset = ...@@ -58,7 +58,7 @@ constexpr uint64_t kWasmMaxHeapOffset =
// Defined in wasm-engine.cc. // Defined in wasm-engine.cc.
// TODO(wasm): Make this size_t for wasm64. Currently the --wasm-max-mem-pages // TODO(wasm): Make this size_t for wasm64. Currently the --wasm-max-mem-pages
// flag is only uint32_t. // flag is only uint32_t.
uint32_t max_mem_pages(); V8_EXPORT_PRIVATE uint32_t max_mem_pages();
uint32_t max_table_init_entries(); uint32_t max_table_init_entries();
inline uint64_t max_mem_bytes() { inline uint64_t max_mem_bytes() {
......
...@@ -231,9 +231,6 @@ ...@@ -231,9 +231,6 @@
# Runs out of stack space in debug builds. # Runs out of stack space in debug builds.
'big-array-literal': [PASS, ['mode == debug', SKIP]], 'big-array-literal': [PASS, ['mode == debug', SKIP]],
# BUG(v8:6306).
'wasm/huge-memory': [SKIP],
# Allocates a huge string and then flattens it, very slow in debug mode. # Allocates a huge string and then flattens it, very slow in debug mode.
'regress/regress-752764': [PASS, ['mode == debug', SLOW]], 'regress/regress-752764': [PASS, ['mode == debug', SLOW]],
...@@ -254,6 +251,8 @@ ...@@ -254,6 +251,8 @@
# Test doesn't work on 32-bit architectures (it would require a # Test doesn't work on 32-bit architectures (it would require a
# regexp pattern with too many captures). # regexp pattern with too many captures).
# TODO(jkummerow/jgruber): Silently fails with pointer compression too.
# Fix it or delete it.
'regress/regress-976627': [FAIL, ['arch == x64 or arch == arm64 or arch == mips64el or arch == ppc64 or arch == s390x', PASS]], 'regress/regress-976627': [FAIL, ['arch == x64 or arch == arm64 or arch == mips64el or arch == ppc64 or arch == s390x', PASS]],
# OOM with too many isolates/memory objects (https://crbug.com/1010272) # OOM with too many isolates/memory objects (https://crbug.com/1010272)
...@@ -446,6 +445,13 @@ ...@@ -446,6 +445,13 @@
'wasm/*': [SKIP], 'wasm/*': [SKIP],
}], # 'byteorder == big' }], # 'byteorder == big'
##############################################################################
# 32-bit platforms
['arch in (ia32, arm, mips, mipsel)', {
# Needs >2GB of available contiguous memory.
'wasm/huge-memory': [SKIP],
}], # 'arch in (ia32, arm, mips, mipsel)'
############################################################################## ##############################################################################
['arch == arm64', { ['arch == arm64', {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
load('test/mjsunit/wasm/wasm-module-builder.js'); load('test/mjsunit/wasm/wasm-module-builder.js');
// Flags: --wasm-max-mem-pages=49152 // Flags: --wasm-max-mem-pages=49151
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
const num_pages = 49152; const num_pages = 49152;
......
...@@ -6,10 +6,10 @@ ...@@ -6,10 +6,10 @@
load('test/mjsunit/wasm/wasm-module-builder.js'); load('test/mjsunit/wasm/wasm-module-builder.js');
let k1MiB = 1 * 1024 * 1024;
let k1GiB = 1 * 1024 * 1024 * 1024; let k1GiB = 1 * 1024 * 1024 * 1024;
let k4GiB = 4 * k1GiB; let k4GiB = 4 * k1GiB;
let kMaxMemory = 2 * k1GiB - kPageSize; // TODO(titzer): raise this to 4GiB // TODO(4153): Raise this to 4GiB, but only on 64-bit platforms.
let kMaxMemory = 2 * k1GiB - kPageSize;
(function Test() { (function Test() {
var memory; var memory;
...@@ -36,20 +36,19 @@ let kMaxMemory = 2 * k1GiB - kPageSize; // TODO(titzer): raise this to 4GiB ...@@ -36,20 +36,19 @@ let kMaxMemory = 2 * k1GiB - kPageSize; // TODO(titzer): raise this to 4GiB
function probe(a, f) { function probe(a, f) {
print("------------------------"); print("------------------------");
let stride = kPageSize; let stride = kPageSize * 32; // Don't check every page to save time.
let max = kMaxMemory; let max = kMaxMemory;
for (let i = 0; i < max; i += stride) { for (let i = 0; i < max; i += stride) {
a.store(i, f(i)); a.store(i, f(i));
} }
for (let i = 0; i < max; i += stride) { for (let i = 0; i < max; i += stride) {
// print(`${i} = ${f(i)}`);
assertEquals(f(i), a.load(i)); assertEquals(f(i), a.load(i));
} }
} }
try { try {
let kPages = kMaxMemory / kPageSize; let kPages = kMaxMemory / kPageSize;
memory = new WebAssembly.Memory({initial: kPages, maximum: kPages}); memory = new WebAssembly.Memory({ initial: kPages, maximum: kPages });
} catch (e) { } catch (e) {
print("OOM: sorry, best effort max memory size test."); print("OOM: sorry, best effort max memory size test.");
return; return;
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --wasm-max-mem-pages=49152 // Flags: --wasm-max-mem-pages=49152
// Save some memory on Linux; other platforms ignore this flag.
// Flags: --multi-mapped-mock-allocator
// This test makes sure things don't break once we support >2GB wasm memories. // This test makes sure things don't break once we support >2GB wasm memories.
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
......
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