Skip to content

Commit

Permalink
wasm2c: implement the custom-page-sizes proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
keithw committed Nov 11, 2024
1 parent 167eae8 commit 102a439
Show file tree
Hide file tree
Showing 15 changed files with 99 additions and 60 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Wabt has been compiled to JavaScript via emscripten. Some of the functionality i
| [multi-memory][] | `--enable-multi-memory` | ||||||
| [extended-const][] | `--enable-extended-const` | ||||||
| [relaxed-simd][] | `--enable-relaxed-simd` | ||||| |
| [custom-page-sizes][] | `--enable-custom-page-sizes`| ||||| |
| [custom-page-sizes][] | `--enable-custom-page-sizes`| ||||| |

[exception handling]: https://github.com/WebAssembly/exception-handling
[mutable globals]: https://github.com/WebAssembly/mutable-global
Expand Down
23 changes: 12 additions & 11 deletions src/c-writer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2229,18 +2229,17 @@ void CWriter::WriteDataInitializers() {
Index memory_idx = module_->num_memory_imports;
for (Index i = memory_idx; i < module_->memories.size(); i++) {
const Memory* memory = module_->memories[i];
uint64_t max;
if (memory->page_limits.has_max) {
max = memory->page_limits.max;
} else {
max = memory->page_limits.is_64 ? (static_cast<uint64_t>(1) << 48)
: 65536;
}
const uint64_t max =
memory->page_limits.has_max
? memory->page_limits.max
: WABT_BYTES_TO_MIN_PAGES(
(memory->page_limits.is_64 ? UINT64_MAX : UINT32_MAX),
memory->page_size);
std::string func = GetMemoryAPIString(*memory, "wasm_rt_allocate_memory");
Write(func, "(",
ExternalInstancePtr(ModuleFieldType::Memory, memory->name), ", ",
memory->page_limits.initial, ", ", max, ", ",
memory->page_limits.is_64, ");", Newline());
Write(
func, "(", ExternalInstancePtr(ModuleFieldType::Memory, memory->name),
", ", memory->page_limits.initial, ", ", max, ", ",
memory->page_limits.is_64, ", ", memory->page_size, ");", Newline());
}
}

Expand Down Expand Up @@ -2881,6 +2880,8 @@ void CWriter::WriteImportProperties(CWriterPhase kind) {
write_import_prop(import, "max", "u64",
limits->has_max ? limits->max : default_max);
write_import_prop(import, "is64", "u8", limits->is_64);
write_import_prop(import, "pagesize", "u32",
cast<MemoryImport>(import)->memory.page_size);
} else if (import->kind() == ExternalKind::Table) {
const Limits* limits = &(cast<TableImport>(import)->table.elem_limits);
const uint64_t default_max = std::numeric_limits<uint32_t>::max();
Expand Down
9 changes: 6 additions & 3 deletions src/tools/wasm2c.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ static const char s_description[] =
)";

static const std::string supported_features[] = {
"multi-memory", "multi-value", "sign-extension", "saturating-float-to-int",
"exceptions", "memory64", "extended-const", "simd",
"threads", "tail-call"};
"multi-memory", "multi-value",
"sign-extension", "saturating-float-to-int",
"exceptions", "memory64",
"extended-const", "simd",
"threads", "tail-call",
"custom-page-sizes"};

