Skip to content

Commit 1059b20

Browse files
authored
embind: Fix some embind issues with memory64. (#21061)
* embind: Fix some embind issues with memory64. - Fixes string encoding/decoding by using the correct offsets. - Allows numbers to be automatically converted to BigInts. - Only validates the range assertion on BigInts when ASSERTIONS are enabled. This more closely matches the behavior of other number validation. - Fixes function signatures for longs in memory64 mode. - Enables test_embind in memory64 mode. - Updates test_embind_i64_binding to match the new behavior of allowing auto conversion of numbers to BigInts. * Only test throwing behavior when assertions are enabled.
1 parent 63036a7 commit 1059b20

File tree

9 files changed

+90
-44
lines changed

9 files changed

+90
-44
lines changed

src/embind/embind.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,14 @@ var LibraryEmbind = {
432432
if (typeof value != "bigint" && typeof value != "number") {
433433
throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${this.name}`);
434434
}
435+
if (typeof value == "number") {
436+
value = BigInt(value);
437+
}
438+
#if ASSERTIONS
435439
if (value < minRange || value > maxRange) {
436440
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}]!`);
437441
}
442+
#endif
438443
return value;
439444
},
440445
'argPackAdvance': GenericWireTypeSize,
@@ -551,7 +556,7 @@ var LibraryEmbind = {
551556
length = value.length;
552557
}
553558

554-
// assumes 4-byte alignment
559+
// assumes POINTER_SIZE alignment
555560
var base = _malloc({{{ POINTER_SIZE }}} + length + 1);
556561
var ptr = base + {{{ POINTER_SIZE }}};
557562
{{{ makeSetValue('base', '0', 'length', SIZE_TYPE) }}};
@@ -616,10 +621,10 @@ var LibraryEmbind = {
616621
var HEAP = getHeap();
617622
var str;
618623

619-
var decodeStartPtr = value + 4;
624+
var decodeStartPtr = value + {{{ POINTER_SIZE }}};
620625
// Looping here to support possible embedded '0' bytes
621626
for (var i = 0; i <= length; ++i) {
622-
var currentBytePtr = value + 4 + i * charSize;
627+
var currentBytePtr = value + {{{ POINTER_SIZE }}} + i * charSize;
623628
if (i == length || HEAP[currentBytePtr >> shift] == 0) {
624629
var maxReadBytes = currentBytePtr - decodeStartPtr;
625630
var stringSegment = decodeString(decodeStartPtr, maxReadBytes);
@@ -642,12 +647,12 @@ var LibraryEmbind = {
642647
throwBindingError(`Cannot pass non-string to C++ string type ${name}`);
643648
}
644649

645-
// assumes 4-byte alignment
650+
// assumes POINTER_SIZE alignment
646651
var length = lengthBytesUTF(value);
647-
var ptr = _malloc(4 + length + charSize);
648-
HEAPU32[ptr >> 2] = length >> shift;
652+
var ptr = _malloc({{{ POINTER_SIZE }}} + length + charSize);
653+
{{{ makeSetValue('ptr', '0', 'length >> shift', SIZE_TYPE) }}};
649654

650-
encodeString(value, ptr + 4, length + charSize);
655+
encodeString(value, ptr + {{{ POINTER_SIZE }}}, length + charSize);
651656

652657
if (destructors !== null) {
653658
destructors.push(_free, ptr);

system/include/emscripten/bind.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,12 @@ struct SignatureCode<size_t> {
519519
return 'p';
520520
}
521521
};
522+
template<>
523+
struct SignatureCode<long> {
524+
static constexpr char get() {
525+
return 'j';
526+
}
527+
};
522528
#endif
523529

524530
template<typename... Args>
@@ -532,6 +538,7 @@ template<> struct SignatureTranslator<void> { using type = void; };
532538
template<> struct SignatureTranslator<float> { using type = float; };
533539
template<> struct SignatureTranslator<double> { using type = double; };
534540
#ifdef __wasm64__
541+
template<> struct SignatureTranslator<long> { using type = long; };
535542
template<> struct SignatureTranslator<size_t> { using type = size_t; };
536543
template<typename PtrType>
537544
struct SignatureTranslator<PtrType*> { using type = void*; };

system/include/emscripten/val.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,28 @@ class val {
540540
return fromGenericWireType<T>(result);
541541
}
542542

543+
#ifdef __wasm64__
544+
template<>
545+
long as<long>() const {
546+
using namespace internal;
547+
548+
typedef BindingType<long> BT;
549+
typename WithPolicies<>::template ArgTypeList<long> targetType;
550+
551+
return _emval_as_int64(as_handle(), targetType.getTypes()[0]);
552+
}
553+
554+
template<>
555+
unsigned long as<unsigned long>() const {
556+
using namespace internal;
557+
558+
typedef BindingType<unsigned long> BT;
559+
typename WithPolicies<>::template ArgTypeList<unsigned long> targetType;
560+
561+
return _emval_as_uint64(as_handle(), targetType.getTypes()[0]);
562+
}
563+
#endif
564+
543565
template<>
544566
int64_t as<int64_t>() const {
545567
using namespace internal;

test/embind/embind.test.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -856,10 +856,17 @@ module({
856856
assert.throws(TypeError, function() { cm.int_to_string(2147483648); });
857857
assert.throws(TypeError, function() { cm.unsigned_int_to_string(-1); });
858858
assert.throws(TypeError, function() { cm.unsigned_int_to_string(4294967296); });
859-
assert.throws(TypeError, function() { cm.long_to_string(-2147483649); });
860-
assert.throws(TypeError, function() { cm.long_to_string(2147483648); });
861-
assert.throws(TypeError, function() { cm.unsigned_long_to_string(-1); });
862-
assert.throws(TypeError, function() { cm.unsigned_long_to_string(4294967296); });
859+
if (cm.getCompilerSetting('MEMORY64')) {
860+
assert.throws(TypeError, function() { cm.long_to_string(-18446744073709551616n); });
861+
assert.throws(TypeError, function() { cm.long_to_string(18446744073709551616n); });
862+
assert.throws(TypeError, function() { cm.unsigned_long_to_string(-1n); });
863+
assert.throws(TypeError, function() { cm.unsigned_long_to_string(18446744073709551616n); });
864+
} else {
865+
assert.throws(TypeError, function() { cm.long_to_string(-2147483649); });
866+
assert.throws(TypeError, function() { cm.long_to_string(2147483648); });
867+
assert.throws(TypeError, function() { cm.unsigned_long_to_string(-1); });
868+
assert.throws(TypeError, function() { cm.unsigned_long_to_string(4294967296); });
869+
}
863870
} else {
864871
// test that an out of range value doesn't throw without assertions.
865872
assert.equal("-129", cm.char_to_string(-129));
@@ -2730,7 +2737,11 @@ module({
27302737
assert.equal(127, cm.val_as_char(127));
27312738
assert.equal(32767, cm.val_as_short(32767));
27322739
assert.equal(65536, cm.val_as_int(65536));
2733-
assert.equal(65536, cm.val_as_long(65536));
2740+
if (cm.getCompilerSetting('MEMORY64')) {
2741+
assert.equal(65536n, cm.val_as_long(65536));
2742+
} else {
2743+
assert.equal(65536, cm.val_as_long(65536));
2744+
}
27342745
assert.equal(10.5, cm.val_as_float(10.5));
27352746
assert.equal(10.5, cm.val_as_double(10.5));
27362747

test/embind/test_i64_binding.cpp

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,30 +41,13 @@ int run_js(string js_code)
4141
}, js_code_pointer);
4242
}
4343

44-
void ensure_js_throws(string js_code, string error_type)
45-
{
46-
js_code.append(";");
47-
const char* js_code_pointer = js_code.c_str();
48-
const char* error_type_pointer = error_type.c_str();
49-
assert(EM_ASM_INT({
50-
var js_code = UTF8ToString($0);
51-
var error_type = UTF8ToString($1);
52-
try {
53-
eval(js_code);
54-
}
55-
catch(error_thrown)
56-
{
57-
return error_thrown.name === error_type;
58-
}
59-
return false;
60-
}, js_code_pointer, error_type_pointer));
61-
}
62-
6344
EMSCRIPTEN_BINDINGS(tests) {
6445
register_vector<int64_t>("Int64Vector");
6546
register_vector<uint64_t>("UInt64Vector");
6647
}
6748

49+
extern "C" void ensure_js_throws_with_assertions_enabled(const char* js_code, const char* error_type);
50+
6851
int main()
6952
{
7053
const int64_t max_int64_t = numeric_limits<int64_t>::max();
@@ -85,11 +68,8 @@ int main()
8568
assert_js("v64.size() === 5");
8669
assert_js("v64.get(4) === 1234n");
8770

88-
test("vector<int64_t> Cannot convert number to int64_t");
89-
ensure_js_throws("v64.push_back(1234)", "TypeError");
90-
9171
test("vector<int64_t> Cannot convert bigint that is too big");
92-
ensure_js_throws("v64.push_back(12345678901234567890123456n)", "TypeError");
72+
ensure_js_throws_with_assertions_enabled("v64.push_back(12345678901234567890123456n)", "TypeError");
9373

9474
test("vector<uint64_t>");
9575
val myval2(vector<uint64_t>{1, 2, 3, 4});
@@ -103,14 +83,15 @@ int main()
10383
assert_js("vU64.size() === 5");
10484
assert_js("vU64.get(4) === 1234n");
10585

106-
test("vector<uint64_t> Cannot convert number to uint64_t");
107-
ensure_js_throws("vU64.push_back(1234)", "TypeError");
86+
execute_js("vU64.push_back(1234)");
87+
assert_js("vU64.size() === 6");
88+
assert_js("vU64.get(5) === 1234n");
10889

10990
test("vector<uint64_t> Cannot convert bigint that is too big");
110-
ensure_js_throws("vU64.push_back(12345678901234567890123456n)", "TypeError");
91+
ensure_js_throws_with_assertions_enabled("vU64.push_back(12345678901234567890123456n)", "TypeError");
11192

11293
test("vector<uint64_t> Cannot convert bigint that is negative");
113-
ensure_js_throws("vU64.push_back(-1n)", "TypeError");
94+
ensure_js_throws_with_assertions_enabled("vU64.push_back(-1n)", "TypeError");
11495

11596
myval.call<void>("delete");
11697
myval2.call<void>("delete");

test/embind/test_i64_binding.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
addToLibrary({
2+
ensure_js_throws_with_assertions_enabled__deps: ['$bigintToI53Checked'],
3+
ensure_js_throws_with_assertions_enabled: function(js_code, error_type) {
4+
js_code = UTF8ToString(bigintToI53Checked(js_code));
5+
error_type = UTF8ToString(bigintToI53Checked(error_type));
6+
js_code += ";";
7+
try {
8+
eval(js_code);
9+
} catch(error_thrown) {
10+
#if ASSERTIONS
11+
assert(error_thrown.name === error_type);
12+
#else
13+
assert(false);
14+
#endif
15+
return;
16+
}
17+
#if ASSERTIONS
18+
assert(false);
19+
#endif
20+
}
21+
});

test/embind/test_i64_binding.out

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@ start
22
test:
33
vector<int64_t>
44
test:
5-
vector<int64_t> Cannot convert number to int64_t
6-
test:
75
vector<int64_t> Cannot convert bigint that is too big
86
test:
97
vector<uint64_t>
108
test:
11-
vector<uint64_t> Cannot convert number to uint64_t
12-
test:
139
vector<uint64_t> Cannot convert bigint that is too big
1410
test:
1511
vector<uint64_t> Cannot convert bigint that is negative

test/test_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7559,7 +7559,7 @@ def test_embind_i64_val(self):
75597559
@no_wasm2js('wasm_bigint')
75607560
def test_embind_i64_binding(self):
75617561
self.set_setting('WASM_BIGINT')
7562-
self.emcc_args += ['-lembind']
7562+
self.emcc_args += ['-lembind', '--js-library', test_file('embind/test_i64_binding.js')]
75637563
self.node_args += shared.node_bigint_flags(self.get_nodejs())
75647564
self.do_run_in_out_file_test('embind/test_i64_binding.cpp', assert_identical=True)
75657565

test/test_other.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2968,6 +2968,7 @@ def test_embind_closure_no_dynamic_execution(self):
29682968
'no_utf8': ['-sEMBIND_STD_STRING_IS_UTF8=0'],
29692969
'no_dynamic': ['-sDYNAMIC_EXECUTION=0'],
29702970
'aot_js': ['-sDYNAMIC_EXECUTION=0', '-sEMBIND_AOT', '-DSKIP_UNBOUND_TYPES'],
2971+
'wasm64': ['-sMEMORY64', '-Wno-experimental'],
29712972
})
29722973
@parameterized({
29732974
'': [],
@@ -2980,6 +2981,8 @@ def test_embind_closure_no_dynamic_execution(self):
29802981
'strict_js': ['-sSTRICT_JS']
29812982
})
29822983
def test_embind(self, *extra_args):
2984+
if '-sMEMORY64' in extra_args:
2985+
self.require_wasm64()
29832986
self.emcc_args += [
29842987
'--no-entry',
29852988
# This test explicitly creates std::string from unsigned char pointers

0 commit comments

Comments
 (0)