Left: | ||
Right: |
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-2017 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 "generator.h" | 18 #include "generator.h" |
19 | 19 |
20 #include <cstdio> | 20 #include <cstdio> |
21 | 21 |
22 namespace | 22 namespace |
23 { | 23 { |
24 std::vector<bindings_internal::ClassInfo> classes; | 24 std::vector<bindings_internal::ClassInfo> classes; |
Wladimir Palant
2017/04/12 14:17:00
I found two bad assumptions here which went wrong
sergei
2017/04/18 10:46:09
That's correct, pointers and iterators are invalid
| |
25 std::vector<bindings_internal::CustomGenerator> customGenerators; | |
26 } | 25 } |
27 | 26 |
28 namespace bindings_internal | 27 namespace bindings_internal |
29 { | 28 { |
30 FunctionInfo::FunctionInfo() | 29 FunctionInfo::FunctionInfo() |
31 { | 30 { |
32 name[0] = '\0'; | 31 name[0] = '\0'; |
33 } | 32 } |
34 | 33 |
35 FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType, | 34 FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType, |
36 std::initializer_list<TypeCategory> argTypes, bool instance_function, | 35 std::initializer_list<TypeCategory> argTypes, bool instance_function, |
37 void* function) | 36 void* function) |
38 : returnType(returnType), pointerType(pointerType), | 37 : returnType(returnType), pointerType(pointerType), |
39 instance_function(instance_function) | 38 instance_function(instance_function) |
40 { | 39 { |
41 name[0] = '\0'; | 40 name[0] = '\0'; |
42 | 41 |
43 // The function parameter is a pointer to the function pointer. | 42 // The function parameter is a pointer to the function pointer. |
44 // Emscripten's "function pointers" are actually integers indicating the | 43 // Emscripten's "function pointers" are actually integers indicating the |
45 // position in the call table. 0 represents nullptr. | 44 // position in the call table. 0 represents nullptr. |
46 if (!*reinterpret_cast<int*>(function)) | 45 if (!*reinterpret_cast<int*>(function)) |
47 return; | 46 return; |
48 | 47 |
49 std::string signature; | 48 std::string signature; |
50 if (returnType == TypeCategory::DEPENDENT_STRING || | 49 |
51 returnType == TypeCategory::OWNED_STRING) | 50 // Add return type to the signature. Similar logic in Emscripten: |
52 { | 51 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46 |
53 // Objects aren't really returned but passed as parameter. Note that | 52 switch (returnType) |
54 // this pointer might come before it but we don't care because both | 53 { |
55 // are integers (pointers) as far as Emscripten is concerned. | 54 case TypeCategory::DEPENDENT_STRING: |
56 signature += "vi"; | 55 case TypeCategory::OWNED_STRING: |
57 } | 56 // Technically, objects aren't really returned with clang. The caller |
58 else if (returnType == TypeCategory::VOID) | 57 // instead adds the reference to the resulting object as an implicit |
59 signature += 'v'; | 58 // parameter. |
60 else if (returnType == TypeCategory::FLOAT) | 59 signature += "vi"; |
61 signature += 'd'; | 60 break; |
62 else if (returnType == TypeCategory::INT || | 61 case TypeCategory::VOID: |
63 returnType == TypeCategory::INT64 || | 62 signature += 'v'; |
64 returnType == TypeCategory::STRING_REF || | 63 break; |
65 returnType == TypeCategory::CLASS_PTR) | 64 case TypeCategory::FLOAT: |
66 { | 65 signature += 'f'; |
66 break; | |
67 case TypeCategory::DOUBLE: | |
68 signature += 'd'; | |
69 break; | |
70 case TypeCategory::INT: | |
71 case TypeCategory::INT64: | |
72 case TypeCategory::STRING_REF: | |
73 case TypeCategory::CLASS_PTR: | |
74 signature += 'i'; | |
75 break; | |
76 default: | |
77 throw std::runtime_error("Unexpected function return type"); | |
78 } | |
79 | |
80 // `this` pointer is an implicit parameter with clang and should be added | |
81 // to the signature. | |
82 if (instance_function) | |
67 signature += 'i'; | 83 signature += 'i'; |
68 } | 84 |
69 else | 85 // Add explicit parameters to the signature, Similar logic in Emscripten: |
70 throw std::runtime_error("Unexpected function return type"); | 86 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L67 |
71 | 87 for (const auto& type : argTypes) |
72 if (instance_function) | 88 { |
73 { | 89 switch (type) |
74 // this pointer is an implicit parameter | 90 { |
75 signature += 'i'; | 91 case TypeCategory::INT: |
76 } | 92 case TypeCategory::STRING_REF: |
77 | 93 case TypeCategory::CLASS_PTR: |
78 for (const auto& item : argTypes) | 94 signature += 'i'; |
79 { | 95 break; |
80 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF || | 96 case TypeCategory::INT64: |
81 item == TypeCategory::CLASS_PTR) | 97 // See https://github.com/kripken/emscripten/blob/1.37.3/src/modules.j s#L73, |
82 { | 98 // numerical types larger than 32-bit are split into multiple |
83 signature += 'i'; | 99 // 32-bit parameters. |
84 } | 100 signature += "ii"; |
85 else if (item == TypeCategory::INT64) | 101 break; |
86 signature += "ii"; | 102 case TypeCategory::FLOAT: |
87 else if (item == TypeCategory::FLOAT) | 103 signature += 'f'; |
88 signature += 'd'; | 104 break; |
89 else | 105 case TypeCategory::DOUBLE: |
90 throw std::runtime_error("Unexpected function argument type"); | 106 signature += 'd'; |
91 args.push_back(item); | 107 break; |
108 default: | |
109 throw std::runtime_error("Unexpected function argument type"); | |
110 } | |
111 args.push_back(type); | |
92 } | 112 } |
93 | 113 |
94 get_function_name(function, signature.c_str()); | 114 get_function_name(function, signature.c_str()); |
95 } | 115 } |
96 | 116 |
97 bool FunctionInfo::empty() const | 117 bool FunctionInfo::empty() const |
98 { | 118 { |
99 return name[0] == '\0'; | 119 return name[0] == '\0'; |
100 } | 120 } |
101 | 121 |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
245 std::string call_str(call.name); | 265 std::string call_str(call.name); |
246 call_str += "("; | 266 call_str += "("; |
247 for (int i = 0; i < params.size(); i++) | 267 for (int i = 0; i < params.size(); i++) |
248 { | 268 { |
249 if (i > 0) | 269 if (i > 0) |
250 call_str += ", "; | 270 call_str += ", "; |
251 call_str += params[i]; | 271 call_str += params[i]; |
252 } | 272 } |
253 call_str += ")"; | 273 call_str += ")"; |
254 | 274 |
255 if (call.returnType == TypeCategory::VOID) | 275 switch (call.returnType) |
256 return " " + call_str + ";\n"; | 276 { |
257 else if (call.returnType == TypeCategory::INT || | 277 case TypeCategory::VOID: |
258 call.returnType == TypeCategory::FLOAT) | 278 return " " + call_str + ";\n"; |
259 { | 279 case TypeCategory::INT: |
260 return " var result = " + call_str + ";\n"; | 280 case TypeCategory::FLOAT: |
261 } | 281 case TypeCategory::DOUBLE: |
262 else if (call.returnType == TypeCategory::INT64) | 282 return " var result = " + call_str + ";\n"; |
263 { | 283 case TypeCategory::INT64: |
264 // Emscripten saves the high bits of a 64-bit return value in a special | 284 return " var result = Runtime.makeBigInt(" + call_str + ", " + |
265 // variable called tempRet0. We cannot use bit operators to combine the | 285 "Runtime.getTempRet0(), " + |
266 // values because JavaScript operates on 32-bit integers. | 286 "true);\n"; |
267 return " var result = (" + call_str + " >>> 0)" + | 287 case TypeCategory::DEPENDENT_STRING: |
268 " + (Runtime.getTempRet0() >>> 0) * 0x100000000;\n"; | 288 case TypeCategory::OWNED_STRING: |
269 } | 289 { |
270 else if (call.returnType == TypeCategory::DEPENDENT_STRING || | 290 std::string result; |
271 call.returnType == TypeCategory::OWNED_STRING) | 291 result += " var string = createString();\n"; |
272 { | 292 result += " " + call_str + ";\n"; |
273 std::string result; | 293 result += " var result = readString(string);\n"; |
274 result += " var string = createString();\n"; | 294 if (call.returnType == TypeCategory::OWNED_STRING) |
275 result += " " + call_str + ";\n"; | 295 result += " Module._DestroyString(string);\n"; |
276 result += " var result = readString(string);\n"; | 296 return result; |
277 if (call.returnType == TypeCategory::OWNED_STRING) | 297 } |
278 result += " Module._DestroyString(string);\n"; | 298 case TypeCategory::STRING_REF: |
279 return result; | 299 return " var result = readString(" + call_str + ");\n"; |
280 } | 300 case TypeCategory::CLASS_PTR: |
281 else if (call.returnType == TypeCategory::STRING_REF) | 301 { |
282 { | 302 std::string result; |
283 return " var result = readString(" + call_str + ");\n"; | 303 result += " var result = " + call_str + ";\n"; |
284 } | 304 result += " if (result)\n"; |
285 else if (call.returnType == TypeCategory::CLASS_PTR) | 305 result += " {\n"; |
286 { | 306 |
287 std::string result; | 307 const ClassInfo* cls = find_class(call.pointerType); |
288 result += " var result = " + call_str + ";\n"; | 308 if (!cls) |
289 result += " if (result)\n"; | 309 throw std::runtime_error("Function " + std::string(call.name) + " retu rns pointer to unknown class"); |
290 result += " {\n"; | 310 |
291 | 311 auto offset = cls->subclass_differentiator.offset; |
292 const ClassInfo* cls = find_class(call.pointerType); | 312 if (offset == SIZE_MAX) |
293 if (!cls) | 313 result += " result = exports." + cls->name + "(result);\n"; |
294 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class"); | 314 else |
295 | 315 result += " result = exports." + cls->name + ".fromPointer(result); \n"; |
296 auto offset = cls->subclass_differentiator.offset; | 316 |
297 if (offset == SIZE_MAX) | 317 result += " }\n"; |
298 result += " result = exports." + cls->name + "(result);\n"; | 318 result += " else\n"; |
299 else | 319 result += " result = null;\n"; |
300 result += " result = exports." + cls->name + ".fromPointer(result);\n "; | 320 return result; |
301 | 321 } |
302 result += " }\n"; | 322 default: |
303 result += " else\n"; | 323 throw std::runtime_error("Unexpected return type for " + std::string(cal l.name)); |
304 result += " result = null;\n"; | 324 } |
305 return result; | |
306 } | |
307 else | |
308 throw std::runtime_error("Unexpected return type for " + std::string(call. name)); | |
309 } | 325 } |
310 | 326 |
311 const std::string wrapCall(const FunctionInfo& call) | 327 const std::string wrapCall(const FunctionInfo& call) |
312 { | 328 { |
313 bool hasStringArgs = false; | 329 bool hasStringArgs = false; |
314 std::vector<std::string> params; | 330 std::vector<std::string> params; |
315 std::string prefix = "function("; | 331 std::string prefix = "function("; |
316 for (int i = 0; i < call.args.size(); i++) | 332 for (int i = 0; i < call.args.size(); i++) |
317 { | 333 { |
318 std::string argName("arg" + std::to_string(i)); | 334 std::string argName("arg" + std::to_string(i)); |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
467 } | 483 } |
468 } | 484 } |
469 } | 485 } |
470 | 486 |
471 void printBindings() | 487 void printBindings() |
472 { | 488 { |
473 bindings_internal::printHelpers(); | 489 bindings_internal::printHelpers(); |
474 | 490 |
475 for (const auto& item : classes) | 491 for (const auto& item : classes) |
476 bindings_internal::printClass(item); | 492 bindings_internal::printClass(item); |
477 | |
478 for (const auto& item : customGenerators) | |
479 item(); | |
480 } | 493 } |
481 | |
482 void custom_generator(bindings_internal::CustomGenerator generator) | |
483 { | |
484 customGenerators.push_back(generator); | |
485 } | |
LEFT | RIGHT |