Skip to content

Commit ac8a2d1

Browse files
committed
Fix handling of 64-bit unsigned integers
1 parent 7fcfbf0 commit ac8a2d1

File tree

4 files changed

+39
-48
lines changed

4 files changed

+39
-48
lines changed

src/lib/libembind.js

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -329,48 +329,32 @@ var LibraryEmbind = {
329329
],
330330
_embind_register_integer: (primitiveType, name, size, minRange, maxRange) => {
331331
name = readLatin1String(name);
332-
// LLVM doesn't have signed and unsigned 32-bit types, so u32 literals come
333-
// out as 'i32 -1'. Always treat those as max u32.
334-
if (maxRange === -1) {
335-
maxRange = 4294967295;
336-
}
337332

338-
var fromWireType = (value) => value;
333+
const isUnsignedType = maxRange < minRange;
339334

340-
if (minRange === 0) {
335+
let fromWireType = (value) => value;
336+
if (isUnsignedType) {
341337
var bitshift = 32 - 8*size;
342338
fromWireType = (value) => (value << bitshift) >>> bitshift;
339+
maxRange = fromWireType(maxRange);
343340
}
344341

345-
var isUnsignedType = (name.includes('unsigned'));
346-
var checkAssertions = (value, toTypeName) => {
342+
registerType(primitiveType, {
343+
name,
344+
'fromWireType': fromWireType,
345+
'toWireType': (destructors, value) => {
347346
#if ASSERTIONS
348-
if (typeof value != "number" && typeof value != "boolean") {
349-
throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${toTypeName}`);
350-
}
351-
if (value < minRange || value > maxRange) {
352-
throw new TypeError(`Passing a number "${embindRepr(value)}" from JS side to C/C++ side to an argument of type "${name}", which is outside the valid range [${minRange}, ${maxRange}]!`);
353-
}
354-
#endif
355-
}
356-
var toWireType;
357-
if (isUnsignedType) {
358-
toWireType = function(destructors, value) {
359-
checkAssertions(value, this.name);
360-
return value >>> 0;
361-
}
362-
} else {
363-
toWireType = function(destructors, value) {
364-
checkAssertions(value, this.name);
347+
if (typeof value != "number" && typeof value != "boolean") {
348+
throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${toTypeName}`);
349+
}
350+
if (value < minRange || value > maxRange) {
351+
throw new TypeError(`Passing a number "${embindRepr(value)}" from JS side to C/C++ side to an argument of type "${name}", which is outside the valid range [${minRange}, ${maxRange}]!`);
352+
}
353+
#endif
365354
// The VM will perform JS to Wasm value conversion, according to the spec:
366355
// https://www.w3.org/TR/wasm-js-api-1/#towebassemblyvalue
367356
return value;
368-
}
369-
}
370-
registerType(primitiveType, {
371-
name,
372-
'fromWireType': fromWireType,
373-
'toWireType': toWireType,
357+
},
374358
argPackAdvance: GenericWireTypeSize,
375359
'readValueFromPointer': integerReadValueFromPointer(name, size, minRange !== 0),
376360
destructorFunction: null, // This type does not need a destructor
@@ -384,24 +368,36 @@ var LibraryEmbind = {
384368
_embind_register_bigint: (primitiveType, name, size, minRange, maxRange) => {
385369
name = readLatin1String(name);
386370

387-
var isUnsignedType = (name.indexOf('u') != -1);
371+
const isUnsignedType = maxRange < minRange;
388372

389-
// maxRange comes through as -1 for uint64_t (see issue 13902). Work around that temporarily
373+
let fromWireType = (value) => value;
390374
if (isUnsignedType) {
391-
maxRange = (1n << 64n) - 1n;
375+
// uint64 get converted to int64 in ABI, fix them up like we do for 32-bit integers.
376+
const bitSize = size * 8;
377+
fromWireType = (value) => {
378+
#if MEMORY64
379+
// FIXME(https://github.com/emscripten-core/emscripten/issues/16975)
380+
// `size_t` ends up here, but it's transferred in the ABI as a plain number instead of a bigint.
381+
if (typeof value == 'number') {
382+
return value >>> 0;
383+
}
384+
#endif
385+
return BigInt.asUintN(bitSize, value);
386+
}
387+
maxRange = fromWireType(maxRange);
392388
}
393389

394390
registerType(primitiveType, {
395391
name,
396-
'fromWireType': (value) => value,
397-
'toWireType': function(destructors, value) {
398-
if (typeof value != "bigint" && typeof value != "number") {
399-
throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${this.name}`);
400-
}
392+
'fromWireType': fromWireType,
393+
'toWireType': (destructors, value) => {
401394
if (typeof value == "number") {
402395
value = BigInt(value);
403396
}
404397
#if ASSERTIONS
398+
else if (typeof value != "bigint") {
399+
throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${this.name}`);
400+
}
405401
if (value < minRange || value > maxRange) {
406402
throw new TypeError(`Passing a number "${embindRepr(value)}" from JS side to C/C++ side to an argument of type "${name}", which is outside the valid range [${minRange}, ${maxRange}]!`);
407403
}

system/lib/embind/bind.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,6 @@ EMSCRIPTEN_BINDINGS(builtin) {
134134
register_integer<unsigned short>("unsigned short");
135135
register_integer<signed int>("int");
136136
register_integer<unsigned int>("unsigned int");
137-
#if __wasm64__
138-
register_bigint<signed long>("long");
139-
register_bigint<unsigned long>("unsigned long");
140-
#else
141-
register_integer<signed long>("long");
142-
register_integer<unsigned long>("unsigned long");
143-
#endif
144137

145138
register_bigint<int64_t>("int64_t");
146139
register_bigint<uint64_t>("uint64_t");

test/embind/test_i64_binding.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
using namespace emscripten;
1414
using namespace std;
1515

16-
#define assert_js_eq(X, Y) run_js(string("const x = ") + X + ", y = " + Y + "; assert(x === y, `" + X + ": actual = ${x}, expected = ${y}`);")
16+
#define assert_js_eq(X, Y) run_js(string("const x = ") + X + ", y = " + Y + "; assert(x === y, `" + X + ": actual = ${typeof x} ${x}, expected = ${typeof y} ${y}`);")
1717

1818
void test(string message)
1919
{

test/embind/test_i64_binding.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
test:
2+
limits
13
start
24
test:
35
vector<int64_t>

0 commit comments

Comments
 (0)