| OLD | NEW |
| 1 #pragma once | 1 #pragma once |
| 2 | 2 |
| 3 #include <cstdint> | 3 #include <cstdint> |
| 4 #include <cstdio> | 4 #include <cstdio> |
| 5 #include <cstdlib> | 5 #include <cstdlib> |
| 6 #include <exception> | 6 #include <exception> |
| 7 #include <map> | 7 #include <map> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <type_traits> | 9 #include <type_traits> |
| 10 #include <utility> | 10 #include <utility> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include <emscripten.h> | 13 #include <emscripten.h> |
| 14 | 14 |
| 15 #include "String.h" | 15 #include "String.h" |
| 16 #include "intrusive_ptr.h" | 16 #include "intrusive_ptr.h" |
| 17 | 17 |
| 18 namespace bindings_internal | 18 namespace bindings_internal |
| 19 { | 19 { |
| 20 typedef void* TYPEID; | 20 typedef void* TYPEID; |
| 21 | 21 |
| 22 enum class TypeCategory | 22 enum class TypeCategory |
| 23 { | 23 { |
| 24 UNKNOWN, | 24 UNKNOWN, |
| 25 VOID, | 25 VOID, |
| 26 INT, | 26 INT, |
| 27 FLOAT, |
| 27 DEPENDENT_STRING, | 28 DEPENDENT_STRING, |
| 28 OWNED_STRING, | 29 OWNED_STRING, |
| 29 STRING_REF, | 30 STRING_REF, |
| 30 CLASS_PTR | 31 CLASS_PTR |
| 31 }; | 32 }; |
| 32 | 33 |
| 33 template<typename T> | 34 template<typename T> |
| 34 struct TypeInfo | 35 struct TypeInfo |
| 35 { | 36 { |
| 36 /* | 37 /* |
| (...skipping 11 matching lines...) Expand all Loading... |
| 48 } | 49 } |
| 49 | 50 |
| 50 constexpr operator TypeCategory() const | 51 constexpr operator TypeCategory() const |
| 51 { | 52 { |
| 52 if (std::is_void<T>()) | 53 if (std::is_void<T>()) |
| 53 return TypeCategory::VOID; | 54 return TypeCategory::VOID; |
| 54 | 55 |
| 55 if (std::is_integral<T>() || std::is_enum<T>()) | 56 if (std::is_integral<T>() || std::is_enum<T>()) |
| 56 return TypeCategory::INT; | 57 return TypeCategory::INT; |
| 57 | 58 |
| 59 if (std::is_floating_point<T>()) |
| 60 return TypeCategory::FLOAT; |
| 61 |
| 58 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri
ng, T>()) | 62 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri
ng, T>()) |
| 59 return TypeCategory::DEPENDENT_STRING; | 63 return TypeCategory::DEPENDENT_STRING; |
| 60 | 64 |
| 61 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>()
) | 65 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>()
) |
| 62 return TypeCategory::OWNED_STRING; | 66 return TypeCategory::OWNED_STRING; |
| 63 | 67 |
| 64 if (std::is_same<String&, T>() || std::is_same<const String&, T>() || | 68 if (std::is_same<String&, T>() || std::is_same<const String&, T>() || |
| 65 std::is_same<DependentString&, T>()) | 69 std::is_same<DependentString&, T>()) |
| 66 { | 70 { |
| 67 return TypeCategory::STRING_REF; | 71 return TypeCategory::STRING_REF; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 instance_function(instance_function) | 111 instance_function(instance_function) |
| 108 { | 112 { |
| 109 name[0] = '\0'; | 113 name[0] = '\0'; |
| 110 | 114 |
| 111 // The function parameter is a pointer to the function pointer. | 115 // The function parameter is a pointer to the function pointer. |
| 112 // Emscripten's "function pointers" are actually integers indicating the | 116 // Emscripten's "function pointers" are actually integers indicating the |
| 113 // position in the call table. 0 represents nullptr. | 117 // position in the call table. 0 represents nullptr. |
| 114 if (!*reinterpret_cast<int*>(function)) | 118 if (!*reinterpret_cast<int*>(function)) |
| 115 return; | 119 return; |
| 116 | 120 |
| 121 char signature[256]; |
| 122 int pos = 0; |
| 123 if (returnType == TypeCategory::DEPENDENT_STRING || |
| 124 returnType == TypeCategory::OWNED_STRING) |
| 125 { |
| 126 // Objects aren't really returned but passed as parameter. Note that |
| 127 // this pointer might come before it but we don't care because both |
| 128 // are integers (pointers) as far as Emscripten is concerned. |
| 129 signature[pos++] = 'v'; |
| 130 signature[pos++] = 'i'; |
| 131 } |
| 132 else if (returnType == TypeCategory::VOID) |
| 133 signature[pos++] = 'v'; |
| 134 else if (returnType == TypeCategory::FLOAT) |
| 135 signature[pos++] = 'd'; |
| 136 else if (returnType == TypeCategory::INT || |
| 137 returnType == TypeCategory::STRING_REF || |
| 138 returnType == TypeCategory::CLASS_PTR) |
| 139 { |
| 140 signature[pos++] = 'i'; |
| 141 } |
| 142 else |
| 143 throw std::runtime_error("Unexpected function return type"); |
| 144 |
| 145 if (instance_function) |
| 146 { |
| 147 // this pointer is an implicit parameter |
| 148 signature[pos++] = 'i'; |
| 149 } |
| 150 |
| 117 for (const auto& item : argTypes) | 151 for (const auto& item : argTypes) |
| 118 { | 152 { |
| 119 if (item != TypeCategory::INT && item != TypeCategory::STRING_REF && | 153 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF || |
| 120 item != TypeCategory::CLASS_PTR) | 154 item == TypeCategory::CLASS_PTR) |
| 121 { | 155 { |
| 156 signature[pos++] = 'i'; |
| 157 } |
| 158 else if (item == TypeCategory::FLOAT) |
| 159 signature[pos++] = 'd'; |
| 160 else |
| 122 throw std::runtime_error("Unexpected function argument type"); | 161 throw std::runtime_error("Unexpected function argument type"); |
| 123 } | |
| 124 args.push_back(item); | 162 args.push_back(item); |
| 125 } | 163 } |
| 126 | 164 |
| 127 if (returnType != TypeCategory::VOID && returnType != TypeCategory::INT && | 165 signature[pos] = 0; |
| 128 returnType != TypeCategory::DEPENDENT_STRING && | |
| 129 returnType != TypeCategory::OWNED_STRING && | |
| 130 returnType != TypeCategory::STRING_REF && | |
| 131 returnType != TypeCategory::CLASS_PTR) | |
| 132 { | |
| 133 throw std::runtime_error("Unexpected function return type"); | |
| 134 } | |
| 135 | 166 |
| 136 effectiveArgs = args.size(); | 167 get_function_name(function, signature); |
| 137 effectiveReturnType = returnType; | |
| 138 if (instance_function) | |
| 139 effectiveArgs++; | |
| 140 | |
| 141 if (returnType == TypeCategory::DEPENDENT_STRING || | |
| 142 returnType == TypeCategory::OWNED_STRING) | |
| 143 { | |
| 144 effectiveArgs++; | |
| 145 effectiveReturnType = TypeCategory::VOID; | |
| 146 } | |
| 147 | |
| 148 get_function_name(function, effectiveArgs, | |
| 149 effectiveReturnType == TypeCategory::VOID); | |
| 150 } | 168 } |
| 151 | 169 |
| 152 template<typename ReturnType, typename... Args> | 170 template<typename ReturnType, typename... Args> |
| 153 FunctionInfo(ReturnType (*function)(Args...)) | 171 FunctionInfo(ReturnType (*function)(Args...)) |
| 154 : FunctionInfo(TypeInfo<ReturnType>(), | 172 : FunctionInfo(TypeInfo<ReturnType>(), |
| 155 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, | 173 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, |
| 156 &function) | 174 &function) |
| 157 { | 175 { |
| 158 } | 176 } |
| 159 | 177 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 171 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, | 189 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, |
| 172 &function) | 190 &function) |
| 173 { | 191 { |
| 174 } | 192 } |
| 175 | 193 |
| 176 bool empty() const | 194 bool empty() const |
| 177 { | 195 { |
| 178 return name[0] == '\0'; | 196 return name[0] == '\0'; |
| 179 } | 197 } |
| 180 | 198 |
| 181 void get_function_name(void* ptr, int numArgs, bool voidResult) | 199 void get_function_name(void* ptr, char* signature) |
| 182 { | 200 { |
| 183 // This is a hack, C++ won't let us get the mangled function name. | 201 // This is a hack, C++ won't let us get the mangled function name. |
| 184 // JavaScript is more dynamic so we pass the pointer to our function | 202 // JavaScript is more dynamic so we pass the pointer to our function |
| 185 // there. With that and the function signature we can call the function - | 203 // there. With that and the function signature we can call the function - |
| 186 // with a full stack so that we will cause it to abort. Sometimes the | 204 // with a full stack so that we will cause it to abort. Sometimes the |
| 187 // function we are calling will also be missing from the build. The result | 205 // function we are calling will also be missing from the build. The result |
| 188 // is the same: abort() is called which in turn calls stackTrace(). By | 206 // is the same: abort() is called which in turn calls stackTrace(). By |
| 189 // replacing stackTrace() we get access to the call stack and search it | 207 // replacing stackTrace() we get access to the call stack and search it |
| 190 // for the name of our function. | 208 // for the name of our function. |
| 191 | 209 |
| 192 EM_ASM_ARGS({ | 210 EM_ASM_ARGS({ |
| 193 var signature = $3 ? "v" : "i"; | 211 var signature = AsciiToString($2); |
| 194 var args = []; | 212 var args = []; |
| 195 for (var i = 0; i < $2; i++) | 213 for (var i = 1; i < signature.length; i++) |
| 196 { | |
| 197 signature += "i"; | |
| 198 args.push(0); | 214 args.push(0); |
| 199 } | |
| 200 | 215 |
| 201 var oldPrint = Module.print; | 216 var oldPrint = Module.print; |
| 202 var oldPrintErr = Module.printErr; | 217 var oldPrintErr = Module.printErr; |
| 203 var oldStackTrace = stackTrace; | 218 var oldStackTrace = stackTrace; |
| 204 var sp = Runtime.stackSave(); | 219 var sp = Runtime.stackSave(); |
| 205 Module.print = function(){}; | 220 Module.print = function(){}; |
| 206 Module.printErr = function(){}; | 221 Module.printErr = function(){}; |
| 207 stackTrace = function() | 222 stackTrace = function() |
| 208 { | 223 { |
| 209 var stack = []; | 224 var stack = []; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 234 { | 249 { |
| 235 Module.stringToAscii(e, $0); | 250 Module.stringToAscii(e, $0); |
| 236 } | 251 } |
| 237 finally | 252 finally |
| 238 { | 253 { |
| 239 Runtime.stackRestore(sp); | 254 Runtime.stackRestore(sp); |
| 240 Module.print = oldPrint; | 255 Module.print = oldPrint; |
| 241 Module.printErr = oldPrintErr; | 256 Module.printErr = oldPrintErr; |
| 242 stackTrace = oldStackTrace; | 257 stackTrace = oldStackTrace; |
| 243 } | 258 } |
| 244 }, name, ptr, numArgs, voidResult); | 259 }, name, ptr, signature); |
| 245 } | 260 } |
| 246 }; | 261 }; |
| 247 | 262 |
| 248 class NoBaseClass | 263 class NoBaseClass |
| 249 { | 264 { |
| 250 }; | 265 }; |
| 251 | 266 |
| 252 struct PropertyInfo | 267 struct PropertyInfo |
| 253 { | 268 { |
| 254 std::string name; | 269 std::string name; |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 for (int i = 0; i < params.size(); i++) | 389 for (int i = 0; i < params.size(); i++) |
| 375 { | 390 { |
| 376 if (i > 0) | 391 if (i > 0) |
| 377 call_str += ", "; | 392 call_str += ", "; |
| 378 call_str += params[i]; | 393 call_str += params[i]; |
| 379 } | 394 } |
| 380 call_str += ")"; | 395 call_str += ")"; |
| 381 | 396 |
| 382 if (call.returnType == TypeCategory::VOID) | 397 if (call.returnType == TypeCategory::VOID) |
| 383 return " " + call_str + ";\n"; | 398 return " " + call_str + ";\n"; |
| 384 else if (call.returnType == TypeCategory::INT) | 399 else if (call.returnType == TypeCategory::INT || |
| 400 call.returnType == TypeCategory::FLOAT) |
| 401 { |
| 385 return " var result = " + call_str + ";\n"; | 402 return " var result = " + call_str + ";\n"; |
| 403 } |
| 386 else if (call.returnType == TypeCategory::DEPENDENT_STRING || | 404 else if (call.returnType == TypeCategory::DEPENDENT_STRING || |
| 387 call.returnType == TypeCategory::OWNED_STRING) | 405 call.returnType == TypeCategory::OWNED_STRING) |
| 388 { | 406 { |
| 389 std::string result; | 407 std::string result; |
| 390 result += " var string = createString();\n"; | 408 result += " var string = createString();\n"; |
| 391 result += " " + call_str + ";\n"; | 409 result += " " + call_str + ";\n"; |
| 392 result += " var result = readString(string);\n"; | 410 result += " var result = readString(string);\n"; |
| 393 if (call.returnType == TypeCategory::OWNED_STRING) | 411 if (call.returnType == TypeCategory::OWNED_STRING) |
| 394 result += " Module._DestroyString(string);\n"; | 412 result += " Module._DestroyString(string);\n"; |
| 395 return result; | 413 return result; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 sprintf(buffer, "arg%i", i); | 458 sprintf(buffer, "arg%i", i); |
| 441 if (i > 0) | 459 if (i > 0) |
| 442 prefix += ", "; | 460 prefix += ", "; |
| 443 prefix += buffer; | 461 prefix += buffer; |
| 444 | 462 |
| 445 if (call.args[i] == TypeCategory::STRING_REF) | 463 if (call.args[i] == TypeCategory::STRING_REF) |
| 446 { | 464 { |
| 447 hasStringArgs = true; | 465 hasStringArgs = true; |
| 448 params.push_back(std::string("createString(") + buffer + ")"); | 466 params.push_back(std::string("createString(") + buffer + ")"); |
| 449 } | 467 } |
| 468 else if (call.args[i] == TypeCategory::CLASS_PTR) |
| 469 params.push_back(std::string(buffer) + "._pointer"); |
| 450 else | 470 else |
| 451 params.push_back(buffer); | 471 params.push_back(buffer); |
| 452 } | 472 } |
| 453 prefix += ")\n{\n"; | 473 prefix += ")\n{\n"; |
| 454 | 474 |
| 455 std::string suffix = "}"; | 475 std::string suffix = "}"; |
| 456 if (call.returnType != TypeCategory::VOID) | 476 if (call.returnType != TypeCategory::VOID) |
| 457 suffix = " return result;\n" + suffix; | 477 suffix = " return result;\n" + suffix; |
| 458 | 478 |
| 459 if (call.returnType == TypeCategory::DEPENDENT_STRING || | 479 if (call.returnType == TypeCategory::DEPENDENT_STRING || |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 718 | 738 |
| 719 std::vector<std::pair<int, std::string>> mapping; | 739 std::vector<std::pair<int, std::string>> mapping; |
| 720 for (const auto& item : list) | 740 for (const auto& item : list) |
| 721 mapping.emplace_back(item.first, item.second); | 741 mapping.emplace_back(item.first, item.second); |
| 722 | 742 |
| 723 bindings_internal::register_differentiator( | 743 bindings_internal::register_differentiator( |
| 724 bindings_internal::TypeInfo<ClassType>(), offset, mapping); | 744 bindings_internal::TypeInfo<ClassType>(), offset, mapping); |
| 725 return *this; | 745 return *this; |
| 726 } | 746 } |
| 727 }; | 747 }; |
| OLD | NEW |