Skip to content

Commit

Permalink
Update embind nortti test and documentation. NFC
Browse files Browse the repository at this point in the history
Automatic downcasting of polymorphic types in embind has been broken
without rtti since emscripten-core#10914 landed.

This test update confirms this brokenness rather than fixing it since
this has been the behavior since 2020.

Fixes: emscripten-core#21619
  • Loading branch information
sbc100 committed Mar 26, 2024
1 parent 3d6d207 commit ffc1e84
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,8 @@ are available.
.. note:: *Embind* must understand the fully-derived type for automatic
downcasting to work.

.. note:: *Embind* does not support this unless RTTI is enabled.


Overloaded functions
====================
Expand Down
3 changes: 2 additions & 1 deletion src/embind/embind.js
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,8 @@ var LibraryEmbind = {
if (signature.includes('j')) {
return getDynCaller(signature, rawFunction);
}
#elif MEMORY64
#endif
#if MEMORY64 || CAN_ADDRESS_2GB
if (signature.includes('p')) {
return getDynCaller(signature, rawFunction);
}
Expand Down
4 changes: 4 additions & 0 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -2755,6 +2755,8 @@ addToLibrary({
$dynCallLegacy: (sig, ptr, args) => {
#if MEMORY64
sig = sig.replace(/p/g, 'j')
#else
sig = sig.replace(/p/g, 'i')
#endif
#if ASSERTIONS
#if MINIMAL_RUNTIME
Expand Down Expand Up @@ -2830,6 +2832,8 @@ addToLibrary({
#endif
#if MEMORY64
return sig[0] == 'p' ? Number(rtn) : rtn;
#elif CAN_ADDRESS_2GB
return sig[0] == 'p' ? rtn >>> 0 : rtn;
#else
return rtn;
#endif
Expand Down
7 changes: 3 additions & 4 deletions system/include/emscripten/bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,9 +510,6 @@ struct SignatureCode<double> {
}
};

#ifdef __wasm64__
// With wasm32 we can fallback to 'i' for pointer types but we need special
// handling with wasm64.
template<>
struct SignatureCode<void*> {
static constexpr char get() {
Expand All @@ -525,6 +522,8 @@ struct SignatureCode<size_t> {
return 'p';
}
};

#ifdef __wasm64__
template<>
struct SignatureCode<long> {
static constexpr char get() {
Expand All @@ -545,14 +544,14 @@ template<> struct SignatureTranslator<float> { using type = float; };
template<> struct SignatureTranslator<double> { using type = double; };
#ifdef __wasm64__
template<> struct SignatureTranslator<long> { using type = long; };
#endif
template<> struct SignatureTranslator<size_t> { using type = size_t; };
template<typename PtrType>
struct SignatureTranslator<PtrType*> { using type = void*; };
template<typename PtrType>
struct SignatureTranslator<PtrType&> { using type = void*; };
template<typename ReturnType, typename... Args>
struct SignatureTranslator<ReturnType (*)(Args...)> { using type = void*; };
#endif

template<typename... Args>
EMSCRIPTEN_ALWAYS_INLINE const char* getSpecificSignature() {
Expand Down
37 changes: 33 additions & 4 deletions test/core/test_embind_polymorphic_class_no_rtti.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,64 @@
#include <stdio.h>

EM_JS(void, calltest, (), {
var foo = new Module["Foo"]();
var foo = new Module.Foo();
var fooRaw = Module.FooRaw();
console.log("foo.test() returned: " + foo.test());
console.log("foo.getClassName() -> " + foo.getClassName());
console.log("fooRaw.getClassName() -> " + fooRaw.getClassName());
#if __has_feature(cxx_rtti)
// When RTTI is available we do automatic downcasting
assert(foo.getClassName() == "Bar");
assert(fooRaw.getClassName() == "Bar");
#else
// When RTTI is not available we cannot do automatic downcasting
assert(foo.getClassName() == "Foo");
assert(fooRaw.getClassName() == "Foo");
#endif
foo.delete();
});

class Foo {
public:
virtual ~Foo() = default;
virtual int test() = 0;
const std::string getClassName() {
return "Foo";
}
};

class Bar : public Foo {
public:
int test() override { return 42; }
const std::string getClassName() {
return "Bar";
}
};

int main(int argc, char** argv){
printf("Hello, world.\n");
printf("in main\n");
calltest();
printf("calltest done\n");
return 0;
}

std::shared_ptr<Foo> MakeFoo() {
Foo* makeFooRaw() {
return new Bar();
}

std::shared_ptr<Foo> makeFoo() {
return std::make_shared<Bar>();
}

using namespace emscripten;

EMSCRIPTEN_BINDINGS(my_module) {
function("FooRaw", &makeFooRaw, allow_raw_pointers());
emscripten::class_<Foo>("Foo")
.smart_ptr_constructor("Foo", &MakeFoo)
.smart_ptr_constructor("Foo", &makeFoo)
.function("test", &Foo::test)
.function("getClassName", &Foo::getClassName)
;
class_<Bar, base<Foo>>("Bar")
.function("getClassName", &Bar::getClassName);
};
2 changes: 1 addition & 1 deletion test/core/test_embind_polymorphic_class_no_rtti.out
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Hello, world.
in main
foo.test() returned: 42
9 changes: 6 additions & 3 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7580,9 +7580,12 @@ def test_embind_no_rtti(self):
self.emcc_args += ['-lembind', '-fno-rtti', '-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0']
self.do_runf('main.cpp', '418\ndotest returned: 42\n')

def test_embind_polymorphic_class_no_rtti(self):
self.emcc_args += ['-lembind', '-fno-rtti', '-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0']
self.do_core_test('test_embind_polymorphic_class_no_rtti.cpp')
@parameterized({
'': ([],),
'no_rtti': (['-fno-rtti', '-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0'],),
})
def test_embind_polymorphic_class(self, args):
self.do_core_test('test_embind_polymorphic_class_no_rtti.cpp', emcc_args=args + ['-lembind'])

def test_embind_no_rtti_followed_by_rtti(self):
src = r'''
Expand Down

0 comments on commit ffc1e84

Please sign in to comment.