Skip to content

Commit 84b444d

Browse files
committed
Changing IntoWasmAbi to use interning
1 parent 9d58b56 commit 84b444d

File tree

9 files changed

+171
-144
lines changed

9 files changed

+171
-144
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ spans = ["wasm-bindgen-macro/spans"]
2525
std = []
2626
serde-serialize = ["serde", "serde_json", "std"]
2727
nightly = []
28+
disable-interning = []
2829

2930
# Whether or not the `#[wasm_bindgen]` macro is strict and generates an error on
3031
# all unused attributes
@@ -38,6 +39,8 @@ xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_
3839
wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.47" }
3940
serde = { version = "1.0", optional = true }
4041
serde_json = { version = "1.0", optional = true }
42+
uluru = "0.3.0"
43+
cfg-if = "0.1.9"
4144

4245
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
4346
js-sys = { path = 'crates/js-sys', version = '0.3.24' }
@@ -89,6 +92,5 @@ exclude = ['crates/typescript']
8992
[patch.crates-io]
9093
wasm-bindgen = { path = '.' }
9194
wasm-bindgen-futures = { path = 'crates/futures' }
92-
wasm-bindgen-cache = { path = 'crates/cache' }
9395
js-sys = { path = 'crates/js-sys' }
9496
web-sys = { path = 'crates/web-sys' }

crates/cache/Cargo.toml

Lines changed: 0 additions & 21 deletions
This file was deleted.

crates/cache/src/lib.rs

Lines changed: 0 additions & 100 deletions
This file was deleted.

src/cache/intern.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use std::thread_local;
2+
use std::string::String;
3+
use std::borrow::ToOwned;
4+
use std::cell::{Cell, RefCell};
5+
use crate::JsValue;
6+
use uluru::{LRUCache, Entry};
7+
8+
9+
struct Pair {
10+
key: String,
11+
value: JsValue,
12+
}
13+
14+
// TODO figure out a good default capacity
15+
type Entries = LRUCache::<[Entry<Pair>; 1_024]>;
16+
17+
struct Cache {
18+
enabled: Cell<bool>,
19+
max_str_len: Cell<usize>,
20+
entries: RefCell<Entries>,
21+
}
22+
23+
// TODO figure out a good max_str_len
24+
thread_local! {
25+
static CACHE: Cache = Cache {
26+
enabled: Cell::new(true),
27+
max_str_len: Cell::new(128),
28+
entries: RefCell::new(LRUCache::default()),
29+
};
30+
}
31+
32+
fn get_js_string(cache: &mut Entries, key: &str) -> JsValue {
33+
if let Some(p) = cache.find(|p| p.key == key) {
34+
p.value.clone()
35+
36+
} else {
37+
let value = JsValue::from(key);
38+
39+
cache.insert(Pair {
40+
key: key.to_owned(),
41+
value: value.clone(),
42+
});
43+
44+
value
45+
}
46+
}
47+
48+
fn cache_str(s: &str) -> JsValue {
49+
CACHE.with(|cache| {
50+
let should_cache =
51+
cache.enabled.get() &&
52+
s.len() <= cache.max_str_len.get();
53+
54+
if should_cache {
55+
get_js_string(&mut cache.entries.borrow_mut(), s)
56+
57+
} else {
58+
JsValue::from(s)
59+
}
60+
})
61+
}
62+
63+
#[inline]
64+
pub fn str(s: &str) -> JsValue {
65+
if cfg!(feature = "disable-interning") {
66+
JsValue::from(s)
67+
68+
} else {
69+
cache_str(s)
70+
}
71+
}
72+
73+
#[inline]
74+
pub fn set_max_str_len(len: usize) {
75+
if !cfg!(feature = "disable-interning") {
76+
CACHE.with(|cache| cache.max_str_len.set(len));
77+
}
78+
}
79+
80+
#[inline]
81+
pub fn enable() {
82+
if !cfg!(feature = "disable-interning") {
83+
CACHE.with(|cache| cache.enabled.set(true));
84+
}
85+
}
86+
87+
#[inline]
88+
pub fn disable() {
89+
if !cfg!(feature = "disable-interning") {
90+
CACHE.with(|cache| cache.enabled.set(false));
91+
}
92+
}

src/cache/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod intern;

src/convert/impls.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,13 @@ impl IntoWasmAbi for JsValue {
315315
}
316316
}
317317

318+
impl OptionIntoWasmAbi for JsValue {
319+
#[inline]
320+
fn none() -> u32 {
321+
std::u32::MAX
322+
}
323+
}
324+
318325
impl FromWasmAbi for JsValue {
319326
type Abi = u32;
320327

src/convert/slices.rs

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use std::prelude::v1::*;
44
use core::slice;
55
use core::str;
66

7+
use cfg_if::cfg_if;
8+
79
use crate::convert::{FromWasmAbi, IntoWasmAbi, RefFromWasmAbi, RefMutFromWasmAbi, WasmAbi};
810
use crate::convert::{OptionIntoWasmAbi, Stack};
911

@@ -151,17 +153,39 @@ if_std! {
151153
fn is_none(abi: &WasmSlice) -> bool { abi.ptr == 0 }
152154
}
153155

154-
impl IntoWasmAbi for String {
155-
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
156+
cfg_if! {
157+
if #[cfg(feature = "disable-interning")] {
158+
impl IntoWasmAbi for String {
159+
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
156160

157-
#[inline]
158-
fn into_abi(self, extra: &mut dyn Stack) -> Self::Abi {
159-
self.into_bytes().into_abi(extra)
160-
}
161-
}
161+
#[inline]
162+
fn into_abi(self, extra: &mut dyn Stack) -> Self::Abi {
163+
self.into_bytes().into_abi(extra)
164+
}
165+
}
162166

163-
impl OptionIntoWasmAbi for String {
164-
fn none() -> WasmSlice { null_slice() }
167+
impl OptionIntoWasmAbi for String {
168+
#[inline]
169+
fn none() -> Self::Abi { null_slice() }
170+
}
171+
172+
} else {
173+
impl IntoWasmAbi for String {
174+
type Abi = <JsValue as IntoWasmAbi>::Abi;
175+
176+
#[inline]
177+
fn into_abi(self, extra: &mut dyn Stack) -> Self::Abi {
178+
crate::cache::intern::str(&self).into_abi(extra)
179+
}
180+
}
181+
182+
impl OptionIntoWasmAbi for String {
183+
#[inline]
184+
fn none() -> Self::Abi {
185+
<JsValue as OptionIntoWasmAbi>::none()
186+
}
187+
}
188+
}
165189
}
166190

167191
impl FromWasmAbi for String {
@@ -178,18 +202,38 @@ if_std! {
178202
}
179203
}
180204

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

184-
#[inline]
185-
fn into_abi(self, extra: &mut dyn Stack) -> Self::Abi {
186-
self.as_bytes().into_abi(extra)
187-
}
188-
}
206+
cfg_if! {
207+
if #[cfg(feature = "disable-interning")] {
208+
impl<'a> IntoWasmAbi for &'a str {
209+
type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
189210

190-
impl<'a> OptionIntoWasmAbi for &'a str {
191-
fn none() -> WasmSlice {
192-
null_slice()
211+
#[inline]
212+
fn into_abi(self, extra: &mut dyn Stack) -> Self::Abi {
213+
self.as_bytes().into_abi(extra)
214+
}
215+
}
216+
217+
impl<'a> OptionIntoWasmAbi for &'a str {
218+
fn none() -> Self::Abi { null_slice() }
219+
}
220+
221+
} else {
222+
impl<'a> IntoWasmAbi for &'a str {
223+
type Abi = <JsValue as IntoWasmAbi>::Abi;
224+
225+
#[inline]
226+
fn into_abi(self, extra: &mut dyn Stack) -> Self::Abi {
227+
crate::cache::intern::str(self).into_abi(extra)
228+
}
229+
}
230+
231+
impl<'a> OptionIntoWasmAbi for &'a str {
232+
#[inline]
233+
fn none() -> Self::Abi {
234+
<JsValue as OptionIntoWasmAbi>::none()
235+
}
236+
}
193237
}
194238
}
195239

src/describe.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub trait WasmDescribe {
5353
}
5454

5555
macro_rules! simple {
56-
($($t:ident => $d:ident)*) => ($(
56+
($($t:ident => $d:expr)*) => ($(
5757
impl WasmDescribe for $t {
5858
fn describe() { inform($d) }
5959
}
@@ -75,7 +75,7 @@ simple! {
7575
f64 => F64
7676
bool => BOOLEAN
7777
char => CHAR
78-
str => STRING
78+
str => if cfg!(feature = "disable-interning") { STRING } else { ANYREF }
7979
JsValue => ANYREF
8080
}
8181

@@ -116,7 +116,7 @@ if_std! {
116116
use std::prelude::v1::*;
117117

118118
impl WasmDescribe for String {
119-
fn describe() { inform(STRING) }
119+
fn describe() { inform(if cfg!(feature = "disable-interning") { STRING } else { ANYREF }) }
120120
}
121121

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

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ pub mod prelude {
5757
}
5858
}
5959

60+
#[allow(unused)]
61+
mod cache;
6062
pub mod convert;
6163
pub mod describe;
6264

0 commit comments

Comments
 (0)