static bool IsFeatureSupported(const std::string& feature) {
return std::find(std::begin(supported_features), std::end(supported_features),
Expand Down
3 changes: 3 additions & 0 deletions test/run-spec-wasm2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ def main(args):
parser.add_argument('--enable-extended-const', action='store_true')
parser.add_argument('--enable-threads', action='store_true')
parser.add_argument('--enable-tail-call', action='store_true')
parser.add_argument('--enable-custom-page-sizes', action='store_true')
parser.add_argument('--disable-bulk-memory', action='store_true')
parser.add_argument('--disable-reference-types', action='store_true')
parser.add_argument('--debug-names', action='store_true')
Expand All @@ -566,6 +567,7 @@ def main(args):
'--enable-extended-const': options.enable_extended_const,
'--enable-threads': options.enable_threads,
'--enable-tail-call': options.enable_tail_call,
'--enable-custom-page-sizes': options.enable_custom_page_sizes,
'--enable-multi-memory': options.enable_multi_memory,
'--disable-bulk-memory': options.disable_bulk_memory,
'--disable-reference-types': options.disable_reference_types,
Expand All @@ -585,6 +587,7 @@ def main(args):
'--enable-extended-const': options.enable_extended_const,
'--enable-threads': options.enable_threads,
'--enable-tail-call': options.enable_tail_call,
'--enable-custom-page-sizes': options.enable_custom_page_sizes,
'--enable-multi-memory': options.enable_multi_memory})

