Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: compiled/bindings/generator.cpp

Issue 29410617: Issue 5131 - [emscripten] Clean separation of bindings code and runtime code (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Left Patch Set: Created April 12, 2017, 2:07 p.m.
Right Patch Set: Rebased Created April 20, 2017, 1:49 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
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
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
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 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld