Skip to content

Commit

Permalink
Changing to use WasmSlice for the caching
Browse files Browse the repository at this point in the history
  • Loading branch information
Pauan committed Jul 16, 2019
1 parent 632ad64 commit 4303b82
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 67 deletions.
3 changes: 3 additions & 0 deletions crates/cli-support/src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ tys! {
BOOLEAN
FUNCTION
CLOSURE
CACHED_STRING
STRING
REF
REFMUT
Expand Down Expand Up @@ -58,6 +59,7 @@ pub enum Descriptor {
RefMut(Box<Descriptor>),
Slice(Box<Descriptor>),
Vector(Box<Descriptor>),
CachedString,
String,
Anyref,
Enum { hole: u32 },
Expand Down Expand Up @@ -127,6 +129,7 @@ impl Descriptor {
SLICE => Descriptor::Slice(Box::new(Descriptor::_decode(data, clamped))),
VECTOR => Descriptor::Vector(Box::new(Descriptor::_decode(data, clamped))),
OPTIONAL => Descriptor::Option(Box::new(Descriptor::_decode(data, clamped))),
CACHED_STRING => Descriptor::CachedString,
STRING => Descriptor::String,
ANYREF => Descriptor::Anyref,
ENUM => Descriptor::Enum { hole: get(data) },
Expand Down
67 changes: 67 additions & 0 deletions crates/cli-support/src/js/outgoing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,33 @@ impl<'a, 'b> Outgoing<'a, 'b> {
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 {
a,
b,
Expand Down Expand Up @@ -305,6 +332,35 @@ impl<'a, 'b> Outgoing<'a, 'b> {
self.js.prelude("}");
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))
}
}
}

Expand Down Expand Up @@ -408,4 +464,15 @@ impl<'a, 'b> Outgoing<'a, 'b> {
));
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")
}
}
57 changes: 57 additions & 0 deletions crates/cli-support/src/webidl/outgoing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ pub enum NonstandardOutgoing {
kind: VectorKind,
},

///
CachedString {
offset: u32,
length: u32,
owned: bool,
},

/// A `&[u64]` or `&[i64]` is being passed to JS, and the 64-bit sizes here
/// aren't supported by WebIDL bindings yet.
View64 {
Expand All @@ -81,6 +88,13 @@ pub enum NonstandardOutgoing {
kind: VectorKind,
},

///
OptionCachedString {
offset: u32,
length: u32,
owned: bool,
},

/// An optional slice of data is being passed into JS.
///
/// TODO: with some cleverness this could probably use `AllocCopy`.
Expand Down Expand Up @@ -240,6 +254,17 @@ impl OutgoingBuilder<'_> {
Descriptor::Ref(d) => self.process_ref(false, 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 => {
let kind = arg.vector_kind().ok_or_else(|| {
format_err!(
Expand Down Expand Up @@ -281,6 +306,16 @@ impl OutgoingBuilder<'_> {
self.bindings
.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 => {
use wasm_webidl_bindings::ast::WebidlScalarType::*;

Expand Down Expand Up @@ -422,6 +457,18 @@ impl OutgoingBuilder<'_> {
}
Descriptor::Ref(d) => self.process_option_ref(false, 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(_) => {
let kind = arg.vector_kind().ok_or_else(|| {
format_err!(
Expand Down Expand Up @@ -455,6 +502,16 @@ impl OutgoingBuilder<'_> {
self.bindings
.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(_) => {
let kind = arg.vector_kind().ok_or_else(|| {
format_err!(
Expand Down
7 changes: 4 additions & 3 deletions src/cache/intern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,16 @@ cfg_if! {
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| {
let mut cache = cache.entries.borrow_mut();

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 {
JsValue::from(s)
None
}
})
}
Expand Down
104 changes: 42 additions & 62 deletions src/convert/slices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,29 @@ vectors! {
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! {
impl<T> IntoWasmAbi for Vec<T> where Box<[T]>: IntoWasmAbi<Abi = WasmSlice> {
type Abi = <Box<[T]> as IntoWasmAbi>::Abi;
Expand All @@ -149,41 +172,20 @@ if_std! {
fn is_none(abi: &WasmSlice) -> bool { abi.ptr == 0 }
}

cfg_if! {
if #[cfg(feature = "enable-interning")] {
impl IntoWasmAbi for String {
type Abi = <JsValue as IntoWasmAbi>::Abi;

#[inline]
fn into_abi(self) -> Self::Abi {
crate::cache::intern::get_str(&self).into_abi()
}
}

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 IntoWasmAbi for String {
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;

impl OptionIntoWasmAbi for String {
#[inline]
fn none() -> Self::Abi { null_slice() }
}
#[inline]
fn into_abi(self) -> Self::Abi {
get_cached_str(&self)
}
}

impl OptionIntoWasmAbi for String {
#[inline]
fn none() -> Self::Abi { null_slice() }
}

impl FromWasmAbi for String {
type Abi = <Vec<u8> as FromWasmAbi>::Abi;

Expand All @@ -198,41 +200,19 @@ if_std! {
}
}

impl<'a> IntoWasmAbi for &'a str {
type Abi = <&'a [u8] as IntoWasmAbi>::Abi;

cfg_if! {
if #[cfg(feature = "enable-interning")] {
impl<'a> IntoWasmAbi for &'a str {
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() }
}
#[inline]
fn into_abi(self) -> Self::Abi {
get_cached_str(self)
}
}

impl<'a> OptionIntoWasmAbi for &'a str {
fn none() -> Self::Abi { null_slice() }
}

impl RefFromWasmAbi for str {
type Abi = <[u8] as RefFromWasmAbi>::Abi;
type Anchor = Box<str>;
Expand Down
5 changes: 3 additions & 2 deletions src/describe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ tys! {
BOOLEAN
FUNCTION
CLOSURE
CACHED_STRING
STRING
REF
REFMUT
Expand Down Expand Up @@ -75,7 +76,7 @@ simple! {
f64 => F64
bool => BOOLEAN
char => CHAR
str => if cfg!(feature = "enable-interning") { ANYREF } else { STRING }
str => if cfg!(feature = "enable-interning") { CACHED_STRING } else { STRING }
JsValue => ANYREF
}

Expand Down Expand Up @@ -116,7 +117,7 @@ if_std! {
use std::prelude::v1::*;

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]> {
Expand Down
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
/// The utf-8 string provided is copied to the JS heap and the string will
Expand Down

0 comments on commit 4303b82

Please sign in to comment.