aboutsummaryrefslogtreecommitdiff
path: root/system
diff options
context:
space:
mode:
authorBill Welden <bwelden@imvu.com>2012-12-04 10:56:59 -0800
committerJukka Jylänki <jujjyl@gmail.com>2013-04-12 14:22:20 +0300
commit03d90a32db03078ff2666b4d8ca63d5f804e57f3 (patch)
tree76d3bb1ddf9612c528d12ad1a74e27e34cb65fde /system
parent1276f9f5b73b10c914aa8c2c1a675be526b57480 (diff)
More work toward dynamic downcasting of pointers.
Diffstat (limited to 'system')
-rwxr-xr-xsystem/include/emscripten/bind.h12
-rwxr-xr-xsystem/lib/embind/bind.cpp102
2 files changed, 107 insertions, 7 deletions
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h
index 96e8dda5..54c017ef 100755
--- a/system/include/emscripten/bind.h
+++ b/system/include/emscripten/bind.h
@@ -104,7 +104,6 @@ namespace emscripten {
TYPEID pointerType,
TYPEID constPointerType,
const char* className,
- GenericFunction getDynamicTypeInfo,
GenericFunction destructor);
void _embind_register_class_constructor(
@@ -267,16 +266,16 @@ namespace emscripten {
// FUNCTIONS
////////////////////////////////////////////////////////////////////////////////
+ extern "C" {
+ int __getDynamicPointerType(int p);
+ int __dynamicPointerCast(int p, int from, int to);
+ }
+
template<typename FromType, typename ToType>
ToType& performCast(FromType& from) {
return *dynamic_cast<ToType*>(&from);
};
- template<typename PointerType>
- internal::TYPEID getDynamicPointerType(PointerType *p) {
- return reinterpret_cast<internal::TYPEID>(&typeid(*p));
- };
-
template<typename FromRawType, typename ToRawType>
std::shared_ptr<ToRawType> performPointerCast(std::shared_ptr<FromRawType> from) {
return std::shared_ptr<ToRawType>(from, dynamic_cast<ToRawType*>(from.get()));
@@ -662,7 +661,6 @@ namespace emscripten {
TypeID<AllowedRawPointer<ClassType>>::get(),
TypeID<AllowedRawPointer<const ClassType>>::get(),
name,
- reinterpret_cast<GenericFunction>(&getDynamicPointerType<ClassType>),
reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>));
}
diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp
index befce08b..c7c1f4b4 100755
--- a/system/lib/embind/bind.cpp
+++ b/system/lib/embind/bind.cpp
@@ -1,7 +1,43 @@
#include <emscripten/bind.h>
+#include <..\lib\libcxxabi\src\private_typeinfo.h>
+#include <list>
+#include <vector>
+#include <emscripten/emscripten.h>
using namespace emscripten;
+namespace __cxxabiv1 {
+ std::vector<const __class_type_info*> __getBaseClasses(const __class_type_info* cti) {
+ std::vector<const __class_type_info*> bases;
+
+ const __si_class_type_info* scti = dynamic_cast<const __si_class_type_info*>(cti);
+ if (scti) {
+ bases.emplace_back(scti->__base_type);
+ } else {
+ const __vmi_class_type_info* vcti = dynamic_cast<const __vmi_class_type_info*>(cti);
+ if (vcti) {
+ for (int i = 0; i < vcti->__base_count; i++) {
+ bases.emplace_back(vcti->__base_info[i].__base_type);
+ }
+ }
+ }
+ return bases;
+ }
+
+ void __getDerivationPaths1(const __class_type_info* dv, const __class_type_info* bs, std::vector<const __class_type_info*>path, std::vector<std::vector<const __class_type_info*>>& paths) {
+ std::vector<const __class_type_info*> newPath(path);
+ newPath.emplace_back(dv);
+ if (dv == bs) {
+ paths.emplace_back(newPath);
+ } else {
+ std::vector<const __class_type_info*> bases = __getBaseClasses(dv);
+ for (int i = 0; i < bases.size(); i++) {
+ __getDerivationPaths1(bases[i], bs, newPath, paths);
+ }
+ }
+ }
+}
+
namespace emscripten {
namespace internal {
void registerStandardTypes() {
@@ -30,5 +66,71 @@ namespace emscripten {
_embind_register_emval(TypeID<val>::get(), "emscripten::val");
}
}
+
+ extern "C" {
+ // These three routines constitute an extension to the compiler's support for dynamic type conversion.
+ // They are used by embind.js to implement automatic downcasting of return values which are pointers to
+ // polymorphic objects.
+
+ // __getDerivationPaths returns an array of arrays of type_info pointers (cast as integers to make
+ // the Javascript bindings simpler). Each element of the outer array is an array of type_info pointers
+ // identifying a derivation path from the derived type to the base type. If either of the type info
+ // pointer paramters does not specify a pointer to a class, or if there is no path from the derived type
+ // to the base type, this routine returns zero.
+ std::vector<std::vector<int>> __getDerivationPaths(int dv, const int bs) {
+ std::vector<std::vector<const __cxxabiv1::__class_type_info*>> paths;
+
+ const std::type_info* dv1 = (std::type_info*)dv;
+ const std::type_info* bs1 = (std::type_info*)bs;
+ const __cxxabiv1::__class_type_info* dv2 = dynamic_cast<const __cxxabiv1::__class_type_info*>(dv1);
+ const __cxxabiv1::__class_type_info* bs2 = dynamic_cast<const __cxxabiv1::__class_type_info*>(bs1);
+
+ if (dv2 && bs2) {
+ __cxxabiv1::__getDerivationPaths1(dv2, bs2, std::vector<const __cxxabiv1::__class_type_info*>(), paths);
+ }
+
+ std::vector<std::vector<int>> pathsAsTypeInfo;
+ for (int i = 0; i < paths.size(); i++) {
+ std::vector<int> pathAsTypeInfo;
+ for (int j = 0; j < paths[i].size(); j++) {
+ pathAsTypeInfo.emplace_back((int)paths[i][j]);
+ }
+ pathsAsTypeInfo.emplace_back(pathAsTypeInfo);
+ }
+
+ return pathsAsTypeInfo;
+ }
+
+ // We bind __getDerivationPaths in order to take advantage of the std::vector to Javascript array
+ // conversion for the return value. This has the unfortunate side-effect of exposing it to third party
+ // developers, but perhaps the double underscore will scare them away from calling it.
+ EMSCRIPTEN_BINDINGS(([]() {
+ function("__getDerivationPaths", &__getDerivationPaths);
+ }));
+
+ // __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually
+ // pointed to.
+ int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) {
+ void** vtable = *(void***)p;
+ return (int)static_cast<const std::type_info*>(vtable[-1]);
+ }
+
+ // Calls to __dynamic_cast are generated by the compiler to implement dynamic_cast<>() -- its prototype is
+ // not available through any header file. It is called directly here because it allows run-time
+ // specification of the target pointer type (which must be specified at compile time when using
+ // dynamic_cast<>().
+ void* __dynamic_cast(void*, const std::type_info*, const std::type_info*, int);
+
+ // __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of
+ // the from and to pointer types.
+ int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int from, int to) {
+ // The final parameter is a place-holder for a hint, a feature which is not currently implemented
+ // in the emscripten runtime. The compiler passes a dummy value of -1, and so do we.
+ return (int)__dynamic_cast((void *)p, (const std::type_info*)from, (const std::type_info *)to, -1);
+ }
+ }
}
}
+
+
+