| OLD | NEW | 
| (Empty) |  | 
 |    1 #pragma once | 
 |    2  | 
 |    3 #include <cstddef> | 
 |    4 #include <cstdint> | 
 |    5 #include <cstdio> | 
 |    6 #include <cstdlib> | 
 |    7 #include <exception> | 
 |    8 #include <map> | 
 |    9 #include <string> | 
 |   10 #include <type_traits> | 
 |   11 #include <utility> | 
 |   12 #include <vector> | 
 |   13  | 
 |   14 #include <emscripten.h> | 
 |   15  | 
 |   16 #include "String.h" | 
 |   17 #include "intrusive_ptr.h" | 
 |   18  | 
 |   19 namespace bindings_internal | 
 |   20 { | 
 |   21   typedef void* TYPEID; | 
 |   22  | 
 |   23   enum class TypeCategory | 
 |   24   { | 
 |   25     UNKNOWN, | 
 |   26     VOID, | 
 |   27     INT, | 
 |   28     DEPENDENT_STRING, | 
 |   29     OWNED_STRING, | 
 |   30     STRING_REF, | 
 |   31     CLASS_PTR | 
 |   32   }; | 
 |   33  | 
 |   34   template<typename T> | 
 |   35   struct TypeInfo | 
 |   36   { | 
 |   37     /* | 
 |   38      * Since TypeInfo is a templated type, in practice the compiler will define | 
 |   39      * a new type for each possible template parameter value. We use that fact | 
 |   40      * to generate type identifiers: each of these TypeInfo types has a | 
 |   41      * different s_typeIDHelper member, so we use a pointer to that static | 
 |   42      * variable as a type identifier - it will be different for each template | 
 |   43      * parameter. | 
 |   44      */ | 
 |   45     static char s_typeIDHelper; | 
 |   46     constexpr operator TYPEID() const | 
 |   47     { | 
 |   48       return &s_typeIDHelper; | 
 |   49     } | 
 |   50  | 
 |   51     constexpr operator TypeCategory() const | 
 |   52     { | 
 |   53       if (std::is_void<T>()) | 
 |   54         return TypeCategory::VOID; | 
 |   55  | 
 |   56       if (std::is_integral<T>() || std::is_enum<T>()) | 
 |   57         return TypeCategory::INT; | 
 |   58  | 
 |   59       if (std::is_same<DependentString, T>() || std::is_same<const DependentStri
     ng, T>()) | 
 |   60         return TypeCategory::DEPENDENT_STRING; | 
 |   61  | 
 |   62       if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>()
     ) | 
 |   63         return TypeCategory::OWNED_STRING; | 
 |   64  | 
 |   65       if (std::is_same<String&, T>() || std::is_same<const String&, T>() || | 
 |   66         std::is_same<DependentString&, T>()) | 
 |   67       { | 
 |   68         return TypeCategory::STRING_REF; | 
 |   69       } | 
 |   70  | 
 |   71       if (std::is_pointer<T>() && std::is_class<typename std::remove_pointer<T>:
     :type>()) | 
 |   72         return TypeCategory::CLASS_PTR; | 
 |   73  | 
 |   74       return TypeCategory::UNKNOWN; | 
 |   75     } | 
 |   76  | 
 |   77     constexpr TYPEID pointer_type() const | 
 |   78     { | 
 |   79       if (std::is_pointer<T>()) | 
 |   80         return TypeInfo<typename std::remove_pointer<T>::type>(); | 
 |   81       else | 
 |   82         return nullptr; | 
 |   83     } | 
 |   84   }; | 
 |   85  | 
 |   86   template<typename T> | 
 |   87   char TypeInfo<T>::s_typeIDHelper; | 
 |   88  | 
 |   89   struct FunctionInfo | 
 |   90   { | 
 |   91     TypeCategory returnType; | 
 |   92     TYPEID pointerType; | 
 |   93     std::vector<TypeCategory> args; | 
 |   94     bool instance_function; | 
 |   95     int effectiveArgs; | 
 |   96     TypeCategory effectiveReturnType; | 
 |   97     char name[1024]; | 
 |   98  | 
 |   99     FunctionInfo() | 
 |  100     { | 
 |  101       name[0] = '\0'; | 
 |  102     } | 
 |  103  | 
 |  104     FunctionInfo(TypeCategory returnType, TYPEID pointerType, | 
 |  105         std::initializer_list<TypeCategory> argTypes, bool instance_function, | 
 |  106         void* function) | 
 |  107         : returnType(returnType), pointerType(pointerType), | 
 |  108           instance_function(instance_function) | 
 |  109     { | 
 |  110       name[0] = '\0'; | 
 |  111  | 
 |  112       // The function parameter is a pointer to the function pointer. | 
 |  113       // Emscripten's "function pointers" are actually integers indicating the | 
 |  114       // position in the call table. 0 represents nullptr. | 
 |  115       if (!*reinterpret_cast<int*>(function)) | 
 |  116         return; | 
 |  117  | 
 |  118       for (const auto& item : argTypes) | 
 |  119       { | 
 |  120         if (item != TypeCategory::INT && item != TypeCategory::STRING_REF && | 
 |  121             item != TypeCategory::CLASS_PTR) | 
 |  122         { | 
 |  123           throw std::runtime_error("Unexpected function argument type"); | 
 |  124         } | 
 |  125         args.push_back(item); | 
 |  126       } | 
 |  127  | 
 |  128       if (returnType != TypeCategory::VOID && returnType != TypeCategory::INT && | 
 |  129           returnType != TypeCategory::DEPENDENT_STRING && | 
 |  130           returnType != TypeCategory::OWNED_STRING && | 
 |  131           returnType != TypeCategory::STRING_REF && | 
 |  132           returnType != TypeCategory::CLASS_PTR) | 
 |  133       { | 
 |  134         throw std::runtime_error("Unexpected function return type"); | 
 |  135       } | 
 |  136  | 
 |  137       effectiveArgs = args.size(); | 
 |  138       effectiveReturnType = returnType; | 
 |  139       if (instance_function) | 
 |  140         effectiveArgs++; | 
 |  141  | 
 |  142       if (returnType == TypeCategory::DEPENDENT_STRING || | 
 |  143           returnType == TypeCategory::OWNED_STRING) | 
 |  144       { | 
 |  145         effectiveArgs++; | 
 |  146         effectiveReturnType = TypeCategory::VOID; | 
 |  147       } | 
 |  148  | 
 |  149       get_function_name(function, effectiveArgs, | 
 |  150           effectiveReturnType == TypeCategory::VOID); | 
 |  151     } | 
 |  152  | 
 |  153     template<typename ReturnType, typename... Args> | 
 |  154     FunctionInfo(ReturnType (*function)(Args...)) | 
 |  155         : FunctionInfo(TypeInfo<ReturnType>(), | 
 |  156           TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, | 
 |  157           &function) | 
 |  158     { | 
 |  159     } | 
 |  160  | 
 |  161     template<typename ClassType, typename ReturnType, typename... Args> | 
 |  162     FunctionInfo(ReturnType (ClassType::*function)(Args...)) | 
 |  163         : FunctionInfo(TypeInfo<ReturnType>(), | 
 |  164           TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, | 
 |  165           &function) | 
 |  166     { | 
 |  167     } | 
 |  168  | 
 |  169     template<typename ClassType, typename ReturnType, typename... Args> | 
 |  170     FunctionInfo(ReturnType (ClassType::*function)(Args...) const) | 
 |  171         : FunctionInfo(TypeInfo<ReturnType>(), | 
 |  172           TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, | 
 |  173           &function) | 
 |  174     { | 
 |  175     } | 
 |  176  | 
 |  177     bool empty() const | 
 |  178     { | 
 |  179       return name[0] == '\0'; | 
 |  180     } | 
 |  181  | 
 |  182     void get_function_name(void* ptr, int numArgs, bool voidResult) | 
 |  183     { | 
 |  184       // This is a hack, C++ won't let us get the mangled function name. | 
 |  185       // JavaScript is more dynamic so we pass the pointer to our function | 
 |  186       // there. With that and the function signature we can call the function - | 
 |  187       // with a full stack so that we will cause it to abort. Sometimes the | 
 |  188       // function we are calling will also be missing from the build. The result | 
 |  189       // is the same: abort() is called which in turn calls stackTrace(). By | 
 |  190       // replacing stackTrace() we get access to the call stack and search it | 
 |  191       // for the name of our function. | 
 |  192  | 
 |  193       EM_ASM_ARGS({ | 
 |  194         var signature = $3 ? "v" : "i"; | 
 |  195         var args = []; | 
 |  196         for (var i = 0; i < $2; i++) | 
 |  197         { | 
 |  198           signature += "i"; | 
 |  199           args.push(0); | 
 |  200         } | 
 |  201  | 
 |  202         var oldPrint = Module.print; | 
 |  203         var oldPrintErr = Module.printErr; | 
 |  204         var oldStackTrace = stackTrace; | 
 |  205         var sp = Runtime.stackSave(); | 
 |  206         Module.print = function(){}; | 
 |  207         Module.printErr = function(){}; | 
 |  208         stackTrace = function() | 
 |  209         { | 
 |  210           var stack = []; | 
 |  211           for (var f = arguments.callee.caller; f; f = f.caller) | 
 |  212           { | 
 |  213             if (f.name) | 
 |  214             { | 
 |  215               if (f.name.indexOf("dynCall") == 0) | 
 |  216                 break; | 
 |  217               else | 
 |  218                 stack.push(f.name); | 
 |  219             } | 
 |  220           } | 
 |  221  | 
 |  222           result = stack[stack.length - 1]; | 
 |  223           if (result && result.indexOf("__wrapper") >= 0) | 
 |  224             result = stack[stack.length - 2]; | 
 |  225           throw result; | 
 |  226         }; | 
 |  227  | 
 |  228         Runtime.stackRestore(STACK_MAX); | 
 |  229  | 
 |  230         try | 
 |  231         { | 
 |  232           Runtime.dynCall(signature, HEAP32[$1 >> 2], args); | 
 |  233         } | 
 |  234         catch(e) | 
 |  235         { | 
 |  236           Module.stringToAscii(e, $0); | 
 |  237         } | 
 |  238         finally | 
 |  239         { | 
 |  240           Runtime.stackRestore(sp); | 
 |  241           Module.print = oldPrint; | 
 |  242           Module.printErr = oldPrintErr; | 
 |  243           stackTrace = oldStackTrace; | 
 |  244         } | 
 |  245       }, name, ptr, numArgs, voidResult); | 
 |  246     } | 
 |  247   }; | 
 |  248  | 
 |  249   class NoBaseClass | 
 |  250   { | 
 |  251   }; | 
 |  252  | 
 |  253   struct PropertyInfo | 
 |  254   { | 
 |  255     std::string name; | 
 |  256     FunctionInfo getter; | 
 |  257     FunctionInfo setter; | 
 |  258     std::string jsValue; | 
 |  259   }; | 
 |  260  | 
 |  261   struct MethodInfo | 
 |  262   { | 
 |  263     std::string name; | 
 |  264     FunctionInfo call; | 
 |  265   }; | 
 |  266  | 
 |  267   struct DifferentiatorInfo | 
 |  268   { | 
 |  269     size_t offset; | 
 |  270     std::vector<std::pair<int, std::string>> mapping; | 
 |  271   }; | 
 |  272  | 
 |  273   struct ClassInfo | 
 |  274   { | 
 |  275     ClassInfo* baseClass; | 
 |  276     std::string name; | 
 |  277     std::vector<PropertyInfo> properties; | 
 |  278     std::vector<MethodInfo> methods; | 
 |  279     std::vector<FunctionInfo> initializers; | 
 |  280     DifferentiatorInfo subclass_differentiator; | 
 |  281     ptrdiff_t ref_counted_offset; | 
 |  282   }; | 
 |  283  | 
 |  284   std::map<TYPEID, ClassInfo> classes; | 
 |  285  | 
 |  286   void register_class(const char* name, TYPEID classID, TYPEID baseClassID, | 
 |  287                       ptrdiff_t ref_counted_offset) | 
 |  288   { | 
 |  289     auto it = classes.find(classID); | 
 |  290     if (it != classes.end()) | 
 |  291       throw std::runtime_error(std::string("Duplicate definition for class ") + 
     name); | 
 |  292  | 
 |  293     ClassInfo* baseClass = nullptr; | 
 |  294     if (baseClassID != TypeInfo<NoBaseClass>()) | 
 |  295     { | 
 |  296       it = classes.find(baseClassID); | 
 |  297       if (it == classes.end()) | 
 |  298         throw std::runtime_error(std::string("Unknown base class defined for cla
     ss ") + name); | 
 |  299       baseClass = &(it->second); | 
 |  300     } | 
 |  301  | 
 |  302     ClassInfo classInfo; | 
 |  303     classInfo.baseClass = baseClass; | 
 |  304     classInfo.name = name; | 
 |  305     classInfo.subclass_differentiator.offset = SIZE_MAX; | 
 |  306     classInfo.ref_counted_offset = ref_counted_offset; | 
 |  307     classes[classID] = classInfo; | 
 |  308   } | 
 |  309  | 
 |  310   void register_property(TYPEID classID, const char* name, | 
 |  311       const FunctionInfo& getter, const FunctionInfo& setter, | 
 |  312       const char* jsValue = "") | 
 |  313   { | 
 |  314     auto it = classes.find(classID); | 
 |  315     if (it == classes.end()) | 
 |  316       throw std::runtime_error(std::string("Property defined on unknown class: "
     ) + name); | 
 |  317  | 
 |  318     PropertyInfo propertyInfo; | 
 |  319     propertyInfo.name = name; | 
 |  320     propertyInfo.getter = getter; | 
 |  321     propertyInfo.setter = setter; | 
 |  322     propertyInfo.jsValue = jsValue; | 
 |  323     it->second.properties.push_back(propertyInfo); | 
 |  324   } | 
 |  325  | 
 |  326   void register_method(TYPEID classID, const char* name, | 
 |  327       const FunctionInfo& call) | 
 |  328   { | 
 |  329     auto it = classes.find(classID); | 
 |  330     if (it == classes.end()) | 
 |  331       throw std::runtime_error(std::string("Method defined on unknown class: ") 
     + name); | 
 |  332  | 
 |  333     MethodInfo methodInfo; | 
 |  334     methodInfo.name = name; | 
 |  335     methodInfo.call = call; | 
 |  336     it->second.methods.push_back(methodInfo); | 
 |  337   } | 
 |  338  | 
 |  339   void register_initializer(TYPEID classID, const FunctionInfo& call) | 
 |  340   { | 
 |  341     auto it = classes.find(classID); | 
 |  342     if (it == classes.end()) | 
 |  343       throw std::runtime_error("Initializer defined on unknown class"); | 
 |  344  | 
 |  345     it->second.initializers.push_back(call); | 
 |  346   } | 
 |  347  | 
 |  348   void register_differentiator(TYPEID classID, size_t offset, | 
 |  349       std::vector<std::pair<int, std::string>>& mapping) | 
 |  350   { | 
 |  351     auto it = classes.find(classID); | 
 |  352     if (it == classes.end()) | 
 |  353       throw std::runtime_error("Subclass differentiator defined on unknown class
     "); | 
 |  354  | 
 |  355     if (it->second.subclass_differentiator.offset != SIZE_MAX) | 
 |  356       throw std::runtime_error("More than one subclass differentiator defined fo
     r class " + it->second.name); | 
 |  357  | 
 |  358     DifferentiatorInfo differentiatorInfo; | 
 |  359     differentiatorInfo.offset = offset; | 
 |  360     differentiatorInfo.mapping = mapping; | 
 |  361     it->second.subclass_differentiator = differentiatorInfo; | 
 |  362   } | 
 |  363  | 
 |  364   const std::string generateCall(const FunctionInfo& call, | 
 |  365       std::vector<std::string>& params) | 
 |  366   { | 
 |  367     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
 |  368         call.returnType == TypeCategory::OWNED_STRING) | 
 |  369     { | 
 |  370       params.insert(params.begin(), "string"); | 
 |  371     } | 
 |  372  | 
 |  373     std::string call_str(call.name); | 
 |  374     call_str += "("; | 
 |  375     for (int i = 0; i < params.size(); i++) | 
 |  376     { | 
 |  377       if (i > 0) | 
 |  378         call_str += ", "; | 
 |  379       call_str += params[i]; | 
 |  380     } | 
 |  381     call_str += ")"; | 
 |  382  | 
 |  383     if (call.returnType == TypeCategory::VOID) | 
 |  384       return "  " + call_str + ";\n"; | 
 |  385     else if (call.returnType == TypeCategory::INT) | 
 |  386       return "  var result = " + call_str + ";\n"; | 
 |  387     else if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
 |  388         call.returnType == TypeCategory::OWNED_STRING) | 
 |  389     { | 
 |  390       std::string result; | 
 |  391       result += "  var string = createString();\n"; | 
 |  392       result += "  " + call_str + ";\n"; | 
 |  393       result += "  var result = readString(string);\n"; | 
 |  394       if (call.returnType == TypeCategory::OWNED_STRING) | 
 |  395         result += "  Module._DestroyString(string);\n"; | 
 |  396       return result; | 
 |  397     } | 
 |  398     else if (call.returnType == TypeCategory::STRING_REF) | 
 |  399     { | 
 |  400       return "  var result = readString(" + call_str + ");\n"; | 
 |  401     } | 
 |  402     else if (call.returnType == TypeCategory::CLASS_PTR) | 
 |  403     { | 
 |  404       std::string result; | 
 |  405       result += "  var result = " + call_str + ";\n"; | 
 |  406       result += "  if (result)\n"; | 
 |  407       result += "  {\n"; | 
 |  408  | 
 |  409       auto it = classes.find(call.pointerType); | 
 |  410       if (it == classes.end()) | 
 |  411         throw std::runtime_error("Function " + std::string(call.name) + " return
     s pointer to unknown class"); | 
 |  412  | 
 |  413       const ClassInfo& cls = it->second; | 
 |  414       auto offset = cls.subclass_differentiator.offset; | 
 |  415       if (offset == SIZE_MAX) | 
 |  416         result += "    result = " + cls.name + "(result);\n"; | 
 |  417       else | 
 |  418       { | 
 |  419         result += "    var type = HEAP32[result + " + std::to_string(offset)+ " 
     >> 2];\n"; | 
 |  420         result += "    if (type in " + cls.name + "_mapping)\n"; | 
 |  421         result += "      result = new (exports[" + cls.name + "_mapping[type]])(
     result);\n"; | 
 |  422         result += "    else\n"; | 
 |  423         result += "      throw new Error('Unexpected " + cls.name + " type: ' + 
     type);\n"; | 
 |  424       } | 
 |  425  | 
 |  426       result += "  }\n"; | 
 |  427       return result; | 
 |  428     } | 
 |  429     else | 
 |  430       throw std::runtime_error("Unexpected return type for " + std::string(call.
     name)); | 
 |  431   } | 
 |  432  | 
 |  433   const std::string wrapCall(const FunctionInfo& call) | 
 |  434   { | 
 |  435     char buffer[20]; | 
 |  436     bool hasStringArgs = false; | 
 |  437     std::vector<std::string> params; | 
 |  438     std::string prefix = "function("; | 
 |  439     for (int i = 0; i < call.args.size(); i++) | 
 |  440     { | 
 |  441       sprintf(buffer, "arg%i", i); | 
 |  442       if (i > 0) | 
 |  443         prefix += ", "; | 
 |  444       prefix += buffer; | 
 |  445  | 
 |  446       if (call.args[i] == TypeCategory::STRING_REF) | 
 |  447       { | 
 |  448         hasStringArgs = true; | 
 |  449         params.push_back(std::string("createString(") + buffer + ")"); | 
 |  450       } | 
 |  451       else | 
 |  452         params.push_back(buffer); | 
 |  453     } | 
 |  454     prefix += ")\n{\n"; | 
 |  455  | 
 |  456     std::string suffix = "}"; | 
 |  457     if (call.returnType != TypeCategory::VOID) | 
 |  458       suffix = "  return result;\n" + suffix; | 
 |  459  | 
 |  460     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
 |  461         call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) | 
 |  462     { | 
 |  463       prefix += "  var sp = Runtime.stackSave();\n"; | 
 |  464       suffix = "  Runtime.stackRestore(sp);\n" + suffix; | 
 |  465     } | 
 |  466  | 
 |  467     if (call.instance_function) | 
 |  468       params.insert(params.begin(), "this._pointer"); | 
 |  469  | 
 |  470     return prefix + generateCall(call, params) + suffix; | 
 |  471   } | 
 |  472  | 
 |  473   std::string generatePropertyDescriptor(const PropertyInfo& property) | 
 |  474   { | 
 |  475     if (!property.jsValue.empty()) | 
 |  476       return "value: " + property.jsValue; | 
 |  477  | 
 |  478     std::string result("get: " + wrapCall(property.getter)); | 
 |  479     if (!property.setter.empty()) | 
 |  480       result += ", set: " + wrapCall(property.setter); | 
 |  481     return result; | 
 |  482   } | 
 |  483  | 
 |  484   void printHelpers() | 
 |  485   { | 
 |  486     printf("var sizeofString = %i;\n", sizeof(String)); | 
 |  487  | 
 |  488     puts(R"( | 
 |  489   function copyString(str, buffer) | 
 |  490   { | 
 |  491     var length = str.length; | 
 |  492     for (var i = 0, pointer = (buffer >> 1); i < length; i++, pointer++) | 
 |  493       HEAP16[pointer] = str.charCodeAt(i); | 
 |  494     return length; | 
 |  495   } | 
 |  496  | 
 |  497   function createString(str) | 
 |  498   { | 
 |  499     var length = 0; | 
 |  500     var buffer = 0; | 
 |  501     if (str) | 
 |  502     { | 
 |  503       buffer = Runtime.stackAlloc(str.length * 2); | 
 |  504       length = copyString(str, buffer); | 
 |  505     } | 
 |  506  | 
 |  507     var result = Module.Runtime.stackAlloc(sizeofString); | 
 |  508     Module._InitString(result, buffer, length); | 
 |  509     return result; | 
 |  510   } | 
 |  511  | 
 |  512   function readString(str) | 
 |  513   { | 
 |  514     var length = Module._GetStringLength(str); | 
 |  515     var pointer = Module._GetStringData(str) >> 1; | 
 |  516     return String.fromCharCode.apply(String, HEAP16.slice(pointer, pointer + len
     gth)); | 
 |  517   } | 
 |  518  | 
 |  519   function createClass(superclass, ref_counted_offset) | 
 |  520   { | 
 |  521     var result = function(pointer) | 
 |  522     { | 
 |  523       this._pointer = pointer; | 
 |  524     }; | 
 |  525     if (superclass) | 
 |  526       result.prototype = Object.create(superclass.prototype); | 
 |  527     result.prototype.delete = function() | 
 |  528     { | 
 |  529       Module._ReleaseRef(this._pointer + ref_counted_offset); | 
 |  530     }; | 
 |  531     return result; | 
 |  532   })"); | 
 |  533   } | 
 |  534  | 
 |  535   void printClass(const ClassInfo& cls) | 
 |  536   { | 
 |  537     DifferentiatorInfo differentiator = cls.subclass_differentiator; | 
 |  538     if (differentiator.offset != SIZE_MAX) | 
 |  539     { | 
 |  540       printf("var %s_mapping = \n", cls.name.c_str()); | 
 |  541       puts("{"); | 
 |  542       for (const auto& item : differentiator.mapping) | 
 |  543         printf("  %i: '%s',\n", item.first, item.second.c_str()); | 
 |  544       puts("};"); | 
 |  545     } | 
 |  546  | 
 |  547     printf("exports.%s = createClass(%s, %i);\n", cls.name.c_str(), | 
 |  548         (cls.baseClass ? ("exports." + cls.baseClass->name).c_str() : "null"), | 
 |  549         cls.ref_counted_offset); | 
 |  550  | 
 |  551     for (const auto& item : cls.properties) | 
 |  552     { | 
 |  553       printf("Object.defineProperty(exports.%s.prototype, '%s', {%s});\n", | 
 |  554           cls.name.c_str(), item.name.c_str(), | 
 |  555           generatePropertyDescriptor(item).c_str()); | 
 |  556     } | 
 |  557  | 
 |  558     for (const auto& item : cls.methods) | 
 |  559     { | 
 |  560       std::string obj("exports." + cls.name); | 
 |  561       if (item.call.instance_function) | 
 |  562         obj += ".prototype"; | 
 |  563       printf("%s.%s = %s;\n", obj.c_str(), item.name.c_str(), | 
 |  564           wrapCall(item.call).c_str()); | 
 |  565     } | 
 |  566  | 
 |  567     for (const auto& item : cls.initializers) | 
 |  568       printf("%s()\n", item.name); | 
 |  569   } | 
 |  570  | 
 |  571   void printBindings() | 
 |  572   { | 
 |  573     printHelpers(); | 
 |  574  | 
 |  575     for (const auto& item : classes) | 
 |  576       printClass(item.second); | 
 |  577   } | 
 |  578 } | 
 |  579  | 
 |  580 #if defined(PRINT_BINDINGS) | 
 |  581   // Bindings generation step: collect bindings information and print | 
 |  582   // corresponding JS code. | 
 |  583   #define EMSCRIPTEN_BINDINGS \ | 
 |  584       struct BindingsInitializer {\ | 
 |  585           BindingsInitializer();\ | 
 |  586           BindingsInitializer(bool dummy)\ | 
 |  587           {\ | 
 |  588             try\ | 
 |  589             {\ | 
 |  590               BindingsInitializer();\ | 
 |  591               bindings_internal::printBindings();\ | 
 |  592             }\ | 
 |  593             catch (const std::exception& e)\ | 
 |  594             {\ | 
 |  595               EM_ASM_ARGS(\ | 
 |  596                 console.error("Error occurred generating JavaScript bindings: " 
     +\ | 
 |  597                     Module.AsciiToString($0)), e.what()\ | 
 |  598               );\ | 
 |  599               abort();\ | 
 |  600             }\ | 
 |  601           }\ | 
 |  602       } BindingsInitializer_instance(true);\ | 
 |  603       BindingsInitializer::BindingsInitializer() | 
 |  604 #else | 
 |  605   // Actual compilation step: ignore bindings information but define some | 
 |  606   // exported helper functions necessary for the bindings. | 
 |  607   #define EMSCRIPTEN_BINDINGS \ | 
 |  608       extern "C"\ | 
 |  609       {\ | 
 |  610         void EMSCRIPTEN_KEEPALIVE InitString(DependentString* str,\ | 
 |  611             String::value_type* data, String::size_type len)\ | 
 |  612         {\ | 
 |  613           /* String is already allocated on stack, we merely need to call*/\ | 
 |  614           /* constructor.*/\ | 
 |  615           new (str) DependentString(data, len);\ | 
 |  616         }\ | 
 |  617         void EMSCRIPTEN_KEEPALIVE DestroyString(OwnedString* str)\ | 
 |  618         {\ | 
 |  619           /* Stack memory will be freed automatically, we need to call*/\ | 
 |  620           /* destructor explicitly however.*/\ | 
 |  621           str->~OwnedString();\ | 
 |  622         }\ | 
 |  623         String::size_type EMSCRIPTEN_KEEPALIVE GetStringLength(\ | 
 |  624             const String& str)\ | 
 |  625         {\ | 
 |  626           return str.length();\ | 
 |  627         }\ | 
 |  628         const String::value_type* EMSCRIPTEN_KEEPALIVE GetStringData(\ | 
 |  629             const String& str)\ | 
 |  630         {\ | 
 |  631           return str.data();\ | 
 |  632         }\ | 
 |  633         void EMSCRIPTEN_KEEPALIVE ReleaseRef(ref_counted* ptr)\ | 
 |  634         {\ | 
 |  635           ptr->ReleaseRef();\ | 
 |  636         }\ | 
 |  637       }\ | 
 |  638       void BindingsInitializer_dummy() | 
 |  639 #endif | 
 |  640  | 
 |  641 template<typename ClassType, | 
 |  642     typename BaseClass = bindings_internal::NoBaseClass, | 
 |  643     typename std::enable_if<std::is_base_of<ref_counted, ClassType>::value>::typ
     e* = nullptr> | 
 |  644 class class_ | 
 |  645 { | 
 |  646 public: | 
 |  647   class_(const char* name) | 
 |  648   { | 
 |  649     ClassType* ptr = reinterpret_cast<ClassType*>(0x10000000); | 
 |  650     ptrdiff_t ref_counted_offset = | 
 |  651         reinterpret_cast<char*>(static_cast<ref_counted*>(ptr)) - | 
 |  652         reinterpret_cast<char*>(ptr); | 
 |  653     bindings_internal::register_class(name, | 
 |  654         bindings_internal::TypeInfo<ClassType>(), | 
 |  655         bindings_internal::TypeInfo<BaseClass>(), | 
 |  656         ref_counted_offset | 
 |  657       ); | 
 |  658   } | 
 |  659  | 
 |  660   template<typename FieldType> | 
 |  661   const class_& property(const char* name, | 
 |  662       FieldType (ClassType::*getter)() const, | 
 |  663       void (ClassType::*setter)(FieldType) = nullptr) const | 
 |  664   { | 
 |  665     bindings_internal::register_property( | 
 |  666         bindings_internal::TypeInfo<ClassType>(), name, getter, setter); | 
 |  667     return *this; | 
 |  668   } | 
 |  669  | 
 |  670   const class_& class_property(const char* name, | 
 |  671       const char* jsValue) const | 
 |  672   { | 
 |  673     bindings_internal::register_property( | 
 |  674         bindings_internal::TypeInfo<ClassType>(), name, | 
 |  675         bindings_internal::FunctionInfo(), bindings_internal::FunctionInfo(), | 
 |  676         jsValue); | 
 |  677     return *this; | 
 |  678   } | 
 |  679  | 
 |  680   template<typename ReturnType, typename... Args> | 
 |  681   const class_& function(const char* name, ReturnType (ClassType::*method)(Args.
     ..)) const | 
 |  682   { | 
 |  683     bindings_internal::register_method( | 
 |  684         bindings_internal::TypeInfo<ClassType>(), name, method); | 
 |  685     return *this; | 
 |  686   } | 
 |  687  | 
 |  688   template<typename ReturnType, typename... Args> | 
 |  689   const class_& function(const char* name, ReturnType (ClassType::*method)(Args.
     ..) const) const | 
 |  690   { | 
 |  691     bindings_internal::register_method( | 
 |  692         bindings_internal::TypeInfo<ClassType>(), name, method); | 
 |  693     return *this; | 
 |  694   } | 
 |  695  | 
 |  696   template<typename ReturnType, typename... Args> | 
 |  697   const class_& class_function(const char* name, ReturnType (*method)(Args...)) 
     const | 
 |  698   { | 
 |  699     bindings_internal::register_method( | 
 |  700         bindings_internal::TypeInfo<ClassType>(), name, method); | 
 |  701     return *this; | 
 |  702   } | 
 |  703  | 
 |  704   const class_& class_initializer(void (*function)()) const | 
 |  705   { | 
 |  706     bindings_internal::register_initializer( | 
 |  707         bindings_internal::TypeInfo<ClassType>(), function); | 
 |  708     return *this; | 
 |  709   } | 
 |  710  | 
 |  711   template<typename ReturnType, | 
 |  712       typename std::enable_if<std::is_convertible<ReturnType, int32_t>::value>::
     type* = nullptr> | 
 |  713   const class_& subclass_differentiator(ReturnType ClassType::* member, | 
 |  714       std::initializer_list<std::pair<ReturnType, const char*>> list) const | 
 |  715   { | 
 |  716     ClassType* instance = nullptr; | 
 |  717     size_t offset = (char*)&(instance->*member) - (char*)instance; | 
 |  718  | 
 |  719     std::vector<std::pair<int, std::string>> mapping; | 
 |  720     for (const auto& item : list) | 
 |  721       mapping.emplace_back(item.first, item.second); | 
 |  722  | 
 |  723     bindings_internal::register_differentiator( | 
 |  724         bindings_internal::TypeInfo<ClassType>(), offset, mapping); | 
 |  725     return *this; | 
 |  726   } | 
 |  727 }; | 
| OLD | NEW |