summaryrefslogtreecommitdiff
path: root/ext/ffi/00_ffi.js
diff options
context:
space:
mode:
authorElias Sjögreen <eliassjogreen1@gmail.com>2022-06-08 13:13:10 +0200
committerGitHub <noreply@github.com>2022-06-08 16:43:10 +0530
commit8113fac939c06b0d71a22d008c060bed3cb47d72 (patch)
treecd9734046f414b344d4b8000c125f8b682768177 /ext/ffi/00_ffi.js
parent2769d602506af1953312b28580506fca3fcbe030 (diff)
feat(ext/ffi): support passing and returning bigints (#14523)
Diffstat (limited to 'ext/ffi/00_ffi.js')
-rw-r--r--ext/ffi/00_ffi.js77
1 files changed, 49 insertions, 28 deletions
diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js
index 3debeef14..fb4fcbfb8 100644
--- a/ext/ffi/00_ffi.js
+++ b/ext/ffi/00_ffi.js
@@ -14,12 +14,12 @@
TypeError,
} = window.__bootstrap.primordials;
- function unpackU64([hi, lo]) {
- return BigInt(hi) << 32n | BigInt(lo);
+ function pack64(value) {
+ return [Number(value >> 32n) >>> 0, Number(value & 0xFFFFFFFFn)];
}
- function packU64(value) {
- return [Number(value >> 32n), Number(value & 0xFFFFFFFFn)];
+ function unpackU64([hi, lo]) {
+ return BigInt(hi) << 32n | BigInt(lo);
}
function unpackI64([hi, lo]) {
@@ -37,77 +37,77 @@
getUint8(offset = 0) {
return core.opSync(
"op_ffi_read_u8",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getInt8(offset = 0) {
return core.opSync(
"op_ffi_read_i8",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getUint16(offset = 0) {
return core.opSync(
"op_ffi_read_u16",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getInt16(offset = 0) {
return core.opSync(
"op_ffi_read_i16",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getUint32(offset = 0) {
return core.opSync(
"op_ffi_read_u32",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getInt32(offset = 0) {
return core.opSync(
"op_ffi_read_i32",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getBigUint64(offset = 0) {
return unpackU64(core.opSync(
"op_ffi_read_u64",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
));
}
getBigInt64(offset = 0) {
return unpackI64(core.opSync(
"op_ffi_read_u64",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
));
}
getFloat32(offset = 0) {
return core.opSync(
"op_ffi_read_f32",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getFloat64(offset = 0) {
return core.opSync(
"op_ffi_read_f64",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
getCString(offset = 0) {
return core.opSync(
"op_ffi_cstr_read",
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
);
}
@@ -119,7 +119,7 @@
copyInto(destination, offset = 0) {
core.opSync("op_ffi_buf_copy_into", [
- packU64(this.pointer.value + BigInt(offset)),
+ pack64(this.pointer.value + BigInt(offset)),
destination,
destination.byteLength,
]);
@@ -161,7 +161,7 @@
parameters.push(buffers.length);
buffers.push(arg);
} else if (ObjectPrototypeIsPrototypeOf(UnsafePointerPrototype, arg)) {
- parameters.push(packU64(arg.value));
+ parameters.push(pack64(arg.value));
buffers.push(undefined);
} else if (arg === null) {
parameters.push(null);
@@ -171,6 +171,14 @@
"Invalid ffi arg value, expected TypedArray, UnsafePointer or null",
);
}
+ } else if (typeof arg === "bigint") {
+ if (arg > 0xffffffffffffffffn) {
+ throw new TypeError(
+ "Invalid ffi arg value, it needs to be less than 0xffffffffffffffff",
+ );
+ }
+
+ parameters.push(pack64(arg));
} else {
parameters.push(arg);
}
@@ -179,6 +187,23 @@
return { parameters, buffers };
}
+ function unpackResult(type, result) {
+ switch (type) {
+ case "pointer":
+ return new UnsafePointer(unpackU64(result));
+ case "u64":
+ return unpackU64(result);
+ case "i64":
+ return unpackI64(result);
+ case "usize":
+ return unpackU64(result);
+ case "isize":
+ return unpackI64(result);
+ default:
+ return result;
+ }
+ }
+
class UnsafeFnPointer {
pointer;
definition;
@@ -195,7 +220,7 @@
);
if (this.definition.nonblocking) {
const promise = core.opAsync("op_ffi_call_ptr_nonblocking", {
- pointer: packU64(this.pointer.value),
+ pointer: pack64(this.pointer.value),
def: this.definition,
parameters,
buffers,
@@ -208,7 +233,7 @@
return promise;
} else {
const result = core.opSync("op_ffi_call_ptr", {
- pointer: packU64(this.pointer.value),
+ pointer: pack64(this.pointer.value),
def: this.definition,
parameters,
buffers,
@@ -268,8 +293,10 @@
);
continue;
}
+
const isNonBlocking = symbols[symbol].nonblocking;
const types = symbols[symbol].parameters;
+ const resultType = symbols[symbol].result;
const fn = (...args) => {
const { parameters, buffers } = prepareArgs(types, args);
@@ -282,10 +309,8 @@
buffers,
});
- if (symbols[symbol].result === "pointer") {
- return promise.then((value) =>
- new UnsafePointer(unpackU64(value))
- );
+ if (resultType === "pointer") {
+ return promise.then((result) => unpackResult(resultType, result));
}
return promise;
@@ -297,11 +322,7 @@
buffers,
});
- if (symbols[symbol].result === "pointer") {
- return new UnsafePointer(unpackU64(result));
- }
-
- return result;
+ return unpackResult(resultType, result);
}
};