mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-15 18:04:55 +00:00
Changing to use WasmSlice for the caching
This commit is contained in:
parent
f7e8e70684
commit
2ee4c54f00
@ -24,6 +24,7 @@ tys! {
|
|||||||
BOOLEAN
|
BOOLEAN
|
||||||
FUNCTION
|
FUNCTION
|
||||||
CLOSURE
|
CLOSURE
|
||||||
|
CACHED_STRING
|
||||||
STRING
|
STRING
|
||||||
REF
|
REF
|
||||||
REFMUT
|
REFMUT
|
||||||
@ -58,6 +59,7 @@ pub enum Descriptor {
|
|||||||
RefMut(Box<Descriptor>),
|
RefMut(Box<Descriptor>),
|
||||||
Slice(Box<Descriptor>),
|
Slice(Box<Descriptor>),
|
||||||
Vector(Box<Descriptor>),
|
Vector(Box<Descriptor>),
|
||||||
|
CachedString,
|
||||||
String,
|
String,
|
||||||
Anyref,
|
Anyref,
|
||||||
Enum { hole: u32 },
|
Enum { hole: u32 },
|
||||||
@ -127,6 +129,7 @@ impl Descriptor {
|
|||||||
SLICE => Descriptor::Slice(Box::new(Descriptor::_decode(data, clamped))),
|
SLICE => Descriptor::Slice(Box::new(Descriptor::_decode(data, clamped))),
|
||||||
VECTOR => Descriptor::Vector(Box::new(Descriptor::_decode(data, clamped))),
|
VECTOR => Descriptor::Vector(Box::new(Descriptor::_decode(data, clamped))),
|
||||||
OPTIONAL => Descriptor::Option(Box::new(Descriptor::_decode(data, clamped))),
|
OPTIONAL => Descriptor::Option(Box::new(Descriptor::_decode(data, clamped))),
|
||||||
|
CACHED_STRING => Descriptor::CachedString,
|
||||||
STRING => Descriptor::String,
|
STRING => Descriptor::String,
|
||||||
ANYREF => Descriptor::Anyref,
|
ANYREF => Descriptor::Anyref,
|
||||||
ENUM => Descriptor::Enum { hole: get(data) },
|
ENUM => Descriptor::Enum { hole: get(data) },
|
||||||
|
@ -130,6 +130,33 @@ impl<'a, 'b> Outgoing<'a, 'b> {
|
|||||||
Ok(format!("v{}", i))
|
Ok(format!("v{}", i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NonstandardOutgoing::CachedString {
|
||||||
|
offset,
|
||||||
|
length,
|
||||||
|
owned,
|
||||||
|
} => {
|
||||||
|
let ptr = self.arg(*offset);
|
||||||
|
let len = self.arg(*length);
|
||||||
|
let tmp = self.js.tmp();
|
||||||
|
|
||||||
|
self.js.typescript_required("string");
|
||||||
|
self.cx.expose_get_object();
|
||||||
|
self.cx.expose_get_string_from_wasm()?;
|
||||||
|
|
||||||
|
self.js.prelude(&format!(
|
||||||
|
"const v{tmp} = {ptr} === 0 ? getObject({len}) : getStringFromWasm({ptr}, {len});",
|
||||||
|
tmp = tmp,
|
||||||
|
ptr = ptr,
|
||||||
|
len = len,
|
||||||
|
));
|
||||||
|
|
||||||
|
if *owned {
|
||||||
|
self.prelude_free_cached_string(&ptr, &len)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(format!("v{}", tmp))
|
||||||
|
}
|
||||||
|
|
||||||
NonstandardOutgoing::StackClosure {
|
NonstandardOutgoing::StackClosure {
|
||||||
a,
|
a,
|
||||||
b,
|
b,
|
||||||
@ -305,6 +332,35 @@ impl<'a, 'b> Outgoing<'a, 'b> {
|
|||||||
self.js.prelude("}");
|
self.js.prelude("}");
|
||||||
Ok(format!("v{}", i))
|
Ok(format!("v{}", i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NonstandardOutgoing::OptionCachedString {
|
||||||
|
offset,
|
||||||
|
length,
|
||||||
|
owned,
|
||||||
|
} => {
|
||||||
|
let ptr = self.arg(*offset);
|
||||||
|
let len = self.arg(*length);
|
||||||
|
let tmp = self.js.tmp();
|
||||||
|
|
||||||
|
self.js.typescript_optional("string");
|
||||||
|
self.cx.expose_get_object();
|
||||||
|
self.cx.expose_get_string_from_wasm()?;
|
||||||
|
|
||||||
|
self.js.prelude(&format!("let v{};", tmp));
|
||||||
|
|
||||||
|
self.js.prelude(&format!(
|
||||||
|
"if ({ptr} === 0) {{ if ({len} !== 0) {{ v{tmp} = getObject({len}); }} }} else {{ v{tmp} = getStringFromWasm({ptr}, {len}); }}",
|
||||||
|
tmp = tmp,
|
||||||
|
ptr = ptr,
|
||||||
|
len = len,
|
||||||
|
));
|
||||||
|
|
||||||
|
if *owned {
|
||||||
|
self.prelude_free_cached_string(&ptr, &len)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(format!("v{}", tmp))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,4 +464,15 @@ impl<'a, 'b> Outgoing<'a, 'b> {
|
|||||||
));
|
));
|
||||||
self.cx.require_internal_export("__wbindgen_free")
|
self.cx.require_internal_export("__wbindgen_free")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prelude_free_cached_string(&mut self, ptr: &str, len: &str) -> Result<(), Error> {
|
||||||
|
self.js.prelude(&format!(
|
||||||
|
"if ({ptr} !== 0) {{ wasm.__wbindgen_free({ptr}, {len} * {size}); }}",
|
||||||
|
ptr = ptr,
|
||||||
|
len = len,
|
||||||
|
size = VectorKind::String.size(),
|
||||||
|
));
|
||||||
|
|
||||||
|
self.cx.require_internal_export("__wbindgen_free")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,13 @@ pub enum NonstandardOutgoing {
|
|||||||
kind: VectorKind,
|
kind: VectorKind,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
///
|
||||||
|
CachedString {
|
||||||
|
offset: u32,
|
||||||
|
length: u32,
|
||||||
|
owned: bool,
|
||||||
|
},
|
||||||
|
|
||||||
/// A `&[u64]` or `&[i64]` is being passed to JS, and the 64-bit sizes here
|
/// A `&[u64]` or `&[i64]` is being passed to JS, and the 64-bit sizes here
|
||||||
/// aren't supported by WebIDL bindings yet.
|
/// aren't supported by WebIDL bindings yet.
|
||||||
View64 {
|
View64 {
|
||||||
@ -81,6 +88,13 @@ pub enum NonstandardOutgoing {
|
|||||||
kind: VectorKind,
|
kind: VectorKind,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
///
|
||||||
|
OptionCachedString {
|
||||||
|
offset: u32,
|
||||||
|
length: u32,
|
||||||
|
owned: bool,
|
||||||
|
},
|
||||||
|
|
||||||
/// An optional slice of data is being passed into JS.
|
/// An optional slice of data is being passed into JS.
|
||||||
///
|
///
|
||||||
/// TODO: with some cleverness this could probably use `AllocCopy`.
|
/// TODO: with some cleverness this could probably use `AllocCopy`.
|
||||||
@ -240,6 +254,17 @@ impl OutgoingBuilder<'_> {
|
|||||||
Descriptor::Ref(d) => self.process_ref(false, d)?,
|
Descriptor::Ref(d) => self.process_ref(false, d)?,
|
||||||
Descriptor::RefMut(d) => self.process_ref(true, d)?,
|
Descriptor::RefMut(d) => self.process_ref(true, d)?,
|
||||||
|
|
||||||
|
Descriptor::CachedString => {
|
||||||
|
let offset = self.push_wasm(ValType::I32);
|
||||||
|
let length = self.push_wasm(ValType::I32);
|
||||||
|
self.webidl.push(ast::WebidlScalarType::Any);
|
||||||
|
self.bindings.push(NonstandardOutgoing::CachedString {
|
||||||
|
offset,
|
||||||
|
length,
|
||||||
|
owned: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Descriptor::Vector(_) | Descriptor::String => {
|
Descriptor::Vector(_) | Descriptor::String => {
|
||||||
let kind = arg.vector_kind().ok_or_else(|| {
|
let kind = arg.vector_kind().ok_or_else(|| {
|
||||||
format_err!(
|
format_err!(
|
||||||
@ -281,6 +306,16 @@ impl OutgoingBuilder<'_> {
|
|||||||
self.bindings
|
self.bindings
|
||||||
.push(NonstandardOutgoing::BorrowedAnyref { idx });
|
.push(NonstandardOutgoing::BorrowedAnyref { idx });
|
||||||
}
|
}
|
||||||
|
Descriptor::CachedString => {
|
||||||
|
let offset = self.push_wasm(ValType::I32);
|
||||||
|
let length = self.push_wasm(ValType::I32);
|
||||||
|
self.webidl.push(ast::WebidlScalarType::DomString);
|
||||||
|
self.bindings.push(NonstandardOutgoing::CachedString {
|
||||||
|
offset,
|
||||||
|
length,
|
||||||
|
owned: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
Descriptor::Slice(_) | Descriptor::String => {
|
Descriptor::Slice(_) | Descriptor::String => {
|
||||||
use wasm_webidl_bindings::ast::WebidlScalarType::*;
|
use wasm_webidl_bindings::ast::WebidlScalarType::*;
|
||||||
|
|
||||||
@ -422,6 +457,18 @@ impl OutgoingBuilder<'_> {
|
|||||||
}
|
}
|
||||||
Descriptor::Ref(d) => self.process_option_ref(false, d)?,
|
Descriptor::Ref(d) => self.process_option_ref(false, d)?,
|
||||||
Descriptor::RefMut(d) => self.process_option_ref(true, d)?,
|
Descriptor::RefMut(d) => self.process_option_ref(true, d)?,
|
||||||
|
|
||||||
|
Descriptor::CachedString => {
|
||||||
|
let offset = self.push_wasm(ValType::I32);
|
||||||
|
let length = self.push_wasm(ValType::I32);
|
||||||
|
self.webidl.push(ast::WebidlScalarType::DomString);
|
||||||
|
self.bindings.push(NonstandardOutgoing::OptionCachedString {
|
||||||
|
offset,
|
||||||
|
length,
|
||||||
|
owned: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Descriptor::String | Descriptor::Vector(_) => {
|
Descriptor::String | Descriptor::Vector(_) => {
|
||||||
let kind = arg.vector_kind().ok_or_else(|| {
|
let kind = arg.vector_kind().ok_or_else(|| {
|
||||||
format_err!(
|
format_err!(
|
||||||
@ -455,6 +502,16 @@ impl OutgoingBuilder<'_> {
|
|||||||
self.bindings
|
self.bindings
|
||||||
.push(NonstandardOutgoing::BorrowedAnyref { idx });
|
.push(NonstandardOutgoing::BorrowedAnyref { idx });
|
||||||
}
|
}
|
||||||
|
Descriptor::CachedString => {
|
||||||
|
let offset = self.push_wasm(ValType::I32);
|
||||||
|
let length = self.push_wasm(ValType::I32);
|
||||||
|
self.webidl.push(ast::WebidlScalarType::DomString);
|
||||||
|
self.bindings.push(NonstandardOutgoing::OptionCachedString {
|
||||||
|
offset,
|
||||||
|
length,
|
||||||
|
owned: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
Descriptor::String | Descriptor::Slice(_) => {
|
Descriptor::String | Descriptor::Slice(_) => {
|
||||||
let kind = arg.vector_kind().ok_or_else(|| {
|
let kind = arg.vector_kind().ok_or_else(|| {
|
||||||
format_err!(
|
format_err!(
|
||||||
|
7
src/cache/intern.rs
vendored
7
src/cache/intern.rs
vendored
@ -33,15 +33,16 @@ cfg_if! {
|
|||||||
cache.find(|p| p.key == key).map(|x| &x.value)
|
cache.find(|p| p.key == key).map(|x| &x.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_str(s: &str) -> JsValue {
|
pub(crate) fn get_str(s: &str) -> Option<JsValue> {
|
||||||
CACHE.with(|cache| {
|
CACHE.with(|cache| {
|
||||||
let mut cache = cache.entries.borrow_mut();
|
let mut cache = cache.entries.borrow_mut();
|
||||||
|
|
||||||
if let Some(value) = get_js_string(&mut cache, s) {
|
if let Some(value) = get_js_string(&mut cache, s) {
|
||||||
value.clone()
|
// This is safe because the cache values are never removed
|
||||||
|
Some(value._unsafe_clone())
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
JsValue::from(s)
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,29 @@ vectors! {
|
|||||||
u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64
|
u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "enable-interning")] {
|
||||||
|
#[inline]
|
||||||
|
fn get_cached_str(x: &str) -> WasmSlice {
|
||||||
|
if let Some(x) = crate::cache::intern::get_str(x) {
|
||||||
|
// This uses 0 for the ptr as an indication that it is a JsValue and not a str
|
||||||
|
WasmSlice { ptr: 0, len: x.into_abi() }
|
||||||
|
|
||||||
|
} else {
|
||||||
|
x.into_bytes().into_abi()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
#[inline]
|
||||||
|
fn get_cached_str(x: &str) -> WasmSlice {
|
||||||
|
x.into_bytes().into_abi()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if_std! {
|
if_std! {
|
||||||
impl<T> IntoWasmAbi for Vec<T> where Box<[T]>: IntoWasmAbi<Abi = WasmSlice> {
|
impl<T> IntoWasmAbi for Vec<T> where Box<[T]>: IntoWasmAbi<Abi = WasmSlice> {
|
||||||
type Abi = <Box<[T]> as IntoWasmAbi>::Abi;
|
type Abi = <Box<[T]> as IntoWasmAbi>::Abi;
|
||||||
@ -149,41 +172,20 @@ if_std! {
|
|||||||
fn is_none(abi: &WasmSlice) -> bool { abi.ptr == 0 }
|
fn is_none(abi: &WasmSlice) -> bool { abi.ptr == 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
impl IntoWasmAbi for String {
|
||||||
if #[cfg(feature = "enable-interning")] {
|
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
|
||||||
impl IntoWasmAbi for String {
|
|
||||||
type Abi = <JsValue as IntoWasmAbi>::Abi;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_abi(self) -> Self::Abi {
|
fn into_abi(self) -> Self::Abi {
|
||||||
crate::cache::intern::get_str(&self).into_abi()
|
get_cached_str(&self)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OptionIntoWasmAbi for String {
|
|
||||||
#[inline]
|
|
||||||
fn none() -> Self::Abi {
|
|
||||||
JsValue::UNDEFINED.into_abi()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
impl IntoWasmAbi for String {
|
|
||||||
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn into_abi(self) -> Self::Abi {
|
|
||||||
self.into_bytes().into_abi()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OptionIntoWasmAbi for String {
|
|
||||||
#[inline]
|
|
||||||
fn none() -> Self::Abi { null_slice() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OptionIntoWasmAbi for String {
|
||||||
|
#[inline]
|
||||||
|
fn none() -> Self::Abi { null_slice() }
|
||||||
|
}
|
||||||
|
|
||||||
impl FromWasmAbi for String {
|
impl FromWasmAbi for String {
|
||||||
type Abi = <Vec<u8> as FromWasmAbi>::Abi;
|
type Abi = <Vec<u8> as FromWasmAbi>::Abi;
|
||||||
|
|
||||||
@ -198,41 +200,19 @@ if_std! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoWasmAbi for &'a str {
|
||||||
|
type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
|
||||||
|
|
||||||
cfg_if! {
|
#[inline]
|
||||||
if #[cfg(feature = "enable-interning")] {
|
fn into_abi(self) -> Self::Abi {
|
||||||
impl<'a> IntoWasmAbi for &'a str {
|
get_cached_str(self)
|
||||||
type Abi = <JsValue as IntoWasmAbi>::Abi;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn into_abi(self) -> Self::Abi {
|
|
||||||
crate::cache::intern::get_str(self).into_abi()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> OptionIntoWasmAbi for &'a str {
|
|
||||||
#[inline]
|
|
||||||
fn none() -> Self::Abi {
|
|
||||||
JsValue::UNDEFINED.into_abi()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
impl<'a> IntoWasmAbi for &'a str {
|
|
||||||
type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn into_abi(self) -> Self::Abi {
|
|
||||||
self.as_bytes().into_abi()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> OptionIntoWasmAbi for &'a str {
|
|
||||||
fn none() -> Self::Abi { null_slice() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> OptionIntoWasmAbi for &'a str {
|
||||||
|
fn none() -> Self::Abi { null_slice() }
|
||||||
|
}
|
||||||
|
|
||||||
impl RefFromWasmAbi for str {
|
impl RefFromWasmAbi for str {
|
||||||
type Abi = <[u8] as RefFromWasmAbi>::Abi;
|
type Abi = <[u8] as RefFromWasmAbi>::Abi;
|
||||||
type Anchor = Box<str>;
|
type Anchor = Box<str>;
|
||||||
|
@ -29,6 +29,7 @@ tys! {
|
|||||||
BOOLEAN
|
BOOLEAN
|
||||||
FUNCTION
|
FUNCTION
|
||||||
CLOSURE
|
CLOSURE
|
||||||
|
CACHED_STRING
|
||||||
STRING
|
STRING
|
||||||
REF
|
REF
|
||||||
REFMUT
|
REFMUT
|
||||||
@ -75,7 +76,7 @@ simple! {
|
|||||||
f64 => F64
|
f64 => F64
|
||||||
bool => BOOLEAN
|
bool => BOOLEAN
|
||||||
char => CHAR
|
char => CHAR
|
||||||
str => if cfg!(feature = "enable-interning") { ANYREF } else { STRING }
|
str => if cfg!(feature = "enable-interning") { CACHED_STRING } else { STRING }
|
||||||
JsValue => ANYREF
|
JsValue => ANYREF
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ if_std! {
|
|||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
impl WasmDescribe for String {
|
impl WasmDescribe for String {
|
||||||
fn describe() { inform(if cfg!(feature = "enable-interning") { ANYREF } else { STRING }) }
|
fn describe() { inform(if cfg!(feature = "enable-interning") { CACHED_STRING } else { STRING }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: WasmDescribe> WasmDescribe for Box<[T]> {
|
impl<T: WasmDescribe> WasmDescribe for Box<[T]> {
|
||||||
|
@ -125,6 +125,11 @@ impl JsValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn _unsafe_clone(&self) -> JsValue {
|
||||||
|
Self::_new(self.idx)
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new JS value which is a string.
|
/// Creates a new JS value which is a string.
|
||||||
///
|
///
|
||||||
/// The utf-8 string provided is copied to the JS heap and the string will
|
/// The utf-8 string provided is copied to the JS heap and the string will
|
||||||
|
Loading…
x
Reference in New Issue
Block a user