diff --git a/crates/wasm-bindgen-cli-support/Cargo.toml b/crates/wasm-bindgen-cli-support/Cargo.toml index e4a60230..190e15fe 100644 --- a/crates/wasm-bindgen-cli-support/Cargo.toml +++ b/crates/wasm-bindgen-cli-support/Cargo.toml @@ -4,8 +4,9 @@ version = "0.1.0" authors = ["Alex Crichton "] [dependencies] -parity-wasm = "0.23" -failure = "0.1" -wasm-bindgen-shared = { path = "../wasm-bindgen-shared" } -serde_json = "1.0" base64 = "0.9" +failure = "0.1" +parity-wasm = "0.23" +serde_json = "1.0" +wasm-bindgen-shared = { path = "../wasm-bindgen-shared" } +wasm-gc-api = "0.1" diff --git a/crates/wasm-bindgen-cli-support/src/js.rs b/crates/wasm-bindgen-cli-support/src/js.rs index f48cbd01..b337dd62 100644 --- a/crates/wasm-bindgen-cli-support/src/js.rs +++ b/crates/wasm-bindgen-cli-support/src/js.rs @@ -10,6 +10,7 @@ pub struct Js<'a> { pub imports: String, pub typescript: String, pub exposed_globals: HashSet<&'static str>, + pub required_internal_exports: HashSet<&'static str>, pub config: &'a Bindgen, pub module: &'a mut Module, pub program: &'a shared::Program, @@ -188,6 +189,7 @@ impl<'a> Js<'a> { ); self.rewrite_imports(module_name); + self.unexport_unused_internal_exports(); (js, self.typescript.clone()) } @@ -343,6 +345,7 @@ impl<'a> Js<'a> { destructors.push_str(&format!("\n\ wasm.__wbindgen_free(ptr{i}, len{i});\n\ ", i = i)); + self.required_internal_exports.insert("__wbindgen_free"); } } shared::TYPE_JS_OWNED => { @@ -416,6 +419,9 @@ impl<'a> Js<'a> { Some(&shared::TYPE_STRING) => { dst_ts.push_str(": string"); self.expose_get_string_from_wasm(); + self.required_internal_exports.insert("__wbindgen_boxed_str_ptr"); + self.required_internal_exports.insert("__wbindgen_boxed_str_len"); + self.required_internal_exports.insert("__wbindgen_boxed_str_free"); format!(" const ptr = wasm.__wbindgen_boxed_str_ptr(ret); const len = wasm.__wbindgen_boxed_str_len(ret); @@ -567,6 +573,7 @@ impl<'a> Js<'a> { wasm.__wbindgen_free(ptr{0}, len{0}); ", i)); invocation.push_str(&format!("arg{}", i)); + self.required_internal_exports.insert("__wbindgen_free"); } shared::TYPE_JS_OWNED => { self.expose_take_object(); @@ -666,6 +673,20 @@ impl<'a> Js<'a> { } } + fn unexport_unused_internal_exports(&mut self) { + let required = &self.required_internal_exports; + for section in self.module.sections_mut() { + let exports = match *section { + Section::Export(ref mut s) => s, + _ => continue, + }; + exports.entries_mut().retain(|export| { + !export.field().starts_with("__wbindgen") || + required.contains(export.field()) + }); + } + } + fn expose_drop_ref(&mut self) { if !self.exposed_globals.insert("drop_ref") { return @@ -805,6 +826,7 @@ impl<'a> Js<'a> { if !self.exposed_globals.insert("pass_string_to_wasm") { return } + self.required_internal_exports.insert("__wbindgen_malloc"); if self.config.nodejs { self.globals.push_str(&format!(" function passStringToWasm(arg) {{ diff --git a/crates/wasm-bindgen-cli-support/src/lib.rs b/crates/wasm-bindgen-cli-support/src/lib.rs index f9a17fcf..3ff1768c 100644 --- a/crates/wasm-bindgen-cli-support/src/lib.rs +++ b/crates/wasm-bindgen-cli-support/src/lib.rs @@ -3,6 +3,7 @@ extern crate failure; extern crate parity_wasm; extern crate wasm_bindgen_shared as shared; extern crate serde_json; +extern crate wasm_gc; use std::fs::File; use std::io::Write; @@ -71,6 +72,7 @@ impl Bindgen { imports: String::new(), typescript: format!("/* tslint:disable */\n"), exposed_globals: Default::default(), + required_internal_exports: Default::default(), config: &self, module: &mut module, program: &program, @@ -87,9 +89,13 @@ impl Bindgen { } let wasm_path = out_dir.join(format!("{}_wasm", stem)).with_extension("wasm"); - parity_wasm::serialize_to_file(wasm_path, module).map_err(|e| { + let wasm_bytes = parity_wasm::serialize(module).map_err(|e| { format_err!("{:?}", e) })?; + let bytes = wasm_gc::Config::new() + .demangle(false) + .gc(&wasm_bytes)?; + File::create(&wasm_path)?.write_all(&bytes)?; Ok(()) } } diff --git a/crates/wasm-bindgen-macro/src/lib.rs b/crates/wasm-bindgen-macro/src/lib.rs index aa13a41b..40c8ffe8 100644 --- a/crates/wasm-bindgen-macro/src/lib.rs +++ b/crates/wasm-bindgen-macro/src/lib.rs @@ -23,9 +23,6 @@ macro_rules! my_quote { mod ast; -static MALLOC_GENERATED: AtomicBool = ATOMIC_BOOL_INIT; -static BOXED_STR_GENERATED: AtomicBool = ATOMIC_BOOL_INIT; - #[proc_macro] pub fn wasm_bindgen(input: TokenStream) -> TokenStream { // Parse the input as a list of Rust items, reusing the `syn::File` parser. @@ -214,9 +211,6 @@ fn bindgen(export_name: &syn::LitStr, let mut converted_arguments = vec![]; let ret = syn::Ident::from("_ret"); - let mut malloc = false; - let mut boxed_str = false; - let mut offset = 0; if let Receiver::StructMethod(class, _, _) = receiver { args.push(my_quote! { me: *mut ::wasm_bindgen::__rt::WasmRefCell<#class> }); @@ -232,7 +226,6 @@ fn bindgen(export_name: &syn::LitStr, let ident = syn::Ident::from(format!("arg{}", i)); match *ty { ast::Type::BorrowedStr => { - malloc = malloc || !MALLOC_GENERATED.swap(true, Ordering::SeqCst); let ptr = syn::Ident::from(format!("arg{}_ptr", i)); let len = syn::Ident::from(format!("arg{}_len", i)); args.push(my_quote! { #ptr: *const u8 }); @@ -245,7 +238,6 @@ fn bindgen(export_name: &syn::LitStr, }); } ast::Type::String => { - malloc = malloc || !MALLOC_GENERATED.swap(true, Ordering::SeqCst); let ptr = syn::Ident::from(format!("arg{}_ptr", i)); let len = syn::Ident::from(format!("arg{}_len", i)); args.push(my_quote! { #ptr: *mut u8 }); @@ -299,7 +291,6 @@ fn bindgen(export_name: &syn::LitStr, let convert_ret; match ret_type { Some(&ast::Type::String) => { - boxed_str = !BOXED_STR_GENERATED.swap(true, Ordering::SeqCst); ret_ty = my_quote! { -> *mut String }; convert_ret = my_quote! { Box::into_raw(Box::new(#ret)) }; } @@ -322,65 +313,7 @@ fn bindgen(export_name: &syn::LitStr, } } - // TODO: move this function into wasm-bindgen-the-crate and then gc it out - // if it's not used. - let malloc = if malloc { - my_quote! { - #[no_mangle] - pub extern fn __wbindgen_malloc(size: usize) -> *mut u8 { - // Any malloc request this big is bogus anyway. If this actually - // goes down to `Vec` we trigger a whole bunch of panicking - // machinery to get pulled in from libstd anyway as it'll verify - // the size passed in below. - // - // Head this all off by just aborting on too-big sizes. This - // avoids panicking (code bloat) and gives a better error - // message too hopefully. - if size >= usize::max_value() / 2 { - ::wasm_bindgen::throw("invalid malloc request"); - } - let mut ret = Vec::with_capacity(size); - let ptr = ret.as_mut_ptr(); - ::std::mem::forget(ret); - return ptr - } - - #[no_mangle] - pub unsafe extern fn __wbindgen_free(ptr: *mut u8, size: usize) { - drop(Vec::::from_raw_parts(ptr, 0, size)); - } - } - } else { - my_quote! { - } - }; - - let boxed_str = if boxed_str { - my_quote! { - #[no_mangle] - pub unsafe extern fn __wbindgen_boxed_str_len(ptr: *mut String) -> usize { - (*ptr).len() - } - - #[no_mangle] - pub unsafe extern fn __wbindgen_boxed_str_ptr(ptr: *mut String) -> *const u8 { - (*ptr).as_ptr() - } - - #[no_mangle] - pub unsafe extern fn __wbindgen_boxed_str_free(ptr: *mut String) { - drop(Box::from_raw(ptr)); - } - } - } else { - my_quote! { - } - }; - let tokens = my_quote! { - #malloc - #boxed_str - #[export_name = #export_name] #[allow(non_snake_case)] pub extern fn #generated_name(#(#args),*) #ret_ty { diff --git a/crates/wasm-bindgen-shared/src/lib.rs b/crates/wasm-bindgen-shared/src/lib.rs index 3fe957c7..fcfdf77e 100644 --- a/crates/wasm-bindgen-shared/src/lib.rs +++ b/crates/wasm-bindgen-shared/src/lib.rs @@ -90,25 +90,3 @@ pub const TYPE_JS_REF: char = '\u{63}'; pub const TYPE_CUSTOM_START: u32 = 0x64; pub const TYPE_CUSTOM_REF_FLAG: u32 = 1; - -// #[derive(Serialize, Deserialize)] -// pub enum Type { -// Number, -// BorrowedStr, -// String, -// ByValue(String), // wrapper class -// ByRef(String), // wrapper class -// ByMutRef(String), // wrapper class -// JsObject, -// JsObjectRef, -// Boolean, -// } - -// impl Type { -// pub fn is_number(&self) -> bool { -// match *self { -// Type::Number => true, -// _ => false, -// } -// } -// } diff --git a/src/lib.rs b/src/lib.rs index 812d4959..b4326f7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -261,6 +261,7 @@ pub fn throw(s: &str) -> ! { #[doc(hidden)] pub mod __rt { use std::cell::{Cell, UnsafeCell}; + use std::mem; use std::ops::{Deref, DerefMut}; #[inline] @@ -394,4 +395,43 @@ pub mod __rt { super::throw("recursive use of an object detected which would lead to \ unsafe aliasing in rust"); } + + #[no_mangle] + pub extern fn __wbindgen_malloc(size: usize) -> *mut u8 { + // Any malloc request this big is bogus anyway. If this actually + // goes down to `Vec` we trigger a whole bunch of panicking + // machinery to get pulled in from libstd anyway as it'll verify + // the size passed in below. + // + // Head this all off by just aborting on too-big sizes. This + // avoids panicking (code bloat) and gives a better error + // message too hopefully. + if size >= usize::max_value() / 2 { + super::throw("invalid malloc request"); + } + let mut ret = Vec::with_capacity(size); + let ptr = ret.as_mut_ptr(); + mem::forget(ret); + return ptr + } + + #[no_mangle] + pub unsafe extern fn __wbindgen_free(ptr: *mut u8, size: usize) { + drop(Vec::::from_raw_parts(ptr, 0, size)); + } + + #[no_mangle] + pub unsafe extern fn __wbindgen_boxed_str_len(ptr: *mut String) -> usize { + (*ptr).len() + } + + #[no_mangle] + pub unsafe extern fn __wbindgen_boxed_str_ptr(ptr: *mut String) -> *const u8 { + (*ptr).as_ptr() + } + + #[no_mangle] + pub unsafe extern fn __wbindgen_boxed_str_free(ptr: *mut String) { + drop(Box::from_raw(ptr)); + } } diff --git a/tests/import-class.rs b/tests/import-class.rs index bf0b4dd3..0cc89c8e 100644 --- a/tests/import-class.rs +++ b/tests/import-class.rs @@ -92,11 +92,16 @@ fn construct() { #[wasm_module = "./test"] extern struct Foo { fn create() -> Foo; - fn doit(&self); + fn get_internal_string(&self) -> String; + fn append_to_internal_string(&self, s: &str); + fn assert_internal_string(&self, s: &str); } - pub fn bar() { - Foo::create().doit(); + pub fn run() { + let f = Foo::create(); + assert_eq!(f.get_internal_string(), "this"); + f.append_to_internal_string(" foo"); + f.assert_internal_string("this foo"); } } "#) @@ -107,22 +112,30 @@ fn construct() { let called = false; export class Foo { - private random_property: string = ''; + private internal_string: string = ''; static create() { const ret = new Foo(); - ret.random_property = 'this'; + ret.internal_string = 'this'; return ret; } - doit() { - assert.strictEqual(this.random_property, 'this'); + get_internal_string() { + return this.internal_string; + } + + append_to_internal_string(s: string) { + this.internal_string += s; + } + + assert_internal_string(s: string) { + assert.strictEqual(this.internal_string, s); called = true; } } export function test() { - wasm.bar(); + wasm.run(); assert.strictEqual(called, true); } "#)