options.cflags += shlex.split(os.environ.get('WASM2C_CFLAGS', ''))
Expand Down
3 changes: 2 additions & 1 deletion test/spec-wasm2c-prefix.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,8 @@ static void init_spectest_module(w2c_spectest* instance) {
instance->spectest_global_i64 = 666l;
instance->spectest_global_f32 = 666.6;
instance->spectest_global_f64 = 666.6;
wasm_rt_allocate_memory(&instance->spectest_memory, 1, 2, false);
wasm_rt_allocate_memory(&instance->spectest_memory, 1, 2, false,
WASM_DEFAULT_PAGE_SIZE);
wasm_rt_allocate_funcref_table(&instance->spectest_table, 10, 20);
wasm_rt_allocate_funcref_table(&instance->spectest_table64, 10, 20);
}
Expand Down
2 changes: 2 additions & 0 deletions test/wasm2c/check-imports.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ extern const u32 wasm2c_test_max_env_0x5F_indirect_function_table;
extern const u64 wasm2c_test_min_env_0x5F_linear_memory;
extern const u64 wasm2c_test_max_env_0x5F_linear_memory;
extern const u8 wasm2c_test_is64_env_0x5F_linear_memory;
extern const u32 wasm2c_test_pagesize_env_0x5F_linear_memory;
#ifdef __cplusplus
}
Expand Down Expand Up @@ -855,6 +856,7 @@ const u32 wasm2c_test_max_env_0x5F_indirect_function_table = 4294967295;
const u64 wasm2c_test_min_env_0x5F_linear_memory = 0;
const u64 wasm2c_test_max_env_0x5F_linear_memory = 65536;
const u8 wasm2c_test_is64_env_0x5F_linear_memory = 0;
const u32 wasm2c_test_pagesize_env_0x5F_linear_memory = 65536;
void wasm2c_test_instantiate(w2c_test* instance, struct w2c_env* w2c_env_instance) {
assert(wasm_rt_is_initialized());
Expand Down
2 changes: 2 additions & 0 deletions test/wasm2c/export-names.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ wasm_rt_func_type_t wasm2c_test_get_func_type(uint32_t param_count, uint32_t res
extern const u64 wasm2c_test_min_0x5Cmodule_import0x200x2A0x2F;
extern const u64 wasm2c_test_max_0x5Cmodule_import0x200x2A0x2F;
extern const u8 wasm2c_test_is64_0x5Cmodule_import0x200x2A0x2F;
extern const u32 wasm2c_test_pagesize_0x5Cmodule_import0x200x2A0x2F;
/* export: '' */
void w2c_test_(w2c_test*);
Expand Down Expand Up @@ -903,6 +904,7 @@ static void init_instance_import(w2c_test* instance, struct w2c_0x5Cmodule* w2c_
const u64 wasm2c_test_min_0x5Cmodule_import0x200x2A0x2F = 0;
const u64 wasm2c_test_max_0x5Cmodule_import0x200x2A0x2F = 65536;
const u8 wasm2c_test_is64_0x5Cmodule_import0x200x2A0x2F = 0;
const u32 wasm2c_test_pagesize_0x5Cmodule_import0x200x2A0x2F = 65536;
void wasm2c_test_instantiate(w2c_test* instance, struct w2c_0x5Cmodule* w2c_0x5Cmodule_instance) {
assert(wasm_rt_is_initialized());
Expand Down
2 changes: 1 addition & 1 deletion test/wasm2c/hello.txt
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ static const u8 data_segment_data_w2c_test_d0[] = {
};
static void init_memories(w2c_test* instance) {
wasm_rt_allocate_memory(&instance->w2c_memory, 1, 65536, 0);
wasm_rt_allocate_memory(&instance->w2c_memory, 1, 65536, 0, 65536);
LOAD_DATA(instance->w2c_memory, 8u, data_segment_data_w2c_test_d0, 14);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
;;; TOOL: run-spec-wasm2c
;;; ARGS*: --enable-custom-page-sizes --enable-multi-memory
;;; STDIN_FILE: third_party/testsuite/proposals/custom-page-sizes/custom-page-sizes-invalid.wast
(;; STDOUT ;;;
0/0 tests passed.
;;; STDOUT ;;)
6 changes: 6 additions & 0 deletions test/wasm2c/spec/custom-page-sizes/custom-page-sizes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
;;; TOOL: run-spec-wasm2c
;;; ARGS*: --enable-custom-page-sizes --enable-multi-memory
;;; STDIN_FILE: third_party/testsuite/proposals/custom-page-sizes/custom-page-sizes.wast
(;; STDOUT ;;;
24/24 tests passed.
;;; STDOUT ;;)
29 changes: 17 additions & 12 deletions wasm2c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,13 +297,16 @@ typedef struct {

Next is the definition of a memory instance. The `data` field is a pointer to
`size` bytes of linear memory. The `size` field of `wasm_rt_memory_t` is the
current size of the memory instance in bytes, whereas `pages` is the current
size in pages (65536 bytes.) `max_pages` is the maximum number of pages as
specified by the module, or `0xffffffff` if there is no limit.
current size of the memory instance in bytes, `pages` is the current
size in pages, and `page_size` contains the page size in bytes (65,536 by default).
`max_pages` is the maximum number of pages specified by the module or allowed
by the memory index type (`is64` is true for memories that can grow to 2^64 bytes;
`false` for memories limited to 2^32 bytes).

```c
typedef struct {
uint8_t* data;
uint32_t page_size;
uint64_t pages, max_pages;
uint64_t size;
bool is64;
Expand Down Expand Up @@ -353,10 +356,10 @@ bool wasm_rt_is_initialized(void);
void wasm_rt_free(void);
void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn));
const char* wasm_rt_strerror(wasm_rt_trap_t trap);
void wasm_rt_allocate_memory(wasm_rt_memory_t*, uint32_t initial_pages, uint32_t max_pages, bool is64);
void wasm_rt_allocate_memory(wasm_rt_memory_t*, uint32_t initial_pages, uint32_t max_pages, bool is64, uint32_t page_size);
uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);
void wasm_rt_free_memory(wasm_rt_memory_t*);
void wasm_rt_allocate_memory_shared(wasm_rt_shared_memory_t*, uint32_t initial_pages, uint32_t max_pages, bool is64);
void wasm_rt_allocate_memory_shared(wasm_rt_shared_memory_t*, uint32_t initial_pages, uint32_t max_pages, bool is64, uint32_t page_size);
uint32_t wasm_rt_grow_memory_shared(wasm_rt_shared_memory_t*, uint32_t pages);
void wasm_rt_free_memory_shared(wasm_rt_shared_memory_t*);
void wasm_rt_allocate_funcref_table(wasm_rt_table_t*, uint32_t elements, uint32_t max_elements);
Expand All @@ -381,10 +384,12 @@ with `WASM_RT_TRAP_HANDLER` defined to the name of a trap handler function. The
handler function should be a function taking a `wasm_rt_trap_t` as a parameter
and returning `void`. e.g. `-DWASM_RT_TRAP_HANDLER=my_trap_handler`
`wasm_rt_allocate_memory` initializes a memory instance, and allocates at least
enough space for the given number of initial pages. The memory must be cleared
to zero. The `is64` parameter indicates if the memory is indexed with
an i32 or i64 address.
`wasm_rt_allocate_memory` initializes a memory instance, and allocates
at least enough space for the given number of initial pages, each of
size `page_size` (which must be `WABT_DEFAULT_PAGE_SIZE`, equal to 64
KiB, unless using the custom-page-sizes feature). The memory must be
cleared to zero. The `is64` parameter indicates if the memory is
indexed with an i32 or i64 address.
`wasm_rt_grow_memory` must grow the given memory instance by the given number of
pages. If there isn't enough memory to do so, or the new page count would be
Expand All @@ -399,7 +404,7 @@ arguments and returning `void` . e.g.
`wasm_rt_free_memory` frees the memory instance.
`wasm_rt_allocate_memory_shared` initializes a memory instance that can be
shared by different Wasm threads. It's operation is otherwise similar to
shared by different Wasm threads. Its operation is otherwise similar to
`wasm_rt_allocate_memory`.
`wasm_rt_grow_memory_shared` must grow the given shared memory instance by the
Expand Down Expand Up @@ -658,8 +663,8 @@ int main(int argc, char** argv) {

/* Create two `host` instances to store the memory and current string */
w2c_host host_1, host_2;
wasm_rt_allocate_memory(&host_1.memory, 1, 1, false);
wasm_rt_allocate_memory(&host_2.memory, 1, 1, false);
wasm_rt_allocate_memory(&host_1.memory, 1, 1, false, WASM_DEFAULT_PAGE_SIZE);
wasm_rt_allocate_memory(&host_2.memory, 1, 1, false, WASM_DEFAULT_PAGE_SIZE);

/* Construct the `rot13` module instances */
w2c_rot13 rot13_1, rot13_2;
Expand Down
2 changes: 1 addition & 1 deletion wasm2c/examples/rot13/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ int main(int argc, char** argv) {
/* Create a structure to store the memory and current string, allocating 1
page of Wasm memory (64 KiB) that the rot13 module instance will import. */
struct w2c_host host;
wasm_rt_allocate_memory(&host.memory, 1, 1, false);
wasm_rt_allocate_memory(&host.memory, 1, 1, false, WASM_DEFAULT_PAGE_SIZE);

// Construct an instance of the `rot13` module, which imports from the host.
w2c_rot13 rot13;
Expand Down
29 changes: 19 additions & 10 deletions wasm2c/wasm-rt-mem-impl-helper.inc
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,28 @@

#endif

bool MEMORY_API_NAME(wasm_rt_memory_is_default32)(const MEMORY_TYPE* memory) {
return memory->page_size == WASM_DEFAULT_PAGE_SIZE && !memory->is64;
}

void MEMORY_API_NAME(wasm_rt_allocate_memory)(MEMORY_TYPE* memory,
uint64_t initial_pages,
uint64_t max_pages,
bool is64) {
uint64_t byte_length = initial_pages * WASM_PAGE_SIZE;
bool is64,
uint32_t page_size) {
uint64_t byte_length = initial_pages * page_size;
memory->size = byte_length;
memory->pages = initial_pages;
memory->max_pages = max_pages;
memory->is64 = is64;
memory->page_size = page_size;
MEMORY_LOCK_VAR_INIT(memory->mem_lock);

if (WASM_RT_USE_MMAP && !is64) {
if (WASM_RT_USE_MMAP &&
MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) {
#if WASM_RT_USE_MMAP // mmap-related functions don't exist unless this is set
const uint64_t mmap_size =
get_alloc_size_for_mmap(memory->max_pages, memory->is64);
get_alloc_size_for_mmap_default32(memory->max_pages);
void* addr = os_mmap(mmap_size);
if (!addr) {
os_print_last_error("os_mmap failed.");
Expand Down Expand Up @@ -105,11 +112,12 @@ static uint64_t MEMORY_API_NAME(grow_memory_impl)(MEMORY_TYPE* memory,
if (new_pages < old_pages || new_pages > memory->max_pages) {
return (uint64_t)-1;
}
uint64_t old_size = old_pages * WASM_PAGE_SIZE;
uint64_t new_size = new_pages * WASM_PAGE_SIZE;
uint64_t delta_size = delta * WASM_PAGE_SIZE;
uint64_t old_size = old_pages * memory->page_size;
uint64_t new_size = new_pages * memory->page_size;
uint64_t delta_size = delta * memory->page_size;
MEMORY_CELL_TYPE new_data;
if (WASM_RT_USE_MMAP && !memory->is64) {
if (WASM_RT_USE_MMAP &&
MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) {
#if WASM_RT_USE_MMAP
new_data = memory->data;
int ret = os_mprotect((void*)(new_data + old_size), delta_size);
Expand Down Expand Up @@ -150,10 +158,11 @@ uint64_t MEMORY_API_NAME(wasm_rt_grow_memory)(MEMORY_TYPE* memory,
}

void MEMORY_API_NAME(wasm_rt_free_memory)(MEMORY_TYPE* memory) {
if (WASM_RT_USE_MMAP && !memory->is64) {
if (WASM_RT_USE_MMAP &&
MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) {
#if WASM_RT_USE_MMAP
const uint64_t mmap_size =
get_alloc_size_for_mmap(memory->max_pages, memory->is64);
get_alloc_size_for_mmap_default32(memory->max_pages);
os_munmap((void*)memory->data, mmap_size); // ignore error
#endif
} else {
Expand Down
14 changes: 5 additions & 9 deletions wasm2c/wasm-rt-mem-impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
#include <sys/mman.h>
#endif

#define WASM_PAGE_SIZE 65536

#ifdef WASM_RT_GROW_FAILED_HANDLER
extern void WASM_RT_GROW_FAILED_HANDLER();
#endif
Expand Down Expand Up @@ -112,7 +110,7 @@ static void os_print_last_error(const char* msg) {
}
}

#else
#else /* !_WIN32 */
static void* os_mmap(size_t size) {
int map_prot = PROT_NONE;
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
Expand All @@ -134,17 +132,16 @@ static void os_print_last_error(const char* msg) {
perror(msg);
}

#endif
#endif /* _WIN32 */

static uint64_t get_alloc_size_for_mmap(uint64_t max_pages, bool is64) {
assert(!is64 && "memory64 is not yet compatible with WASM_RT_USE_MMAP");
static uint64_t get_alloc_size_for_mmap_default32(uint64_t max_pages) {
#if WASM_RT_MEMCHECK_GUARD_PAGES
/* Reserve 8GiB. */
const uint64_t max_size = 0x200000000ul;
return max_size;
#else
if (max_pages != 0) {
const uint64_t max_size = max_pages * WASM_PAGE_SIZE;
const uint64_t max_size = max_pages * WASM_DEFAULT_PAGE_SIZE;
return max_size;
}

Expand All @@ -154,7 +151,7 @@ static uint64_t get_alloc_size_for_mmap(uint64_t max_pages, bool is64) {
#endif
}

#endif
#endif /* WASM_RT_USE_MMAP */

// Include operations for memory
#define WASM_RT_MEM_OPS
Expand All @@ -175,4 +172,3 @@ static uint64_t get_alloc_size_for_mmap(uint64_t max_pages, bool is64) {
#undef WIN_MEMORY_LOCK_VAR_INIT
#undef WIN_MEMORY_LOCK_AQUIRE
#undef WIN_MEMORY_LOCK_RELEASE
#undef WASM_PAGE_SIZE
Loading

0 comments on commit 102a439

Please sign in to comment.