mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 02:00:51 +00:00
Fix some class import methods and auto gc
The runtime functions are now moved to the `wasm-bindgen` crate and are auto-gc'd if they don't end up actually being required.
This commit is contained in:
parent
28966d9853
commit
56b7fa453a
@ -4,8 +4,9 @@ version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
|
||||
[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"
|
||||
|
@ -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) {{
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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::<u8>::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 {
|
||||
|
@ -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,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
40
src/lib.rs
40
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::<u8>::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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
"#)
|
||||
|
Loading…
x
Reference in New Issue
Block a user