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: Use uint64_t for properties Created April 7, 2017, 7:12 a.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 26 matching lines...) Expand all
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 INT64,
46 FLOAT, 46 FLOAT,
47 DOUBLE,
47 DEPENDENT_STRING, 48 DEPENDENT_STRING,
48 OWNED_STRING, 49 OWNED_STRING,
49 STRING_REF, 50 STRING_REF,
50 CLASS_PTR 51 CLASS_PTR
51 }; 52 };
52 53
53 template<typename T> 54 template<typename T>
54 struct TypeInfo 55 struct TypeInfo
55 { 56 {
56 /* 57 /*
(...skipping 14 matching lines...) Expand all
71 { 72 {
72 if (std::is_void<T>()) 73 if (std::is_void<T>())
73 return TypeCategory::VOID; 74 return TypeCategory::VOID;
74 75
75 if (std::is_same<T, uint64_t>()) 76 if (std::is_same<T, uint64_t>())
76 return TypeCategory::INT64; 77 return TypeCategory::INT64;
77 78
78 if (std::is_integral<T>() || std::is_enum<T>()) 79 if (std::is_integral<T>() || std::is_enum<T>())
79 return TypeCategory::INT; 80 return TypeCategory::INT;
80 81
81 if (std::is_floating_point<T>()) 82 if (std::is_same<T, float>())
82 return TypeCategory::FLOAT; 83 return TypeCategory::FLOAT;
84
85 if (std::is_same<T, double>())
86 return TypeCategory::DOUBLE;
83 87
84 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>())
85 return TypeCategory::DEPENDENT_STRING; 89 return TypeCategory::DEPENDENT_STRING;
86 90
87 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>() )
88 return TypeCategory::OWNED_STRING; 92 return TypeCategory::OWNED_STRING;
89 93
90 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>() ||
91 std::is_same<DependentString&, T>()) 95 std::is_same<DependentString&, T>())
92 { 96 {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 instance_function(instance_function) 137 instance_function(instance_function)
134 { 138 {
135 name[0] = '\0'; 139 name[0] = '\0';
136 140
137 // The function parameter is a pointer to the function pointer. 141 // The function parameter is a pointer to the function pointer.
138 // Emscripten's "function pointers" are actually integers indicating the 142 // Emscripten's "function pointers" are actually integers indicating the
139 // position in the call table. 0 represents nullptr. 143 // position in the call table. 0 represents nullptr.
140 if (!*reinterpret_cast<int*>(function)) 144 if (!*reinterpret_cast<int*>(function))
141 return; 145 return;
142 146
143 char signature[256]; 147 std::string signature;
144 int pos = 0; 148
145 if (returnType == TypeCategory::DEPENDENT_STRING || 149 // Add return type to the signature. Similar logic in Emscripten:
146 returnType == TypeCategory::OWNED_STRING) 150 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46
147 { 151 switch (returnType)
148 // Objects aren't really returned but passed as parameter. Note that 152 {
149 // this pointer might come before it but we don't care because both 153 case TypeCategory::DEPENDENT_STRING:
150 // are integers (pointers) as far as Emscripten is concerned. 154 case TypeCategory::OWNED_STRING:
151 signature[pos++] = 'v'; 155 // Technically, objects aren't really returned with clang. The caller
152 signature[pos++] = 'i'; 156 // instead adds the reference to the resulting object as an implicit
153 } 157 // parameter.
154 else if (returnType == TypeCategory::VOID) 158 signature += "vi";
155 signature[pos++] = 'v'; 159 break;
156 else if (returnType == TypeCategory::FLOAT) 160 case TypeCategory::VOID:
157 signature[pos++] = 'd'; 161 signature += 'v';
158 else if (returnType == TypeCategory::INT || 162 break;
159 returnType == TypeCategory::INT64 || 163 case TypeCategory::FLOAT:
160 returnType == TypeCategory::STRING_REF || 164 signature += 'f';
161 returnType == TypeCategory::CLASS_PTR) 165 break;
162 { 166 case TypeCategory::DOUBLE:
163 signature[pos++] = 'i'; 167 signature += 'd';
164 } 168 break;
165 else 169 case TypeCategory::INT:
166 throw std::runtime_error("Unexpected function return type"); 170 case TypeCategory::INT64:
167 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.
168 if (instance_function) 181 if (instance_function)
169 { 182 signature += 'i';
170 // this pointer is an implicit parameter 183
171 signature[pos++] = 'i'; 184 // Add explicit parameters to the signature, Similar logic in Emscripten:
172 } 185 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L67
173 186 for (const auto& type : argTypes)
174 for (const auto& item : argTypes) 187 {
175 { 188 switch (type)
176 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF ||
177 item == TypeCategory::CLASS_PTR)
178 { 189 {
179 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");
180 } 209 }
181 else if (item == TypeCategory::INT64) 210 args.push_back(type);
182 { 211 }
183 signature[pos++] = 'i'; 212
184 signature[pos++] = 'i'; 213 get_function_name(function, signature.c_str());
185 }
186 else if (item == TypeCategory::FLOAT)
187 signature[pos++] = 'd';
188 else
189 throw std::runtime_error("Unexpected function argument type");
190 args.push_back(item);
191 }
192
193 signature[pos] = 0;
hub 2017/04/10 15:30:09 Nowhere we check that pos doesn't overflow. Not ev
Wladimir Palant 2017/04/10 18:27:49 Indeed, this is unnecessary. This is bindings gene
194
195 get_function_name(function, signature);
196 } 214 }
197 215
198 template<typename ReturnType, typename... Args> 216 template<typename ReturnType, typename... Args>
199 FunctionInfo(ReturnType (*function)(Args...)) 217 FunctionInfo(ReturnType (*function)(Args...))
200 : FunctionInfo(TypeInfo<ReturnType>(), 218 : FunctionInfo(TypeInfo<ReturnType>(),
201 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, 219 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false,
202 &function) 220 &function)
203 { 221 {
204 } 222 }
205 223
(...skipping 11 matching lines...) Expand all
217 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, 235 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true,
218 &function) 236 &function)
219 { 237 {
220 } 238 }
221 239
222 bool empty() const 240 bool empty() const
223 { 241 {
224 return name[0] == '\0'; 242 return name[0] == '\0';
225 } 243 }
226 244
227 void get_function_name(void* ptr, char* signature) 245 void get_function_name(void* ptr, const char* signature)
228 { 246 {
229 // 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.
230 // 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
231 // 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 -
232 // 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
233 // 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
234 // 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
235 // 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
236 // for the name of our function. 254 // for the name of our function.
237 255
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 std::string call_str(call.name); 433 std::string call_str(call.name);
416 call_str += "("; 434 call_str += "(";
417 for (int i = 0; i < params.size(); i++) 435 for (int i = 0; i < params.size(); i++)
418 { 436 {
419 if (i > 0) 437 if (i > 0)
420 call_str += ", "; 438 call_str += ", ";
421 call_str += params[i]; 439 call_str += params[i];
422 } 440 }
423 call_str += ")"; 441 call_str += ")";
424 442
425 if (call.returnType == TypeCategory::VOID) 443 switch (call.returnType)
426 return " " + call_str + ";\n"; 444 {
427 else if (call.returnType == TypeCategory::INT || 445 case TypeCategory::VOID:
428 call.returnType == TypeCategory::FLOAT) 446 return " " + call_str + ";\n";
429 { 447 case TypeCategory::INT:
430 return " var result = " + call_str + ";\n"; 448 case TypeCategory::FLOAT:
431 } 449 case TypeCategory::DOUBLE:
432 else if (call.returnType == TypeCategory::INT64) 450 return " var result = " + call_str + ";\n";
433 { 451 case TypeCategory::INT64:
434 // Emscripten saves the high bits of a 64-bit return value in a special 452 return " var result = Runtime.makeBigInt(" + call_str + ", " +
435 // variable called tempRet0. We cannot use bit operators to combine the 453 "Runtime.getTempRet0(), " +
436 // values because JavaScript operates on 32-bit integers. 454 "true);\n";
437 return " var result = (" + call_str + " >>> 0)" + 455 case TypeCategory::DEPENDENT_STRING:
438 " + (Runtime.getTempRet0() >>> 0) * 0x100000000;\n"; 456 case TypeCategory::OWNED_STRING:
439 } 457 {
440 else if (call.returnType == TypeCategory::DEPENDENT_STRING || 458 std::string result;
441 call.returnType == TypeCategory::OWNED_STRING) 459 result += " var string = createString();\n";
442 { 460 result += " " + call_str + ";\n";
443 std::string result; 461 result += " var result = readString(string);\n";
444 result += " var string = createString();\n"; 462 if (call.returnType == TypeCategory::OWNED_STRING)
445 result += " " + call_str + ";\n"; 463 result += " Module._DestroyString(string);\n";
446 result += " var result = readString(string);\n"; 464 return result;
447 if (call.returnType == TypeCategory::OWNED_STRING) 465 }
448 result += " Module._DestroyString(string);\n"; 466 case TypeCategory::STRING_REF:
449 return result; 467 return " var result = readString(" + call_str + ");\n";
450 } 468 case TypeCategory::CLASS_PTR:
451 else if (call.returnType == TypeCategory::STRING_REF) 469 {
452 { 470 std::string result;
453 return " var result = readString(" + call_str + ");\n"; 471 result += " var result = " + call_str + ";\n";
454 } 472 result += " if (result)\n";
455 else if (call.returnType == TypeCategory::CLASS_PTR) 473 result += " {\n";
456 { 474
457 std::string result; 475 auto it = classes.find(call.pointerType);
458 result += " var result = " + call_str + ";\n"; 476 if (it == classes.end())
459 result += " if (result)\n"; 477 throw std::runtime_error("Function " + std::string(call.name) + " retu rns pointer to unknown class");
460 result += " {\n"; 478
461 479 const ClassInfo& cls = it->second;
462 auto it = classes.find(call.pointerType); 480 auto offset = cls.subclass_differentiator.offset;
463 if (it == classes.end()) 481 if (offset == SIZE_MAX)
464 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class"); 482 result += " result = " + cls.name + "(result);\n";
465 483 else
466 const ClassInfo& cls = it->second; 484 {
467 auto offset = cls.subclass_differentiator.offset; 485 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n";
468 if (offset == SIZE_MAX) 486 result += " if (type in " + cls.name + "_mapping)\n";
469 result += " result = " + cls.name + "(result);\n"; 487 result += " result = new (exports[" + cls.name + "_mapping[type]] )(result);\n";
470 else 488 result += " else\n";
471 { 489 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n";
472 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n"; 490 }
473 result += " if (type in " + cls.name + "_mapping)\n"; 491
474 result += " result = new (exports[" + cls.name + "_mapping[type]])( result);\n"; 492 result += " }\n";
475 result += " else\n"; 493 return result;
476 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n"; 494 }
477 } 495 default:
478 496 throw std::runtime_error("Unexpected return type for " + std::string(cal l.name));
479 result += " }\n"; 497 }
480 return result;
481 }
482 else
483 throw std::runtime_error("Unexpected return type for " + std::string(call. name));
484 } 498 }
485 499
486 const std::string wrapCall(const FunctionInfo& call) 500 const std::string wrapCall(const FunctionInfo& call)
487 { 501 {
488 bool hasStringArgs = false; 502 bool hasStringArgs = false;
489 std::vector<std::string> params; 503 std::vector<std::string> params;
490 std::string prefix = "function("; 504 std::string prefix = "function(";
491 for (int i = 0; i < call.args.size(); i++) 505 for (int i = 0; i < call.args.size(); i++)
492 { 506 {
493 std::string argName("arg" + std::to_string(i)); 507 std::string argName("arg" + std::to_string(i));
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 793
780 std::vector<std::pair<int, std::string>> mapping; 794 std::vector<std::pair<int, std::string>> mapping;
781 for (const auto& item : list) 795 for (const auto& item : list)
782 mapping.emplace_back(item.first, item.second); 796 mapping.emplace_back(item.first, item.second);
783 797
784 bindings_internal::register_differentiator( 798 bindings_internal::register_differentiator(
785 bindings_internal::TypeInfo<ClassType>(), offset, mapping); 799 bindings_internal::TypeInfo<ClassType>(), offset, mapping);
786 return *this; 800 return *this;
787 } 801 }
788 }; 802 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld