diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 008884a4..a2444e32 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -82,9 +82,6 @@ pub struct Variant { } pub enum Type { - // special - Vector(VectorType, bool), - ByRef(syn::Type), ByMutRef(syn::Type), ByValue(syn::Type), @@ -320,7 +317,6 @@ impl Program { let class = match *class { Type::ByRef(ref t) | Type::ByValue(ref t) => t, Type::ByMutRef(_) => panic!("first method argument cannot be mutable ref"), - Type::Vector(..) => panic!("method receivers cannot be vectors"), }; let class_name = match *class { syn::Type::Path(syn::TypePath { @@ -505,61 +501,13 @@ pub fn extract_path_ident(path: &syn::Path) -> Option { impl Type { pub fn from(ty: &syn::Type) -> Type { - match *ty { - syn::Type::Reference(ref r) => { - match *r.elem { - syn::Type::Path(syn::TypePath { - qself: None, - ref path, - }) => { - let ident = extract_path_ident(path); - match ident.as_ref().map(|s| s.as_ref()) { - Some("str") => return Type::Vector(VectorType::String, false), - _ => {} - } - } - syn::Type::Slice(ref slice) => { - if let Some(ty) = VectorType::from(&slice.elem) { - return Type::Vector(ty, false); - } - } - _ => {} - } - return if r.mutability.is_some() { - Type::ByMutRef((*r.elem).clone()) - } else { - Type::ByRef((*r.elem).clone()) - }; + if let syn::Type::Reference(ref r) = *ty { + return if r.mutability.is_some() { + Type::ByMutRef((*r.elem).clone()) + } else { + Type::ByRef((*r.elem).clone()) } - syn::Type::Path(syn::TypePath { - qself: None, - ref path, - }) if path.leading_colon.is_none() && path.segments.len() == 1 => - { - let seg = path.segments.first().unwrap().into_value(); - match seg.arguments { - syn::PathArguments::None => match seg.ident.as_ref() { - "String" => return Type::Vector(VectorType::String, true), - _ => {} - }, - syn::PathArguments::AngleBracketed(ref t) - if seg.ident == "Vec" && t.args.len() == 1 => - { - match **t.args.first().unwrap().value() { - syn::GenericArgument::Type(ref t) => { - if let Some(ty) = VectorType::from(t) { - return Type::Vector(ty, true); - } - } - _ => {} - } - } - _ => {} - } - } - _ => {} } - Type::ByValue(ty.clone()) } } diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index bb162d42..44c7fadd 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -91,14 +91,14 @@ impl ToTokens for ast::Struct { let c = shared::name_to_descriptor(name.as_ref()) as u32; (my_quote! { impl ::wasm_bindgen::convert::WasmBoundary for #name { - type Js = u32; + type Abi = u32; const DESCRIPTOR: u32 = #c; - fn into_js(self) -> u32 { + fn into_abi(self) -> u32 { Box::into_raw(Box::new(::wasm_bindgen::__rt::WasmRefCell::new(self))) as u32 } - unsafe fn from_js(js: u32) -> Self { + unsafe fn from_abi(js: u32) -> Self { let js = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>; ::wasm_bindgen::__rt::assert_not_null(js); let js = Box::from_raw(js); @@ -109,7 +109,7 @@ impl ToTokens for ast::Struct { impl ::wasm_bindgen::convert::FromRefWasmBoundary for #name { type RefAnchor = ::wasm_bindgen::__rt::Ref<'static, #name>; - unsafe fn from_js_ref(js: Self::Js) -> Self::RefAnchor { + unsafe fn from_abi_ref(js: Self::Abi) -> Self::RefAnchor { let js = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>; ::wasm_bindgen::__rt::assert_not_null(js); (*js).borrow() @@ -119,7 +119,7 @@ impl ToTokens for ast::Struct { impl ::wasm_bindgen::convert::FromRefMutWasmBoundary for #name { type RefAnchor = ::wasm_bindgen::__rt::RefMut<'static, #name>; - unsafe fn from_js_ref_mut(js: Self::Js) -> Self::RefAnchor { + unsafe fn from_abi_ref_mut(js: Self::Abi) -> Self::RefAnchor { let js = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>; ::wasm_bindgen::__rt::assert_not_null(js); (*js).borrow_mut() @@ -128,7 +128,7 @@ impl ToTokens for ast::Struct { #[no_mangle] pub unsafe extern fn #free_fn(ptr: u32) { - <#name as ::wasm_bindgen::convert::WasmBoundary>::from_js(ptr); + <#name as ::wasm_bindgen::convert::WasmBoundary>::from_abi(ptr); } }).to_tokens(tokens); } @@ -158,72 +158,72 @@ impl ToTokens for ast::Export { let i = i + offset; let ident = syn::Ident::from(format!("arg{}", i)); match *ty { - ast::Type::Vector(ref ty, owned) => { - let ptr = syn::Ident::from(format!("arg{}_ptr", i)); - let len = syn::Ident::from(format!("arg{}_len", i)); - let abi_ty = ty.abi_element(); - args.push(my_quote! { #ptr: *mut #abi_ty }); - args.push(my_quote! { #len: usize }); - if owned { - arg_conversions.push(my_quote! { - let #ident = unsafe { - ::std::vec::Vec::from_raw_parts(#ptr, #len, #len) - }; - }); - } else { - arg_conversions.push(my_quote! { - let #ident = unsafe { - ::std::slice::from_raw_parts(#ptr as *const #abi_ty, #len) - }; - }); - } - if let ast::VectorType::String = *ty { - if owned { - arg_conversions.push(my_quote! { - let #ident = unsafe { - ::std::string::String::from_utf8_unchecked(#ident) - }; - }); - } else { - arg_conversions.push(my_quote! { - let #ident = unsafe { - ::std::str::from_utf8_unchecked(#ident) - }; - }); - } - } - } + // ast::Type::Vector(ref ty, owned) => { + // let ptr = syn::Ident::from(format!("arg{}_ptr", i)); + // let len = syn::Ident::from(format!("arg{}_len", i)); + // let abi_ty = ty.abi_element(); + // args.push(my_quote! { #ptr: *mut #abi_ty }); + // args.push(my_quote! { #len: usize }); + // if owned { + // arg_conversions.push(my_quote! { + // let #ident = unsafe { + // ::std::vec::Vec::from_raw_parts(#ptr, #len, #len) + // }; + // }); + // } else { + // arg_conversions.push(my_quote! { + // let #ident = unsafe { + // ::std::slice::from_raw_parts(#ptr as *const #abi_ty, #len) + // }; + // }); + // } + // if let ast::VectorType::String = *ty { + // if owned { + // arg_conversions.push(my_quote! { + // let #ident = unsafe { + // ::std::string::String::from_utf8_unchecked(#ident) + // }; + // }); + // } else { + // arg_conversions.push(my_quote! { + // let #ident = unsafe { + // ::std::str::from_utf8_unchecked(#ident) + // }; + // }); + // } + // } + // } ast::Type::ByValue(ref t) => { args.push(my_quote! { - #ident: <#t as ::wasm_bindgen::convert::WasmBoundary >::Js + #ident: <#t as ::wasm_bindgen::convert::WasmBoundary>::Abi }); arg_conversions.push(my_quote! { let #ident = unsafe { <#t as ::wasm_bindgen::convert::WasmBoundary> - ::from_js(#ident) + ::from_abi(#ident, &mut __stack) }; }); } ast::Type::ByRef(ref ty) => { args.push(my_quote! { - #ident: <#ty as ::wasm_bindgen::convert::WasmBoundary>::Js + #ident: <#ty as ::wasm_bindgen::convert::FromRefWasmBoundary>::Abi }); arg_conversions.push(my_quote! { let #ident = unsafe { <#ty as ::wasm_bindgen::convert::FromRefWasmBoundary> - ::from_js_ref(#ident) + ::from_abi_ref(#ident, &mut __stack) }; let #ident = &*#ident; }); } ast::Type::ByMutRef(ref ty) => { args.push(my_quote! { - #ident: <#ty as ::wasm_bindgen::convert::WasmBoundary>::Js + #ident: <#ty as ::wasm_bindgen::convert::FromRefutWasmBoundary>::Abi }); arg_conversions.push(my_quote! { let mut #ident = unsafe { <#ty as ::wasm_bindgen::convert::FromRefMutWasmBoundary> - ::from_js_ref_mut(#ident) + ::from_abi_ref_mut(#ident, &mut __stack) }; let #ident = &mut *#ident; }); @@ -234,20 +234,22 @@ impl ToTokens for ast::Export { let ret_ty; let convert_ret; match self.function.ret { - Some(ast::Type::Vector(ref ty, true)) => { - ret_ty = my_quote! { -> *mut #ty }; - convert_ret = my_quote! { Box::into_raw(Box::new(#ret)) }; - } + // Some(ast::Type::Vector(ref ty, true)) => { + // ret_ty = my_quote! { -> *mut #ty }; + // convert_ret = my_quote! { Box::into_raw(Box::new(#ret)) }; + // } Some(ast::Type::ByValue(ref t)) => { ret_ty = my_quote! { - -> <#t as ::wasm_bindgen::convert::WasmBoundary>::Js + -> <#t as ::wasm_bindgen::convert::WasmBoundary>::Abi }; convert_ret = my_quote! { - <#t as ::wasm_bindgen::convert::WasmBoundary>::into_js(#ret) + <#t as ::wasm_bindgen::convert::WasmBoundary> + ::into_abi(#ret, &mut unsafe { + ::wasm_bindgen::convert::GlobalStack::new() + }) }; } - Some(ast::Type::Vector(_, false)) - | Some(ast::Type::ByMutRef(_)) + Some(ast::Type::ByMutRef(_)) | Some(ast::Type::ByRef(_)) => { panic!("can't return a borrowed ref"); } @@ -275,6 +277,9 @@ impl ToTokens for ast::Export { #[allow(non_snake_case)] pub extern fn #generated_name(#(#args),*) #ret_ty { ::wasm_bindgen::__rt::link_this_library(); + let mut __stack = unsafe { + ::wasm_bindgen::convert::GlobalStack::new() + }; #(#arg_conversions)* let #ret = #receiver(#(#converted_arguments),*); #convert_ret @@ -295,31 +300,31 @@ impl ToTokens for ast::ImportType { } impl ::wasm_bindgen::convert::WasmBoundary for #name { - type Js = <::wasm_bindgen::JsValue as - ::wasm_bindgen::convert::WasmBoundary>::Js; + type Abi = <::wasm_bindgen::JsValue as + ::wasm_bindgen::convert::WasmBoundary>::Abi; const DESCRIPTOR: u32 = <::wasm_bindgen::JsValue as ::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR; - fn into_js(self) -> Self::Js { - self.obj.into_js() + fn into_abi(self) -> Self::Abi { + self.obj.into_abi() } - unsafe fn from_js(js: Self::Js) -> Self { - #name { obj: ::wasm_bindgen::JsValue::from_js(js) } + unsafe fn from_abi(js: Self::Abi) -> Self { + #name { obj: ::wasm_bindgen::JsValue::from_abi(js) } } } impl ::wasm_bindgen::convert::ToRefWasmBoundary for #name { - fn to_js_ref(&self) -> u32 { - self.obj.to_js_ref() + fn to_abi_ref(&self) -> u32 { + self.obj.to_abi_ref() } } impl ::wasm_bindgen::convert::FromRefWasmBoundary for #name { type RefAnchor = ::std::mem::ManuallyDrop<#name>; - unsafe fn from_js_ref(js: Self::Js) -> Self::RefAnchor { + unsafe fn from_abi_ref(js: Self::Abi) -> Self::RefAnchor { let obj = <::wasm_bindgen::JsValue as ::wasm_bindgen::convert::WasmBoundary> - ::from_js(js); + ::from_abi(js); ::std::mem::ManuallyDrop::new(#name { obj }) } } @@ -393,36 +398,36 @@ impl ToTokens for ast::ImportFunction { for (i, (ty, name)) in self.function.arguments.iter().zip(names).enumerate() { match *ty { - ast::Type::Vector(ref ty, owned) => { - let ptr = syn::Ident::from(format!("{}_ptr", name)); - let len = syn::Ident::from(format!("{}_len", name)); - abi_argument_names.push(ptr); - abi_argument_names.push(len); - let abi_ty = ty.abi_element(); - abi_arguments.push(my_quote! { #ptr: *const #abi_ty }); - abi_arguments.push(my_quote! { #len: usize }); - arg_conversions.push(my_quote! { - let #ptr = #name.as_ptr(); - let #len = #name.len(); - }); - if owned { - arg_conversions.push(my_quote! { ::std::mem::forget(#name); }); - } - } + // ast::Type::Vector(ref ty, owned) => { + // let ptr = syn::Ident::from(format!("{}_ptr", name)); + // let len = syn::Ident::from(format!("{}_len", name)); + // abi_argument_names.push(ptr); + // abi_argument_names.push(len); + // let abi_ty = ty.abi_element(); + // abi_arguments.push(my_quote! { #ptr: *const #abi_ty }); + // abi_arguments.push(my_quote! { #len: usize }); + // arg_conversions.push(my_quote! { + // let #ptr = #name.as_ptr(); + // let #len = #name.len(); + // }); + // if owned { + // arg_conversions.push(my_quote! { ::std::mem::forget(#name); }); + // } + // } ast::Type::ByValue(ref t) => { abi_argument_names.push(name); abi_arguments.push(my_quote! { - #name: <#t as ::wasm_bindgen::convert::WasmBoundary>::Js + #name: <#t as ::wasm_bindgen::convert::WasmBoundary>::Abi }); if i == 0 && is_method { arg_conversions.push(my_quote! { let #name = <#t as ::wasm_bindgen::convert::WasmBoundary> - ::into_js(self); + ::into_abi(self); }); } else { arg_conversions.push(my_quote! { let #name = <#t as ::wasm_bindgen::convert::WasmBoundary> - ::into_js(#name); + ::into_abi(#name); }); } } @@ -433,12 +438,12 @@ impl ToTokens for ast::ImportFunction { if i == 0 && is_method { arg_conversions.push(my_quote! { let #name = <#t as ::wasm_bindgen::convert::ToRefWasmBoundary> - ::to_js_ref(self); + ::to_abi_ref(self); }); } else { arg_conversions.push(my_quote! { let #name = <#t as ::wasm_bindgen::convert::ToRefWasmBoundary> - ::to_js_ref(#name); + ::to_abi_ref(#name); }); } } @@ -449,38 +454,37 @@ impl ToTokens for ast::ImportFunction { match self.function.ret { Some(ast::Type::ByValue(ref t)) => { abi_ret = my_quote! { - <#t as ::wasm_bindgen::convert::WasmBoundary>::Js + <#t as ::wasm_bindgen::convert::WasmBoundary>::Abi }; convert_ret = my_quote! { - <#t as ::wasm_bindgen::convert::WasmBoundary>::from_js(#ret_ident) + <#t as ::wasm_bindgen::convert::WasmBoundary>::from_abi(#ret_ident) }; } - Some(ast::Type::Vector(ref ty, true)) => { - let name = syn::Ident::from("__ret_len"); - let name_ptr = syn::Ident::from("__ret_len_ptr"); - abi_argument_names.push(name_ptr); - abi_arguments.push(my_quote! { #name_ptr: *mut usize }); - arg_conversions.push(my_quote! { - let mut #name = 0; - let mut #name_ptr = &mut #name as *mut usize; - }); - let abi_ty = ty.abi_element(); - abi_ret = my_quote! { *mut #abi_ty }; - if let ast::VectorType::String = *ty { - convert_ret = my_quote! { - String::from_utf8_unchecked( - Vec::from_raw_parts(#ret_ident, #name, #name) - ) - }; - } else { - convert_ret = my_quote! { - Vec::from_raw_parts(#ret_ident, #name, #name) - }; - } - } + // Some(ast::Type::Vector(ref ty, true)) => { + // let name = syn::Ident::from("__ret_len"); + // let name_ptr = syn::Ident::from("__ret_len_ptr"); + // abi_argument_names.push(name_ptr); + // abi_arguments.push(my_quote! { #name_ptr: *mut usize }); + // arg_conversions.push(my_quote! { + // let mut #name = 0; + // let mut #name_ptr = &mut #name as *mut usize; + // }); + // let abi_ty = ty.abi_element(); + // abi_ret = my_quote! { *mut #abi_ty }; + // if let ast::VectorType::String = *ty { + // convert_ret = my_quote! { + // String::from_utf8_unchecked( + // Vec::from_raw_parts(#ret_ident, #name, #name) + // ) + // }; + // } else { + // convert_ret = my_quote! { + // Vec::from_raw_parts(#ret_ident, #name, #name) + // }; + // } + // } Some(ast::Type::ByRef(_)) - | Some(ast::Type::Vector(_, false)) | Some(ast::Type::ByMutRef(_)) => panic!("can't return a borrowed ref"), None => { abi_ret = my_quote! { () }; @@ -502,7 +506,7 @@ impl ToTokens for ast::ImportFunction { exceptional_ret = my_quote! { if #exn_data[0] == 1 { return Err(<::wasm_bindgen::JsValue as - ::wasm_bindgen::convert::WasmBoundary>::from_js(#exn_data[1])) + ::wasm_bindgen::convert::WasmBoundary>::from_abi(#exn_data[1])) } }; } @@ -578,14 +582,14 @@ impl ToTokens for ast::Enum { } impl ::wasm_bindgen::convert::WasmBoundary for #enum_name { - type Js = u32; + type Abi = u32; const DESCRIPTOR: u32 = #c; - fn into_js(self) -> u32 { + fn into_abi(self) -> u32 { self as u32 } - unsafe fn from_js(js: u32) -> Self { + unsafe fn from_abi(js: u32) -> Self { #enum_name::from_u32(js) } } @@ -608,7 +612,7 @@ impl ToTokens for ast::ImportStatic { fn #shim_name() -> u32; } unsafe { - ::wasm_bindgen::convert::WasmBoundary::from_js(#shim_name()) + ::wasm_bindgen::convert::WasmBoundary::from_abi(#shim_name()) } } ::wasm_bindgen::JsStatic { diff --git a/crates/backend/src/literal.rs b/crates/backend/src/literal.rs index 286fac47..57387876 100644 --- a/crates/backend/src/literal.rs +++ b/crates/backend/src/literal.rs @@ -24,17 +24,9 @@ impl<'a> LiteralBuilder<'a> { b.to_tokens(self.dst); } - fn char_lit(&mut self, c: char) { - let c = c as u32; - self.byte(c as u8); - self.byte((c >> 8) as u8); - self.byte((c >> 16) as u8); - self.byte((c >> 24) as u8); - } - fn append(&mut self, s: &str) { - for c in s.chars() { - self.char_lit(c); + for &b in s.as_bytes() { + self.byte(b); } } @@ -52,22 +44,18 @@ impl<'a> LiteralBuilder<'a> { } } - fn char(&mut self, s: char) { - self.append("\""); - self.char_lit(s); - self.append("\""); + fn u32(&mut self, s: u32) { + self.append(&s.to_string()) } fn as_char(&mut self, tokens: Tokens) { - self.append("\""); (quote! { - , (((#tokens) as u32) >> 0) as u8 - , (((#tokens) as u32) >> 8) as u8 - , (((#tokens) as u32) >> 16) as u8 - , (((#tokens) as u32) >> 24) as u8 + ,(#tokens).__x[0] + ,(#tokens).__x[1] + ,(#tokens).__x[2] + ,(#tokens).__x[3] }).to_tokens(self.dst); self.cnt += 4; - self.append("\""); } pub fn fields(&mut self, fields: &[(&str, &Fn(&mut Self))]) { @@ -126,7 +114,7 @@ impl Literal for ast::Program { a.list(&names, |s, a| { let val = shared::name_to_descriptor(s.as_ref()); a.fields(&[ - ("descriptor", &|a| a.char(val)), + ("descriptor", &|a| a.u32(val)), ("name", &|a| a.str(s.as_ref())), ]); }) @@ -153,39 +141,16 @@ impl Literal for ast::Function { impl Literal for ast::Type { fn literal(&self, a: &mut LiteralBuilder) { match *self { - ast::Type::Vector(ast::VectorType::String, true) => a.char(shared::TYPE_STRING), - ast::Type::Vector(ast::VectorType::String, false) => a.char(shared::TYPE_BORROWED_STR), - ast::Type::Vector(ast::VectorType::U8, true) => a.char(shared::TYPE_VECTOR_U8), - ast::Type::Vector(ast::VectorType::U8, false) => a.char(shared::TYPE_SLICE_U8), - ast::Type::Vector(ast::VectorType::I8, true) => a.char(shared::TYPE_VECTOR_I8), - ast::Type::Vector(ast::VectorType::I8, false) => a.char(shared::TYPE_SLICE_I8), - ast::Type::Vector(ast::VectorType::U16, true) => a.char(shared::TYPE_VECTOR_U16), - ast::Type::Vector(ast::VectorType::U16, false) => a.char(shared::TYPE_SLICE_U16), - ast::Type::Vector(ast::VectorType::I16, true) => a.char(shared::TYPE_VECTOR_I16), - ast::Type::Vector(ast::VectorType::I16, false) => a.char(shared::TYPE_SLICE_I16), - ast::Type::Vector(ast::VectorType::U32, true) => a.char(shared::TYPE_VECTOR_U32), - ast::Type::Vector(ast::VectorType::U32, false) => a.char(shared::TYPE_SLICE_U32), - ast::Type::Vector(ast::VectorType::I32, true) => a.char(shared::TYPE_VECTOR_I32), - ast::Type::Vector(ast::VectorType::I32, false) => a.char(shared::TYPE_SLICE_I32), - ast::Type::Vector(ast::VectorType::F32, true) => a.char(shared::TYPE_VECTOR_F32), - ast::Type::Vector(ast::VectorType::F32, false) => a.char(shared::TYPE_SLICE_F32), - ast::Type::Vector(ast::VectorType::F64, true) => a.char(shared::TYPE_VECTOR_F64), - ast::Type::Vector(ast::VectorType::F64, false) => a.char(shared::TYPE_SLICE_F64), - ast::Type::Vector(ast::VectorType::JsValue, true) => { - a.char(shared::TYPE_VECTOR_JSVALUE) - } - ast::Type::Vector(ast::VectorType::JsValue, false) => { - panic!("Slices of JsValues not supported") - } ast::Type::ByValue(ref t) => { a.as_char(my_quote! { <#t as ::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR }); } ast::Type::ByRef(ref ty) | ast::Type::ByMutRef(ref ty) => { + // TODO: this assumes `ToRef*` and `FromRef*` use the same + // descriptor. a.as_char(my_quote! { - (<#ty as ::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR | - ::wasm_bindgen::convert::DESCRIPTOR_CUSTOM_REF_FLAG) + <#ty as ::wasm_bindgen::convert::ToRefWasmBoundary>::DESCRIPTOR }); } } diff --git a/crates/cli-support/src/js.rs b/crates/cli-support/src/js.rs index 82da1d03..537368a8 100644 --- a/crates/cli-support/src/js.rs +++ b/crates/cli-support/src/js.rs @@ -17,7 +17,7 @@ pub struct Context<'a> { pub required_internal_exports: HashSet<&'static str>, pub config: &'a Bindgen, pub module: &'a mut Module, - pub custom_type_names: HashMap, + pub custom_type_names: HashMap, pub imported_names: HashSet, pub exported_classes: HashMap, } @@ -528,6 +528,7 @@ impl<'a> Context<'a> { self.required_internal_exports.insert("__wbindgen_malloc"); self.expose_text_encoder(); self.expose_uint8_memory(); + self.expose_push_global_argument(); self.globals.push_str(&format!(" function passStringToWasm(arg) {{ if (typeof(arg) !== 'string') @@ -936,9 +937,8 @@ impl<'a> Context<'a> { }) } - fn custom_type_name(&self, c: char) -> &str { - let c = (c as u32) & !shared::TYPE_CUSTOM_REF_FLAG; - let c = char::from_u32(c).unwrap(); + fn custom_type_name(&self, c: u32) -> &str { + let c = c & !shared::TYPE_CUSTOM_REF_FLAG; &self.custom_type_names[&c] } @@ -1016,6 +1016,51 @@ impl<'a> Context<'a> { } } } + + fn expose_push_global_argument(&mut self) { + if !self.exposed_globals.insert("push_global_argument") { + return + } + self.expose_uint32_memory(); + self.expose_global_argument_ptr(); + self.globals.push_str(" + function pushGlobalArgument(arg) {{ + const idx = globalArgumentPtr() / 4 + GLOBAL_ARGUMENT_CNT; + getUint32Memory()[idx] = arg; + GLOBAL_ARGUMENT_CNT += 1; + }} + "); + } + + fn expose_get_global_argument(&mut self) { + if !self.exposed_globals.insert("get_global_argument") { + return + } + self.expose_uint32_memory(); + self.expose_global_argument_ptr(); + self.globals.push_str(" + function getGlobalArgument(arg) {{ + const idx = globalArgumentPtr() / 4 + arg; + return getUint32Memory()[idx]; + }} + "); + } + + fn expose_global_argument_ptr(&mut self) { + if !self.exposed_globals.insert("global_argument_ptr") { + return + } + self.required_internal_exports.insert("__wbindgen_global_argument_ptr"); + self.globals.push_str(" + let cachedGlobalArgumentPtr = null; + let GLOBAL_ARGUMENT_CNT = 0; + function globalArgumentPtr() { + if (cachedGlobalArgumentPtr === null) + cachedGlobalArgumentPtr = wasm.__wbindgen_global_argument_ptr(); + return cachedGlobalArgumentPtr; + } + "); + } } impl<'a, 'b> SubContext<'a, 'b> { @@ -1095,6 +1140,7 @@ impl<'a, 'b> SubContext<'a, 'b> { passed_args.push_str("this.ptr"); } + let mut argument_pushed = false; for (i, arg) in function.arguments.iter().enumerate() { let name = format!("arg{}", i); if i > 0 { @@ -1130,40 +1176,6 @@ impl<'a, 'b> SubContext<'a, 'b> { } pass(&format!("arg{i} ? 1 : 0", i = i)) } - shared::TYPE_BORROWED_STR | - shared::TYPE_STRING | - shared::TYPE_VECTOR_U8 | - shared::TYPE_VECTOR_I8 | - shared::TYPE_SLICE_U8 | - shared::TYPE_SLICE_I8 | - shared::TYPE_VECTOR_U16 | - shared::TYPE_VECTOR_I16 | - shared::TYPE_SLICE_U16 | - shared::TYPE_SLICE_I16 | - shared::TYPE_VECTOR_U32 | - shared::TYPE_VECTOR_I32 | - shared::TYPE_SLICE_U32 | - shared::TYPE_SLICE_I32 | - shared::TYPE_VECTOR_F32 | - shared::TYPE_VECTOR_F64 | - shared::TYPE_SLICE_F32 | - shared::TYPE_SLICE_F64 => { - let ty = VectorType::from(*arg); - dst_ts.push_str(": "); - dst_ts.push_str(ty.js_ty()); - let func = self.cx.pass_to_wasm_function(&ty); - arg_conversions.push_str(&format!("\ - const [ptr{i}, len{i}] = {func}({arg}); - ", i = i, func = func, arg = name)); - pass(&format!("ptr{}", i)); - pass(&format!("len{}", i)); - if !ty.owned { - destructors.push_str(&format!("\n\ - wasm.__wbindgen_free(ptr{i}, len{i});\n\ - ", i = i)); - self.cx.required_internal_exports.insert("__wbindgen_free"); - } - } shared::TYPE_JS_OWNED => { dst_ts.push_str(": any"); self.cx.expose_add_heap_object(); @@ -1181,31 +1193,49 @@ impl<'a, 'b> SubContext<'a, 'b> { destructors.push_str("stack.pop();\n"); pass(&format!("idx{}", i)); } - custom if (custom as u32) & shared::TYPE_CUSTOM_REF_FLAG != 0 => { - let s = self.cx.custom_type_name(custom).to_string(); - dst_ts.push_str(&format!(": {}", s)); - if self.cx.config.debug { - self.cx.expose_assert_class(); - arg_conversions.push_str(&format!("\ - _assertClass({arg}, {struct_}); - ", arg = name, struct_ = s)); + other => { + match VectorType::from(other) { + Some(ty) => { + dst_ts.push_str(": "); + dst_ts.push_str(ty.js_ty()); + let func = self.cx.pass_to_wasm_function(&ty); + self.cx.expose_push_global_argument(); + argument_pushed = true; + arg_conversions.push_str(&format!("\ + const [ptr{i}, len{i}] = {func}({arg}); + pushGlobalArgument(len{i}); + ", i = i, func = func, arg = name)); + pass(&format!("ptr{}", i)); + if !ty.owned { + destructors.push_str(&format!("\n\ + wasm.__wbindgen_free(ptr{i}, len{i} * {size});\n\ + ", i = i, size = ty.size())); + self.cx.required_internal_exports.insert( + "__wbindgen_free", + ); + } + } + None => { + let s = self.cx.custom_type_name(other).to_string(); + dst_ts.push_str(&format!(": {}", s)); + if self.cx.config.debug { + self.cx.expose_assert_class(); + arg_conversions.push_str(&format!("\ + _assertClass({arg}, {struct_}); + ", arg = name, struct_ = s)); + } + + if other & shared::TYPE_CUSTOM_REF_FLAG != 0 { + pass(&format!("{}.ptr", name)); + } else { + arg_conversions.push_str(&format!("\ + const ptr{i} = {arg}.ptr; + {arg}.ptr = 0; + ", i = i, arg = name)); + pass(&format!("ptr{}", i)); + } + } } - pass(&format!("{}.ptr", name)); - } - custom => { - let s = self.cx.custom_type_name(custom).to_string(); - dst_ts.push_str(&format!(": {}", s)); - if self.cx.config.debug { - self.cx.expose_assert_class(); - arg_conversions.push_str(&format!("\ - _assertClass({arg}, {struct_}); - ", arg = name, struct_ = s)); - } - arg_conversions.push_str(&format!("\ - const ptr{i} = {arg}.ptr; - {arg}.ptr = 0; - ", i = i, arg = name)); - pass(&format!("ptr{}", i)); } } } @@ -1233,51 +1263,53 @@ impl<'a, 'b> SubContext<'a, 'b> { self.cx.expose_take_object(); format!("return takeObject(ret);") } - Some(shared::TYPE_STRING) | - Some(shared::TYPE_VECTOR_U8) | - Some(shared::TYPE_VECTOR_I8) | - Some(shared::TYPE_VECTOR_U16) | - Some(shared::TYPE_VECTOR_I16) | - Some(shared::TYPE_VECTOR_U32) | - Some(shared::TYPE_VECTOR_I32) | - Some(shared::TYPE_VECTOR_F32) | - Some(shared::TYPE_VECTOR_F64) | - Some(shared::TYPE_VECTOR_JSVALUE) => { - let ty = VectorType::from(function.ret.unwrap()); - dst_ts.push_str(": "); - dst_ts.push_str(ty.js_ty()); - let f = self.cx.expose_get_vector_from_wasm(&ty); - self.cx.required_internal_exports.insert("__wbindgen_boxed_str_ptr"); - self.cx.required_internal_exports.insert("__wbindgen_boxed_str_len"); - self.cx.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); - const realRet = {}(ptr, len); - wasm.__wbindgen_boxed_str_free(ret); - return realRet; - ", f) + Some(shared::TYPE_JS_REF) => { + dst_ts.push_str(": any"); + self.cx.expose_get_object(); + format!("return getObject(ret);") } - Some(shared::TYPE_JS_REF) | - Some(shared::TYPE_BORROWED_STR) => panic!(), - Some(t) if (t as u32) & shared::TYPE_CUSTOM_REF_FLAG != 0 => panic!(), - Some(custom) => { - let name = self.cx.custom_type_name(custom); - dst_ts.push_str(": "); - dst_ts.push_str(name); - if self.cx.config.debug { - format!("\ - return new {name}(ret, token); - ", name = name) - } else { - format!("\ - return new {name}(ret); - ", name = name) + Some(other) => { + if other & shared::TYPE_CUSTOM_REF_FLAG != 0 { + panic!("cannot return references yet"); + } + match VectorType::from(other) { + Some(ty) => { + dst_ts.push_str(": "); + dst_ts.push_str(ty.js_ty()); + let f = self.cx.expose_get_vector_from_wasm(&ty); + self.cx.expose_get_global_argument(); + self.cx.required_internal_exports.insert( + "__wbindgen_free", + ); + format!(" + const len = getGlobalArgument(0); + const realRet = {}(ret, len); + wasm.__wbindgen_free(ret, len * {}); + return realRet; + ", f, ty.size()) + } + None => { + let name = self.cx.custom_type_name(other); + dst_ts.push_str(": "); + dst_ts.push_str(name); + if self.cx.config.debug { + format!("\ + return new {name}(ret, token); + ", name = name) + } else { + format!("\ + return new {name}(ret); + ", name = name) + } + } } } }; dst_ts.push_str(";"); dst.push_str(" {\n "); + if argument_pushed { + dst.push_str("GLOBAL_ARGUMENT_CNT = 0;\n"); + } dst.push_str(&arg_conversions); if destructors.len() == 0 { dst.push_str(&format!("\ @@ -1353,40 +1385,40 @@ impl<'a, 'b> SubContext<'a, 'b> { invoc_args.push(format!("arg{} !== 0", i)); abi_args.push(format!("arg{}", i)); } - shared::TYPE_BORROWED_STR | - shared::TYPE_STRING | - shared::TYPE_VECTOR_U8 | - shared::TYPE_VECTOR_I8 | - shared::TYPE_SLICE_U8 | - shared::TYPE_SLICE_I8 | - shared::TYPE_VECTOR_U16 | - shared::TYPE_VECTOR_I16 | - shared::TYPE_SLICE_U16 | - shared::TYPE_SLICE_I16 | - shared::TYPE_VECTOR_U32 | - shared::TYPE_VECTOR_I32 | - shared::TYPE_SLICE_U32 | - shared::TYPE_SLICE_I32 | - shared::TYPE_VECTOR_F32 | - shared::TYPE_VECTOR_F64 | - shared::TYPE_SLICE_F32 | - shared::TYPE_SLICE_F64 => { - let ty = VectorType::from(*arg); - let f = self.cx.expose_get_vector_from_wasm(&ty); - abi_args.push(format!("ptr{}", i)); - abi_args.push(format!("len{}", i)); - extra.push_str(&format!(" - let arg{0} = {func}(ptr{0}, len{0}); - ", i, func = f)); - invoc_args.push(format!("arg{}", i)); - - if ty.owned { - extra.push_str(&format!(" - wasm.__wbindgen_free(ptr{0}, len{0}); - ", i)); - self.cx.required_internal_exports.insert("__wbindgen_free"); - } - } + // shared::TYPE_BORROWED_STR | + // shared::TYPE_STRING | + // shared::TYPE_VECTOR_U8 | + // shared::TYPE_VECTOR_I8 | + // shared::TYPE_SLICE_U8 | + // shared::TYPE_SLICE_I8 | + // shared::TYPE_VECTOR_U16 | + // shared::TYPE_VECTOR_I16 | + // shared::TYPE_SLICE_U16 | + // shared::TYPE_SLICE_I16 | + // shared::TYPE_VECTOR_U32 | + // shared::TYPE_VECTOR_I32 | + // shared::TYPE_SLICE_U32 | + // shared::TYPE_SLICE_I32 | + // shared::TYPE_VECTOR_F32 | + // shared::TYPE_VECTOR_F64 | + // shared::TYPE_SLICE_F32 | + // shared::TYPE_SLICE_F64 => { + // let ty = VectorType::from(*arg); + // let f = self.cx.expose_get_vector_from_wasm(&ty); + // abi_args.push(format!("ptr{}", i)); + // abi_args.push(format!("len{}", i)); + // extra.push_str(&format!(" + // let arg{0} = {func}(ptr{0}, len{0}); + // ", i, func = f)); + // invoc_args.push(format!("arg{}", i)); + // + // if ty.owned { + // extra.push_str(&format!(" + // wasm.__wbindgen_free(ptr{0}, len{0}); + // ", i)); + // self.cx.required_internal_exports.insert("__wbindgen_free"); + // } + // } shared::TYPE_JS_OWNED => { self.cx.expose_take_object(); invoc_args.push(format!("takeObject(arg{})", i)); @@ -1397,7 +1429,7 @@ impl<'a, 'b> SubContext<'a, 'b> { invoc_args.push(format!("getObject(arg{})", i)); abi_args.push(format!("arg{}", i)); } - custom if (custom as u32) & shared::TYPE_CUSTOM_REF_FLAG == 0 => { + custom if custom & shared::TYPE_CUSTOM_REF_FLAG == 0 => { let s = self.cx.custom_type_name(custom).to_string(); abi_args.push(format!("ptr{}", i)); let assign = if self.cx.config.debug { @@ -1501,25 +1533,25 @@ impl<'a, 'b> SubContext<'a, 'b> { self.cx.expose_add_heap_object(); format!("return addHeapObject({});", invoc) } - Some(shared::TYPE_STRING) | - Some(shared::TYPE_VECTOR_U8) | - Some(shared::TYPE_VECTOR_I8) | - Some(shared::TYPE_VECTOR_U16) | - Some(shared::TYPE_VECTOR_I16) | - Some(shared::TYPE_VECTOR_U32) | - Some(shared::TYPE_VECTOR_I32) | - Some(shared::TYPE_VECTOR_F32) | - Some(shared::TYPE_VECTOR_F64) => { - let ty = VectorType::from(import.function.ret.unwrap()); - let f = self.cx.pass_to_wasm_function(&ty); - self.cx.expose_uint32_memory(); - abi_args.push("wasmretptr".to_string()); - format!(" - const [retptr, retlen] = {}({}); - getUint32Memory()[wasmretptr / 4] = retlen; - return retptr; - ", f, invoc) - } + // Some(shared::TYPE_STRING) | + // Some(shared::TYPE_VECTOR_U8) | + // Some(shared::TYPE_VECTOR_I8) | + // Some(shared::TYPE_VECTOR_U16) | + // Some(shared::TYPE_VECTOR_I16) | + // Some(shared::TYPE_VECTOR_U32) | + // Some(shared::TYPE_VECTOR_I32) | + // Some(shared::TYPE_VECTOR_F32) | + // Some(shared::TYPE_VECTOR_F64) => { + // let ty = VectorType::from(import.function.ret.unwrap()); + // let f = self.cx.pass_to_wasm_function(&ty); + // self.cx.expose_uint32_memory(); + // abi_args.push("wasmretptr".to_string()); + // format!(" + // const [retptr, retlen] = {}({}); + // getUint32Memory()[wasmretptr / 4] = retlen; + // return retptr; + // ", f, invoc) + // } None => invoc, _ => unimplemented!(), }; @@ -1632,8 +1664,8 @@ enum VectorKind { } impl VectorType { - fn from(desc: char) -> VectorType { - match desc { + fn from(desc: u32) -> Option { + let ty = match desc { shared::TYPE_BORROWED_STR => { VectorType { owned: false, kind: VectorKind::String } } @@ -1691,8 +1723,9 @@ impl VectorType { shared::TYPE_VECTOR_JSVALUE => { VectorType { owned: true, kind: VectorKind::JsValue } } - _ => panic!() - } + _ => return None + }; + Some(ty) } fn js_ty(&self) -> &str { @@ -1709,4 +1742,19 @@ impl VectorType { VectorKind::JsValue => "any[]", } } + + fn size(&self) -> usize { + match self.kind { + VectorKind::String => 1, + VectorKind::I8 => 1, + VectorKind::U8 => 1, + VectorKind::I16 => 2, + VectorKind::U16 => 2, + VectorKind::I32 => 4, + VectorKind::U32 => 4, + VectorKind::F32 => 4, + VectorKind::F64 => 8, + VectorKind::JsValue => 4, + } + } } diff --git a/crates/cli-support/src/lib.rs b/crates/cli-support/src/lib.rs index c10b0054..a3693309 100644 --- a/crates/cli-support/src/lib.rs +++ b/crates/cli-support/src/lib.rs @@ -166,9 +166,6 @@ fn extract_programs(module: &mut Module) -> Vec { let version = shared::version(); let mut ret = Vec::new(); - #[repr(packed)] - struct Unaligned(u32); - module.sections_mut().retain(|s| { let custom = match *s { Section::Custom(ref s) => s, @@ -178,21 +175,16 @@ fn extract_programs(module: &mut Module) -> Vec { return true } - assert!(custom.payload().len() % 4 == 0); - let mut payload = unsafe { - slice::from_raw_parts(custom.payload().as_ptr() as *const Unaligned, - custom.payload().len() / 4) - }; - + let mut payload = custom.payload(); while payload.len() > 0 { - let len = payload[0].0.to_le(); - assert!(len % 4 == 0); - let (a, b) = payload[1..].split_at((len / 4) as usize); + let len = + ((payload[0] as usize) << 0) | + ((payload[1] as usize) << 8) | + ((payload[2] as usize) << 16) | + ((payload[3] as usize) << 24); + let (a, b) = payload[4..].split_at(len as usize); payload = b; - let json = a.iter() - .map(|i| char::from_u32(i.0.to_le()).unwrap()) - .collect::(); - let p: shared::Program = match serde_json::from_str(&json) { + let p: shared::Program = match serde_json::from_slice(&a) { Ok(f) => f, Err(e) => { panic!("failed to decode what looked like wasm-bindgen data: {}", e) diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index 96c61b16..5af5e9d7 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -85,7 +85,7 @@ pub struct Function { #[derive(Deserialize)] pub struct CustomTypeName { - pub descriptor: char, + pub descriptor: u32, pub name: String, } @@ -112,51 +112,42 @@ pub fn struct_function_export_name(struct_: &str, f: &str) -> String { return name } -pub type Type = char; +pub type Type = u32; -pub const TYPE_VECTOR_JSVALUE: char = '\u{5b}'; -// Note: '\u{5c}' is '\' which breaks json encoding/decoding -pub const TYPE_ENUM: char = '\u{5d}'; -pub const TYPE_NUMBER: char = '\u{5e}'; -pub const TYPE_BORROWED_STR: char = '\u{5f}'; -pub const TYPE_STRING: char = '\u{60}'; -pub const TYPE_BOOLEAN: char = '\u{61}'; -pub const TYPE_SLICE_U8: char = '\u{62}'; -pub const TYPE_VECTOR_U8: char = '\u{63}'; -pub const TYPE_SLICE_I8: char = '\u{64}'; -pub const TYPE_VECTOR_I8: char = '\u{65}'; -pub const TYPE_SLICE_U16: char = '\u{66}'; -pub const TYPE_VECTOR_U16: char = '\u{67}'; -pub const TYPE_SLICE_I16: char = '\u{68}'; -pub const TYPE_VECTOR_I16: char = '\u{69}'; -pub const TYPE_SLICE_U32: char = '\u{6a}'; -pub const TYPE_VECTOR_U32: char = '\u{6b}'; -pub const TYPE_SLICE_I32: char = '\u{6c}'; -pub const TYPE_VECTOR_I32: char = '\u{6d}'; -pub const TYPE_VECTOR_F32: char = '\u{6e}'; -pub const TYPE_SLICE_F32: char = '\u{6f}'; -pub const TYPE_VECTOR_F64: char = '\u{70}'; -pub const TYPE_SLICE_F64: char = '\u{71}'; -pub const TYPE_JS_OWNED: char = '\u{72}'; -pub const TYPE_JS_REF: char = '\u{73}'; +pub const TYPE_VECTOR_JSVALUE: u32 = 0; +pub const TYPE_ENUM: u32 = 1; +pub const TYPE_NUMBER: u32 = 2; +pub const TYPE_BORROWED_STR: u32 = 3; +pub const TYPE_STRING: u32 = 4; +pub const TYPE_BOOLEAN: u32 = 5; +pub const TYPE_SLICE_U8: u32 = 6; +pub const TYPE_VECTOR_U8: u32 = 7; +pub const TYPE_SLICE_I8: u32 = 8; +pub const TYPE_VECTOR_I8: u32 = 9; +pub const TYPE_SLICE_U16: u32 = 10; +pub const TYPE_VECTOR_U16: u32 = 11; +pub const TYPE_SLICE_I16: u32 = 12; +pub const TYPE_VECTOR_I16: u32 = 13; +pub const TYPE_SLICE_U32: u32 = 14; +pub const TYPE_VECTOR_U32: u32 = 15; +pub const TYPE_SLICE_I32: u32 = 16; +pub const TYPE_VECTOR_I32: u32 = 17; +pub const TYPE_VECTOR_F32: u32 = 18; +pub const TYPE_SLICE_F32: u32 = 19; +pub const TYPE_VECTOR_F64: u32 = 20; +pub const TYPE_SLICE_F64: u32 = 21; +pub const TYPE_JS_OWNED: u32 = 22; +pub const TYPE_JS_REF: u32 = 23; -pub const TYPE_CUSTOM_START: u32 = 0x74; +pub const TYPE_CUSTOM_START: u32 = 24; pub const TYPE_CUSTOM_REF_FLAG: u32 = 1; -pub fn name_to_descriptor(name: &str) -> char { - const CHAR_MAX: u32 = 0x10ffff; - const CHAR_HOLE_START: u32 = 0xd800; - const CHAR_HOLE_END: u32 = 0xe000; +pub fn name_to_descriptor(name: &str) -> u32 { + const MAX: u32 = 10_000; let mut h = fnv::FnvHasher::default(); name.hash(&mut h); - let val = h.finish(); - let range = (CHAR_MAX - (CHAR_HOLE_END - CHAR_HOLE_START) - TYPE_CUSTOM_START) / 2; - let idx = (val % (range as u64)) as u32; - let mut ret = TYPE_CUSTOM_START + idx * 2; - if CHAR_HOLE_START <= ret && ret < CHAR_HOLE_END { - ret += CHAR_HOLE_END - CHAR_HOLE_START; - } - char::from_u32(ret).unwrap() + ((h.finish() as u32) % (MAX - TYPE_CUSTOM_START)) + TYPE_CUSTOM_START + } pub fn version() -> String { diff --git a/src/convert.rs b/src/convert.rs index 3d48c17e..41c9f249 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -1,38 +1,68 @@ use std::mem::{self, ManuallyDrop}; use std::ops::{Deref, DerefMut}; +use std::slice; +use std::str; use super::JsValue; +#[derive(PartialEq, Eq, Copy, Clone)] +pub struct Descriptor { + #[doc(hidden)] + pub __x: [u8; 4], +} + // keep in sync with shared/src/lib.rs TYPE constants -pub const DESCRIPTOR_CUSTOM_REF_FLAG: u32 = 0x1; -pub const DESCRIPTOR_NUMBER: u32 = 0x5e; -pub const DESCRIPTOR_BOOLEAN: u32 = 0x61; -pub const DESCRIPTOR_JS_OWNED: u32 = 0x72; +// pub const DESCRIPTOR_CUSTOM_REF_FLAG: Descriptor = Descriptor { __x: *b" 1", }; +pub const DESCRIPTOR_NUMBER: Descriptor = Descriptor { __x: *b" 2", }; +pub const DESCRIPTOR_BORROWED_STR: Descriptor = Descriptor { __x: *b" 3", }; +pub const DESCRIPTOR_STRING: Descriptor = Descriptor { __x: *b" 4", }; +pub const DESCRIPTOR_BOOLEAN: Descriptor = Descriptor { __x: *b" 5", }; + +pub const DESCRIPTOR_JS_OWNED: Descriptor = Descriptor { __x: *b" 22", }; +pub const DESCRIPTOR_JS_REF: Descriptor = Descriptor { __x: *b" 23", }; pub trait WasmBoundary { - type Js: WasmAbi; - const DESCRIPTOR: u32; + type Abi: WasmAbi; + const DESCRIPTOR: Descriptor; - fn into_js(self) -> Self::Js; - unsafe fn from_js(js: Self::Js) -> Self; + fn into_abi(self, extra: &mut Stack) -> Self::Abi; + unsafe fn from_abi(js: Self::Abi, extra: &mut Stack) -> Self; } -pub trait FromRefWasmBoundary: WasmBoundary { +pub trait FromRefWasmBoundary { + type Abi: WasmAbi; + const DESCRIPTOR: Descriptor; type RefAnchor: Deref; - unsafe fn from_js_ref(js: Self::Js) -> Self::RefAnchor; + unsafe fn from_abi_ref(js: Self::Abi, extra: &mut Stack) -> Self::RefAnchor; } -pub trait FromRefMutWasmBoundary: WasmBoundary { +pub trait FromRefMutWasmBoundary { + type Abi: WasmAbi; + const DESCRIPTOR: Descriptor; type RefAnchor: DerefMut; - unsafe fn from_js_ref_mut(js: Self::Js) -> Self::RefAnchor; + unsafe fn from_abi_ref_mut(js: Self::Abi, extra: &mut Stack) -> Self::RefAnchor; } -pub trait ToRefWasmBoundary: WasmBoundary { - fn to_js_ref(&self) -> u32; +pub trait ToRefWasmBoundary { + type Abi: WasmAbi; + const DESCRIPTOR: Descriptor; + + fn to_abi_ref(&self, extra: &mut Stack) -> u32; } +pub trait Stack { + fn push(&mut self, bits: u32); + fn pop(&mut self) -> u32; +} + +/// An unsafe trait which represents types that are ABI-safe to pass via wasm +/// arguments. +/// +/// This is an unsafe trait to implement as there's no guarantee the type is +/// actually safe to transfer across the was boundary, it's up to you to +/// guarantee this so codegen works correctly. pub unsafe trait WasmAbi {} unsafe impl WasmAbi for u32 {} @@ -43,11 +73,11 @@ unsafe impl WasmAbi for f64 {} macro_rules! simple { ($($t:tt)*) => ($( impl WasmBoundary for $t { - type Js = $t; - const DESCRIPTOR: u32 = DESCRIPTOR_NUMBER; + type Abi = $t; + const DESCRIPTOR: Descriptor = DESCRIPTOR_NUMBER; - fn into_js(self) -> $t { self } - unsafe fn from_js(js: $t) -> $t { js } + fn into_abi(self, _extra: &mut Stack) -> $t { self } + unsafe fn from_abi(js: $t, _extra: &mut Stack) -> $t { js } } )*) } @@ -57,11 +87,11 @@ simple!(u32 u64 f32 f64); macro_rules! as_u32 { ($($t:tt)*) => ($( impl WasmBoundary for $t { - type Js = u32; - const DESCRIPTOR: u32 = DESCRIPTOR_NUMBER; + type Abi = u32; + const DESCRIPTOR: Descriptor = DESCRIPTOR_NUMBER; - fn into_js(self) -> u32 { self as u32 } - unsafe fn from_js(js: u32) -> $t { js as $t } + fn into_abi(self, _extra: &mut Stack) -> u32 { self as u32 } + unsafe fn from_abi(js: u32, _extra: &mut Stack) -> $t { js as $t } } )*) } @@ -69,54 +99,222 @@ macro_rules! as_u32 { as_u32!(i8 u8 i16 u16 i32 isize usize); impl WasmBoundary for bool { - type Js = u32; - const DESCRIPTOR: u32 = DESCRIPTOR_BOOLEAN; + type Abi = u32; + const DESCRIPTOR: Descriptor = DESCRIPTOR_BOOLEAN; - fn into_js(self) -> u32 { self as u32 } - unsafe fn from_js(js: u32) -> bool { js != 0 } + fn into_abi(self, _extra: &mut Stack) -> u32 { self as u32 } + unsafe fn from_abi(js: u32, _extra: &mut Stack) -> bool { js != 0 } } impl WasmBoundary for *const T { - type Js = u32; - const DESCRIPTOR: u32 = DESCRIPTOR_NUMBER; + type Abi = u32; + const DESCRIPTOR: Descriptor = DESCRIPTOR_NUMBER; - fn into_js(self) -> u32 { self as u32 } - unsafe fn from_js(js: u32) -> *const T { js as *const T } + fn into_abi(self, _extra: &mut Stack) -> u32 { self as u32 } + unsafe fn from_abi(js: u32, _extra: &mut Stack) -> *const T { js as *const T } } impl WasmBoundary for *mut T { - type Js = u32; - const DESCRIPTOR: u32 = DESCRIPTOR_NUMBER; + type Abi = u32; + const DESCRIPTOR: Descriptor = DESCRIPTOR_NUMBER; - fn into_js(self) -> u32 { self as u32 } - unsafe fn from_js(js: u32) -> *mut T { js as *mut T } + fn into_abi(self, _extra: &mut Stack) -> u32 { self as u32 } + unsafe fn from_abi(js: u32, _extra: &mut Stack) -> *mut T { js as *mut T } +} + +macro_rules! vectors { + ($($t:ident => ($owned:expr, $slice:expr))*) => ($( + impl WasmBoundary for Box<[$t]> { + type Abi = u32; + const DESCRIPTOR: Descriptor = Descriptor { __x: *$owned }; + + fn into_abi(self, extra: &mut Stack) -> u32 { + let ptr = self.as_ptr(); + let len = self.len(); + mem::forget(self); + extra.push(len as u32); + ptr.into_abi(extra) + } + + unsafe fn from_abi(js: u32, extra: &mut Stack) -> Box<[$t]> { + let ptr = <*mut $t>::from_abi(js, extra); + let len = extra.pop() as usize; + Vec::from_raw_parts(ptr, len, len).into_boxed_slice() + } + } + + impl ToRefWasmBoundary for [$t] { + type Abi = u32; + const DESCRIPTOR: Descriptor = Descriptor { __x: *$slice }; + + fn to_abi_ref(&self, extra: &mut Stack) -> u32 { + let ptr = self.as_ptr(); + let len = self.len(); + extra.push(len as u32); + ptr.into_abi(extra) + } + } + + impl FromRefWasmBoundary for [$t] { + type Abi = u32; + const DESCRIPTOR: Descriptor = Descriptor { __x: *$slice }; + type RefAnchor = SliceAnchor<$t>; + + unsafe fn from_abi_ref(js: u32, extra: &mut Stack) -> SliceAnchor<$t> { + SliceAnchor { + ptr: <*mut $t>::from_abi(js, extra), + len: extra.pop() as usize, + } + } + } + )*) +} + +pub struct SliceAnchor { + ptr: *mut T, + len: usize, +} + +impl Deref for SliceAnchor { + type Target = [T]; + fn deref(&self) -> &[T] { + unsafe { slice::from_raw_parts(self.ptr, self.len) } + } +} + +vectors! { + u8 => (b" 6", b" 7") + i8 => (b" 8", b" 9") + u16 => (b" 10", b" 11") + i16 => (b" 12", b" 13") + u32 => (b" 14", b" 15") + i32 => (b" 16", b" 17") + f32 => (b" 18", b" 19") + f64 => (b" 20", b" 21") +} + +impl WasmBoundary for Vec where Box<[T]>: WasmBoundary { + type Abi = as WasmBoundary>::Abi; + const DESCRIPTOR: Descriptor = as WasmBoundary>::DESCRIPTOR; + + fn into_abi(self, extra: &mut Stack) -> Self::Abi { + self.into_boxed_slice().into_abi(extra) + } + + unsafe fn from_abi(js: Self::Abi, extra: &mut Stack) -> Self { + >::from_abi(js, extra).into() + } +} + +impl WasmBoundary for String { + type Abi = u32; + const DESCRIPTOR: Descriptor = DESCRIPTOR_STRING; + + fn into_abi(self, extra: &mut Stack) -> u32 { + self.into_bytes().into_abi(extra) + } + + unsafe fn from_abi(js: u32, extra: &mut Stack) -> String { + String::from_utf8_unchecked(Vec::from_abi(js, extra)) + } +} + +impl ToRefWasmBoundary for str { + type Abi = <[u8] as ToRefWasmBoundary>::Abi; + const DESCRIPTOR: Descriptor = DESCRIPTOR_BORROWED_STR; + + fn to_abi_ref(&self, extra: &mut Stack) -> Self::Abi { + self.as_bytes().to_abi_ref(extra) + } +} + +impl FromRefWasmBoundary for str { + type Abi = <[u8] as ToRefWasmBoundary>::Abi; + const DESCRIPTOR: Descriptor = DESCRIPTOR_BORROWED_STR; + type RefAnchor = StrAnchor; + + unsafe fn from_abi_ref(js: Self::Abi, extra: &mut Stack) -> Self::RefAnchor { + StrAnchor { inner: <[u8]>::from_abi_ref(js, extra) } + } +} + +pub struct StrAnchor { + inner: SliceAnchor, +} + +impl Deref for StrAnchor { + type Target = str; + + fn deref(&self) -> &str { + unsafe { str::from_utf8_unchecked(&self.inner) } + } } impl WasmBoundary for JsValue { - type Js = u32; - const DESCRIPTOR: u32 = DESCRIPTOR_JS_OWNED; + type Abi = u32; + const DESCRIPTOR: Descriptor = DESCRIPTOR_JS_OWNED; - fn into_js(self) -> u32 { + fn into_abi(self, _extra: &mut Stack) -> u32 { let ret = self.idx; mem::forget(self); return ret } - unsafe fn from_js(js: u32) -> JsValue { + unsafe fn from_abi(js: u32, _extra: &mut Stack) -> JsValue { JsValue { idx: js } } } impl ToRefWasmBoundary for JsValue { - fn to_js_ref(&self) -> u32 { + type Abi = u32; + const DESCRIPTOR: Descriptor = DESCRIPTOR_JS_REF; + fn to_abi_ref(&self, _extra: &mut Stack) -> u32 { self.idx } } impl FromRefWasmBoundary for JsValue { + type Abi = u32; + const DESCRIPTOR: Descriptor = DESCRIPTOR_JS_REF; type RefAnchor = ManuallyDrop; - unsafe fn from_js_ref(js: u32) -> ManuallyDrop { + unsafe fn from_abi_ref(js: u32, _extra: &mut Stack) -> ManuallyDrop { ManuallyDrop::new(JsValue { idx: js }) } } + +pub struct GlobalStack { next: usize } + +const GLOBAL_STACK_CAP: usize = 16; +static mut GLOBAL_STACK: [u32; GLOBAL_STACK_CAP] = [0; GLOBAL_STACK_CAP]; + +impl GlobalStack { + pub unsafe fn new() -> GlobalStack { + GlobalStack { next: 0 } + } +} + +impl Stack for GlobalStack { + fn push(&mut self, val: u32) { + unsafe { + assert!(self.next < GLOBAL_STACK_CAP); + GLOBAL_STACK[self.next] = val; + self.next += 1; + } + } + + fn pop(&mut self) -> u32 { + unsafe { + assert!(self.next < GLOBAL_STACK_CAP); + let ret = GLOBAL_STACK[self.next]; + self.next += 1; + ret + } + } +} + +#[doc(hidden)] +#[no_mangle] +pub unsafe extern fn __wbindgen_global_argument_ptr() -> *mut u32 { + GLOBAL_STACK.as_mut_ptr() +} diff --git a/src/lib.rs b/src/lib.rs index 7087cfd0..e9e3cb31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -459,20 +459,5 @@ pub mod __rt { 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)); - } - pub fn link_this_library() {} }