From 36fcc41bb2518ae28f81945a3c42afd20c53c3aa Mon Sep 17 00:00:00 2001 From: dAxpeDDa Date: Tue, 6 Jun 2023 01:05:44 +0200 Subject: [PATCH 1/4] Take alignment into consideration during `malloc` --- crates/cli-support/src/js/binding.rs | 14 ++++++++++---- crates/cli-support/src/js/mod.rs | 14 +++++++------- crates/cli/tests/reference/result-string.js | 2 +- crates/cli/tests/reference/result-string.wat | 4 ++-- crates/cli/tests/reference/string-arg.js | 6 +++--- crates/cli/tests/reference/string-arg.wat | 12 ++++++------ crates/threads-xform/src/lib.rs | 8 ++++++-- guide/src/contributing/design/exporting-rust.md | 4 ++-- src/lib.rs | 10 +++------- 9 files changed, 40 insertions(+), 34 deletions(-) diff --git a/crates/cli-support/src/js/binding.rs b/crates/cli-support/src/js/binding.rs index 3dfd22cc082..e9dae127fe2 100644 --- a/crates/cli-support/src/js/binding.rs +++ b/crates/cli-support/src/js/binding.rs @@ -550,11 +550,13 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> | Instruction::CallTableElement(_) | Instruction::DeferCallCore(_) => { let invoc = Invocation::from(instr, js.cx.module)?; - let (params, results) = invoc.params_results(js.cx); + let (mut params, results) = invoc.params_results(js.cx); let mut args = Vec::new(); let tmp = js.tmp(); if invoc.defer() { + // substract alignment + params -= 1; // If the call is deferred, the arguments to the function still need to be // accessible in the `finally` block, so we declare variables to hold the args // outside of the try-finally block and then set those to the args. @@ -564,6 +566,8 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> writeln!(js.prelude, "{name} = {arg};").unwrap(); args.push(name); } + // add alignment + args.push(String::from("4")); } else { // Otherwise, pop off the number of parameters for the function we're calling. for _ in 0..params { @@ -813,12 +817,14 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> let func = js.cx.pass_to_wasm_function(kind.clone(), *mem)?; let malloc = js.cx.export_name_of(*malloc); let i = js.tmp(); + let align = std::cmp::max(kind.size(), 4); js.prelude(&format!( - "const ptr{i} = {f}({0}, wasm.{malloc});", + "const ptr{i} = {f}({0}, wasm.{malloc}, {align});", val, i = i, f = func, malloc = malloc, + align = align, )); js.prelude(&format!("const len{} = WASM_VECTOR_LEN;", i)); js.push(format!("ptr{}", i)); @@ -922,7 +928,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> let malloc = js.cx.export_name_of(*malloc); let val = js.pop(); js.prelude(&format!( - "var ptr{i} = isLikeNone({0}) ? 0 : {f}({0}, wasm.{malloc});", + "var ptr{i} = isLikeNone({0}) ? 0 : {f}({0}, wasm.{malloc}, 4);", val, i = i, f = func, @@ -940,7 +946,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> let malloc = js.cx.export_name_of(*malloc); let i = js.tmp(); js.prelude(&format!( - "var ptr{i} = {f}({val}, wasm.{malloc});", + "var ptr{i} = {f}({val}, wasm.{malloc}, 4);", val = val, i = i, f = func, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 33c03ef9518..efe43b5b14d 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -1259,14 +1259,14 @@ impl<'a> Context<'a> { "\ if (realloc === undefined) {{ const buf = cachedTextEncoder.encode(arg); - const ptr = malloc(buf.length) >>> 0; + const ptr = malloc(buf.length, 4) >>> 0; {mem}().subarray(ptr, ptr + buf.length).set(buf); WASM_VECTOR_LEN = buf.length; return ptr; }} let len = arg.length; - let ptr = malloc(len) >>> 0; + let ptr = malloc(len, 4) >>> 0; const mem = {mem}(); @@ -1294,7 +1294,7 @@ impl<'a> Context<'a> { if (offset !== 0) {{ arg = arg.slice(offset); }} - ptr = realloc(ptr, len, len = offset + arg.length * 3) >>> 0; + ptr = realloc(ptr, len, len = offset + arg.length * 3, 4) >>> 0; const view = {mem}().subarray(ptr + offset, ptr + len); const ret = encodeString(arg, view); {debug_end} @@ -1366,7 +1366,7 @@ impl<'a> Context<'a> { self.global(&format!( " function {}(array, malloc) {{ - const ptr = malloc(array.length * 4) >>> 0; + const ptr = malloc(array.length * 4, 4) >>> 0; const mem = {}(); for (let i = 0; i < array.length; i++) {{ mem[ptr / 4 + i] = {}(array[i]); @@ -1383,7 +1383,7 @@ impl<'a> Context<'a> { self.global(&format!( " function {}(array, malloc) {{ - const ptr = malloc(array.length * 4) >>> 0; + const ptr = malloc(array.length * 4, 4) >>> 0; const mem = {}(); for (let i = 0; i < array.length; i++) {{ mem[ptr / 4 + i] = addHeapObject(array[i]); @@ -1415,8 +1415,8 @@ impl<'a> Context<'a> { self.expose_wasm_vector_len(); self.global(&format!( " - function {}(arg, malloc) {{ - const ptr = malloc(arg.length * {size}) >>> 0; + function {}(arg, malloc, align) {{ + const ptr = malloc(arg.length * {size}, align) >>> 0; {}().set(arg, ptr / {size}); WASM_VECTOR_LEN = arg.length; return ptr; diff --git a/crates/cli/tests/reference/result-string.js b/crates/cli/tests/reference/result-string.js index 3415b902951..95aa113dad3 100644 --- a/crates/cli/tests/reference/result-string.js +++ b/crates/cli/tests/reference/result-string.js @@ -85,7 +85,7 @@ export function exported() { return getStringFromWasm0(ptr1, len1); } finally { wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(deferred2_0, deferred2_1); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 4); } } diff --git a/crates/cli/tests/reference/result-string.wat b/crates/cli/tests/reference/result-string.wat index 00277c9f806..ff21a91d969 100644 --- a/crates/cli/tests/reference/result-string.wat +++ b/crates/cli/tests/reference/result-string.wat @@ -1,9 +1,9 @@ (module (type (;0;) (func (param i32))) (type (;1;) (func (param i32) (result i32))) - (type (;2;) (func (param i32 i32))) + (type (;2;) (func (param i32 i32 i32))) (func $exported (;0;) (type 0) (param i32)) - (func $__wbindgen_free (;1;) (type 2) (param i32 i32)) + (func $__wbindgen_free (;1;) (type 2) (param i32 i32 i32)) (func $__wbindgen_add_to_stack_pointer (;2;) (type 1) (param i32) (result i32)) (memory (;0;) 17) (export "memory" (memory 0)) diff --git a/crates/cli/tests/reference/string-arg.js b/crates/cli/tests/reference/string-arg.js index 7921d3ca422..62d74ddd171 100644 --- a/crates/cli/tests/reference/string-arg.js +++ b/crates/cli/tests/reference/string-arg.js @@ -47,14 +47,14 @@ function passStringToWasm0(arg, malloc, realloc) { if (realloc === undefined) { const buf = cachedTextEncoder.encode(arg); - const ptr = malloc(buf.length) >>> 0; + const ptr = malloc(buf.length, 4) >>> 0; getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); WASM_VECTOR_LEN = buf.length; return ptr; } let len = arg.length; - let ptr = malloc(len) >>> 0; + let ptr = malloc(len, 4) >>> 0; const mem = getUint8Memory0(); @@ -70,7 +70,7 @@ function passStringToWasm0(arg, malloc, realloc) { if (offset !== 0) { arg = arg.slice(offset); } - ptr = realloc(ptr, len, len = offset + arg.length * 3) >>> 0; + ptr = realloc(ptr, len, len = offset + arg.length * 3, 4) >>> 0; const view = getUint8Memory0().subarray(ptr + offset, ptr + len); const ret = encodeString(arg, view); diff --git a/crates/cli/tests/reference/string-arg.wat b/crates/cli/tests/reference/string-arg.wat index bc970113904..120d0f15af4 100644 --- a/crates/cli/tests/reference/string-arg.wat +++ b/crates/cli/tests/reference/string-arg.wat @@ -1,10 +1,10 @@ (module - (type (;0;) (func (param i32) (result i32))) - (type (;1;) (func (param i32 i32))) - (type (;2;) (func (param i32 i32 i32) (result i32))) - (func $__wbindgen_realloc (;0;) (type 2) (param i32 i32 i32) (result i32)) - (func $__wbindgen_malloc (;1;) (type 0) (param i32) (result i32)) - (func $foo (;2;) (type 1) (param i32 i32)) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (type (;2;) (func (param i32 i32 i32 i32) (result i32))) + (func $__wbindgen_realloc (;0;) (type 2) (param i32 i32 i32 i32) (result i32)) + (func $__wbindgen_malloc (;1;) (type 1) (param i32 i32) (result i32)) + (func $foo (;2;) (type 0) (param i32 i32)) (memory (;0;) 17) (export "memory" (memory 0)) (export "foo" (func $foo)) diff --git a/crates/threads-xform/src/lib.rs b/crates/threads-xform/src/lib.rs index 4cb5c2a57b7..3c861cbc80a 100644 --- a/crates/threads-xform/src/lib.rs +++ b/crates/threads-xform/src/lib.rs @@ -344,9 +344,10 @@ fn inject_start( // we give ourselves a stack and we update our stack // pointer as the default stack pointer is surely wrong for us. |body| { - // local = malloc(stack.size) [aka base] + // local = malloc(stack.size, align) [aka base] with_temp_stack(body, memory, stack, |body| { body.i32_const(stack.size as i32) + .i32_const(4) .call(malloc) .local_tee(local); }); @@ -368,7 +369,6 @@ fn inject_start( // Afterwards we need to initialize our thread-local state. body.i32_const(tls.size as i32) .i32_const(tls.align as i32) - .drop() // TODO: need to actually respect alignment .call(malloc) .global_set(tls.base) .global_get(tls.base) @@ -406,11 +406,13 @@ fn inject_destroy( |body| { body.local_get(tls_base) .i32_const(tls.size as i32) + .i32_const(tls.align as i32) .call(free); }, |body| { body.global_get(tls.base) .i32_const(tls.size as i32) + .i32_const(tls.align as i32) .call(free); // set tls.base = i32::MIN to trigger invalid memory @@ -425,12 +427,14 @@ fn inject_destroy( // we're destroying somebody else's stack, so we can use our own body.local_get(stack_alloc) .i32_const(stack.size as i32) + .i32_const(4) .call(free); }, |body| { with_temp_stack(body, memory, stack, |body| { body.global_get(stack.alloc) .i32_const(stack.size as i32) + .i32_const(4) .call(free); }); diff --git a/guide/src/contributing/design/exporting-rust.md b/guide/src/contributing/design/exporting-rust.md index 68ca5543068..a91829681b0 100644 --- a/guide/src/contributing/design/exporting-rust.md +++ b/guide/src/contributing/design/exporting-rust.md @@ -33,7 +33,7 @@ import * as wasm from './foo_bg'; function passStringToWasm(arg) { const buf = new TextEncoder('utf-8').encode(arg); const len = buf.length; - const ptr = wasm.__wbindgen_malloc(len); + const ptr = wasm.__wbindgen_malloc(len, 4); let array = new Uint8Array(wasm.memory.buffer); array.set(buf, ptr); return [ptr, len]; @@ -56,7 +56,7 @@ export function greet(arg0) { wasm.__wbindgen_boxed_str_free(ret); return realRet; } finally { - wasm.__wbindgen_free(ptr0, len0); + wasm.__wbindgen_free(ptr0, len0, 4); } } ``` diff --git a/src/lib.rs b/src/lib.rs index e14c6ffa174..fd2feae6f29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1566,11 +1566,9 @@ pub mod __rt { if_std! { use std::alloc::{alloc, dealloc, realloc, Layout}; - use std::mem; #[no_mangle] - pub extern "C" fn __wbindgen_malloc(size: usize) -> *mut u8 { - let align = mem::align_of::(); + pub extern "C" fn __wbindgen_malloc(size: usize, align: usize) -> *mut u8 { if let Ok(layout) = Layout::from_size_align(size, align) { unsafe { if layout.size() > 0 { @@ -1588,8 +1586,7 @@ pub mod __rt { } #[no_mangle] - pub unsafe extern "C" fn __wbindgen_realloc(ptr: *mut u8, old_size: usize, new_size: usize) -> *mut u8 { - let align = mem::align_of::(); + pub unsafe extern "C" fn __wbindgen_realloc(ptr: *mut u8, old_size: usize, new_size: usize, align: usize) -> *mut u8 { debug_assert!(old_size > 0); debug_assert!(new_size > 0); if let Ok(layout) = Layout::from_size_align(old_size, align) { @@ -1611,13 +1608,12 @@ pub mod __rt { } #[no_mangle] - pub unsafe extern "C" fn __wbindgen_free(ptr: *mut u8, size: usize) { + pub unsafe extern "C" fn __wbindgen_free(ptr: *mut u8, size: usize, align: usize) { // This happens for zero-length slices, and in that case `ptr` is // likely bogus so don't actually send this to the system allocator if size == 0 { return } - let align = mem::align_of::(); let layout = Layout::from_size_align_unchecked(size, align); dealloc(ptr, layout); } From 033a712342ca47a6a0d1d05792f3823c4bef1314 Mon Sep 17 00:00:00 2001 From: dAxpeDDa Date: Tue, 6 Jun 2023 11:02:06 +0200 Subject: [PATCH 2/4] Use smallest possible alignment Co-Authored-By: Liam Murphy <43807659+Liamolucko@users.noreply.github.com> --- crates/cli-support/src/js/binding.rs | 8 +++----- crates/cli-support/src/js/mod.rs | 10 +++++----- crates/cli/tests/reference/string-arg.js | 6 +++--- crates/threads-xform/src/lib.rs | 6 +++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/crates/cli-support/src/js/binding.rs b/crates/cli-support/src/js/binding.rs index e9dae127fe2..611c0508ecc 100644 --- a/crates/cli-support/src/js/binding.rs +++ b/crates/cli-support/src/js/binding.rs @@ -817,14 +817,12 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> let func = js.cx.pass_to_wasm_function(kind.clone(), *mem)?; let malloc = js.cx.export_name_of(*malloc); let i = js.tmp(); - let align = std::cmp::max(kind.size(), 4); js.prelude(&format!( - "const ptr{i} = {f}({0}, wasm.{malloc}, {align});", + "const ptr{i} = {f}({0}, wasm.{malloc});", val, i = i, f = func, malloc = malloc, - align = align, )); js.prelude(&format!("const len{} = WASM_VECTOR_LEN;", i)); js.push(format!("ptr{}", i)); @@ -928,7 +926,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> let malloc = js.cx.export_name_of(*malloc); let val = js.pop(); js.prelude(&format!( - "var ptr{i} = isLikeNone({0}) ? 0 : {f}({0}, wasm.{malloc}, 4);", + "var ptr{i} = isLikeNone({0}) ? 0 : {f}({0}, wasm.{malloc});", val, i = i, f = func, @@ -946,7 +944,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> let malloc = js.cx.export_name_of(*malloc); let i = js.tmp(); js.prelude(&format!( - "var ptr{i} = {f}({val}, wasm.{malloc}, 4);", + "var ptr{i} = {f}({val}, wasm.{malloc});", val = val, i = i, f = func, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index efe43b5b14d..56847262544 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -1259,14 +1259,14 @@ impl<'a> Context<'a> { "\ if (realloc === undefined) {{ const buf = cachedTextEncoder.encode(arg); - const ptr = malloc(buf.length, 4) >>> 0; + const ptr = malloc(buf.length, 1) >>> 0; {mem}().subarray(ptr, ptr + buf.length).set(buf); WASM_VECTOR_LEN = buf.length; return ptr; }} let len = arg.length; - let ptr = malloc(len, 4) >>> 0; + let ptr = malloc(len, 1) >>> 0; const mem = {mem}(); @@ -1294,7 +1294,7 @@ impl<'a> Context<'a> { if (offset !== 0) {{ arg = arg.slice(offset); }} - ptr = realloc(ptr, len, len = offset + arg.length * 3, 4) >>> 0; + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; const view = {mem}().subarray(ptr + offset, ptr + len); const ret = encodeString(arg, view); {debug_end} @@ -1415,8 +1415,8 @@ impl<'a> Context<'a> { self.expose_wasm_vector_len(); self.global(&format!( " - function {}(arg, malloc, align) {{ - const ptr = malloc(arg.length * {size}, align) >>> 0; + function {}(arg, malloc) {{ + const ptr = malloc(arg.length * {size}, {size}) >>> 0; {}().set(arg, ptr / {size}); WASM_VECTOR_LEN = arg.length; return ptr; diff --git a/crates/cli/tests/reference/string-arg.js b/crates/cli/tests/reference/string-arg.js index 62d74ddd171..8c006997f9d 100644 --- a/crates/cli/tests/reference/string-arg.js +++ b/crates/cli/tests/reference/string-arg.js @@ -47,14 +47,14 @@ function passStringToWasm0(arg, malloc, realloc) { if (realloc === undefined) { const buf = cachedTextEncoder.encode(arg); - const ptr = malloc(buf.length, 4) >>> 0; + const ptr = malloc(buf.length, 1) >>> 0; getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); WASM_VECTOR_LEN = buf.length; return ptr; } let len = arg.length; - let ptr = malloc(len, 4) >>> 0; + let ptr = malloc(len, 1) >>> 0; const mem = getUint8Memory0(); @@ -70,7 +70,7 @@ function passStringToWasm0(arg, malloc, realloc) { if (offset !== 0) { arg = arg.slice(offset); } - ptr = realloc(ptr, len, len = offset + arg.length * 3, 4) >>> 0; + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; const view = getUint8Memory0().subarray(ptr + offset, ptr + len); const ret = encodeString(arg, view); diff --git a/crates/threads-xform/src/lib.rs b/crates/threads-xform/src/lib.rs index 3c861cbc80a..29e5aa35804 100644 --- a/crates/threads-xform/src/lib.rs +++ b/crates/threads-xform/src/lib.rs @@ -347,7 +347,7 @@ fn inject_start( // local = malloc(stack.size, align) [aka base] with_temp_stack(body, memory, stack, |body| { body.i32_const(stack.size as i32) - .i32_const(4) + .i32_const(16) .call(malloc) .local_tee(local); }); @@ -427,14 +427,14 @@ fn inject_destroy( // we're destroying somebody else's stack, so we can use our own body.local_get(stack_alloc) .i32_const(stack.size as i32) - .i32_const(4) + .i32_const(16) .call(free); }, |body| { with_temp_stack(body, memory, stack, |body| { body.global_get(stack.alloc) .i32_const(stack.size as i32) - .i32_const(4) + .i32_const(16) .call(free); }); From 0ba5241d7809f85f6b8b069231c5774d25c7fd74 Mon Sep 17 00:00:00 2001 From: dAxpeDDa Date: Tue, 6 Jun 2023 11:32:39 +0200 Subject: [PATCH 3/4] Rework `DeferCallCore` to `DeferFree` Co-Authored-By: Liam Murphy <43807659+Liamolucko@users.noreply.github.com> --- crates/cli-support/src/js/binding.rs | 18 +++++++++++------- crates/cli-support/src/wit/outgoing.rs | 6 +++--- crates/cli-support/src/wit/standard.rs | 7 +++++-- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/crates/cli-support/src/js/binding.rs b/crates/cli-support/src/js/binding.rs index 611c0508ecc..fdb0a0b01f9 100644 --- a/crates/cli-support/src/js/binding.rs +++ b/crates/cli-support/src/js/binding.rs @@ -548,15 +548,17 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> | Instruction::CallExport(_) | Instruction::CallAdapter(_) | Instruction::CallTableElement(_) - | Instruction::DeferCallCore(_) => { + | Instruction::DeferFree { .. } => { let invoc = Invocation::from(instr, js.cx.module)?; let (mut params, results) = invoc.params_results(js.cx); let mut args = Vec::new(); let tmp = js.tmp(); if invoc.defer() { - // substract alignment - params -= 1; + if let Instruction::DeferFree { .. } = instr { + // substract alignment + params -= 1; + } // If the call is deferred, the arguments to the function still need to be // accessible in the `finally` block, so we declare variables to hold the args // outside of the try-finally block and then set those to the args. @@ -566,8 +568,10 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> writeln!(js.prelude, "{name} = {arg};").unwrap(); args.push(name); } - // add alignment - args.push(String::from("4")); + if let Instruction::DeferFree { align, .. } = instr { + // add alignment + args.push(align.to_string()); + } } else { // Otherwise, pop off the number of parameters for the function we're calling. for _ in 0..params { @@ -1194,8 +1198,8 @@ impl Invocation { defer: false, }, - DeferCallCore(f) => Invocation::Core { - id: *f, + DeferFree { free, .. } => Invocation::Core { + id: *free, defer: true, }, diff --git a/crates/cli-support/src/wit/outgoing.rs b/crates/cli-support/src/wit/outgoing.rs index 890b79b2fb0..506d34d92fd 100644 --- a/crates/cli-support/src/wit/outgoing.rs +++ b/crates/cli-support/src/wit/outgoing.rs @@ -105,7 +105,7 @@ impl InstructionBuilder<'_, '_> { // ... then defer a call to `free` to happen later let free = self.cx.free()?; self.instructions.push(InstructionData { - instr: Instruction::DeferCallCore(free), + instr: Instruction::DeferFree { free, align: 4 }, stack_change: StackChange::Modified { popped: 2, pushed: 2, @@ -389,7 +389,7 @@ impl InstructionBuilder<'_, '_> { // special case it. assert!(!self.instructions[len..] .iter() - .any(|idata| matches!(idata.instr, Instruction::DeferCallCore(_)))); + .any(|idata| matches!(idata.instr, Instruction::DeferFree { .. }))); // Finally, we add the two inputs to UnwrapResult, and everything checks out // @@ -429,7 +429,7 @@ impl InstructionBuilder<'_, '_> { // implementation. let free = self.cx.free()?; self.instructions.push(InstructionData { - instr: Instruction::DeferCallCore(free), + instr: Instruction::DeferFree { free, align: 4 }, stack_change: StackChange::Modified { popped: 2, pushed: 2, diff --git a/crates/cli-support/src/wit/standard.rs b/crates/cli-support/src/wit/standard.rs index 953fbfa5688..ba29a75e417 100644 --- a/crates/cli-support/src/wit/standard.rs +++ b/crates/cli-support/src/wit/standard.rs @@ -95,7 +95,10 @@ pub enum Instruction { CallCore(walrus::FunctionId), /// Schedules a function to be called after the whole lift/lower cycle is /// finished, e.g. to deallocate a string or something. - DeferCallCore(walrus::FunctionId), + DeferFree { + free: walrus::FunctionId, + align: usize, + }, /// A call to one of our own defined adapters, similar to the standard /// call-adapter instruction CallAdapter(AdapterId), @@ -423,7 +426,7 @@ impl walrus::CustomSection for NonstandardWitSection { }; for instr in instrs { match instr.instr { - DeferCallCore(f) | CallCore(f) => { + DeferFree { free: f, .. } | CallCore(f) => { roots.push_func(f); } StoreRetptr { mem, .. } From 750eccc87ca4d9575f3a137afb2bd2cd5e66c94d Mon Sep 17 00:00:00 2001 From: dAxpeDDa Date: Tue, 6 Jun 2023 13:56:28 +0200 Subject: [PATCH 4/4] Address review Co-Authored-By: Liam Murphy <43807659+Liamolucko@users.noreply.github.com> --- crates/cli-support/src/js/binding.rs | 2 +- crates/cli-support/src/wit/outgoing.rs | 4 ++-- crates/cli-support/src/wit/standard.rs | 3 +-- crates/cli/tests/reference/result-string.js | 2 +- guide/src/contributing/design/exporting-rust.md | 4 ++-- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/crates/cli-support/src/js/binding.rs b/crates/cli-support/src/js/binding.rs index fdb0a0b01f9..83a04f92fb6 100644 --- a/crates/cli-support/src/js/binding.rs +++ b/crates/cli-support/src/js/binding.rs @@ -556,7 +556,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> let tmp = js.tmp(); if invoc.defer() { if let Instruction::DeferFree { .. } = instr { - // substract alignment + // Ignore `free`'s final `align` argument, since that's manually inserted later. params -= 1; } // If the call is deferred, the arguments to the function still need to be diff --git a/crates/cli-support/src/wit/outgoing.rs b/crates/cli-support/src/wit/outgoing.rs index 506d34d92fd..d90dcd3f5ee 100644 --- a/crates/cli-support/src/wit/outgoing.rs +++ b/crates/cli-support/src/wit/outgoing.rs @@ -105,7 +105,7 @@ impl InstructionBuilder<'_, '_> { // ... then defer a call to `free` to happen later let free = self.cx.free()?; self.instructions.push(InstructionData { - instr: Instruction::DeferFree { free, align: 4 }, + instr: Instruction::DeferFree { free, align: 1 }, stack_change: StackChange::Modified { popped: 2, pushed: 2, @@ -429,7 +429,7 @@ impl InstructionBuilder<'_, '_> { // implementation. let free = self.cx.free()?; self.instructions.push(InstructionData { - instr: Instruction::DeferFree { free, align: 4 }, + instr: Instruction::DeferFree { free, align: 1 }, stack_change: StackChange::Modified { popped: 2, pushed: 2, diff --git a/crates/cli-support/src/wit/standard.rs b/crates/cli-support/src/wit/standard.rs index ba29a75e417..5a771d59675 100644 --- a/crates/cli-support/src/wit/standard.rs +++ b/crates/cli-support/src/wit/standard.rs @@ -93,8 +93,7 @@ pub enum AdapterType { pub enum Instruction { /// Calls a function by its id. CallCore(walrus::FunctionId), - /// Schedules a function to be called after the whole lift/lower cycle is - /// finished, e.g. to deallocate a string or something. + /// Call the deallocation function. DeferFree { free: walrus::FunctionId, align: usize, diff --git a/crates/cli/tests/reference/result-string.js b/crates/cli/tests/reference/result-string.js index 95aa113dad3..a0795b44d4d 100644 --- a/crates/cli/tests/reference/result-string.js +++ b/crates/cli/tests/reference/result-string.js @@ -85,7 +85,7 @@ export function exported() { return getStringFromWasm0(ptr1, len1); } finally { wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(deferred2_0, deferred2_1, 4); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); } } diff --git a/guide/src/contributing/design/exporting-rust.md b/guide/src/contributing/design/exporting-rust.md index a91829681b0..58491b34d4a 100644 --- a/guide/src/contributing/design/exporting-rust.md +++ b/guide/src/contributing/design/exporting-rust.md @@ -33,7 +33,7 @@ import * as wasm from './foo_bg'; function passStringToWasm(arg) { const buf = new TextEncoder('utf-8').encode(arg); const len = buf.length; - const ptr = wasm.__wbindgen_malloc(len, 4); + const ptr = wasm.__wbindgen_malloc(len, 1); let array = new Uint8Array(wasm.memory.buffer); array.set(buf, ptr); return [ptr, len]; @@ -56,7 +56,7 @@ export function greet(arg0) { wasm.__wbindgen_boxed_str_free(ret); return realRet; } finally { - wasm.__wbindgen_free(ptr0, len0, 4); + wasm.__wbindgen_free(ptr0, len0, 1); } } ```