Skip to content

Commit 86a8842

Browse files
committed
Changing IntoWasmAbi to use interning
1 parent 6767371 commit 86a8842

File tree

9 files changed

+170
-144
lines changed

9 files changed

+170
-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.48" }
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.25' }
@@ -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: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::prelude::v1::*;
44
use core::slice;
55
use core::str;
66

7+
use cfg_if::cfg_if;
78
use crate::convert::OptionIntoWasmAbi;
89
use crate::convert::{FromWasmAbi, IntoWasmAbi, RefFromWasmAbi, RefMutFromWasmAbi, WasmAbi};
910

@@ -148,17 +149,39 @@ if_std! {
148149
fn is_none(abi: &WasmSlice) -> bool { abi.ptr == 0 }
149150
}
150151

151-
impl IntoWasmAbi for String {
152-
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
152+
cfg_if! {
153+
if #[cfg(feature = "disable-interning")] {
154+
impl IntoWasmAbi for String {
155+
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
153156

154-
#[inline]
155-
fn into_abi(self) -> Self::Abi {
156-
self.into_bytes().into_abi()
157-
}
158-
}
157+
#[inline]
158+
fn into_abi(self) -> Self::Abi {
159+
self.into_bytes().into_abi()
160+
}
161+
}
159162

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

164187
impl FromWasmAbi for String {
@@ -175,18 +198,38 @@ if_std! {
175198
}
176199
}
177200

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

181-
#[inline]
182-
fn into_abi(self) -> Self::Abi {
183-
self.as_bytes().into_abi()
184-
}
185-
}
202+
cfg_if! {
203+
if #[cfg(feature = "disable-interning")] {
204+
impl<'a> IntoWasmAbi for &'a str {
205+
type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
206+
207+
#[inline]
208+
fn into_abi(self) -> Self::Abi {
209+
self.as_bytes().into_abi()
210+
}
211+
}
212+
213+
impl<'a> OptionIntoWasmAbi for &'a str {
214+
fn none() -> Self::Abi { null_slice() }
215+
}
216+
217+
} else {
218+
impl<'a> IntoWasmAbi for &'a str {
219+
type Abi = <JsValue as IntoWasmAbi>::Abi;
186220

187-
impl<'a> OptionIntoWasmAbi for &'a str {
188-
fn none() -> WasmSlice {
189-
null_slice()
221+
#[inline]
222+
fn into_abi(self, extra: &mut dyn Stack) -> Self::Abi {
223+
crate::cache::intern::str(self).into_abi(extra)
224+
}
225+
}
226+
227+
impl<'a> OptionIntoWasmAbi for &'a str {
228+
#[inline]
229+
fn none() -> Self::Abi {
230+
<JsValue as OptionIntoWasmAbi>::none()
231+
}
232+
}
190233
}
191234
}
192235

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)