| 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 |