]> git.saurik.com Git - cycript.git/blame_incremental - Execute.cpp
Add hasProperty for All and ObjectiveC::Classes.
[cycript.git] / Execute.cpp
... / ...
CommitLineData
1/* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
3*/
4
5/* GNU General Public License, Version 3 {{{ */
6/*
7 * Cycript is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
11 *
12 * Cycript is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
19**/
20/* }}} */
21
22#include "Internal.hpp"
23
24#include <dlfcn.h>
25#include <dirent.h>
26#include <fcntl.h>
27#include <unistd.h>
28
29#include "cycript.hpp"
30
31#include "sig/parse.hpp"
32#include "sig/ffi_type.hpp"
33
34#include "Pooling.hpp"
35#include "Execute.hpp"
36
37#include <sys/mman.h>
38#include <sys/stat.h>
39
40#include <iostream>
41#include <set>
42#include <map>
43#include <iomanip>
44#include <sstream>
45#include <cmath>
46
47#include "Parser.hpp"
48
49#include "Decode.hpp"
50#include "Error.hpp"
51#include "JavaScript.hpp"
52#include "String.hpp"
53
54struct CYHooks *hooks_;
55
56/* JavaScript Properties {{{ */
57bool CYHasProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
58 return JSObjectHasProperty(context, object, name);
59}
60
61JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, size_t index) {
62 return _jsccall(JSObjectGetPropertyAtIndex, context, object, index);
63}
64
65JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
66 return _jsccall(JSObjectGetProperty, context, object, name);
67}
68
69void CYSetProperty(JSContextRef context, JSObjectRef object, size_t index, JSValueRef value) {
70 _jsccall(JSObjectSetPropertyAtIndex, context, object, index, value);
71}
72
73void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef value, JSPropertyAttributes attributes) {
74 _jsccall(JSObjectSetProperty, context, object, name, value, attributes);
75}
76
77void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef (*callback)(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef *), JSPropertyAttributes attributes) {
78 CYSetProperty(context, object, name, JSObjectMakeFunctionWithCallback(context, name, callback), attributes);
79}
80/* }}} */
81/* JavaScript Strings {{{ */
82JSStringRef CYCopyJSString(const char *value) {
83 return value == NULL ? NULL : JSStringCreateWithUTF8CString(value);
84}
85
86JSStringRef CYCopyJSString(JSStringRef value) {
87 return value == NULL ? NULL : JSStringRetain(value);
88}
89
90JSStringRef CYCopyJSString(CYUTF8String value) {
91 // XXX: this is very wrong; it needs to convert to UTF16 and then create from there
92 return CYCopyJSString(value.data);
93}
94
95JSStringRef CYCopyJSString(JSContextRef context, JSValueRef value) {
96 if (JSValueIsNull(context, value))
97 return NULL;
98 return _jsccall(JSValueToStringCopy, context, value);
99}
100
101static CYUTF16String CYCastUTF16String(JSStringRef value) {
102 return CYUTF16String(JSStringGetCharactersPtr(value), JSStringGetLength(value));
103}
104
105CYUTF8String CYPoolUTF8String(CYPool &pool, JSContextRef context, JSStringRef value) {
106 return CYPoolUTF8String(pool, CYCastUTF16String(value));
107}
108
109const char *CYPoolCString(CYPool &pool, JSContextRef context, JSStringRef value) {
110 CYUTF8String utf8(CYPoolUTF8String(pool, context, value));
111 _assert(memchr(utf8.data, '\0', utf8.size) == NULL);
112 return utf8.data;
113}
114
115const char *CYPoolCString(CYPool &pool, JSContextRef context, JSValueRef value) {
116 return JSValueIsNull(context, value) ? NULL : CYPoolCString(pool, context, CYJSString(context, value));
117}
118/* }}} */
119/* Index Offsets {{{ */
120size_t CYGetIndex(CYPool &pool, JSContextRef context, JSStringRef value) {
121 return CYGetIndex(CYPoolUTF8String(pool, context, value));
122}
123/* }}} */
124
125static JSClassRef All_;
126static JSClassRef Context_;
127JSClassRef Functor_;
128static JSClassRef Global_;
129static JSClassRef Pointer_;
130static JSClassRef Struct_;
131
132JSStringRef Array_s;
133JSStringRef cy_s;
134JSStringRef cyi_s;
135JSStringRef length_s;
136JSStringRef message_s;
137JSStringRef name_s;
138JSStringRef pop_s;
139JSStringRef prototype_s;
140JSStringRef push_s;
141JSStringRef splice_s;
142JSStringRef toCYON_s;
143JSStringRef toJSON_s;
144JSStringRef toPointer_s;
145JSStringRef toString_s;
146
147static JSStringRef Result_;
148
149void CYFinalize(JSObjectRef object) {
150 CYData *internal(reinterpret_cast<CYData *>(JSObjectGetPrivate(object)));
151 _assert(internal->count_ != _not(unsigned));
152 if (--internal->count_ == 0)
153 delete internal;
154}
155
156void Structor_(CYPool &pool, sig::Type *&type) {
157 if (
158 type->primitive == sig::pointer_P &&
159 type->data.data.type->primitive == sig::struct_P &&
160 type->data.data.type->name != NULL &&
161 strcmp(type->data.data.type->name, "_objc_class") == 0
162 ) {
163 type->primitive = sig::typename_P;
164 type->data.data.type = NULL;
165 return;
166 }
167
168 if (type->primitive != sig::struct_P || type->name == NULL)
169 return;
170
171 size_t length(strlen(type->name));
172 char keyed[length + 2];
173 memcpy(keyed + 1, type->name, length + 1);
174
175 static const char *modes = "34";
176 for (size_t i(0); i != 2; ++i) {
177 char mode(modes[i]);
178 keyed[0] = mode;
179
180 if (CYBridgeEntry *entry = CYBridgeHash(keyed, length + 1))
181 switch (mode) {
182 case '3':
183 sig::Parse(pool, &type->data.signature, entry->value_, &Structor_);
184 break;
185
186 case '4': {
187 sig::Signature signature;
188 sig::Parse(pool, &signature, entry->value_, &Structor_);
189 type = signature.elements[0].type;
190 } break;
191 }
192 }
193}
194
195JSClassRef Type_privateData::Class_;
196
197struct Context :
198 CYData
199{
200 JSGlobalContextRef context_;
201
202 Context(JSGlobalContextRef context) :
203 context_(context)
204 {
205 }
206};
207
208struct Pointer :
209 CYOwned
210{
211 Type_privateData *type_;
212 size_t length_;
213
214 Pointer(void *value, JSContextRef context, JSObjectRef owner, size_t length, sig::Type *type) :
215 CYOwned(value, context, owner),
216 type_(new(*pool_) Type_privateData(type)),
217 length_(length)
218 {
219 }
220};
221
222struct Struct_privateData :
223 CYOwned
224{
225 Type_privateData *type_;
226
227 Struct_privateData(JSContextRef context, JSObjectRef owner) :
228 CYOwned(NULL, context, owner)
229 {
230 }
231};
232
233typedef std::map<const char *, Type_privateData *, CYCStringLess> TypeMap;
234static TypeMap Types_;
235
236JSObjectRef CYMakeStruct(JSContextRef context, void *data, sig::Type *type, ffi_type *ffi, JSObjectRef owner) {
237 Struct_privateData *internal(new Struct_privateData(context, owner));
238 CYPool &pool(*internal->pool_);
239 Type_privateData *typical(new(pool) Type_privateData(type, ffi));
240 internal->type_ = typical;
241
242 if (owner != NULL)
243 internal->value_ = data;
244 else {
245 size_t size(typical->GetFFI()->size);
246 void *copy(internal->pool_->malloc<void>(size));
247 memcpy(copy, data, size);
248 internal->value_ = copy;
249 }
250
251 return JSObjectMake(context, Struct_, internal);
252}
253
254static void *CYCastSymbol(const char *name) {
255 return dlsym(RTLD_DEFAULT, name);
256}
257
258JSValueRef CYCastJSValue(JSContextRef context, bool value) {
259 return JSValueMakeBoolean(context, value);
260}
261
262JSValueRef CYCastJSValue(JSContextRef context, double value) {
263 return JSValueMakeNumber(context, value);
264}
265
266#define CYCastJSValue_(Type_) \
267 JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \
268 return JSValueMakeNumber(context, static_cast<double>(value)); \
269 }
270
271CYCastJSValue_(int)
272CYCastJSValue_(unsigned int)
273CYCastJSValue_(long int)
274CYCastJSValue_(long unsigned int)
275CYCastJSValue_(long long int)
276CYCastJSValue_(long long unsigned int)
277
278JSValueRef CYJSUndefined(JSContextRef context) {
279 return JSValueMakeUndefined(context);
280}
281
282double CYCastDouble(JSContextRef context, JSValueRef value) {
283 return _jsccall(JSValueToNumber, context, value);
284}
285
286bool CYCastBool(JSContextRef context, JSValueRef value) {
287 return JSValueToBoolean(context, value);
288}
289
290JSValueRef CYJSNull(JSContextRef context) {
291 return JSValueMakeNull(context);
292}
293
294JSValueRef CYCastJSValue(JSContextRef context, JSStringRef value) {
295 return value == NULL ? CYJSNull(context) : JSValueMakeString(context, value);
296}
297
298JSValueRef CYCastJSValue(JSContextRef context, const char *value) {
299 return CYCastJSValue(context, CYJSString(value));
300}
301
302JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) {
303 return _jsccall(JSValueToObject, context, value);
304}
305
306JSValueRef CYCallAsFunction(JSContextRef context, JSObjectRef function, JSObjectRef _this, size_t count, const JSValueRef arguments[]) {
307 return _jsccall(JSObjectCallAsFunction, context, function, _this, count, arguments);
308}
309
310bool CYIsCallable(JSContextRef context, JSValueRef value) {
311 return value != NULL && JSValueIsObject(context, value) && JSObjectIsFunction(context, (JSObjectRef) value);
312}
313
314size_t CYArrayLength(JSContextRef context, JSObjectRef array) {
315 return CYCastDouble(context, CYGetProperty(context, array, length_s));
316}
317
318JSValueRef CYArrayGet(JSContextRef context, JSObjectRef array, size_t index) {
319 return _jsccall(JSObjectGetPropertyAtIndex, context, array, index);
320}
321
322void CYArrayPush(JSContextRef context, JSObjectRef array, JSValueRef value) {
323 JSValueRef arguments[1];
324 arguments[0] = value;
325 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
326 _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, push_s)), array, 1, arguments);
327}
328
329static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
330 if (count == 0)
331 printf("\n");
332 else {
333 CYPool pool;
334 printf("%s\n", CYPoolCString(pool, context, arguments[0]));
335 }
336
337 return CYJSUndefined(context);
338} CYCatch(NULL) }
339
340static size_t Nonce_(0);
341
342static JSValueRef $cyq(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
343 CYPool pool;
344 const char *name(pool.strcat(CYPoolCString(pool, context, arguments[0]), pool.itoa(Nonce_++), NULL));
345 return CYCastJSValue(context, name);
346} CYCatch(NULL) }
347
348static void (*JSSynchronousGarbageCollectForDebugging$)(JSContextRef);
349
350void CYGarbageCollect(JSContextRef context) {
351 (JSSynchronousGarbageCollectForDebugging$ ?: &JSGarbageCollect)(context);
352}
353
354static JSValueRef Cycript_gc_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
355 CYGarbageCollect(context);
356 return CYJSUndefined(context);
357} CYCatch(NULL) }
358
359const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, JSValueRef *exception) { CYTry {
360 switch (JSType type = JSValueGetType(context, value)) {
361 case kJSTypeUndefined:
362 return "undefined";
363 case kJSTypeNull:
364 return "null";
365 case kJSTypeBoolean:
366 return CYCastBool(context, value) ? "true" : "false";
367
368 case kJSTypeNumber: {
369 std::ostringstream str;
370 CYNumerify(str, CYCastDouble(context, value));
371 std::string value(str.str());
372 return pool.strmemdup(value.c_str(), value.size());
373 } break;
374
375 case kJSTypeString: {
376 std::ostringstream str;
377 CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, value)));
378 CYStringify(str, string.data, string.size);
379 std::string value(str.str());
380 return pool.strmemdup(value.c_str(), value.size());
381 } break;
382
383 case kJSTypeObject:
384 return CYPoolCCYON(pool, context, (JSObjectRef) value);
385 default:
386 throw CYJSError(context, "JSValueGetType() == 0x%x", type);
387 }
388} CYCatch(NULL) }
389
390const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value) {
391 return _jsccall(CYPoolCCYON, pool, context, value);
392}
393
394const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object) {
395 JSValueRef toCYON(CYGetProperty(context, object, toCYON_s));
396 if (CYIsCallable(context, toCYON)) {
397 JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 0, NULL));
398 _assert(value != NULL);
399 return CYPoolCString(pool, context, value);
400 }
401
402 JSValueRef toJSON(CYGetProperty(context, object, toJSON_s));
403 if (CYIsCallable(context, toJSON)) {
404 JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))};
405 return _jsccall(CYPoolCCYON, pool, context, CYCallAsFunction(context, (JSObjectRef) toJSON, object, 1, arguments));
406 }
407
408 if (JSObjectIsFunction(context, object)) {
409 JSValueRef toString(CYGetProperty(context, object, toString_s));
410 if (CYIsCallable(context, toString)) {
411 JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))};
412 JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toString, object, 1, arguments));
413 _assert(value != NULL);
414 return CYPoolCString(pool, context, value);
415 }
416 }
417
418 std::ostringstream str;
419
420 str << '{';
421
422 // XXX: this is, sadly, going to leak
423 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object));
424
425 bool comma(false);
426
427 for (size_t index(0), count(JSPropertyNameArrayGetCount(names)); index != count; ++index) {
428 if (comma)
429 str << ',';
430 else
431 comma = true;
432
433 JSStringRef name(JSPropertyNameArrayGetNameAtIndex(names, index));
434 CYUTF8String string(CYPoolUTF8String(pool, context, name));
435
436 if (CYIsKey(string))
437 str << string.data;
438 else
439 CYStringify(str, string.data, string.size);
440
441 str << ':';
442
443 try {
444 JSValueRef value(CYGetProperty(context, object, name));
445 str << CYPoolCCYON(pool, context, value);
446 } catch (const CYException &error) {
447 str << "@error";
448 }
449 }
450
451 JSPropertyNameArrayRelease(names);
452
453 str << '}';
454
455 std::string string(str.str());
456 return pool.strmemdup(string.c_str(), string.size());
457}
458
459static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
460 CYPool pool;
461 std::ostringstream str;
462
463 str << '[';
464
465 JSValueRef length(CYGetProperty(context, _this, length_s));
466 bool comma(false);
467
468 for (size_t index(0), count(CYCastDouble(context, length)); index != count; ++index) {
469 if (comma)
470 str << ',';
471 else
472 comma = true;
473
474 try {
475 JSValueRef value(CYGetProperty(context, _this, index));
476 if (!JSValueIsUndefined(context, value))
477 str << CYPoolCCYON(pool, context, value);
478 else {
479 str << ',';
480 comma = false;
481 }
482 } catch (const CYException &error) {
483 str << "@error";
484 }
485 }
486
487 str << ']';
488
489 std::string value(str.str());
490 return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
491} CYCatch(NULL) }
492
493static JSValueRef String_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
494 CYPool pool;
495 std::ostringstream str;
496
497 CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, _this)));
498 CYStringify(str, string.data, string.size);
499
500 std::string value(str.str());
501 return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
502} CYCatch(NULL) }
503
504JSObjectRef CYMakePointer(JSContextRef context, void *pointer, size_t length, sig::Type *type, ffi_type *ffi, JSObjectRef owner) {
505 Pointer *internal(new Pointer(pointer, context, owner, length, type));
506 return JSObjectMake(context, Pointer_, internal);
507}
508
509static JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const sig::Signature &signature) {
510 return JSObjectMake(context, Functor_, new cy::Functor(signature, function));
511}
512
513static JSObjectRef CYMakeFunctor(JSContextRef context, const char *symbol, const char *encoding, void **cache) {
514 cy::Functor *internal;
515 if (*cache != NULL)
516 internal = reinterpret_cast<cy::Functor *>(*cache);
517 else {
518 void (*function)()(reinterpret_cast<void (*)()>(CYCastSymbol(symbol)));
519 if (function == NULL)
520 return NULL;
521
522 internal = new cy::Functor(encoding, function);
523 *cache = internal;
524 }
525
526 ++internal->count_;
527 return JSObjectMake(context, Functor_, internal);
528}
529
530static bool CYGetOffset(CYPool &pool, JSContextRef context, JSStringRef value, ssize_t &index) {
531 return CYGetOffset(CYPoolCString(pool, context, value), index);
532}
533
534void *CYCastPointer_(JSContextRef context, JSValueRef value) {
535 switch (JSValueGetType(context, value)) {
536 case kJSTypeNull:
537 return NULL;
538 case kJSTypeObject: {
539 JSObjectRef object((JSObjectRef) value);
540 if (JSValueIsObjectOfClass(context, value, Pointer_)) {
541 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
542 return internal->value_;
543 }
544 JSValueRef toPointer(CYGetProperty(context, object, toPointer_s));
545 if (CYIsCallable(context, toPointer)) {
546 JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toPointer, object, 0, NULL));
547 _assert(value != NULL);
548 return CYCastPointer_(context, value);
549 }
550 } default:
551 double number(CYCastDouble(context, value));
552 if (std::isnan(number))
553 throw CYJSError(context, "cannot convert value to pointer");
554 return reinterpret_cast<void *>(static_cast<uintptr_t>(static_cast<long long>(number)));
555 }
556}
557
558void CYPoolFFI(CYPool *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) {
559 switch (type->primitive) {
560 case sig::boolean_P:
561 *reinterpret_cast<bool *>(data) = JSValueToBoolean(context, value);
562 break;
563
564#define CYPoolFFI_(primitive, native) \
565 case sig::primitive ## _P: \
566 *reinterpret_cast<native *>(data) = CYCastDouble(context, value); \
567 break;
568
569 CYPoolFFI_(uchar, unsigned char)
570 CYPoolFFI_(char, char)
571 CYPoolFFI_(ushort, unsigned short)
572 CYPoolFFI_(short, short)
573 CYPoolFFI_(ulong, unsigned long)
574 CYPoolFFI_(long, long)
575 CYPoolFFI_(uint, unsigned int)
576 CYPoolFFI_(int, int)
577 CYPoolFFI_(ulonglong, unsigned long long)
578 CYPoolFFI_(longlong, long long)
579 CYPoolFFI_(float, float)
580 CYPoolFFI_(double, double)
581
582 case sig::array_P: {
583 uint8_t *base(reinterpret_cast<uint8_t *>(data));
584 JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL);
585 for (size_t index(0); index != type->data.data.size; ++index) {
586 ffi_type *field(ffi->elements[index]);
587
588 JSValueRef rhs;
589 if (aggregate == NULL)
590 rhs = value;
591 else {
592 rhs = CYGetProperty(context, aggregate, index);
593 if (JSValueIsUndefined(context, rhs))
594 throw CYJSError(context, "unable to extract array value");
595 }
596
597 CYPoolFFI(pool, context, type->data.data.type, field, base, rhs);
598 // XXX: alignment?
599 base += field->size;
600 }
601 } break;
602
603 case sig::pointer_P:
604 *reinterpret_cast<void **>(data) = CYCastPointer<void *>(context, value);
605 break;
606
607 case sig::string_P:
608 _assert(pool != NULL);
609 *reinterpret_cast<const char **>(data) = CYPoolCString(*pool, context, value);
610 break;
611
612 case sig::struct_P: {
613 uint8_t *base(reinterpret_cast<uint8_t *>(data));
614 JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL);
615 for (size_t index(0); index != type->data.signature.count; ++index) {
616 sig::Element *element(&type->data.signature.elements[index]);
617 ffi_type *field(ffi->elements[index]);
618
619 JSValueRef rhs;
620 if (aggregate == NULL)
621 rhs = value;
622 else {
623 rhs = CYGetProperty(context, aggregate, index);
624 if (JSValueIsUndefined(context, rhs)) {
625 if (element->name != NULL)
626 rhs = CYGetProperty(context, aggregate, CYJSString(element->name));
627 else
628 goto undefined;
629 if (JSValueIsUndefined(context, rhs)) undefined:
630 throw CYJSError(context, "unable to extract structure value");
631 }
632 }
633
634 CYPoolFFI(pool, context, element->type, field, base, rhs);
635 // XXX: alignment?
636 base += field->size;
637 }
638 } break;
639
640 case sig::void_P:
641 break;
642
643 default:
644 if (hooks_ != NULL && hooks_->PoolFFI != NULL)
645 if ((*hooks_->PoolFFI)(pool, context, type, ffi, data, value))
646 return;
647
648 CYThrow("unimplemented signature code: '%c''\n", type->primitive);
649 }
650}
651
652JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) {
653 switch (type->primitive) {
654 case sig::boolean_P:
655 return CYCastJSValue(context, *reinterpret_cast<bool *>(data));
656
657#define CYFromFFI_(primitive, native) \
658 case sig::primitive ## _P: \
659 return CYCastJSValue(context, *reinterpret_cast<native *>(data)); \
660
661 CYFromFFI_(uchar, unsigned char)
662 CYFromFFI_(char, char)
663 CYFromFFI_(ushort, unsigned short)
664 CYFromFFI_(short, short)
665 CYFromFFI_(ulong, unsigned long)
666 CYFromFFI_(long, long)
667 CYFromFFI_(uint, unsigned int)
668 CYFromFFI_(int, int)
669 CYFromFFI_(ulonglong, unsigned long long)
670 CYFromFFI_(longlong, long long)
671 CYFromFFI_(float, float)
672 CYFromFFI_(double, double)
673
674 case sig::array_P:
675 if (void *pointer = data)
676 return CYMakePointer(context, pointer, type->data.data.size, type->data.data.type, NULL, owner);
677 else goto null;
678
679 case sig::pointer_P:
680 if (void *pointer = *reinterpret_cast<void **>(data))
681 return CYMakePointer(context, pointer, _not(size_t), type->data.data.type, NULL, owner);
682 else goto null;
683
684 case sig::string_P:
685 if (char *utf8 = *reinterpret_cast<char **>(data))
686 return CYCastJSValue(context, utf8);
687 else goto null;
688
689 case sig::struct_P:
690 return CYMakeStruct(context, data, type, ffi, owner);
691 case sig::void_P:
692 return CYJSUndefined(context);
693
694 null:
695 return CYJSNull(context);
696 default:
697 if (hooks_ != NULL && hooks_->FromFFI != NULL)
698 if (JSValueRef value = (*hooks_->FromFFI)(context, type, ffi, data, initialize, owner))
699 return value;
700
701 CYThrow("unimplemented signature code: '%c''\n", type->primitive);
702 }
703}
704
705void CYExecuteClosure(ffi_cif *cif, void *result, void **arguments, void *arg, JSValueRef (*adapter)(JSContextRef, size_t, JSValueRef[], JSObjectRef)) {
706 Closure_privateData *internal(reinterpret_cast<Closure_privateData *>(arg));
707
708 JSContextRef context(internal->context_);
709
710 size_t count(internal->cif_.nargs);
711 JSValueRef values[count];
712
713 for (size_t index(0); index != count; ++index)
714 values[index] = CYFromFFI(context, internal->signature_.elements[1 + index].type, internal->cif_.arg_types[index], arguments[index]);
715
716 JSValueRef value(adapter(context, count, values, internal->function_));
717 CYPoolFFI(NULL, context, internal->signature_.elements[0].type, internal->cif_.rtype, result, value);
718}
719
720static JSValueRef FunctionAdapter_(JSContextRef context, size_t count, JSValueRef values[], JSObjectRef function) {
721 return CYCallAsFunction(context, function, NULL, count, values);
722}
723
724static void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
725 CYExecuteClosure(cif, result, arguments, arg, &FunctionAdapter_);
726}
727
728Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const sig::Signature &signature, void (*callback)(ffi_cif *, void *, void **, void *)) {
729 // XXX: in case of exceptions this will leak
730 // XXX: in point of fact, this may /need/ to leak :(
731 Closure_privateData *internal(new Closure_privateData(context, function, signature));
732
733#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__))
734 void *executable;
735 ffi_closure *writable(reinterpret_cast<ffi_closure *>(ffi_closure_alloc(sizeof(ffi_closure), &executable)));
736
737 ffi_status status(ffi_prep_closure_loc(writable, &internal->cif_, callback, internal, executable));
738 _assert(status == FFI_OK);
739
740 internal->value_ = executable;
741#else
742 ffi_closure *closure((ffi_closure *) _syscall(mmap(
743 NULL, sizeof(ffi_closure),
744 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
745 -1, 0
746 )));
747
748 ffi_status status(ffi_prep_closure(closure, &internal->cif_, callback, internal));
749 _assert(status == FFI_OK);
750
751 _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
752
753 internal->value_ = closure;
754#endif
755
756 return internal;
757}
758
759static JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const sig::Signature &signature) {
760 Closure_privateData *internal(CYMakeFunctor_(context, function, signature, &FunctionClosure_));
761 JSObjectRef object(JSObjectMake(context, Functor_, internal));
762 // XXX: see above notes about needing to leak
763 JSValueProtect(CYGetJSContext(context), object);
764 return object;
765}
766
767JSObjectRef CYGetCachedObject(JSContextRef context, JSStringRef name) {
768 return CYCastJSObject(context, CYGetProperty(context, CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s)), name));
769}
770
771static JSObjectRef CYMakeFunctor(JSContextRef context, JSValueRef value, const sig::Signature &signature) {
772 JSObjectRef Function(CYGetCachedObject(context, CYJSString("Function")));
773
774 bool function(_jsccall(JSValueIsInstanceOfConstructor, context, value, Function));
775 if (function) {
776 JSObjectRef function(CYCastJSObject(context, value));
777 return CYMakeFunctor(context, function, signature);
778 } else {
779 void (*function)()(CYCastPointer<void (*)()>(context, value));
780 return CYMakeFunctor(context, function, signature);
781 }
782}
783
784static bool Index_(CYPool &pool, JSContextRef context, Struct_privateData *internal, JSStringRef property, ssize_t &index, uint8_t *&base) {
785 Type_privateData *typical(internal->type_);
786 sig::Type *type(typical->type_);
787 if (type == NULL)
788 return false;
789
790 const char *name(CYPoolCString(pool, context, property));
791 size_t length(strlen(name));
792 double number(CYCastDouble(name, length));
793
794 size_t count(type->data.signature.count);
795
796 if (std::isnan(number)) {
797 if (property == NULL)
798 return false;
799
800 sig::Element *elements(type->data.signature.elements);
801
802 for (size_t local(0); local != count; ++local) {
803 sig::Element *element(&elements[local]);
804 if (element->name != NULL && strcmp(name, element->name) == 0) {
805 index = local;
806 goto base;
807 }
808 }
809
810 return false;
811 } else {
812 index = static_cast<ssize_t>(number);
813 if (index != number || index < 0 || static_cast<size_t>(index) >= count)
814 return false;
815 }
816
817 base:
818 ffi_type **elements(typical->GetFFI()->elements);
819
820 base = reinterpret_cast<uint8_t *>(internal->value_);
821 for (ssize_t local(0); local != index; ++local)
822 base += elements[local]->size;
823
824 return true;
825}
826
827static JSValueRef Pointer_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
828 CYPool pool;
829 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
830
831 if (JSStringIsEqual(property, length_s))
832 return internal->length_ == _not(size_t) ? CYJSUndefined(context) : CYCastJSValue(context, internal->length_);
833
834 Type_privateData *typical(internal->type_);
835 if (typical->type_ == NULL)
836 return NULL;
837 sig::Type &type(*typical->type_);
838
839 ssize_t offset;
840 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
841 offset = 0;
842 else if (!CYGetOffset(pool, context, property, offset))
843 return NULL;
844
845 if (type.primitive == sig::function_P)
846 return CYMakeFunctor(context, reinterpret_cast<void (*)()>(internal->value_), type.data.signature);
847
848 ffi_type *ffi(typical->GetFFI());
849
850 uint8_t *base(reinterpret_cast<uint8_t *>(internal->value_));
851 base += ffi->size * offset;
852
853 JSObjectRef owner(internal->GetOwner() ?: object);
854 return CYFromFFI(context, &type, ffi, base, false, owner);
855} CYCatch(NULL) }
856
857static bool Pointer_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
858 CYPool pool;
859 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
860 Type_privateData *typical(internal->type_);
861
862 if (typical->type_ == NULL)
863 return false;
864
865 ssize_t offset;
866 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
867 offset = 0;
868 else if (!CYGetOffset(pool, context, property, offset))
869 return false;
870
871 ffi_type *ffi(typical->GetFFI());
872
873 uint8_t *base(reinterpret_cast<uint8_t *>(internal->value_));
874 base += ffi->size * offset;
875
876 CYPoolFFI(NULL, context, typical->type_, ffi, base, value);
877 return true;
878} CYCatch(false) }
879
880static JSValueRef Struct_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
881 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(_this)));
882 Type_privateData *typical(internal->type_);
883 return CYMakePointer(context, internal->value_, _not(size_t), typical->type_, typical->ffi_, _this);
884} CYCatch(NULL) }
885
886static JSValueRef Struct_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
887 CYPool pool;
888 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
889 Type_privateData *typical(internal->type_);
890
891 ssize_t index;
892 uint8_t *base;
893
894 if (!Index_(pool, context, internal, property, index, base))
895 return NULL;
896
897 JSObjectRef owner(internal->GetOwner() ?: object);
898
899 return CYFromFFI(context, typical->type_->data.signature.elements[index].type, typical->GetFFI()->elements[index], base, false, owner);
900} CYCatch(NULL) }
901
902static bool Struct_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
903 CYPool pool;
904 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
905 Type_privateData *typical(internal->type_);
906
907 ssize_t index;
908 uint8_t *base;
909
910 if (!Index_(pool, context, internal, property, index, base))
911 return false;
912
913 CYPoolFFI(NULL, context, typical->type_->data.signature.elements[index].type, typical->GetFFI()->elements[index], base, value);
914 return true;
915} CYCatch(false) }
916
917static void Struct_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
918 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
919 Type_privateData *typical(internal->type_);
920 sig::Type *type(typical->type_);
921
922 if (type == NULL)
923 return;
924
925 size_t count(type->data.signature.count);
926 sig::Element *elements(type->data.signature.elements);
927
928 char number[32];
929
930 for (size_t index(0); index != count; ++index) {
931 const char *name;
932 name = elements[index].name;
933
934 if (name == NULL) {
935 sprintf(number, "%zu", index);
936 name = number;
937 }
938
939 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
940 }
941}
942
943JSValueRef CYCallFunction(CYPool &pool, JSContextRef context, size_t setups, void *setup[], size_t count, const JSValueRef arguments[], bool initialize, sig::Signature *signature, ffi_cif *cif, void (*function)()) {
944 if (setups + count != signature->count - 1)
945 throw CYJSError(context, "incorrect number of arguments to ffi function");
946
947 size_t size(setups + count);
948 void *values[size];
949 memcpy(values, setup, sizeof(void *) * setups);
950
951 for (size_t index(setups); index != size; ++index) {
952 sig::Element *element(&signature->elements[index + 1]);
953 ffi_type *ffi(cif->arg_types[index]);
954 // XXX: alignment?
955 values[index] = new(pool) uint8_t[ffi->size];
956 CYPoolFFI(&pool, context, element->type, ffi, values[index], arguments[index - setups]);
957 }
958
959 uint8_t value[cif->rtype->size];
960
961 if (hooks_ != NULL && hooks_->CallFunction != NULL)
962 (*hooks_->CallFunction)(context, cif, function, value, values);
963 else
964 ffi_call(cif, function, value, values);
965
966 return CYFromFFI(context, signature->elements[0].type, cif->rtype, value, initialize);
967}
968
969static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
970 CYPool pool;
971 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(object)));
972 return CYCallFunction(pool, context, 0, NULL, count, arguments, false, &internal->signature_, &internal->cif_, internal->GetValue());
973} CYCatch(NULL) }
974
975JSObjectRef CYMakeType(JSContextRef context, const char *encoding) {
976 Type_privateData *internal(new Type_privateData(encoding));
977 return JSObjectMake(context, Type_privateData::Class_, internal);
978}
979
980JSObjectRef CYMakeType(JSContextRef context, sig::Type *type) {
981 Type_privateData *internal(new Type_privateData(type));
982 return JSObjectMake(context, Type_privateData::Class_, internal);
983}
984
985JSObjectRef CYMakeType(JSContextRef context, sig::Signature *signature) {
986 CYPool pool;
987
988 sig::Type type;
989 type.name = NULL;
990 type.flags = 0;
991
992 type.primitive = sig::function_P;
993 sig::Copy(pool, type.data.signature, *signature);
994
995 return CYMakeType(context, &type);
996}
997
998static bool All_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
999 JSObjectRef global(CYGetGlobalObject(context));
1000 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
1001 JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
1002
1003 for (size_t i(0), count(CYArrayLength(context, alls)); i != count; ++i)
1004 if (JSObjectRef space = CYCastJSObject(context, CYArrayGet(context, alls, count - i - 1)))
1005 if (CYHasProperty(context, space, property))
1006 return true;
1007
1008 CYPool pool;
1009 CYUTF8String name(CYPoolUTF8String(pool, context, property));
1010
1011 size_t length(name.size);
1012 char keyed[length + 2];
1013 memcpy(keyed + 1, name.data, length + 1);
1014
1015 static const char *modes = "0124";
1016 for (size_t i(0); i != 4; ++i) {
1017 keyed[0] = modes[i];
1018 if (CYBridgeHash(keyed, length + 1) != NULL)
1019 return true;
1020 }
1021
1022 return false;
1023}
1024
1025static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1026 JSObjectRef global(CYGetGlobalObject(context));
1027 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
1028 JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
1029
1030 for (size_t i(0), count(CYArrayLength(context, alls)); i != count; ++i)
1031 if (JSObjectRef space = CYCastJSObject(context, CYArrayGet(context, alls, count - i - 1)))
1032 if (JSValueRef value = CYGetProperty(context, space, property))
1033 if (!JSValueIsUndefined(context, value))
1034 return value;
1035
1036 CYPool pool;
1037 CYUTF8String name(CYPoolUTF8String(pool, context, property));
1038
1039 size_t length(name.size);
1040 char keyed[length + 2];
1041 memcpy(keyed + 1, name.data, length + 1);
1042
1043 static const char *modes = "0124";
1044 for (size_t i(0); i != 4; ++i) {
1045 char mode(modes[i]);
1046 keyed[0] = mode;
1047
1048 if (CYBridgeEntry *entry = CYBridgeHash(keyed, length + 1))
1049 switch (mode) {
1050 case '0':
1051 return JSEvaluateScript(CYGetJSContext(context), CYJSString(entry->value_), NULL, NULL, 0, NULL);
1052
1053 case '1':
1054 return CYMakeFunctor(context, name.data, entry->value_, &entry->cache_);
1055
1056 case '2':
1057 if (void *symbol = CYCastSymbol(name.data)) {
1058 // XXX: this is horrendously inefficient
1059 sig::Signature signature;
1060 sig::Parse(pool, &signature, entry->value_, &Structor_);
1061 ffi_cif cif;
1062 sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
1063 return CYFromFFI(context, signature.elements[0].type, cif.rtype, symbol);
1064 } else return NULL;
1065
1066 // XXX: implement case 3
1067 case '4':
1068 return CYMakeType(context, entry->value_);
1069 }
1070 }
1071
1072 return NULL;
1073} CYCatch(NULL) }
1074
1075static void All_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
1076 JSObjectRef global(CYGetGlobalObject(context));
1077 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
1078 JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
1079
1080 for (size_t i(0), count(CYArrayLength(context, alls)); i != count; ++i)
1081 if (JSObjectRef space = CYCastJSObject(context, CYArrayGet(context, alls, count - i - 1))) {
1082 JSPropertyNameArrayRef subset(JSObjectCopyPropertyNames(context, space));
1083 for (size_t index(0), count(JSPropertyNameArrayGetCount(subset)); index != count; ++index)
1084 JSPropertyNameAccumulatorAddName(names, JSPropertyNameArrayGetNameAtIndex(subset, index));
1085 JSPropertyNameArrayRelease(subset);
1086 }
1087}
1088
1089static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1090 if (count != 2)
1091 throw CYJSError(context, "incorrect number of arguments to Pointer constructor");
1092
1093 CYPool pool;
1094
1095 void *value(CYCastPointer<void *>(context, arguments[0]));
1096 const char *type(CYPoolCString(pool, context, arguments[1]));
1097
1098 sig::Signature signature;
1099 sig::Parse(pool, &signature, type, &Structor_);
1100
1101 return CYMakePointer(context, value, _not(size_t), signature.elements[0].type, NULL, NULL);
1102} CYCatch(NULL) }
1103
1104static JSObjectRef Type_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1105 if (count != 1)
1106 throw CYJSError(context, "incorrect number of arguments to Type constructor");
1107 CYPool pool;
1108 const char *type(CYPoolCString(pool, context, arguments[0]));
1109 return CYMakeType(context, type);
1110} CYCatch(NULL) }
1111
1112static JSValueRef Type_callAsFunction_$With(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], sig::Primitive primitive, JSValueRef *exception) { CYTry {
1113 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1114
1115 CYPool pool;
1116
1117 sig::Type type;
1118 type.name = NULL;
1119 type.flags = 0;
1120
1121 type.primitive = primitive;
1122 type.data.signature.elements = new(pool) sig::Element[1 + count];
1123 type.data.signature.count = 1 + count;
1124
1125 type.data.signature.elements[0].name = NULL;
1126 type.data.signature.elements[0].type = internal->type_;
1127 type.data.signature.elements[0].offset = _not(size_t);
1128
1129 for (size_t i(0); i != count; ++i) {
1130 sig::Element &element(type.data.signature.elements[i + 1]);
1131 element.name = NULL;
1132 element.offset = _not(size_t);
1133
1134 JSObjectRef object(CYCastJSObject(context, arguments[i]));
1135 _assert(JSValueIsObjectOfClass(context, object, Type_privateData::Class_));
1136 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1137
1138 element.type = internal->type_;
1139 }
1140
1141 return CYMakeType(context, &type);
1142} CYCatch(NULL) }
1143
1144static JSValueRef Type_callAsFunction_arrayOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1145 if (count != 1)
1146 throw CYJSError(context, "incorrect number of arguments to Type.arrayOf");
1147 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1148
1149 CYPool pool;
1150 size_t index(CYGetIndex(pool, context, CYJSString(context, arguments[0])));
1151 if (index == _not(size_t))
1152 throw CYJSError(context, "invalid array size used with Type.arrayOf");
1153
1154 sig::Type type;
1155 type.name = NULL;
1156 type.flags = 0;
1157
1158 type.primitive = sig::array_P;
1159 type.data.data.type = internal->type_;
1160 type.data.data.size = index;
1161
1162 return CYMakeType(context, &type);
1163} CYCatch(NULL) }
1164
1165static JSValueRef Type_callAsFunction_blockWith(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1166 return Type_callAsFunction_$With(context, object, _this, count, arguments, sig::block_P, exception);
1167}
1168
1169static JSValueRef Type_callAsFunction_constant(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1170 if (count != 0)
1171 throw CYJSError(context, "incorrect number of arguments to Type.constant");
1172 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1173
1174 sig::Type type(*internal->type_);
1175 type.flags |= JOC_TYPE_CONST;
1176 return CYMakeType(context, &type);
1177} CYCatch(NULL) }
1178
1179static JSValueRef Type_callAsFunction_long(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1180 if (count != 0)
1181 throw CYJSError(context, "incorrect number of arguments to Type.long");
1182 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1183
1184 sig::Type type(*internal->type_);
1185
1186 switch (type.primitive) {
1187 case sig::short_P: type.primitive = sig::int_P; break;
1188 case sig::int_P: type.primitive = sig::long_P; break;
1189 case sig::long_P: type.primitive = sig::longlong_P; break;
1190 default: throw CYJSError(context, "invalid type argument to Type.long");
1191 }
1192
1193 return CYMakeType(context, &type);
1194} CYCatch(NULL) }
1195
1196static JSValueRef Type_callAsFunction_short(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1197 if (count != 0)
1198 throw CYJSError(context, "incorrect number of arguments to Type.short");
1199 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1200
1201 sig::Type type(*internal->type_);
1202
1203 switch (type.primitive) {
1204 case sig::int_P: type.primitive = sig::short_P; break;
1205 case sig::long_P: type.primitive = sig::int_P; break;
1206 case sig::longlong_P: type.primitive = sig::long_P; break;
1207 default: throw CYJSError(context, "invalid type argument to Type.short");
1208 }
1209
1210 return CYMakeType(context, &type);
1211} CYCatch(NULL) }
1212
1213static JSValueRef Type_callAsFunction_signed(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1214 if (count != 0)
1215 throw CYJSError(context, "incorrect number of arguments to Type.signed");
1216 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1217
1218 sig::Type type(*internal->type_);
1219
1220 switch (type.primitive) {
1221 case sig::char_P: case sig::uchar_P: type.primitive = sig::char_P; break;
1222 case sig::short_P: case sig::ushort_P: type.primitive = sig::short_P; break;
1223 case sig::int_P: case sig::uint_P: type.primitive = sig::int_P; break;
1224 case sig::long_P: case sig::ulong_P: type.primitive = sig::long_P; break;
1225 case sig::longlong_P: case sig::ulonglong_P: type.primitive = sig::longlong_P; break;
1226 default: throw CYJSError(context, "invalid type argument to Type.signed");
1227 }
1228
1229 return CYMakeType(context, &type);
1230} CYCatch(NULL) }
1231
1232static JSValueRef Type_callAsFunction_unsigned(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1233 if (count != 0)
1234 throw CYJSError(context, "incorrect number of arguments to Type.unsigned");
1235 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1236
1237 sig::Type type(*internal->type_);
1238
1239 switch (type.primitive) {
1240 case sig::char_P: case sig::uchar_P: type.primitive = sig::uchar_P; break;
1241 case sig::short_P: case sig::ushort_P: type.primitive = sig::ushort_P; break;
1242 case sig::int_P: case sig::uint_P: type.primitive = sig::uint_P; break;
1243 case sig::long_P: case sig::ulong_P: type.primitive = sig::ulong_P; break;
1244 case sig::longlong_P: case sig::ulonglong_P: type.primitive = sig::ulonglong_P; break;
1245 default: throw CYJSError(context, "invalid type argument to Type.unsigned");
1246 }
1247
1248 return CYMakeType(context, &type);
1249} CYCatch(NULL) }
1250
1251static JSValueRef Type_callAsFunction_functionWith(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1252 return Type_callAsFunction_$With(context, object, _this, count, arguments, sig::function_P, exception);
1253}
1254
1255static JSValueRef Type_callAsFunction_pointerTo(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1256 if (count != 0)
1257 throw CYJSError(context, "incorrect number of arguments to Type.pointerTo");
1258 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1259
1260 sig::Type type;
1261 type.name = NULL;
1262
1263 if (internal->type_->primitive == sig::char_P) {
1264 type.flags = internal->type_->flags;
1265 type.primitive = sig::string_P;
1266 type.data.data.type = NULL;
1267 type.data.data.size = 0;
1268 } else {
1269 type.flags = 0;
1270 type.primitive = sig::pointer_P;
1271 type.data.data.type = internal->type_;
1272 type.data.data.size = 0;
1273 }
1274
1275 return CYMakeType(context, &type);
1276} CYCatch(NULL) }
1277
1278static JSValueRef Type_callAsFunction_withName(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1279 if (count != 1)
1280 throw CYJSError(context, "incorrect number of arguments to Type.withName");
1281 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1282
1283 CYPool pool;
1284 const char *name(CYPoolCString(pool, context, arguments[0]));
1285
1286 sig::Type type(*internal->type_);
1287 type.name = name;
1288 return CYMakeType(context, &type);
1289} CYCatch(NULL) }
1290
1291static JSValueRef Type_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1292 if (count != 1)
1293 throw CYJSError(context, "incorrect number of arguments to type cast function");
1294 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1295
1296 if (internal->type_->primitive == sig::function_P)
1297 return CYMakeFunctor(context, arguments[0], internal->type_->data.signature);
1298
1299 sig::Type *type(internal->type_);
1300 ffi_type *ffi(internal->GetFFI());
1301 // XXX: alignment?
1302 uint8_t value[ffi->size];
1303 CYPool pool;
1304 CYPoolFFI(&pool, context, type, ffi, value, arguments[0]);
1305 return CYFromFFI(context, type, ffi, value);
1306} CYCatch(NULL) }
1307
1308static JSObjectRef Type_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1309 if (count != 0)
1310 throw CYJSError(context, "incorrect number of arguments to Type allocator");
1311 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1312
1313 sig::Type *type(internal->type_);
1314 size_t length;
1315
1316 if (type->primitive != sig::array_P)
1317 length = _not(size_t);
1318 else {
1319 length = type->data.data.size;
1320 type = type->data.data.type;
1321 }
1322
1323 void *value(calloc(1, internal->GetFFI()->size));
1324 return CYMakePointer(context, value, length, type, NULL, NULL);
1325} CYCatch(NULL) }
1326
1327static JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1328 if (count != 2)
1329 throw CYJSError(context, "incorrect number of arguments to Functor constructor");
1330 CYPool pool;
1331 const char *encoding(CYPoolCString(pool, context, arguments[1]));
1332 sig::Signature signature;
1333 sig::Parse(pool, &signature, encoding, &Structor_);
1334 return CYMakeFunctor(context, arguments[0], signature);
1335} CYCatch(NULL) }
1336
1337static JSValueRef CYValue_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1338 CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
1339 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
1340} CYCatch(NULL) }
1341
1342static JSValueRef CYValue_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1343 return CYValue_callAsFunction_valueOf(context, object, _this, count, arguments, exception);
1344}
1345
1346static JSValueRef CYValue_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1347 CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
1348 char string[32];
1349 sprintf(string, "%p", internal->value_);
1350 return CYCastJSValue(context, string);
1351} CYCatch(NULL) }
1352
1353static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1354 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(_this)));
1355 if (internal->length_ != _not(size_t)) {
1356 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
1357 JSObjectRef toCYON(CYCastJSObject(context, CYGetProperty(context, Array, toCYON_s)));
1358 return CYCallAsFunction(context, toCYON, _this, count, arguments);
1359 } else if (internal->type_->type_ == NULL) pointer: {
1360 char string[32];
1361 sprintf(string, "%p", internal->value_);
1362 return CYCastJSValue(context, string);
1363 } try {
1364 JSValueRef value(CYGetProperty(context, _this, cyi_s));
1365 if (JSValueIsUndefined(context, value))
1366 goto pointer;
1367 CYPool pool;
1368 return CYCastJSValue(context, pool.strcat("&", CYPoolCCYON(pool, context, value), NULL));
1369 } catch (const CYException &e) {
1370 goto pointer;
1371 }
1372} CYCatch(NULL) }
1373
1374static JSValueRef Pointer_getProperty_type(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1375 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
1376 return CYMakeType(context, internal->type_->type_);
1377} CYCatch(NULL) }
1378
1379static JSValueRef Functor_getProperty_type(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1380 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(object)));
1381 return CYMakeType(context, &internal->signature_);
1382} CYCatch(NULL) }
1383
1384static JSValueRef Type_getProperty_alignment(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1385 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1386 return CYCastJSValue(context, internal->GetFFI()->alignment);
1387} CYCatch(NULL) }
1388
1389static JSValueRef Type_getProperty_name(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1390 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1391 return CYCastJSValue(context, internal->type_->name);
1392} CYCatch(NULL) }
1393
1394static JSValueRef Type_getProperty_size(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1395 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1396 return CYCastJSValue(context, internal->GetFFI()->size);
1397} CYCatch(NULL) }
1398
1399static JSValueRef Type_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1400 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1401 CYPool pool;
1402 const char *type(sig::Unparse(pool, internal->type_));
1403 return CYCastJSValue(context, CYJSString(type));
1404} CYCatch(NULL) }
1405
1406static JSValueRef Type_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1407 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1408 CYLocalPool pool;
1409 std::ostringstream out;
1410 CYOptions options;
1411 CYOutput output(out, options);
1412 (new(pool) CYEncodedType(Decode(pool, internal->type_)))->Output(output, CYNoFlags);
1413 return CYCastJSValue(context, CYJSString(out.str().c_str()));
1414} CYCatch(NULL) }
1415
1416static JSValueRef Type_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1417 return Type_callAsFunction_toString(context, object, _this, count, arguments, exception);
1418}
1419
1420static JSStaticFunction Pointer_staticFunctions[4] = {
1421 {"toCYON", &Pointer_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1422 {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1423 {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1424 {NULL, NULL, 0}
1425};
1426
1427static JSStaticValue Pointer_staticValues[2] = {
1428 {"type", &Pointer_getProperty_type, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1429 {NULL, NULL, NULL, 0}
1430};
1431
1432static JSStaticFunction Struct_staticFunctions[2] = {
1433 {"$cya", &Struct_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1434 {NULL, NULL, 0}
1435};
1436
1437static JSStaticFunction Functor_staticFunctions[4] = {
1438 {"toCYON", &CYValue_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1439 {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1440 {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1441 {NULL, NULL, 0}
1442};
1443
1444namespace cy {
1445 JSStaticFunction const * const Functor::StaticFunctions = Functor_staticFunctions;
1446}
1447
1448static JSStaticValue Functor_staticValues[2] = {
1449 {"type", &Functor_getProperty_type, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1450 {NULL, NULL, NULL, 0}
1451};
1452
1453namespace cy {
1454 JSStaticValue const * const Functor::StaticValues = Functor_staticValues;
1455}
1456
1457static JSStaticValue Type_staticValues[4] = {
1458 {"alignment", &Type_getProperty_alignment, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1459 {"name", &Type_getProperty_name, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1460 {"size", &Type_getProperty_size, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1461 {NULL, NULL, NULL, 0}
1462};
1463
1464static JSStaticFunction Type_staticFunctions[14] = {
1465 {"arrayOf", &Type_callAsFunction_arrayOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1466 {"blockWith", &Type_callAsFunction_blockWith, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1467 {"constant", &Type_callAsFunction_constant, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1468 {"functionWith", &Type_callAsFunction_functionWith, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1469 {"long", &Type_callAsFunction_long, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1470 {"pointerTo", &Type_callAsFunction_pointerTo, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1471 {"short", &Type_callAsFunction_short, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1472 {"signed", &Type_callAsFunction_signed, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1473 {"withName", &Type_callAsFunction_withName, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1474 {"toCYON", &Type_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1475 {"toJSON", &Type_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1476 {"toString", &Type_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1477 {"unsigned", &Type_callAsFunction_unsigned, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1478 {NULL, NULL, 0}
1479};
1480
1481static JSObjectRef (*JSObjectMakeArray$)(JSContextRef, size_t, const JSValueRef[], JSValueRef *);
1482
1483void CYSetArgs(int argc, const char *argv[]) {
1484 JSContextRef context(CYGetJSContext());
1485 JSValueRef args[argc];
1486 for (int i(0); i != argc; ++i)
1487 args[i] = CYCastJSValue(context, argv[i]);
1488
1489 JSObjectRef array;
1490 if (JSObjectMakeArray$ != NULL)
1491 array = _jsccall(*JSObjectMakeArray$, context, argc, args);
1492 else {
1493 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
1494 JSValueRef value(CYCallAsFunction(context, Array, NULL, argc, args));
1495 array = CYCastJSObject(context, value);
1496 }
1497
1498 JSObjectRef System(CYGetCachedObject(context, CYJSString("System")));
1499 CYSetProperty(context, System, CYJSString("args"), array);
1500}
1501
1502JSObjectRef CYGetGlobalObject(JSContextRef context) {
1503 return JSContextGetGlobalObject(context);
1504}
1505
1506class ExecutionHandle {
1507 private:
1508 JSContextRef context_;
1509 void *handle_;
1510
1511 public:
1512 ExecutionHandle(JSContextRef context) :
1513 context_(context)
1514 {
1515 if (hooks_ != NULL && hooks_->ExecuteStart != NULL)
1516 handle_ = (*hooks_->ExecuteStart)(context_);
1517 else
1518 handle_ = NULL;
1519 }
1520
1521 ~ExecutionHandle() {
1522 if (hooks_ != NULL && hooks_->ExecuteEnd != NULL)
1523 (*hooks_->ExecuteEnd)(context_, handle_);
1524 }
1525};
1526
1527const char *CYExecute(JSContextRef context, CYPool &pool, CYUTF8String code) {
1528 JSValueRef exception(NULL);
1529
1530 ExecutionHandle handle(context);
1531
1532 JSValueRef result; try {
1533 result = JSEvaluateScript(context, CYJSString(code), NULL, NULL, 0, &exception);
1534 } catch (const char *error) {
1535 return error;
1536 }
1537
1538 if (exception != NULL) error:
1539 return CYPoolCString(pool, context, CYJSString(context, exception));
1540
1541 if (JSValueIsUndefined(context, result))
1542 return NULL;
1543
1544 const char *json; try {
1545 json = CYPoolCCYON(pool, context, result, &exception);
1546 } catch (const char *error) {
1547 return error;
1548 }
1549
1550 if (exception != NULL)
1551 goto error;
1552
1553 CYSetProperty(context, CYGetGlobalObject(context), Result_, result);
1554
1555 return json;
1556}
1557
1558static bool initialized_ = false;
1559
1560void CYInitializeDynamic() {
1561 if (!initialized_)
1562 initialized_ = true;
1563 else return;
1564
1565 JSObjectMakeArray$ = reinterpret_cast<JSObjectRef (*)(JSContextRef, size_t, const JSValueRef[], JSValueRef *)>(dlsym(RTLD_DEFAULT, "JSObjectMakeArray"));
1566 JSSynchronousGarbageCollectForDebugging$ = reinterpret_cast<void (*)(JSContextRef)>(dlsym(RTLD_DEFAULT, "JSSynchronousGarbageCollectForDebugging"));
1567
1568 JSClassDefinition definition;
1569
1570 definition = kJSClassDefinitionEmpty;
1571 definition.className = "All";
1572 definition.hasProperty = &All_hasProperty;
1573 definition.getProperty = &All_getProperty;
1574 definition.getPropertyNames = &All_getPropertyNames;
1575 All_ = JSClassCreate(&definition);
1576
1577 definition = kJSClassDefinitionEmpty;
1578 definition.className = "Context";
1579 definition.finalize = &CYFinalize;
1580 Context_ = JSClassCreate(&definition);
1581
1582 definition = kJSClassDefinitionEmpty;
1583 definition.className = "Functor";
1584 definition.staticFunctions = cy::Functor::StaticFunctions;
1585 definition.staticValues = Functor_staticValues;
1586 definition.callAsFunction = &Functor_callAsFunction;
1587 definition.finalize = &CYFinalize;
1588 Functor_ = JSClassCreate(&definition);
1589
1590 definition = kJSClassDefinitionEmpty;
1591 definition.className = "Pointer";
1592 definition.staticFunctions = Pointer_staticFunctions;
1593 definition.staticValues = Pointer_staticValues;
1594 definition.getProperty = &Pointer_getProperty;
1595 definition.setProperty = &Pointer_setProperty;
1596 definition.finalize = &CYFinalize;
1597 Pointer_ = JSClassCreate(&definition);
1598
1599 definition = kJSClassDefinitionEmpty;
1600 definition.className = "Struct";
1601 definition.staticFunctions = Struct_staticFunctions;
1602 definition.getProperty = &Struct_getProperty;
1603 definition.setProperty = &Struct_setProperty;
1604 definition.getPropertyNames = &Struct_getPropertyNames;
1605 definition.finalize = &CYFinalize;
1606 Struct_ = JSClassCreate(&definition);
1607
1608 definition = kJSClassDefinitionEmpty;
1609 definition.className = "Type";
1610 definition.staticValues = Type_staticValues;
1611 definition.staticFunctions = Type_staticFunctions;
1612 definition.callAsFunction = &Type_callAsFunction;
1613 definition.callAsConstructor = &Type_callAsConstructor;
1614 definition.finalize = &CYFinalize;
1615 Type_privateData::Class_ = JSClassCreate(&definition);
1616
1617 definition = kJSClassDefinitionEmpty;
1618 definition.className = "Global";
1619 //definition.getProperty = &Global_getProperty;
1620 Global_ = JSClassCreate(&definition);
1621
1622 Array_s = JSStringCreateWithUTF8CString("Array");
1623 cy_s = JSStringCreateWithUTF8CString("$cy");
1624 cyi_s = JSStringCreateWithUTF8CString("$cyi");
1625 length_s = JSStringCreateWithUTF8CString("length");
1626 message_s = JSStringCreateWithUTF8CString("message");
1627 name_s = JSStringCreateWithUTF8CString("name");
1628 pop_s = JSStringCreateWithUTF8CString("pop");
1629 prototype_s = JSStringCreateWithUTF8CString("prototype");
1630 push_s = JSStringCreateWithUTF8CString("push");
1631 splice_s = JSStringCreateWithUTF8CString("splice");
1632 toCYON_s = JSStringCreateWithUTF8CString("toCYON");
1633 toJSON_s = JSStringCreateWithUTF8CString("toJSON");
1634 toPointer_s = JSStringCreateWithUTF8CString("toPointer");
1635 toString_s = JSStringCreateWithUTF8CString("toString");
1636
1637 Result_ = JSStringCreateWithUTF8CString("_");
1638
1639 if (hooks_ != NULL && hooks_->Initialize != NULL)
1640 (*hooks_->Initialize)();
1641}
1642
1643void CYThrow(JSContextRef context, JSValueRef value) {
1644 if (value != NULL)
1645 throw CYJSError(context, value);
1646}
1647
1648const char *CYJSError::PoolCString(CYPool &pool) const {
1649 // XXX: this used to be CYPoolCString
1650 return CYPoolCCYON(pool, context_, value_);
1651}
1652
1653JSValueRef CYJSError::CastJSValue(JSContextRef context) const {
1654 // XXX: what if the context is different?
1655 return value_;
1656}
1657
1658JSValueRef CYCastJSError(JSContextRef context, const char *message) {
1659 JSObjectRef Error(CYGetCachedObject(context, CYJSString("Error")));
1660 JSValueRef arguments[1] = {CYCastJSValue(context, message)};
1661 return _jsccall(JSObjectCallAsConstructor, context, Error, 1, arguments);
1662}
1663
1664JSValueRef CYPoolError::CastJSValue(JSContextRef context) const {
1665 return CYCastJSError(context, message_);
1666}
1667
1668CYJSError::CYJSError(JSContextRef context, const char *format, ...) {
1669 _assert(context != NULL);
1670
1671 CYPool pool;
1672
1673 va_list args;
1674 va_start(args, format);
1675 // XXX: there might be a beter way to think about this
1676 const char *message(pool.vsprintf(64, format, args));
1677 va_end(args);
1678
1679 value_ = CYCastJSError(context, message);
1680}
1681
1682JSGlobalContextRef CYGetJSContext(JSContextRef context) {
1683 return reinterpret_cast<Context *>(JSObjectGetPrivate(CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s))))->context_;
1684}
1685
1686extern "C" bool CydgetMemoryParse(const uint16_t **data, size_t *size);
1687
1688void *CYMapFile(const char *path, size_t *psize) {
1689 int fd;
1690 _syscall(fd = open(path, O_RDONLY));
1691
1692 struct stat stat;
1693 _syscall(fstat(fd, &stat));
1694 size_t size(stat.st_size);
1695
1696 *psize = size;
1697
1698 void *base;
1699 _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
1700
1701 _syscall(close(fd));
1702 return base;
1703}
1704
1705static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1706 _assert(count == 1);
1707 CYPool pool;
1708
1709 Dl_info addr;
1710 _assert(dladdr(reinterpret_cast<void *>(&require), &addr) != 0);
1711 char *lib(pool.strdup(addr.dli_fname));
1712
1713 char *slash(strrchr(lib, '/'));
1714 _assert(slash != NULL);
1715 *slash = '\0';
1716
1717 CYJSString property("exports");
1718 JSObjectRef module;
1719
1720 const char *path(pool.strcat(lib, "/cycript0.9/", CYPoolCString(pool, context, arguments[0]), ".cy", NULL));
1721 CYJSString key(path);
1722 JSObjectRef modules(CYGetCachedObject(context, CYJSString("modules")));
1723 JSValueRef cache(CYGetProperty(context, modules, key));
1724
1725 if (!JSValueIsUndefined(context, cache))
1726 module = CYCastJSObject(context, cache);
1727 else {
1728 CYUTF8String code;
1729 code.data = reinterpret_cast<char *>(CYMapFile(path, &code.size));
1730
1731 std::stringstream wrap;
1732 wrap << "(function (exports, require, module) { " << code << "\n});";
1733 code = CYPoolCode(pool, wrap.str().c_str());
1734
1735 JSValueRef value(_jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0));
1736 JSObjectRef function(CYCastJSObject(context, value));
1737
1738 module = JSObjectMake(context, NULL, NULL);
1739 JSObjectRef exports(JSObjectMake(context, NULL, NULL));
1740 CYSetProperty(context, module, property, exports);
1741
1742 JSValueRef arguments[3] = { exports, JSObjectMakeFunctionWithCallback(context, CYJSString("require"), &require), module };
1743 CYCallAsFunction(context, function, NULL, 3, arguments);
1744 CYSetProperty(context, modules, key, module);
1745 }
1746
1747 return CYGetProperty(context, module, property);
1748} CYCatch(NULL) }
1749
1750extern "C" void CYSetupContext(JSGlobalContextRef context) {
1751 CYInitializeDynamic();
1752
1753 JSObjectRef global(CYGetGlobalObject(context));
1754
1755 JSObjectRef cy(JSObjectMake(context, Context_, new Context(context)));
1756 CYSetProperty(context, global, cy_s, cy, kJSPropertyAttributeDontEnum);
1757
1758/* Cache Globals {{{ */
1759 JSObjectRef Array(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array"))));
1760 CYSetProperty(context, cy, CYJSString("Array"), Array);
1761
1762 JSObjectRef Array_prototype(CYCastJSObject(context, CYGetProperty(context, Array, prototype_s)));
1763 CYSetProperty(context, cy, CYJSString("Array_prototype"), Array_prototype);
1764
1765 JSObjectRef Boolean(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Boolean"))));
1766 CYSetProperty(context, cy, CYJSString("Boolean"), Boolean);
1767
1768 JSObjectRef Boolean_prototype(CYCastJSObject(context, CYGetProperty(context, Boolean, prototype_s)));
1769 CYSetProperty(context, cy, CYJSString("Boolean_prototype"), Boolean_prototype);
1770
1771 JSObjectRef Error(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Error"))));
1772 CYSetProperty(context, cy, CYJSString("Error"), Error);
1773
1774 JSObjectRef Function(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function"))));
1775 CYSetProperty(context, cy, CYJSString("Function"), Function);
1776
1777 JSObjectRef Function_prototype(CYCastJSObject(context, CYGetProperty(context, Function, prototype_s)));
1778 CYSetProperty(context, cy, CYJSString("Function_prototype"), Function_prototype);
1779
1780 JSObjectRef Number(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Number"))));
1781 CYSetProperty(context, cy, CYJSString("Number"), Number);
1782
1783 JSObjectRef Number_prototype(CYCastJSObject(context, CYGetProperty(context, Number, prototype_s)));
1784 CYSetProperty(context, cy, CYJSString("Number_prototype"), Number_prototype);
1785
1786 JSObjectRef Object(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Object"))));
1787 CYSetProperty(context, cy, CYJSString("Object"), Object);
1788
1789 JSObjectRef Object_prototype(CYCastJSObject(context, CYGetProperty(context, Object, prototype_s)));
1790 CYSetProperty(context, cy, CYJSString("Object_prototype"), Object_prototype);
1791
1792 JSObjectRef String(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("String"))));
1793 CYSetProperty(context, cy, CYJSString("String"), String);
1794
1795 JSObjectRef String_prototype(CYCastJSObject(context, CYGetProperty(context, String, prototype_s)));
1796 CYSetProperty(context, cy, CYJSString("String_prototype"), String_prototype);
1797/* }}} */
1798
1799 CYSetProperty(context, Array_prototype, toCYON_s, &Array_callAsFunction_toCYON, kJSPropertyAttributeDontEnum);
1800 CYSetProperty(context, String_prototype, toCYON_s, &String_callAsFunction_toCYON, kJSPropertyAttributeDontEnum);
1801
1802 JSObjectRef cycript(JSObjectMake(context, NULL, NULL));
1803 CYSetProperty(context, global, CYJSString("Cycript"), cycript);
1804 CYSetProperty(context, cycript, CYJSString("gc"), &Cycript_gc_callAsFunction);
1805
1806 JSObjectRef Functor(JSObjectMakeConstructor(context, Functor_, &Functor_new));
1807 JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Functor, prototype_s)), Function_prototype);
1808 CYSetProperty(context, cycript, CYJSString("Functor"), Functor);
1809
1810 CYSetProperty(context, cycript, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new));
1811 CYSetProperty(context, cycript, CYJSString("Type"), JSObjectMakeConstructor(context, Type_privateData::Class_, &Type_new));
1812
1813 JSObjectRef modules(JSObjectMake(context, NULL, NULL));
1814 CYSetProperty(context, cy, CYJSString("modules"), modules);
1815
1816 JSObjectRef all(JSObjectMake(context, All_, NULL));
1817 CYSetProperty(context, cycript, CYJSString("all"), all);
1818
1819 JSObjectRef alls(_jsccall(JSObjectCallAsConstructor, context, Array, 0, NULL));
1820 CYSetProperty(context, cycript, CYJSString("alls"), alls);
1821
1822 if (true) {
1823 JSObjectRef last(NULL), curr(global);
1824
1825 goto next; for (JSValueRef next;;) {
1826 if (JSValueIsNull(context, next))
1827 break;
1828 last = curr;
1829 curr = CYCastJSObject(context, next);
1830 next:
1831 next = JSObjectGetPrototype(context, curr);
1832 }
1833
1834 JSObjectSetPrototype(context, last, all);
1835 }
1836
1837 CYSetProperty(context, global, CYJSString("$cyq"), &$cyq, kJSPropertyAttributeDontEnum);
1838
1839 JSObjectRef System(JSObjectMake(context, NULL, NULL));
1840 CYSetProperty(context, cy, CYJSString("System"), System);
1841
1842 CYSetProperty(context, all, CYJSString("require"), &require, kJSPropertyAttributeDontEnum);
1843
1844 CYSetProperty(context, global, CYJSString("system"), System);
1845 CYSetProperty(context, System, CYJSString("args"), CYJSNull(context));
1846 //CYSetProperty(context, System, CYJSString("global"), global);
1847 CYSetProperty(context, System, CYJSString("print"), &System_print);
1848
1849 if (CYBridgeEntry *entry = CYBridgeHash("1dlerror", 8))
1850 entry->cache_ = new cy::Functor(entry->value_, reinterpret_cast<void (*)()>(&dlerror));
1851
1852 if (hooks_ != NULL && hooks_->SetupContext != NULL)
1853 (*hooks_->SetupContext)(context);
1854
1855 CYArrayPush(context, alls, cycript);
1856}
1857
1858static JSGlobalContextRef context_;
1859
1860JSGlobalContextRef CYGetJSContext() {
1861 CYInitializeDynamic();
1862
1863 if (context_ == NULL) {
1864 context_ = JSGlobalContextCreate(Global_);
1865 CYSetupContext(context_);
1866 }
1867
1868 return context_;
1869}
1870
1871void CYDestroyContext() {
1872 if (context_ == NULL)
1873 return;
1874 JSGlobalContextRelease(context_);
1875 context_ = NULL;
1876}