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