| LEFT | RIGHT | 
|---|
| 1 /* | 1 /* | 
| 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| 3  * Copyright (C) 2006-2017 eyeo GmbH | 3  * Copyright (C) 2006-present eyeo GmbH | 
| 4  * | 4  * | 
| 5  * Adblock Plus is free software: you can redistribute it and/or modify | 5  * Adblock Plus is free software: you can redistribute it and/or modify | 
| 6  * it under the terms of the GNU General Public License version 3 as | 6  * it under the terms of the GNU General Public License version 3 as | 
| 7  * published by the Free Software Foundation. | 7  * published by the Free Software Foundation. | 
| 8  * | 8  * | 
| 9  * Adblock Plus is distributed in the hope that it will be useful, | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
| 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 12  * GNU General Public License for more details. | 12  * GNU General Public License for more details. | 
| 13  * | 13  * | 
| 14  * You should have received a copy of the GNU General Public License | 14  * You should have received a copy of the GNU General Public License | 
| 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| 16  */ | 16  */ | 
| 17 | 17 | 
| 18 #include <cstdio> | 18 #include <cstdio> | 
| 19 | 19 | 
| 20 #include <emscripten.h> |  | 
| 21 |  | 
| 22 #include "generator.h" | 20 #include "generator.h" | 
|  | 21 #include "library.h" | 
| 23 | 22 | 
| 24 namespace | 23 namespace | 
| 25 { | 24 { | 
| 26   std::vector<bindings_internal::ClassInfo> classes; | 25   std::vector<bindings_internal::ClassInfo> classes; | 
| 27   std::vector<bindings_internal::NamespaceInfo> namespaces; |  | 
| 28 |  | 
| 29   void printProperties(const bindings_internal::PropertyList& properties) |  | 
| 30   { |  | 
| 31     for (const auto& property : properties) |  | 
| 32     { |  | 
| 33       if (property.jsValue.empty()) |  | 
| 34       { |  | 
| 35         printf("get %s%s,\n", property.name.c_str(), |  | 
| 36                wrapCall(property.getter, false).c_str()); |  | 
| 37         if (!property.setter.empty()) |  | 
| 38         { |  | 
| 39           printf("set %s%s,\n", property.name.c_str(), |  | 
| 40                  wrapCall(property.setter, false).c_str()); |  | 
| 41         } |  | 
| 42       } |  | 
| 43       else |  | 
| 44         printf("%s: %s,\n", property.name.c_str(), property.jsValue.c_str()); |  | 
| 45     } |  | 
| 46   } |  | 
| 47 |  | 
| 48   void printMethods(const bindings_internal::MethodList& methods, |  | 
| 49                     bool instanceOnly = true) |  | 
| 50   { |  | 
| 51     for (const auto& method : methods) |  | 
| 52       if (!instanceOnly || method.call.instance_function) |  | 
| 53         printf("%s: %s,\n", method.name.c_str(), wrapCall(method.call).c_str()); |  | 
| 54   } |  | 
| 55 } | 26 } | 
| 56 | 27 | 
| 57 namespace bindings_internal | 28 namespace bindings_internal | 
| 58 { | 29 { | 
| 59   FunctionInfo::FunctionInfo() | 30   FunctionInfo::FunctionInfo() | 
| 60   { | 31   { | 
| 61     name[0] = '\0'; |  | 
| 62   } | 32   } | 
| 63 | 33 | 
| 64   FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType, | 34   FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType, | 
| 65       std::initializer_list<TypeCategory> argTypes, bool instance_function, | 35       std::initializer_list<TypeCategory> argTypes, bool instance_function, | 
| 66       void* function) | 36       void* function) | 
| 67       : returnType(returnType), pointerType(pointerType), | 37       : returnType(returnType), pointerType(pointerType), | 
| 68         instance_function(instance_function) | 38         instance_function(instance_function) | 
| 69   { | 39   { | 
| 70     name[0] = '\0'; |  | 
| 71 |  | 
| 72     // The function parameter is a pointer to the function pointer. | 40     // The function parameter is a pointer to the function pointer. | 
| 73     // Emscripten's "function pointers" are actually integers indicating the | 41     // Emscripten's "function pointers" are actually integers indicating the | 
| 74     // position in the call table. 0 represents nullptr. | 42     // position in the call table. 0 represents nullptr. | 
| 75     if (!*reinterpret_cast<int*>(function)) | 43     if (!*reinterpret_cast<int*>(function)) | 
| 76       return; | 44       return; | 
| 77 | 45 | 
| 78     std::string signature; | 46     std::string signature; | 
| 79 | 47 | 
| 80     // Add return type to the signature. Similar logic in Emscripten: | 48     // Add return type to the signature. Similar logic in Emscripten: | 
| 81     // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46 | 49     // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46 | 
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 134           break; | 102           break; | 
| 135         case TypeCategory::DOUBLE: | 103         case TypeCategory::DOUBLE: | 
| 136           signature += 'd'; | 104           signature += 'd'; | 
| 137           break; | 105           break; | 
| 138         default: | 106         default: | 
| 139           throw std::runtime_error("Unexpected function argument type"); | 107           throw std::runtime_error("Unexpected function argument type"); | 
| 140       } | 108       } | 
| 141       args.push_back(type); | 109       args.push_back(type); | 
| 142     } | 110     } | 
| 143 | 111 | 
| 144     get_function_name(function, signature.c_str()); | 112     int nameLength = GetFunctionName(nullptr, function, signature.c_str()); | 
|  | 113     name.resize(nameLength); | 
|  | 114     GetFunctionName(name.data(), function, signature.c_str()); | 
| 145   } | 115   } | 
| 146 | 116 | 
| 147   bool FunctionInfo::empty() const | 117   bool FunctionInfo::empty() const | 
| 148   { | 118   { | 
| 149     return name[0] == '\0'; | 119     return name.empty(); | 
| 150   } |  | 
| 151 |  | 
| 152   void FunctionInfo::get_function_name(void* ptr, const char* signature) |  | 
| 153   { |  | 
| 154     // This is a hack, C++ won't let us get the mangled function name. |  | 
| 155     // JavaScript is more dynamic so we pass the pointer to our function |  | 
| 156     // there. With that and the function signature we can call the function - |  | 
| 157     // with a full stack so that we will cause it to abort. Sometimes the |  | 
| 158     // function we are calling will also be missing from the build. The result |  | 
| 159     // is the same: abort() is called which in turn calls stackTrace(). By |  | 
| 160     // replacing stackTrace() we get access to the call stack and search it |  | 
| 161     // for the name of our function. |  | 
| 162 |  | 
| 163     EM_ASM_ARGS({ |  | 
| 164       var signature = AsciiToString($2); |  | 
| 165       var args = []; |  | 
| 166       for (var i = 1; i < signature.length; i++) |  | 
| 167         args.push(0); |  | 
| 168 |  | 
| 169       var oldPrint = Module.print; |  | 
| 170       var oldPrintErr = Module.printErr; |  | 
| 171       var oldStackTrace = stackTrace; |  | 
| 172       var sp = Runtime.stackSave(); |  | 
| 173       Module.print = function(){}; |  | 
| 174       Module.printErr = function(){}; |  | 
| 175       stackTrace = function() |  | 
| 176       { |  | 
| 177         var stack = []; |  | 
| 178         for (var f = arguments.callee.caller; f; f = f.caller) |  | 
| 179         { |  | 
| 180           if (f.name) |  | 
| 181           { |  | 
| 182             if (f.name.indexOf("dynCall") == 0) |  | 
| 183               break; |  | 
| 184             else |  | 
| 185               stack.push(f.name); |  | 
| 186           } |  | 
| 187         } |  | 
| 188 |  | 
| 189         result = stack[stack.length - 1]; |  | 
| 190         if (result && result.indexOf("__wrapper") >= 0) |  | 
| 191           result = stack[stack.length - 2]; |  | 
| 192         throw result; |  | 
| 193       }; |  | 
| 194 |  | 
| 195       Runtime.stackRestore(STACK_MAX); |  | 
| 196 |  | 
| 197       try |  | 
| 198       { |  | 
| 199         Runtime.dynCall(signature, HEAP32[$1 >> 2], args); |  | 
| 200       } |  | 
| 201       catch(e) |  | 
| 202       { |  | 
| 203         Module.stringToAscii(e, $0); |  | 
| 204       } |  | 
| 205       finally |  | 
| 206       { |  | 
| 207         Runtime.stackRestore(sp); |  | 
| 208         Module.print = oldPrint; |  | 
| 209         Module.printErr = oldPrintErr; |  | 
| 210         stackTrace = oldStackTrace; |  | 
| 211       } |  | 
| 212     }, name, ptr, signature); |  | 
| 213   } | 120   } | 
| 214 | 121 | 
| 215   ClassInfo* find_class(TYPEID classID) | 122   ClassInfo* find_class(TYPEID classID) | 
| 216   { | 123   { | 
| 217     for (auto& classInfo : classes) | 124     for (auto& classInfo : classes) | 
| 218       if (classInfo.id == classID) | 125       if (classInfo.id == classID) | 
| 219         return &classInfo; | 126         return &classInfo; | 
| 220     return nullptr; | 127     return nullptr; | 
| 221   } | 128   } | 
| 222 | 129 | 
| 223   void register_class(const char* name, TYPEID classID, TYPEID baseClassID, | 130   void register_class(const char* name, TYPEID classID, TYPEID baseClassID, | 
| 224                       ptrdiff_t ref_counted_offset) | 131                       ptrdiff_t ref_counted_offset, | 
|  | 132                       const FunctionInfo& instanceGetter) | 
| 225   { | 133   { | 
| 226     if (find_class(classID)) | 134     if (find_class(classID)) | 
| 227       throw std::runtime_error(std::string("Duplicate definition for class ") + 
     name); | 135       throw std::runtime_error(std::string("Duplicate definition for class ") + 
     name); | 
| 228 | 136 | 
| 229     if (baseClassID != TypeInfo<NoBaseClass>() && !find_class(baseClassID)) | 137     if (baseClassID != TypeInfo<NoBaseClass>() && !find_class(baseClassID)) | 
| 230       throw std::runtime_error(std::string("Unknown base class defined for class
      ") + name); | 138       throw std::runtime_error(std::string("Unknown base class defined for class
      ") + name); | 
| 231 | 139 | 
| 232     ClassInfo classInfo; | 140     ClassInfo classInfo; | 
| 233     classInfo.id = classID; | 141     classInfo.id = classID; | 
| 234     classInfo.baseClass = baseClassID; | 142     classInfo.baseClass = baseClassID; | 
| 235     classInfo.name = name; | 143     classInfo.name = name; | 
| 236     classInfo.subclass_differentiator.offset = SIZE_MAX; | 144     classInfo.subclass_differentiator.offset = SIZE_MAX; | 
| 237     classInfo.ref_counted_offset = ref_counted_offset; | 145     classInfo.ref_counted_offset = ref_counted_offset; | 
|  | 146     classInfo.instanceGetter = instanceGetter; | 
| 238     classes.push_back(classInfo); | 147     classes.push_back(classInfo); | 
| 239   } | 148   } | 
| 240 | 149 | 
| 241   void register_property(TYPEID classID, const char* name, | 150   void register_property(TYPEID classID, const char* name, | 
| 242       const FunctionInfo& getter, const FunctionInfo& setter, | 151       const FunctionInfo& getter, const FunctionInfo& setter, | 
| 243       const char* jsValue) | 152       const char* jsValue) | 
| 244   { | 153   { | 
| 245     ClassInfo* classInfo = find_class(classID); | 154     ClassInfo* classInfo = find_class(classID); | 
| 246     if (!classInfo) | 155     if (!classInfo) | 
| 247       throw std::runtime_error(std::string("Property defined on unknown class: "
     ) + name); | 156       throw std::runtime_error(std::string("Property defined on unknown class: "
     ) + name); | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 274     if (!classInfo) | 183     if (!classInfo) | 
| 275       throw std::runtime_error("Subclass differentiator defined on unknown class
     "); | 184       throw std::runtime_error("Subclass differentiator defined on unknown class
     "); | 
| 276 | 185 | 
| 277     if (classInfo->subclass_differentiator.offset != SIZE_MAX) | 186     if (classInfo->subclass_differentiator.offset != SIZE_MAX) | 
| 278       throw std::runtime_error("More than one subclass differentiator defined fo
     r class " + classInfo->name); | 187       throw std::runtime_error("More than one subclass differentiator defined fo
     r class " + classInfo->name); | 
| 279 | 188 | 
| 280     DifferentiatorInfo differentiatorInfo; | 189     DifferentiatorInfo differentiatorInfo; | 
| 281     differentiatorInfo.offset = offset; | 190     differentiatorInfo.offset = offset; | 
| 282     differentiatorInfo.mapping = mapping; | 191     differentiatorInfo.mapping = mapping; | 
| 283     classInfo->subclass_differentiator = differentiatorInfo; | 192     classInfo->subclass_differentiator = differentiatorInfo; | 
| 284   } |  | 
| 285 |  | 
| 286   NamespaceInfo* find_namespace(const char* namespaceName) |  | 
| 287   { |  | 
| 288     for (auto& namespaceInfo : namespaces) |  | 
| 289       if (namespaceInfo.name == namespaceName) |  | 
| 290         return &namespaceInfo; |  | 
| 291     return nullptr; |  | 
| 292   } |  | 
| 293 |  | 
| 294   void register_namespace(const char* name) |  | 
| 295   { |  | 
| 296     if (find_namespace(name)) |  | 
| 297       throw std::runtime_error(std::string("Duplicate definition for namespace "
     ) + name); |  | 
| 298 |  | 
| 299     NamespaceInfo namespaceInfo; |  | 
| 300     namespaceInfo.name = name; |  | 
| 301     namespaces.push_back(namespaceInfo); |  | 
| 302   } |  | 
| 303 |  | 
| 304   void register_namespace_property(const char* namespaceName, const char* name, |  | 
| 305       const FunctionInfo& getter, const FunctionInfo& setter) |  | 
| 306   { |  | 
| 307     NamespaceInfo* namespaceInfo = find_namespace(namespaceName); |  | 
| 308     if (!namespaceInfo) |  | 
| 309       throw std::runtime_error(std::string("Property defined on unknown namespac
     e: ") + name); |  | 
| 310 |  | 
| 311     PropertyInfo propertyInfo; |  | 
| 312     propertyInfo.name = name; |  | 
| 313     propertyInfo.getter = getter; |  | 
| 314     propertyInfo.setter = setter; |  | 
| 315     namespaceInfo->properties.push_back(propertyInfo); |  | 
| 316   } |  | 
| 317 |  | 
| 318   void register_namespace_method(const char* namespaceName, const char* name, |  | 
| 319       const FunctionInfo& call) |  | 
| 320   { |  | 
| 321     NamespaceInfo* namespaceInfo = find_namespace(namespaceName); |  | 
| 322     if (!namespaceInfo) |  | 
| 323       throw std::runtime_error(std::string("Method defined on unknown namespace:
      ") + name); |  | 
| 324 |  | 
| 325     MethodInfo methodInfo; |  | 
| 326     methodInfo.name = name; |  | 
| 327     methodInfo.call = call; |  | 
| 328     namespaceInfo->methods.push_back(methodInfo); |  | 
| 329   } | 193   } | 
| 330 | 194 | 
| 331   std::string generateCall(const FunctionInfo& call, | 195   std::string generateCall(const FunctionInfo& call, | 
| 332       std::vector<std::string>& params) | 196       std::vector<std::string>& params) | 
| 333   { | 197   { | 
| 334     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 198     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
| 335         call.returnType == TypeCategory::OWNED_STRING) | 199         call.returnType == TypeCategory::OWNED_STRING) | 
| 336     { | 200     { | 
| 337       params.insert(params.begin(), "string"); | 201       params.insert(params.begin(), "string"); | 
| 338     } | 202     } | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 353         return "  " + call_str + ";\n"; | 217         return "  " + call_str + ";\n"; | 
| 354       case TypeCategory::INT: | 218       case TypeCategory::INT: | 
| 355       case TypeCategory::FLOAT: | 219       case TypeCategory::FLOAT: | 
| 356       case TypeCategory::DOUBLE: | 220       case TypeCategory::DOUBLE: | 
| 357         return "  var result = " + call_str + ";\n"; | 221         return "  var result = " + call_str + ";\n"; | 
| 358       case TypeCategory::INT64: | 222       case TypeCategory::INT64: | 
| 359         return "  var result = Runtime.makeBigInt(" + call_str + ", " + | 223         return "  var result = Runtime.makeBigInt(" + call_str + ", " + | 
| 360                                                   "Runtime.getTempRet0(), " + | 224                                                   "Runtime.getTempRet0(), " + | 
| 361                                                   "true);\n"; | 225                                                   "true);\n"; | 
| 362       case TypeCategory::DEPENDENT_STRING: | 226       case TypeCategory::DEPENDENT_STRING: | 
| 363       case TypeCategory::OWNED_STRING: |  | 
| 364       { | 227       { | 
| 365         std::string result; | 228         std::string result; | 
| 366         result += "  var string = createString();\n"; | 229         result += "  var string = createString();\n"; | 
| 367         result += "  " + call_str + ";\n"; | 230         result += "  " + call_str + ";\n"; | 
| 368         result += "  var result = readString(string);\n"; | 231         result += "  var result = readString(string);\n"; | 
| 369         if (call.returnType == TypeCategory::OWNED_STRING) | 232         // We don't call a destructor here because we know that dependent | 
| 370           result += "  Module._DestroyString(string);\n"; | 233         // strings don't need to clean up. | 
|  | 234         return result; | 
|  | 235       } | 
|  | 236       case TypeCategory::OWNED_STRING: | 
|  | 237       { | 
|  | 238         std::string result; | 
|  | 239         result += "  var string = createOwnedString();\n"; | 
|  | 240         result += "  " + call_str + ";\n"; | 
|  | 241         result += "  var result = readString(string);\n"; | 
|  | 242         result += "  Module._DestroyString(string);\n"; | 
| 371         return result; | 243         return result; | 
| 372       } | 244       } | 
| 373       case TypeCategory::STRING_REF: | 245       case TypeCategory::STRING_REF: | 
| 374         return "  var result = readString(" + call_str + ");\n"; | 246         return "  var result = readString(" + call_str + ");\n"; | 
| 375       case TypeCategory::CLASS_PTR: | 247       case TypeCategory::CLASS_PTR: | 
| 376       { | 248       { | 
| 377         std::string result; | 249         std::string result; | 
| 378         result += "  var result = " + call_str + ";\n"; | 250         result += "  var result = " + call_str + ";\n"; | 
| 379         result += "  if (result)\n"; | 251         result += "  if (result)\n"; | 
| 380         result += "  {\n"; |  | 
| 381 | 252 | 
| 382         const ClassInfo* cls = find_class(call.pointerType); | 253         const ClassInfo* cls = find_class(call.pointerType); | 
| 383         if (!cls) | 254         if (!cls) | 
| 384           throw std::runtime_error("Function " + std::string(call.name) + " retu
     rns pointer to unknown class"); | 255           throw std::runtime_error("Function " + call.name + " returns pointer t
     o unknown class"); | 
| 385 | 256 | 
| 386         auto offset = cls->subclass_differentiator.offset; | 257         auto offset = cls->subclass_differentiator.offset; | 
| 387         if (offset == SIZE_MAX) | 258         if (offset == SIZE_MAX) | 
| 388           result += "    result = exports." + cls->name + "(result);\n"; | 259           result += "    result = exports." + cls->name + "(result);\n"; | 
| 389         else | 260         else | 
| 390           result += "    result = exports." + cls->name + ".fromPointer(result);
     \n"; | 261           result += "    result = exports." + cls->name + ".fromPointer(result);
     \n"; | 
| 391 | 262 | 
| 392         result += "  }\n"; |  | 
| 393         result += "  else\n"; | 263         result += "  else\n"; | 
| 394         result += "    result = null;\n"; | 264         result += "    result = null;\n"; | 
| 395         return result; | 265         return result; | 
| 396       } | 266       } | 
| 397       default: | 267       default: | 
| 398         throw std::runtime_error("Unexpected return type for " + std::string(cal
     l.name)); | 268         throw std::runtime_error("Unexpected return type for " + call.name); | 
| 399     } | 269     } | 
| 400   } | 270   } | 
| 401 | 271 | 
| 402   std::string wrapCall(const FunctionInfo& call, bool isFunction) | 272   std::string wrapCall(const FunctionInfo& call, bool isFunction, | 
|  | 273       const FunctionInfo& instanceGetter) | 
| 403   { | 274   { | 
| 404     bool hasStringArgs = false; | 275     bool hasStringArgs = false; | 
| 405     std::vector<std::string> params; | 276     std::vector<std::string> params; | 
| 406     std::string prefix; | 277     std::string prefix; | 
| 407 | 278 | 
| 408     if (isFunction) | 279     if (isFunction) | 
| 409       prefix += "function"; | 280       prefix += "function"; | 
| 410     prefix += "("; | 281     prefix += "("; | 
| 411     for (int i = 0; i < call.args.size(); i++) | 282     for (int i = 0; i < call.args.size(); i++) | 
| 412     { | 283     { | 
| (...skipping 25 matching lines...) Expand all  Loading... | 
| 438       suffix = "  return result;\n" + suffix; | 309       suffix = "  return result;\n" + suffix; | 
| 439 | 310 | 
| 440     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 311     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
| 441         call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) | 312         call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) | 
| 442     { | 313     { | 
| 443       prefix += "  var sp = Runtime.stackSave();\n"; | 314       prefix += "  var sp = Runtime.stackSave();\n"; | 
| 444       suffix = "  Runtime.stackRestore(sp);\n" + suffix; | 315       suffix = "  Runtime.stackRestore(sp);\n" + suffix; | 
| 445     } | 316     } | 
| 446 | 317 | 
| 447     if (call.instance_function) | 318     if (call.instance_function) | 
| 448       params.insert(params.begin(), "this._pointer"); | 319     { | 
|  | 320       if (instanceGetter.empty()) | 
|  | 321         params.insert(params.begin(), "this._pointer"); | 
|  | 322       else | 
|  | 323         params.insert(params.begin(), instanceGetter.name + "()"); | 
|  | 324     } | 
| 449 | 325 | 
| 450     return prefix + generateCall(call, params) + suffix; | 326     return prefix + generateCall(call, params) + suffix; | 
| 451   } | 327   } | 
| 452 | 328 | 
| 453   void printHelpers() | 329   void printHelpers() | 
| 454   { | 330   { | 
| 455     printf("var sizeofString = %i;\n", sizeof(String)); | 331     printf("var sizeofString = %i;\n", sizeof(String)); | 
| 456 | 332 | 
| 457     puts(R"( | 333     puts(R"( | 
| 458       function copyString(str, buffer) | 334       function copyString(str, buffer) | 
| 459       { | 335       { | 
| 460         var length = str.length; | 336         var length = str.length; | 
| 461         for (var i = 0, pointer = (buffer >> 1); i < length; i++, pointer++) | 337         for (var i = 0, pointer = (buffer >> 1); i < length; i++, pointer++) | 
| 462           HEAP16[pointer] = str.charCodeAt(i); | 338           HEAP16[pointer] = str.charCodeAt(i); | 
| 463         return length; | 339         return length; | 
| 464       } | 340       } | 
| 465 | 341 | 
| 466       function createString(str) | 342       function createString(str) | 
| 467       { | 343       { | 
| 468         var length = 0; | 344         var length = 0; | 
| 469         var buffer = 0; | 345         var buffer = 0; | 
| 470         if (str) | 346         if (str) | 
| 471         { | 347         { | 
| 472           buffer = Runtime.stackAlloc(str.length * 2); | 348           buffer = Runtime.stackAlloc(str.length * 2); | 
| 473           length = copyString(str, buffer); | 349           length = copyString(str, buffer); | 
| 474         } | 350         } | 
| 475 | 351 | 
| 476         var result = Runtime.stackAlloc(sizeofString); | 352         var result = Runtime.stackAlloc(sizeofString); | 
| 477         Module._InitString(result, buffer, length); | 353         Module._InitString(result, buffer, length); | 
|  | 354         return result; | 
|  | 355       } | 
|  | 356 | 
|  | 357       function createOwnedString() | 
|  | 358       { | 
|  | 359         var result = Runtime.stackAlloc(sizeofString); | 
|  | 360         Module._InitOwnedString(result); | 
| 478         return result; | 361         return result; | 
| 479       } | 362       } | 
| 480 | 363 | 
| 481       function readString(str) | 364       function readString(str) | 
| 482       { | 365       { | 
| 483         var length = Module._GetStringLength(str); | 366         var length = Module._GetStringLength(str); | 
| 484         var pointer = Module._GetStringData(str) >> 1; | 367         var pointer = Module._GetStringData(str) >> 1; | 
| 485         return String.fromCharCode.apply(String, HEAP16.slice(pointer, pointer +
      length)); | 368         return String.fromCharCode.apply(String, HEAP16.slice(pointer, pointer +
      length)); | 
| 486       } | 369       } | 
| 487 | 370 | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 498           Module._ReleaseRef(this._pointer + ref_counted_offset); | 381           Module._ReleaseRef(this._pointer + ref_counted_offset); | 
| 499         }; | 382         }; | 
| 500         return result; | 383         return result; | 
| 501       } | 384       } | 
| 502     )"); | 385     )"); | 
| 503   } | 386   } | 
| 504 | 387 | 
| 505   void printClass(const ClassInfo& cls) | 388   void printClass(const ClassInfo& cls) | 
| 506   { | 389   { | 
| 507     // Begin class definition | 390     // Begin class definition | 
| 508     ClassInfo* baseClass = find_class(cls.baseClass); | 391     bool singleton = !cls.instanceGetter.empty(); | 
| 509     printf("exports.%s = createClass(%s, %i, {\n", cls.name.c_str(), | 392     if (singleton) | 
| 510         (baseClass ? ("exports." + baseClass->name).c_str() : "null"), | 393       printf("exports.%s = {\n", cls.name.c_str()); | 
| 511         cls.ref_counted_offset); | 394     else | 
|  | 395     { | 
|  | 396       ClassInfo* baseClass = find_class(cls.baseClass); | 
|  | 397       printf("exports.%s = createClass(%s, %i, {\n", cls.name.c_str(), | 
|  | 398           (baseClass ? ("exports." + baseClass->name).c_str() : "null"), | 
|  | 399           cls.ref_counted_offset); | 
|  | 400     } | 
| 512 | 401 | 
| 513     // Print prototype members | 402     // Print prototype members | 
| 514     printProperties(cls.properties); | 403     for (const auto& property : cls.properties) | 
| 515     printMethods(cls.methods); | 404     { | 
|  | 405       if (property.jsValue.empty()) | 
|  | 406       { | 
|  | 407         printf("get %s%s,\n", property.name.c_str(), | 
|  | 408                wrapCall(property.getter, false, cls.instanceGetter).c_str()); | 
|  | 409         if (!property.setter.empty()) | 
|  | 410         { | 
|  | 411           printf("set %s%s,\n", property.name.c_str(), | 
|  | 412                  wrapCall(property.setter, false, cls.instanceGetter).c_str()); | 
|  | 413         } | 
|  | 414       } | 
|  | 415       else | 
|  | 416         printf("%s: %s,\n", property.name.c_str(), property.jsValue.c_str()); | 
|  | 417     } | 
|  | 418 | 
|  | 419     for (const auto& method : cls.methods) | 
|  | 420     { | 
|  | 421       if (method.call.instance_function) | 
|  | 422       { | 
|  | 423         printf("%s: %s,\n", | 
|  | 424             method.name.c_str(), | 
|  | 425             wrapCall(method.call, true, cls.instanceGetter).c_str()); | 
|  | 426       } | 
|  | 427     } | 
| 516 | 428 | 
| 517     // End class definition | 429     // End class definition | 
| 518     printf("});\n"); | 430     if (singleton) | 
|  | 431       printf("};\n"); | 
|  | 432     else | 
|  | 433       printf("});\n"); | 
| 519 | 434 | 
| 520     // Print static members | 435     // Print static members | 
| 521     DifferentiatorInfo differentiator = cls.subclass_differentiator; | 436     DifferentiatorInfo differentiator = cls.subclass_differentiator; | 
| 522     if (differentiator.offset != SIZE_MAX) | 437     if (differentiator.offset != SIZE_MAX) | 
| 523     { | 438     { | 
| 524       printf("var %s_mapping = \n", cls.name.c_str()); |  | 
| 525       puts("{"); |  | 
| 526       for (const auto& item : differentiator.mapping) |  | 
| 527         printf("  %i: '%s',\n", item.first, item.second.c_str()); |  | 
| 528       puts("};"); |  | 
| 529 |  | 
| 530       printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); | 439       printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); | 
| 531       puts("{"); | 440       puts("{"); | 
| 532       printf("  var type = HEAP32[ptr + %i >> 2];\n", differentiator.offset); | 441       printf("  var type = HEAP32[ptr + %i >> 2];\n", differentiator.offset); | 
| 533       printf("  if (type in %s_mapping)\n", cls.name.c_str()); | 442       printf("  if (type in %s_mapping)\n", cls.name.c_str()); | 
| 534       printf("    return new (exports[%s_mapping[type]])(ptr);\n", cls.name.c_st
     r()); | 443       printf("    return new %s_mapping[type](ptr);\n", cls.name.c_str()); | 
| 535       printf("  throw new Error('Unexpected %s type: ' + type);\n", cls.name.c_s
     tr()); | 444       printf("  throw new Error('Unexpected %s type: ' + type);\n", cls.name.c_s
     tr()); | 
| 536       puts("};"); | 445       puts("};"); | 
| 537     } | 446     } | 
| 538     else | 447     else | 
| 539     { | 448     { | 
| 540       printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); | 449       printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); | 
| 541       puts("{"); | 450       puts("{"); | 
| 542       printf("  return new exports.%s(ptr);\n", cls.name.c_str()); | 451       printf("  return new exports.%s(ptr);\n", cls.name.c_str()); | 
| 543       puts("};"); | 452       puts("};"); | 
| 544     } | 453     } | 
| 545 | 454 | 
| 546     for (const auto& method : cls.methods) | 455     for (const auto& method : cls.methods) | 
| 547     { | 456     { | 
| 548       if (!method.call.instance_function) | 457       if (!method.call.instance_function) | 
| 549       { | 458       { | 
| 550         printf("exports.%s.%s = %s;\n", cls.name.c_str(), method.name.c_str(), | 459         printf("exports.%s.%s = %s;\n", cls.name.c_str(), method.name.c_str(), | 
| 551                wrapCall(method.call).c_str()); | 460                wrapCall(method.call).c_str()); | 
| 552       } | 461       } | 
| 553     } | 462     } | 
| 554   } | 463   } | 
| 555 | 464 | 
| 556   void printNamespace(const NamespaceInfo& namespaceInfo) | 465   void printClassMapping(const ClassInfo& cls) | 
| 557   { | 466   { | 
| 558     printf("exports.%s = {\n", namespaceInfo.name.c_str()); | 467       DifferentiatorInfo differentiator = cls.subclass_differentiator; | 
| 559     printProperties(namespaceInfo.properties); | 468       if (differentiator.offset == SIZE_MAX) | 
| 560     printMethods(namespaceInfo.methods, false); | 469         return; | 
| 561     puts("};"); | 470 | 
|  | 471       printf("var %s_mapping = \n", cls.name.c_str()); | 
|  | 472       puts("{"); | 
|  | 473       for (const auto& item : differentiator.mapping) | 
|  | 474         printf("  %i: exports.%s,\n", item.first, item.second.c_str()); | 
|  | 475       puts("};"); | 
| 562   } | 476   } | 
| 563 } | 477 } | 
| 564 | 478 | 
| 565 void printBindings() | 479 void printBindings() | 
| 566 { | 480 { | 
| 567   bindings_internal::printHelpers(); | 481   bindings_internal::printHelpers(); | 
| 568 | 482 | 
| 569   for (const auto& item : classes) | 483   for (const auto& cls : classes) | 
| 570     bindings_internal::printClass(item); | 484     bindings_internal::printClass(cls); | 
| 571   for (const auto& item : namespaces) | 485   for (const auto& cls : classes) | 
| 572     bindings_internal::printNamespace(item); | 486     bindings_internal::printClassMapping(cls); | 
| 573 } | 487 } | 
| LEFT | RIGHT | 
|---|