diff options
author | Bill Welden <bwelden@imvu.com> | 2012-12-04 10:56:59 -0800 |
---|---|---|
committer | Jukka Jylänki <jujjyl@gmail.com> | 2013-04-12 14:22:20 +0300 |
commit | 03d90a32db03078ff2666b4d8ca63d5f804e57f3 (patch) | |
tree | 76d3bb1ddf9612c528d12ad1a74e27e34cb65fde | |
parent | 1276f9f5b73b10c914aa8c2c1a675be526b57480 (diff) |
More work toward dynamic downcasting of pointers.
-rwxr-xr-x | src/embind/embind.js | 136 | ||||
-rwxr-xr-x | system/include/emscripten/bind.h | 12 | ||||
-rwxr-xr-x | system/lib/embind/bind.cpp | 102 |
3 files changed, 113 insertions, 137 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js index 45341700..7f4e0d2e 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -493,23 +493,16 @@ function __embind_register_vector( }); } -// hang onto your hats, guys, we're going to try to make this one registration work for the class and all its -// derived classes - function __embind_register_class( classType, pointerType, constPointerType, name, - getDynamicPointerType, destructor ) { name = Pointer_stringify(name); destructor = FUNCTION_TABLE[destructor]; - if (getDynamicPointerType) { - getDynamicPointerType = FUNCTION_TABLE[getDynamicPointerType]; - } - + var Handle = createNamedFunction(name, function(ptr) { var h = function() { if(h.operator_call !== undefined) { @@ -521,7 +514,7 @@ function __embind_register_class( h.count = {value: 1}; h.ptr = ptr; - + for(var prop in Handle.prototype) { var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); Object.defineProperty(h, prop, dp); @@ -566,6 +559,8 @@ function __embind_register_class( return body.apply(this, arguments); }); constructor.prototype = Handle.prototype; + constructor.classType = classType; + registerType(classType, name, { name: name, @@ -584,14 +579,14 @@ function __embind_register_class( registerType(pointerType, pointerName, { name: pointerName, fromWireType: function(ptr) { - var dynamicType = getDynamicPointerType && getDynamicPointerType(ptr); + var dynamicType = ___getDynamicPointerType(ptr); // !!! this won't work if pointer is not dynamic if (dynamicType === null || dynamicType === pointerType) { return new Handle(ptr); } try { dynamicType = requireRegisteredType(dynamicType); } catch (err) { - return new Handle(ptr); // I suppose we could work our way up the inheritance tree... + return new Handle(ptr); } dynamicType = requireRegisteredType(dynamicType.pointerType); return dynamicType.fromWireTypeStatic(ptr); @@ -607,19 +602,6 @@ function __embind_register_class( var constPointerName = name + ' const*'; registerType(constPointerType, constPointerName, { name: constPointerName, - fromWireType: function(ptr) { - var dynamicType = getDynamicPointerType && getDynamicPointerType(ptr); - if (dynamicType === null || dynamicType === pointerType) { - return new Handle(ptr); - } - try { - dynamicType = requireRegisteredType(dynamicType); - } catch (err) { - return new Handle(ptr); // I suppose we could work our way up the inheritance tree... - } - dynamicType = requireRegisteredType(dynamicType.pointerType); - return dynamicType.fromWireType(ptr); - }, toWireType: function(destructors, o) { return o.ptr; } @@ -628,112 +610,6 @@ function __embind_register_class( exposePublicSymbol(name, constructor); } -//function __embind_register_class( -// classType, -// pointerType, -// constPointerType, -// name, -// destructor -//) { -// name = Pointer_stringify(name); -// destructor = FUNCTION_TABLE[destructor]; -// -// var Handle = createNamedFunction(name, function(ptr) { -// var h = function() { -// if(h.operator_call !== undefined) { -// return h.operator_call.apply(h, arguments); -// } else { -// throw new BindingError(name + ' does not define call operator'); -// } -// }; -// -// h.count = {value: 1}; -// h.ptr = ptr; -// -// for(var prop in Handle.prototype) { -// var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop); -// Object.defineProperty(h, prop, dp); -// } -// -// return h; -// }); -// -// Handle.prototype.clone = function() { -// if (!this.ptr) { -// throw new BindingError(classType.name + ' instance already deleted'); -// } -// -// var clone = Object.create(Handle.prototype); -// clone.count = this.count; -// clone.ptr = this.ptr; -// -// clone.count.value += 1; -// return clone; -// }; -// -// Handle.prototype.move = function() { -// var rv = this.clone(); -// this.delete(); -// return rv; -// }; -// -// Handle.prototype['delete'] = function() { -// if (!this.ptr) { -// throw new BindingError(classType.name + ' instance already deleted'); -// } -// -// this.count.value -= 1; -// if (0 === this.count.value) { -// destructor(this.ptr); -// } -// this.ptr = undefined; -// }; -// -// var constructor = createNamedFunction(name, function() { -// var body = constructor.body; -// return body.apply(this, arguments); -// }); -// constructor.prototype = Handle.prototype; -// -// registerType(classType, name, { -// name: name, -// constructor: constructor, -// Handle: Handle, -// fromWireType: function(ptr) { -// return new Handle(ptr); -// }, -// toWireType: function(destructors, o) { -// return o.ptr; -// } -// }); -// -// var pointerName = name + '*'; -// registerType(pointerType, pointerName, { -// name: pointerName, -// fromWireType: function(ptr) { -// // based on the fully downcast type of the pointer, -// -// return new Handle(ptr); // if me -// }, -// toWireType: function(destructors, o) { -// return o.ptr; -// } -// }); -// -// var constPointerName = name + ' const*'; -// registerType(constPointerType, constPointerName, { -// name: constPointerName, -// fromWireType: function(ptr) { -// return new Handle(ptr); -// }, -// toWireType: function(destructors, o) { -// return o.ptr; -// } -// }); -// -// exposePublicSymbol(name, constructor); -//} -// function __embind_register_class_constructor( classType, argCount, 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);
+ }
+ }
}
}
+
+
+
|