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

Delta Between Two Patch Sets: compiled/bindings.ipp

Issue 29333474: Issue 4125 - [emscripten] Convert filter classes to C++ (Closed)
Left Patch Set: Got rid of extra output in bindings.js file Created June 9, 2016, 1:35 p.m.
Right Patch Set: Addressed comments from Patch Set 28 Created March 21, 2017, 10:04 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/debug.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 #pragma once 1 #pragma once
sergei 2016/06/16 21:16:53 Why does it not print 'use strict;'?
sergei 2016/06/16 21:16:57 Why are "-1" at the beginning of compiled/bindings
sergei 2016/06/16 21:17:08 I don't think that it is worth paying attention to
Wladimir Palant 2016/12/06 10:47:55 The bindings are only a small part of the resultin
Wladimir Palant 2016/12/06 10:48:12 That's output from an abort() call not being suppr
2 2
3 #include <cstddef>
4 #include <cstdint>
3 #include <cstdio> 5 #include <cstdio>
4 #include <cstdlib> 6 #include <cstdlib>
5 #include <cstring>
6 #include <exception> 7 #include <exception>
7 #include <map> 8 #include <map>
8 #include <string> 9 #include <string>
9 #include <type_traits> 10 #include <type_traits>
10 #include <utility> 11 #include <utility>
11 #include <vector> 12 #include <vector>
sergei 2016/06/16 21:16:50 What do you think about excluding std classes from
Wladimir Palant 2016/12/06 10:48:00 Headers don't result in any code, they are merely
12 13
13 #include <emscripten.h> 14 #include <emscripten.h>
14 15
15 #include "String.h" 16 #include "String.h"
16 #include "intrusive_ptr.h" 17 #include "intrusive_ptr.h"
17 18
18 namespace bindings_internal 19 namespace bindings_internal
sergei 2016/06/16 21:17:05 It would be good to have some comment here which e
Wladimir Palant 2016/12/06 10:47:52 With the approach changing with each iteration, I
19 { 20 {
20 typedef void* TYPEID; 21 typedef void* TYPEID;
21 22
22 enum class TypeCategory 23 enum class TypeCategory
23 { 24 {
24 UNKNOWN, 25 UNKNOWN,
25 VOID, 26 VOID,
26 INT, 27 INT,
27 DEPENDENT_STRING, 28 DEPENDENT_STRING,
28 OWNED_STRING, 29 OWNED_STRING,
29 STRING_REF, 30 STRING_REF,
30 CLASS_PTR 31 CLASS_PTR
31 }; 32 };
32 33
33 template<typename T> 34 template<typename T>
34 struct TypeInfo 35 struct TypeInfo
35 { 36 {
36 static char c; 37 /*
sergei 2016/06/16 21:17:10 I think it would be better to call it something li
Wladimir Palant 2016/12/06 10:47:59 Done.
38 * Since TypeInfo is a templated type, in practice the compiler will define
39 * a new type for each possible template parameter value. We use that fact
40 * to generate type identifiers: each of these TypeInfo types has a
41 * different s_typeIDHelper member, so we use a pointer to that static
42 * variable as a type identifier - it will be different for each template
43 * parameter.
44 */
45 static char s_typeIDHelper;
37 constexpr operator TYPEID() const 46 constexpr operator TYPEID() const
38 { 47 {
39 return &c; 48 return &s_typeIDHelper;
40 } 49 }
41 50
42 constexpr operator TypeCategory() const 51 constexpr operator TypeCategory() const
43 { 52 {
44 if (std::is_void<T>()) 53 if (std::is_void<T>())
45 return TypeCategory::VOID; 54 return TypeCategory::VOID;
46 55
47 if (std::is_integral<T>() || std::is_enum<T>()) 56 if (std::is_integral<T>() || std::is_enum<T>())
48 return TypeCategory::INT; 57 return TypeCategory::INT;
49 58
50 if (std::is_same<DependentString,T>() || std::is_same<const DependentStrin g,T>()) 59 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>())
51 return TypeCategory::DEPENDENT_STRING; 60 return TypeCategory::DEPENDENT_STRING;
52 61
53 if (std::is_same<OwnedString,T>() || std::is_same<const OwnedString,T>()) 62 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() )
54 return TypeCategory::OWNED_STRING; 63 return TypeCategory::OWNED_STRING;
55 64
56 if (std::is_same<String&,T>() || std::is_same<const String&,T>() || 65 if (std::is_same<String&, T>() || std::is_same<const String&, T>() ||
57 std::is_same<DependentString&,T>()) 66 std::is_same<DependentString&, T>())
58 { 67 {
59 return TypeCategory::STRING_REF; 68 return TypeCategory::STRING_REF;
60 } 69 }
61 70
62 if (std::is_pointer<T>() && std::is_class<typename std::remove_pointer<T>: :type>()) 71 if (std::is_pointer<T>() && std::is_class<typename std::remove_pointer<T>: :type>())
63 return TypeCategory::CLASS_PTR; 72 return TypeCategory::CLASS_PTR;
64 73
65 return TypeCategory::UNKNOWN; 74 return TypeCategory::UNKNOWN;
66 } 75 }
67 76
68 TYPEID pointer_type() const 77 constexpr TYPEID pointer_type() const
sergei 2016/06/16 21:16:51 Actually it might be makes sense to make the metho
Wladimir Palant 2016/12/06 10:47:42 Done.
69 { 78 {
70 if (std::is_pointer<T>()) 79 if (std::is_pointer<T>())
71 return TypeInfo<typename std::remove_pointer<T>::type>(); 80 return TypeInfo<typename std::remove_pointer<T>::type>();
72 else 81 else
73 return nullptr; 82 return nullptr;
74 } 83 }
75 }; 84 };
76 85
77 template<typename T> 86 template<typename T>
78 char TypeInfo<T>::c; 87 char TypeInfo<T>::s_typeIDHelper;
79 88
80 struct FunctionInfo 89 struct FunctionInfo
81 { 90 {
82 TypeCategory returnType; 91 TypeCategory returnType;
83 TYPEID pointerType; 92 TYPEID pointerType;
84 std::vector<TypeCategory> args; 93 std::vector<TypeCategory> args;
85 bool instance_function; 94 bool instance_function;
86 int effectiveArgs; 95 int effectiveArgs;
87 TypeCategory effectiveReturnType; 96 TypeCategory effectiveReturnType;
88 char name[1024]; 97 char name[1024];
89 98
90 FunctionInfo() 99 FunctionInfo()
91 { 100 {
92 name[0] = 0; 101 name[0] = '\0';
sergei 2016/06/16 21:17:02 Although it makes no difference I personally prefe
Wladimir Palant 2016/12/06 10:47:39 Done.
93 } 102 }
94 103
95 FunctionInfo(TypeCategory returnType, TYPEID pointerType, 104 FunctionInfo(TypeCategory returnType, TYPEID pointerType,
96 std::initializer_list<TypeCategory> argTypes, bool instance_function, 105 std::initializer_list<TypeCategory> argTypes, bool instance_function,
97 void* function) 106 void* function)
98 : returnType(returnType), pointerType(pointerType), 107 : returnType(returnType), pointerType(pointerType),
99 instance_function(instance_function) 108 instance_function(instance_function)
100 { 109 {
101 name[0] = 0; 110 name[0] = '\0';
102 111
103 // The function parameter is a pointer to the function pointer. 112 // The function parameter is a pointer to the function pointer.
104 // Emscripten's "function pointers" are actually integers indicating the 113 // Emscripten's "function pointers" are actually integers indicating the
105 // position in the call table. 0 represents nullptr. 114 // position in the call table. 0 represents nullptr.
106 if (!*reinterpret_cast<int*>(function)) 115 if (!*reinterpret_cast<int*>(function))
107 return; 116 return;
108 117
109 for (auto it = argTypes.begin(); it != argTypes.end(); ++it) 118 for (const auto& item : argTypes)
110 { 119 {
111 if (*it != TypeCategory::INT && *it != TypeCategory::STRING_REF && 120 if (item != TypeCategory::INT && item != TypeCategory::STRING_REF &&
112 *it != TypeCategory::CLASS_PTR) 121 item != TypeCategory::CLASS_PTR)
113 { 122 {
114 throw std::runtime_error("Unexpected function argument type"); 123 throw std::runtime_error("Unexpected function argument type");
115 } 124 }
116 args.push_back(*it); 125 args.push_back(item);
117 } 126 }
118 127
119 if (returnType != TypeCategory::VOID && returnType != TypeCategory::INT && 128 if (returnType != TypeCategory::VOID && returnType != TypeCategory::INT &&
120 returnType != TypeCategory::DEPENDENT_STRING && 129 returnType != TypeCategory::DEPENDENT_STRING &&
121 returnType != TypeCategory::OWNED_STRING && 130 returnType != TypeCategory::OWNED_STRING &&
122 returnType != TypeCategory::STRING_REF && 131 returnType != TypeCategory::STRING_REF &&
123 returnType != TypeCategory::CLASS_PTR) 132 returnType != TypeCategory::CLASS_PTR)
124 { 133 {
125 throw std::runtime_error("Unexpected function return type"); 134 throw std::runtime_error("Unexpected function return type");
126 } 135 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 template<typename ClassType, typename ReturnType, typename... Args> 169 template<typename ClassType, typename ReturnType, typename... Args>
161 FunctionInfo(ReturnType (ClassType::*function)(Args...) const) 170 FunctionInfo(ReturnType (ClassType::*function)(Args...) const)
162 : FunctionInfo(TypeInfo<ReturnType>(), 171 : FunctionInfo(TypeInfo<ReturnType>(),
163 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, 172 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true,
164 &function) 173 &function)
165 { 174 {
166 } 175 }
167 176
168 bool empty() const 177 bool empty() const
169 { 178 {
170 return name[0] == 0; 179 return name[0] == '\0';
171 } 180 }
172 181
173 void get_function_name(void* ptr, int numArgs, bool voidResult) 182 void get_function_name(void* ptr, int numArgs, bool voidResult)
174 { 183 {
175 // This is a hack, C++ won't let us get the mangled function name. 184 // This is a hack, C++ won't let us get the mangled function name.
176 // JavaScript is more dynamic so we pass the pointer to our function 185 // JavaScript is more dynamic so we pass the pointer to our function
177 // there. With that and the function signature we can call the function - 186 // there. With that and the function signature we can call the function -
178 // with a full stack so that we will cause it to abort. Sometimes the 187 // with a full stack so that we will cause it to abort. Sometimes the
179 // function we are calling will also be missing from the build. The result 188 // function we are calling will also be missing from the build. The result
180 // is the same: abort() is called which in turn calls stackTrace(). By 189 // is the same: abort() is called which in turn calls stackTrace(). By
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 }; 259 };
251 260
252 struct MethodInfo 261 struct MethodInfo
253 { 262 {
254 std::string name; 263 std::string name;
255 FunctionInfo call; 264 FunctionInfo call;
256 }; 265 };
257 266
258 struct DifferentiatorInfo 267 struct DifferentiatorInfo
259 { 268 {
260 FunctionInfo call; 269 size_t offset;
261 std::vector<std::pair<int,std::string>> mapping; 270 std::vector<std::pair<int, std::string>> mapping;
262 }; 271 };
263 272
264 struct ClassInfo 273 struct ClassInfo
265 { 274 {
266 ClassInfo* baseClass; 275 ClassInfo* baseClass;
267 std::string name; 276 std::string name;
268 std::vector<PropertyInfo> properties; 277 std::vector<PropertyInfo> properties;
269 std::vector<MethodInfo> methods; 278 std::vector<MethodInfo> methods;
270 std::vector<FunctionInfo> initializers; 279 std::vector<FunctionInfo> initializers;
271 DifferentiatorInfo subclass_differentiator; 280 DifferentiatorInfo subclass_differentiator;
281 ptrdiff_t ref_counted_offset;
272 }; 282 };
273 283
274 std::map<TYPEID,ClassInfo> classes; 284 std::map<TYPEID, ClassInfo> classes;
275 285
276 void register_class(const char* name, TYPEID classID, TYPEID baseClassID) 286 void register_class(const char* name, TYPEID classID, TYPEID baseClassID,
287 ptrdiff_t ref_counted_offset)
277 { 288 {
278 auto it = classes.find(classID); 289 auto it = classes.find(classID);
279 if (it != classes.end()) 290 if (it != classes.end())
280 throw std::runtime_error(std::string("Duplicate definition for class ") + name); 291 throw std::runtime_error(std::string("Duplicate definition for class ") + name);
281 292
282 ClassInfo* baseClass = nullptr; 293 ClassInfo* baseClass = nullptr;
283 if (baseClassID != TypeInfo<NoBaseClass>()) 294 if (baseClassID != TypeInfo<NoBaseClass>())
284 { 295 {
285 it = classes.find(baseClassID); 296 it = classes.find(baseClassID);
286 if (it == classes.end()) 297 if (it == classes.end())
287 throw std::runtime_error(std::string("Unknown base class defined for cla ss ") + name); 298 throw std::runtime_error(std::string("Unknown base class defined for cla ss ") + name);
288 baseClass = &(it->second); 299 baseClass = &(it->second);
289 } 300 }
290 301
291 ClassInfo classInfo; 302 ClassInfo classInfo;
292 classInfo.baseClass = baseClass; 303 classInfo.baseClass = baseClass;
293 classInfo.name = name; 304 classInfo.name = name;
305 classInfo.subclass_differentiator.offset = SIZE_MAX;
306 classInfo.ref_counted_offset = ref_counted_offset;
294 classes[classID] = classInfo; 307 classes[classID] = classInfo;
295 } 308 }
296 309
297 void register_property(TYPEID classID, const char* name, 310 void register_property(TYPEID classID, const char* name,
298 const FunctionInfo& getter, const FunctionInfo& setter, 311 const FunctionInfo& getter, const FunctionInfo& setter,
299 const char* jsValue = "") 312 const char* jsValue = "")
300 { 313 {
301 auto it = classes.find(classID); 314 auto it = classes.find(classID);
302 if (it == classes.end()) 315 if (it == classes.end())
303 throw std::runtime_error(std::string("Property defined on unknown class: " ) + name); 316 throw std::runtime_error(std::string("Property defined on unknown class: " ) + name);
(...skipping 21 matching lines...) Expand all
325 338
326 void register_initializer(TYPEID classID, const FunctionInfo& call) 339 void register_initializer(TYPEID classID, const FunctionInfo& call)
327 { 340 {
328 auto it = classes.find(classID); 341 auto it = classes.find(classID);
329 if (it == classes.end()) 342 if (it == classes.end())
330 throw std::runtime_error("Initializer defined on unknown class"); 343 throw std::runtime_error("Initializer defined on unknown class");
331 344
332 it->second.initializers.push_back(call); 345 it->second.initializers.push_back(call);
333 } 346 }
334 347
335 void register_differentiator(TYPEID classID, const FunctionInfo& call, 348 void register_differentiator(TYPEID classID, size_t offset,
336 std::vector<std::pair<int,std::string>>& mapping) 349 std::vector<std::pair<int, std::string>>& mapping)
337 { 350 {
338 auto it = classes.find(classID); 351 auto it = classes.find(classID);
339 if (it == classes.end()) 352 if (it == classes.end())
340 throw std::runtime_error("Subclass differentiator defined on unknown class "); 353 throw std::runtime_error("Subclass differentiator defined on unknown class ");
341 354
342 if (!it->second.subclass_differentiator.call.empty()) 355 if (it->second.subclass_differentiator.offset != SIZE_MAX)
343 throw std::runtime_error("More than one subclass differentiator defined fo r class " + it->second.name); 356 throw std::runtime_error("More than one subclass differentiator defined fo r class " + it->second.name);
344 357
345 DifferentiatorInfo differentiatorInfo; 358 DifferentiatorInfo differentiatorInfo;
346 differentiatorInfo.call = call; 359 differentiatorInfo.offset = offset;
347 differentiatorInfo.mapping = mapping; 360 differentiatorInfo.mapping = mapping;
348 it->second.subclass_differentiator = differentiatorInfo; 361 it->second.subclass_differentiator = differentiatorInfo;
349 } 362 }
350 363
351 const std::string generateCall(const FunctionInfo& call, 364 const std::string generateCall(const FunctionInfo& call,
352 std::vector<std::string>& params) 365 std::vector<std::string>& params)
353 { 366 {
354 if (call.returnType == TypeCategory::DEPENDENT_STRING || 367 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
355 call.returnType == TypeCategory::OWNED_STRING) 368 call.returnType == TypeCategory::OWNED_STRING)
356 { 369 {
(...skipping 13 matching lines...) Expand all
370 if (call.returnType == TypeCategory::VOID) 383 if (call.returnType == TypeCategory::VOID)
371 return " " + call_str + ";\n"; 384 return " " + call_str + ";\n";
372 else if (call.returnType == TypeCategory::INT) 385 else if (call.returnType == TypeCategory::INT)
373 return " var result = " + call_str + ";\n"; 386 return " var result = " + call_str + ";\n";
374 else if (call.returnType == TypeCategory::DEPENDENT_STRING || 387 else if (call.returnType == TypeCategory::DEPENDENT_STRING ||
375 call.returnType == TypeCategory::OWNED_STRING) 388 call.returnType == TypeCategory::OWNED_STRING)
376 { 389 {
377 std::string result; 390 std::string result;
378 result += " var string = createString();\n"; 391 result += " var string = createString();\n";
379 result += " " + call_str + ";\n"; 392 result += " " + call_str + ";\n";
380 result += " var result = getStringData(string);\n"; 393 result += " var result = readString(string);\n";
381 if (call.returnType == TypeCategory::OWNED_STRING) 394 if (call.returnType == TypeCategory::OWNED_STRING)
382 result += " Module._DestroyString(string);\n"; 395 result += " Module._DestroyString(string);\n";
383 return result; 396 return result;
384 } 397 }
385 else if (call.returnType == TypeCategory::STRING_REF) 398 else if (call.returnType == TypeCategory::STRING_REF)
386 { 399 {
387 return " var result = getStringData(" + call_str + ");\n"; 400 return " var result = readString(" + call_str + ");\n";
388 } 401 }
389 else if (call.returnType == TypeCategory::CLASS_PTR) 402 else if (call.returnType == TypeCategory::CLASS_PTR)
390 { 403 {
391 std::string result; 404 std::string result;
392 result += " var result = " + call_str + ";\n"; 405 result += " var result = " + call_str + ";\n";
393 result += " if (result)\n"; 406 result += " if (result)\n";
394 result += " {\n"; 407 result += " {\n";
395 result += " Module._AddRef(result);\n";
396 408
397 auto it = classes.find(call.pointerType); 409 auto it = classes.find(call.pointerType);
398 if (it == classes.end()) 410 if (it == classes.end())
399 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class"); 411 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class");
400 412
401 const ClassInfo& cls = it->second; 413 const ClassInfo& cls = it->second;
402 if (cls.subclass_differentiator.call.empty()) 414 auto offset = cls.subclass_differentiator.offset;
415 if (offset == SIZE_MAX)
403 result += " result = " + cls.name + "(result);\n"; 416 result += " result = " + cls.name + "(result);\n";
404 else 417 else
405 { 418 {
406 result += " var type = " + 419 result += " var type = HEAP32[result + " + std::to_string(offset)+ " >> 2];\n";
407 std::string(cls.subclass_differentiator.call.name) + "(result);\n";
408 result += " if (type in " + cls.name + "_mapping)\n"; 420 result += " if (type in " + cls.name + "_mapping)\n";
409 result += " result = new (exports[" + cls.name + "_mapping[type]])( result);\n"; 421 result += " result = new (exports[" + cls.name + "_mapping[type]])( result);\n";
410 result += " else\n"; 422 result += " else\n";
411 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n"; 423 result += " throw new Error('Unexpected " + cls.name + " type: ' + type);\n";
412 } 424 }
413 425
414 result += " }\n"; 426 result += " }\n";
415 return result; 427 return result;
416 } 428 }
417 else 429 else
418 throw std::runtime_error("Unexpected return type for " + std::string(call. name)); 430 throw std::runtime_error("Unexpected return type for " + std::string(call. name));
419 } 431 }
420 432
421 const std::string wrapCall(const FunctionInfo& call) 433 const std::string wrapCall(const FunctionInfo& call)
422 { 434 {
423 char buffer[20]; 435 char buffer[20];
424 bool hasStringArgs = false; 436 bool hasStringArgs = false;
425 std::vector<std::string> params; 437 std::vector<std::string> params;
426 std::string prefix = "function("; 438 std::string prefix = "function(";
427 for (int i = 0; i < call.args.size(); i++) 439 for (int i = 0; i < call.args.size(); i++)
428 { 440 {
429 sprintf(buffer, "arg%i", i); 441 sprintf(buffer, "arg%i", i);
430 if (i > 0) 442 if (i > 0)
431 prefix += ", "; 443 prefix += ", ";
432 prefix += buffer; 444 prefix += buffer;
433
sergei 2016/06/16 21:16:45 Additional line.
Wladimir Palant 2016/12/06 10:47:57 Done.
434 445
435 if (call.args[i] == TypeCategory::STRING_REF) 446 if (call.args[i] == TypeCategory::STRING_REF)
436 { 447 {
437 hasStringArgs = true; 448 hasStringArgs = true;
438 params.push_back(std::string("createString(") + buffer + ")"); 449 params.push_back(std::string("createString(") + buffer + ")");
439 } 450 }
440 else 451 else
441 params.push_back(buffer); 452 params.push_back(buffer);
442 } 453 }
443 prefix += ")\n{\n"; 454 prefix += ")\n{\n";
444 455
445 std::string suffix = "}"; 456 std::string suffix = "}";
446 if (call.returnType != TypeCategory::VOID) 457 if (call.returnType != TypeCategory::VOID)
447 suffix = " return result;\n" + suffix; 458 suffix = " return result;\n" + suffix;
448 459
449 if (call.returnType == TypeCategory::DEPENDENT_STRING || 460 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
450 call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) 461 call.returnType == TypeCategory::OWNED_STRING || hasStringArgs)
451 { 462 {
452 prefix += " var sp = Runtime.stackSave();\n"; 463 prefix += " var sp = Runtime.stackSave();\n";
453 suffix = " Runtime.stackRestore(sp);\n" + suffix; 464 suffix = " Runtime.stackRestore(sp);\n" + suffix;
454 } 465 }
455 466
456 if (call.instance_function) 467 if (call.instance_function)
457 params.insert(params.begin(), "this._pointer"); 468 params.insert(params.begin(), "this._pointer");
458 469
459 return prefix + generateCall(call, params) + suffix; 470 return prefix + generateCall(call, params) + suffix;
460 } 471 }
461 472
462 const std::string generatePropertyDescriptor(const PropertyInfo& property) 473 std::string generatePropertyDescriptor(const PropertyInfo& property)
sergei 2016/06/16 21:16:56 I'm not sure that we need the `const` for the retu
Wladimir Palant 2016/12/06 10:48:05 Done.
463 { 474 {
464 if (!property.jsValue.empty()) 475 if (!property.jsValue.empty())
465 return "value: " + property.jsValue; 476 return "value: " + property.jsValue;
466 477
467 std::string result("get: " + wrapCall(property.getter)); 478 std::string result("get: " + wrapCall(property.getter));
468 if (!property.setter.empty()) 479 if (!property.setter.empty())
469 result += ", set: " + wrapCall(property.setter); 480 result += ", set: " + wrapCall(property.setter);
470 return result; 481 return result;
471 } 482 }
472 483
473 void printHelpers() 484 void printHelpers()
474 { 485 {
475 printf("var sizeofString = %i\n", sizeof(String)); 486 printf("var sizeofString = %i;\n", sizeof(String));
sergei 2016/06/16 21:17:16 What about ';' after "%i"?
Wladimir Palant 2016/12/06 10:48:07 Done.
476 487
477 puts(R"( 488 puts(R"(
478 function copyString(str, buffer) 489 function copyString(str, buffer)
479 { 490 {
480 var length = str.length; 491 var length = str.length;
481 for (var i = 0, pointer = (buffer >> 1); i < length; i++, pointer++) 492 for (var i = 0, pointer = (buffer >> 1); i < length; i++, pointer++)
482 HEAP16[pointer] = str.charCodeAt(i); 493 HEAP16[pointer] = str.charCodeAt(i);
483 return length; 494 return length;
484 } 495 }
485 496
486 function createString(str) 497 function createString(str)
487 { 498 {
488 var length = 0; 499 var length = 0;
489 var buffer = 0; 500 var buffer = 0;
490 if (str) 501 if (str)
491 { 502 {
492 buffer = Runtime.stackAlloc(str.length * 2); 503 buffer = Runtime.stackAlloc(str.length * 2);
493 length = copyString(str, buffer); 504 length = copyString(str, buffer);
494 } 505 }
495 506
496 var result = Module.Runtime.stackAlloc(sizeofString); 507 var result = Module.Runtime.stackAlloc(sizeofString);
497 Module._InitString(result, buffer, length); 508 Module._InitString(result, buffer, length);
498 return result; 509 return result;
499 } 510 }
500 511
501 function getStringData(str) 512 function readString(str)
sergei 2016/06/16 21:17:15 What do you think about renaming of this method. C
Wladimir Palant 2016/12/06 10:48:10 Ok, readString() it is - hopefully more obvious.
502 { 513 {
503 var length = Module._GetStringLength(str); 514 var length = Module._GetStringLength(str);
504 var pointer = Module._GetStringData(str) >> 1; 515 var pointer = Module._GetStringData(str) >> 1;
505 return String.fromCharCode.apply(String, HEAP16.slice(pointer, pointer + len gth)); 516 return String.fromCharCode.apply(String, HEAP16.slice(pointer, pointer + len gth));
sergei 2016/06/16 21:16:46 Shouldn't we use fromCodePoint instead of fromChar
Wladimir Palant 2016/12/06 10:48:08 No, we shouldn't - we are using 16-bit characters.
506 } 517 }
507 518
508 function createClass(superclass) 519 function createClass(superclass, ref_counted_offset)
509 { 520 {
510 var result = function(pointer) 521 var result = function(pointer)
511 { 522 {
512 this._pointer = pointer; 523 this._pointer = pointer;
sergei 2016/06/16 21:17:11 We should call Module._AddRef on stored _pointer h
Wladimir Palant 2016/12/06 10:47:41 No, we shouldn't - that's a raw pointer we got her
513 }; 524 };
514 if (superclass) 525 if (superclass)
515 result.prototype = Object.create(superclass.prototype); 526 result.prototype = Object.create(superclass.prototype);
516 result.prototype.delete = function() 527 result.prototype.delete = function()
517 { 528 {
518 Module._ReleaseRef(this._pointer); 529 Module._ReleaseRef(this._pointer + ref_counted_offset);
519 }; 530 };
520 return result; 531 return result;
521 })"); 532 })");
522 } 533 }
523 534
524 void printClass(ClassInfo& cls) 535 void printClass(const ClassInfo& cls)
525 { 536 {
526 DifferentiatorInfo differentiator = cls.subclass_differentiator; 537 DifferentiatorInfo differentiator = cls.subclass_differentiator;
527 if (!differentiator.call.empty()) 538 if (differentiator.offset != SIZE_MAX)
528 { 539 {
529 printf("var %s_mapping = \n", cls.name.c_str()); 540 printf("var %s_mapping = \n", cls.name.c_str());
530 puts("{"); 541 puts("{");
531 for (auto it = differentiator.mapping.begin(); it != differentiator.mappin g.end(); ++it) 542 for (const auto& item : differentiator.mapping)
532 printf(" %i: '%s',\n", it->first, it->second.c_str()); 543 printf(" %i: '%s',\n", item.first, item.second.c_str());
533 puts("};"); 544 puts("};");
534 } 545 }
535 546
536 printf("exports.%s = createClass(%s);\n", cls.name.c_str(), 547 printf("exports.%s = createClass(%s, %i);\n", cls.name.c_str(),
537 (cls.baseClass ? ("exports." + cls.baseClass->name).c_str() : "")); 548 (cls.baseClass ? ("exports." + cls.baseClass->name).c_str() : "null"),
538 549 cls.ref_counted_offset);
539 for (auto it = cls.properties.begin(); it != cls.properties.end(); ++it) 550
551 for (const auto& item : cls.properties)
540 { 552 {
541 printf("Object.defineProperty(exports.%s.prototype, '%s', {%s});\n", 553 printf("Object.defineProperty(exports.%s.prototype, '%s', {%s});\n",
542 cls.name.c_str(), it->name.c_str(), 554 cls.name.c_str(), item.name.c_str(),
543 generatePropertyDescriptor(*it).c_str()); 555 generatePropertyDescriptor(item).c_str());
544 } 556 }
545 557
546 for (auto it = cls.methods.begin(); it != cls.methods.end(); ++it) 558 for (const auto& item : cls.methods)
547 { 559 {
548 std::string obj("exports." + cls.name); 560 std::string obj("exports." + cls.name);
549 if (it->call.instance_function) 561 if (item.call.instance_function)
550 obj += ".prototype"; 562 obj += ".prototype";
551 printf("%s.%s = %s;\n", obj.c_str(), it->name.c_str(), 563 printf("%s.%s = %s;\n", obj.c_str(), item.name.c_str(),
552 wrapCall(it->call).c_str()); 564 wrapCall(item.call).c_str());
553 } 565 }
554 566
555 for (auto it = cls.initializers.begin(); it != cls.initializers.end(); ++it) 567 for (const auto& item : cls.initializers)
556 printf("%s()\n", it->name); 568 printf("%s()\n", item.name);
557 } 569 }
558 570
559 void printBindings() 571 void printBindings()
560 { 572 {
561 printHelpers(); 573 printHelpers();
562 574
563 for (auto it = classes.begin(); it != classes.end(); ++it) 575 for (const auto& item : classes)
564 printClass(it->second); 576 printClass(item.second);
565 } 577 }
566 } 578 }
567 579
568 #if defined(PRINT_BINDINGS) 580 #if defined(PRINT_BINDINGS)
569 // Bindings generation step: collect bindings information and print 581 // Bindings generation step: collect bindings information and print
570 // corresponding JS code. 582 // corresponding JS code.
571 #define EMSCRIPTEN_BINDINGS \ 583 #define EMSCRIPTEN_BINDINGS \
572 static struct BindingsInitializer {\ 584 struct BindingsInitializer {\
sergei 2016/06/16 21:16:54 I think static is not required here.
Wladimir Palant 2016/12/06 10:47:44 Done.
573 BindingsInitializer();\ 585 BindingsInitializer();\
574 BindingsInitializer(bool dummy)\ 586 BindingsInitializer(bool dummy)\
575 {\ 587 {\
576 try\ 588 try\
577 {\ 589 {\
578 BindingsInitializer();\ 590 BindingsInitializer();\
579 bindings_internal::printBindings();\ 591 bindings_internal::printBindings();\
580 }\ 592 }\
581 catch (const std::exception& e)\ 593 catch (const std::exception& e)\
582 {\ 594 {\
(...skipping 28 matching lines...) Expand all
611 String::size_type EMSCRIPTEN_KEEPALIVE GetStringLength(\ 623 String::size_type EMSCRIPTEN_KEEPALIVE GetStringLength(\
612 const String& str)\ 624 const String& str)\
613 {\ 625 {\
614 return str.length();\ 626 return str.length();\
615 }\ 627 }\
616 const String::value_type* EMSCRIPTEN_KEEPALIVE GetStringData(\ 628 const String::value_type* EMSCRIPTEN_KEEPALIVE GetStringData(\
617 const String& str)\ 629 const String& str)\
618 {\ 630 {\
619 return str.data();\ 631 return str.data();\
620 }\ 632 }\
621 void EMSCRIPTEN_KEEPALIVE AddRef(ref_counted* ptr)\
622 {\
623 ptr->AddRef();\
624 }\
625 void EMSCRIPTEN_KEEPALIVE ReleaseRef(ref_counted* ptr)\ 633 void EMSCRIPTEN_KEEPALIVE ReleaseRef(ref_counted* ptr)\
626 {\ 634 {\
627 ptr->ReleaseRef();\ 635 ptr->ReleaseRef();\
628 }\ 636 }\
629 }\ 637 }\
630 void BindingsInitializer_dummy() 638 void BindingsInitializer_dummy()
631 #endif 639 #endif
632 640
633 template<typename ClassType, 641 template<typename ClassType,
634 typename BaseClass = bindings_internal::NoBaseClass, 642 typename BaseClass = bindings_internal::NoBaseClass,
635 typename std::enable_if<std::is_base_of<ref_counted, ClassType>::value>::typ e* = nullptr> 643 typename std::enable_if<std::is_base_of<ref_counted, ClassType>::value>::typ e* = nullptr>
636 class class_ 644 class class_
637 { 645 {
638 public: 646 public:
639 class_(const char* name) 647 class_(const char* name)
640 { 648 {
649 ClassType* ptr = reinterpret_cast<ClassType*>(0x10000000);
650 ptrdiff_t ref_counted_offset =
651 reinterpret_cast<char*>(static_cast<ref_counted*>(ptr)) -
652 reinterpret_cast<char*>(ptr);
641 bindings_internal::register_class(name, 653 bindings_internal::register_class(name,
642 bindings_internal::TypeInfo<ClassType>(), 654 bindings_internal::TypeInfo<ClassType>(),
643 bindings_internal::TypeInfo<BaseClass>()); 655 bindings_internal::TypeInfo<BaseClass>(),
656 ref_counted_offset
657 );
644 } 658 }
645 659
646 template<typename FieldType> 660 template<typename FieldType>
647 const class_& property(const char* name, 661 const class_& property(const char* name,
648 FieldType (ClassType::*getter)() const, 662 FieldType (ClassType::*getter)() const,
649 void (ClassType::*setter)(FieldType) = 0) const 663 void (ClassType::*setter)(FieldType) = nullptr) const
sergei 2016/06/16 21:17:07 I would rather use nullptr instead of 0.
Wladimir Palant 2016/12/06 10:47:50 Done.
650 { 664 {
651 bindings_internal::register_property( 665 bindings_internal::register_property(
652 bindings_internal::TypeInfo<ClassType>(), name, getter, setter); 666 bindings_internal::TypeInfo<ClassType>(), name, getter, setter);
653 return *this; 667 return *this;
654 } 668 }
655 669
656 const class_& class_property(const char* name, 670 const class_& class_property(const char* name,
657 const char* jsValue) const 671 const char* jsValue) const
658 { 672 {
659 bindings_internal::register_property( 673 bindings_internal::register_property(
(...skipping 28 matching lines...) Expand all
688 } 702 }
689 703
690 const class_& class_initializer(void (*function)()) const 704 const class_& class_initializer(void (*function)()) const
691 { 705 {
692 bindings_internal::register_initializer( 706 bindings_internal::register_initializer(
693 bindings_internal::TypeInfo<ClassType>(), function); 707 bindings_internal::TypeInfo<ClassType>(), function);
694 return *this; 708 return *this;
695 } 709 }
696 710
697 template<typename ReturnType, 711 template<typename ReturnType,
698 typename std::enable_if<std::is_convertible<ReturnType, int>::value>::type * = nullptr> 712 typename std::enable_if<std::is_convertible<ReturnType, int32_t>::value>:: type* = nullptr>
699 const class_& subclass_differentiator(ReturnType (*function)(ClassType*), 713 const class_& subclass_differentiator(ReturnType ClassType::* member,
700 std::initializer_list<std::pair<ReturnType,const char*>> list) const 714 std::initializer_list<std::pair<ReturnType, const char*>> list) const
sergei 2016/06/16 21:17:04 Just wonder, why are no spaces between types for s
Wladimir Palant 2016/12/06 10:47:54 Done.
701 { 715 {
702 std::vector<std::pair<int,std::string>> mapping; 716 ClassType* instance = nullptr;
703 for (auto it = list.begin(); it != list.end(); ++it) 717 size_t offset = (char*)&(instance->*member) - (char*)instance;
704 mapping.push_back(std::pair<int,std::string>(it->first, it->second)); 718
sergei 2016/06/16 21:16:59 Merely a shorter syntax, here and above we can use
Wladimir Palant 2016/12/06 10:47:48 Done.
719 std::vector<std::pair<int, std::string>> mapping;
720 for (const auto& item : list)
721 mapping.emplace_back(item.first, item.second);
705 722
706 bindings_internal::register_differentiator( 723 bindings_internal::register_differentiator(
707 bindings_internal::TypeInfo<ClassType>(), function, mapping); 724 bindings_internal::TypeInfo<ClassType>(), offset, mapping);
708 return *this; 725 return *this;
709 } 726 }
710 }; 727 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld