* Implement a setting for reserved dynamic memory growth Dynamic memories aren't really that heavily used in Wasmtime right now because for most 32-bit memories they're classified as "static" which means they reserve 4gb of address space and never move. Growth of a static memory is simply making pages accessible, so it's quite fast. With the memory64 feature, however, this is no longer true since all memory64 memories are classified as "dynamic" at this time. Previous to this commit growth of a dynamic memory unconditionally moved the entire linear memory in the host's address space, always resulting in a new `Mmap` allocation. This behavior is causing fuzzers to time out when working with 64-bit memories because incrementally growing a memory by 1 page at a time can incur a quadratic time complexity as bytes are constantly moved. This commit implements a scheme where there is now a tunable setting for memory to be reserved at the end of a dynamic memory to grow into. This means that dynamic memory growth is ideally amortized as most calls to `memory.grow` will be able to grow into the pre-reserved space. Some calls, though, will still need to copy the memory around. This helps enable a commented out test for 64-bit memories now that it's fast enough to run in debug mode. This is because the growth of memory in the test no longer needs to copy 4gb of zeros. * Test fixes & review comments * More comments
62 lines
1.8 KiB
Plaintext
62 lines
1.8 KiB
Plaintext
;; try to create as few 4gb memories as we can to reduce the memory consumption
|
|
;; of this test, so create one up front here and use it below.
|
|
(module $memory
|
|
(memory (export "memory") i64 0x1_0001 0x1_0005)
|
|
)
|
|
|
|
(module
|
|
(import "memory" "memory" (memory i64 0))
|
|
(func (export "grow") (param i64) (result i64)
|
|
local.get 0
|
|
memory.grow)
|
|
(func (export "size") (result i64)
|
|
memory.size)
|
|
)
|
|
(assert_return (invoke "grow" (i64.const 0)) (i64.const 0x1_0001))
|
|
(assert_return (invoke "size") (i64.const 0x1_0001))
|
|
(assert_return (invoke "grow" (i64.const 1)) (i64.const 0x1_0001))
|
|
(assert_return (invoke "size") (i64.const 0x1_0002))
|
|
|
|
;; Test that initialization with a 64-bit global works
|
|
(module $offset
|
|
(global (export "offset") i64 (i64.const 0x1_0000_0000))
|
|
)
|
|
(module
|
|
(import "offset" "offset" (global i64))
|
|
(import "memory" "memory" (memory i64 0))
|
|
(data (global.get 0) "\01\02\03\04")
|
|
|
|
(func (export "load32") (param i64) (result i32)
|
|
local.get 0
|
|
i32.load)
|
|
)
|
|
(assert_return (invoke "load32" (i64.const 0x1_0000_0000)) (i32.const 0x04030201))
|
|
|
|
;; Test that initialization with a 64-bit data segment works
|
|
(module $offset
|
|
(global (export "offset") i64 (i64.const 0x1_0000_0000))
|
|
)
|
|
(module
|
|
(import "memory" "memory" (memory i64 0))
|
|
(data (i64.const 0x1_0000_0004) "\01\02\03\04")
|
|
|
|
(func (export "load32") (param i64) (result i32)
|
|
local.get 0
|
|
i32.load)
|
|
)
|
|
(assert_return (invoke "load32" (i64.const 0x1_0000_0004)) (i32.const 0x04030201))
|
|
|
|
;; loading with a huge offset works
|
|
(module $offset
|
|
(global (export "offset") i64 (i64.const 0x1_0000_0000))
|
|
)
|
|
(module
|
|
(import "memory" "memory" (memory i64 0))
|
|
(data (i64.const 0x1_0000_0004) "\01\02\03\04")
|
|
|
|
(func (export "load32") (param i64) (result i32)
|
|
local.get 0
|
|
i32.load offset=0x100000000)
|
|
)
|
|
(assert_return (invoke "load32" (i64.const 2)) (i32.const 0x02010403))
|