Skip to content

Commit 8606124

Browse files
authored
Merge pull request #1279 from alexcrichton/encode-into
Add support for `TextEncoder#encodeInto`
2 parents 6cabb07 + 745b16e commit 8606124

File tree

4 files changed

+110
-7
lines changed

4 files changed

+110
-7
lines changed

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

+63-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::decode;
22
use crate::descriptor::{Descriptor, VectorKind};
3-
use crate::Bindgen;
3+
use crate::{Bindgen, EncodeInto};
44
use failure::{bail, Error, ResultExt};
55
use std::collections::{HashMap, HashSet};
66
use walrus::{MemoryId, Module};
@@ -1168,19 +1168,77 @@ impl<'a> Context<'a> {
11681168
} else {
11691169
""
11701170
};
1171-
self.global(&format!(
1171+
1172+
// The first implementation we have for this is to use
1173+
// `TextEncoder#encode` which has been around for quite some time.
1174+
let use_encode = format!(
11721175
"
1173-
function passStringToWasm(arg) {{
11741176
{}
11751177
const buf = cachedTextEncoder.encode(arg);
11761178
const ptr = wasm.__wbindgen_malloc(buf.length);
11771179
getUint8Memory().set(buf, ptr);
11781180
WASM_VECTOR_LEN = buf.length;
11791181
return ptr;
1180-
}}
11811182
",
11821183
debug
1183-
));
1184+
);
1185+
1186+
// Another possibility is to use `TextEncoder#encodeInto` which is much
1187+
// newer and isn't implemented everywhere yet. It's more efficient,
1188+
// however, becaues it allows us to elide an intermediate allocation.
1189+
let use_encode_into = format!(
1190+
"
1191+
{}
1192+
let size = arg.length;
1193+
let ptr = wasm.__wbindgen_malloc(size);
1194+
let writeOffset = 0;
1195+
while (true) {{
1196+
const view = getUint8Memory().subarray(ptr + writeOffset, ptr + size);
1197+
const {{ read, written }} = cachedTextEncoder.encodeInto(arg, view);
1198+
arg = arg.substring(read);
1199+
writeOffset += written;
1200+
if (arg.length === 0) {{
1201+
break;
1202+
}}
1203+
ptr = wasm.__wbindgen_realloc(ptr, size, size * 2);
1204+
size *= 2;
1205+
}}
1206+
WASM_VECTOR_LEN = writeOffset;
1207+
return ptr;
1208+
",
1209+
debug
1210+
);
1211+
1212+
match self.config.encode_into {
1213+
EncodeInto::Never => {
1214+
self.global(&format!(
1215+
"function passStringToWasm(arg) {{ {} }}",
1216+
use_encode,
1217+
));
1218+
}
1219+
EncodeInto::Always => {
1220+
self.require_internal_export("__wbindgen_realloc")?;
1221+
self.global(&format!(
1222+
"function passStringToWasm(arg) {{ {} }}",
1223+
use_encode_into,
1224+
));
1225+
}
1226+
EncodeInto::Test => {
1227+
self.require_internal_export("__wbindgen_realloc")?;
1228+
self.global(&format!(
1229+
"
1230+
let passStringToWasm;
1231+
if (typeof cachedTextEncoder.encodeInto === 'function') {{
1232+
passStringToWasm = function(arg) {{ {} }};
1233+
}} else {{
1234+
passStringToWasm = function(arg) {{ {} }};
1235+
}}
1236+
",
1237+
use_encode_into,
1238+
use_encode,
1239+
));
1240+
}
1241+
}
11841242
Ok(())
11851243
}
11861244

crates/cli-support/src/lib.rs

+13
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub struct Bindgen {
3636
// module to be "ready to be instantiated on any thread"
3737
threads: Option<wasm_bindgen_threads_xform::Config>,
3838
anyref: bool,
39+
encode_into: EncodeInto,
3940
}
4041

