mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-31 01:11:06 +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>"]
|
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parity-wasm = "0.23"
|
|
||||||
failure = "0.1"
|
|
||||||
wasm-bindgen-shared = { path = "../wasm-bindgen-shared" }
|
|
||||||
serde_json = "1.0"
|
|
||||||
base64 = "0.9"
|
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 imports: String,
|
||||||
pub typescript: String,
|
pub typescript: String,
|
||||||
pub exposed_globals: HashSet<&'static str>,
|
pub exposed_globals: HashSet<&'static str>,
|
||||||
|
pub required_internal_exports: HashSet<&'static str>,
|
||||||
pub config: &'a Bindgen,
|
pub config: &'a Bindgen,
|
||||||
pub module: &'a mut Module,
|
pub module: &'a mut Module,
|
||||||
pub program: &'a shared::Program,
|
pub program: &'a shared::Program,
|
||||||
@ -188,6 +189,7 @@ impl<'a> Js<'a> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
self.rewrite_imports(module_name);
|
self.rewrite_imports(module_name);
|
||||||
|
self.unexport_unused_internal_exports();
|
||||||
|
|
||||||
(js, self.typescript.clone())
|
(js, self.typescript.clone())
|
||||||
}
|
}
|
||||||
@ -343,6 +345,7 @@ impl<'a> Js<'a> {
|
|||||||
destructors.push_str(&format!("\n\
|
destructors.push_str(&format!("\n\
|
||||||
wasm.__wbindgen_free(ptr{i}, len{i});\n\
|
wasm.__wbindgen_free(ptr{i}, len{i});\n\
|
||||||
", i = i));
|
", i = i));
|
||||||
|
self.required_internal_exports.insert("__wbindgen_free");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shared::TYPE_JS_OWNED => {
|
shared::TYPE_JS_OWNED => {
|
||||||
@ -416,6 +419,9 @@ impl<'a> Js<'a> {
|
|||||||
Some(&shared::TYPE_STRING) => {
|
Some(&shared::TYPE_STRING) => {
|
||||||
dst_ts.push_str(": string");
|
dst_ts.push_str(": string");
|
||||||
self.expose_get_string_from_wasm();
|
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!("
|
format!("
|
||||||
const ptr = wasm.__wbindgen_boxed_str_ptr(ret);
|
const ptr = wasm.__wbindgen_boxed_str_ptr(ret);
|
||||||
const len = wasm.__wbindgen_boxed_str_len(ret);
|
const len = wasm.__wbindgen_boxed_str_len(ret);
|
||||||
@ -567,6 +573,7 @@ impl<'a> Js<'a> {
|
|||||||
wasm.__wbindgen_free(ptr{0}, len{0});
|
wasm.__wbindgen_free(ptr{0}, len{0});
|
||||||
", i));
|
", i));
|
||||||
invocation.push_str(&format!("arg{}", i));
|
invocation.push_str(&format!("arg{}", i));
|
||||||
|
self.required_internal_exports.insert("__wbindgen_free");
|
||||||
}
|
}
|
||||||
shared::TYPE_JS_OWNED => {
|
shared::TYPE_JS_OWNED => {
|
||||||
self.expose_take_object();
|
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) {
|
fn expose_drop_ref(&mut self) {
|
||||||
if !self.exposed_globals.insert("drop_ref") {
|
if !self.exposed_globals.insert("drop_ref") {
|
||||||
return
|
return
|
||||||
@ -805,6 +826,7 @@ impl<'a> Js<'a> {
|
|||||||
if !self.exposed_globals.insert("pass_string_to_wasm") {
|
if !self.exposed_globals.insert("pass_string_to_wasm") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
self.required_internal_exports.insert("__wbindgen_malloc");
|
||||||
if self.config.nodejs {
|
if self.config.nodejs {
|
||||||
self.globals.push_str(&format!("
|
self.globals.push_str(&format!("
|
||||||
function passStringToWasm(arg) {{
|
function passStringToWasm(arg) {{
|
||||||
|
@ -3,6 +3,7 @@ extern crate failure;
|
|||||||
extern crate parity_wasm;
|
extern crate parity_wasm;
|
||||||
extern crate wasm_bindgen_shared as shared;
|
extern crate wasm_bindgen_shared as shared;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
extern crate wasm_gc;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -71,6 +72,7 @@ impl Bindgen {
|
|||||||
imports: String::new(),
|
imports: String::new(),
|
||||||
typescript: format!("/* tslint:disable */\n"),
|
typescript: format!("/* tslint:disable */\n"),
|
||||||
exposed_globals: Default::default(),
|
exposed_globals: Default::default(),
|
||||||
|
required_internal_exports: Default::default(),
|
||||||
config: &self,
|
config: &self,
|
||||||
module: &mut module,
|
module: &mut module,
|
||||||
program: &program,
|
program: &program,
|
||||||
@ -87,9 +89,13 @@ impl Bindgen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let wasm_path = out_dir.join(format!("{}_wasm", stem)).with_extension("wasm");
|
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)
|
format_err!("{:?}", e)
|
||||||
})?;
|
})?;
|
||||||
|
let bytes = wasm_gc::Config::new()
|
||||||
|
.demangle(false)
|
||||||
|
.gc(&wasm_bytes)?;
|
||||||
|
File::create(&wasm_path)?.write_all(&bytes)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,6 @@ macro_rules! my_quote {
|
|||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
|
|
||||||
static MALLOC_GENERATED: AtomicBool = ATOMIC_BOOL_INIT;
|
|
||||||
static BOXED_STR_GENERATED: AtomicBool = ATOMIC_BOOL_INIT;
|
|
||||||
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
||||||
// Parse the input as a list of Rust items, reusing the `syn::File` parser.
|
// 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 mut converted_arguments = vec![];
|
||||||
let ret = syn::Ident::from("_ret");
|
let ret = syn::Ident::from("_ret");
|
||||||
|
|
||||||
let mut malloc = false;
|
|
||||||
let mut boxed_str = false;
|
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
if let Receiver::StructMethod(class, _, _) = receiver {
|
if let Receiver::StructMethod(class, _, _) = receiver {
|
||||||
args.push(my_quote! { me: *mut ::wasm_bindgen::__rt::WasmRefCell<#class> });
|
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));
|
let ident = syn::Ident::from(format!("arg{}", i));
|
||||||
match *ty {
|
match *ty {
|
||||||
ast::Type::BorrowedStr => {
|
ast::Type::BorrowedStr => {
|
||||||
malloc = malloc || !MALLOC_GENERATED.swap(true, Ordering::SeqCst);
|
|
||||||
let ptr = syn::Ident::from(format!("arg{}_ptr", i));
|
let ptr = syn::Ident::from(format!("arg{}_ptr", i));
|
||||||
let len = syn::Ident::from(format!("arg{}_len", i));
|
let len = syn::Ident::from(format!("arg{}_len", i));
|
||||||
args.push(my_quote! { #ptr: *const u8 });
|
args.push(my_quote! { #ptr: *const u8 });
|
||||||
@ -245,7 +238,6 @@ fn bindgen(export_name: &syn::LitStr,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
ast::Type::String => {
|
ast::Type::String => {
|
||||||
malloc = malloc || !MALLOC_GENERATED.swap(true, Ordering::SeqCst);
|
|
||||||
let ptr = syn::Ident::from(format!("arg{}_ptr", i));
|
let ptr = syn::Ident::from(format!("arg{}_ptr", i));
|
||||||
let len = syn::Ident::from(format!("arg{}_len", i));
|
let len = syn::Ident::from(format!("arg{}_len", i));
|
||||||
args.push(my_quote! { #ptr: *mut u8 });
|
args.push(my_quote! { #ptr: *mut u8 });
|
||||||
@ -299,7 +291,6 @@ fn bindgen(export_name: &syn::LitStr,
|
|||||||
let convert_ret;
|
let convert_ret;
|
||||||
match ret_type {
|
match ret_type {
|
||||||
Some(&ast::Type::String) => {
|
Some(&ast::Type::String) => {
|
||||||
boxed_str = !BOXED_STR_GENERATED.swap(true, Ordering::SeqCst);
|
|
||||||
ret_ty = my_quote! { -> *mut String };
|
ret_ty = my_quote! { -> *mut String };
|
||||||
convert_ret = my_quote! { Box::into_raw(Box::new(#ret)) };
|
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! {
|
let tokens = my_quote! {
|
||||||
#malloc
|
|
||||||
#boxed_str
|
|
||||||
|
|
||||||
#[export_name = #export_name]
|
#[export_name = #export_name]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub extern fn #generated_name(#(#args),*) #ret_ty {
|
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_START: u32 = 0x64;
|
||||||
pub const TYPE_CUSTOM_REF_FLAG: u32 = 1;
|
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)]
|
#[doc(hidden)]
|
||||||
pub mod __rt {
|
pub mod __rt {
|
||||||
use std::cell::{Cell, UnsafeCell};
|
use std::cell::{Cell, UnsafeCell};
|
||||||
|
use std::mem;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -394,4 +395,43 @@ pub mod __rt {
|
|||||||
super::throw("recursive use of an object detected which would lead to \
|
super::throw("recursive use of an object detected which would lead to \
|
||||||
unsafe aliasing in rust");
|
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"]
|
#[wasm_module = "./test"]
|
||||||
extern struct Foo {
|
extern struct Foo {
|
||||||
fn create() -> 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() {
|
pub fn run() {
|
||||||
Foo::create().doit();
|
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;
|
let called = false;
|
||||||
|
|
||||||
export class Foo {
|
export class Foo {
|
||||||
private random_property: string = '';
|
private internal_string: string = '';
|
||||||
|
|
||||||
static create() {
|
static create() {
|
||||||
const ret = new Foo();
|
const ret = new Foo();
|
||||||
ret.random_property = 'this';
|
ret.internal_string = 'this';
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
doit() {
|
get_internal_string() {
|
||||||
assert.strictEqual(this.random_property, 'this');
|
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;
|
called = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function test() {
|
export function test() {
|
||||||
wasm.bar();
|
wasm.run();
|
||||||
assert.strictEqual(called, true);
|
assert.strictEqual(called, true);
|
||||||
}
|
}
|
||||||
"#)
|
"#)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user