Skip to content

Commit 2ee4c54

Browse files
committed
Changing to use WasmSlice for the caching
1 parent f7e8e70 commit 2ee4c54

File tree

7 files changed

+181
-67
lines changed

7 files changed

+181
-67
lines changed

crates/cli-support/src/descriptor.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ tys! {
2424
BOOLEAN
2525
FUNCTION
2626
CLOSURE
27+
CACHED_STRING
2728
STRING
2829
REF
2930
REFMUT
@@ -58,6 +59,7 @@ pub enum Descriptor {
5859
RefMut(Box<Descriptor>),
5960
Slice(Box<Descriptor>),
6061
Vector(Box<Descriptor>),
62+
CachedString,
6163
String,
6264
Anyref,
6365
Enum { hole: u32 },
@@ -127,6 +129,7 @@ impl Descriptor {
127129
SLICE => Descriptor::Slice(Box::new(Descriptor::_decode(data, clamped))),
128130
VECTOR => Descriptor::Vector(Box::new(Descriptor::_decode(data, clamped))),
129131
OPTIONAL => Descriptor::Option(Box::new(Descriptor::_decode(data, clamped))),
132+
CACHED_STRING => Descriptor::CachedString,
130133
STRING => Descriptor::String,
131134
ANYREF => Descriptor::Anyref,
132135
ENUM => Descriptor::Enum { hole: get(data) },

crates/cli-support/src/js/outgoing.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,33 @@ impl<'a, 'b> Outgoing<'a, 'b> {
130130
Ok(format!("v{}", i))
131131
}
132132

133+
NonstandardOutgoing::CachedString {
134+
offset,
135+
length,
136+
owned,
137+
} => {
138+
let ptr = self.arg(*offset);
139+
let len = self.arg(*length);
140+
let tmp = self.js.tmp();
141+
142+
self.js.typescript_required("string");
143+
self.cx.expose_get_object();
144+
self.cx.expose_get_string_from_wasm()?;
145+
146+
self.js.prelude(&format!(
147+
"const v{tmp} = {ptr} === 0 ? getObject({len}) : getStringFromWasm({ptr}, {len});",
148+
tmp = tmp,
149+
ptr = ptr,
150+
len = len,
151+
));
152+
153+
if *owned {
154+
self.prelude_free_cached_string(&ptr, &len)?;
155+
}
156+
157+
Ok(format!("v{}", tmp))
158+
}
159+
133160
NonstandardOutgoing::StackClosure {
134161
a,
135162
b,
@@ -305,6 +332,35 @@ impl<'a, 'b> Outgoing<'a, 'b> {
305332
self.js.prelude("}");
306333
Ok(format!("v{}", i))
307334
}
335+
336+
NonstandardOutgoing::OptionCachedString {
337+
offset,
338+
length,
339+
owned,
340+
} => {
341+
let ptr = self.arg(*offset);
342+
let len = self.arg(*length);
343+
let tmp = self.js.tmp();
344+
345+
self.js.typescript_optional("string");
346+
self.cx.expose_get_object();
347+
self.cx.expose_get_string_from_wasm()?;
348+
349+
self.js.prelude(&format!("let v{};", tmp));
350+
351+
self.js.prelude(&format!(
352+
"if ({ptr} === 0) {{ if ({len} !== 0) {{ v{tmp} = getObject({len}); }} }} else {{ v{tmp} = getStringFromWasm({ptr}, {len}); }}",
353+
tmp = tmp,
354+
ptr = ptr,
355+
len = len,
356+
));
357+
358+
if *owned {
359+
self.prelude_free_cached_string(&ptr, &len)?;
360+
}
361+
362+
Ok(format!("v{}", tmp))
363+
}
308364
}
309365
}
310366

@@ -408,4 +464,15 @@ impl<'a, 'b> Outgoing<'a, 'b> {
408464
));
409465
self.cx.require_internal_export("__wbindgen_free")
410466
}
467+
468+
fn prelude_free_cached_string(&mut self, ptr: &str, len: &str) -> Result<(), Error> {
469+
self.js.prelude(&format!(
470+
"if ({ptr} !== 0) {{ wasm.__wbindgen_free({ptr}, {len} * {size}); }}",
471+
ptr = ptr,
472+
len = len,
473+
size = VectorKind::String.size(),
474+
));
475+
476+
self.cx.require_internal_export("__wbindgen_free")
477+
}
411478
}

crates/cli-support/src/webidl/outgoing.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ pub enum NonstandardOutgoing {
6060
kind: VectorKind,
6161
},
6262

63+
///
64+
CachedString {
65+
offset: u32,
66+
length: u32,
67+
owned: bool,
68+
},
69+
6370
/// A `&[u64]` or `&[i64]` is being passed to JS, and the 64-bit sizes here
6471
/// aren't supported by WebIDL bindings yet.
6572
View64 {
@@ -81,6 +88,13 @@ pub enum NonstandardOutgoing {
8188
kind: VectorKind,
8289
},
8390

91+
///
92+
OptionCachedString {
93+
offset: u32,
94+
length: u32,
95+
owned: bool,
96+
},
97+
8498
/// An optional slice of data is being passed into JS.
8599
///
86100
/// TODO: with some cleverness this could probably use `AllocCopy`.
@@ -240,6 +254,17 @@ impl OutgoingBuilder<'_> {
240254
Descriptor::Ref(d) => self.process_ref(false, d)?,
241255
Descriptor::RefMut(d) => self.process_ref(true, d)?,
242256

257+
Descriptor::CachedString => {
258+
let offset = self.push_wasm(ValType::I32);
259+
let length = self.push_wasm(ValType::I32);
260+
self.webidl.push(ast::WebidlScalarType::Any);
261+
self.bindings.push(NonstandardOutgoing::CachedString {
262+
offset,
263+
length,
264+
owned: true,
265+
})
266+
}
267+
243268
Descriptor::Vector(_) | Descriptor::String => {
244269
let kind = arg.vector_kind().ok_or_else(|| {
245270
format_err!(
@@ -281,6 +306,16 @@ impl OutgoingBuilder<'_> {
281306
self.bindings
282307
.push(NonstandardOutgoing::BorrowedAnyref { idx });
283308
}
309+
Descriptor::CachedString => {
310+
let offset = self.push_wasm(ValType::I32);
311+
let length = self.push_wasm(ValType::I32);
312+
self.webidl.push(ast::WebidlScalarType::DomString);
313+
self.bindings.push(NonstandardOutgoing::CachedString {
314+
offset,
315+
length,
316+
owned: false,
317+
})
318+
}
284319
Descriptor::Slice(_) | Descriptor::String => {
285320
use wasm_webidl_bindings::ast::WebidlScalarType::*;
286321

@@ -422,6 +457,18 @@ impl OutgoingBuilder<'_> {
422457
}
423458
Descriptor::Ref(d) => self.process_option_ref(false, d)?,
424459
Descriptor::RefMut(d) => self.process_option_ref(true, d)?,
460+
461+
Descriptor::CachedString => {
462+
let offset = self.push_wasm(ValType::I32);
463+
let length = self.push_wasm(ValType::I32);
464+
self.webidl.push(ast::WebidlScalarType::DomString);
465+
self.bindings.push(NonstandardOutgoing::OptionCachedString {
466+
offset,
467+
length,
468+
owned: true,
469+
})
470+
}
471+
425472
Descriptor::String | Descriptor::Vector(_) => {
426473
let kind = arg.vector_kind().ok_or_else(|| {
427474
format_err!(
@@ -455,6 +502,16 @@ impl OutgoingBuilder<'_> {
455502
self.bindings
456503
.push(NonstandardOutgoing::BorrowedAnyref { idx });
457504
}
505+
Descriptor::CachedString => {
506+
let offset = self.push_wasm(ValType::I32);
507+
let length = self.push_wasm(ValType::I32);
508+
self.webidl.push(ast::WebidlScalarType::DomString);
509+
self.bindings.push(NonstandardOutgoing::OptionCachedString {
510+
offset,
511+
length,
512+
owned: false,
513+
})
514+
}
458515
Descriptor::String | Descriptor::Slice(_) => {
459516
let kind = arg.vector_kind().ok_or_else(|| {
460517
format_err!(

src/cache/intern.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,16 @@ cfg_if! {
3333
cache.find(|p| p.key == key).map(|x| &x.value)
3434
}
3535

36-
pub(crate) fn get_str(s: &str) -> JsValue {
36+
pub(crate) fn get_str(s: &str) -> Option<JsValue> {
3737
CACHE.with(|cache| {
3838
let mut cache = cache.entries.borrow_mut();
3939

4040
if let Some(value) = get_js_string(&mut cache, s) {
41-
value.clone()
41+
// This is safe because the cache values are never removed
42+
Some(value._unsafe_clone())
4243

4344
} else {
44-
JsValue::from(s)
45+
None
4546
}
4647
})
4748
}

src/convert/slices.rs

Lines changed: 42 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,29 @@ vectors! {
124124
u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64
125125
}
126126

127+
128+
cfg_if! {
129+
if #[cfg(feature = "enable-interning")] {
130+
#[inline]
131+
fn get_cached_str(x: &str) -> WasmSlice {
132+
if let Some(x) = crate::cache::intern::get_str(x) {
133+
// This uses 0 for the ptr as an indication that it is a JsValue and not a str
134+
WasmSlice { ptr: 0, len: x.into_abi() }
135+
136+
} else {
137+
x.into_bytes().into_abi()
138+
}
139+
}
140+
141+
} else {
142+
#[inline]
143+
fn get_cached_str(x: &str) -> WasmSlice {
144+
x.into_bytes().into_abi()
145+
}
146+
}
147+
}
148+
149+
127150
if_std! {
128151
impl<T> IntoWasmAbi for Vec<T> where Box<[T]>: IntoWasmAbi<Abi = WasmSlice> {
129152
type Abi = <Box<[T]> as IntoWasmAbi>::Abi;
@@ -149,41 +172,20 @@ if_std! {
149172
fn is_none(abi: &WasmSlice) -> bool { abi.ptr == 0 }
150173
}
151174

152-
cfg_if! {
153-
if #[cfg(feature = "enable-interning")] {
154-
impl IntoWasmAbi for String {
155-
type Abi = <JsValue as IntoWasmAbi>::Abi;
156-
157-
#[inline]
158-
fn into_abi(self) -> Self::Abi {
159-
crate::cache::intern::get_str(&self).into_abi()
160-
}
161-
}
162-
163-
impl OptionIntoWasmAbi for String {
164-
#[inline]
165-
fn none() -> Self::Abi {
166-
JsValue::UNDEFINED.into_abi()
167-
}
168-
}
169-
170-
} else {
171-
impl IntoWasmAbi for String {
172-
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
173-
174-
#[inline]
175-
fn into_abi(self) -> Self::Abi {
176-
self.into_bytes().into_abi()
177-
}
178-
}
175+
impl IntoWasmAbi for String {
176+
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
179177

180-
impl OptionIntoWasmAbi for String {
181-
#[inline]
182-
fn none() -> Self::Abi { null_slice() }
183-
}
178+
#[inline]
179+
fn into_abi(self) -> Self::Abi {
180+
get_cached_str(&self)
184181
}
185182
}
186183

184+
impl OptionIntoWasmAbi for String {
185+
#[inline]
186+
fn none() -> Self::Abi { null_slice() }
187+
}
188+
187189
impl FromWasmAbi for String {
188190
type Abi = <Vec<u8> as FromWasmAbi>::Abi;
189191

@@ -198,41 +200,19 @@ if_std! {
198200
}
199201
}
200202

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

202-
cfg_if! {
203-
if #[cfg(feature = "enable-interning")] {
204-
impl<'a> IntoWasmAbi for &'a str {
205-
type Abi = <JsValue as IntoWasmAbi>::Abi;
206-
207-
#[inline]
208-
fn into_abi(self) -> Self::Abi {
209-
crate::cache::intern::get_str(self).into_abi()
210-
}
211-
}
212-
213-
impl<'a> OptionIntoWasmAbi for &'a str {
214-
#[inline]
215-
fn none() -> Self::Abi {
216-
JsValue::UNDEFINED.into_abi()
217-
}
218-
}
219-
220-
} else {
221-
impl<'a> IntoWasmAbi for &'a str {
222-
type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
223-
224-
#[inline]
225-
fn into_abi(self) -> Self::Abi {
226-
self.as_bytes().into_abi()
227-
}
228-
}
229-
230-
impl<'a> OptionIntoWasmAbi for &'a str {
231-
fn none() -> Self::Abi { null_slice() }
232-
}
206+
#[inline]
207+
fn into_abi(self) -> Self::Abi {
208+
get_cached_str(self)
233209
}
234210
}
235211

212+
impl<'a> OptionIntoWasmAbi for &'a str {
213+
fn none() -> Self::Abi { null_slice() }
214+
}
215+
236216
impl RefFromWasmAbi for str {
237217
type Abi = <[u8] as RefFromWasmAbi>::Abi;
238218
type Anchor = Box<str>;

src/describe.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ tys! {
2929
BOOLEAN
3030
FUNCTION
3131
CLOSURE
32+
CACHED_STRING
3233
STRING
3334
REF
3435
REFMUT
@@ -75,7 +76,7 @@ simple! {
7576
f64 => F64
7677
bool => BOOLEAN
7778
char => CHAR
78-
str => if cfg!(feature = "enable-interning") { ANYREF } else { STRING }
79+
str => if cfg!(feature = "enable-interning") { CACHED_STRING } else { STRING }
7980
JsValue => ANYREF
8081
}
8182

@@ -116,7 +117,7 @@ if_std! {
116117
use std::prelude::v1::*;
117118

118119
impl WasmDescribe for String {
119-
fn describe() { inform(if cfg!(feature = "enable-interning") { ANYREF } else { STRING }) }
120+
fn describe() { inform(if cfg!(feature = "enable-interning") { CACHED_STRING } else { STRING }) }
120121
}
121122

122123
impl<T: WasmDescribe> WasmDescribe for Box<[T]> {

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ impl JsValue {
125125
}
126126
}
127127

128+
#[inline]
129+
fn _unsafe_clone(&self) -> JsValue {
130+
Self::_new(self.idx)
131+
}
132+
128133
/// Creates a new JS value which is a string.
129134
///
130135
/// The utf-8 string provided is copied to the JS heap and the string will

0 commit comments

Comments
 (0)