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: Removed unnecessary raw buffer Created April 10, 2017, 6:27 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
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,
sergei 2017/04/12 12:04:32 I would rather call it DOUBLE because emscripten u
Wladimir Palant 2017/04/13 13:04:40 I was under the impression that Emscripten doesn't
45 DEPENDENT_STRING, 47 DEPENDENT_STRING,
46 OWNED_STRING, 48 OWNED_STRING,
47 STRING_REF, 49 STRING_REF,
48 CLASS_PTR 50 CLASS_PTR
49 }; 51 };
50 52
51 template<typename T> 53 template<typename T>
52 struct TypeInfo 54 struct TypeInfo
53 { 55 {
54 /* 56 /*
55 * Since TypeInfo is a templated type, in practice the compiler will define 57 * 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 58 * 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 59 * to generate type identifiers: each of these TypeInfo types has a
58 * different s_typeIDHelper member, so we use a pointer to that static 60 * 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 61 * variable as a type identifier - it will be different for each template
60 * parameter. 62 * parameter.
61 */ 63 */
62 static char s_typeIDHelper; 64 static char s_typeIDHelper;
63 constexpr operator TYPEID() const 65 constexpr operator TYPEID() const
64 { 66 {
65 return &s_typeIDHelper; 67 return &s_typeIDHelper;
66 } 68 }
67 69
68 constexpr operator TypeCategory() const 70 constexpr operator TypeCategory() const
69 { 71 {
70 if (std::is_void<T>()) 72 if (std::is_void<T>())
71 return TypeCategory::VOID; 73 return TypeCategory::VOID;
72 74
75 if (std::is_same<T, uint64_t>())
76 return TypeCategory::INT64;
77
73 if (std::is_integral<T>() || std::is_enum<T>()) 78 if (std::is_integral<T>() || std::is_enum<T>())
74 return TypeCategory::INT; 79 return TypeCategory::INT;
75 80
81 if (std::is_floating_point<T>())
82 return TypeCategory::FLOAT;
83
76 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>()) 84 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>())
77 return TypeCategory::DEPENDENT_STRING; 85 return TypeCategory::DEPENDENT_STRING;
78 86
79 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() ) 87 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() )
80 return TypeCategory::OWNED_STRING; 88 return TypeCategory::OWNED_STRING;
81 89
82 if (std::is_same<String&, T>() || std::is_same<const String&, T>() || 90 if (std::is_same<String&, T>() || std::is_same<const String&, T>() ||
83 std::is_same<DependentString&, T>()) 91 std::is_same<DependentString&, T>())
84 { 92 {
85 return TypeCategory::STRING_REF; 93 return TypeCategory::STRING_REF;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 instance_function(instance_function) 133 instance_function(instance_function)
126 { 134 {
127 name[0] = '\0'; 135 name[0] = '\0';
128 136
129 // The function parameter is a pointer to the function pointer. 137 // The function parameter is a pointer to the function pointer.
130 // Emscripten's "function pointers" are actually integers indicating the 138 // Emscripten's "function pointers" are actually integers indicating the
131 // position in the call table. 0 represents nullptr. 139 // position in the call table. 0 represents nullptr.
132 if (!*reinterpret_cast<int*>(function)) 140 if (!*reinterpret_cast<int*>(function))
133 return; 141 return;
134 142
143 std::string signature;
144 if (returnType == TypeCategory::DEPENDENT_STRING ||
145 returnType == TypeCategory::OWNED_STRING)
146 {
147 // Objects aren't really returned but passed as parameter. Note that
148 // this pointer might come before it but we don't care because both
149 // are integers (pointers) as far as Emscripten is concerned.
150 signature += "vi";
151 }
152 else if (returnType == TypeCategory::VOID)
153 signature += 'v';
154 else if (returnType == TypeCategory::FLOAT)
155 signature += 'd';
156 else if (returnType == TypeCategory::INT ||
157 returnType == TypeCategory::INT64 ||
158 returnType == TypeCategory::STRING_REF ||
159 returnType == TypeCategory::CLASS_PTR)
160 {
161 signature += 'i';
162 }
163 else
164 throw std::runtime_error("Unexpected function return type");
165
166 if (instance_function)
167 {
168 // this pointer is an implicit parameter
169 signature += 'i';
170 }
171
135 for (const auto& item : argTypes) 172 for (const auto& item : argTypes)
136 { 173 {
137 if (item != TypeCategory::INT && item != TypeCategory::STRING_REF && 174 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF ||
138 item != TypeCategory::CLASS_PTR) 175 item == TypeCategory::CLASS_PTR)
139 { 176 {
177 signature += 'i';
178 }
179 else if (item == TypeCategory::INT64)
180 signature += "ii";
sergei 2017/04/12 12:04:32 It would be good to have a link (maybe better to s
Wladimir Palant 2017/04/13 13:04:39 Ok, I managed to find the correct code line, linke
181 else if (item == TypeCategory::FLOAT)
182 signature += 'd';
183 else
140 throw std::runtime_error("Unexpected function argument type"); 184 throw std::runtime_error("Unexpected function argument type");
141 }
142 args.push_back(item); 185 args.push_back(item);
143 } 186 }
144 187
145 if (returnType != TypeCategory::VOID && returnType != TypeCategory::INT && 188 get_function_name(function, signature.c_str());
146 returnType != TypeCategory::DEPENDENT_STRING &&
147 returnType != TypeCategory::OWNED_STRING &&
148 returnType != TypeCategory::STRING_REF &&
149 returnType != TypeCategory::CLASS_PTR)
150 {
151 throw std::runtime_error("Unexpected function return type");
152 }
153
154 effectiveArgs = args.size();
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 } 189 }
169 190
170 template<typename ReturnType, typename... Args> 191 template<typename ReturnType, typename... Args>
171 FunctionInfo(ReturnType (*function)(Args...)) 192 FunctionInfo(ReturnType (*function)(Args...))
172 : FunctionInfo(TypeInfo<ReturnType>(), 193 : FunctionInfo(TypeInfo<ReturnType>(),
173 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, 194 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false,
174 &function) 195 &function)
175 { 196 {
176 } 197 }
177 198
(...skipping 11 matching lines...) Expand all
189 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, 210 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true,
190 &function) 211 &function)
191 { 212 {
192 } 213 }
193 214
194 bool empty() const 215 bool empty() const
195 { 216 {
196 return name[0] == '\0'; 217 return name[0] == '\0';
197 } 218 }
198 219
199 void get_function_name(void* ptr, int numArgs, bool voidResult) 220 void get_function_name(void* ptr, const char* signature)
200 { 221 {
201 // This is a hack, C++ won't let us get the mangled function name. 222 // 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 223 // 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 - 224 // 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 225 // 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 226 // 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 227 // 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 228 // replacing stackTrace() we get access to the call stack and search it
208 // for the name of our function. 229 // for the name of our function.
209 230
210 EM_ASM_ARGS({ 231 EM_ASM_ARGS({
211 var signature = $3 ? "v" : "i"; 232 var signature = AsciiToString($2);
212 var args = []; 233 var args = [];
213 for (var i = 0; i < $2; i++) 234 for (var i = 1; i < signature.length; i++)
214 {
215 signature += "i";
216 args.push(0); 235 args.push(0);
217 }
218 236
219 var oldPrint = Module.print; 237 var oldPrint = Module.print;
220 var oldPrintErr = Module.printErr; 238 var oldPrintErr = Module.printErr;
221 var oldStackTrace = stackTrace; 239 var oldStackTrace = stackTrace;
222 var sp = Runtime.stackSave(); 240 var sp = Runtime.stackSave();
223 Module.print = function(){}; 241 Module.print = function(){};
224 Module.printErr = function(){}; 242 Module.printErr = function(){};
225 stackTrace = function() 243 stackTrace = function()
226 { 244 {
227 var stack = []; 245 var stack = [];
(...skipping 24 matching lines...) Expand all
252 { 270 {
253 Module.stringToAscii(e, $0); 271 Module.stringToAscii(e, $0);
254 } 272 }
255 finally 273 finally
256 { 274 {
257 Runtime.stackRestore(sp); 275 Runtime.stackRestore(sp);
258 Module.print = oldPrint; 276 Module.print = oldPrint;
259 Module.printErr = oldPrintErr; 277 Module.printErr = oldPrintErr;
260 stackTrace = oldStackTrace; 278 stackTrace = oldStackTrace;
261 } 279 }
262 }, name, ptr, numArgs, voidResult); 280 }, name, ptr, signature);
263 } 281 }
264 }; 282 };
265 283
266 class NoBaseClass 284 class NoBaseClass
267 { 285 {
268 }; 286 };
269 287
270 struct PropertyInfo 288 struct PropertyInfo
271 { 289 {
272 std::string name; 290 std::string name;
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 for (int i = 0; i < params.size(); i++) 410 for (int i = 0; i < params.size(); i++)
393 { 411 {
394 if (i > 0) 412 if (i > 0)
395 call_str += ", "; 413 call_str += ", ";
396 call_str += params[i]; 414 call_str += params[i];
397 } 415 }
398 call_str += ")"; 416 call_str += ")";
399 417
400 if (call.returnType == TypeCategory::VOID) 418 if (call.returnType == TypeCategory::VOID)
401 return " " + call_str + ";\n"; 419 return " " + call_str + ";\n";
402 else if (call.returnType == TypeCategory::INT) 420 else if (call.returnType == TypeCategory::INT ||
421 call.returnType == TypeCategory::FLOAT)
422 {
403 return " var result = " + call_str + ";\n"; 423 return " var result = " + call_str + ";\n";
424 }
425 else if (call.returnType == TypeCategory::INT64)
426 {
427 // Emscripten saves the high bits of a 64-bit return value in a special
428 // variable called tempRet0. We cannot use bit operators to combine the
429 // values because JavaScript operates on 32-bit integers.
sergei 2017/04/12 12:04:32 I would replace JavaScript by something more speci
Wladimir Palant 2017/04/13 13:04:40 This comment is gone - I found that Emscripten exp
430 return " var result = (" + call_str + " >>> 0)" +
431 " + (Runtime.getTempRet0() >>> 0) * 0x100000000;\n";
432 }
404 else if (call.returnType == TypeCategory::DEPENDENT_STRING || 433 else if (call.returnType == TypeCategory::DEPENDENT_STRING ||
405 call.returnType == TypeCategory::OWNED_STRING) 434 call.returnType == TypeCategory::OWNED_STRING)
406 { 435 {
407 std::string result; 436 std::string result;
408 result += " var string = createString();\n"; 437 result += " var string = createString();\n";
409 result += " " + call_str + ";\n"; 438 result += " " + call_str + ";\n";
410 result += " var result = readString(string);\n"; 439 result += " var result = readString(string);\n";
411 if (call.returnType == TypeCategory::OWNED_STRING) 440 if (call.returnType == TypeCategory::OWNED_STRING)
412 result += " Module._DestroyString(string);\n"; 441 result += " Module._DestroyString(string);\n";
413 return result; 442 return result;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 std::string argName("arg" + std::to_string(i)); 486 std::string argName("arg" + std::to_string(i));
458 if (i > 0) 487 if (i > 0)
459 prefix += ", "; 488 prefix += ", ";
460 prefix += argName; 489 prefix += argName;
461 490
462 if (call.args[i] == TypeCategory::STRING_REF) 491 if (call.args[i] == TypeCategory::STRING_REF)
463 { 492 {
464 hasStringArgs = true; 493 hasStringArgs = true;
465 params.push_back(std::string("createString(") + argName + ")"); 494 params.push_back(std::string("createString(") + argName + ")");
466 } 495 }
496 else if (call.args[i] == TypeCategory::CLASS_PTR)
497 params.push_back(argName + "._pointer");
498 else if (call.args[i] == TypeCategory::INT64)
499 {
500 // 64-bit integers are passed as two integer parameters
501 params.push_back(argName + " >>> 0");
502 params.push_back(argName + " / 0x100000000 >>> 0");
sergei 2017/04/12 12:04:32 It would be very useful to have few tests for that
Wladimir Palant 2017/04/13 13:04:40 We have a few tests in FilterNotifier further up m
503 }
467 else 504 else
468 params.push_back(argName); 505 params.push_back(argName);
469 } 506 }
470 prefix += ")\n{\n"; 507 prefix += ")\n{\n";
471 508
472 std::string suffix = "}"; 509 std::string suffix = "}";
473 if (call.returnType != TypeCategory::VOID) 510 if (call.returnType != TypeCategory::VOID)
474 suffix = " return result;\n" + suffix; 511 suffix = " return result;\n" + suffix;
475 512
476 if (call.returnType == TypeCategory::DEPENDENT_STRING || 513 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 772
736 std::vector<std::pair<int, std::string>> mapping; 773 std::vector<std::pair<int, std::string>> mapping;
737 for (const auto& item : list) 774 for (const auto& item : list)
738 mapping.emplace_back(item.first, item.second); 775 mapping.emplace_back(item.first, item.second);
739 776
740 bindings_internal::register_differentiator( 777 bindings_internal::register_differentiator(
741 bindings_internal::TypeInfo<ClassType>(), offset, mapping); 778 bindings_internal::TypeInfo<ClassType>(), offset, mapping);
742 return *this; 779 return *this;
743 } 780 }
744 }; 781 };
OLDNEW

Powered by Google App Engine
This is Rietveld