diff options
author | Chad Austin <chad@imvu.com> | 2014-03-31 22:43:28 -0700 |
---|---|---|
committer | Chad Austin <chad@chadaustin.me> | 2014-04-13 09:08:27 -0700 |
commit | 2bbdb0cd396d785a9587bc776d699283c1902ff7 (patch) | |
tree | 7660e0be1523660cf21bd252af16f9bd605bcd9a | |
parent | ce58885c11947bc4fb511646989c7d88212f69fa (diff) |
embind doesn't always need the full std::type_info record. if EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0, then use a lighter type identifier. This shaves 175 KB off of our engine's minified JavaScript.
-rw-r--r-- | system/include/emscripten/bind.h | 2 | ||||
-rw-r--r-- | system/include/emscripten/wire.h | 64 | ||||
-rw-r--r-- | system/lib/embind/bind.cpp | 38 | ||||
-rw-r--r-- | tests/embind/embind.test.js | 4 | ||||
-rw-r--r-- | tests/embind/embind_test.cpp | 2 |
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") |