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

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

Issue 29410617: Issue 5131 - [emscripten] Clean separation of bindings code and runtime code (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Patch Set: Created April 12, 2017, 2:07 p.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 #pragma once 18 #include "generator.h"
19 19
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstdio> 20 #include <cstdio>
23 #include <cstdlib> 21
24 #include <exception> 22 namespace
25 #include <functional> 23 {
26 #include <map> 24 std::vector<bindings_internal::ClassInfo> classes;
Wladimir Palant 2017/04/12 14:17:00 I found two bad assumptions here which went wrong
sergei 2017/04/18 10:46:09 That's correct, pointers and iterators are invalid
27 #include <string> 25 std::vector<bindings_internal::CustomGenerator> customGenerators;
28 #include <type_traits> 26 }
29 #include <utility>
30 #include <vector>
31
32 #include <emscripten.h>
33
34 #include "String.h"
35 #include "intrusive_ptr.h"
36 27
37 namespace bindings_internal 28 namespace bindings_internal
38 { 29 {
39 typedef void* TYPEID; 30 FunctionInfo::FunctionInfo()
40 31 {
41 enum class TypeCategory 32 name[0] = '\0';
42 { 33 }
43 UNKNOWN, 34
44 VOID, 35 FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType,
45 INT, 36 std::initializer_list<TypeCategory> argTypes, bool instance_function,
46 INT64, 37 void* function)
47 FLOAT, 38 : returnType(returnType), pointerType(pointerType),
48 DEPENDENT_STRING, 39 instance_function(instance_function)
49 OWNED_STRING, 40 {
50 STRING_REF, 41 name[0] = '\0';
51 CLASS_PTR 42
52 }; 43 // The function parameter is a pointer to the function pointer.
53 44 // Emscripten's "function pointers" are actually integers indicating the
54 template<typename T> 45 // position in the call table. 0 represents nullptr.
55 struct TypeInfo 46 if (!*reinterpret_cast<int*>(function))
56 { 47 return;
57 /* 48
58 * Since TypeInfo is a templated type, in practice the compiler will define 49 std::string signature;
59 * a new type for each possible template parameter value. We use that fact 50 if (returnType == TypeCategory::DEPENDENT_STRING ||
60 * to generate type identifiers: each of these TypeInfo types has a 51 returnType == TypeCategory::OWNED_STRING)
61 * different s_typeIDHelper member, so we use a pointer to that static 52 {
62 * variable as a type identifier - it will be different for each template 53 // Objects aren't really returned but passed as parameter. Note that
63 * parameter. 54 // this pointer might come before it but we don't care because both
64 */ 55 // are integers (pointers) as far as Emscripten is concerned.
65 static char s_typeIDHelper; 56 signature += "vi";
66 constexpr operator TYPEID() const 57 }
67 { 58 else if (returnType == TypeCategory::VOID)
68 return &s_typeIDHelper; 59 signature += 'v';
69 } 60 else if (returnType == TypeCategory::FLOAT)
70 61 signature += 'd';
71 constexpr operator TypeCategory() const 62 else if (returnType == TypeCategory::INT ||
72 { 63 returnType == TypeCategory::INT64 ||
73 if (std::is_void<T>()) 64 returnType == TypeCategory::STRING_REF ||
74 return TypeCategory::VOID; 65 returnType == TypeCategory::CLASS_PTR)
75 66 {
76 if (std::is_same<T, uint64_t>()) 67 signature += 'i';
77 return TypeCategory::INT64; 68 }
78 69 else
79 if (std::is_integral<T>() || std::is_enum<T>()) 70 throw std::runtime_error("Unexpected function return type");
80 return TypeCategory::INT; 71
81 72 if (instance_function)
82 if (std::is_floating_point<T>()) 73 {
83 return TypeCategory::FLOAT; 74 // this pointer is an implicit parameter
84 75 signature += 'i';
85 if (std::is_same<DependentString, T>() || std::is_same<const DependentStri ng, T>()) 76 }
86 return TypeCategory::DEPENDENT_STRING; 77
87 78 for (const auto& item : argTypes)
88 if (std::is_same<OwnedString, T>() || std::is_same<const OwnedString, T>() ) 79 {
89 return TypeCategory::OWNED_STRING; 80 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF ||
90 81 item == TypeCategory::CLASS_PTR)
91 if (std::is_same<String&, T>() || std::is_same<const String&, T>() || 82 {
92 std::is_same<DependentString&, T>()) 83 signature += 'i';
93 { 84 }
94 return TypeCategory::STRING_REF; 85 else if (item == TypeCategory::INT64)
95 } 86 signature += "ii";
96 87 else if (item == TypeCategory::FLOAT)
97 if (std::is_pointer<T>() && std::is_class<typename std::remove_pointer<T>: :type>()) 88 signature += 'd';
98 return TypeCategory::CLASS_PTR;
99
100 return TypeCategory::UNKNOWN;
101 }
102
103 constexpr TYPEID pointer_type() const
104 {
105 if (std::is_pointer<T>())
106 return TypeInfo<typename std::remove_pointer<T>::type>();
107 else 89 else
108 return nullptr; 90 throw std::runtime_error("Unexpected function argument type");
109 } 91 args.push_back(item);
110 }; 92 }
111 93
112 template<typename T> 94 get_function_name(function, signature.c_str());
113 char TypeInfo<T>::s_typeIDHelper; 95 }
114 96
115 struct FunctionInfo 97 bool FunctionInfo::empty() const
116 { 98 {
117 TypeCategory returnType; 99 return name[0] == '\0';
118 TYPEID pointerType; 100 }
119 std::vector<TypeCategory> args; 101
120 bool instance_function; 102 void FunctionInfo::get_function_name(void* ptr, const char* signature)
121 int effectiveArgs; 103 {
122 TypeCategory effectiveReturnType; 104 // This is a hack, C++ won't let us get the mangled function name.
123 char name[1024]; 105 // JavaScript is more dynamic so we pass the pointer to our function
124 106 // there. With that and the function signature we can call the function -
125 FunctionInfo() 107 // with a full stack so that we will cause it to abort. Sometimes the
126 { 108 // function we are calling will also be missing from the build. The result
127 name[0] = '\0'; 109 // is the same: abort() is called which in turn calls stackTrace(). By
128 } 110 // replacing stackTrace() we get access to the call stack and search it
129 111 // for the name of our function.
130 FunctionInfo(TypeCategory returnType, TYPEID pointerType, 112
131 std::initializer_list<TypeCategory> argTypes, bool instance_function, 113 EM_ASM_ARGS({
132 void* function) 114 var signature = AsciiToString($2);
133 : returnType(returnType), pointerType(pointerType), 115 var args = [];
134 instance_function(instance_function) 116 for (var i = 1; i < signature.length; i++)
135 { 117 args.push(0);
136 name[0] = '\0'; 118
137 119 var oldPrint = Module.print;
138 // The function parameter is a pointer to the function pointer. 120 var oldPrintErr = Module.printErr;
139 // Emscripten's "function pointers" are actually integers indicating the 121 var oldStackTrace = stackTrace;
140 // position in the call table. 0 represents nullptr. 122 var sp = Runtime.stackSave();
141 if (!*reinterpret_cast<int*>(function)) 123 Module.print = function(){};
142 return; 124 Module.printErr = function(){};
143 125 stackTrace = function()
144 std::string signature; 126 {
145 if (returnType == TypeCategory::DEPENDENT_STRING || 127 var stack = [];
146 returnType == TypeCategory::OWNED_STRING) 128 for (var f = arguments.callee.caller; f; f = f.caller)
147 {
148 // Objects aren't really returned but passed as parameter. Note that
149 // this pointer might come before it but we don't care because both
150 // are integers (pointers) as far as Emscripten is concerned.
151 signature += "vi";
152 }
153 else if (returnType == TypeCategory::VOID)
154 signature += 'v';
155 else if (returnType == TypeCategory::FLOAT)
156 signature += 'd';
157 else if (returnType == TypeCategory::INT ||
158 returnType == TypeCategory::INT64 ||
159 returnType == TypeCategory::STRING_REF ||
160 returnType == TypeCategory::CLASS_PTR)
161 {
162 signature += 'i';
163 }
164 else
165 throw std::runtime_error("Unexpected function return type");
166
167 if (instance_function)
168 {
169 // this pointer is an implicit parameter
170 signature += 'i';
171 }
172
173 for (const auto& item : argTypes)
174 {
175 if (item == TypeCategory::INT || item == TypeCategory::STRING_REF ||
176 item == TypeCategory::CLASS_PTR)
177 { 129 {
178 signature += 'i'; 130 if (f.name)
131 {
132 if (f.name.indexOf("dynCall") == 0)
133 break;
134 else
135 stack.push(f.name);
136 }
179 } 137 }
180 else if (item == TypeCategory::INT64) 138
181 signature += "ii"; 139 result = stack[stack.length - 1];
182 else if (item == TypeCategory::FLOAT) 140 if (result && result.indexOf("__wrapper") >= 0)
183 signature += 'd'; 141 result = stack[stack.length - 2];
184 else 142 throw result;
185 throw std::runtime_error("Unexpected function argument type"); 143 };
186 args.push_back(item); 144
187 } 145 Runtime.stackRestore(STACK_MAX);
188 146
189 get_function_name(function, signature.c_str()); 147 try
190 } 148 {
191 149 Runtime.dynCall(signature, HEAP32[$1 >> 2], args);
192 template<typename ReturnType, typename... Args> 150 }
193 FunctionInfo(ReturnType (*function)(Args...)) 151 catch(e)
194 : FunctionInfo(TypeInfo<ReturnType>(), 152 {
195 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, 153 Module.stringToAscii(e, $0);
196 &function) 154 }
197 { 155 finally
198 } 156 {
199 157 Runtime.stackRestore(sp);
200 template<typename ClassType, typename ReturnType, typename... Args> 158 Module.print = oldPrint;
201 FunctionInfo(ReturnType (ClassType::*function)(Args...)) 159 Module.printErr = oldPrintErr;
202 : FunctionInfo(TypeInfo<ReturnType>(), 160 stackTrace = oldStackTrace;
203 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, 161 }
204 &function) 162 }, name, ptr, signature);
205 { 163 }
206 } 164
207 165 ClassInfo* find_class(TYPEID classID)
208 template<typename ClassType, typename ReturnType, typename... Args> 166 {
209 FunctionInfo(ReturnType (ClassType::*function)(Args...) const) 167 for (auto& classInfo : classes)
210 : FunctionInfo(TypeInfo<ReturnType>(), 168 if (classInfo.id == classID)
211 TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, 169 return &classInfo;
212 &function) 170 return nullptr;
213 { 171 }
214 }
215
216 bool empty() const
217 {
218 return name[0] == '\0';
219 }
220
221 void get_function_name(void* ptr, const char* signature)
222 {
223 // This is a hack, C++ won't let us get the mangled function name.
224 // JavaScript is more dynamic so we pass the pointer to our function
225 // there. With that and the function signature we can call the function -
226 // with a full stack so that we will cause it to abort. Sometimes the
227 // function we are calling will also be missing from the build. The result
228 // is the same: abort() is called which in turn calls stackTrace(). By
229 // replacing stackTrace() we get access to the call stack and search it
230 // for the name of our function.
231
232 EM_ASM_ARGS({
233 var signature = AsciiToString($2);
234 var args = [];
235 for (var i = 1; i < signature.length; i++)
236 args.push(0);
237
238 var oldPrint = Module.print;
239 var oldPrintErr = Module.printErr;
240 var oldStackTrace = stackTrace;
241 var sp = Runtime.stackSave();
242 Module.print = function(){};
243 Module.printErr = function(){};
244 stackTrace = function()
245 {
246 var stack = [];
247 for (var f = arguments.callee.caller; f; f = f.caller)
248 {
249 if (f.name)
250 {
251 if (f.name.indexOf("dynCall") == 0)
252 break;
253 else
254 stack.push(f.name);
255 }
256 }
257
258 result = stack[stack.length - 1];
259 if (result && result.indexOf("__wrapper") >= 0)
260 result = stack[stack.length - 2];
261 throw result;
262 };
263
264 Runtime.stackRestore(STACK_MAX);
265
266 try
267 {
268 Runtime.dynCall(signature, HEAP32[$1 >> 2], args);
269 }
270 catch(e)
271 {
272 Module.stringToAscii(e, $0);
273 }
274 finally
275 {
276 Runtime.stackRestore(sp);
277 Module.print = oldPrint;
278 Module.printErr = oldPrintErr;
279 stackTrace = oldStackTrace;
280 }
281 }, name, ptr, signature);
282 }
283 };
284
285 class NoBaseClass
286 {
287 };
288
289 struct PropertyInfo
290 {
291 std::string name;
292 FunctionInfo getter;
293 FunctionInfo setter;
294 std::string jsValue;
295 };
296
297 struct MethodInfo
298 {
299 std::string name;
300 FunctionInfo call;
301 };
302
303 struct DifferentiatorInfo
304 {
305 size_t offset;
306 std::vector<std::pair<int, std::string>> mapping;
307 };
308
309 struct ClassInfo
310 {
311 ClassInfo* baseClass;
312 std::string name;
313 std::vector<PropertyInfo> properties;
314 std::vector<MethodInfo> methods;
315 DifferentiatorInfo subclass_differentiator;
316 ptrdiff_t ref_counted_offset;
317 };
318
319 typedef std::function<void()> CustomGenerator;
320
321 std::map<TYPEID, ClassInfo> classes;
322 std::vector<CustomGenerator> customGenerators;
323 172
324 void register_class(const char* name, TYPEID classID, TYPEID baseClassID, 173 void register_class(const char* name, TYPEID classID, TYPEID baseClassID,
325 ptrdiff_t ref_counted_offset) 174 ptrdiff_t ref_counted_offset)
326 { 175 {
327 auto it = classes.find(classID); 176 if (find_class(classID))
328 if (it != classes.end())
329 throw std::runtime_error(std::string("Duplicate definition for class ") + name); 177 throw std::runtime_error(std::string("Duplicate definition for class ") + name);
330 178
331 ClassInfo* baseClass = nullptr; 179 if (baseClassID != TypeInfo<NoBaseClass>() && !find_class(baseClassID))
332 if (baseClassID != TypeInfo<NoBaseClass>()) 180 throw std::runtime_error(std::string("Unknown base class defined for class ") + name);
333 {
334 it = classes.find(baseClassID);
335 if (it == classes.end())
336 throw std::runtime_error(std::string("Unknown base class defined for cla ss ") + name);
337 baseClass = &(it->second);
338 }
339 181
340 ClassInfo classInfo; 182 ClassInfo classInfo;
341 classInfo.baseClass = baseClass; 183 classInfo.id = classID;
184 classInfo.baseClass = baseClassID;
342 classInfo.name = name; 185 classInfo.name = name;
343 classInfo.subclass_differentiator.offset = SIZE_MAX; 186 classInfo.subclass_differentiator.offset = SIZE_MAX;
344 classInfo.ref_counted_offset = ref_counted_offset; 187 classInfo.ref_counted_offset = ref_counted_offset;
345 classes[classID] = classInfo; 188 classes.push_back(classInfo);
346 } 189 }
347 190
348 void register_property(TYPEID classID, const char* name, 191 void register_property(TYPEID classID, const char* name,
349 const FunctionInfo& getter, const FunctionInfo& setter, 192 const FunctionInfo& getter, const FunctionInfo& setter,
350 const char* jsValue = "") 193 const char* jsValue)
351 { 194 {
352 auto it = classes.find(classID); 195 ClassInfo* classInfo = find_class(classID);
353 if (it == classes.end()) 196 if (!classInfo)
354 throw std::runtime_error(std::string("Property defined on unknown class: " ) + name); 197 throw std::runtime_error(std::string("Property defined on unknown class: " ) + name);
355 198
356 PropertyInfo propertyInfo; 199 PropertyInfo propertyInfo;
357 propertyInfo.name = name; 200 propertyInfo.name = name;
358 propertyInfo.getter = getter; 201 propertyInfo.getter = getter;
359 propertyInfo.setter = setter; 202 propertyInfo.setter = setter;
360 propertyInfo.jsValue = jsValue; 203 propertyInfo.jsValue = jsValue;
361 it->second.properties.push_back(propertyInfo); 204 classInfo->properties.push_back(propertyInfo);
362 } 205 }
363 206
364 void register_method(TYPEID classID, const char* name, 207 void register_method(TYPEID classID, const char* name,
365 const FunctionInfo& call) 208 const FunctionInfo& call)
366 { 209 {
367 auto it = classes.find(classID); 210 ClassInfo* classInfo = find_class(classID);
368 if (it == classes.end()) 211 if (!classInfo)
369 throw std::runtime_error(std::string("Method defined on unknown class: ") + name); 212 throw std::runtime_error(std::string("Method defined on unknown class: ") + name);
370 213
371 MethodInfo methodInfo; 214 MethodInfo methodInfo;
372 methodInfo.name = name; 215 methodInfo.name = name;
373 methodInfo.call = call; 216 methodInfo.call = call;
374 it->second.methods.push_back(methodInfo); 217 classInfo->methods.push_back(methodInfo);
375 } 218 }
376 219
377 void register_differentiator(TYPEID classID, size_t offset, 220 void register_differentiator(TYPEID classID, size_t offset,
378 std::vector<std::pair<int, std::string>>& mapping) 221 std::vector<std::pair<int, std::string>>& mapping)
379 { 222 {
380 auto it = classes.find(classID); 223 ClassInfo* classInfo = find_class(classID);
381 if (it == classes.end()) 224 if (!classInfo)
382 throw std::runtime_error("Subclass differentiator defined on unknown class "); 225 throw std::runtime_error("Subclass differentiator defined on unknown class ");
383 226
384 if (it->second.subclass_differentiator.offset != SIZE_MAX) 227 if (classInfo->subclass_differentiator.offset != SIZE_MAX)
385 throw std::runtime_error("More than one subclass differentiator defined fo r class " + it->second.name); 228 throw std::runtime_error("More than one subclass differentiator defined fo r class " + classInfo->name);
386 229
387 DifferentiatorInfo differentiatorInfo; 230 DifferentiatorInfo differentiatorInfo;
388 differentiatorInfo.offset = offset; 231 differentiatorInfo.offset = offset;
389 differentiatorInfo.mapping = mapping; 232 differentiatorInfo.mapping = mapping;
390 it->second.subclass_differentiator = differentiatorInfo; 233 classInfo->subclass_differentiator = differentiatorInfo;
391 } 234 }
392 235
393 const std::string generateCall(const FunctionInfo& call, 236 const std::string generateCall(const FunctionInfo& call,
394 std::vector<std::string>& params) 237 std::vector<std::string>& params)
395 { 238 {
396 if (call.returnType == TypeCategory::DEPENDENT_STRING || 239 if (call.returnType == TypeCategory::DEPENDENT_STRING ||
397 call.returnType == TypeCategory::OWNED_STRING) 240 call.returnType == TypeCategory::OWNED_STRING)
398 { 241 {
399 params.insert(params.begin(), "string"); 242 params.insert(params.begin(), "string");
400 } 243 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
439 { 282 {
440 return " var result = readString(" + call_str + ");\n"; 283 return " var result = readString(" + call_str + ");\n";
441 } 284 }
442 else if (call.returnType == TypeCategory::CLASS_PTR) 285 else if (call.returnType == TypeCategory::CLASS_PTR)
443 { 286 {
444 std::string result; 287 std::string result;
445 result += " var result = " + call_str + ";\n"; 288 result += " var result = " + call_str + ";\n";
446 result += " if (result)\n"; 289 result += " if (result)\n";
447 result += " {\n"; 290 result += " {\n";
448 291
449 auto it = classes.find(call.pointerType); 292 const ClassInfo* cls = find_class(call.pointerType);
450 if (it == classes.end()) 293 if (!cls)
451 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class"); 294 throw std::runtime_error("Function " + std::string(call.name) + " return s pointer to unknown class");
452 295
453 const ClassInfo& cls = it->second; 296 auto offset = cls->subclass_differentiator.offset;
454 auto offset = cls.subclass_differentiator.offset;
455 if (offset == SIZE_MAX) 297 if (offset == SIZE_MAX)
456 result += " result = exports." + cls.name + "(result);\n"; 298 result += " result = exports." + cls->name + "(result);\n";
457 else 299 else
458 result += " result = exports." + cls.name + ".fromPointer(result);\n" ; 300 result += " result = exports." + cls->name + ".fromPointer(result);\n ";
459 301
460 result += " }\n"; 302 result += " }\n";
461 result += " else\n"; 303 result += " else\n";
462 result += " result = null;\n"; 304 result += " result = null;\n";
463 return result; 305 return result;
464 } 306 }
465 else 307 else
466 throw std::runtime_error("Unexpected return type for " + std::string(call. name)); 308 throw std::runtime_error("Unexpected return type for " + std::string(call. name));
467 } 309 }
468 310
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
571 { 413 {
572 Module._ReleaseRef(this._pointer + ref_counted_offset); 414 Module._ReleaseRef(this._pointer + ref_counted_offset);
573 }; 415 };
574 return result; 416 return result;
575 } 417 }
576 )"); 418 )");
577 } 419 }
578 420
579 void printClass(const ClassInfo& cls) 421 void printClass(const ClassInfo& cls)
580 { 422 {
423 ClassInfo* baseClass = find_class(cls.baseClass);
581 printf("exports.%s = createClass(%s, %i);\n", cls.name.c_str(), 424 printf("exports.%s = createClass(%s, %i);\n", cls.name.c_str(),
582 (cls.baseClass ? ("exports." + cls.baseClass->name).c_str() : "null"), 425 (baseClass ? ("exports." + baseClass->name).c_str() : "null"),
583 cls.ref_counted_offset); 426 cls.ref_counted_offset);
584 427
585 DifferentiatorInfo differentiator = cls.subclass_differentiator; 428 DifferentiatorInfo differentiator = cls.subclass_differentiator;
586 if (differentiator.offset != SIZE_MAX) 429 if (differentiator.offset != SIZE_MAX)
587 { 430 {
588 printf("var %s_mapping = \n", cls.name.c_str()); 431 printf("var %s_mapping = \n", cls.name.c_str());
589 puts("{"); 432 puts("{");
590 for (const auto& item : differentiator.mapping) 433 for (const auto& item : differentiator.mapping)
591 printf(" %i: '%s',\n", item.first, item.second.c_str()); 434 printf(" %i: '%s',\n", item.first, item.second.c_str());
592 puts("};"); 435 puts("};");
(...skipping 23 matching lines...) Expand all
616 459
617 for (const auto& item : cls.methods) 460 for (const auto& item : cls.methods)
618 { 461 {
619 std::string obj("exports." + cls.name); 462 std::string obj("exports." + cls.name);
620 if (item.call.instance_function) 463 if (item.call.instance_function)
621 obj += ".prototype"; 464 obj += ".prototype";
622 printf("%s.%s = %s;\n", obj.c_str(), item.name.c_str(), 465 printf("%s.%s = %s;\n", obj.c_str(), item.name.c_str(),
623 wrapCall(item.call).c_str()); 466 wrapCall(item.call).c_str());
624 } 467 }
625 } 468 }
626
627 void printBindings()
628 {
629 printHelpers();
630
631 for (const auto& item : classes)
632 printClass(item.second);
633
634 for (const auto& item : customGenerators)
635 item();
636 }
637 } 469 }
638 470
639 #if defined(PRINT_BINDINGS) 471 void printBindings()
640 // Bindings generation step: collect bindings information and print 472 {
641 // corresponding JS code. 473 bindings_internal::printHelpers();
642 #define EMSCRIPTEN_BINDINGS \
643 void InitializeBindings();\
644 int main()\
645 {\
646 try\
647 {\
648 InitializeBindings();\
649 bindings_internal::printBindings();\
650 }\
651 catch (const std::exception& e)\
652 {\
653 EM_ASM_ARGS(\
654 console.error("Error occurred generating JavaScript bindings: " +\
655 Module.AsciiToString($0)), e.what()\
656 );\
657 abort();\
658 }\
659 return 0;\
660 }\
661 void InitializeBindings()
662 #else
663 // Actual compilation step: ignore bindings information but define some
664 // exported helper functions necessary for the bindings.
665 #define EMSCRIPTEN_BINDINGS \
666 extern "C"\
667 {\
668 void EMSCRIPTEN_KEEPALIVE InitString(DependentString* str,\
669 String::value_type* data, String::size_type len)\
670 {\
671 /* String is already allocated on stack, we merely need to call*/\
672 /* constructor.*/\
673 new (str) DependentString(data, len);\
674 }\
675 void EMSCRIPTEN_KEEPALIVE DestroyString(OwnedString* str)\
676 {\
677 /* Stack memory will be freed automatically, we need to call*/\
678 /* destructor explicitly however.*/\
679 str->~OwnedString();\
680 }\
681 String::size_type EMSCRIPTEN_KEEPALIVE GetStringLength(\
682 const String& str)\
683 {\
684 return str.length();\
685 }\
686 const String::value_type* EMSCRIPTEN_KEEPALIVE GetStringData(\
687 const String& str)\
688 {\
689 return str.data();\
690 }\
691 void EMSCRIPTEN_KEEPALIVE ReleaseRef(ref_counted* ptr)\
692 {\
693 ptr->ReleaseRef();\
694 }\
695 }\
696 void BindingsInitializer_dummy()
697 #endif
698 474
699 template<typename ClassType, 475 for (const auto& item : classes)
700 typename BaseClass = bindings_internal::NoBaseClass, 476 bindings_internal::printClass(item);
701 typename std::enable_if<std::is_base_of<ref_counted, ClassType>::value>::typ e* = nullptr>
702 class class_
703 {
704 public:
705 class_(const char* name)
706 {
707 ClassType* ptr = reinterpret_cast<ClassType*>(0x10000000);
708 ptrdiff_t ref_counted_offset =
709 reinterpret_cast<char*>(static_cast<ref_counted*>(ptr)) -
710 reinterpret_cast<char*>(ptr);
711 bindings_internal::register_class(name,
712 bindings_internal::TypeInfo<ClassType>(),
713 bindings_internal::TypeInfo<BaseClass>(),
714 ref_counted_offset
715 );
716 }
717 477
718 template<typename FieldType> 478 for (const auto& item : customGenerators)
719 const class_& property(const char* name, 479 item();
720 FieldType (ClassType::*getter)() const, 480 }
721 void (ClassType::*setter)(FieldType) = nullptr) const
722 {
723 bindings_internal::register_property(
724 bindings_internal::TypeInfo<ClassType>(), name, getter, setter);
725 return *this;
726 }
727
728 const class_& class_property(const char* name,
729 const char* jsValue) const
730 {
731 bindings_internal::register_property(
732 bindings_internal::TypeInfo<ClassType>(), name,
733 bindings_internal::FunctionInfo(), bindings_internal::FunctionInfo(),
734 jsValue);
735 return *this;
736 }
737
738 template<typename ReturnType, typename... Args>
739 const class_& function(const char* name, ReturnType (ClassType::*method)(Args. ..)) const
740 {
741 bindings_internal::register_method(
742 bindings_internal::TypeInfo<ClassType>(), name, method);
743 return *this;
744 }
745
746 template<typename ReturnType, typename... Args>
747 const class_& function(const char* name, ReturnType (ClassType::*method)(Args. ..) const) const
748 {
749 bindings_internal::register_method(
750 bindings_internal::TypeInfo<ClassType>(), name, method);
751 return *this;
752 }
753
754 template<typename ReturnType, typename... Args>
755 const class_& class_function(const char* name, ReturnType (*method)(Args...)) const
756 {
757 bindings_internal::register_method(
758 bindings_internal::TypeInfo<ClassType>(), name, method);
759 return *this;
760 }
761
762 template<typename ReturnType,
763 typename std::enable_if<std::is_convertible<ReturnType, int32_t>::value>:: type* = nullptr>
764 const class_& subclass_differentiator(ReturnType ClassType::* member,
765 std::initializer_list<std::pair<ReturnType, const char*>> list) const
766 {
767 ClassType* instance = nullptr;
768 size_t offset = (char*)&(instance->*member) - (char*)instance;
769
770 std::vector<std::pair<int, std::string>> mapping;
771 for (const auto& item : list)
772 mapping.emplace_back(item.first, item.second);
773
774 bindings_internal::register_differentiator(
775 bindings_internal::TypeInfo<ClassType>(), offset, mapping);
776 return *this;
777 }
778 };
779 481
780 void custom_generator(bindings_internal::CustomGenerator generator) 482 void custom_generator(bindings_internal::CustomGenerator generator)
781 { 483 {
782 bindings_internal::customGenerators.push_back(generator); 484 customGenerators.push_back(generator);
783 } 485 }
OLDNEW

Powered by Google App Engine
This is Rietveld