aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--system/include/emscripten/bind.h2
-rw-r--r--system/include/emscripten/wire.h64
-rw-r--r--system/lib/embind/bind.cpp38
-rw-r--r--tests/embind/embind.test.js4
-rw-r--r--tests/embind/embind_test.cpp2
5 files changed, 83 insertions, 27 deletions
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h
index 872f279b..b4c5004e 100644
--- a/system/include/emscripten/bind.h
+++ b/system/include/emscripten/bind.h
@@ -813,7 +813,7 @@ namespace emscripten {
// NOTE: this returns the class type, not the pointer type
template<typename T>
inline TYPEID getActualType(T* ptr) {
- return reinterpret_cast<TYPEID>(&typeid(*ptr));
+ return getLightTypeID(*ptr);
};
}
diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h
index 05b3ac33..c20e2f55 100644
--- a/system/include/emscripten/wire.h
+++ b/system/include/emscripten/wire.h
@@ -15,22 +15,66 @@
#define EMSCRIPTEN_ALWAYS_INLINE __attribute__((always_inline))
namespace emscripten {
+ #ifndef EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES
+ #define EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES 1
+ #endif
+
+
+ #if EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES
+ constexpr bool has_unbound_type_names = true;
+ #else
+ constexpr bool has_unbound_type_names = false;
+ #endif
+
namespace internal {
typedef void (*GenericFunction)();
- typedef const struct _TYPEID* TYPEID;
+ typedef const struct _TYPEID {}* TYPEID;
+
+
+ // We don't need the full std::type_info implementation. We
+ // just need a unique identifier per type and polymorphic type
+ // identification.
+
+ template<typename T>
+ struct CanonicalizedID {
+ static TYPEID get() {
+ static _TYPEID c;
+ return &c;
+ }
+ };
+
+ template<typename T>
+ struct Canonicalized {
+ typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type;
+ };
+
+ template<typename T>
+ struct LightTypeID {
+ static TYPEID get() {
+ typedef typename Canonicalized<T>::type C;
+ if (has_unbound_type_names || std::is_polymorphic<C>::value) {
+ return reinterpret_cast<TYPEID>(&typeid(C));
+ } else {
+ return CanonicalizedID<C>::get();
+ }
+ }
+ };
+
+ template<typename T>
+ const TYPEID getLightTypeID(const T& value) {
+ typedef typename Canonicalized<T>::type C;
+ if (has_unbound_type_names || std::is_polymorphic<C>::value) {
+ return reinterpret_cast<TYPEID>(&typeid(value));
+ } else {
+ return LightTypeID<T>::get();
+ }
+ }
- // This implementation is technically not legal, as it's not
- // required that two calls to typeid produce the same exact
- // std::type_info instance. That said, it's likely to work
- // given Emscripten compiles everything into one binary.
- // Should it not work in the future: replace TypeID with an
- // int, and store all TypeInfo we see in a map, allocating new
- // TypeIDs as we add new items to the map.
template<typename T>
struct TypeID {
static TYPEID get() {
- return reinterpret_cast<TYPEID>(&typeid(T));
+ return LightTypeID<T>::get();
}
};
@@ -53,7 +97,7 @@ namespace emscripten {
template<typename T>
struct TypeID<AllowedRawPointer<T>> {
static TYPEID get() {
- return reinterpret_cast<TYPEID>(&typeid(T*));
+ return LightTypeID<T*>::get();
}
};
diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp
index f43d1ea1..37918050 100644
--- a/system/lib/embind/bind.cpp
+++ b/system/lib/embind/bind.cpp
@@ -14,26 +14,32 @@ using namespace emscripten;
extern "C" {
const char* __attribute__((used)) __getTypeName(const std::type_info* ti) {
+ if (has_unbound_type_names) {
#ifdef USE_CXA_DEMANGLE
- int stat;
- char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat);
- if (stat == 0 && demangled) {
- return demangled;
- }
+ int stat;
+ char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat);
+ if (stat == 0 && demangled) {
+ return demangled;
+ }
- switch (stat) {
- case -1:
- return strdup("<allocation failure>");
- case -2:
- return strdup("<invalid C++ symbol>");
- case -3:
- return strdup("<invalid argument>");
- default:
- return strdup("<unknown error>");
- }
+ switch (stat) {
+ case -1:
+ return strdup("<allocation failure>");
+ case -2:
+ return strdup("<invalid C++ symbol>");
+ case -3:
+ return strdup("<invalid argument>");
+ default:
+ return strdup("<unknown error>");
+ }
#else
- return strdup(ti->name());
+ return strdup(ti->name());
#endif
+ } else {
+ char str[80];
+ sprintf(str, "%p", ti);
+ return strdup(str);
+ }
}
}
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index e2160c33..4b10a6c6 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -1646,6 +1646,10 @@ module({
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
BaseFixture.extend("unbound types", function() {
+ if (!cm.hasUnboundTypeNames) {
+ return;
+ }
+
function assertMessage(fn, message) {
var e = assert.throws(cm.UnboundTypeError, fn);
assert.equal(message, e.message);
diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp
index d299660a..b0c68f75 100644
--- a/tests/embind/embind_test.cpp
+++ b/tests/embind/embind_test.cpp
@@ -2147,6 +2147,8 @@ struct BoundClass {
};
EMSCRIPTEN_BINDINGS(incomplete) {
+ constant("hasUnboundTypeNames", emscripten::has_unbound_type_names);
+
function("getUnboundClass", &passThrough<UnboundClass>);
class_<HasUnboundBase, base<UnboundClass>>("HasUnboundBase")