mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-18 07:21:24 +00:00
Map u64/i64 to BigInt in JS
This commit is an implementation of mapping u64/i64 to `BigInt` in JS through the unstable BigInt APIs. The BigInt type will ship soon in Chrome and so this commit builds out the necessary support for wasm-bindgen to use it!
This commit is contained in:
@ -79,6 +79,8 @@ pub enum VectorKind {
|
||||
U16,
|
||||
I32,
|
||||
U32,
|
||||
I64,
|
||||
U64,
|
||||
F32,
|
||||
F64,
|
||||
String,
|
||||
@ -139,8 +141,6 @@ impl Descriptor {
|
||||
Descriptor::U16 |
|
||||
Descriptor::I32 |
|
||||
Descriptor::U32 |
|
||||
Descriptor::I64 |
|
||||
Descriptor::U64 |
|
||||
Descriptor::F32 |
|
||||
Descriptor::F64 |
|
||||
Descriptor::Enum => true,
|
||||
@ -148,6 +148,14 @@ impl Descriptor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_64bit(&self) -> Option<bool> {
|
||||
match *self {
|
||||
Descriptor::I64 => Some(true),
|
||||
Descriptor::U64 => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ref_anyref(&self) -> bool {
|
||||
match *self {
|
||||
Descriptor::Ref(ref s) => s.is_anyref(),
|
||||
@ -199,9 +207,11 @@ impl Descriptor {
|
||||
Descriptor::I8 => Some(VectorKind::I8),
|
||||
Descriptor::I16 => Some(VectorKind::I16),
|
||||
Descriptor::I32 => Some(VectorKind::I32),
|
||||
Descriptor::I64 => Some(VectorKind::I64),
|
||||
Descriptor::U8 => Some(VectorKind::U8),
|
||||
Descriptor::U16 => Some(VectorKind::U16),
|
||||
Descriptor::U32 => Some(VectorKind::U32),
|
||||
Descriptor::U64 => Some(VectorKind::U64),
|
||||
Descriptor::F32 => Some(VectorKind::F32),
|
||||
Descriptor::F64 => Some(VectorKind::F64),
|
||||
Descriptor::Anyref => Some(VectorKind::Anyref),
|
||||
@ -290,6 +300,8 @@ impl VectorKind {
|
||||
VectorKind::U16 => "Uint16Array",
|
||||
VectorKind::I32 => "Int32Array",
|
||||
VectorKind::U32 => "Uint32Array",
|
||||
VectorKind::I64 => "BigInt64Array",
|
||||
VectorKind::U64 => "BigUint64Array",
|
||||
VectorKind::F32 => "Float32Array",
|
||||
VectorKind::F64 => "Float64Array",
|
||||
VectorKind::Anyref => "any[]",
|
||||
@ -305,6 +317,8 @@ impl VectorKind {
|
||||
VectorKind::U16 => 2,
|
||||
VectorKind::I32 => 4,
|
||||
VectorKind::U32 => 4,
|
||||
VectorKind::I64 => 8,
|
||||
VectorKind::U64 => 8,
|
||||
VectorKind::F32 => 4,
|
||||
VectorKind::F64 => 8,
|
||||
VectorKind::Anyref => 4,
|
||||
|
@ -168,6 +168,29 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
||||
return Ok(self)
|
||||
}
|
||||
|
||||
if let Some(signed) = arg.get_64bit() {
|
||||
let f = if signed {
|
||||
self.cx.expose_int64_cvt_shim()
|
||||
} else {
|
||||
self.cx.expose_uint64_cvt_shim()
|
||||
};
|
||||
self.cx.expose_uint32_memory();
|
||||
self.cx.expose_global_argument_ptr()?;
|
||||
self.js_arguments.push((name.clone(), "BigInt".to_string()));
|
||||
self.prelude(&format!("\
|
||||
{f}[0] = {name};\n\
|
||||
const lo{i} = u32CvtShim[0];\n\
|
||||
const hi{i} = u32CvtShim[1];\n\
|
||||
",
|
||||
i = i,
|
||||
f = f,
|
||||
name = name,
|
||||
));
|
||||
self.rust_arguments.push(format!("lo{}", i));
|
||||
self.rust_arguments.push(format!("hi{}", i));
|
||||
return Ok(self)
|
||||
}
|
||||
|
||||
if arg.is_ref_anyref() {
|
||||
self.js_arguments.push((name.clone(), "any".to_string()));
|
||||
self.cx.expose_borrowed_objects();
|
||||
@ -252,6 +275,25 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
||||
return Ok(self)
|
||||
}
|
||||
|
||||
if let Some(signed) = ty.get_64bit() {
|
||||
self.ret_ty = "BigInt".to_string();
|
||||
self.cx.expose_global_argument_ptr()?;
|
||||
let f = if signed {
|
||||
self.cx.expose_int64_memory();
|
||||
"getInt64Memory"
|
||||
} else {
|
||||
self.cx.expose_uint64_memory();
|
||||
"getUint64Memory"
|
||||
};
|
||||
self.prelude("const retptr = globalArgumentPtr();");
|
||||
self.rust_arguments.insert(0, "retptr".to_string());
|
||||
self.ret_expr = format!("\
|
||||
RET;\n\
|
||||
return {}()[retptr / 8];\n\
|
||||
", f);
|
||||
return Ok(self)
|
||||
}
|
||||
|
||||
match *ty {
|
||||
Descriptor::Boolean => {
|
||||
self.ret_ty = "boolean".to_string();
|
||||
|
@ -787,80 +787,52 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
|
||||
fn expose_pass_array8_to_wasm(&mut self) -> Result<(), Error> {
|
||||
if !self.exposed_globals.insert("pass_array8_to_wasm") {
|
||||
return Ok(());
|
||||
}
|
||||
self.require_internal_export("__wbindgen_malloc")?;
|
||||
self.expose_uint8_memory();
|
||||
self.global(&format!("
|
||||
function passArray8ToWasm(arg) {{
|
||||
const ptr = wasm.__wbindgen_malloc(arg.length);
|
||||
getUint8Memory().set(arg, ptr);
|
||||
return [ptr, arg.length];
|
||||
}}
|
||||
"));
|
||||
Ok(())
|
||||
self.pass_array_to_wasm("passArray8ToWasm", "getUint8Memory", 1)
|
||||
}
|
||||
|
||||
fn expose_pass_array16_to_wasm(&mut self) -> Result<(), Error> {
|
||||
if !self.exposed_globals.insert("pass_array16_to_wasm") {
|
||||
return Ok(());
|
||||
}
|
||||
self.require_internal_export("__wbindgen_malloc")?;
|
||||
self.expose_uint16_memory();
|
||||
self.global(&format!("
|
||||
function passArray16ToWasm(arg) {{
|
||||
const ptr = wasm.__wbindgen_malloc(arg.length * 2);
|
||||
getUint16Memory().set(arg, ptr / 2);
|
||||
return [ptr, arg.length];
|
||||
}}
|
||||
"));
|
||||
Ok(())
|
||||
self.pass_array_to_wasm("passArray16ToWasm", "getUint16Memory", 2)
|
||||
}
|
||||
|
||||
fn expose_pass_array32_to_wasm(&mut self) -> Result<(), Error> {
|
||||
if !self.exposed_globals.insert("pass_array32_to_wasm") {
|
||||
return Ok(())
|
||||
}
|
||||
self.require_internal_export("__wbindgen_malloc")?;
|
||||
self.expose_uint32_memory();
|
||||
self.global(&format!("
|
||||
function passArray32ToWasm(arg) {{
|
||||
const ptr = wasm.__wbindgen_malloc(arg.length * 4);
|
||||
getUint32Memory().set(arg, ptr / 4);
|
||||
return [ptr, arg.length];
|
||||
}}
|
||||
"));
|
||||
Ok(())
|
||||
self.pass_array_to_wasm("passArray32ToWasm", "getUint32Memory", 4)
|
||||
}
|
||||
|
||||
fn expose_pass_array64_to_wasm(&mut self) -> Result<(), Error> {
|
||||
self.expose_uint64_memory();
|
||||
self.pass_array_to_wasm("passArray64ToWasm", "getUint64Memory", 8)
|
||||
}
|
||||
|
||||
fn expose_pass_array_f32_to_wasm(&mut self) -> Result<(), Error> {
|
||||
if !self.exposed_globals.insert("pass_array_f32_to_wasm") {
|
||||
return Ok(())
|
||||
}
|
||||
self.require_internal_export("__wbindgen_malloc")?;
|
||||
self.global(&format!("
|
||||
function passArrayF32ToWasm(arg) {{
|
||||
const ptr = wasm.__wbindgen_malloc(arg.length * 4);
|
||||
new Float32Array(wasm.memory.buffer).set(arg, ptr / 4);
|
||||
return [ptr, arg.length];
|
||||
}}
|
||||
"));
|
||||
Ok(())
|
||||
self.expose_f32_memory();
|
||||
self.pass_array_to_wasm("passArrayF32ToWasm", "getFloat32Memory", 4)
|
||||
}
|
||||
|
||||
fn expose_pass_array_f64_to_wasm(&mut self) -> Result<(), Error> {
|
||||
if !self.exposed_globals.insert("pass_array_f64_to_wasm") {
|
||||
self.expose_f64_memory();
|
||||
self.pass_array_to_wasm("passArrayF64ToWasm", "getFloat64Memory", 8)
|
||||
}
|
||||
|
||||
fn pass_array_to_wasm(&mut self,
|
||||
name: &'static str,
|
||||
delegate: &str,
|
||||
size: usize) -> Result<(), Error>
|
||||
{
|
||||
if !self.exposed_globals.insert(name) {
|
||||
return Ok(())
|
||||
}
|
||||
self.require_internal_export("__wbindgen_malloc")?;
|
||||
self.expose_uint64_memory();
|
||||
self.global(&format!("
|
||||
function passArrayF64ToWasm(arg) {{
|
||||
const ptr = wasm.__wbindgen_malloc(arg.length * 8);
|
||||
new Float64Array(wasm.memory.buffer).set(arg, ptr / 8);
|
||||
function {}(arg) {{
|
||||
const ptr = wasm.__wbindgen_malloc(arg.length * {size});
|
||||
{}().set(arg, ptr / {size});
|
||||
return [ptr, arg.length];
|
||||
}}
|
||||
"));
|
||||
", name, delegate, size = size));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -980,6 +952,16 @@ impl<'a> Context<'a> {
|
||||
self.arrayget("getArrayU32FromWasm", "getUint32Memory", 4);
|
||||
}
|
||||
|
||||
fn expose_get_array_i64_from_wasm(&mut self) {
|
||||
self.expose_int64_memory();
|
||||
self.arrayget("getArrayI64FromWasm", "getInt64Memory", 8);
|
||||
}
|
||||
|
||||
fn expose_get_array_u64_from_wasm(&mut self) {
|
||||
self.expose_uint64_memory();
|
||||
self.arrayget("getArrayU64FromWasm", "getUint64Memory", 8);
|
||||
}
|
||||
|
||||
fn expose_get_array_f32_from_wasm(&mut self) {
|
||||
self.expose_f32_memory();
|
||||
self.arrayget("getArrayF32FromWasm", "getFloat32Memory", 4);
|
||||
@ -1029,6 +1011,14 @@ impl<'a> Context<'a> {
|
||||
self.memview("getUint32Memory", "Uint32Array");
|
||||
}
|
||||
|
||||
fn expose_int64_memory(&mut self) {
|
||||
self.memview("getInt64Memory", "BigInt64Array");
|
||||
}
|
||||
|
||||
fn expose_uint64_memory(&mut self) {
|
||||
self.memview("getUint64Memory", "BigUint64Array");
|
||||
}
|
||||
|
||||
fn expose_f32_memory(&mut self) {
|
||||
self.memview("getFloat32Memory", "Float32Array");
|
||||
}
|
||||
@ -1067,6 +1057,14 @@ impl<'a> Context<'a> {
|
||||
self.expose_uint32_memory();
|
||||
"getUint32Memory"
|
||||
}
|
||||
VectorKind::I64 => {
|
||||
self.expose_int64_memory();
|
||||
"getInt64Memory"
|
||||
}
|
||||
VectorKind::U64 => {
|
||||
self.expose_uint64_memory();
|
||||
"getUint64Memory"
|
||||
}
|
||||
VectorKind::F32 => {
|
||||
self.expose_f32_memory();
|
||||
"getFloat32Memory"
|
||||
@ -1204,6 +1202,11 @@ impl<'a> Context<'a> {
|
||||
self.expose_pass_array32_to_wasm()?;
|
||||
"passArray32ToWasm"
|
||||
}
|
||||
VectorKind::I64 |
|
||||
VectorKind::U64 => {
|
||||
self.expose_pass_array64_to_wasm()?;
|
||||
"passArray64ToWasm"
|
||||
}
|
||||
VectorKind::F32 => {
|
||||
self.expose_pass_array_f32_to_wasm()?;
|
||||
"passArrayF32ToWasm"
|
||||
@ -1249,6 +1252,14 @@ impl<'a> Context<'a> {
|
||||
self.expose_get_array_u32_from_wasm();
|
||||
"getArrayU32FromWasm"
|
||||
}
|
||||
VectorKind::I64 => {
|
||||
self.expose_get_array_i64_from_wasm();
|
||||
"getArrayI64FromWasm"
|
||||
}
|
||||
VectorKind::U64 => {
|
||||
self.expose_get_array_u64_from_wasm();
|
||||
"getArrayU64FromWasm"
|
||||
}
|
||||
VectorKind::F32 => {
|
||||
self.expose_get_array_f32_from_wasm();
|
||||
"getArrayF32FromWasm"
|
||||
@ -1320,6 +1331,35 @@ impl<'a> Context<'a> {
|
||||
");
|
||||
}
|
||||
|
||||
fn expose_u32_cvt_shim(&mut self) -> &'static str {
|
||||
let name = "u32CvtShim";
|
||||
if !self.exposed_globals.insert(name) {
|
||||
return name
|
||||
}
|
||||
self.global(&format!("const {} = new Uint32Array(2);", name));
|
||||
name
|
||||
}
|
||||
|
||||
fn expose_int64_cvt_shim(&mut self) -> &'static str {
|
||||
let name = "int64CvtShim";
|
||||
if !self.exposed_globals.insert(name) {
|
||||
return name
|
||||
}
|
||||
let n = self.expose_u32_cvt_shim();
|
||||
self.global(&format!("const {} = new BigInt64Array({}.buffer);", name, n));
|
||||
name
|
||||
}
|
||||
|
||||
fn expose_uint64_cvt_shim(&mut self) -> &'static str {
|
||||
let name = "uint64CvtShim";
|
||||
if !self.exposed_globals.insert(name) {
|
||||
return name
|
||||
}
|
||||
let n = self.expose_u32_cvt_shim();
|
||||
self.global(&format!("const {} = new BigUint64Array({}.buffer);", name, n));
|
||||
name
|
||||
}
|
||||
|
||||
fn gc(&mut self) -> Result<(), Error> {
|
||||
let module = mem::replace(self.module, Module::default());
|
||||
let wasm_bytes = parity_wasm::serialize(module)?;
|
||||
|
@ -98,6 +98,28 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if let Some(signed) = arg.get_64bit() {
|
||||
let f = if signed {
|
||||
self.cx.expose_int64_cvt_shim()
|
||||
} else {
|
||||
self.cx.expose_uint64_cvt_shim()
|
||||
};
|
||||
let hi = self.shim_argument();
|
||||
let name = format!("n{}", abi);
|
||||
self.prelude(&format!("\
|
||||
u32CvtShim[0] = {lo};\n\
|
||||
u32CvtShim[1] = {hi};\n\
|
||||
const {name} = {f}[0];\n\
|
||||
",
|
||||
lo = abi,
|
||||
hi = hi,
|
||||
f = f,
|
||||
name = name,
|
||||
));
|
||||
self.js_arguments.push(name);
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if let Some(class) = arg.rust_struct() {
|
||||
if arg.is_by_ref() {
|
||||
bail!("cannot invoke JS functions with custom ref types yet")
|
||||
@ -229,6 +251,21 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
||||
self.ret_expr = "return JS;".to_string();
|
||||
return Ok(())
|
||||
}
|
||||
if let Some(signed) = ty.get_64bit() {
|
||||
let f = if signed {
|
||||
self.cx.expose_int64_memory();
|
||||
"getInt64Memory"
|
||||
} else {
|
||||
self.cx.expose_uint64_memory();
|
||||
"getUint64Memory"
|
||||
};
|
||||
self.shim_arguments.insert(0, "ret".to_string());
|
||||
self.ret_expr = format!("\
|
||||
const val = JS;\n\
|
||||
{}()[ret / 8] = val;\n\
|
||||
", f);
|
||||
return Ok(())
|
||||
}
|
||||
self.ret_expr = match *ty {
|
||||
Descriptor::Boolean => "return JS ? 1 : 0;".to_string(),
|
||||
Descriptor::Anyref => {
|
||||
|
Reference in New Issue
Block a user