]> git.saurik.com Git - cycript.git/blob - Execute.cpp
Analyze even more headers and added enum typedefs.
[cycript.git] / Execute.cpp
1 /* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include "cycript.hpp"
23
24 #include <iostream>
25 #include <set>
26 #include <map>
27 #include <iomanip>
28 #include <sstream>
29 #include <cmath>
30
31 #include <dlfcn.h>
32 #include <dirent.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38
39 #include <sqlite3.h>
40
41 #include "sig/parse.hpp"
42 #include "sig/ffi_type.hpp"
43
44 #include "Bridge.hpp"
45 #include "Code.hpp"
46 #include "Decode.hpp"
47 #include "Error.hpp"
48 #include "Execute.hpp"
49 #include "Internal.hpp"
50 #include "JavaScript.hpp"
51 #include "Pooling.hpp"
52 #include "String.hpp"
53
54 const char *sqlite3_column_string(sqlite3_stmt *stmt, int n) {
55 return reinterpret_cast<const char *>(sqlite3_column_text(stmt, n));
56 }
57
58 char *sqlite3_column_pooled(CYPool &pool, sqlite3_stmt *stmt, int n) {
59 if (const char *value = sqlite3_column_string(stmt, n))
60 return pool.strdup(value);
61 else return NULL;
62 }
63
64 static std::vector<CYHook *> &GetHooks() {
65 static std::vector<CYHook *> hooks;
66 return hooks;
67 }
68
69 CYRegisterHook::CYRegisterHook(CYHook *hook) {
70 GetHooks().push_back(hook);
71 }
72
73 /* JavaScript Properties {{{ */
74 bool CYHasProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
75 return JSObjectHasProperty(context, object, name);
76 }
77
78 JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, size_t index) {
79 return _jsccall(JSObjectGetPropertyAtIndex, context, object, index);
80 }
81
82 JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
83 return _jsccall(JSObjectGetProperty, context, object, name);
84 }
85
86 void CYSetProperty(JSContextRef context, JSObjectRef object, size_t index, JSValueRef value) {
87 _jsccall(JSObjectSetPropertyAtIndex, context, object, index, value);
88 }
89
90 void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef value, JSPropertyAttributes attributes) {
91 _jsccall(JSObjectSetProperty, context, object, name, value, attributes);
92 }
93
94 void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef (*callback)(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef *), JSPropertyAttributes attributes) {
95 CYSetProperty(context, object, name, JSObjectMakeFunctionWithCallback(context, name, callback), attributes);
96 }
97
98 JSObjectRef CYGetPrototype(JSContextRef context, JSObjectRef object) {
99 return CYCastJSObject(context, JSObjectGetPrototype(context, object));
100 }
101
102 void CYSetPrototype(JSContextRef context, JSObjectRef object, JSValueRef value) {
103 _assert(!JSValueIsUndefined(context, value));
104 JSObjectSetPrototype(context, object, value);
105 _assert(CYIsStrictEqual(context, JSObjectGetPrototype(context, object), value));
106 }
107 /* }}} */
108 /* JavaScript Strings {{{ */
109 JSStringRef CYCopyJSString(const char *value) {
110 return value == NULL ? NULL : JSStringCreateWithUTF8CString(value);
111 }
112
113 JSStringRef CYCopyJSString(JSStringRef value) {
114 return value == NULL ? NULL : JSStringRetain(value);
115 }
116
117 JSStringRef CYCopyJSString(CYUTF8String value) {
118 if (memchr(value.data, '\0', value.size) != NULL) {
119 CYPool pool;
120 return CYCopyJSString(CYPoolUTF16String(pool, value));
121 } else if (value.data[value.size] != '\0') {
122 CYPool pool;
123 return CYCopyJSString(pool.strmemdup(value.data, value.size));
124 } else {
125 return CYCopyJSString(value.data);
126 }
127 }
128
129 JSStringRef CYCopyJSString(const std::string &value) {
130 return CYCopyJSString(CYUTF8String(value.c_str(), value.size()));
131 }
132
133 JSStringRef CYCopyJSString(CYUTF16String value) {
134 return JSStringCreateWithCharacters(value.data, value.size);
135 }
136
137 JSStringRef CYCopyJSString(JSContextRef context, JSValueRef value) {
138 if (JSValueIsNull(context, value))
139 return NULL;
140 return _jsccall(JSValueToStringCopy, context, value);
141 }
142
143 CYUTF16String CYCastUTF16String(JSStringRef value) {
144 return CYUTF16String(JSStringGetCharactersPtr(value), JSStringGetLength(value));
145 }
146
147 const char *CYPoolCString(CYPool &pool, CYUTF8String utf8) {
148 return pool.strndup(utf8.data, utf8.size);
149 }
150
151 CYUTF8String CYPoolUTF8String(CYPool &pool, JSContextRef context, JSStringRef value) {
152 return CYPoolUTF8String(pool, CYCastUTF16String(value));
153 }
154
155 const char *CYPoolCString(CYPool &pool, JSContextRef context, JSStringRef value) {
156 CYUTF8String utf8(CYPoolUTF8String(pool, context, value));
157 _assert(memchr(utf8.data, '\0', utf8.size) == NULL);
158 return utf8.data;
159 }
160
161 const char *CYPoolCString(CYPool &pool, JSContextRef context, JSValueRef value) {
162 return JSValueIsNull(context, value) ? NULL : CYPoolCString(pool, context, CYJSString(context, value));
163 }
164 /* }}} */
165 /* Index Offsets {{{ */
166 size_t CYGetIndex(CYPool &pool, JSContextRef context, JSStringRef value) {
167 return CYGetIndex(CYPoolUTF8String(pool, context, value));
168 }
169 /* }}} */
170
171 static JSObjectRef (*JSObjectMakeArray$)(JSContextRef, size_t, const JSValueRef[], JSValueRef *);
172
173 JSObjectRef CYObjectMakeArray(JSContextRef context, size_t length, const JSValueRef values[]) {
174 if (JSObjectMakeArray$ != NULL)
175 return _jsccall(*JSObjectMakeArray$, context, length, values);
176 else {
177 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
178 JSValueRef value(CYCallAsFunction(context, Array, NULL, length, values));
179 return CYCastJSObject(context, value);
180 }
181 }
182
183 static JSClassRef All_;
184 JSClassRef Functor_;
185 static JSClassRef Global_;
186
187 JSStringRef Array_s;
188 JSStringRef constructor_s;
189 JSStringRef cy_s;
190 JSStringRef cyi_s;
191 JSStringRef cyt_s;
192 JSStringRef length_s;
193 JSStringRef message_s;
194 JSStringRef name_s;
195 JSStringRef pop_s;
196 JSStringRef prototype_s;
197 JSStringRef push_s;
198 JSStringRef splice_s;
199 JSStringRef toCYON_s;
200 JSStringRef toJSON_s;
201 JSStringRef toPointer_s;
202 JSStringRef toString_s;
203 JSStringRef weak_s;
204
205 static sqlite3 *database_;
206
207 static JSStringRef Result_;
208
209 void CYFinalize(JSObjectRef object) {
210 CYData *internal(reinterpret_cast<CYData *>(JSObjectGetPrivate(object)));
211 _assert(internal->count_ != _not(unsigned));
212 if (--internal->count_ == 0)
213 delete internal;
214 }
215
216 sig::Type *Structor_(CYPool &pool, sig::Aggregate *aggregate) {
217 //_assert(false);
218 return aggregate;
219 }
220
221 struct Context :
222 CYPrivate<Context>
223 {
224 JSGlobalContextRef context_;
225
226 Context(JSGlobalContextRef context) :
227 context_(context)
228 {
229 }
230 };
231
232 struct CArray :
233 CYValue<CArray, void *>
234 {
235 CYProtect owner_;
236 Type_privateData *type_;
237 size_t length_;
238
239 CArray(void *value, size_t length, const sig::Type &type, ffi_type *ffi, JSContextRef context, JSObjectRef owner) :
240 CYValue(value),
241 owner_(context, owner),
242 type_(new(*pool_) Type_privateData(type, ffi)),
243 length_(length)
244 {
245 if (owner == NULL) {
246 size_t size(ffi->size * length);
247 void *copy(pool_->malloc<void>(size, ffi->alignment));
248 memcpy(copy, value_, size);
249 value_ = copy;
250 }
251 }
252 };
253
254 struct CString :
255 CYValue<CString, char *>
256 {
257 CYProtect owner_;
258
259 CString(char *value, JSContextRef context, JSObjectRef owner) :
260 CYValue(value),
261 owner_(context, owner)
262 {
263 if (owner == NULL)
264 value_ = pool_->strdup(value_);
265 }
266 };
267
268 struct Pointer :
269 CYValue<Pointer, void *>
270 {
271 CYProtect owner_;
272 Type_privateData *type_;
273
274 Pointer(void *value, const sig::Type &type, JSContextRef context, JSObjectRef owner) :
275 CYValue(value),
276 owner_(context, owner),
277 type_(new(*pool_) Type_privateData(type))
278 {
279 }
280
281 Pointer(void *value, const char *encoding, JSContextRef context, JSObjectRef owner) :
282 CYValue(value),
283 owner_(context, owner),
284 type_(new(*pool_) Type_privateData(encoding))
285 {
286 }
287 };
288
289 struct Struct_privateData :
290 CYValue<Struct_privateData, void *>
291 {
292 CYProtect owner_;
293 Type_privateData *type_;
294
295 Struct_privateData(void *value, const sig::Type &type, ffi_type *ffi, JSContextRef context, JSObjectRef owner) :
296 CYValue(value),
297 owner_(context, owner),
298 type_(new(*pool_) Type_privateData(type, ffi))
299 {
300 if (owner == NULL) {
301 size_t size(ffi->size);
302 void *copy(pool_->malloc<void>(size, ffi->alignment));
303 memcpy(copy, value_, size);
304 value_ = copy;
305 }
306 }
307 };
308
309 static void *CYCastSymbol(const char *name) {
310 for (CYHook *hook : GetHooks())
311 if (hook->CastSymbol != NULL)
312 if (void *value = (*hook->CastSymbol)(name))
313 return value;
314 return dlsym(RTLD_DEFAULT, name);
315 }
316
317 JSValueRef CYCastJSValue(JSContextRef context, bool value) {
318 return JSValueMakeBoolean(context, value);
319 }
320
321 JSValueRef CYCastJSValue(JSContextRef context, double value) {
322 return JSValueMakeNumber(context, value);
323 }
324
325 #define CYCastJSValue_(Type_) \
326 JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \
327 _assert(static_cast<Type_>(static_cast<double>(value)) == value); \
328 return JSValueMakeNumber(context, static_cast<double>(value)); \
329 }
330
331 CYCastJSValue_(signed short int)
332 CYCastJSValue_(unsigned short int)
333 CYCastJSValue_(signed int)
334 CYCastJSValue_(unsigned int)
335 CYCastJSValue_(signed long int)
336 CYCastJSValue_(unsigned long int)
337 CYCastJSValue_(signed long long int)
338 CYCastJSValue_(unsigned long long int)
339
340 #ifdef __SIZEOF_INT128__
341 CYCastJSValue_(signed __int128)
342 CYCastJSValue_(unsigned __int128)
343 #endif
344
345 JSValueRef CYJSUndefined(JSContextRef context) {
346 return JSValueMakeUndefined(context);
347 }
348
349 double CYCastDouble(JSContextRef context, JSValueRef value) {
350 return _jsccall(JSValueToNumber, context, value);
351 }
352
353 bool CYCastBool(JSContextRef context, JSValueRef value) {
354 return JSValueToBoolean(context, value);
355 }
356
357 JSValueRef CYJSNull(JSContextRef context) {
358 return JSValueMakeNull(context);
359 }
360
361 JSValueRef CYCastJSValue(JSContextRef context, JSStringRef value) {
362 return value == NULL ? CYJSNull(context) : JSValueMakeString(context, value);
363 }
364
365 JSValueRef CYCastJSValue(JSContextRef context, const char *value) {
366 return CYCastJSValue(context, CYJSString(value));
367 }
368
369 JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) {
370 return _jsccall(JSValueToObject, context, value);
371 }
372
373 JSValueRef CYCallAsFunction(JSContextRef context, JSObjectRef function, JSObjectRef _this, size_t count, const JSValueRef arguments[]) {
374 return _jsccall(JSObjectCallAsFunction, context, function, _this, count, arguments);
375 }
376
377 bool CYIsCallable(JSContextRef context, JSValueRef value) {
378 return value != NULL && JSValueIsObject(context, value) && JSObjectIsFunction(context, (JSObjectRef) value);
379 }
380
381 bool CYIsEqual(JSContextRef context, JSValueRef lhs, JSValueRef rhs) {
382 return _jsccall(JSValueIsEqual, context, lhs, rhs);
383 }
384
385 bool CYIsStrictEqual(JSContextRef context, JSValueRef lhs, JSValueRef rhs) {
386 return JSValueIsStrictEqual(context, lhs, rhs);
387 }
388
389 size_t CYArrayLength(JSContextRef context, JSObjectRef array) {
390 return CYCastDouble(context, CYGetProperty(context, array, length_s));
391 }
392
393 JSValueRef CYArrayGet(JSContextRef context, JSObjectRef array, size_t index) {
394 return _jsccall(JSObjectGetPropertyAtIndex, context, array, index);
395 }
396
397 void CYArrayPush(JSContextRef context, JSObjectRef array, size_t length, const JSValueRef arguments[]) {
398 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
399 _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, push_s)), array, length, arguments);
400 }
401
402 void CYArrayPush(JSContextRef context, JSObjectRef array, JSValueRef value) {
403 return CYArrayPush(context, array, 1, &value);
404 }
405
406 static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
407 FILE *file(stdout);
408
409 if (count == 0)
410 fputc('\n', file);
411 else {
412 CYPool pool;
413 CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
414 fwrite(string.data, string.size, 1, file);
415 }
416
417 fflush(file);
418 return CYJSUndefined(context);
419 } CYCatch(NULL) }
420
421 static void (*JSSynchronousGarbageCollectForDebugging$)(JSContextRef);
422
423 _visible void CYGarbageCollect(JSContextRef context) {
424 (JSSynchronousGarbageCollectForDebugging$ ?: &JSGarbageCollect)(context);
425 }
426
427 static JSValueRef Cycript_compile_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
428 CYPool pool;
429 CYUTF8String before(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
430 CYUTF8String after(CYPoolCode(pool, before));
431 return CYCastJSValue(context, CYJSString(after));
432 } CYCatch_(NULL, "SyntaxError") }
433
434 static JSValueRef Cycript_gc_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
435 CYGarbageCollect(context);
436 return CYJSUndefined(context);
437 } CYCatch(NULL) }
438
439 const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, std::set<void *> &objects, JSValueRef *exception) { CYTry {
440 switch (JSType type = JSValueGetType(context, value)) {
441 case kJSTypeUndefined:
442 return "undefined";
443 case kJSTypeNull:
444 return "null";
445 case kJSTypeBoolean:
446 return CYCastBool(context, value) ? "true" : "false";
447
448 case kJSTypeNumber: {
449 std::ostringstream str;
450 CYNumerify(str, CYCastDouble(context, value));
451 std::string value(str.str());
452 return pool.strmemdup(value.c_str(), value.size());
453 } break;
454
455 case kJSTypeString: {
456 std::ostringstream str;
457 CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, value)));
458 CYStringify(str, string.data, string.size);
459 std::string value(str.str());
460 return pool.strmemdup(value.c_str(), value.size());
461 } break;
462
463 case kJSTypeObject:
464 return CYPoolCCYON(pool, context, (JSObjectRef) value, objects);
465 default:
466 throw CYJSError(context, "JSValueGetType() == 0x%x", type);
467 }
468 } CYCatch(NULL) }
469
470 const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, std::set<void *> &objects) {
471 return _jsccall(CYPoolCCYON, pool, context, value, objects);
472 }
473
474 const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, std::set<void *> *objects) {
475 if (objects != NULL)
476 return CYPoolCCYON(pool, context, value, *objects);
477 else {
478 std::set<void *> objects;
479 return CYPoolCCYON(pool, context, value, objects);
480 }
481 }
482
483 const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object, std::set<void *> &objects) {
484 JSValueRef toCYON(CYGetProperty(context, object, toCYON_s));
485 if (CYIsCallable(context, toCYON)) {
486 // XXX: this needs to be abstracted behind some kind of function
487 JSValueRef arguments[1] = {CYCastJSValue(context, reinterpret_cast<uintptr_t>(&objects))};
488 JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 1, arguments));
489 _assert(value != NULL);
490 return CYPoolCString(pool, context, value);
491 }
492
493 JSValueRef toJSON(CYGetProperty(context, object, toJSON_s));
494 if (CYIsCallable(context, toJSON)) {
495 JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))};
496 return _jsccall(CYPoolCCYON, pool, context, CYCallAsFunction(context, (JSObjectRef) toJSON, object, 1, arguments), objects);
497 }
498
499 if (JSObjectIsFunction(context, object)) {
500 JSValueRef toString(CYGetProperty(context, object, toString_s));
501 if (CYIsCallable(context, toString)) {
502 JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))};
503 JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toString, object, 1, arguments));
504 _assert(value != NULL);
505 return CYPoolCString(pool, context, value);
506 }
507 }
508
509 _assert(objects.insert(object).second);
510
511 std::ostringstream str;
512
513 JSValueRef value(CYGetProperty(context, object, constructor_s));
514 if (JSValueIsObject(context, value)) {
515 JSObjectRef constructor(CYCastJSObject(context, value));
516 JSValueRef theory(CYGetProperty(context, constructor, prototype_s));
517 JSValueRef practice(JSObjectGetPrototype(context, object));
518
519 if (CYIsStrictEqual(context, theory, practice)) {
520 JSValueRef name(CYGetProperty(context, constructor, name_s));
521 if (!JSValueIsUndefined(context, name)) {
522 auto utf8(CYPoolUTF8String(pool, context, CYJSString(context, name)));
523 if (utf8 != "Object")
524 str << "new" << ' ' << utf8;
525 }
526 }
527 }
528
529 str << '{';
530
531 // XXX: this is, sadly, going to leak
532 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object));
533
534 bool comma(false);
535
536 for (size_t index(0), count(JSPropertyNameArrayGetCount(names)); index != count; ++index) {
537 if (comma)
538 str << ',';
539 else
540 comma = true;
541
542 JSStringRef name(JSPropertyNameArrayGetNameAtIndex(names, index));
543 CYUTF8String string(CYPoolUTF8String(pool, context, name));
544
545 if (CYIsKey(string))
546 str << string.data;
547 else
548 CYStringify(str, string.data, string.size);
549
550 str << ':';
551
552 try {
553 JSValueRef value(CYGetProperty(context, object, name));
554 str << CYPoolCCYON(pool, context, value, objects);
555 } catch (const CYException &error) {
556 str << "@error";
557 }
558 }
559
560 JSPropertyNameArrayRelease(names);
561
562 str << '}';
563
564 std::string string(str.str());
565 return pool.strmemdup(string.c_str(), string.size());
566 }
567
568 std::set<void *> *CYCastObjects(JSContextRef context, JSObjectRef _this, size_t count, const JSValueRef arguments[]) {
569 if (count == 0)
570 return NULL;
571 return CYCastPointer<std::set<void *> *>(context, arguments[0]);
572 }
573
574 static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
575 std::set<void *> *objects(CYCastObjects(context, _this, count, arguments));
576 // XXX: this is horribly inefficient
577 std::set<void *> backup;
578 if (objects == NULL)
579 objects = &backup;
580
581 CYPool pool;
582 std::ostringstream str;
583
584 str << '[';
585
586 JSValueRef length(CYGetProperty(context, _this, length_s));
587 bool comma(false);
588
589 for (size_t index(0), count(CYCastDouble(context, length)); index != count; ++index) {
590 if (comma)
591 str << ',';
592 else
593 comma = true;
594
595 try {
596 JSValueRef value(CYGetProperty(context, _this, index));
597 if (!JSValueIsUndefined(context, value))
598 str << CYPoolCCYON(pool, context, value, *objects);
599 else {
600 str << ',';
601 comma = false;
602 }
603 } catch (const CYException &error) {
604 str << "@error";
605 }
606 }
607
608 str << ']';
609
610 std::string value(str.str());
611 return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
612 } CYCatch(NULL) }
613
614 static JSValueRef String_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
615 CYPool pool;
616 std::ostringstream str;
617
618 CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, _this)));
619 CYStringify(str, string.data, string.size);
620
621 std::string value(str.str());
622 return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
623 } CYCatch(NULL) }
624
625 JSObjectRef CYMakePointer(JSContextRef context, void *pointer, const sig::Type &type, ffi_type *ffi, JSObjectRef owner) {
626 return Pointer::Make(context, pointer, type, context, owner);
627 }
628
629 static JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), bool variadic, const sig::Signature &signature) {
630 return JSObjectMake(context, Functor_, new cy::Functor(function, variadic, signature));
631 }
632
633 static JSObjectRef CYMakeFunctor(JSContextRef context, const char *symbol, const char *encoding) {
634 void (*function)()(reinterpret_cast<void (*)()>(CYCastSymbol(symbol)));
635 if (function == NULL)
636 return NULL;
637
638 cy::Functor *internal(new cy::Functor(function, encoding));
639 ++internal->count_;
640 return JSObjectMake(context, Functor_, internal);
641 }
642
643 bool CYGetOffset(CYPool &pool, JSContextRef context, JSStringRef value, ssize_t &index) {
644 return CYGetOffset(CYPoolCString(pool, context, value), index);
645 }
646
647 void *CYCastPointer_(JSContextRef context, JSValueRef value, bool *guess) {
648 if (value == NULL)
649 return NULL;
650 else switch (JSValueGetType(context, value)) {
651 case kJSTypeNull:
652 return NULL;
653 case kJSTypeObject: {
654 JSObjectRef object((JSObjectRef) value);
655 if (JSValueIsObjectOfClass(context, value, Pointer::Class_)) {
656 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
657 return internal->value_;
658 }
659 JSValueRef toPointer(CYGetProperty(context, object, toPointer_s));
660 if (CYIsCallable(context, toPointer)) {
661 JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toPointer, object, 0, NULL));
662 _assert(value != NULL);
663 return CYCastPointer_(context, value, guess);
664 }
665 } default:
666 if (guess != NULL)
667 *guess = true;
668 case kJSTypeNumber:
669 double number(CYCastDouble(context, value));
670 if (!std::isnan(number))
671 return reinterpret_cast<void *>(static_cast<uintptr_t>(static_cast<long long>(number)));
672 if (guess == NULL)
673 throw CYJSError(context, "cannot convert value to pointer");
674 else {
675 *guess = true;
676 return NULL;
677 }
678 }
679 }
680
681 namespace sig {
682
683 // XXX: this is somehow not quite a template :/
684
685 template <>
686 void Primitive<bool>::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
687 *reinterpret_cast<bool *>(data) = JSValueToBoolean(context, value);
688 }
689
690 #define CYPoolFFI_(Type_) \
691 template <> \
692 void Primitive<Type_>::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { \
693 *reinterpret_cast<Type_ *>(data) = CYCastDouble(context, value); \
694 }
695
696 CYPoolFFI_(char)
697 CYPoolFFI_(double)
698 CYPoolFFI_(float)
699 CYPoolFFI_(signed char)
700 CYPoolFFI_(signed int)
701 CYPoolFFI_(signed long int)
702 CYPoolFFI_(signed long long int)
703 CYPoolFFI_(signed short int)
704 CYPoolFFI_(unsigned char)
705 CYPoolFFI_(unsigned int)
706 CYPoolFFI_(unsigned long int)
707 CYPoolFFI_(unsigned long long int)
708 CYPoolFFI_(unsigned short int)
709
710 #ifdef __SIZEOF_INT128__
711 CYPoolFFI_(signed __int128)
712 CYPoolFFI_(unsigned __int128)
713 #endif
714
715 void Void::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
716 _assert(false);
717 }
718
719 void Unknown::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
720 _assert(false);
721 }
722
723 void String::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
724 bool guess(false);
725 *reinterpret_cast<const char **>(data) = CYCastPointer<const char *>(context, value, &guess);
726 if (guess && pool != NULL)
727 *reinterpret_cast<const char **>(data) = CYPoolCString(*pool, context, value);
728 }
729
730 void Bits::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
731 _assert(false);
732 }
733
734 static void CYArrayCopy(CYPool *pool, JSContextRef context, uint8_t *base, size_t length, const sig::Type &type, ffi_type *ffi, JSValueRef value, JSObjectRef object) {
735 for (size_t index(0); index != length; ++index) {
736 JSValueRef rhs;
737 if (object == NULL)
738 rhs = value;
739 else {
740 rhs = CYGetProperty(context, object, index);
741 if (JSValueIsUndefined(context, rhs))
742 throw CYJSError(context, "unable to extract array value");
743 }
744
745 type.PoolFFI(pool, context, ffi, base, rhs);
746 base += ffi->size;
747 }
748 }
749
750 void Pointer::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
751 bool guess(false);
752 *reinterpret_cast<void **>(data) = CYCastPointer<void *>(context, value, &guess);
753 if (!guess || pool == NULL || !JSValueIsObject(context, value))
754 return;
755 JSObjectRef object(CYCastJSObject(context, value));
756 if (CYHasProperty(context, object, length_s)) {
757 size_t length(CYArrayLength(context, object));
758 ffi_type *element(type.GetFFI(*pool));
759 size_t size(element->size * length);
760 uint8_t *base(pool->malloc<uint8_t>(size, element->alignment));
761 CYArrayCopy(pool, context, base, length, type, element, value, object);
762 *reinterpret_cast<void **>(data) = base;
763 }
764 }
765
766 void Array::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
767 if (size == 0)
768 return;
769 uint8_t *base(reinterpret_cast<uint8_t *>(data));
770 JSObjectRef object(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL);
771 CYArrayCopy(pool, context, base, size, type, ffi->elements[0], value, object);
772 }
773
774 void Enum::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
775 return type.PoolFFI(pool, context, ffi, data, value);
776 }
777
778 void Aggregate::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
779 _assert(!overlap);
780
781 size_t offset(0);
782 uint8_t *base(reinterpret_cast<uint8_t *>(data));
783 JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL);
784 for (size_t index(0); index != signature.count; ++index) {
785 sig::Element *element(&signature.elements[index]);
786 ffi_type *field(ffi->elements[index]);
787
788 JSValueRef rhs;
789 if (aggregate == NULL)
790 rhs = value;
791 else {
792 rhs = CYGetProperty(context, aggregate, index);
793 if (JSValueIsUndefined(context, rhs)) {
794 if (element->name != NULL)
795 rhs = CYGetProperty(context, aggregate, CYJSString(element->name));
796 else
797 goto undefined;
798 if (JSValueIsUndefined(context, rhs)) undefined:
799 throw CYJSError(context, "unable to extract structure value");
800 }
801 }
802
803 element->type->PoolFFI(pool, context, field, base + offset, rhs);
804 offset += field->size;
805 CYAlign(offset, field->alignment);
806 }
807 }
808
809 void Function::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
810 _assert(false);
811 }
812
813 #define CYFromFFI_(Type_) \
814 template <> \
815 JSValueRef Primitive<Type_>::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const { \
816 return CYCastJSValue(context, *reinterpret_cast<Type_ *>(data)); \
817 }
818
819 CYFromFFI_(bool)
820 CYFromFFI_(char)
821 CYFromFFI_(double)
822 CYFromFFI_(float)
823 CYFromFFI_(signed char)
824 CYFromFFI_(signed int)
825 CYFromFFI_(signed long int)
826 CYFromFFI_(signed long long int)
827 CYFromFFI_(signed short int)
828 CYFromFFI_(unsigned char)
829 CYFromFFI_(unsigned int)
830 CYFromFFI_(unsigned long int)
831 CYFromFFI_(unsigned long long int)
832 CYFromFFI_(unsigned short int)
833
834 #ifdef __SIZEOF_INT128__
835 CYFromFFI_(signed __int128)
836 CYFromFFI_(unsigned __int128)
837 #endif
838
839 JSValueRef Void::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
840 return CYJSUndefined(context);
841 }
842
843 JSValueRef Unknown::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
844 _assert(false);
845 }
846
847 JSValueRef String::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
848 if (char *value = *reinterpret_cast<char **>(data))
849 return CString::Make(context, value, context, owner);
850 return CYJSNull(context);
851 }
852
853 JSValueRef Bits::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
854 _assert(false);
855 }
856
857 JSValueRef Pointer::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
858 if (void *value = *reinterpret_cast<void **>(data))
859 return CYMakePointer(context, value, type, NULL, owner);
860 return CYJSNull(context);
861 }
862
863 JSValueRef Array::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
864 return CArray::Make(context, data, size, type, ffi->elements[0], context, owner);
865 }
866
867 JSValueRef Enum::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
868 return type.FromFFI(context, ffi, data, initialize, owner);
869 }
870
871 JSValueRef Aggregate::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
872 return Struct_privateData::Make(context, data, *this, ffi, context, owner);
873 }
874
875 JSValueRef Function::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
876 return CYMakeFunctor(context, reinterpret_cast<void (*)()>(data), variadic, signature);
877 }
878
879 }
880
881 void CYExecuteClosure(ffi_cif *cif, void *result, void **arguments, void *arg) {
882 Closure_privateData *internal(reinterpret_cast<Closure_privateData *>(arg));
883
884 JSContextRef context(internal->function_);
885
886 size_t count(internal->cif_.nargs);
887 JSValueRef values[count];
888
889 for (size_t index(0); index != count; ++index)
890 values[index] = internal->signature_.elements[1 + index].type->FromFFI(context, internal->cif_.arg_types[index], arguments[index]);
891
892 JSValueRef value(internal->adapter_(context, count, values, internal->function_));
893 if (internal->cif_.rtype != &ffi_type_void)
894 internal->signature_.elements[0].type->PoolFFI(NULL, context, internal->cif_.rtype, result, value);
895 }
896
897 static JSValueRef FunctionAdapter_(JSContextRef context, size_t count, JSValueRef values[], JSObjectRef function) {
898 return CYCallAsFunction(context, function, NULL, count, values);
899 }
900
901 #if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__))
902 static void CYFreeFunctor(void *data) {
903 ffi_closure_free(data);
904 }
905 #else
906 static void CYFreeFunctor(void *data) {
907 _syscall(munmap(data, sizeof(ffi_closure)));
908 }
909 #endif
910
911 Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const sig::Signature &signature, JSValueRef (*adapter)(JSContextRef, size_t, JSValueRef[], JSObjectRef)) {
912 // XXX: in case of exceptions this will leak
913 Closure_privateData *internal(new Closure_privateData(context, function, adapter, signature));
914
915 #if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__))
916 void *executable;
917 ffi_closure *writable(reinterpret_cast<ffi_closure *>(ffi_closure_alloc(sizeof(ffi_closure), &executable)));
918
919 ffi_status status(ffi_prep_closure_loc(writable, &internal->cif_, &CYExecuteClosure, internal, executable));
920 _assert(status == FFI_OK);
921
922 internal->pool_->atexit(&CYFreeFunctor, writable);
923 internal->value_ = reinterpret_cast<void (*)()>(executable);
924 #else
925 ffi_closure *closure((ffi_closure *) _syscall(mmap(
926 NULL, sizeof(ffi_closure),
927 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
928 -1, 0
929 )));
930
931 ffi_status status(ffi_prep_closure(closure, &internal->cif_, &CYExecuteClosure, internal));
932 _assert(status == FFI_OK);
933
934 _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
935
936 internal->pool_->atexit(&CYFreeFunctor, closure);
937 internal->value_ = reinterpret_cast<void (*)()>(closure);
938 #endif
939
940 return internal;
941 }
942
943 static JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const sig::Signature &signature) {
944 Closure_privateData *internal(CYMakeFunctor_(context, function, signature, &FunctionAdapter_));
945 JSObjectRef object(JSObjectMake(context, Functor_, internal));
946 // XXX: see above notes about needing to leak
947 JSValueProtect(CYGetJSContext(context), object);
948 return object;
949 }
950
951 JSValueRef CYGetCachedValue(JSContextRef context, JSStringRef name) {
952 return CYGetProperty(context, CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s)), name);
953 }
954
955 JSObjectRef CYGetCachedObject(JSContextRef context, JSStringRef name) {
956 return CYCastJSObject(context, CYGetCachedValue(context, name));
957 }
958
959 static JSObjectRef CYMakeFunctor(JSContextRef context, JSValueRef value, bool variadic, const sig::Signature &signature) {
960 JSObjectRef Function(CYGetCachedObject(context, CYJSString("Function")));
961
962 bool function(_jsccall(JSValueIsInstanceOfConstructor, context, value, Function));
963 if (function) {
964 JSObjectRef function(CYCastJSObject(context, value));
965 return CYMakeFunctor(context, function, signature);
966 } else {
967 void (*function)()(CYCastPointer<void (*)()>(context, value));
968 return CYMakeFunctor(context, function, variadic, signature);
969 }
970 }
971
972 static JSValueRef CString_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
973 CYPool pool;
974 CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(object)));
975
976 ssize_t offset;
977 if (!CYGetOffset(pool, context, property, offset))
978 return NULL;
979
980 return CYCastJSValue(context, CYJSString(CYUTF8String(&internal->value_[offset], 1)));
981 } CYCatch(NULL) }
982
983 static bool CString_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
984 CYPool pool;
985 CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(object)));
986
987 ssize_t offset;
988 if (!CYGetOffset(pool, context, property, offset))
989 return false;
990
991 const char *data(CYPoolCString(pool, context, value));
992 internal->value_[offset] = *data;
993 return true;
994 } CYCatch(false) }
995
996 static bool Index_(CYPool &pool, JSContextRef context, Struct_privateData *internal, JSStringRef property, ssize_t &index, uint8_t *&base) {
997 Type_privateData *typical(internal->type_);
998 sig::Aggregate *type(static_cast<sig::Aggregate *>(typical->type_));
999 if (type == NULL)
1000 return false;
1001
1002 const char *name(CYPoolCString(pool, context, property));
1003 size_t length(strlen(name));
1004 double number(CYCastDouble(name, length));
1005
1006 size_t count(type->signature.count);
1007
1008 if (std::isnan(number)) {
1009 if (property == NULL)
1010 return false;
1011
1012 sig::Element *elements(type->signature.elements);
1013
1014 for (size_t local(0); local != count; ++local) {
1015 sig::Element *element(&elements[local]);
1016 if (element->name != NULL && strcmp(name, element->name) == 0) {
1017 index = local;
1018 goto base;
1019 }
1020 }
1021
1022 return false;
1023 } else {
1024 index = static_cast<ssize_t>(number);
1025 if (index != number || index < 0 || static_cast<size_t>(index) >= count)
1026 return false;
1027 }
1028
1029 base:
1030 ffi_type **elements(typical->GetFFI()->elements);
1031
1032 size_t offset(0);
1033 for (ssize_t local(0); local != index; ++local) {
1034 offset += elements[local]->size;
1035 CYAlign(offset, elements[local + 1]->alignment);
1036 }
1037
1038 base = reinterpret_cast<uint8_t *>(internal->value_) + offset;
1039 return true;
1040 }
1041
1042 static void *Offset_(CYPool &pool, JSContextRef context, JSStringRef property, void *data, ffi_type *ffi) {
1043 ssize_t offset;
1044 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
1045 offset = 0;
1046 else if (!CYGetOffset(pool, context, property, offset))
1047 return NULL;
1048 return reinterpret_cast<uint8_t *>(data) + ffi->size * offset;
1049 }
1050
1051 static JSValueRef Offset_getProperty(CYPool &pool, JSContextRef context, JSStringRef property, void *data, Type_privateData *typical, JSObjectRef owner) {
1052 ffi_type *ffi(typical->GetFFI());
1053 void *base(Offset_(pool, context, property, data, ffi));
1054 if (base == NULL)
1055 return NULL;
1056 return typical->type_->FromFFI(context, ffi, base, false, owner);
1057 }
1058
1059 static bool Offset_setProperty(CYPool &pool, JSContextRef context, JSStringRef property, void *data, Type_privateData *typical, JSValueRef value) {
1060 ffi_type *ffi(typical->GetFFI());
1061 void *base(Offset_(pool, context, property, data, ffi));
1062 if (base == NULL)
1063 return false;
1064
1065 typical->type_->PoolFFI(NULL, context, ffi, base, value);
1066 return true;
1067 }
1068
1069 static JSValueRef CArray_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1070 CYPool pool;
1071 CArray *internal(reinterpret_cast<CArray *>(JSObjectGetPrivate(object)));
1072 if (JSStringIsEqual(property, length_s))
1073 return CYCastJSValue(context, internal->length_);
1074 Type_privateData *typical(internal->type_);
1075 JSObjectRef owner(internal->owner_ ?: object);
1076 return Offset_getProperty(pool, context, property, internal->value_, typical, owner);
1077 } CYCatch(NULL) }
1078
1079 static bool CArray_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
1080 CYPool pool;
1081 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
1082 Type_privateData *typical(internal->type_);
1083 return Offset_setProperty(pool, context, property, internal->value_, typical, value);
1084 } CYCatch(false) }
1085
1086 static JSValueRef Pointer_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1087 CYPool pool;
1088 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
1089
1090 Type_privateData *typical(internal->type_);
1091
1092 if (sig::Function *function = dynamic_cast<sig::Function *>(typical->type_)) {
1093 if (!JSStringIsEqualToUTF8CString(property, "$cyi"))
1094 return NULL;
1095 return CYMakeFunctor(context, reinterpret_cast<void (*)()>(internal->value_), function->variadic, function->signature);
1096 }
1097
1098 JSObjectRef owner(internal->owner_ ?: object);
1099 return Offset_getProperty(pool, context, property, internal->value_, typical, owner);
1100 } CYCatch(NULL) }
1101
1102 static bool Pointer_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
1103 CYPool pool;
1104 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
1105 Type_privateData *typical(internal->type_);
1106 return Offset_setProperty(pool, context, property, internal->value_, typical, value);
1107 } CYCatch(false) }
1108
1109 static JSValueRef Struct_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1110 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(_this)));
1111 Type_privateData *typical(internal->type_);
1112 return CYMakePointer(context, internal->value_, *typical->type_, typical->ffi_, _this);
1113 } CYCatch(NULL) }
1114
1115 static JSValueRef Struct_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1116 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
1117 return CYMakeType(context, *internal->type_->type_);
1118 } CYCatch(NULL) }
1119
1120 static JSValueRef Struct_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1121 CYPool pool;
1122 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
1123 Type_privateData *typical(internal->type_);
1124 sig::Aggregate *type(static_cast<sig::Aggregate *>(typical->type_));
1125
1126 ssize_t index;
1127 uint8_t *base;
1128
1129 if (!Index_(pool, context, internal, property, index, base))
1130 return NULL;
1131
1132 JSObjectRef owner(internal->owner_ ?: object);
1133
1134 return type->signature.elements[index].type->FromFFI(context, typical->GetFFI()->elements[index], base, false, owner);
1135 } CYCatch(NULL) }
1136
1137 static bool Struct_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
1138 CYPool pool;
1139 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
1140 Type_privateData *typical(internal->type_);
1141 sig::Aggregate *type(static_cast<sig::Aggregate *>(typical->type_));
1142
1143 ssize_t index;
1144 uint8_t *base;
1145
1146 if (!Index_(pool, context, internal, property, index, base))
1147 return false;
1148
1149 type->signature.elements[index].type->PoolFFI(NULL, context, typical->GetFFI()->elements[index], base, value);
1150 return true;
1151 } CYCatch(false) }
1152
1153 static void Struct_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
1154 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
1155 Type_privateData *typical(internal->type_);
1156 sig::Aggregate *type(static_cast<sig::Aggregate *>(typical->type_));
1157
1158 if (type == NULL)
1159 return;
1160
1161 size_t count(type->signature.count);
1162 sig::Element *elements(type->signature.elements);
1163
1164 char number[32];
1165
1166 for (size_t index(0); index != count; ++index) {
1167 const char *name;
1168 name = elements[index].name;
1169
1170 if (name == NULL) {
1171 sprintf(number, "%zu", index);
1172 name = number;
1173 }
1174
1175 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
1176 }
1177 }
1178
1179 static sig::Void Void_;
1180 static sig::Pointer PointerToVoid_(Void_);
1181
1182 static sig::Type *CYGetType(CYPool &pool, JSContextRef context, JSValueRef value) {
1183 if (JSValueIsNull(context, value))
1184 return &PointerToVoid_;
1185 JSObjectRef object(CYCastJSObject(context, value));
1186 JSObjectRef type(CYCastJSObject(context, CYGetProperty(context, object, cyt_s)));
1187 _assert(JSValueIsObjectOfClass(context, type, Type_privateData::Class_));
1188 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(type)));
1189 return internal->type_;
1190 }
1191
1192 void CYCallFunction(CYPool &pool, JSContextRef context, ffi_cif *cif, void (*function)(), void *value, void **values) {
1193 ffi_call(cif, function, value, values);
1194 }
1195
1196 JSValueRef CYCallFunction(CYPool &pool, JSContextRef context, size_t setups, void *setup[], size_t count, const JSValueRef arguments[], bool initialize, bool variadic, const sig::Signature &signature, ffi_cif *cif, void (*function)()) {
1197 size_t have(setups + count);
1198 size_t need(signature.count - 1);
1199
1200 if (have < need)
1201 throw CYJSError(context, "insufficient number of arguments to ffi function");
1202
1203 ffi_cif corrected;
1204 sig::Element *elements(signature.elements);
1205
1206 if (have > need) {
1207 if (!variadic)
1208 throw CYJSError(context, "exorbitant number of arguments to ffi function");
1209
1210 elements = new (pool) sig::Element[have + 1];
1211 memcpy(elements, signature.elements, sizeof(sig::Element) * (need + 1));
1212
1213 for (size_t index(need); index != have; ++index) {
1214 sig::Element &element(elements[index + 1]);
1215 element.name = NULL;
1216 element.offset = _not(size_t);
1217 element.type = CYGetType(pool, context, arguments[index - setups]);
1218 }
1219
1220 sig::Signature extended;
1221 extended.elements = elements;
1222 extended.count = have + 1;
1223 sig::sig_ffi_cif(pool, signature.count, extended, &corrected);
1224 cif = &corrected;
1225 }
1226
1227 void *values[have];
1228 memcpy(values, setup, sizeof(void *) * setups);
1229
1230 for (size_t index(setups); index != have; ++index) {
1231 sig::Element &element(elements[index + 1]);
1232 ffi_type *ffi(cif->arg_types[index]);
1233 values[index] = pool.malloc<uint8_t>(ffi->size, ffi->alignment);
1234 element.type->PoolFFI(&pool, context, ffi, values[index], arguments[index - setups]);
1235 }
1236
1237 uint8_t value[cif->rtype->size];
1238
1239 void (*call)(CYPool &, JSContextRef, ffi_cif *, void (*)(), void *, void **) = &CYCallFunction;
1240 // XXX: this only supports one hook, but it is a bad idea anyway
1241 for (CYHook *hook : GetHooks())
1242 if (hook->CallFunction != NULL)
1243 call = hook->CallFunction;
1244
1245 call(pool, context, cif, function, value, values);
1246 return signature.elements[0].type->FromFFI(context, cif->rtype, value, initialize);
1247 }
1248
1249 static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1250 CYPool pool;
1251 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(object)));
1252 return CYCallFunction(pool, context, 0, NULL, count, arguments, false, internal->variadic_, internal->signature_, &internal->cif_, internal->value_);
1253 } CYCatch(NULL) }
1254
1255 static JSValueRef Pointer_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1256 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
1257 if (dynamic_cast<sig::Function *>(internal->type_->type_) == NULL)
1258 throw CYJSError(context, "cannot call a pointer to non-function");
1259 JSObjectRef functor(CYCastJSObject(context, CYGetProperty(context, object, cyi_s)));
1260 return CYCallAsFunction(context, functor, _this, count, arguments);
1261 } CYCatch(NULL) }
1262
1263 JSObjectRef CYMakeType(JSContextRef context, const sig::Type &type) {
1264 return Type_privateData::Make(context, type);
1265 }
1266
1267 extern "C" bool CYBridgeHash(CYPool &pool, CYUTF8String name, const char *&code, unsigned &flags) {
1268 sqlite3_stmt *statement;
1269
1270 _sqlcall(sqlite3_prepare(database_,
1271 "select "
1272 "\"cache\".\"code\", "
1273 "\"cache\".\"flags\" "
1274 "from \"cache\" "
1275 "where"
1276 " \"cache\".\"system\" & " CY_SYSTEM " == " CY_SYSTEM " and"
1277 " \"cache\".\"name\" = ?"
1278 " limit 1"
1279 , -1, &statement, NULL));
1280
1281 _sqlcall(sqlite3_bind_text(statement, 1, name.data, name.size, SQLITE_STATIC));
1282
1283 bool success;
1284 if (_sqlcall(sqlite3_step(statement)) == SQLITE_DONE)
1285 success = false;
1286 else {
1287 success = true;
1288 code = sqlite3_column_pooled(pool, statement, 0);
1289 flags = sqlite3_column_int(statement, 1);
1290 }
1291
1292 _sqlcall(sqlite3_finalize(statement));
1293 return success;
1294 }
1295
1296 static bool All_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1297 if (JSStringIsEqualToUTF8CString(property, "errno"))
1298 return true;
1299
1300 JSObjectRef global(CYGetGlobalObject(context));
1301 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
1302 JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
1303
1304 for (size_t i(0), count(CYArrayLength(context, alls)); i != count; ++i)
1305 if (JSObjectRef space = CYCastJSObject(context, CYArrayGet(context, alls, count - i - 1)))
1306 if (CYHasProperty(context, space, property))
1307 return true;
1308
1309 CYPool pool;
1310 const char *code;
1311 unsigned flags;
1312 if (CYBridgeHash(pool, CYPoolUTF8String(pool, context, property), code, flags))
1313 return true;
1314
1315 return false;
1316 }
1317
1318 static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1319 if (JSStringIsEqualToUTF8CString(property, "errno"))
1320 return CYCastJSValue(context, errno);
1321
1322 JSObjectRef global(CYGetGlobalObject(context));
1323 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
1324 JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
1325
1326 for (size_t i(0), count(CYArrayLength(context, alls)); i != count; ++i)
1327 if (JSObjectRef space = CYCastJSObject(context, CYArrayGet(context, alls, count - i - 1)))
1328 if (JSValueRef value = CYGetProperty(context, space, property))
1329 if (!JSValueIsUndefined(context, value))
1330 return value;
1331
1332 CYPool pool;
1333 const char *code;
1334 unsigned flags;
1335 if (CYBridgeHash(pool, CYPoolUTF8String(pool, context, property), code, flags)) {
1336 CYUTF8String parsed;
1337
1338 try {
1339 parsed = CYPoolCode(pool, code);
1340 } catch (const CYException &error) {
1341 CYThrow("%s", pool.strcat("error caching ", CYPoolCString(pool, context, property), ": ", error.PoolCString(pool), NULL));
1342 }
1343
1344 JSObjectRef cache(CYGetCachedObject(context, CYJSString("cache")));
1345
1346 JSObjectRef stub;
1347 if (flags == CYBridgeType) {
1348 stub = CYMakeType(context, sig::Void());
1349 CYSetProperty(context, cache, property, stub);
1350 } else
1351 stub = NULL;
1352
1353 JSValueRef value(_jsccall(JSEvaluateScript, context, CYJSString(parsed), NULL, NULL, 0));
1354
1355 switch (flags) {
1356 case CYBridgeVoid: {
1357 } break;
1358
1359 case CYBridgeHold: {
1360 CYSetProperty(context, cache, property, value);
1361 } break;
1362
1363 case CYBridgeType: {
1364 JSObjectRef swap(CYCastJSObject(context, value));
1365 void *source(JSObjectGetPrivate(swap));
1366 _assert(source != NULL);
1367 void *target(JSObjectGetPrivate(stub));
1368 _assert(JSObjectSetPrivate(swap, target));
1369 _assert(JSObjectSetPrivate(stub, source));
1370 value = stub;
1371 } break;
1372 }
1373
1374 return value;
1375 }
1376
1377 return NULL;
1378 } CYCatch(NULL) }
1379
1380 static JSValueRef All_complete_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1381 _assert(count == 1);
1382 CYPool pool;
1383 CYUTF8String prefix(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
1384
1385 JSObjectRef array(NULL);
1386
1387 {
1388 CYArrayBuilder<1024> values(context, array);
1389
1390 sqlite3_stmt *statement;
1391
1392 if (prefix.size == 0)
1393 _sqlcall(sqlite3_prepare(database_,
1394 "select "
1395 "\"cache\".\"name\" "
1396 "from \"cache\" "
1397 "where"
1398 " \"cache\".\"system\" & " CY_SYSTEM " == " CY_SYSTEM
1399 , -1, &statement, NULL));
1400 else {
1401 _sqlcall(sqlite3_prepare(database_,
1402 "select "
1403 "\"cache\".\"name\" "
1404 "from \"cache\" "
1405 "where"
1406 " \"cache\".\"name\" >= ? and \"cache\".\"name\" < ? and "
1407 " \"cache\".\"system\" & " CY_SYSTEM " == " CY_SYSTEM
1408 , -1, &statement, NULL));
1409
1410 _sqlcall(sqlite3_bind_text(statement, 1, prefix.data, prefix.size, SQLITE_STATIC));
1411
1412 char *after(pool.strndup(prefix.data, prefix.size));
1413 ++after[prefix.size - 1];
1414 _sqlcall(sqlite3_bind_text(statement, 2, after, prefix.size, SQLITE_STATIC));
1415 }
1416
1417 while (_sqlcall(sqlite3_step(statement)) != SQLITE_DONE)
1418 values(CYCastJSValue(context, CYJSString(sqlite3_column_string(statement, 0))));
1419
1420 _sqlcall(sqlite3_finalize(statement));
1421 }
1422
1423 return array;
1424 } CYCatch(NULL) }
1425
1426 static void All_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
1427 JSObjectRef global(CYGetGlobalObject(context));
1428 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
1429 JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
1430
1431 for (size_t i(0), count(CYArrayLength(context, alls)); i != count; ++i)
1432 if (JSObjectRef space = CYCastJSObject(context, CYArrayGet(context, alls, count - i - 1))) {
1433 JSPropertyNameArrayRef subset(JSObjectCopyPropertyNames(context, space));
1434 for (size_t index(0), count(JSPropertyNameArrayGetCount(subset)); index != count; ++index)
1435 JSPropertyNameAccumulatorAddName(names, JSPropertyNameArrayGetNameAtIndex(subset, index));
1436 JSPropertyNameArrayRelease(subset);
1437 }
1438 }
1439
1440 static JSObjectRef CArray_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1441 _assert(false);
1442 } CYCatch(NULL) }
1443
1444 static JSObjectRef CString_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1445 _assert(false);
1446 } CYCatch(NULL) }
1447
1448 static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1449 _assert(false);
1450 } CYCatch(NULL) }
1451
1452 static JSObjectRef Type_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1453 CYPool pool;
1454
1455 if (false) {
1456 } else if (count == 1) {
1457 switch (JSValueGetType(context, arguments[0])) {
1458 case kJSTypeString: {
1459 const char *encoding(CYPoolCString(pool, context, arguments[0]));
1460 sig::Signature signature;
1461 sig::Parse(pool, &signature, encoding, &Structor_);
1462 return CYMakeType(context, *signature.elements[0].type);
1463 } break;
1464
1465 case kJSTypeObject: {
1466 // XXX: accept a set of enum constants and /guess/ at their size
1467 _assert(false);
1468 } break;
1469
1470 default:
1471 throw CYJSError(context, "incorrect kind of argument to new Type");
1472 }
1473 } else if (count == 2) {
1474 JSObjectRef types(CYCastJSObject(context, arguments[0]));
1475 size_t count(CYArrayLength(context, types));
1476
1477 JSObjectRef names(CYCastJSObject(context, arguments[1]));
1478
1479 sig::Aggregate type(false);
1480 type.signature.elements = new(pool) sig::Element[count];
1481 type.signature.count = count;
1482
1483 for (size_t i(0); i != count; ++i) {
1484 sig::Element &element(type.signature.elements[i]);
1485 element.offset = _not(size_t);
1486
1487 JSValueRef name(CYArrayGet(context, names, i));
1488 if (JSValueIsUndefined(context, name))
1489 element.name = NULL;
1490 else
1491 element.name = CYPoolCString(pool, context, name);
1492
1493 JSObjectRef object(CYCastJSObject(context, CYArrayGet(context, types, i)));
1494 _assert(JSValueIsObjectOfClass(context, object, Type_privateData::Class_));
1495 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1496 element.type = internal->type_;
1497 }
1498
1499 return CYMakeType(context, type);
1500 } else {
1501 throw CYJSError(context, "incorrect number of arguments to Type constructor");
1502 }
1503 } CYCatch(NULL) }
1504
1505 static JSValueRef Type_callAsFunction_$With(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], sig::Callable &type, JSValueRef *exception) { CYTry {
1506 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1507
1508 CYPool pool;
1509
1510 type.signature.elements = new(pool) sig::Element[1 + count];
1511 type.signature.count = 1 + count;
1512
1513 type.signature.elements[0].name = NULL;
1514 type.signature.elements[0].type = internal->type_;
1515 type.signature.elements[0].offset = _not(size_t);
1516
1517 for (size_t i(0); i != count; ++i) {
1518 sig::Element &element(type.signature.elements[i + 1]);
1519 element.name = NULL;
1520 element.offset = _not(size_t);
1521
1522 JSObjectRef object(CYCastJSObject(context, arguments[i]));
1523 _assert(JSValueIsObjectOfClass(context, object, Type_privateData::Class_));
1524 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1525
1526 element.type = internal->type_;
1527 }
1528
1529 return CYMakeType(context, type);
1530 } CYCatch(NULL) }
1531
1532 static JSValueRef Type_callAsFunction_arrayOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1533 if (count != 1)
1534 throw CYJSError(context, "incorrect number of arguments to Type.arrayOf");
1535 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1536
1537 CYPool pool;
1538 size_t index(CYGetIndex(pool, context, CYJSString(context, arguments[0])));
1539 if (index == _not(size_t))
1540 throw CYJSError(context, "invalid array size used with Type.arrayOf");
1541
1542 sig::Array type(*internal->type_, index);
1543 return CYMakeType(context, type);
1544 } CYCatch(NULL) }
1545
1546 static JSValueRef Type_callAsFunction_blockWith(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1547 #ifdef CY_OBJECTIVEC
1548 sig::Block type;
1549 return Type_callAsFunction_$With(context, object, _this, count, arguments, type, exception);
1550 #else
1551 _assert(false);
1552 #endif
1553 }
1554
1555 static JSValueRef Type_callAsFunction_constant(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1556 if (count != 0)
1557 throw CYJSError(context, "incorrect number of arguments to Type.constant");
1558 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1559
1560 CYPool pool;
1561 sig::Type *type(internal->type_->Copy(pool));
1562 type->flags |= JOC_TYPE_CONST;
1563 return CYMakeType(context, *type);
1564 } CYCatch(NULL) }
1565
1566 static JSValueRef Type_callAsFunction_enumFor(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1567 if (count != 1)
1568 throw CYJSError(context, "incorrect number of arguments to Type.enumFor");
1569 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1570
1571 CYPool pool;
1572
1573 JSObjectRef constants(CYCastJSObject(context, arguments[0]));
1574
1575 // XXX: this is, sadly, going to leak
1576 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, constants));
1577
1578 size_t count(JSPropertyNameArrayGetCount(names));
1579
1580 sig::Enum type(*internal->type_, count);
1581 type.constants = new(pool) sig::Constant[count];
1582
1583 for (size_t index(0); index != count; ++index) {
1584 JSStringRef name(JSPropertyNameArrayGetNameAtIndex(names, index));
1585 JSValueRef value(CYGetProperty(context, constants, name));
1586 _assert(JSValueGetType(context, value) == kJSTypeNumber);
1587 CYUTF8String string(CYPoolUTF8String(pool, context, name));
1588 type.constants[index].name = string.data;
1589 type.constants[index].value = CYCastDouble(context, value);
1590 }
1591
1592 JSPropertyNameArrayRelease(names);
1593
1594 return CYMakeType(context, type);
1595 } CYCatch(NULL) }
1596
1597 static JSValueRef Type_callAsFunction_functionWith(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1598 bool variadic(count != 0 && JSValueIsNull(context, arguments[count - 1]));
1599 sig::Function type(variadic);
1600 return Type_callAsFunction_$With(context, object, _this, variadic ? count - 1 : count, arguments, type, exception);
1601 }
1602
1603 static JSValueRef Type_callAsFunction_pointerTo(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1604 if (count != 0)
1605 throw CYJSError(context, "incorrect number of arguments to Type.pointerTo");
1606 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1607
1608 if (dynamic_cast<sig::Primitive<char> *>(internal->type_) != NULL)
1609 return CYMakeType(context, sig::String());
1610 else
1611 return CYMakeType(context, sig::Pointer(*internal->type_));
1612 } CYCatch(NULL) }
1613
1614 static JSValueRef Type_callAsFunction_withName(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1615 if (count != 1)
1616 throw CYJSError(context, "incorrect number of arguments to Type.withName");
1617 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1618
1619 CYPool pool;
1620 return CYMakeType(context, *internal->type_->Copy(pool, CYPoolCString(pool, context, arguments[0])));
1621 } CYCatch(NULL) }
1622
1623 static JSValueRef Type_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1624 if (count != 1)
1625 throw CYJSError(context, "incorrect number of arguments to type cast function");
1626 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1627
1628 if (sig::Function *function = dynamic_cast<sig::Function *>(internal->type_))
1629 return CYMakeFunctor(context, arguments[0], function->variadic, function->signature);
1630
1631 CYPool pool;
1632
1633 sig::Type *type(internal->type_);
1634 ffi_type *ffi(internal->GetFFI());
1635 void *data(pool.malloc<void>(ffi->size, ffi->alignment));
1636
1637 type->PoolFFI(&pool, context, ffi, data, arguments[0]);
1638 JSValueRef value(type->FromFFI(context, ffi, data));
1639
1640 if (JSValueGetType(context, value) == kJSTypeNumber) {
1641 JSObjectRef typed(_jsccall(JSObjectCallAsConstructor, context, CYGetCachedObject(context, CYJSString("Number")), 1, &value));
1642 CYSetProperty(context, typed, cyt_s, object, kJSPropertyAttributeDontEnum);
1643 value = typed;
1644 }
1645
1646 return value;
1647 } CYCatch(NULL) }
1648
1649 static JSObjectRef Type_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1650 if (count > 1)
1651 throw CYJSError(context, "incorrect number of arguments to Type allocator");
1652 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1653
1654 JSObjectRef pointer(CYMakePointer(context, NULL, *internal->type_, NULL, NULL));
1655 Pointer *value(reinterpret_cast<Pointer *>(JSObjectGetPrivate(pointer)));
1656
1657 sig::Type *type(internal->type_);
1658 ffi_type *ffi(internal->GetFFI());
1659 value->value_ = value->pool_->malloc<void>(ffi->size, ffi->alignment);
1660
1661 if (count == 0)
1662 memset(value->value_, 0, ffi->size);
1663 else
1664 type->PoolFFI(value->pool_, context, ffi, value->value_, arguments[0]);
1665
1666 return pointer;
1667 } CYCatch(NULL) }
1668
1669 static JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1670 if (count != 2)
1671 throw CYJSError(context, "incorrect number of arguments to Functor constructor");
1672 CYPool pool;
1673 const char *encoding(CYPoolCString(pool, context, arguments[1]));
1674 sig::Signature signature;
1675 sig::Parse(pool, &signature, encoding, &Structor_);
1676 return CYMakeFunctor(context, arguments[0], false, signature);
1677 } CYCatch(NULL) }
1678
1679 static JSValueRef CArray_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1680 CArray *internal(reinterpret_cast<CArray *>(JSObjectGetPrivate(_this)));
1681 JSObjectRef owner(internal->owner_ ?: object);
1682 return CYMakePointer(context, internal->value_, *internal->type_->type_, NULL, owner);
1683 } CYCatch(NULL) }
1684
1685 static JSValueRef CString_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1686 CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(_this)));
1687 JSObjectRef owner(internal->owner_ ?: object);
1688 return CYMakePointer(context, internal->value_, sig::Primitive<char>(), NULL, owner);
1689 } CYCatch(NULL) }
1690
1691 static JSValueRef Functor_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1692 CYPool pool;
1693 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(_this)));
1694
1695 sig::Function type(internal->variadic_);
1696 sig::Copy(pool, type.signature, internal->signature_);
1697
1698 return CYMakePointer(context, reinterpret_cast<void *>(internal->value_), type, NULL, NULL);
1699 } CYCatch(NULL) }
1700
1701 static JSValueRef Pointer_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1702 return _this;
1703 } CYCatch(NULL) }
1704
1705 static JSValueRef CArray_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1706 CArray *internal(reinterpret_cast<CArray *>(JSObjectGetPrivate(_this)));
1707 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
1708 } CYCatch(NULL) }
1709
1710 static JSValueRef Pointer_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1711 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(_this)));
1712 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
1713 } CYCatch(NULL) }
1714
1715 static JSValueRef Functor_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1716 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(_this)));
1717 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
1718 } CYCatch(NULL) }
1719
1720 static JSValueRef Functor_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1721 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(_this)));
1722 uint8_t *value(reinterpret_cast<uint8_t *>(internal->value_));
1723
1724 CYLocalPool pool;
1725
1726 sig::Function function(internal->variadic_);
1727 sig::Copy(pool, function.signature, internal->signature_);
1728
1729 auto typed(CYDecodeType(pool, &function)); {
1730 std::ostringstream str;
1731 Dl_info info;
1732 if (internal->value_ == NULL)
1733 str << "NULL";
1734 else if (dladdr(value, &info) == 0)
1735 str << internal->value_;
1736 else {
1737 str << info.dli_sname;
1738 off_t offset(value - reinterpret_cast<uint8_t *>(info.dli_saddr));
1739 if (offset != 0)
1740 str << "+0x" << std::hex << offset;
1741 }
1742
1743 typed->identifier_ = new(pool) CYIdentifier(pool.strdup(str.str().c_str()));
1744 }
1745
1746 std::ostringstream str;
1747 CYOptions options;
1748 CYOutput output(*str.rdbuf(), options);
1749 output.pretty_ = true;
1750 (new(pool) CYExternalExpression(new(pool) CYString("C"), typed))->Output(output, CYNoFlags);
1751 return CYCastJSValue(context, CYJSString(str.str()));
1752 } CYCatch(NULL) }
1753
1754 static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1755 std::set<void *> *objects(CYCastObjects(context, _this, count, arguments));
1756
1757 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(_this)));
1758
1759 try {
1760 JSValueRef value(CYGetProperty(context, _this, cyi_s));
1761 if (!JSValueIsUndefined(context, value)) {
1762 CYPool pool;
1763 return CYCastJSValue(context, pool.strcat("&", CYPoolCCYON(pool, context, value, objects), NULL));
1764 }
1765 } catch (const CYException &e) {
1766 // XXX: it might be interesting to include this error
1767 }
1768
1769 CYLocalPool pool;
1770 std::ostringstream str;
1771
1772 sig::Pointer type(*internal->type_->type_);
1773
1774 CYOptions options;
1775 CYOutput output(*str.rdbuf(), options);
1776 (new(pool) CYTypeExpression(CYDecodeType(pool, &type)))->Output(output, CYNoFlags);
1777
1778 str << "(" << internal->value_ << ")";
1779 std::string value(str.str());
1780 return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
1781 } CYCatch(NULL) }
1782
1783 static JSValueRef CString_getProperty_length(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1784 CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(object)));
1785 return CYCastJSValue(context, strlen(internal->value_));
1786 } CYCatch(NULL) }
1787
1788 static JSValueRef CString_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1789 return CYMakeType(context, sig::String());
1790 } CYCatch(NULL) }
1791
1792 static JSValueRef CArray_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1793 CArray *internal(reinterpret_cast<CArray *>(JSObjectGetPrivate(object)));
1794 sig::Array type(*internal->type_->type_, internal->length_);
1795 return CYMakeType(context, type);
1796 } CYCatch(NULL) }
1797
1798 static JSValueRef Pointer_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1799 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
1800 sig::Pointer type(*internal->type_->type_);
1801 return CYMakeType(context, type);
1802 } CYCatch(NULL) }
1803
1804 static JSValueRef CString_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1805 CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(_this)));
1806 const char *string(internal->value_);
1807 std::ostringstream str;
1808 if (string == NULL)
1809 str << "NULL";
1810 else {
1811 str << "&";
1812 CYStringify(str, string, strlen(string), true);
1813 }
1814 std::string value(str.str());
1815 return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
1816 } CYCatch(NULL) }
1817
1818 static JSValueRef CString_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1819 CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(_this)));
1820 return CYCastJSValue(context, internal->value_);
1821 } CYCatch(NULL) }
1822
1823 static JSValueRef Functor_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1824 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(object)));
1825 CYPool pool;
1826 sig::Function type(internal->variadic_);
1827 sig::Copy(pool, type.signature, internal->signature_);
1828 return CYMakeType(context, type);
1829 } CYCatch(NULL) }
1830
1831 static JSValueRef Type_getProperty_alignment(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1832 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1833 return CYCastJSValue(context, internal->GetFFI()->alignment);
1834 } CYCatch(NULL) }
1835
1836 static JSValueRef Type_getProperty_name(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1837 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1838 return CYCastJSValue(context, internal->type_->GetName());
1839 } CYCatch(NULL) }
1840
1841 static JSValueRef Type_getProperty_size(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1842 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1843 return CYCastJSValue(context, internal->GetFFI()->size);
1844 } CYCatch(NULL) }
1845
1846 static JSValueRef Type_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1847 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1848 CYPool pool;
1849 const char *type(sig::Unparse(pool, internal->type_));
1850 return CYCastJSValue(context, CYJSString(type));
1851 } CYCatch(NULL) }
1852
1853 static JSValueRef Type_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1854 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1855 CYLocalPool pool;
1856 std::stringbuf out;
1857 CYOptions options;
1858 CYOutput output(out, options);
1859 output.pretty_ = true;
1860 (new(pool) CYTypeExpression(CYDecodeType(pool, internal->type_->Copy(pool, ""))))->Output(output, CYNoFlags);
1861 return CYCastJSValue(context, CYJSString(out.str().c_str()));
1862 } CYCatch(NULL) }
1863
1864 static JSStaticFunction All_staticFunctions[2] = {
1865 {"cy$complete", &All_complete_callAsFunction, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1866 {NULL, NULL, 0}
1867 };
1868
1869 static JSStaticFunction CArray_staticFunctions[3] = {
1870 {"toPointer", &CArray_callAsFunction_toPointer, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1871 {"valueOf", &CArray_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1872 {NULL, NULL, 0}
1873 };
1874
1875 static JSStaticValue CArray_staticValues[2] = {
1876 {"$cyt", &CArray_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1877 {NULL, NULL, NULL, 0}
1878 };
1879
1880 static JSStaticFunction CString_staticFunctions[5] = {
1881 {"toCYON", &CString_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1882 {"toPointer", &CString_callAsFunction_toPointer, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1883 {"toString", &CString_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1884 {"valueOf", &CString_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1885 {NULL, NULL, 0}
1886 };
1887
1888 static JSStaticValue CString_staticValues[3] = {
1889 {"length", &CString_getProperty_length, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1890 {"$cyt", &CString_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1891 {NULL, NULL, NULL, 0}
1892 };
1893
1894 static JSStaticFunction Pointer_staticFunctions[4] = {
1895 {"toCYON", &Pointer_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1896 {"toPointer", &Pointer_callAsFunction_toPointer, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1897 {"valueOf", &Pointer_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1898 {NULL, NULL, 0}
1899 };
1900
1901 static JSStaticValue Pointer_staticValues[2] = {
1902 {"$cyt", &Pointer_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1903 {NULL, NULL, NULL, 0}
1904 };
1905
1906 static JSStaticFunction Struct_staticFunctions[2] = {
1907 {"$cya", &Struct_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1908 {NULL, NULL, 0}
1909 };
1910
1911 static JSStaticValue Struct_staticValues[2] = {
1912 {"$cyt", &Struct_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1913 {NULL, NULL, NULL, 0}
1914 };
1915
1916 static JSStaticFunction Functor_staticFunctions[4] = {
1917 {"$cya", &Functor_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1918 {"toCYON", &Functor_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1919 {"valueOf", &Functor_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1920 {NULL, NULL, 0}
1921 };
1922
1923 namespace cy {
1924 JSStaticFunction const * const Functor::StaticFunctions = Functor_staticFunctions;
1925 }
1926
1927 static JSStaticValue Functor_staticValues[2] = {
1928 {"$cyt", &Functor_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1929 {NULL, NULL, NULL, 0}
1930 };
1931
1932 namespace cy {
1933 JSStaticValue const * const Functor::StaticValues = Functor_staticValues;
1934 }
1935
1936 static JSStaticValue Type_staticValues[4] = {
1937 {"alignment", &Type_getProperty_alignment, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1938 {"name", &Type_getProperty_name, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1939 {"size", &Type_getProperty_size, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1940 {NULL, NULL, NULL, 0}
1941 };
1942
1943 static JSStaticFunction Type_staticFunctions[10] = {
1944 {"arrayOf", &Type_callAsFunction_arrayOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1945 {"blockWith", &Type_callAsFunction_blockWith, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1946 {"constant", &Type_callAsFunction_constant, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1947 {"enumFor", &Type_callAsFunction_enumFor, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1948 {"functionWith", &Type_callAsFunction_functionWith, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1949 {"pointerTo", &Type_callAsFunction_pointerTo, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1950 {"withName", &Type_callAsFunction_withName, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1951 {"toCYON", &Type_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1952 {"toString", &Type_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1953 {NULL, NULL, 0}
1954 };
1955
1956 _visible void CYSetArgs(int argc, const char *argv[]) {
1957 JSContextRef context(CYGetJSContext());
1958 JSValueRef args[argc];
1959 for (int i(0); i != argc; ++i)
1960 args[i] = CYCastJSValue(context, argv[i]);
1961
1962 JSObjectRef array(CYObjectMakeArray(context, argc, args));
1963 JSObjectRef System(CYGetCachedObject(context, CYJSString("System")));
1964 CYSetProperty(context, System, CYJSString("args"), array);
1965 }
1966
1967 JSObjectRef CYGetGlobalObject(JSContextRef context) {
1968 return JSContextGetGlobalObject(context);
1969 }
1970
1971 // XXX: this is neither exceptin safe nor even terribly sane
1972 class ExecutionHandle {
1973 private:
1974 JSContextRef context_;
1975 std::vector<void *> handles_;
1976
1977 public:
1978 ExecutionHandle(JSContextRef context) :
1979 context_(context)
1980 {
1981 handles_.resize(GetHooks().size());
1982 for (size_t i(0); i != GetHooks().size(); ++i) {
1983 CYHook *hook(GetHooks()[i]);
1984 if (hook->ExecuteStart != NULL)
1985 handles_[i] = (*hook->ExecuteStart)(context_);
1986 else
1987 handles_[i] = NULL;
1988 }
1989 }
1990
1991 ~ExecutionHandle() {
1992 for (size_t i(GetHooks().size()); i != 0; --i) {
1993 CYHook *hook(GetHooks()[i-1]);
1994 if (hook->ExecuteEnd != NULL)
1995 (*hook->ExecuteEnd)(context_, handles_[i-1]);
1996 }
1997 }
1998 };
1999
2000 #ifndef __ANDROID__
2001 static volatile bool cancel_;
2002
2003 static bool CYShouldTerminate(JSContextRef context, void *arg) {
2004 return cancel_;
2005 }
2006 #endif
2007
2008 _visible const char *CYExecute(JSContextRef context, CYPool &pool, CYUTF8String code) {
2009 ExecutionHandle handle(context);
2010
2011 #ifndef __ANDROID__
2012 cancel_ = false;
2013 if (&JSContextGroupSetExecutionTimeLimit != NULL)
2014 JSContextGroupSetExecutionTimeLimit(JSContextGetGroup(context), 0.5, &CYShouldTerminate, NULL);
2015 #endif
2016
2017 try {
2018 JSValueRef result(_jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0));
2019 if (JSValueIsUndefined(context, result))
2020 return NULL;
2021
2022 std::set<void *> objects;
2023 const char *json(_jsccall(CYPoolCCYON, pool, context, result, objects));
2024 CYSetProperty(context, CYGetGlobalObject(context), Result_, result);
2025
2026 return json;
2027 } catch (const CYException &error) {
2028 return pool.strcat("throw ", error.PoolCString(pool), NULL);
2029 }
2030 }
2031
2032 #ifndef __ANDROID__
2033 _visible void CYCancel() {
2034 cancel_ = true;
2035 }
2036 #endif
2037
2038 const char *CYPoolLibraryPath(CYPool &pool);
2039
2040 static bool initialized_ = false;
2041
2042 void CYInitializeDynamic() {
2043 if (!initialized_)
2044 initialized_ = true;
2045 else return;
2046
2047 CYPool pool;
2048 const char *db(pool.strcat(CYPoolLibraryPath(pool), "/libcycript.db", NULL));
2049 _sqlcall(sqlite3_open_v2(db, &database_, SQLITE_OPEN_READONLY, NULL));
2050
2051 JSObjectMakeArray$ = reinterpret_cast<JSObjectRef (*)(JSContextRef, size_t, const JSValueRef[], JSValueRef *)>(dlsym(RTLD_DEFAULT, "JSObjectMakeArray"));
2052 JSSynchronousGarbageCollectForDebugging$ = reinterpret_cast<void (*)(JSContextRef)>(dlsym(RTLD_DEFAULT, "JSSynchronousGarbageCollectForDebugging"));
2053
2054 JSClassDefinition definition;
2055
2056 definition = kJSClassDefinitionEmpty;
2057 definition.className = "All";
2058 definition.staticFunctions = All_staticFunctions;
2059 definition.hasProperty = &All_hasProperty;
2060 definition.getProperty = &All_getProperty;
2061 definition.getPropertyNames = &All_getPropertyNames;
2062 All_ = JSClassCreate(&definition);
2063
2064 definition = kJSClassDefinitionEmpty;
2065 definition.className = "Context";
2066 definition.finalize = &CYFinalize;
2067 Context::Class_ = JSClassCreate(&definition);
2068
2069 definition = kJSClassDefinitionEmpty;
2070 definition.className = "CArray";
2071 definition.staticFunctions = CArray_staticFunctions;
2072 definition.staticValues = CArray_staticValues;
2073 definition.getProperty = &CArray_getProperty;
2074 definition.setProperty = &CArray_setProperty;
2075 definition.finalize = &CYFinalize;
2076 CArray::Class_ = JSClassCreate(&definition);
2077
2078 definition = kJSClassDefinitionEmpty;
2079 definition.className = "CString";
2080 definition.staticFunctions = CString_staticFunctions;
2081 definition.staticValues = CString_staticValues;
2082 definition.getProperty = &CString_getProperty;
2083 definition.setProperty = &CString_setProperty;
2084 definition.finalize = &CYFinalize;
2085 CString::Class_ = JSClassCreate(&definition);
2086
2087 definition = kJSClassDefinitionEmpty;
2088 definition.className = "Functor";
2089 definition.staticFunctions = cy::Functor::StaticFunctions;
2090 definition.staticValues = Functor_staticValues;
2091 definition.callAsFunction = &Functor_callAsFunction;
2092 definition.finalize = &CYFinalize;
2093 Functor_ = JSClassCreate(&definition);
2094
2095 definition = kJSClassDefinitionEmpty;
2096 definition.className = "Pointer";
2097 definition.staticFunctions = Pointer_staticFunctions;
2098 definition.staticValues = Pointer_staticValues;
2099 definition.callAsFunction = &Pointer_callAsFunction;
2100 definition.getProperty = &Pointer_getProperty;
2101 definition.setProperty = &Pointer_setProperty;
2102 definition.finalize = &CYFinalize;
2103 Pointer::Class_ = JSClassCreate(&definition);
2104
2105 definition = kJSClassDefinitionEmpty;
2106 definition.className = "Struct";
2107 definition.staticFunctions = Struct_staticFunctions;
2108 definition.staticValues = Struct_staticValues;
2109 definition.getProperty = &Struct_getProperty;
2110 definition.setProperty = &Struct_setProperty;
2111 definition.getPropertyNames = &Struct_getPropertyNames;
2112 definition.finalize = &CYFinalize;
2113 Struct_privateData::Class_ = JSClassCreate(&definition);
2114
2115 definition = kJSClassDefinitionEmpty;
2116 definition.className = "Type";
2117 definition.staticValues = Type_staticValues;
2118 definition.staticFunctions = Type_staticFunctions;
2119 definition.callAsFunction = &Type_callAsFunction;
2120 definition.callAsConstructor = &Type_callAsConstructor;
2121 definition.finalize = &CYFinalize;
2122 Type_privateData::Class_ = JSClassCreate(&definition);
2123
2124 definition = kJSClassDefinitionEmpty;
2125 definition.className = "Global";
2126 //definition.getProperty = &Global_getProperty;
2127 Global_ = JSClassCreate(&definition);
2128
2129 Array_s = JSStringCreateWithUTF8CString("Array");
2130 constructor_s = JSStringCreateWithUTF8CString("constructor");
2131 cy_s = JSStringCreateWithUTF8CString("$cy");
2132 cyi_s = JSStringCreateWithUTF8CString("$cyi");
2133 cyt_s = JSStringCreateWithUTF8CString("$cyt");
2134 length_s = JSStringCreateWithUTF8CString("length");
2135 message_s = JSStringCreateWithUTF8CString("message");
2136 name_s = JSStringCreateWithUTF8CString("name");
2137 pop_s = JSStringCreateWithUTF8CString("pop");
2138 prototype_s = JSStringCreateWithUTF8CString("prototype");
2139 push_s = JSStringCreateWithUTF8CString("push");
2140 splice_s = JSStringCreateWithUTF8CString("splice");
2141 toCYON_s = JSStringCreateWithUTF8CString("toCYON");
2142 toJSON_s = JSStringCreateWithUTF8CString("toJSON");
2143 toPointer_s = JSStringCreateWithUTF8CString("toPointer");
2144 toString_s = JSStringCreateWithUTF8CString("toString");
2145 weak_s = JSStringCreateWithUTF8CString("weak");
2146
2147 Result_ = JSStringCreateWithUTF8CString("_");
2148
2149 for (CYHook *hook : GetHooks())
2150 if (hook->Initialize != NULL)
2151 (*hook->Initialize)();
2152 }
2153
2154 void CYThrow(JSContextRef context, JSValueRef value) {
2155 if (value != NULL)
2156 throw CYJSError(context, value);
2157 }
2158
2159 const char *CYJSError::PoolCString(CYPool &pool) const {
2160 std::set<void *> objects;
2161 // XXX: this used to be CYPoolCString
2162 return CYPoolCCYON(pool, context_, value_, objects);
2163 }
2164
2165 JSValueRef CYJSError::CastJSValue(JSContextRef context, const char *name) const {
2166 // XXX: what if the context is different? or the name? I dunno. ("epic" :/)
2167 return value_;
2168 }
2169
2170 JSValueRef CYCastJSError(JSContextRef context, const char *name, const char *message) {
2171 JSObjectRef Error(CYGetCachedObject(context, CYJSString(name)));
2172 JSValueRef arguments[1] = {CYCastJSValue(context, message)};
2173 return _jsccall(JSObjectCallAsConstructor, context, Error, 1, arguments);
2174 }
2175
2176 JSValueRef CYPoolError::CastJSValue(JSContextRef context, const char *name) const {
2177 return CYCastJSError(context, name, message_);
2178 }
2179
2180 CYJSError::CYJSError(JSContextRef context, const char *format, ...) {
2181 _assert(context != NULL);
2182
2183 CYPool pool;
2184
2185 va_list args;
2186 va_start(args, format);
2187 // XXX: there might be a beter way to think about this
2188 const char *message(pool.vsprintf(64, format, args));
2189 va_end(args);
2190
2191 value_ = CYCastJSError(context, "Error", message);
2192 }
2193
2194 JSGlobalContextRef CYGetJSContext(JSContextRef context) {
2195 return reinterpret_cast<Context *>(JSObjectGetPrivate(CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s))))->context_;
2196 }
2197
2198 #ifdef __ANDROID__
2199 char *CYPoolLibraryPath_(CYPool &pool) {
2200 FILE *maps(fopen("/proc/self/maps", "r"));
2201 struct F { FILE *f; F(FILE *f) : f(f) {}
2202 ~F() { fclose(f); } } f(maps);
2203
2204 size_t function(reinterpret_cast<size_t>(&CYPoolLibraryPath));
2205
2206 for (;;) {
2207 size_t start; size_t end; char flags[8]; unsigned long long offset;
2208 int major; int minor; unsigned long long inode; char file[1024];
2209 int count(fscanf(maps, "%zx-%zx %7s %llx %x:%x %llu%[ ]%1024[^\n]\n",
2210 &start, &end, flags, &offset, &major, &minor, &inode, file, file));
2211 if (count < 8) break; else if (start <= function && function < end)
2212 return pool.strdup(file);
2213 }
2214
2215 _assert(false);
2216 }
2217 #else
2218 char *CYPoolLibraryPath_(CYPool &pool) {
2219 Dl_info addr;
2220 _assert(dladdr(reinterpret_cast<void *>(&CYPoolLibraryPath), &addr) != 0);
2221 return pool.strdup(addr.dli_fname);
2222 }
2223 #endif
2224
2225 const char *CYPoolLibraryPath(CYPool &pool) {
2226 char *lib(CYPoolLibraryPath_(pool));
2227
2228 char *slash(strrchr(lib, '/'));
2229 if (slash == NULL)
2230 return ".";
2231 *slash = '\0';
2232
2233 slash = strrchr(lib, '/');
2234 if (slash != NULL) {
2235 if (strcmp(slash, "/.libs") == 0)
2236 *slash = '\0';
2237 } else if (strcmp(lib, ".libs") == 0)
2238 return ".";
2239
2240 return lib;
2241 }
2242
2243 static JSValueRef require_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2244 _assert(count == 1);
2245 CYPool pool;
2246
2247 const char *name(CYPoolCString(pool, context, arguments[0]));
2248 if (strchr(name, '/') == NULL && (
2249 #ifdef __APPLE__
2250 dlopen(pool.strcat("/System/Library/Frameworks/", name, ".framework/", name, NULL), RTLD_LAZY | RTLD_GLOBAL) != NULL ||
2251 dlopen(pool.strcat("/System/Library/PrivateFrameworks/", name, ".framework/", name, NULL), RTLD_LAZY | RTLD_GLOBAL) != NULL ||
2252 #endif
2253 false))
2254 return CYJSUndefined(context);
2255
2256 JSObjectRef resolve(CYCastJSObject(context, CYGetProperty(context, object, CYJSString("resolve"))));
2257 CYJSString path(context, CYCallAsFunction(context, resolve, NULL, 1, arguments));
2258
2259 CYJSString property("exports");
2260
2261 JSObjectRef modules(CYGetCachedObject(context, CYJSString("modules")));
2262 JSValueRef cache(CYGetProperty(context, modules, path));
2263
2264 JSValueRef result;
2265 if (!JSValueIsUndefined(context, cache)) {
2266 JSObjectRef module(CYCastJSObject(context, cache));
2267 result = CYGetProperty(context, module, property);
2268 } else {
2269 CYUTF8String code(CYPoolFileUTF8String(pool, CYPoolCString(pool, context, path)));
2270 _assert(code.data != NULL);
2271
2272 size_t length(strlen(name));
2273 if (length >= 5 && strcmp(name + length - 5, ".json") == 0) {
2274 JSObjectRef JSON(CYGetCachedObject(context, CYJSString("JSON")));
2275 JSObjectRef parse(CYCastJSObject(context, CYGetProperty(context, JSON, CYJSString("parse"))));
2276 JSValueRef arguments[1] = { CYCastJSValue(context, CYJSString(code)) };
2277 result = CYCallAsFunction(context, parse, JSON, 1, arguments);
2278 } else {
2279 JSObjectRef module(JSObjectMake(context, NULL, NULL));
2280 CYSetProperty(context, modules, path, module);
2281
2282 JSObjectRef exports(JSObjectMake(context, NULL, NULL));
2283 CYSetProperty(context, module, property, exports);
2284
2285 std::stringstream wrap;
2286 wrap << "(function (exports, require, module, __filename) { " << code << "\n});";
2287 code = CYPoolCode(pool, *wrap.rdbuf());
2288
2289 JSValueRef value(_jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0));
2290 JSObjectRef function(CYCastJSObject(context, value));
2291
2292 JSValueRef arguments[4] = { exports, object, module, CYCastJSValue(context, path) };
2293 CYCallAsFunction(context, function, NULL, 4, arguments);
2294 result = CYGetProperty(context, module, property);
2295 }
2296 }
2297
2298 return result;
2299 } CYCatch(NULL) }
2300
2301 static bool CYRunScript(JSGlobalContextRef context, const char *path) {
2302 CYPool pool;
2303 CYUTF8String code(CYPoolFileUTF8String(pool, pool.strcat(CYPoolLibraryPath(pool), path, NULL)));
2304 if (code.data == NULL)
2305 return false;
2306
2307 code = CYPoolCode(pool, code);
2308 _jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0);
2309 return true;
2310 }
2311
2312 extern "C" void CYDestroyWeak(JSWeakObjectMapRef weak, void *data) {
2313 }
2314
2315 extern "C" void CYSetupContext(JSGlobalContextRef context) {
2316 CYInitializeDynamic();
2317
2318 JSObjectRef global(CYGetGlobalObject(context));
2319
2320 JSObjectRef cy(Context::Make(context, context));
2321 CYSetProperty(context, global, cy_s, cy, kJSPropertyAttributeDontEnum);
2322
2323 /* Cache Globals {{{ */
2324 JSObjectRef Array(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array"))));
2325 CYSetProperty(context, cy, CYJSString("Array"), Array);
2326
2327 JSObjectRef Array_prototype(CYCastJSObject(context, CYGetProperty(context, Array, prototype_s)));
2328 CYSetProperty(context, cy, CYJSString("Array_prototype"), Array_prototype);
2329
2330 JSObjectRef Boolean(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Boolean"))));
2331 CYSetProperty(context, cy, CYJSString("Boolean"), Boolean);
2332
2333 JSObjectRef Boolean_prototype(CYCastJSObject(context, CYGetProperty(context, Boolean, prototype_s)));
2334 CYSetProperty(context, cy, CYJSString("Boolean_prototype"), Boolean_prototype);
2335
2336 JSObjectRef Error(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Error"))));
2337 CYSetProperty(context, cy, CYJSString("Error"), Error);
2338
2339 JSObjectRef Function(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function"))));
2340 CYSetProperty(context, cy, CYJSString("Function"), Function);
2341
2342 JSObjectRef Function_prototype(CYCastJSObject(context, CYGetProperty(context, Function, prototype_s)));
2343 CYSetProperty(context, cy, CYJSString("Function_prototype"), Function_prototype);
2344
2345 JSObjectRef JSON(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("JSON"))));
2346 CYSetProperty(context, cy, CYJSString("JSON"), JSON);
2347
2348 JSObjectRef Number(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Number"))));
2349 CYSetProperty(context, cy, CYJSString("Number"), Number);
2350
2351 JSObjectRef Number_prototype(CYCastJSObject(context, CYGetProperty(context, Number, prototype_s)));
2352 CYSetProperty(context, cy, CYJSString("Number_prototype"), Number_prototype);
2353
2354 JSObjectRef Object(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Object"))));
2355 CYSetProperty(context, cy, CYJSString("Object"), Object);
2356
2357 JSObjectRef Object_prototype(CYCastJSObject(context, CYGetProperty(context, Object, prototype_s)));
2358 CYSetProperty(context, cy, CYJSString("Object_prototype"), Object_prototype);
2359
2360 JSObjectRef String(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("String"))));
2361 CYSetProperty(context, cy, CYJSString("String"), String);
2362
2363 JSObjectRef String_prototype(CYCastJSObject(context, CYGetProperty(context, String, prototype_s)));
2364 CYSetProperty(context, cy, CYJSString("String_prototype"), String_prototype);
2365
2366 JSObjectRef SyntaxError(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("SyntaxError"))));
2367 CYSetProperty(context, cy, CYJSString("SyntaxError"), SyntaxError);
2368 /* }}} */
2369
2370 CYSetProperty(context, Array_prototype, toCYON_s, &Array_callAsFunction_toCYON, kJSPropertyAttributeDontEnum);
2371 CYSetProperty(context, String_prototype, toCYON_s, &String_callAsFunction_toCYON, kJSPropertyAttributeDontEnum);
2372
2373 JSObjectRef cycript(JSObjectMake(context, NULL, NULL));
2374 CYSetProperty(context, global, CYJSString("Cycript"), cycript);
2375 CYSetProperty(context, cycript, CYJSString("compile"), &Cycript_compile_callAsFunction);
2376 CYSetProperty(context, cycript, CYJSString("gc"), &Cycript_gc_callAsFunction);
2377
2378 JSObjectRef CArray(JSObjectMakeConstructor(context, CArray::Class_, &CArray_new));
2379 CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, CArray, prototype_s)), Array_prototype);
2380 CYSetProperty(context, cycript, CYJSString("CArray"), CArray);
2381
2382 JSObjectRef CString(JSObjectMakeConstructor(context, CString::Class_, &CString_new));
2383 CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, CString, prototype_s)), String_prototype);
2384 CYSetProperty(context, cycript, CYJSString("CString"), CString);
2385
2386 JSObjectRef Functor(JSObjectMakeConstructor(context, Functor_, &Functor_new));
2387 CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Functor, prototype_s)), Function_prototype);
2388 CYSetProperty(context, cycript, CYJSString("Functor"), Functor);
2389
2390 CYSetProperty(context, cycript, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer::Class_, &Pointer_new));
2391 CYSetProperty(context, cycript, CYJSString("Type"), JSObjectMakeConstructor(context, Type_privateData::Class_, &Type_new));
2392
2393 JSObjectRef modules(JSObjectMake(context, NULL, NULL));
2394 CYSetProperty(context, cy, CYJSString("modules"), modules);
2395
2396 JSObjectRef all(JSObjectMake(context, All_, NULL));
2397 CYSetProperty(context, cycript, CYJSString("all"), all);
2398
2399 JSObjectRef cache(JSObjectMake(context, NULL, NULL));
2400 CYSetProperty(context, cy, CYJSString("cache"), cache);
2401 CYSetPrototype(context, cache, all);
2402
2403 JSObjectRef alls(_jsccall(JSObjectCallAsConstructor, context, Array, 0, NULL));
2404 CYSetProperty(context, cycript, CYJSString("alls"), alls);
2405
2406 if (true) {
2407 JSObjectRef last(NULL), curr(global);
2408
2409 goto next; for (JSValueRef next;;) {
2410 if (JSValueIsNull(context, next))
2411 break;
2412 last = curr;
2413 curr = CYCastJSObject(context, next);
2414 next:
2415 next = JSObjectGetPrototype(context, curr);
2416 }
2417
2418 CYSetPrototype(context, last, cache);
2419 }
2420
2421 JSObjectRef System(JSObjectMake(context, NULL, NULL));
2422 CYSetProperty(context, cy, CYJSString("System"), System);
2423
2424 CYSetProperty(context, global, CYJSString("require"), &require_callAsFunction, kJSPropertyAttributeDontEnum);
2425
2426 CYSetProperty(context, global, CYJSString("system"), System);
2427 CYSetProperty(context, System, CYJSString("args"), CYJSNull(context));
2428 CYSetProperty(context, System, CYJSString("print"), &System_print);
2429
2430 CYSetProperty(context, global, CYJSString("global"), global);
2431
2432 #ifdef __APPLE__
2433 if (&JSWeakObjectMapCreate != NULL) {
2434 JSWeakObjectMapRef weak(JSWeakObjectMapCreate(context, NULL, &CYDestroyWeak));
2435 CYSetProperty(context, cy, weak_s, CYCastJSValue(context, reinterpret_cast<uintptr_t>(weak)));
2436 }
2437 #endif
2438
2439 CYSetProperty(context, String_prototype, cyt_s, CYMakeType(context, sig::String()), kJSPropertyAttributeDontEnum);
2440
2441 CYSetProperty(context, cache, CYJSString("dlerror"), CYMakeFunctor(context, "dlerror", "*"), kJSPropertyAttributeDontEnum);
2442 CYSetProperty(context, cache, CYJSString("RTLD_DEFAULT"), CYCastJSValue(context, reinterpret_cast<intptr_t>(RTLD_DEFAULT)), kJSPropertyAttributeDontEnum);
2443 CYSetProperty(context, cache, CYJSString("dlsym"), CYMakeFunctor(context, "dlsym", "^v^v*"), kJSPropertyAttributeDontEnum);
2444
2445 CYSetProperty(context, cache, CYJSString("NULL"), CYJSNull(context), kJSPropertyAttributeDontEnum);
2446
2447 CYSetProperty(context, cache, CYJSString("bool"), CYMakeType(context, sig::Primitive<bool>()), kJSPropertyAttributeDontEnum);
2448 CYSetProperty(context, cache, CYJSString("char"), CYMakeType(context, sig::Primitive<char>()), kJSPropertyAttributeDontEnum);
2449 CYSetProperty(context, cache, CYJSString("schar"), CYMakeType(context, sig::Primitive<signed char>()), kJSPropertyAttributeDontEnum);
2450 CYSetProperty(context, cache, CYJSString("uchar"), CYMakeType(context, sig::Primitive<unsigned char>()), kJSPropertyAttributeDontEnum);
2451
2452 CYSetProperty(context, cache, CYJSString("short"), CYMakeType(context, sig::Primitive<short>()), kJSPropertyAttributeDontEnum);
2453 CYSetProperty(context, cache, CYJSString("int"), CYMakeType(context, sig::Primitive<int>()), kJSPropertyAttributeDontEnum);
2454 CYSetProperty(context, cache, CYJSString("long"), CYMakeType(context, sig::Primitive<long>()), kJSPropertyAttributeDontEnum);
2455 CYSetProperty(context, cache, CYJSString("longlong"), CYMakeType(context, sig::Primitive<long long>()), kJSPropertyAttributeDontEnum);
2456
2457 CYSetProperty(context, cache, CYJSString("ushort"), CYMakeType(context, sig::Primitive<unsigned short>()), kJSPropertyAttributeDontEnum);
2458 CYSetProperty(context, cache, CYJSString("uint"), CYMakeType(context, sig::Primitive<unsigned int>()), kJSPropertyAttributeDontEnum);
2459 CYSetProperty(context, cache, CYJSString("ulong"), CYMakeType(context, sig::Primitive<unsigned long>()), kJSPropertyAttributeDontEnum);
2460 CYSetProperty(context, cache, CYJSString("ulonglong"), CYMakeType(context, sig::Primitive<unsigned long long>()), kJSPropertyAttributeDontEnum);
2461
2462 #ifdef __SIZEOF_INT128__
2463 CYSetProperty(context, cache, CYJSString("int128"), CYMakeType(context, sig::Primitive<__int128>()), kJSPropertyAttributeDontEnum);
2464 CYSetProperty(context, cache, CYJSString("uint128"), CYMakeType(context, sig::Primitive<unsigned __int128>()), kJSPropertyAttributeDontEnum);
2465 #endif
2466
2467 CYSetProperty(context, cache, CYJSString("float"), CYMakeType(context, sig::Primitive<float>()), kJSPropertyAttributeDontEnum);
2468 CYSetProperty(context, cache, CYJSString("double"), CYMakeType(context, sig::Primitive<double>()), kJSPropertyAttributeDontEnum);
2469
2470 for (CYHook *hook : GetHooks())
2471 if (hook->SetupContext != NULL)
2472 (*hook->SetupContext)(context);
2473
2474 CYArrayPush(context, alls, cycript);
2475
2476 CYRunScript(context, "/libcycript.cy");
2477 }
2478
2479 static JSGlobalContextRef context_;
2480
2481 _visible JSGlobalContextRef CYGetJSContext() {
2482 CYInitializeDynamic();
2483
2484 if (context_ == NULL) {
2485 context_ = JSGlobalContextCreate(Global_);
2486 CYSetupContext(context_);
2487 }
2488
2489 return context_;
2490 }
2491
2492 _visible void CYDestroyContext() {
2493 if (context_ == NULL)
2494 return;
2495 JSGlobalContextRelease(context_);
2496 context_ = NULL;
2497 }