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

Delta Between Two Patch Sets: compiled/bindings.ipp

Issue 29384812: Issue 4127 - [emscripten] Convert subscription classes to C++ - Part 1 (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Left Patch Set: Safe buffer manipulation Created April 4, 2017, 2:45 p.m.
Right 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « compiled/bindings.cpp ('k') | compiled/filter/Filter.h » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
(...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,
45 FLOAT, 46 FLOAT,
47 DOUBLE,
46 DEPENDENT_STRING, 48 DEPENDENT_STRING,
47 OWNED_STRING, 49 OWNED_STRING,
48 STRING_REF, 50 STRING_REF,
49 CLASS_PTR 51 CLASS_PTR
50 }; 52 };
51 53
52 template<typename T> 54 template<typename T>
53 struct TypeInfo 55 struct TypeInfo
54 { 56 {
55 /* 57 /*
56 * 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
57 * 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
58 * to generate type identifiers: each of these TypeInfo types has a 60 * to generate type identifiers: each of these TypeInfo types has a
59 * 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
60 * 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
61 * parameter. 63 * parameter.
62 */ 64 */
63 static char s_typeIDHelper; 65 static char s_typeIDHelper;
64 constexpr operator TYPEID() const 66 constexpr operator TYPEID() const
65 { 67 {
66 return &s_typeIDHelper; 68 return &s_typeIDHelper;
67 } 69 }
68 70
69 constexpr operator TypeCategory() const 71 constexpr operator TypeCategory() const
70 { 72 {
71 if (std::is_void<T>()) 73 if (std::is_void<T>())
72 return TypeCategory::VOID; 74 return TypeCategory::VOID;
73 75
76 if (std::is_same<T, uint64_t>())
77 return TypeCategory::INT64;
78
74 if (std::is_integral<T>() || std::is_enum<T>()) 79 if (std::is_integral<T>() || std::is_enum<T>())
75 return TypeCategory::INT; 80 return TypeCategory::INT;
76 81
77 if (std::is_floating_point<T>()) 82 if (std::is_same<T, float>())
78 return TypeCategory::FLOAT; 83 return TypeCategory::FLOAT;
84
85 if (std::is_same<T, double>())
86 return TypeCategory::DOUBLE;
79 87
80 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>())
81 return TypeCategory::DEPENDENT_STRING; 89 return TypeCategory::DEPENDENT_STRING;
82 90
83 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>() )
84 return TypeCategory::OWNED_STRING; 92 return TypeCategory::OWNED_STRING;
85 93
86 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>() ||
87 std::is_same<DependentString&, T>()) 95 std::is_same<DependentString&, T>())
88 { 96 {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 instance_function(instance_function) 137 instance_function(instance_function)
130 { 138 {
131 name[0] = '\0'; 139 name[0] = '\0';
132 140
133 // The function parameter is a pointer to the function pointer. 141 // The function parameter is a pointer to the function pointer.
134 // Emscripten's "function pointers" are actually integers indicating the 142 // Emscripten's "function pointers" are actually integers indicating the
135 // position in the call table. 0 represents nullptr. 143 // position in the call table. 0 represents nullptr.
136 if (!*reinterpret_cast<int*>(function)) 144 if (!*reinterpret_cast<int*>(function))
137 return; 145 return;
138 146
139 char signature[256]; 147 std::string signature;
140 int pos = 0; 148
141 if (returnType == TypeCategory::DEPENDENT_STRING || 149 // Add return type to the signature. Similar logic in Emscripten:
142 returnType == TypeCategory::OWNED_STRING) 150 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46
143 { 151 switch (returnType)
144 // Objects aren't really returned but passed as parameter. Note that 152 {
145 // this pointer might come before it but we don't care because both 153 case TypeCategory::DEPENDENT_STRING:
146 // are integers (pointers) as far as Emscripten is concerned. 154 case TypeCategory::OWNED_STRING:
147 signature[pos++] = 'v'; 155 // Technically, objects aren't really returned with clang. The caller
148 signature[pos++] = 'i'; 156 // instead adds the reference to the resulting object as an implicit
149 } 157 // parameter.
150 else if (returnType == TypeCategory::VOID) 158 signature += "vi";
151 signature[pos++] = 'v'; 159 break;
152 else if (returnType == TypeCategory::FLOAT) 160 case TypeCategory::VOID:
153 signature[pos++] = 'd'; 161 signature += 'v';
154 else if (returnType == TypeCategory::INT || 162 break;
155 returnType == TypeCategory::STRING_REF || 163 case TypeCategory::FLOAT:
156 returnType == TypeCategory::CLASS_PTR) 164 signature += 'f';
157 { 165 break;
158 signature[pos++] = 'i'; 166 case TypeCategory::DOUBLE:
159 } 167 signature += 'd';
160 else 168 break;
161 throw std::runtime_error("Unexpected function return type"); 169 case TypeCategory::INT:
162 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");
177 }
178
179 // `this` pointer is an implicit parameter with clang and should be added
180 // to the signature.
163 if (instance_function) 181 if (instance_function)
164 { 182 signature += 'i';
165 // this pointer is an implicit parameter 183
166 signature[pos++] = 'i'; 184 // Add explicit parameters to the signature, Similar logic in Emscripten:
167 } 185 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L67
168 186 for (const auto& type : argTypes)
169 for (const auto& item : argTypes) 187 {
170 { 188 switch (type)
171 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF ||
172 item == TypeCategory::CLASS_PTR)
173 { 189 {
174 signature[pos++] = 'i'; 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");
175 } 209 }
176 else if (item == TypeCategory::FLOAT) 210 args.push_back(type);
177 signature[pos++] = 'd'; 211 }
178 else 212
179 throw std::runtime_error("Unexpected function argument type"); 213 get_function_name(function, signature.c_str());
180 args.push_back(item);
181 }
182
183 signature[pos] = 0;
184
185 get_function_name(function, signature);
186 } 214 }
187 215
188 template<typename ReturnType, typename... Args> 216 template<typename ReturnType, typename... Args>
189 FunctionInfo(ReturnType (*function)(Args...)) 217 FunctionInfo(ReturnType (*function)(Args...))
190 : FunctionInfo(TypeInfo<ReturnType>(), 218 : FunctionInfo(TypeInfo<ReturnType>(),
191 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, 219 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false,
192 &function) 220 &function)
193 { 221 {
194 } 222 }
195 223
(...skipping 11 matching lines...) Expand all
207 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, 235 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true,
208 &function) 236 &function)
209 { 237 {
210 } 238 }
211 239
212 bool empty() const 240 bool empty() const
213 { 241 {
214 return name[0] == '\0'; 242 return name[0] == '\0';
215 } 243 }
216 244
217 void get_function_name(void* ptr, char* signature) 245 void get_function_name(void* ptr, const char* signature)
218 { 246 {
219 // 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.
220 // 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
221 // 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 -
222 // 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
223 // 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
224 // 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
225 // 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
226 // for the name of our function. 254 // for the name of our function.
227 255
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 std::string call_str(call.name); 433 std::string call_str(call.name);
406 call_str += "("; 434 call_str += "(";
407 for (int i = 0; i < params.size(); i++) 435 for (int i = 0; i < params.size(); i++)
408 { 436 {
409 if (i > 0) 437 if (i > 0)
410 call_str += ", "; 438 call_str += ", ";
411 call_str += params[i]; 439 call_str += params[i];
412 } 440 }
413 call_str += ")"; 441 call_str += ")";
414 442
415 if (call.returnType == TypeCategory::VOID) 443 switch (call.returnType)
416 return " " + call_str + ";\n"; 444 {
417 else if (call.returnType == TypeCategory::INT || 445 case TypeCategory::VOID:
418 call.returnType == TypeCategory::FLOAT) 446 return " " + call_str + ";\n";
419 { 447 case TypeCategory::INT:
420 return " var result = " + call_str + ";\n"; 448 case TypeCategory::FLOAT:
421 } 449 case TypeCategory::DOUBLE:
422 else if (call.returnType == TypeCategory::DEPENDENT_STRING || 450 return " var result = " + call_str + ";\n";
423 call.returnType == TypeCategory::OWNED_STRING) 451 case TypeCategory::INT64:
424 { 452 return " var result = Runtime.makeBigInt(" + call_str + ", " +
425 std::string result; 453 "Runtime.getTempRet0(), " +
426 result += " var string = createString();\n"; 454 "true);\n";
427 result += " " + call_str + ";\n"; 455 case TypeCategory::DEPENDENT_STRING:
428 result += " var result = readString(string);\n"; 456 case TypeCategory::OWNED_STRING:
429 if (call.returnType == TypeCategory::OWNED_STRING) 457 {
430 result += " Module._DestroyString(string);\n"; 458 std::string result;
431 return result; 459 result += " var string = createString();\n";
432 } 460 result += " " + call_str + ";\n";
433 else if (call.returnType == TypeCategory::STRING_REF) 461 result += " var result = readString(string);\n";
434 { 462 if (call.returnType == TypeCategory::OWNED_STRING)
435 return " var result = readString(" + call_str + ");\n"; 463 result += " Module._DestroyString(string);\n";
436 } 464 return result;
437 else if (call.returnType == TypeCategory::CLASS_PTR) 465 }
438 { 466 case TypeCategory::STRING_REF:
439 std::string result; 467 return " var result = readString(" + call_str + ");\n";
440 result += " var result = " + call_str + ";\n"; 468 case TypeCategory::CLASS_PTR:
441 result += " if (result)\n"; 469 {
442 result += " {\n"; 470 std::string result;
443 471 result += " var result = " + call_str + ";\n";
444 auto it = classes.find(call.pointerType); 472 result += " if (result)\n";
445 if (it == classes.end()) 473 result += " {\n";
446 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class"); 474
447 475 auto it = classes.find(call.pointerType);
448 const ClassInfo& cls = it->second; 476 if (it == classes.end())
449 auto offset = cls.subclass_differentiator.offset; 477 throw std::runtime_error("Function " + std::string(call.name) + " retu rns pointer to unknown class");
450 if (offset == SIZE_MAX) 478
451 result += " result = " + cls.name + "(result);\n"; 479 const ClassInfo& cls = it->second;
452 else 480 auto offset = cls.subclass_differentiator.offset;
453 { 481 if (offset == SIZE_MAX)
454 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n"; 482 result += " result = " + cls.name + "(result);\n";
455 result += " if (type in " + cls.name + "_mapping)\n"; 483 else
456 result += " result = new (exports[" + cls.name + "_mapping[type]])( result);\n"; 484 {
457 result += " else\n"; 485 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n";
458 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n"; 486 result += " if (type in " + cls.name + "_mapping)\n";
459 } 487 result += " result = new (exports[" + cls.name + "_mapping[type]] )(result);\n";
460 488 result += " else\n";
461 result += " }\n"; 489 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n";
462 return result; 490 }
463 } 491
464 else 492 result += " }\n";
465 throw std::runtime_error("Unexpected return type for " + std::string(call. name)); 493 return result;
494 }
495 default:
496 throw std::runtime_error("Unexpected return type for " + std::string(cal l.name));
497 }
466 } 498 }
467 499
468 const std::string wrapCall(const FunctionInfo& call) 500 const std::string wrapCall(const FunctionInfo& call)
469 { 501 {
470 char buffer[20];
471 bool hasStringArgs = false; 502 bool hasStringArgs = false;
472 std::vector<std::string> params; 503 std::vector<std::string> params;
473 std::string prefix = "function("; 504 std::string prefix = "function(";
474 for (int i = 0; i < call.args.size(); i++) 505 for (int i = 0; i < call.args.size(); i++)
475 { 506 {
476 sprintf(buffer, "arg%i", i); 507 std::string argName("arg" + std::to_string(i));
477 if (i > 0) 508 if (i > 0)
478 prefix += ", "; 509 prefix += ", ";
479 prefix += buffer; 510 prefix += argName;
480 511
481 if (call.args[i] == TypeCategory::STRING_REF) 512 if (call.args[i] == TypeCategory::STRING_REF)
482 { 513 {
483 hasStringArgs = true; 514 hasStringArgs = true;
484 params.push_back(std::string("createString(") + buffer + ")"); 515 params.push_back(std::string("createString(") + argName + ")");
485 } 516 }
486 else if (call.args[i] == TypeCategory::CLASS_PTR) 517 else if (call.args[i] == TypeCategory::CLASS_PTR)
487 params.push_back(std::string(buffer) + "._pointer"); 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 }
488 else 525 else
489 params.push_back(buffer); 526 params.push_back(argName);
490 } 527 }
491 prefix += ")\n{\n"; 528 prefix += ")\n{\n";
492 529
493 std::string suffix = "}"; 530 std::string suffix = "}";
494 if (call.returnType != TypeCategory::VOID) 531 if (call.returnType != TypeCategory::VOID)
495 suffix = " return result;\n" + suffix; 532 suffix = " return result;\n" + suffix;
496 533
497 if (call.returnType == TypeCategory::DEPENDENT_STRING || 534 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
498 call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) 535 call.returnType == TypeCategory::OWNED_STRING || hasStringArgs)
499 { 536 {
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 793
757 std::vector<std::pair<int, std::string>> mapping; 794 std::vector<std::pair<int, std::string>> mapping;
758 for (const auto& item : list) 795 for (const auto& item : list)
759 mapping.emplace_back(item.first, item.second); 796 mapping.emplace_back(item.first, item.second);
760 797
761 bindings_internal::register_differentiator( 798 bindings_internal::register_differentiator(
762 bindings_internal::TypeInfo<ClassType>(), offset, mapping); 799 bindings_internal::TypeInfo<ClassType>(), offset, mapping);
763 return *this; 800 return *this;
764 } 801 }
765 }; 802 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld