aboutsummaryrefslogtreecommitdiff
path: root/system/lib/embind/bind.cpp
blob: c7c1f4b4474a163cc3fd5e9e16afb7ea6d5449a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#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() {
            static bool first = true;
            if (first) {
                first = false;

                _embind_register_void(TypeID<void>::get(), "void");

                _embind_register_bool(TypeID<bool>::get(), "bool", true, false);

                _embind_register_integer(TypeID<char>::get(), "char");
                _embind_register_integer(TypeID<signed char>::get(), "signed char");
                _embind_register_integer(TypeID<unsigned char>::get(), "unsigned char");
                _embind_register_integer(TypeID<signed short>::get(), "short");
                _embind_register_integer(TypeID<unsigned short>::get(), "unsigned short");
                _embind_register_integer(TypeID<signed int>::get(), "int");
                _embind_register_integer(TypeID<unsigned int>::get(), "unsigned int");
                _embind_register_integer(TypeID<signed long>::get(), "long");
                _embind_register_integer(TypeID<unsigned long>::get(), "unsigned long");

                _embind_register_float(TypeID<float>::get(), "float");
                _embind_register_float(TypeID<double>::get(), "double");

                _embind_register_cstring(TypeID<std::string>::get(), "std::string");
                _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);
            }
        }
    }
}