4142
enum Input {
@@ -44,6 +45,12 @@ enum Input {
4445
None,
4546
}
4647

48+
pub enum EncodeInto {
49+
Test,
50+
Always,
51+
Never,
52+
}
53+
4754
impl Bindgen {
4855
pub fn new() -> Bindgen {
4956
Bindgen {
@@ -64,6 +71,7 @@ impl Bindgen {
6471
weak_refs: env::var("WASM_BINDGEN_WEAKREF").is_ok(),
6572
threads: threads_config(),
6673
anyref: env::var("WASM_BINDGEN_ANYREF").is_ok(),
74+
encode_into: EncodeInto::Test,
6775
}
6876
}
6977

@@ -144,6 +152,11 @@ impl Bindgen {
144152
self
145153
}
146154

155+
pub fn encode_into(&mut self, mode: EncodeInto) -> &mut Bindgen {
156+
self.encode_into = mode;
157+
self
158+
}
159+
147160
pub fn generate<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
148161
self._generate(path.as_ref())
149162
}

crates/cli/src/bin/wasm-bindgen.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use failure::{bail, Error};
33
use serde::Deserialize;
44
use std::path::PathBuf;
55
use std::process;
6-
use wasm_bindgen_cli_support::Bindgen;
6+
use wasm_bindgen_cli_support::{Bindgen, EncodeInto};
77

88
// no need for jemalloc bloat in this binary (and we don't need speed)
99
#[global_allocator]
@@ -32,6 +32,8 @@ Options:
3232
--keep-debug Keep debug sections in wasm files
3333
--remove-name-section Remove the debugging `name` section of the file
3434
--remove-producers-section Remove the telemetry `producers` section
35+
--encode-into MODE Whether or not to use TextEncoder#encodeInto,
36+
valid values are [test, always, never]
3537
-V --version Print the version number of wasm-bindgen
3638
";
3739

@@ -51,6 +53,7 @@ struct Args {
5153
flag_remove_name_section: bool,
5254
flag_remove_producers_section: bool,
5355
flag_keep_debug: bool,
56+
flag_encode_into: Option<String>,
5457
arg_input: Option<PathBuf>,
5558
}
5659

@@ -100,6 +103,14 @@ fn rmain(args: &Args) -> Result<(), Error> {
100103
if let Some(ref name) = args.flag_out_name {
101104
b.out_name(name);
102105
}
106+
if let Some(mode) = &args.flag_encode_into {
107+
match mode.as_str() {
108+
"test" => b.encode_into(EncodeInto::Test),
109+
"always" => b.encode_into(EncodeInto::Always),
110+
"never" => b.encode_into(EncodeInto::Never),
111+
s => bail!("invalid encode-into mode: `{}`", s),
112+
};
113+
}
103114

104115
let out_dir = match args.flag_out_dir {
105116
Some(ref p) => p,

src/lib.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ pub mod __rt {
892892
}
893893

894894
if_std! {
895-
use std::alloc::{alloc, dealloc, Layout};
895+
use std::alloc::{alloc, dealloc, realloc, Layout};
896896
use std::mem;
897897

898898
#[no_mangle]
@@ -911,6 +911,27 @@ pub mod __rt {
911911
}
912912
}
913913

914+
malloc_failure();
915+
}
916+
917+
#[no_mangle]
918+
pub extern "C" fn __wbindgen_realloc(ptr: *mut u8, old_size: usize, new_size: usize) -> *mut u8 {
919+
let align = mem::align_of::<usize>();
920+
debug_assert!(old_size > 0);
921+
debug_assert!(new_size > 0);
922+
if let Ok(layout) = Layout::from_size_align(old_size, align) {
923+
unsafe {
924+
let ptr = realloc(ptr, layout, new_size);
925+
if !ptr.is_null() {
926+
return ptr
927+
}
928+
}
929+
}
930+
malloc_failure();
931+
}
932+
933+
#[cold]
934+
fn malloc_failure() -> ! {
914935
if cfg!(debug_assertions) {
915936
super::throw_str("invalid malloc request")
916937
} else {

0 commit comments

Comments
 (0)