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 |