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

Side by Side Diff: compiled/bindings/generator.cpp

Issue 29431555: Issue 5216 - [emscripten] Use a more reliable way of retrieving mangled function name (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Patch Set: Slight code improvements Created May 8, 2017, 8:52 a.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
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #include <cstdio> 18 #include <cstdio>
19 19
20 #include <emscripten.h>
21
22 #include "generator.h" 20 #include "generator.h"
21 #include "library.h"
23 22
24 namespace 23 namespace
25 { 24 {
26 std::vector<bindings_internal::ClassInfo> classes; 25 std::vector<bindings_internal::ClassInfo> classes;
27 std::vector<bindings_internal::NamespaceInfo> namespaces; 26 std::vector<bindings_internal::NamespaceInfo> namespaces;
28 27
29 void printProperties(const bindings_internal::PropertyList& properties) 28 void printProperties(const bindings_internal::PropertyList& properties)
30 { 29 {
31 for (const auto& property : properties) 30 for (const auto& property : properties)
32 { 31 {
(...skipping 18 matching lines...) Expand all
51 for (const auto& method : methods) 50 for (const auto& method : methods)
52 if (!instanceOnly || method.call.instance_function) 51 if (!instanceOnly || method.call.instance_function)
53 printf("%s: %s,\n", method.name.c_str(), wrapCall(method.call).c_str()); 52 printf("%s: %s,\n", method.name.c_str(), wrapCall(method.call).c_str());
54 } 53 }
55 } 54 }
56 55
57 namespace bindings_internal 56 namespace bindings_internal
58 { 57 {
59 FunctionInfo::FunctionInfo() 58 FunctionInfo::FunctionInfo()
60 { 59 {
61 name[0] = '\0';
62 } 60 }
63 61
64 FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType, 62 FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType,
65 std::initializer_list<TypeCategory> argTypes, bool instance_function, 63 std::initializer_list<TypeCategory> argTypes, bool instance_function,
66 void* function) 64 void* function)
67 : returnType(returnType), pointerType(pointerType), 65 : returnType(returnType), pointerType(pointerType),
68 instance_function(instance_function) 66 instance_function(instance_function)
69 { 67 {
70 name[0] = '\0';
71
72 // The function parameter is a pointer to the function pointer. 68 // The function parameter is a pointer to the function pointer.
73 // Emscripten's "function pointers" are actually integers indicating the 69 // Emscripten's "function pointers" are actually integers indicating the
74 // position in the call table. 0 represents nullptr. 70 // position in the call table. 0 represents nullptr.
75 if (!*reinterpret_cast<int*>(function)) 71 if (!*reinterpret_cast<int*>(function))
76 return; 72 return;
77 73
78 std::string signature; 74 std::string signature;
79 75
80 // Add return type to the signature. Similar logic in Emscripten: 76 // Add return type to the signature. Similar logic in Emscripten:
81 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46 77 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 break; 130 break;
135 case TypeCategory::DOUBLE: 131 case TypeCategory::DOUBLE:
136 signature += 'd'; 132 signature += 'd';
137 break; 133 break;
138 default: 134 default:
139 throw std::runtime_error("Unexpected function argument type"); 135 throw std::runtime_error("Unexpected function argument type");
140 } 136 }
141 args.push_back(type); 137 args.push_back(type);
142 } 138 }
143 139
144 get_function_name(function, signature.c_str()); 140 int nameLength = GetFunctionName(nullptr, function, signature.c_str());
141 name.resize(nameLength);
142 GetFunctionName(name.data(), function, signature.c_str());
sergei 2017/05/08 09:16:29 if std::string::data() returns only a const pointe
Wladimir Palant 2017/05/08 10:17:18 Oh, so the C++ standard in its most recent iterati
145 } 143 }
146 144
147 bool FunctionInfo::empty() const 145 bool FunctionInfo::empty() const
148 { 146 {
149 return name[0] == '\0'; 147 return name.size() == 0;
150 }
151
152 void FunctionInfo::get_function_name(void* ptr, const char* signature)
153 {
154 // This is a hack, C++ won't let us get the mangled function name.
155 // JavaScript is more dynamic so we pass the pointer to our function
156 // there. With that and the function signature we can call the function -
157 // with a full stack so that we will cause it to abort. Sometimes the
158 // function we are calling will also be missing from the build. The result
159 // is the same: abort() is called which in turn calls stackTrace(). By
160 // replacing stackTrace() we get access to the call stack and search it
161 // for the name of our function.
162
163 EM_ASM_ARGS({
164 var signature = AsciiToString($2);
165 var args = [];
166 for (var i = 1; i < signature.length; i++)
167 args.push(0);
168
169 var oldPrint = Module.print;
170 var oldPrintErr = Module.printErr;
171 var oldStackTrace = stackTrace;
172 var sp = Runtime.stackSave();
173 Module.print = function(){};
174 Module.printErr = function(){};
175 stackTrace = function()
176 {
177 var stack = [];
178 for (var f = arguments.callee.caller; f; f = f.caller)
179 {
180 if (f.name)
181 {
182 if (f.name.indexOf("dynCall") == 0)
183 break;
184 else
185 stack.push(f.name);
186 }
187 }
188
189 result = stack[stack.length - 1];
190 if (result && result.indexOf("__wrapper") >= 0)
191 result = stack[stack.length - 2];
192 throw result;
193 };
194
195 Runtime.stackRestore(STACK_MAX);
196
197 try
198 {
199 Runtime.dynCall(signature, HEAP32[$1 >> 2], args);
200 }
201 catch(e)
202 {
203 Module.stringToAscii(e, $0);
204 }
205 finally
206 {
207 Runtime.stackRestore(sp);
208 Module.print = oldPrint;
209 Module.printErr = oldPrintErr;
210 stackTrace = oldStackTrace;
211 }
212 }, name, ptr, signature);
213 } 148 }
214 149
215 ClassInfo* find_class(TYPEID classID) 150 ClassInfo* find_class(TYPEID classID)
216 { 151 {
217 for (auto& classInfo : classes) 152 for (auto& classInfo : classes)
218 if (classInfo.id == classID) 153 if (classInfo.id == classID)
219 return &classInfo; 154 return &classInfo;
220 return nullptr; 155 return nullptr;
221 } 156 }
222 157
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 265
331 std::string generateCall(const FunctionInfo& call, 266 std::string generateCall(const FunctionInfo& call,
332 std::vector<std::string>& params) 267 std::vector<std::string>& params)
333 { 268 {
334 if (call.returnType == TypeCategory::DEPENDENT_STRING || 269 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
335 call.returnType == TypeCategory::OWNED_STRING) 270 call.returnType == TypeCategory::OWNED_STRING)
336 { 271 {
337 params.insert(params.begin(), "string"); 272 params.insert(params.begin(), "string");
338 } 273 }
339 274
340 std::string call_str(call.name); 275 std::string call_str(call.name.data());
341 call_str += "("; 276 call_str += "(";
342 for (int i = 0; i < params.size(); i++) 277 for (int i = 0; i < params.size(); i++)
343 { 278 {
344 if (i > 0) 279 if (i > 0)
345 call_str += ", "; 280 call_str += ", ";
346 call_str += params[i]; 281 call_str += params[i];
347 } 282 }
348 call_str += ")"; 283 call_str += ")";
349 284
350 switch (call.returnType) 285 switch (call.returnType)
(...skipping 23 matching lines...) Expand all
374 return " var result = readString(" + call_str + ");\n"; 309 return " var result = readString(" + call_str + ");\n";
375 case TypeCategory::CLASS_PTR: 310 case TypeCategory::CLASS_PTR:
376 { 311 {
377 std::string result; 312 std::string result;
378 result += " var result = " + call_str + ";\n"; 313 result += " var result = " + call_str + ";\n";
379 result += " if (result)\n"; 314 result += " if (result)\n";
380 result += " {\n"; 315 result += " {\n";
381 316
382 const ClassInfo* cls = find_class(call.pointerType); 317 const ClassInfo* cls = find_class(call.pointerType);
383 if (!cls) 318 if (!cls)
384 throw std::runtime_error("Function " + std::string(call.name) + " retu rns pointer to unknown class"); 319 throw std::runtime_error("Function " + std::string(call.name.data()) + " returns pointer to unknown class");
385 320
386 auto offset = cls->subclass_differentiator.offset; 321 auto offset = cls->subclass_differentiator.offset;
387 if (offset == SIZE_MAX) 322 if (offset == SIZE_MAX)
388 result += " result = exports." + cls->name + "(result);\n"; 323 result += " result = exports." + cls->name + "(result);\n";
389 else 324 else
390 result += " result = exports." + cls->name + ".fromPointer(result); \n"; 325 result += " result = exports." + cls->name + ".fromPointer(result); \n";
391 326
392 result += " }\n"; 327 result += " }\n";
393 result += " else\n"; 328 result += " else\n";
394 result += " result = null;\n"; 329 result += " result = null;\n";
395 return result; 330 return result;
396 } 331 }
397 default: 332 default:
398 throw std::runtime_error("Unexpected return type for " + std::string(cal l.name)); 333 throw std::runtime_error("Unexpected return type for " + std::string(cal l.name.data()));
399 } 334 }
400 } 335 }
401 336
402 std::string wrapCall(const FunctionInfo& call, bool isFunction) 337 std::string wrapCall(const FunctionInfo& call, bool isFunction)
403 { 338 {
404 bool hasStringArgs = false; 339 bool hasStringArgs = false;
405 std::vector<std::string> params; 340 std::vector<std::string> params;
406 std::string prefix; 341 std::string prefix;
407 342
408 if (isFunction) 343 if (isFunction)
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 499
565 void printBindings() 500 void printBindings()
566 { 501 {
567 bindings_internal::printHelpers(); 502 bindings_internal::printHelpers();
568 503
569 for (const auto& item : classes) 504 for (const auto& item : classes)
570 bindings_internal::printClass(item); 505 bindings_internal::printClass(item);
571 for (const auto& item : namespaces) 506 for (const auto& item : namespaces)
572 bindings_internal::printNamespace(item); 507 bindings_internal::printNamespace(item);
573 } 508 }
OLDNEW

Powered by Google App Engine
This is Rietveld