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

Delta Between Two Patch Sets: compiled/bindings.ipp

Issue 29398669: Issue 5063 - [emscripten] Make FilterNotifier calls more efficient (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Left Patch Set: Created March 30, 2017, 10:08 a.m.
Right Patch Set: Addressed comments Created April 20, 2017, 8 a.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/ActiveFilter.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 36
37 namespace bindings_internal 37 namespace bindings_internal
38 { 38 {
39 typedef void* TYPEID; 39 typedef void* TYPEID;
40 40
41 enum class TypeCategory 41 enum class TypeCategory
42 { 42 {
43 UNKNOWN, 43 UNKNOWN,
44 VOID, 44 VOID,
45 INT, 45 INT,
46 INT64,
46 FLOAT, 47 FLOAT,
48 DOUBLE,
47 DEPENDENT_STRING, 49 DEPENDENT_STRING,
48 OWNED_STRING, 50 OWNED_STRING,
49 STRING_REF, 51 STRING_REF,
50 CLASS_PTR 52 CLASS_PTR
51 }; 53 };
52 54
53 template<typename T> 55 template<typename T>
54 struct TypeInfo 56 struct TypeInfo
55 { 57 {
56 /* 58 /*
57 * Since TypeInfo is a templated type, in practice the compiler will define 59 * Since TypeInfo is a templated type, in practice the compiler will define
58 * a new type for each possible template parameter value. We use that fact 60 * a new type for each possible template parameter value. We use that fact
59 * to generate type identifiers: each of these TypeInfo types has a 61 * to generate type identifiers: each of these TypeInfo types has a
60 * different s_typeIDHelper member, so we use a pointer to that static 62 * different s_typeIDHelper member, so we use a pointer to that static
61 * variable as a type identifier - it will be different for each template 63 * variable as a type identifier - it will be different for each template
62 * parameter. 64 * parameter.
63 */ 65 */
64 static char s_typeIDHelper; 66 static char s_typeIDHelper;
65 constexpr operator TYPEID() const 67 constexpr operator TYPEID() const
66 { 68 {
67 return &s_typeIDHelper; 69 return &s_typeIDHelper;
68 } 70 }
69 71
70 constexpr operator TypeCategory() const 72 constexpr operator TypeCategory() const
71 { 73 {
72 if (std::is_void<T>()) 74 if (std::is_void<T>())
73 return TypeCategory::VOID; 75 return TypeCategory::VOID;
74 76
77 if (std::is_same<T, uint64_t>())
78 return TypeCategory::INT64;
79
75 if (std::is_integral<T>() || std::is_enum<T>()) 80 if (std::is_integral<T>() || std::is_enum<T>())
76 return TypeCategory::INT; 81 return TypeCategory::INT;
77 82
78 if (std::is_floating_point<T>()) 83 if (std::is_same<T, float>())
79 return TypeCategory::FLOAT; 84 return TypeCategory::FLOAT;
85
86 if (std::is_same<T, double>())
87 return TypeCategory::DOUBLE;
80 88
81 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>()) 89 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>())
82 return TypeCategory::DEPENDENT_STRING; 90 return TypeCategory::DEPENDENT_STRING;
83 91
84 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() ) 92 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() )
85 return TypeCategory::OWNED_STRING; 93 return TypeCategory::OWNED_STRING;
86 94
87 if (std::is_same<String&, T>() || std::is_same<const String&, T>() || 95 if (std::is_same<String&, T>() || std::is_same<const String&, T>() ||
88 std::is_same<DependentString&, T>()) 96 std::is_same<DependentString&, T>())
89 { 97 {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 instance_function(instance_function) 138 instance_function(instance_function)
131 { 139 {
132 name[0] = '\0'; 140 name[0] = '\0';
133 141
134 // The function parameter is a pointer to the function pointer. 142 // The function parameter is a pointer to the function pointer.
135 // Emscripten's "function pointers" are actually integers indicating the 143 // Emscripten's "function pointers" are actually integers indicating the
136 // position in the call table. 0 represents nullptr. 144 // position in the call table. 0 represents nullptr.
137 if (!*reinterpret_cast<int*>(function)) 145 if (!*reinterpret_cast<int*>(function))
138 return; 146 return;
139 147
140 char signature[256]; 148 std::string signature;
141 int pos = 0; 149
142 if (returnType == TypeCategory::DEPENDENT_STRING || 150 // Add return type to the signature. Similar logic in Emscripten:
143 returnType == TypeCategory::OWNED_STRING) 151 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46
144 { 152 switch (returnType)
145 // Objects aren't really returned but passed as parameter. Note that 153 {
146 // this pointer might come before it but we don't care because both 154 case TypeCategory::DEPENDENT_STRING:
147 // are integers (pointers) as far as Emscripten is concerned. 155 case TypeCategory::OWNED_STRING:
148 signature[pos++] = 'v'; 156 // Technically, objects aren't really returned with clang. The caller
149 signature[pos++] = 'i'; 157 // instead adds the reference to the resulting object as an implicit
150 } 158 // parameter.
151 else if (returnType == TypeCategory::VOID) 159 signature += "vi";
152 signature[pos++] = 'v'; 160 break;
153 else if (returnType == TypeCategory::FLOAT) 161 case TypeCategory::VOID:
154 signature[pos++] = 'd'; 162 signature += 'v';
155 else if (returnType == TypeCategory::INT || 163 break;
156 returnType == TypeCategory::STRING_REF || 164 case TypeCategory::FLOAT:
157 returnType == TypeCategory::CLASS_PTR) 165 signature += 'f';
158 { 166 break;
159 signature[pos++] = 'i'; 167 case TypeCategory::DOUBLE:
160 } 168 signature += 'd';
161 else 169 break;
162 throw std::runtime_error("Unexpected function return type"); 170 case TypeCategory::INT:
163 171 case TypeCategory::INT64:
172 case TypeCategory::STRING_REF:
173 case TypeCategory::CLASS_PTR:
174 signature += 'i';
175 break;
176 default:
177 throw std::runtime_error("Unexpected function return type");
178 }
179
180 // `this` pointer is an implicit parameter with clang and should be added
181 // to the signature.
164 if (instance_function) 182 if (instance_function)
165 { 183 signature += 'i';
166 // this pointer is an implicit parameter 184
167 signature[pos++] = 'i'; 185 // Add explicit parameters to the signature, Similar logic in Emscripten:
168 } 186 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L67
169 187 for (const auto& type : argTypes)
170 for (const auto& item : argTypes) 188 {
171 { 189 switch (type)
172 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF ||
173 item == TypeCategory::CLASS_PTR)
174 { 190 {
175 signature[pos++] = 'i'; 191 case TypeCategory::INT:
192 case TypeCategory::STRING_REF:
193 case TypeCategory::CLASS_PTR:
194 signature += 'i';
195 break;
196 case TypeCategory::INT64:
197 // See https://github.com/kripken/emscripten/blob/1.37.3/src/modules .js#L73,
198 // numerical types larger than 32-bit are split into multiple
199 // 32-bit parameters.
200 signature += "ii";
201 break;
202 case TypeCategory::FLOAT:
203 signature += 'f';
204 break;
205 case TypeCategory::DOUBLE:
206 signature += 'd';
207 break;
208 default:
209 throw std::runtime_error("Unexpected function argument type");
176 } 210 }
177 else if (item == TypeCategory::FLOAT) 211 args.push_back(type);
178 signature[pos++] = 'd'; 212 }
179 else 213
180 throw std::runtime_error("Unexpected function argument type"); 214 get_function_name(function, signature.c_str());
181 args.push_back(item);
182 }
183
184 signature[pos] = 0;
185
186 get_function_name(function, signature);
187 } 215 }
188 216
189 template<typename ReturnType, typename... Args> 217 template<typename ReturnType, typename... Args>
190 FunctionInfo(ReturnType (*function)(Args...)) 218 FunctionInfo(ReturnType (*function)(Args...))
191 : FunctionInfo(TypeInfo<ReturnType>(), 219 : FunctionInfo(TypeInfo<ReturnType>(),
192 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, 220 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false,
193 &function) 221 &function)
194 { 222 {
195 } 223 }
196 224
(...skipping 11 matching lines...) Expand all
208 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, 236 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true,
209 &function) 237 &function)
210 { 238 {
211 } 239 }
212 240
213 bool empty() const 241 bool empty() const
214 { 242 {
215 return name[0] == '\0'; 243 return name[0] == '\0';
216 } 244 }
217 245
218 void get_function_name(void* ptr, char* signature) 246 void get_function_name(void* ptr, const char* signature)
219 { 247 {
220 // This is a hack, C++ won't let us get the mangled function name. 248 // This is a hack, C++ won't let us get the mangled function name.
221 // JavaScript is more dynamic so we pass the pointer to our function 249 // JavaScript is more dynamic so we pass the pointer to our function
222 // there. With that and the function signature we can call the function - 250 // there. With that and the function signature we can call the function -
223 // with a full stack so that we will cause it to abort. Sometimes the 251 // with a full stack so that we will cause it to abort. Sometimes the
224 // function we are calling will also be missing from the build. The result 252 // function we are calling will also be missing from the build. The result
225 // is the same: abort() is called which in turn calls stackTrace(). By 253 // is the same: abort() is called which in turn calls stackTrace(). By
226 // replacing stackTrace() we get access to the call stack and search it 254 // replacing stackTrace() we get access to the call stack and search it
227 // for the name of our function. 255 // for the name of our function.
228 256
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 std::string call_str(call.name); 427 std::string call_str(call.name);
400 call_str += "("; 428 call_str += "(";
401 for (int i = 0; i < params.size(); i++) 429 for (int i = 0; i < params.size(); i++)
402 { 430 {
403 if (i > 0) 431 if (i > 0)
404 call_str += ", "; 432 call_str += ", ";
405 call_str += params[i]; 433 call_str += params[i];
406 } 434 }
407 call_str += ")"; 435 call_str += ")";
408 436
409 if (call.returnType == TypeCategory::VOID) 437 switch (call.returnType)
410 return " " + call_str + ";\n"; 438 {
411 else if (call.returnType == TypeCategory::INT || 439 case TypeCategory::VOID:
412 call.returnType == TypeCategory::FLOAT) 440 return " " + call_str + ";\n";
413 { 441 case TypeCategory::INT:
414 return " var result = " + call_str + ";\n"; 442 case TypeCategory::FLOAT:
415 } 443 case TypeCategory::DOUBLE:
416 else if (call.returnType == TypeCategory::DEPENDENT_STRING || 444 return " var result = " + call_str + ";\n";
417 call.returnType == TypeCategory::OWNED_STRING) 445 case TypeCategory::INT64:
418 { 446 return " var result = Runtime.makeBigInt(" + call_str + ", " +
419 std::string result; 447 "Runtime.getTempRet0(), " +
420 result += " var string = createString();\n"; 448 "true);\n";
421 result += " " + call_str + ";\n"; 449 case TypeCategory::DEPENDENT_STRING:
422 result += " var result = readString(string);\n"; 450 case TypeCategory::OWNED_STRING:
423 if (call.returnType == TypeCategory::OWNED_STRING) 451 {
424 result += " Module._DestroyString(string);\n"; 452 std::string result;
425 return result; 453 result += " var string = createString();\n";
426 } 454 result += " " + call_str + ";\n";
427 else if (call.returnType == TypeCategory::STRING_REF) 455 result += " var result = readString(string);\n";
428 { 456 if (call.returnType == TypeCategory::OWNED_STRING)
429 return " var result = readString(" + call_str + ");\n"; 457 result += " Module._DestroyString(string);\n";
430 } 458 return result;
431 else if (call.returnType == TypeCategory::CLASS_PTR) 459 }
432 { 460 case TypeCategory::STRING_REF:
433 std::string result; 461 return " var result = readString(" + call_str + ");\n";
434 result += " var result = " + call_str + ";\n"; 462 case TypeCategory::CLASS_PTR:
435 result += " if (result)\n"; 463 {
436 result += " {\n"; 464 std::string result;
437 465 result += " var result = " + call_str + ";\n";
438 auto it = classes.find(call.pointerType); 466 result += " if (result)\n";
439 if (it == classes.end()) 467 result += " {\n";
440 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class"); 468
441 469 auto it = classes.find(call.pointerType);
442 const ClassInfo& cls = it->second; 470 if (it == classes.end())
443 auto offset = cls.subclass_differentiator.offset; 471 throw std::runtime_error("Function " + std::string(call.name) + " retu rns pointer to unknown class");
444 if (offset == SIZE_MAX) 472
445 result += " result = exports." + cls.name + "(result);\n"; 473 const ClassInfo& cls = it->second;
446 else 474 auto offset = cls.subclass_differentiator.offset;
447 result += " result = exports." + cls.name + ".fromPointer(result);\n" ; 475 if (offset == SIZE_MAX)
448 476 result += " result = exports." + cls.name + "(result);\n";
449 result += " }\n"; 477 else
450 result += " else\n"; 478 result += " result = exports." + cls.name + ".fromPointer(result);\ n";
451 result += " result = null;\n"; 479
452 return result; 480 result += " }\n";
453 } 481 result += " else\n";
454 else 482 result += " result = null;\n";
455 throw std::runtime_error("Unexpected return type for " + std::string(call. name)); 483 return result;
484 }
485 default:
486 throw std::runtime_error("Unexpected return type for " + std::string(cal l.name));
487 }
456 } 488 }
457 489
458 const std::string wrapCall(const FunctionInfo& call) 490 const std::string wrapCall(const FunctionInfo& call)
459 { 491 {
460 char buffer[20];
461 bool hasStringArgs = false; 492 bool hasStringArgs = false;
462 std::vector<std::string> params; 493 std::vector<std::string> params;
463 std::string prefix = "function("; 494 std::string prefix = "function(";
464 for (int i = 0; i < call.args.size(); i++) 495 for (int i = 0; i < call.args.size(); i++)
465 { 496 {
466 sprintf(buffer, "arg%i", i); 497 std::string argName("arg" + std::to_string(i));
467 if (i > 0) 498 if (i > 0)
468 prefix += ", "; 499 prefix += ", ";
469 prefix += buffer; 500 prefix += argName;
470 501
471 if (call.args[i] == TypeCategory::STRING_REF) 502 if (call.args[i] == TypeCategory::STRING_REF)
472 { 503 {
473 hasStringArgs = true; 504 hasStringArgs = true;
474 params.push_back(std::string("createString(") + buffer + ")"); 505 params.push_back(std::string("createString(") + argName + ")");
475 } 506 }
476 else if (call.args[i] == TypeCategory::CLASS_PTR) 507 else if (call.args[i] == TypeCategory::CLASS_PTR)
477 params.push_back(std::string(buffer) + "._pointer"); 508 params.push_back(argName + "._pointer");
509 else if (call.args[i] == TypeCategory::INT64)
510 {
511 // 64-bit integers are passed as two integer parameters
512 params.push_back(argName + " >>> 0");
513 params.push_back(argName + " / 0x100000000 >>> 0");
514 }
478 else 515 else
479 params.push_back(buffer); 516 params.push_back(argName);
480 } 517 }
481 prefix += ")\n{\n"; 518 prefix += ")\n{\n";
482 519
483 std::string suffix = "}"; 520 std::string suffix = "}";
484 if (call.returnType != TypeCategory::VOID) 521 if (call.returnType != TypeCategory::VOID)
485 suffix = " return result;\n" + suffix; 522 suffix = " return result;\n" + suffix;
486 523
487 if (call.returnType == TypeCategory::DEPENDENT_STRING || 524 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
488 call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) 525 call.returnType == TypeCategory::OWNED_STRING || hasStringArgs)
489 { 526 {
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
617 654
618 for (const auto& item : customGenerators) 655 for (const auto& item : customGenerators)
619 item(); 656 item();
620 } 657 }
621 } 658 }
622 659
623 #if defined(PRINT_BINDINGS) 660 #if defined(PRINT_BINDINGS)
624 // Bindings generation step: collect bindings information and print 661 // Bindings generation step: collect bindings information and print
625 // corresponding JS code. 662 // corresponding JS code.
626 #define EMSCRIPTEN_BINDINGS \ 663 #define EMSCRIPTEN_BINDINGS \
627 struct BindingsInitializer {\ 664 void InitializeBindings();\
628 BindingsInitializer();\ 665 int main()\
629 };\
630 int main(void)\
631 {\ 666 {\
632 try\ 667 try\
633 {\ 668 {\
634 struct BindingsInitializer instance;\ 669 InitializeBindings();\
635 bindings_internal::printBindings();\ 670 bindings_internal::printBindings();\
636 }\ 671 }\
637 catch (const std::exception& e)\ 672 catch (const std::exception& e)\
638 {\ 673 {\
639 EM_ASM_ARGS(\ 674 EM_ASM_ARGS(\
640 console.error("Error occurred generating JavaScript bindings: " +\ 675 console.error("Error occurred generating JavaScript bindings: " +\
641 Module.AsciiToString($0)), e.what()\ 676 Module.AsciiToString($0)), e.what()\
642 );\ 677 );\
643 abort();\ 678 abort();\
644 }\ 679 }\
645 return 0;\ 680 return 0;\
646 }\ 681 }\
647 BindingsInitializer::BindingsInitializer() 682 void InitializeBindings()
648 #else 683 #else
649 // Actual compilation step: ignore bindings information but define some 684 // Actual compilation step: ignore bindings information but define some
650 // exported helper functions necessary for the bindings. 685 // exported helper functions necessary for the bindings.
651 #define EMSCRIPTEN_BINDINGS \ 686 #define EMSCRIPTEN_BINDINGS \
652 extern "C"\ 687 extern "C"\
653 {\ 688 {\
654 void EMSCRIPTEN_KEEPALIVE InitString(DependentString* str,\ 689 void EMSCRIPTEN_KEEPALIVE InitString(DependentString* str,\
655 String::value_type* data, String::size_type len)\ 690 String::value_type* data, String::size_type len)\
656 {\ 691 {\
657 /* String is already allocated on stack, we merely need to call*/\ 692 /* String is already allocated on stack, we merely need to call*/\
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
760 bindings_internal::register_differentiator( 795 bindings_internal::register_differentiator(
761 bindings_internal::TypeInfo<ClassType>(), offset, mapping); 796 bindings_internal::TypeInfo<ClassType>(), offset, mapping);
762 return *this; 797 return *this;
763 } 798 }
764 }; 799 };
765 800
766 void custom_generator(bindings_internal::CustomGenerator generator) 801 void custom_generator(bindings_internal::CustomGenerator generator)
767 { 802 {
768 bindings_internal::customGenerators.push_back(generator); 803 bindings_internal::customGenerators.push_back(generator);
769 } 804 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld