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

Delta Between Two Patch Sets: compiled/bindings/generator.cpp

Issue 29426559: Issue 5137 - [emscripten] Added basic filter storage implementation (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Left Patch Set: Created May 1, 2017, 2:36 p.m.
Right Patch Set: Fixed bogus assert Created Aug. 31, 2017, 12:44 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « compiled/bindings/generator.h ('k') | compiled/bindings/main.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-present 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;
28
29 void printProperties(const bindings_internal::PropertyList& properties)
30 {
31 for (const auto& property : properties)
32 {
33 if (property.jsValue.empty())
34 {
35 printf("get %s%s,\n", property.name.c_str(),
36 wrapCall(property.getter, false).c_str());
37 if (!property.setter.empty())
38 {
39 printf("set %s%s,\n", property.name.c_str(),
40 wrapCall(property.setter, false).c_str());
41 }
42 }
43 else
44 printf("%s: %s,\n", property.name.c_str(), property.jsValue.c_str());
45 }
46 }
47
48 void printMethods(const bindings_internal::MethodList& methods,
49 bool instanceOnly = true)
50 {
51 for (const auto& method : methods)
52 if (!instanceOnly || method.call.instance_function)
53 printf("%s: %s,\n", method.name.c_str(), wrapCall(method.call).c_str());
54 }
55 } 26 }
56 27
57 namespace bindings_internal 28 namespace bindings_internal
58 { 29 {
59 FunctionInfo::FunctionInfo() 30 FunctionInfo::FunctionInfo()
60 { 31 {
61 name[0] = '\0';
62 } 32 }
63 33
64 FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType, 34 FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType,
65 std::initializer_list<TypeCategory> argTypes, bool instance_function, 35 std::initializer_list<TypeCategory> argTypes, bool instance_function,
66 void* function) 36 void* function)
67 : returnType(returnType), pointerType(pointerType), 37 : returnType(returnType), pointerType(pointerType),
68 instance_function(instance_function) 38 instance_function(instance_function)
69 { 39 {
70 name[0] = '\0';
71
72 // The function parameter is a pointer to the function pointer. 40 // The function parameter is a pointer to the function pointer.
73 // Emscripten's "function pointers" are actually integers indicating the 41 // Emscripten's "function pointers" are actually integers indicating the
74 // position in the call table. 0 represents nullptr. 42 // position in the call table. 0 represents nullptr.
75 if (!*reinterpret_cast<int*>(function)) 43 if (!*reinterpret_cast<int*>(function))
76 return; 44 return;
77 45
78 std::string signature; 46 std::string signature;
79 47
80 // Add return type to the signature. Similar logic in Emscripten: 48 // Add return type to the signature. Similar logic in Emscripten:
81 // https://github.com/kripken/emscripten/blob/1.37.3/src/modules.js#L46 49 // 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; 102 break;
135 case TypeCategory::DOUBLE: 103 case TypeCategory::DOUBLE:
136 signature += 'd'; 104 signature += 'd';
137 break; 105 break;
138 default: 106 default:
139 throw std::runtime_error("Unexpected function argument type"); 107 throw std::runtime_error("Unexpected function argument type");
140 } 108 }
141 args.push_back(type); 109 args.push_back(type);
142 } 110 }
143 111
144 get_function_name(function, signature.c_str()); 112 int nameLength = GetFunctionName(nullptr, function, signature.c_str());
113 name.resize(nameLength);
114 GetFunctionName(name.data(), function, signature.c_str());
145 } 115 }
146 116
147 bool FunctionInfo::empty() const 117 bool FunctionInfo::empty() const
148 { 118 {
149 return name[0] == '\0'; 119 return name.empty();
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 } 120 }
214 121
215 ClassInfo* find_class(TYPEID classID) 122 ClassInfo* find_class(TYPEID classID)
216 { 123 {
217 for (auto& classInfo : classes) 124 for (auto& classInfo : classes)
218 if (classInfo.id == classID) 125 if (classInfo.id == classID)
219 return &classInfo; 126 return &classInfo;
220 return nullptr; 127 return nullptr;
221 } 128 }
222 129
223 void register_class(const char* name, TYPEID classID, TYPEID baseClassID, 130 void register_class(const char* name, TYPEID classID, TYPEID baseClassID,
224 ptrdiff_t ref_counted_offset) 131 ptrdiff_t ref_counted_offset,
132 const FunctionInfo& instanceGetter)
225 { 133 {
226 if (find_class(classID)) 134 if (find_class(classID))
227 throw std::runtime_error(std::string("Duplicate definition for class ") + name); 135 throw std::runtime_error(std::string("Duplicate definition for class ") + name);
228 136
229 if (baseClassID != TypeInfo<NoBaseClass>() && !find_class(baseClassID)) 137 if (baseClassID != TypeInfo<NoBaseClass>() && !find_class(baseClassID))
230 throw std::runtime_error(std::string("Unknown base class defined for class ") + name); 138 throw std::runtime_error(std::string("Unknown base class defined for class ") + name);
231 139
232 ClassInfo classInfo; 140 ClassInfo classInfo;
233 classInfo.id = classID; 141 classInfo.id = classID;
234 classInfo.baseClass = baseClassID; 142 classInfo.baseClass = baseClassID;
235 classInfo.name = name; 143 classInfo.name = name;
236 classInfo.subclass_differentiator.offset = SIZE_MAX; 144 classInfo.subclass_differentiator.offset = SIZE_MAX;
237 classInfo.ref_counted_offset = ref_counted_offset; 145 classInfo.ref_counted_offset = ref_counted_offset;
146 classInfo.instanceGetter = instanceGetter;
238 classes.push_back(classInfo); 147 classes.push_back(classInfo);
239 } 148 }
240 149
241 void register_property(TYPEID classID, const char* name, 150 void register_property(TYPEID classID, const char* name,
242 const FunctionInfo& getter, const FunctionInfo& setter, 151 const FunctionInfo& getter, const FunctionInfo& setter,
243 const char* jsValue) 152 const char* jsValue)
244 { 153 {
245 ClassInfo* classInfo = find_class(classID); 154 ClassInfo* classInfo = find_class(classID);
246 if (!classInfo) 155 if (!classInfo)
247 throw std::runtime_error(std::string("Property defined on unknown class: " ) + name); 156 throw std::runtime_error(std::string("Property defined on unknown class: " ) + name);
(...skipping 26 matching lines...) Expand all
274 if (!classInfo) 183 if (!classInfo)
275 throw std::runtime_error("Subclass differentiator defined on unknown class "); 184 throw std::runtime_error("Subclass differentiator defined on unknown class ");
276 185
277 if (classInfo->subclass_differentiator.offset != SIZE_MAX) 186 if (classInfo->subclass_differentiator.offset != SIZE_MAX)
278 throw std::runtime_error("More than one subclass differentiator defined fo r class " + classInfo->name); 187 throw std::runtime_error("More than one subclass differentiator defined fo r class " + classInfo->name);
279 188
280 DifferentiatorInfo differentiatorInfo; 189 DifferentiatorInfo differentiatorInfo;
281 differentiatorInfo.offset = offset; 190 differentiatorInfo.offset = offset;
282 differentiatorInfo.mapping = mapping; 191 differentiatorInfo.mapping = mapping;
283 classInfo->subclass_differentiator = differentiatorInfo; 192 classInfo->subclass_differentiator = differentiatorInfo;
284 }
285
286 NamespaceInfo* find_namespace(const char* namespaceName)
287 {
288 for (auto& namespaceInfo : namespaces)
289 if (namespaceInfo.name == namespaceName)
290 return &namespaceInfo;
291 return nullptr;
292 }
293
294 void register_namespace(const char* name)
295 {
296 if (find_namespace(name))
297 throw std::runtime_error(std::string("Duplicate definition for namespace " ) + name);
298
299 NamespaceInfo namespaceInfo;
300 namespaceInfo.name = name;
301 namespaces.push_back(namespaceInfo);
302 }
303
304 void register_namespace_property(const char* namespaceName, const char* name,
305 const FunctionInfo& getter, const FunctionInfo& setter)
306 {
307 NamespaceInfo* namespaceInfo = find_namespace(namespaceName);
308 if (!namespaceInfo)
309 throw std::runtime_error(std::string("Property defined on unknown namespac e: ") + name);
310
311 PropertyInfo propertyInfo;
312 propertyInfo.name = name;
313 propertyInfo.getter = getter;
314 propertyInfo.setter = setter;
315 namespaceInfo->properties.push_back(propertyInfo);
316 }
317
318 void register_namespace_method(const char* namespaceName, const char* name,
319 const FunctionInfo& call)
320 {
321 NamespaceInfo* namespaceInfo = find_namespace(namespaceName);
322 if (!namespaceInfo)
323 throw std::runtime_error(std::string("Method defined on unknown namespace: ") + name);
324
325 MethodInfo methodInfo;
326 methodInfo.name = name;
327 methodInfo.call = call;
328 namespaceInfo->methods.push_back(methodInfo);
329 } 193 }
Wladimir Palant 2017/05/01 14:47:25 I'm not really happy with the complexity required
sergei 2017/05/08 10:54:39 I would like to include in that discussion the des
Wladimir Palant 2017/05/08 12:55:41 I considered making FilterStorage a singleton clas
sergei 2017/08/24 13:32:04 Singleton and global variables are actually equall
330 194
331 std::string generateCall(const FunctionInfo& call, 195 std::string generateCall(const FunctionInfo& call,
332 std::vector<std::string>& params) 196 std::vector<std::string>& params)
333 { 197 {
334 if (call.returnType == TypeCategory::DEPENDENT_STRING || 198 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
335 call.returnType == TypeCategory::OWNED_STRING) 199 call.returnType == TypeCategory::OWNED_STRING)
336 { 200 {
337 params.insert(params.begin(), "string"); 201 params.insert(params.begin(), "string");
338 } 202 }
339 203
(...skipping 13 matching lines...) Expand all
353 return " " + call_str + ";\n"; 217 return " " + call_str + ";\n";
354 case TypeCategory::INT: 218 case TypeCategory::INT:
355 case TypeCategory::FLOAT: 219 case TypeCategory::FLOAT:
356 case TypeCategory::DOUBLE: 220 case TypeCategory::DOUBLE:
357 return " var result = " + call_str + ";\n"; 221 return " var result = " + call_str + ";\n";
358 case TypeCategory::INT64: 222 case TypeCategory::INT64:
359 return " var result = Runtime.makeBigInt(" + call_str + ", " + 223 return " var result = Runtime.makeBigInt(" + call_str + ", " +
360 "Runtime.getTempRet0(), " + 224 "Runtime.getTempRet0(), " +
361 "true);\n"; 225 "true);\n";
362 case TypeCategory::DEPENDENT_STRING: 226 case TypeCategory::DEPENDENT_STRING:
363 case TypeCategory::OWNED_STRING:
364 { 227 {
365 std::string result; 228 std::string result;
366 result += " var string = createString();\n"; 229 result += " var string = createString();\n";
367 result += " " + call_str + ";\n"; 230 result += " " + call_str + ";\n";
368 result += " var result = readString(string);\n"; 231 result += " var result = readString(string);\n";
369 if (call.returnType == TypeCategory::OWNED_STRING) 232 // We don't call a destructor here because we know that dependent
370 result += " Module._DestroyString(string);\n"; 233 // strings don't need to clean up.
234 return result;
235 }
236 case TypeCategory::OWNED_STRING:
237 {
238 std::string result;
239 result += " var string = createOwnedString();\n";
240 result += " " + call_str + ";\n";
241 result += " var result = readString(string);\n";
242 result += " Module._DestroyString(string);\n";
371 return result; 243 return result;
372 } 244 }
373 case TypeCategory::STRING_REF: 245 case TypeCategory::STRING_REF:
374 return " var result = readString(" + call_str + ");\n"; 246 return " var result = readString(" + call_str + ");\n";
375 case TypeCategory::CLASS_PTR: 247 case TypeCategory::CLASS_PTR:
376 { 248 {
377 std::string result; 249 std::string result;
378 result += " var result = " + call_str + ";\n"; 250 result += " var result = " + call_str + ";\n";
379 result += " if (result)\n"; 251 result += " if (result)\n";
380 result += " {\n";
381 252
382 const ClassInfo* cls = find_class(call.pointerType); 253 const ClassInfo* cls = find_class(call.pointerType);
383 if (!cls) 254 if (!cls)
384 throw std::runtime_error("Function " + std::string(call.name) + " retu rns pointer to unknown class"); 255 throw std::runtime_error("Function " + call.name + " returns pointer t o unknown class");
385 256
386 auto offset = cls->subclass_differentiator.offset; 257 auto offset = cls->subclass_differentiator.offset;
387 if (offset == SIZE_MAX) 258 if (offset == SIZE_MAX)
388 result += " result = exports." + cls->name + "(result);\n"; 259 result += " result = exports." + cls->name + "(result);\n";
389 else 260 else
390 result += " result = exports." + cls->name + ".fromPointer(result); \n"; 261 result += " result = exports." + cls->name + ".fromPointer(result); \n";
391 262
392 result += " }\n";
393 result += " else\n"; 263 result += " else\n";
394 result += " result = null;\n"; 264 result += " result = null;\n";
395 return result; 265 return result;
396 } 266 }
397 default: 267 default:
398 throw std::runtime_error("Unexpected return type for " + std::string(cal l.name)); 268 throw std::runtime_error("Unexpected return type for " + call.name);
399 } 269 }
400 } 270 }
401 271
402 std::string wrapCall(const FunctionInfo& call, bool isFunction) 272 std::string wrapCall(const FunctionInfo& call, bool isFunction,
273 const FunctionInfo& instanceGetter)
403 { 274 {
404 bool hasStringArgs = false; 275 bool hasStringArgs = false;
405 std::vector<std::string> params; 276 std::vector<std::string> params;
406 std::string prefix; 277 std::string prefix;
407 278
408 if (isFunction) 279 if (isFunction)
409 prefix += "function"; 280 prefix += "function";
410 prefix += "("; 281 prefix += "(";
411 for (int i = 0; i < call.args.size(); i++) 282 for (int i = 0; i < call.args.size(); i++)
412 { 283 {
413 std::string argName("arg" + std::to_string(i)); 284 std::string argName("arg" + std::to_string(i));
414 if (i > 0) 285 if (i > 0)
415 prefix += ", "; 286 prefix += ", ";
416 prefix += argName; 287 prefix += argName;
417 288
418 if (call.args[i] == TypeCategory::STRING_REF) 289 if (call.args[i] == TypeCategory::STRING_REF)
419 { 290 {
420 hasStringArgs = true; 291 hasStringArgs = true;
421 params.push_back(std::string("createString(") + argName + ")"); 292 params.push_back(std::string("createString(") + argName + ")");
422 } 293 }
423 else if (call.args[i] == TypeCategory::CLASS_PTR) 294 else if (call.args[i] == TypeCategory::CLASS_PTR)
424 params.push_back(argName + " ? " + argName + "._pointer : 0"); 295 params.push_back(argName + " ? " + argName + "._pointer : 0");
Wladimir Palant 2017/05/01 14:47:25 Turns out we weren't supporting null for parameter
sergei 2017/05/08 10:54:39 In addition I wonder whether we can use C++ refere
Wladimir Palant 2017/05/08 12:55:41 We could use references easily but these won't be
sergei 2017/08/24 13:32:04 Currently one has to manually test whether a point
Wladimir Palant 2017/08/31 11:32:34 I filed https://issues.adblockplus.org/ticket/5603
425 else if (call.args[i] == TypeCategory::INT64) 296 else if (call.args[i] == TypeCategory::INT64)
426 { 297 {
427 // 64-bit integers are passed as two integer parameters 298 // 64-bit integers are passed as two integer parameters
428 params.push_back(argName + " >>> 0"); 299 params.push_back(argName + " >>> 0");
429 params.push_back(argName + " / 0x100000000 >>> 0"); 300 params.push_back(argName + " / 0x100000000 >>> 0");
430 } 301 }
431 else 302 else
432 params.push_back(argName); 303 params.push_back(argName);
433 } 304 }
434 prefix += ")\n{\n"; 305 prefix += ")\n{\n";
435 306
436 std::string suffix = "}"; 307 std::string suffix = "}";
437 if (call.returnType != TypeCategory::VOID) 308 if (call.returnType != TypeCategory::VOID)
438 suffix = " return result;\n" + suffix; 309 suffix = " return result;\n" + suffix;
439 310
440 if (call.returnType == TypeCategory::DEPENDENT_STRING || 311 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
441 call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) 312 call.returnType == TypeCategory::OWNED_STRING || hasStringArgs)
442 { 313 {
443 prefix += " var sp = Runtime.stackSave();\n"; 314 prefix += " var sp = Runtime.stackSave();\n";
444 suffix = " Runtime.stackRestore(sp);\n" + suffix; 315 suffix = " Runtime.stackRestore(sp);\n" + suffix;
445 } 316 }
446 317
447 if (call.instance_function) 318 if (call.instance_function)
448 params.insert(params.begin(), "this._pointer"); 319 {
320 if (instanceGetter.empty())
321 params.insert(params.begin(), "this._pointer");
322 else
323 params.insert(params.begin(), instanceGetter.name + "()");
324 }
449 325
450 return prefix + generateCall(call, params) + suffix; 326 return prefix + generateCall(call, params) + suffix;
451 } 327 }
452 328
453 void printHelpers() 329 void printHelpers()
454 { 330 {
455 printf("var sizeofString = %i;\n", sizeof(String)); 331 printf("var sizeofString = %i;\n", sizeof(String));
456 332
457 puts(R"( 333 puts(R"(
458 function copyString(str, buffer) 334 function copyString(str, buffer)
459 { 335 {
460 var length = str.length; 336 var length = str.length;
461 for (var i = 0, pointer = (buffer >> 1); i < length; i++, pointer++) 337 for (var i = 0, pointer = (buffer >> 1); i < length; i++, pointer++)
462 HEAP16[pointer] = str.charCodeAt(i); 338 HEAP16[pointer] = str.charCodeAt(i);
463 return length; 339 return length;
464 } 340 }
465 341
466 function createString(str) 342 function createString(str)
467 { 343 {
468 var length = 0; 344 var length = 0;
469 var buffer = 0; 345 var buffer = 0;
470 if (str) 346 if (str)
471 { 347 {
472 buffer = Runtime.stackAlloc(str.length * 2); 348 buffer = Runtime.stackAlloc(str.length * 2);
473 length = copyString(str, buffer); 349 length = copyString(str, buffer);
474 } 350 }
475 351
476 var result = Runtime.stackAlloc(sizeofString); 352 var result = Runtime.stackAlloc(sizeofString);
477 Module._InitString(result, buffer, length); 353 Module._InitString(result, buffer, length);
354 return result;
355 }
356
357 function createOwnedString()
358 {
359 var result = Runtime.stackAlloc(sizeofString);
360 Module._InitOwnedString(result);
478 return result; 361 return result;
479 } 362 }
480 363
481 function readString(str) 364 function readString(str)
482 { 365 {
483 var length = Module._GetStringLength(str); 366 var length = Module._GetStringLength(str);
484 var pointer = Module._GetStringData(str) >> 1; 367 var pointer = Module._GetStringData(str) >> 1;
485 return String.fromCharCode.apply(String, HEAP16.slice(pointer, pointer + length)); 368 return String.fromCharCode.apply(String, HEAP16.slice(pointer, pointer + length));
486 } 369 }
487 370
(...skipping 10 matching lines...) Expand all
498 Module._ReleaseRef(this._pointer + ref_counted_offset); 381 Module._ReleaseRef(this._pointer + ref_counted_offset);
499 }; 382 };
500 return result; 383 return result;
501 } 384 }
502 )"); 385 )");
503 } 386 }
504 387
505 void printClass(const ClassInfo& cls) 388 void printClass(const ClassInfo& cls)
506 { 389 {
507 // Begin class definition 390 // Begin class definition
508 ClassInfo* baseClass = find_class(cls.baseClass); 391 bool singleton = !cls.instanceGetter.empty();
509 printf("exports.%s = createClass(%s, %i, {\n", cls.name.c_str(), 392 if (singleton)
510 (baseClass ? ("exports." + baseClass->name).c_str() : "null"), 393 printf("exports.%s = {\n", cls.name.c_str());
511 cls.ref_counted_offset); 394 else
395 {
396 ClassInfo* baseClass = find_class(cls.baseClass);
397 printf("exports.%s = createClass(%s, %i, {\n", cls.name.c_str(),
398 (baseClass ? ("exports." + baseClass->name).c_str() : "null"),
399 cls.ref_counted_offset);
400 }
512 401
513 // Print prototype members 402 // Print prototype members
514 printProperties(cls.properties); 403 for (const auto& property : cls.properties)
515 printMethods(cls.methods); 404 {
405 if (property.jsValue.empty())
406 {
407 printf("get %s%s,\n", property.name.c_str(),
408 wrapCall(property.getter, false, cls.instanceGetter).c_str());
409 if (!property.setter.empty())
410 {
411 printf("set %s%s,\n", property.name.c_str(),
412 wrapCall(property.setter, false, cls.instanceGetter).c_str());
413 }
414 }
415 else
416 printf("%s: %s,\n", property.name.c_str(), property.jsValue.c_str());
417 }
418
419 for (const auto& method : cls.methods)
420 {
421 if (method.call.instance_function)
422 {
423 printf("%s: %s,\n",
424 method.name.c_str(),
425 wrapCall(method.call, true, cls.instanceGetter).c_str());
426 }
427 }
516 428
517 // End class definition 429 // End class definition
518 printf("});\n"); 430 if (singleton)
431 printf("};\n");
432 else
433 printf("});\n");
519 434
520 // Print static members 435 // Print static members
521 DifferentiatorInfo differentiator = cls.subclass_differentiator; 436 DifferentiatorInfo differentiator = cls.subclass_differentiator;
522 if (differentiator.offset != SIZE_MAX) 437 if (differentiator.offset != SIZE_MAX)
523 { 438 {
524 printf("var %s_mapping = \n", cls.name.c_str());
525 puts("{");
526 for (const auto& item : differentiator.mapping)
527 printf(" %i: '%s',\n", item.first, item.second.c_str());
528 puts("};");
529
530 printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); 439 printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str());
531 puts("{"); 440 puts("{");
532 printf(" var type = HEAP32[ptr + %i >> 2];\n", differentiator.offset); 441 printf(" var type = HEAP32[ptr + %i >> 2];\n", differentiator.offset);
533 printf(" if (type in %s_mapping)\n", cls.name.c_str()); 442 printf(" if (type in %s_mapping)\n", cls.name.c_str());
534 printf(" return new (exports[%s_mapping[type]])(ptr);\n", cls.name.c_st r()); 443 printf(" return new %s_mapping[type](ptr);\n", cls.name.c_str());
535 printf(" throw new Error('Unexpected %s type: ' + type);\n", cls.name.c_s tr()); 444 printf(" throw new Error('Unexpected %s type: ' + type);\n", cls.name.c_s tr());
536 puts("};"); 445 puts("};");
537 } 446 }
538 else 447 else
539 { 448 {
540 printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); 449 printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str());
541 puts("{"); 450 puts("{");
542 printf(" return new exports.%s(ptr);\n", cls.name.c_str()); 451 printf(" return new exports.%s(ptr);\n", cls.name.c_str());
543 puts("};"); 452 puts("};");
544 } 453 }
545 454
546 for (const auto& method : cls.methods) 455 for (const auto& method : cls.methods)
547 { 456 {
548 if (!method.call.instance_function) 457 if (!method.call.instance_function)
549 { 458 {
550 printf("exports.%s.%s = %s;\n", cls.name.c_str(), method.name.c_str(), 459 printf("exports.%s.%s = %s;\n", cls.name.c_str(), method.name.c_str(),
551 wrapCall(method.call).c_str()); 460 wrapCall(method.call).c_str());
552 } 461 }
553 } 462 }
554 } 463 }
555 464
556 void printNamespace(const NamespaceInfo& namespaceInfo) 465 void printClassMapping(const ClassInfo& cls)
557 { 466 {
558 printf("exports.%s = {\n", namespaceInfo.name.c_str()); 467 DifferentiatorInfo differentiator = cls.subclass_differentiator;
559 printProperties(namespaceInfo.properties); 468 if (differentiator.offset == SIZE_MAX)
560 printMethods(namespaceInfo.methods, false); 469 return;
561 puts("};"); 470
471 printf("var %s_mapping = \n", cls.name.c_str());
472 puts("{");
473 for (const auto& item : differentiator.mapping)
474 printf(" %i: exports.%s,\n", item.first, item.second.c_str());
475 puts("};");
562 } 476 }
563 } 477 }
564 478
565 void printBindings() 479 void printBindings()
566 { 480 {
567 bindings_internal::printHelpers(); 481 bindings_internal::printHelpers();
568 482
569 for (const auto& item : classes) 483 for (const auto& cls : classes)
570 bindings_internal::printClass(item); 484 bindings_internal::printClass(cls);
571 for (const auto& item : namespaces) 485 for (const auto& cls : classes)
572 bindings_internal::printNamespace(item); 486 bindings_internal::printClassMapping(cls);
573 } 487 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld