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

Delta Between Two Patch Sets: compiled/bindings.ipp

Issue 29404594: Noissue - [emscripten] Replace sprintf() usage by safe alternatives (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Left Patch Set: Created April 6, 2017, 8:40 a.m.
Right Patch Set: Implemented a simple number conversion method Created April 6, 2017, 3:12 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/String.h ('k') | compiled/filter/ActiveFilter.cpp » ('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
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 #pragma once 18 #pragma once
19 19
20 #include <cstddef> 20 #include <cstddef>
21 #include <cstdint> 21 #include <cstdint>
22 #include <cstdio> 22 #include <cstdio>
23 #include <cstdlib> 23 #include <cstdlib>
24 #include <exception> 24 #include <exception>
25 #include <functional>
26 #include <map> 25 #include <map>
27 #include <string> 26 #include <string>
28 #include <type_traits> 27 #include <type_traits>
29 #include <utility> 28 #include <utility>
30 #include <vector> 29 #include <vector>
31 30
32 #include <emscripten.h> 31 #include <emscripten.h>
33 32
34 #include "String.h" 33 #include "String.h"
35 #include "intrusive_ptr.h" 34 #include "intrusive_ptr.h"
36 35
37 namespace bindings_internal 36 namespace bindings_internal
38 { 37 {
39 typedef void* TYPEID; 38 typedef void* TYPEID;
40 39
41 enum class TypeCategory 40 enum class TypeCategory
42 { 41 {
43 UNKNOWN, 42 UNKNOWN,
44 VOID, 43 VOID,
45 INT, 44 INT,
46 FLOAT,
47 DEPENDENT_STRING, 45 DEPENDENT_STRING,
48 OWNED_STRING, 46 OWNED_STRING,
49 STRING_REF, 47 STRING_REF,
50 CLASS_PTR 48 CLASS_PTR
51 }; 49 };
52 50
53 template<typename T> 51 template<typename T>
54 struct TypeInfo 52 struct TypeInfo
55 { 53 {
56 /* 54 /*
(...skipping 11 matching lines...) Expand all
68 } 66 }
69 67
70 constexpr operator TypeCategory() const 68 constexpr operator TypeCategory() const
71 { 69 {
72 if (std::is_void<T>()) 70 if (std::is_void<T>())
73 return TypeCategory::VOID; 71 return TypeCategory::VOID;
74 72
75 if (std::is_integral<T>() || std::is_enum<T>()) 73 if (std::is_integral<T>() || std::is_enum<T>())
76 return TypeCategory::INT; 74 return TypeCategory::INT;
77 75
78 if (std::is_floating_point<T>())
79 return TypeCategory::FLOAT;
80
81 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>()) 76 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>())
82 return TypeCategory::DEPENDENT_STRING; 77 return TypeCategory::DEPENDENT_STRING;
83 78
84 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() ) 79 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() )
85 return TypeCategory::OWNED_STRING; 80 return TypeCategory::OWNED_STRING;
86 81
87 if (std::is_same<String&, T>() || std::is_same<const String&, T>() || 82 if (std::is_same<String&, T>() || std::is_same<const String&, T>() ||
88 std::is_same<DependentString&, T>()) 83 std::is_same<DependentString&, T>())
89 { 84 {
90 return TypeCategory::STRING_REF; 85 return TypeCategory::STRING_REF;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 instance_function(instance_function) 125 instance_function(instance_function)
131 { 126 {
132 name[0] = '\0'; 127 name[0] = '\0';
133 128
134 // The function parameter is a pointer to the function pointer. 129 // The function parameter is a pointer to the function pointer.
135 // Emscripten's "function pointers" are actually integers indicating the 130 // Emscripten's "function pointers" are actually integers indicating the
136 // position in the call table. 0 represents nullptr. 131 // position in the call table. 0 represents nullptr.
137 if (!*reinterpret_cast<int*>(function)) 132 if (!*reinterpret_cast<int*>(function))
138 return; 133 return;
139 134
140 char signature[256]; 135 for (const auto& item : argTypes)
141 int pos = 0; 136 {
137 if (item != TypeCategory::INT && item != TypeCategory::STRING_REF &&
138 item != TypeCategory::CLASS_PTR)
139 {
140 throw std::runtime_error("Unexpected function argument type");
141 }
142 args.push_back(item);
143 }
144
145 if (returnType != TypeCategory::VOID && returnType != TypeCategory::INT &&
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
142 if (returnType == TypeCategory::DEPENDENT_STRING || 159 if (returnType == TypeCategory::DEPENDENT_STRING ||
143 returnType == TypeCategory::OWNED_STRING) 160 returnType == TypeCategory::OWNED_STRING)
144 { 161 {
145 // Objects aren't really returned but passed as parameter. Note that 162 effectiveArgs++;
146 // this pointer might come before it but we don't care because both 163 effectiveReturnType = TypeCategory::VOID;
147 // are integers (pointers) as far as Emscripten is concerned. 164 }
148 signature[pos++] = 'v'; 165
149 signature[pos++] = 'i'; 166 get_function_name(function, effectiveArgs,
150 } 167 effectiveReturnType == TypeCategory::VOID);
151 else if (returnType == TypeCategory::VOID)
152 signature[pos++] = 'v';
153 else if (returnType == TypeCategory::FLOAT)
154 signature[pos++] = 'd';
155 else if (returnType == TypeCategory::INT ||
156 returnType == TypeCategory::STRING_REF ||
157 returnType == TypeCategory::CLASS_PTR)
158 {
159 signature[pos++] = 'i';
160 }
161 else
162 throw std::runtime_error("Unexpected function return type");
163
164 if (instance_function)
165 {
166 // this pointer is an implicit parameter
167 signature[pos++] = 'i';
168 }
169
170 for (const auto& item : argTypes)
171 {
172 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF ||
173 item == TypeCategory::CLASS_PTR)
174 {
175 signature[pos++] = 'i';
176 }
177 else if (item == TypeCategory::FLOAT)
178 signature[pos++] = 'd';
179 else
180 throw std::runtime_error("Unexpected function argument type");
181 args.push_back(item);
182 }
183
184 signature[pos] = 0;
185
186 get_function_name(function, signature);
187 } 168 }
188 169
189 template<typename ReturnType, typename... Args> 170 template<typename ReturnType, typename... Args>
190 FunctionInfo(ReturnType (*function)(Args...)) 171 FunctionInfo(ReturnType (*function)(Args...))
191 : FunctionInfo(TypeInfo<ReturnType>(), 172 : FunctionInfo(TypeInfo<ReturnType>(),
192 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, 173 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false,
193 &function) 174 &function)
194 { 175 {
195 } 176 }
196 177
(...skipping 11 matching lines...) Expand all
208 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, 189 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true,
209 &function) 190 &function)
210 { 191 {
211 } 192 }
212 193
213 bool empty() const 194 bool empty() const
214 { 195 {
215 return name[0] == '\0'; 196 return name[0] == '\0';
216 } 197 }
217 198
218 void get_function_name(void* ptr, char* signature) 199 void get_function_name(void* ptr, int numArgs, bool voidResult)
219 { 200 {
220 // This is a hack, C++ won't let us get the mangled function name. 201 // 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 202 // 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 - 203 // 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 204 // 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 205 // 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 206 // 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 207 // replacing stackTrace() we get access to the call stack and search it
227 // for the name of our function. 208 // for the name of our function.
228 209
229 EM_ASM_ARGS({ 210 EM_ASM_ARGS({
230 var signature = AsciiToString($2); 211 var signature = $3 ? "v" : "i";
231 var args = []; 212 var args = [];
232 for (var i = 1; i < signature.length; i++) 213 for (var i = 0; i < $2; i++)
214 {
215 signature += "i";
233 args.push(0); 216 args.push(0);
217 }
234 218
235 var oldPrint = Module.print; 219 var oldPrint = Module.print;
236 var oldPrintErr = Module.printErr; 220 var oldPrintErr = Module.printErr;
237 var oldStackTrace = stackTrace; 221 var oldStackTrace = stackTrace;
238 var sp = Runtime.stackSave(); 222 var sp = Runtime.stackSave();
239 Module.print = function(){}; 223 Module.print = function(){};
240 Module.printErr = function(){}; 224 Module.printErr = function(){};
241 stackTrace = function() 225 stackTrace = function()
242 { 226 {
243 var stack = []; 227 var stack = [];
(...skipping 24 matching lines...) Expand all
268 { 252 {
269 Module.stringToAscii(e, $0); 253 Module.stringToAscii(e, $0);
270 } 254 }
271 finally 255 finally
272 { 256 {
273 Runtime.stackRestore(sp); 257 Runtime.stackRestore(sp);
274 Module.print = oldPrint; 258 Module.print = oldPrint;
275 Module.printErr = oldPrintErr; 259 Module.printErr = oldPrintErr;
276 stackTrace = oldStackTrace; 260 stackTrace = oldStackTrace;
277 } 261 }
278 }, name, ptr, signature); 262 }, name, ptr, numArgs, voidResult);
279 } 263 }
280 }; 264 };
281 265
282 class NoBaseClass 266 class NoBaseClass
283 { 267 {
284 }; 268 };
285 269
286 struct PropertyInfo 270 struct PropertyInfo
287 { 271 {
288 std::string name; 272 std::string name;
(...skipping 13 matching lines...) Expand all
302 size_t offset; 286 size_t offset;
303 std::vector<std::pair<int, std::string>> mapping; 287 std::vector<std::pair<int, std::string>> mapping;
304 }; 288 };
305 289
306 struct ClassInfo 290 struct ClassInfo
307 { 291 {
308 ClassInfo* baseClass; 292 ClassInfo* baseClass;
309 std::string name; 293 std::string name;
310 std::vector<PropertyInfo> properties; 294 std::vector<PropertyInfo> properties;
311 std::vector<MethodInfo> methods; 295 std::vector<MethodInfo> methods;
296 std::vector<FunctionInfo> initializers;
312 DifferentiatorInfo subclass_differentiator; 297 DifferentiatorInfo subclass_differentiator;
313 ptrdiff_t ref_counted_offset; 298 ptrdiff_t ref_counted_offset;
314 }; 299 };
315 300
316 typedef std::function<void()> CustomGenerator;
317
318 std::map<TYPEID, ClassInfo> classes; 301 std::map<TYPEID, ClassInfo> classes;
319 std::vector<CustomGenerator> customGenerators;
320 302
321 void register_class(const char* name, TYPEID classID, TYPEID baseClassID, 303 void register_class(const char* name, TYPEID classID, TYPEID baseClassID,
322 ptrdiff_t ref_counted_offset) 304 ptrdiff_t ref_counted_offset)
323 { 305 {
324 auto it = classes.find(classID); 306 auto it = classes.find(classID);
325 if (it != classes.end()) 307 if (it != classes.end())
326 throw std::runtime_error(std::string("Duplicate definition for class ") + name); 308 throw std::runtime_error(std::string("Duplicate definition for class ") + name);
327 309
328 ClassInfo* baseClass = nullptr; 310 ClassInfo* baseClass = nullptr;
329 if (baseClassID != TypeInfo<NoBaseClass>()) 311 if (baseClassID != TypeInfo<NoBaseClass>())
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 auto it = classes.find(classID); 346 auto it = classes.find(classID);
365 if (it == classes.end()) 347 if (it == classes.end())
366 throw std::runtime_error(std::string("Method defined on unknown class: ") + name); 348 throw std::runtime_error(std::string("Method defined on unknown class: ") + name);
367 349
368 MethodInfo methodInfo; 350 MethodInfo methodInfo;
369 methodInfo.name = name; 351 methodInfo.name = name;
370 methodInfo.call = call; 352 methodInfo.call = call;
371 it->second.methods.push_back(methodInfo); 353 it->second.methods.push_back(methodInfo);
372 } 354 }
373 355
356 void register_initializer(TYPEID classID, const FunctionInfo& call)
357 {
358 auto it = classes.find(classID);
359 if (it == classes.end())
360 throw std::runtime_error("Initializer defined on unknown class");
361
362 it->second.initializers.push_back(call);
363 }
364
374 void register_differentiator(TYPEID classID, size_t offset, 365 void register_differentiator(TYPEID classID, size_t offset,
375 std::vector<std::pair<int, std::string>>& mapping) 366 std::vector<std::pair<int, std::string>>& mapping)
376 { 367 {
377 auto it = classes.find(classID); 368 auto it = classes.find(classID);
378 if (it == classes.end()) 369 if (it == classes.end())
379 throw std::runtime_error("Subclass differentiator defined on unknown class "); 370 throw std::runtime_error("Subclass differentiator defined on unknown class ");
380 371
381 if (it->second.subclass_differentiator.offset != SIZE_MAX) 372 if (it->second.subclass_differentiator.offset != SIZE_MAX)
382 throw std::runtime_error("More than one subclass differentiator defined fo r class " + it->second.name); 373 throw std::runtime_error("More than one subclass differentiator defined fo r class " + it->second.name);
383 374
(...skipping 17 matching lines...) Expand all
401 for (int i = 0; i < params.size(); i++) 392 for (int i = 0; i < params.size(); i++)
402 { 393 {
403 if (i > 0) 394 if (i > 0)
404 call_str += ", "; 395 call_str += ", ";
405 call_str += params[i]; 396 call_str += params[i];
406 } 397 }
407 call_str += ")"; 398 call_str += ")";
408 399
409 if (call.returnType == TypeCategory::VOID) 400 if (call.returnType == TypeCategory::VOID)
410 return " " + call_str + ";\n"; 401 return " " + call_str + ";\n";
411 else if (call.returnType == TypeCategory::INT || 402 else if (call.returnType == TypeCategory::INT)
412 call.returnType == TypeCategory::FLOAT)
413 {
414 return " var result = " + call_str + ";\n"; 403 return " var result = " + call_str + ";\n";
415 }
416 else if (call.returnType == TypeCategory::DEPENDENT_STRING || 404 else if (call.returnType == TypeCategory::DEPENDENT_STRING ||
417 call.returnType == TypeCategory::OWNED_STRING) 405 call.returnType == TypeCategory::OWNED_STRING)
418 { 406 {
419 std::string result; 407 std::string result;
420 result += " var string = createString();\n"; 408 result += " var string = createString();\n";
421 result += " " + call_str + ";\n"; 409 result += " " + call_str + ";\n";
422 result += " var result = readString(string);\n"; 410 result += " var result = readString(string);\n";
423 if (call.returnType == TypeCategory::OWNED_STRING) 411 if (call.returnType == TypeCategory::OWNED_STRING)
424 result += " Module._DestroyString(string);\n"; 412 result += " Module._DestroyString(string);\n";
425 return result; 413 return result;
426 } 414 }
427 else if (call.returnType == TypeCategory::STRING_REF) 415 else if (call.returnType == TypeCategory::STRING_REF)
428 { 416 {
429 return " var result = readString(" + call_str + ");\n"; 417 return " var result = readString(" + call_str + ");\n";
430 } 418 }
431 else if (call.returnType == TypeCategory::CLASS_PTR) 419 else if (call.returnType == TypeCategory::CLASS_PTR)
432 { 420 {
433 std::string result; 421 std::string result;
434 result += " var result = " + call_str + ";\n"; 422 result += " var result = " + call_str + ";\n";
435 result += " if (result)\n"; 423 result += " if (result)\n";
436 result += " {\n"; 424 result += " {\n";
437 425
438 auto it = classes.find(call.pointerType); 426 auto it = classes.find(call.pointerType);
439 if (it == classes.end()) 427 if (it == classes.end())
440 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class"); 428 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class");
441 429
442 const ClassInfo& cls = it->second; 430 const ClassInfo& cls = it->second;
443 auto offset = cls.subclass_differentiator.offset; 431 auto offset = cls.subclass_differentiator.offset;
444 if (offset == SIZE_MAX) 432 if (offset == SIZE_MAX)
445 result += " result = exports." + cls.name + "(result);\n"; 433 result += " result = " + cls.name + "(result);\n";
446 else 434 else
447 result += " result = exports." + cls.name + ".fromPointer(result);\n" ; 435 {
436 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n";
437 result += " if (type in " + cls.name + "_mapping)\n";
438 result += " result = new (exports[" + cls.name + "_mapping[type]])( result);\n";
439 result += " else\n";
440 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n";
441 }
448 442
449 result += " }\n"; 443 result += " }\n";
450 result += " else\n";
451 result += " result = null;\n";
452 return result; 444 return result;
453 } 445 }
454 else 446 else
455 throw std::runtime_error("Unexpected return type for " + std::string(call. name)); 447 throw std::runtime_error("Unexpected return type for " + std::string(call. name));
456 } 448 }
457 449
458 const std::string wrapCall(const FunctionInfo& call) 450 const std::string wrapCall(const FunctionInfo& call)
459 { 451 {
460 bool hasStringArgs = false; 452 bool hasStringArgs = false;
461 std::vector<std::string> params; 453 std::vector<std::string> params;
462 std::string prefix = "function("; 454 std::string prefix = "function(";
463 for (int i = 0; i < call.args.size(); i++) 455 for (int i = 0; i < call.args.size(); i++)
464 { 456 {
465 std::string argName("arg" + std::to_string(i)); 457 std::string argName("arg" + std::to_string(i));
466 if (i > 0) 458 if (i > 0)
467 prefix += ", "; 459 prefix += ", ";
468 prefix += argName; 460 prefix += argName;
469 461
470 if (call.args[i] == TypeCategory::STRING_REF) 462 if (call.args[i] == TypeCategory::STRING_REF)
471 { 463 {
472 hasStringArgs = true; 464 hasStringArgs = true;
473 params.push_back(std::string("createString(") + argName + ")"); 465 params.push_back(std::string("createString(") + argName + ")");
474 } 466 }
475 else if (call.args[i] == TypeCategory::CLASS_PTR)
476 params.push_back(argName + "._pointer");
477 else 467 else
478 params.push_back(argName); 468 params.push_back(argName);
479 } 469 }
480 prefix += ")\n{\n"; 470 prefix += ")\n{\n";
481 471
482 std::string suffix = "}"; 472 std::string suffix = "}";
483 if (call.returnType != TypeCategory::VOID) 473 if (call.returnType != TypeCategory::VOID)
484 suffix = " return result;\n" + suffix; 474 suffix = " return result;\n" + suffix;
485 475
486 if (call.returnType == TypeCategory::DEPENDENT_STRING || 476 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 { 544 {
555 Module._ReleaseRef(this._pointer + ref_counted_offset); 545 Module._ReleaseRef(this._pointer + ref_counted_offset);
556 }; 546 };
557 return result; 547 return result;
558 } 548 }
559 )"); 549 )");
560 } 550 }
561 551
562 void printClass(const ClassInfo& cls) 552 void printClass(const ClassInfo& cls)
563 { 553 {
564 printf("exports.%s = createClass(%s, %i);\n", cls.name.c_str(),
565 (cls.baseClass ? ("exports." + cls.baseClass->name).c_str() : "null"),
566 cls.ref_counted_offset);
567
568 DifferentiatorInfo differentiator = cls.subclass_differentiator; 554 DifferentiatorInfo differentiator = cls.subclass_differentiator;
569 if (differentiator.offset != SIZE_MAX) 555 if (differentiator.offset != SIZE_MAX)
570 { 556 {
571 printf("var %s_mapping = \n", cls.name.c_str()); 557 printf("var %s_mapping = \n", cls.name.c_str());
572 puts("{"); 558 puts("{");
573 for (const auto& item : differentiator.mapping) 559 for (const auto& item : differentiator.mapping)
574 printf(" %i: '%s',\n", item.first, item.second.c_str()); 560 printf(" %i: '%s',\n", item.first, item.second.c_str());
575 puts("};"); 561 puts("};");
576 562 }
577 printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); 563
578 puts("{"); 564 printf("exports.%s = createClass(%s, %i);\n", cls.name.c_str(),
579 printf(" var type = HEAP32[ptr + %i >> 2];\n", differentiator.offset); 565 (cls.baseClass ? ("exports." + cls.baseClass->name).c_str() : "null"),
580 printf(" if (type in %s_mapping)\n", cls.name.c_str()); 566 cls.ref_counted_offset);
581 printf(" return new (exports[%s_mapping[type]])(ptr);\n", cls.name.c_st r());
582 printf(" throw new Error('Unexpected %s type: ' + type);\n", cls.name.c_s tr());
583 puts("};");
584 }
585 else
586 {
587 printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str());
588 puts("{");
589 printf(" return new exports.%s(ptr);\n", cls.name.c_str());
590 puts("};");
591 }
592 567
593 for (const auto& item : cls.properties) 568 for (const auto& item : cls.properties)
594 { 569 {
595 printf("Object.defineProperty(exports.%s.prototype, '%s', {%s});\n", 570 printf("Object.defineProperty(exports.%s.prototype, '%s', {%s});\n",
596 cls.name.c_str(), item.name.c_str(), 571 cls.name.c_str(), item.name.c_str(),
597 generatePropertyDescriptor(item).c_str()); 572 generatePropertyDescriptor(item).c_str());
598 } 573 }
599 574
600 for (const auto& item : cls.methods) 575 for (const auto& item : cls.methods)
601 { 576 {
602 std::string obj("exports." + cls.name); 577 std::string obj("exports." + cls.name);
603 if (item.call.instance_function) 578 if (item.call.instance_function)
604 obj += ".prototype"; 579 obj += ".prototype";
605 printf("%s.%s = %s;\n", obj.c_str(), item.name.c_str(), 580 printf("%s.%s = %s;\n", obj.c_str(), item.name.c_str(),
606 wrapCall(item.call).c_str()); 581 wrapCall(item.call).c_str());
607 } 582 }
583
584 for (const auto& item : cls.initializers)
585 printf("%s()\n", item.name);
608 } 586 }
609 587
610 void printBindings() 588 void printBindings()
611 { 589 {
612 printHelpers(); 590 printHelpers();
613 591
614 for (const auto& item : classes) 592 for (const auto& item : classes)
615 printClass(item.second); 593 printClass(item.second);
616
617 for (const auto& item : customGenerators)
618 item();
619 } 594 }
620 } 595 }
621 596
622 #if defined(PRINT_BINDINGS) 597 #if defined(PRINT_BINDINGS)
623 // Bindings generation step: collect bindings information and print 598 // Bindings generation step: collect bindings information and print
624 // corresponding JS code. 599 // corresponding JS code.
625 #define EMSCRIPTEN_BINDINGS \ 600 #define EMSCRIPTEN_BINDINGS \
626 void InitializeBindings();\ 601 struct BindingsInitializer {\
627 int main()\ 602 BindingsInitializer();\
628 {\ 603 BindingsInitializer(bool dummy)\
629 try\ 604 {\
630 {\ 605 try\
631 InitializeBindings();\ 606 {\
632 bindings_internal::printBindings();\ 607 BindingsInitializer();\
633 }\ 608 bindings_internal::printBindings();\
634 catch (const std::exception& e)\ 609 }\
635 {\ 610 catch (const std::exception& e)\
636 EM_ASM_ARGS(\ 611 {\
637 console.error("Error occurred generating JavaScript bindings: " +\ 612 EM_ASM_ARGS(\
638 Module.AsciiToString($0)), e.what()\ 613 console.error("Error occurred generating JavaScript bindings: " +\
639 );\ 614 Module.AsciiToString($0)), e.what()\
640 abort();\ 615 );\
641 }\ 616 abort();\
642 return 0;\ 617 }\
643 }\ 618 }\
644 void InitializeBindings() 619 } BindingsInitializer_instance(true);\
620 BindingsInitializer::BindingsInitializer()
645 #else 621 #else
646 // Actual compilation step: ignore bindings information but define some 622 // Actual compilation step: ignore bindings information but define some
647 // exported helper functions necessary for the bindings. 623 // exported helper functions necessary for the bindings.
648 #define EMSCRIPTEN_BINDINGS \ 624 #define EMSCRIPTEN_BINDINGS \
649 extern "C"\ 625 extern "C"\
650 {\ 626 {\
651 void EMSCRIPTEN_KEEPALIVE InitString(DependentString* str,\ 627 void EMSCRIPTEN_KEEPALIVE InitString(DependentString* str,\
652 String::value_type* data, String::size_type len)\ 628 String::value_type* data, String::size_type len)\
653 {\ 629 {\
654 /* String is already allocated on stack, we merely need to call*/\ 630 /* String is already allocated on stack, we merely need to call*/\
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 } 711 }
736 712
737 template<typename ReturnType, typename... Args> 713 template<typename ReturnType, typename... Args>
738 const class_& class_function(const char* name, ReturnType (*method)(Args...)) const 714 const class_& class_function(const char* name, ReturnType (*method)(Args...)) const
739 { 715 {
740 bindings_internal::register_method( 716 bindings_internal::register_method(
741 bindings_internal::TypeInfo<ClassType>(), name, method); 717 bindings_internal::TypeInfo<ClassType>(), name, method);
742 return *this; 718 return *this;
743 } 719 }
744 720
721 const class_& class_initializer(void (*function)()) const
722 {
723 bindings_internal::register_initializer(
724 bindings_internal::TypeInfo<ClassType>(), function);
725 return *this;
726 }
727
745 template<typename ReturnType, 728 template<typename ReturnType,
746 typename std::enable_if<std::is_convertible<ReturnType, int32_t>::value>:: type* = nullptr> 729 typename std::enable_if<std::is_convertible<ReturnType, int32_t>::value>:: type* = nullptr>
747 const class_& subclass_differentiator(ReturnType ClassType::* member, 730 const class_& subclass_differentiator(ReturnType ClassType::* member,
748 std::initializer_list<std::pair<ReturnType, const char*>> list) const 731 std::initializer_list<std::pair<ReturnType, const char*>> list) const
749 { 732 {
750 ClassType* instance = nullptr; 733 ClassType* instance = nullptr;
751 size_t offset = (char*)&(instance->*member) - (char*)instance; 734 size_t offset = (char*)&(instance->*member) - (char*)instance;
752 735
753 std::vector<std::pair<int, std::string>> mapping; 736 std::vector<std::pair<int, std::string>> mapping;
754 for (const auto& item : list) 737 for (const auto& item : list)
755 mapping.emplace_back(item.first, item.second); 738 mapping.emplace_back(item.first, item.second);
756 739
757 bindings_internal::register_differentiator( 740 bindings_internal::register_differentiator(
758 bindings_internal::TypeInfo<ClassType>(), offset, mapping); 741 bindings_internal::TypeInfo<ClassType>(), offset, mapping);
759 return *this; 742 return *this;
760 } 743 }
761 }; 744 };
762
763 void custom_generator(bindings_internal::CustomGenerator generator)
764 {
765 bindings_internal::customGenerators.push_back(generator);
766 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld