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

Side by Side Diff: compiled/bindings.ipp

Issue 29384812: Issue 4127 - [emscripten] Convert subscription classes to C++ - Part 1 (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Patch Set: Addressed comments Created April 13, 2017, 1:02 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « compiled/bindings.cpp ('k') | compiled/filter/Filter.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
(...skipping 24 matching lines...) Expand all
35 35
36 namespace bindings_internal 36 namespace bindings_internal
37 { 37 {
38 typedef void* TYPEID; 38 typedef void* TYPEID;
39 39
40 enum class TypeCategory 40 enum class TypeCategory
41 { 41 {
42 UNKNOWN, 42 UNKNOWN,
43 VOID, 43 VOID,
44 INT, 44 INT,
45 INT64,
46 FLOAT,
47 DOUBLE,
45 DEPENDENT_STRING, 48 DEPENDENT_STRING,
46 OWNED_STRING, 49 OWNED_STRING,
47 STRING_REF, 50 STRING_REF,
48 CLASS_PTR 51 CLASS_PTR
49 }; 52 };
50 53
51 template<typename T> 54 template<typename T>
52 struct TypeInfo 55 struct TypeInfo
53 { 56 {
54 /* 57 /*
55 * Since TypeInfo is a templated type, in practice the compiler will define 58 * Since TypeInfo is a templated type, in practice the compiler will define
56 * a new type for each possible template parameter value. We use that fact 59 * a new type for each possible template parameter value. We use that fact
57 * to generate type identifiers: each of these TypeInfo types has a 60 * to generate type identifiers: each of these TypeInfo types has a
58 * different s_typeIDHelper member, so we use a pointer to that static 61 * different s_typeIDHelper member, so we use a pointer to that static
59 * variable as a type identifier - it will be different for each template 62 * variable as a type identifier - it will be different for each template
60 * parameter. 63 * parameter.
61 */ 64 */
62 static char s_typeIDHelper; 65 static char s_typeIDHelper;
63 constexpr operator TYPEID() const 66 constexpr operator TYPEID() const
64 { 67 {
65 return &s_typeIDHelper; 68 return &s_typeIDHelper;
66 } 69 }
67 70
68 constexpr operator TypeCategory() const 71 constexpr operator TypeCategory() const
69 { 72 {
70 if (std::is_void<T>()) 73 if (std::is_void<T>())
71 return TypeCategory::VOID; 74 return TypeCategory::VOID;
72 75
76 if (std::is_same<T, uint64_t>())
77 return TypeCategory::INT64;
78
73 if (std::is_integral<T>() || std::is_enum<T>()) 79 if (std::is_integral<T>() || std::is_enum<T>())
74 return TypeCategory::INT; 80 return TypeCategory::INT;
75 81
82 if (std::is_same<T, float>())
83 return TypeCategory::FLOAT;
84
85 if (std::is_same<T, double>())
86 return TypeCategory::DOUBLE;
87
76 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>()) 88 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>())
77 return TypeCategory::DEPENDENT_STRING; 89 return TypeCategory::DEPENDENT_STRING;
78 90
79 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() ) 91 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() )
80 return TypeCategory::OWNED_STRING; 92 return TypeCategory::OWNED_STRING;
81 93
82 if (std::is_same<String&, T>() || std::is_same<const String&, T>() || 94 if (std::is_same<String&, T>() || std::is_same<const String&, T>() ||
83 std::is_same<DependentString&, T>()) 95 std::is_same<DependentString&, T>())
84 { 96 {
85 return TypeCategory::STRING_REF; 97 return TypeCategory::STRING_REF;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 instance_function(instance_function) 137 instance_function(instance_function)
126 { 138 {
127 name[0] = '\0'; 139 name[0] = '\0';
128 140
129 // The function parameter is a pointer to the function pointer. 141 // The function parameter is a pointer to the function pointer.
130 // Emscripten's "function pointers" are actually integers indicating the 142 // Emscripten's "function pointers" are actually integers indicating the
131 // position in the call table. 0 represents nullptr. 143 // position in the call table. 0 represents nullptr.
132 if (!*reinterpret_cast<int*>(function)) 144 if (!*reinterpret_cast<int*>(function))
133 return; 145 return;
134 146
135 for (const auto& item : argTypes) 147 std::string signature;
148
149 // Add return type to the signature. Similar logic in Emscripten:
150 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46
151 switch (returnType)
136 { 152 {
137 if (item != TypeCategory::INT && item != TypeCategory::STRING_REF && 153 case TypeCategory::DEPENDENT_STRING:
138 item != TypeCategory::CLASS_PTR) 154 case TypeCategory::OWNED_STRING:
139 { 155 // Technically, objects aren't really returned with clang. The caller
140 throw std::runtime_error("Unexpected function argument type"); 156 // instead adds the reference to the resulting object as an implicit
141 } 157 // parameter.
142 args.push_back(item); 158 signature += "vi";
159 break;
160 case TypeCategory::VOID:
161 signature += 'v';
162 break;
163 case TypeCategory::FLOAT:
164 signature += 'f';
165 break;
166 case TypeCategory::DOUBLE:
167 signature += 'd';
168 break;
169 case TypeCategory::INT:
170 case TypeCategory::INT64:
171 case TypeCategory::STRING_REF:
172 case TypeCategory::CLASS_PTR:
173 signature += 'i';
174 break;
175 default:
176 throw std::runtime_error("Unexpected function return type");
143 } 177 }
144 178
145 if (returnType != TypeCategory::VOID && returnType != TypeCategory::INT && 179 // `this` pointer is an implicit parameter with clang and should be added
146 returnType != TypeCategory::DEPENDENT_STRING && 180 // to the signature.
147 returnType != TypeCategory::OWNED_STRING && 181 if (instance_function)
148 returnType != TypeCategory::STRING_REF && 182 signature += 'i';
149 returnType != TypeCategory::CLASS_PTR) 183
184 // Add explicit parameters to the signature, Similar logic in Emscripten:
185 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L67
186 for (const auto& type : argTypes)
150 { 187 {
151 throw std::runtime_error("Unexpected function return type"); 188 switch (type)
189 {
190 case TypeCategory::INT:
191 case TypeCategory::STRING_REF:
192 case TypeCategory::CLASS_PTR:
193 signature += 'i';
194 break;
195 case TypeCategory::INT64:
196 // See https://github.com/kripken/emscripten/blob/1.37.3/src/modules .js#L73,
197 // numerical types larger than 32-bit are split into multiple
198 // 32-bit parameters.
199 signature += "ii";
200 break;
201 case TypeCategory::FLOAT:
202 signature += 'f';
203 break;
204 case TypeCategory::DOUBLE:
205 signature += 'd';
206 break;
207 default:
208 throw std::runtime_error("Unexpected function argument type");
209 }
210 args.push_back(type);
152 } 211 }
153 212
154 effectiveArgs = args.size(); 213 get_function_name(function, signature.c_str());
155 effectiveReturnType = returnType;
156 if (instance_function)
157 effectiveArgs++;
158
159 if (returnType == TypeCategory::DEPENDENT_STRING ||
160 returnType == TypeCategory::OWNED_STRING)
161 {
162 effectiveArgs++;
163 effectiveReturnType = TypeCategory::VOID;
164 }
165
166 get_function_name(function, effectiveArgs,
167 effectiveReturnType == TypeCategory::VOID);
168 } 214 }
169 215
170 template<typename ReturnType, typename... Args> 216 template<typename ReturnType, typename... Args>
171 FunctionInfo(ReturnType (*function)(Args...)) 217 FunctionInfo(ReturnType (*function)(Args...))
172 : FunctionInfo(TypeInfo<ReturnType>(), 218 : FunctionInfo(TypeInfo<ReturnType>(),
173 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, 219 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false,
174 &function) 220 &function)
175 { 221 {
176 } 222 }
177 223
(...skipping 11 matching lines...) Expand all
189 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, 235 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true,
190 &function) 236 &function)
191 { 237 {
192 } 238 }
193 239
194 bool empty() const 240 bool empty() const
195 { 241 {
196 return name[0] == '\0'; 242 return name[0] == '\0';
197 } 243 }
198 244
199 void get_function_name(void* ptr, int numArgs, bool voidResult) 245 void get_function_name(void* ptr, const char* signature)
200 { 246 {
201 // This is a hack, C++ won't let us get the mangled function name. 247 // This is a hack, C++ won't let us get the mangled function name.
202 // JavaScript is more dynamic so we pass the pointer to our function 248 // JavaScript is more dynamic so we pass the pointer to our function
203 // there. With that and the function signature we can call the function - 249 // there. With that and the function signature we can call the function -
204 // with a full stack so that we will cause it to abort. Sometimes the 250 // with a full stack so that we will cause it to abort. Sometimes the
205 // function we are calling will also be missing from the build. The result 251 // function we are calling will also be missing from the build. The result
206 // is the same: abort() is called which in turn calls stackTrace(). By 252 // is the same: abort() is called which in turn calls stackTrace(). By
207 // replacing stackTrace() we get access to the call stack and search it 253 // replacing stackTrace() we get access to the call stack and search it
208 // for the name of our function. 254 // for the name of our function.
209 255
210 EM_ASM_ARGS({ 256 EM_ASM_ARGS({
211 var signature = $3 ? "v" : "i"; 257 var signature = AsciiToString($2);
212 var args = []; 258 var args = [];
213 for (var i = 0; i < $2; i++) 259 for (var i = 1; i < signature.length; i++)
214 {
215 signature += "i";
216 args.push(0); 260 args.push(0);
217 }
218 261
219 var oldPrint = Module.print; 262 var oldPrint = Module.print;
220 var oldPrintErr = Module.printErr; 263 var oldPrintErr = Module.printErr;
221 var oldStackTrace = stackTrace; 264 var oldStackTrace = stackTrace;
222 var sp = Runtime.stackSave(); 265 var sp = Runtime.stackSave();
223 Module.print = function(){}; 266 Module.print = function(){};
224 Module.printErr = function(){}; 267 Module.printErr = function(){};
225 stackTrace = function() 268 stackTrace = function()
226 { 269 {
227 var stack = []; 270 var stack = [];
(...skipping 24 matching lines...) Expand all
252 { 295 {
253 Module.stringToAscii(e, $0); 296 Module.stringToAscii(e, $0);
254 } 297 }
255 finally 298 finally
256 { 299 {
257 Runtime.stackRestore(sp); 300 Runtime.stackRestore(sp);
258 Module.print = oldPrint; 301 Module.print = oldPrint;
259 Module.printErr = oldPrintErr; 302 Module.printErr = oldPrintErr;
260 stackTrace = oldStackTrace; 303 stackTrace = oldStackTrace;
261 } 304 }
262 }, name, ptr, numArgs, voidResult); 305 }, name, ptr, signature);
263 } 306 }
264 }; 307 };
265 308
266 class NoBaseClass 309 class NoBaseClass
267 { 310 {
268 }; 311 };
269 312
270 struct PropertyInfo 313 struct PropertyInfo
271 { 314 {
272 std::string name; 315 std::string name;
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 std::string call_str(call.name); 433 std::string call_str(call.name);
391 call_str += "("; 434 call_str += "(";
392 for (int i = 0; i < params.size(); i++) 435 for (int i = 0; i < params.size(); i++)
393 { 436 {
394 if (i > 0) 437 if (i > 0)
395 call_str += ", "; 438 call_str += ", ";
396 call_str += params[i]; 439 call_str += params[i];
397 } 440 }
398 call_str += ")"; 441 call_str += ")";
399 442
400 if (call.returnType == TypeCategory::VOID) 443 switch (call.returnType)
401 return " " + call_str + ";\n";
402 else if (call.returnType == TypeCategory::INT)
403 return " var result = " + call_str + ";\n";
404 else if (call.returnType == TypeCategory::DEPENDENT_STRING ||
405 call.returnType == TypeCategory::OWNED_STRING)
406 { 444 {
407 std::string result; 445 case TypeCategory::VOID:
408 result += " var string = createString();\n"; 446 return " " + call_str + ";\n";
409 result += " " + call_str + ";\n"; 447 case TypeCategory::INT:
410 result += " var result = readString(string);\n"; 448 case TypeCategory::FLOAT:
411 if (call.returnType == TypeCategory::OWNED_STRING) 449 case TypeCategory::DOUBLE:
412 result += " Module._DestroyString(string);\n"; 450 return " var result = " + call_str + ";\n";
413 return result; 451 case TypeCategory::INT64:
452 return " var result = Runtime.makeBigInt(" + call_str + ", " +
453 "Runtime.getTempRet0(), " +
454 "true);\n";
455 case TypeCategory::DEPENDENT_STRING:
456 case TypeCategory::OWNED_STRING:
457 {
458 std::string result;
459 result += " var string = createString();\n";
460 result += " " + call_str + ";\n";
461 result += " var result = readString(string);\n";
462 if (call.returnType == TypeCategory::OWNED_STRING)
463 result += " Module._DestroyString(string);\n";
464 return result;
465 }
466 case TypeCategory::STRING_REF:
467 return " var result = readString(" + call_str + ");\n";
468 case TypeCategory::CLASS_PTR:
469 {
470 std::string result;
471 result += " var result = " + call_str + ";\n";
472 result += " if (result)\n";
473 result += " {\n";
474
475 auto it = classes.find(call.pointerType);
476 if (it == classes.end())
477 throw std::runtime_error("Function " + std::string(call.name) + " retu rns pointer to unknown class");
478
479 const ClassInfo& cls = it->second;
480 auto offset = cls.subclass_differentiator.offset;
481 if (offset == SIZE_MAX)
482 result += " result = " + cls.name + "(result);\n";
483 else
484 {
485 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n";
486 result += " if (type in " + cls.name + "_mapping)\n";
487 result += " result = new (exports[" + cls.name + "_mapping[type]] )(result);\n";
488 result += " else\n";
489 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n";
490 }
491
492 result += " }\n";
493 return result;
494 }
495 default:
496 throw std::runtime_error("Unexpected return type for " + std::string(cal l.name));
414 } 497 }
415 else if (call.returnType == TypeCategory::STRING_REF)
416 {
417 return " var result = readString(" + call_str + ");\n";
418 }
419 else if (call.returnType == TypeCategory::CLASS_PTR)
420 {
421 std::string result;
422 result += " var result = " + call_str + ";\n";
423 result += " if (result)\n";
424 result += " {\n";
425
426 auto it = classes.find(call.pointerType);
427 if (it == classes.end())
428 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class");
429
430 const ClassInfo& cls = it->second;
431 auto offset = cls.subclass_differentiator.offset;
432 if (offset == SIZE_MAX)
433 result += " result = " + cls.name + "(result);\n";
434 else
435 {
436 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n";
437 result += " if (type in " + cls.name + "_mapping)\n";
438 result += " result = new (exports[" + cls.name + "_mapping[type]])( result);\n";
439 result += " else\n";
440 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n";
441 }
442
443 result += " }\n";
444 return result;
445 }
446 else
447 throw std::runtime_error("Unexpected return type for " + std::string(call. name));
448 } 498 }
449 499
450 const std::string wrapCall(const FunctionInfo& call) 500 const std::string wrapCall(const FunctionInfo& call)
451 { 501 {
452 bool hasStringArgs = false; 502 bool hasStringArgs = false;
453 std::vector<std::string> params; 503 std::vector<std::string> params;
454 std::string prefix = "function("; 504 std::string prefix = "function(";
455 for (int i = 0; i < call.args.size(); i++) 505 for (int i = 0; i < call.args.size(); i++)
456 { 506 {
457 std::string argName("arg" + std::to_string(i)); 507 std::string argName("arg" + std::to_string(i));
458 if (i > 0) 508 if (i > 0)
459 prefix += ", "; 509 prefix += ", ";
460 prefix += argName; 510 prefix += argName;
461 511
462 if (call.args[i] == TypeCategory::STRING_REF) 512 if (call.args[i] == TypeCategory::STRING_REF)
463 { 513 {
464 hasStringArgs = true; 514 hasStringArgs = true;
465 params.push_back(std::string("createString(") + argName + ")"); 515 params.push_back(std::string("createString(") + argName + ")");
466 } 516 }
517 else if (call.args[i] == TypeCategory::CLASS_PTR)
518 params.push_back(argName + "._pointer");
519 else if (call.args[i] == TypeCategory::INT64)
520 {
521 // 64-bit integers are passed as two integer parameters
522 params.push_back(argName + " >>> 0");
523 params.push_back(argName + " / 0x100000000 >>> 0");
524 }
467 else 525 else
468 params.push_back(argName); 526 params.push_back(argName);
469 } 527 }
470 prefix += ")\n{\n"; 528 prefix += ")\n{\n";
471 529
472 std::string suffix = "}"; 530 std::string suffix = "}";
473 if (call.returnType != TypeCategory::VOID) 531 if (call.returnType != TypeCategory::VOID)
474 suffix = " return result;\n" + suffix; 532 suffix = " return result;\n" + suffix;
475 533
476 if (call.returnType == TypeCategory::DEPENDENT_STRING || 534 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 793
736 std::vector<std::pair<int, std::string>> mapping; 794 std::vector<std::pair<int, std::string>> mapping;
737 for (const auto& item : list) 795 for (const auto& item : list)
738 mapping.emplace_back(item.first, item.second); 796 mapping.emplace_back(item.first, item.second);
739 797
740 bindings_internal::register_differentiator( 798 bindings_internal::register_differentiator(
741 bindings_internal::TypeInfo<ClassType>(), offset, mapping); 799 bindings_internal::TypeInfo<ClassType>(), offset, mapping);
742 return *this; 800 return *this;
743 } 801 }
744 }; 802 };
OLDNEW
« no previous file with comments | « compiled/bindings.cpp ('k') | compiled/filter/Filter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld