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: Removed unnecessary raw buffer Created April 10, 2017, 6:27 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 25 matching lines...) Expand all
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 INT64,
46 FLOAT, 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
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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 std::string signature; 147 std::string signature;
144 if (returnType == TypeCategory::DEPENDENT_STRING || 148
145 returnType == TypeCategory::OWNED_STRING) 149 // Add return type to the signature. Similar logic in Emscripten:
146 { 150 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46
147 // Objects aren't really returned but passed as parameter. Note that 151 switch (returnType)
148 // this pointer might come before it but we don't care because both 152 {
149 // are integers (pointers) as far as Emscripten is concerned. 153 case TypeCategory::DEPENDENT_STRING:
150 signature += "vi"; 154 case TypeCategory::OWNED_STRING:
151 } 155 // Technically, objects aren't really returned with clang. The caller
152 else if (returnType == TypeCategory::VOID) 156 // instead adds the reference to the resulting object as an implicit
153 signature += 'v'; 157 // parameter.
154 else if (returnType == TypeCategory::FLOAT) 158 signature += "vi";
155 signature += 'd'; 159 break;
156 else if (returnType == TypeCategory::INT || 160 case TypeCategory::VOID:
157 returnType == TypeCategory::INT64 || 161 signature += 'v';
158 returnType == TypeCategory::STRING_REF || 162 break;
159 returnType == TypeCategory::CLASS_PTR) 163 case TypeCategory::FLOAT:
160 { 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");
177 }
178
179 // `this` pointer is an implicit parameter with clang and should be added
180 // to the signature.
181 if (instance_function)
161 signature += 'i'; 182 signature += 'i';
162 } 183
163 else 184 // Add explicit parameters to the signature, Similar logic in Emscripten:
164 throw std::runtime_error("Unexpected function return type"); 185 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L67
165 186 for (const auto& type : argTypes)
166 if (instance_function) 187 {
167 { 188 switch (type)
168 // this pointer is an implicit parameter
169 signature += 'i';
170 }
171
172 for (const auto& item : argTypes)
173 {
174 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF ||
175 item == TypeCategory::CLASS_PTR)
176 { 189 {
177 signature += '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");
178 } 209 }
179 else if (item == TypeCategory::INT64) 210 args.push_back(type);
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
184 throw std::runtime_error("Unexpected function argument type");
185 args.push_back(item);
186 } 211 }
187 212
188 get_function_name(function, signature.c_str()); 213 get_function_name(function, signature.c_str());
189 } 214 }
190 215
191 template<typename ReturnType, typename... Args> 216 template<typename ReturnType, typename... Args>
192 FunctionInfo(ReturnType (*function)(Args...)) 217 FunctionInfo(ReturnType (*function)(Args...))
193 : FunctionInfo(TypeInfo<ReturnType>(), 218 : FunctionInfo(TypeInfo<ReturnType>(),
194 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, 219 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false,
195 &function) 220 &function)
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 std::string call_str(call.name); 433 std::string call_str(call.name);
409 call_str += "("; 434 call_str += "(";
410 for (int i = 0; i < params.size(); i++) 435 for (int i = 0; i < params.size(); i++)
411 { 436 {
412 if (i > 0) 437 if (i > 0)
413 call_str += ", "; 438 call_str += ", ";
414 call_str += params[i]; 439 call_str += params[i];
415 } 440 }
416 call_str += ")"; 441 call_str += ")";
417 442
418 if (call.returnType == TypeCategory::VOID) 443 switch (call.returnType)
419 return " " + call_str + ";\n"; 444 {
420 else if (call.returnType == TypeCategory::INT || 445 case TypeCategory::VOID:
421 call.returnType == TypeCategory::FLOAT) 446 return " " + call_str + ";\n";
422 { 447 case TypeCategory::INT:
423 return " var result = " + call_str + ";\n"; 448 case TypeCategory::FLOAT:
424 } 449 case TypeCategory::DOUBLE:
425 else if (call.returnType == TypeCategory::INT64) 450 return " var result = " + call_str + ";\n";
426 { 451 case TypeCategory::INT64:
427 // Emscripten saves the high bits of a 64-bit return value in a special 452 return " var result = Runtime.makeBigInt(" + call_str + ", " +
428 // variable called tempRet0. We cannot use bit operators to combine the 453 "Runtime.getTempRet0(), " +
429 // values because JavaScript operates on 32-bit integers. 454 "true);\n";
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)" + 455 case TypeCategory::DEPENDENT_STRING:
431 " + (Runtime.getTempRet0() >>> 0) * 0x100000000;\n"; 456 case TypeCategory::OWNED_STRING:
432 } 457 {
433 else if (call.returnType == TypeCategory::DEPENDENT_STRING || 458 std::string result;
434 call.returnType == TypeCategory::OWNED_STRING) 459 result += " var string = createString();\n";
435 { 460 result += " " + call_str + ";\n";
436 std::string result; 461 result += " var result = readString(string);\n";
437 result += " var string = createString();\n"; 462 if (call.returnType == TypeCategory::OWNED_STRING)
438 result += " " + call_str + ";\n"; 463 result += " Module._DestroyString(string);\n";
439 result += " var result = readString(string);\n"; 464 return result;
440 if (call.returnType == TypeCategory::OWNED_STRING) 465 }
441 result += " Module._DestroyString(string);\n"; 466 case TypeCategory::STRING_REF:
442 return result; 467 return " var result = readString(" + call_str + ");\n";
443 } 468 case TypeCategory::CLASS_PTR:
444 else if (call.returnType == TypeCategory::STRING_REF) 469 {
445 { 470 std::string result;
446 return " var result = readString(" + call_str + ");\n"; 471 result += " var result = " + call_str + ";\n";
447 } 472 result += " if (result)\n";
448 else if (call.returnType == TypeCategory::CLASS_PTR) 473 result += " {\n";
449 { 474
450 std::string result; 475 auto it = classes.find(call.pointerType);
451 result += " var result = " + call_str + ";\n"; 476 if (it == classes.end())
452 result += " if (result)\n"; 477 throw std::runtime_error("Function " + std::string(call.name) + " retu rns pointer to unknown class");
453 result += " {\n"; 478
454 479 const ClassInfo& cls = it->second;
455 auto it = classes.find(call.pointerType); 480 auto offset = cls.subclass_differentiator.offset;
456 if (it == classes.end()) 481 if (offset == SIZE_MAX)
457 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class"); 482 result += " result = " + cls.name + "(result);\n";
458 483 else
459 const ClassInfo& cls = it->second; 484 {
460 auto offset = cls.subclass_differentiator.offset; 485 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n";
461 if (offset == SIZE_MAX) 486 result += " if (type in " + cls.name + "_mapping)\n";
462 result += " result = " + cls.name + "(result);\n"; 487 result += " result = new (exports[" + cls.name + "_mapping[type]] )(result);\n";
463 else 488 result += " else\n";
464 { 489 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n";
465 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n"; 490 }
466 result += " if (type in " + cls.name + "_mapping)\n"; 491
467 result += " result = new (exports[" + cls.name + "_mapping[type]])( result);\n"; 492 result += " }\n";
468 result += " else\n"; 493 return result;
469 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n"; 494 }
470 } 495 default:
471 496 throw std::runtime_error("Unexpected return type for " + std::string(cal l.name));
472 result += " }\n"; 497 }
473 return result;
474 }
475 else
476 throw std::runtime_error("Unexpected return type for " + std::string(call. name));
477 } 498 }
478 499
479 const std::string wrapCall(const FunctionInfo& call) 500 const std::string wrapCall(const FunctionInfo& call)
480 { 501 {
481 bool hasStringArgs = false; 502 bool hasStringArgs = false;
482 std::vector<std::string> params; 503 std::vector<std::string> params;
483 std::string prefix = "function("; 504 std::string prefix = "function(";
484 for (int i = 0; i < call.args.size(); i++) 505 for (int i = 0; i < call.args.size(); i++)
485 { 506 {
486 std::string argName("arg" + std::to_string(i)); 507 std::string argName("arg" + std::to_string(i));
487 if (i > 0) 508 if (i > 0)
488 prefix += ", "; 509 prefix += ", ";
489 prefix += argName; 510 prefix += argName;
490 511
491 if (call.args[i] == TypeCategory::STRING_REF) 512 if (call.args[i] == TypeCategory::STRING_REF)
492 { 513 {
493 hasStringArgs = true; 514 hasStringArgs = true;
494 params.push_back(std::string("createString(") + argName + ")"); 515 params.push_back(std::string("createString(") + argName + ")");
495 } 516 }
496 else if (call.args[i] == TypeCategory::CLASS_PTR) 517 else if (call.args[i] == TypeCategory::CLASS_PTR)
497 params.push_back(argName + "._pointer"); 518 params.push_back(argName + "._pointer");
498 else if (call.args[i] == TypeCategory::INT64) 519 else if (call.args[i] == TypeCategory::INT64)
499 { 520 {
500 // 64-bit integers are passed as two integer parameters 521 // 64-bit integers are passed as two integer parameters
501 params.push_back(argName + " >>> 0"); 522 params.push_back(argName + " >>> 0");
502 params.push_back(argName + " / 0x100000000 >>> 0"); 523 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 } 524 }
504 else 525 else
505 params.push_back(argName); 526 params.push_back(argName);
506 } 527 }
507 prefix += ")\n{\n"; 528 prefix += ")\n{\n";
508 529
509 std::string suffix = "}"; 530 std::string suffix = "}";
510 if (call.returnType != TypeCategory::VOID) 531 if (call.returnType != TypeCategory::VOID)
511 suffix = " return result;\n" + suffix; 532 suffix = " return result;\n" + suffix;
512 533
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
772 793
773 std::vector<std::pair<int, std::string>> mapping; 794 std::vector<std::pair<int, std::string>> mapping;
774 for (const auto& item : list) 795 for (const auto& item : list)
775 mapping.emplace_back(item.first, item.second); 796 mapping.emplace_back(item.first, item.second);
776 797
777 bindings_internal::register_differentiator( 798 bindings_internal::register_differentiator(
778 bindings_internal::TypeInfo<ClassType>(), offset, mapping); 799 bindings_internal::TypeInfo<ClassType>(), offset, mapping);
779 return *this; 800 return *this;
780 } 801 }
781 }; 802 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld