Changing IntoWasmAbi to use interning

This commit is contained in:
Pauan 2019-06-22 21:51:36 +02:00
parent 6767371ca7
commit 86a8842f24
9 changed files with 170 additions and 144 deletions

View File

@ -25,6 +25,7 @@ spans = ["wasm-bindgen-macro/spans"]
std = []
serde-serialize = ["serde", "serde_json", "std"]
nightly = []
disable-interning = []
# Whether or not the `#[wasm_bindgen]` macro is strict and generates an error on
# all unused attributes
@ -38,6 +39,8 @@ xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_
wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.48" }
serde = { version = "1.0", optional = true }
serde_json = { version = "1.0", optional = true }
uluru = "0.3.0"
cfg-if = "0.1.9"
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
js-sys = { path = 'crates/js-sys', version = '0.3.25' }
@ -89,6 +92,5 @@ exclude = ['crates/typescript']
[patch.crates-io]
wasm-bindgen = { path = '.' }
wasm-bindgen-futures = { path = 'crates/futures' }
wasm-bindgen-cache = { path = 'crates/cache' }
js-sys = { path = 'crates/js-sys' }
web-sys = { path = 'crates/web-sys' }

View File

@ -1,21 +0,0 @@
[package]
authors = ["The wasm-bindgen Developers"]
description = "Utilities for caching JS objects to avoid expensive copying"
documentation = "https://docs.rs/wasm-bindgen-cache"
homepage = "https://rustwasm.github.io/wasm-bindgen/"
license = "MIT/Apache-2.0"
name = "wasm-bindgen-cache"
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cache"
readme = "./README.md"
version = "0.1.0"
edition = "2018"
[features]
disabled = []
[dependencies]
js-sys = { path = "../js-sys", version = '0.3.24' }
uluru = "0.3.0"
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = { path = '../test', version = '0.2.47' }

View File

@ -1,100 +0,0 @@
#![deny(missing_docs)]
//!
///
pub mod intern {
use js_sys::JsString;
use std::cell::{Cell, RefCell};
use uluru::{LRUCache, Entry};
struct Pair {
key: String,
value: JsString,
}
// TODO figure out a good default capacity
type Entries = LRUCache::<[Entry<Pair>; 1_024]>;
struct Cache {
enabled: Cell<bool>,
max_str_len: Cell<usize>,
entries: RefCell<Entries>,
}
// TODO figure out a good max_str_len
thread_local! {
static CACHE: Cache = Cache {
enabled: Cell::new(true),
max_str_len: Cell::new(128),
entries: RefCell::new(LRUCache::default()),
};
}
fn get_js_string(cache: &mut Entries, key: &str) -> JsString {
if let Some(p) = cache.find(|p| p.key == key) {
p.value.clone()
} else {
let value = JsString::from(key);
cache.insert(Pair {
key: key.to_owned(),
value: value.clone(),
});
value
}
}
fn cache_str(s: &str) -> JsString {
CACHE.with(|cache| {
let should_cache =
cache.enabled.get() &&
s.len() <= cache.max_str_len.get();
if should_cache {
get_js_string(&mut cache.entries.borrow_mut(), s)
} else {
JsString::from(s)
}
})
}
///
#[inline]
pub fn str(s: &str) -> JsString {
if cfg!(feature = "disabled") {
JsString::from(s)
} else {
cache_str(s)
}
}
///
#[inline]
pub fn set_max_str_len(len: usize) {
if !cfg!(feature = "disabled") {
CACHE.with(|cache| cache.max_str_len.set(len));
}
}
///
#[inline]
pub fn enable() {
if !cfg!(feature = "disabled") {
CACHE.with(|cache| cache.enabled.set(true));
}
}
///
#[inline]
pub fn disable() {
if !cfg!(feature = "disabled") {
CACHE.with(|cache| cache.enabled.set(false));
}
}
}

92
src/cache/intern.rs vendored Normal file
View File

@ -0,0 +1,92 @@
use std::thread_local;
use std::string::String;
use std::borrow::ToOwned;
use std::cell::{Cell, RefCell};
use crate::JsValue;
use uluru::{LRUCache, Entry};
struct Pair {
key: String,
value: JsValue,
}
// TODO figure out a good default capacity
type Entries = LRUCache::<[Entry<Pair>; 1_024]>;
struct Cache {
enabled: Cell<bool>,
max_str_len: Cell<usize>,
entries: RefCell<Entries>,
}
// TODO figure out a good max_str_len
thread_local! {
static CACHE: Cache = Cache {
enabled: Cell::new(true),
max_str_len: Cell::new(128),
entries: RefCell::new(LRUCache::default()),
};
}
fn get_js_string(cache: &mut Entries, key: &str) -> JsValue {
if let Some(p) = cache.find(|p| p.key == key) {
p.value.clone()
} else {
let value = JsValue::from(key);
cache.insert(Pair {
key: key.to_owned(),
value: value.clone(),
});
value
}
}
fn cache_str(s: &str) -> JsValue {
CACHE.with(|cache| {
let should_cache =
cache.enabled.get() &&
s.len() <= cache.max_str_len.get();
if should_cache {
get_js_string(&mut cache.entries.borrow_mut(), s)
} else {
JsValue::from(s)
}
})
}
#[inline]
pub fn str(s: &str) -> JsValue {
if cfg!(feature = "disable-interning") {
JsValue::from(s)
} else {
cache_str(s)
}
}
#[inline]
pub fn set_max_str_len(len: usize) {
if !cfg!(feature = "disable-interning") {
CACHE.with(|cache| cache.max_str_len.set(len));
}
}
#[inline]
pub fn enable() {
if !cfg!(feature = "disable-interning") {
CACHE.with(|cache| cache.enabled.set(true));
}
}
#[inline]
pub fn disable() {
if !cfg!(feature = "disable-interning") {
CACHE.with(|cache| cache.enabled.set(false));
}
}

1
src/cache/mod.rs vendored Normal file
View File

@ -0,0 +1 @@
pub mod intern;

View File

@ -315,6 +315,13 @@ impl IntoWasmAbi for JsValue {
}
}
impl OptionIntoWasmAbi for JsValue {
#[inline]
fn none() -> u32 {
std::u32::MAX
}
}
impl FromWasmAbi for JsValue {
type Abi = u32;

View File

@ -4,6 +4,7 @@ use std::prelude::v1::*;
use core::slice;
use core::str;
use cfg_if::cfg_if;
use crate::convert::OptionIntoWasmAbi;
use crate::convert::{FromWasmAbi, IntoWasmAbi, RefFromWasmAbi, RefMutFromWasmAbi, WasmAbi};
@ -148,6 +149,8 @@ if_std! {
fn is_none(abi: &WasmSlice) -> bool { abi.ptr == 0 }
}
cfg_if! {
if #[cfg(feature = "disable-interning")] {
impl IntoWasmAbi for String {
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
@ -158,7 +161,27 @@ if_std! {
}
impl OptionIntoWasmAbi for String {
fn none() -> WasmSlice { null_slice() }
#[inline]
fn none() -> Self::Abi { null_slice() }
}
} else {
impl IntoWasmAbi for String {
type Abi = <JsValue as IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self, extra: &mut dyn Stack) -> Self::Abi {
crate::cache::intern::str(&self).into_abi(extra)
}
}
impl OptionIntoWasmAbi for String {
#[inline]
fn none() -> Self::Abi {
<JsValue as OptionIntoWasmAbi>::none()
}
}
}
}
impl FromWasmAbi for String {
@ -175,6 +198,9 @@ if_std! {
}
}
cfg_if! {
if #[cfg(feature = "disable-interning")] {
impl<'a> IntoWasmAbi for &'a str {
type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
@ -185,8 +211,25 @@ impl<'a> IntoWasmAbi for &'a str {
}
impl<'a> OptionIntoWasmAbi for &'a str {
fn none() -> WasmSlice {
null_slice()
fn none() -> Self::Abi { null_slice() }
}
} else {
impl<'a> IntoWasmAbi for &'a str {
type Abi = <JsValue as IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self, extra: &mut dyn Stack) -> Self::Abi {
crate::cache::intern::str(self).into_abi(extra)
}
}
impl<'a> OptionIntoWasmAbi for &'a str {
#[inline]
fn none() -> Self::Abi {
<JsValue as OptionIntoWasmAbi>::none()
}
}
}
}

View File

@ -53,7 +53,7 @@ pub trait WasmDescribe {
}
macro_rules! simple {
($($t:ident => $d:ident)*) => ($(
($($t:ident => $d:expr)*) => ($(
impl WasmDescribe for $t {
fn describe() { inform($d) }
}
@ -75,7 +75,7 @@ simple! {
f64 => F64
bool => BOOLEAN
char => CHAR
str => STRING
str => if cfg!(feature = "disable-interning") { STRING } else { ANYREF }
JsValue => ANYREF
}
@ -116,7 +116,7 @@ if_std! {
use std::prelude::v1::*;
impl WasmDescribe for String {
fn describe() { inform(STRING) }
fn describe() { inform(if cfg!(feature = "disable-interning") { STRING } else { ANYREF }) }
}
impl<T: WasmDescribe> WasmDescribe for Box<[T]> {

View File

@ -57,6 +57,8 @@ pub mod prelude {
}
}
#[allow(unused)]
mod cache;
pub mod convert;
pub mod describe;