]> git.saurik.com Git - cycript.git/blame - Execute.cpp
Fix on Linux?!
[cycript.git] / Execute.cpp
CommitLineData
9cad30fa
JF
1/* Cycript - Inlining/Optimizing JavaScript Compiler
2 * Copyright (C) 2009 Jay Freeman (saurik)
3*/
4
5/* Modified BSD License {{{ */
6/*
7 * Redistribution and use in source and binary
8 * forms, with or without modification, are permitted
9 * provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the
12 * above copyright notice, this list of conditions
13 * and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the
15 * above copyright notice, this list of conditions
16 * and the following disclaimer in the documentation
17 * and/or other materials provided with the
18 * distribution.
19 * 3. The name of the author may not be used to endorse
20 * or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
25 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37*/
38/* }}} */
39
40#include <sqlite3.h>
41
42#include "Internal.hpp"
43
44#include <dlfcn.h>
45#include <iconv.h>
46
47#include "cycript.hpp"
48
49#include "sig/parse.hpp"
50#include "sig/ffi_type.hpp"
51
52#include "Pooling.hpp"
53
54#include <sys/mman.h>
55
56#include <iostream>
57#include <ext/stdio_filebuf.h>
58#include <set>
59#include <map>
60#include <iomanip>
61#include <sstream>
62#include <cmath>
63
64#include "Parser.hpp"
65#include "Cycript.tab.hh"
66
67#include "Error.hpp"
68#include "JavaScript.hpp"
69#include "String.hpp"
70
71char *sqlite3_column_pooled(apr_pool_t *pool, sqlite3_stmt *stmt, int n) {
72 if (const unsigned char *value = sqlite3_column_text(stmt, n))
73 return apr_pstrdup(pool, (const char *) value);
74 else return NULL;
75}
76
77struct CYHooks *hooks_;
78
79/* JavaScript Properties {{{ */
80JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, size_t index) {
81 JSValueRef exception(NULL);
82 JSValueRef value(JSObjectGetPropertyAtIndex(context, object, index, &exception));
83 CYThrow(context, exception);
84 return value;
85}
86
87JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
88 JSValueRef exception(NULL);
89 JSValueRef value(JSObjectGetProperty(context, object, name, &exception));
90 CYThrow(context, exception);
91 return value;
92}
93
94void CYSetProperty(JSContextRef context, JSObjectRef object, size_t index, JSValueRef value) {
95 JSValueRef exception(NULL);
96 JSObjectSetPropertyAtIndex(context, object, index, value, &exception);
97 CYThrow(context, exception);
98}
99
100void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef value, JSPropertyAttributes attributes) {
101 JSValueRef exception(NULL);
102 JSObjectSetProperty(context, object, name, value, attributes, &exception);
103 CYThrow(context, exception);
104}
105
106void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef (*callback)(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef *), JSPropertyAttributes attributes) {
107 CYSetProperty(context, object, name, JSObjectMakeFunctionWithCallback(context, name, callback), attributes);
108}
109/* }}} */
110/* JavaScript Strings {{{ */
111JSStringRef CYCopyJSString(const char *value) {
112 return value == NULL ? NULL : JSStringCreateWithUTF8CString(value);
113}
114
115JSStringRef CYCopyJSString(JSStringRef value) {
116 return value == NULL ? NULL : JSStringRetain(value);
117}
118
119JSStringRef CYCopyJSString(CYUTF8String value) {
120 // XXX: this is very wrong; it needs to convert to UTF16 and then create from there
121 return CYCopyJSString(value.data);
122}
123
124JSStringRef CYCopyJSString(JSContextRef context, JSValueRef value) {
125 if (JSValueIsNull(context, value))
126 return NULL;
127 JSValueRef exception(NULL);
128 JSStringRef string(JSValueToStringCopy(context, value, &exception));
129 CYThrow(context, exception);
130 return string;
131}
132
133static CYUTF16String CYCastUTF16String(JSStringRef value) {
134 return CYUTF16String(JSStringGetCharactersPtr(value), JSStringGetLength(value));
135}
136
137CYUTF8String CYPoolUTF8String(apr_pool_t *pool, JSContextRef context, JSStringRef value) {
138 return CYPoolUTF8String(pool, CYCastUTF16String(value));
139}
140
141const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSStringRef value) {
142 CYUTF8String utf8(CYPoolUTF8String(pool, context, value));
143 _assert(memchr(utf8.data, '\0', utf8.size) == NULL);
144 return utf8.data;
145}
146
147const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
148 return JSValueIsNull(context, value) ? NULL : CYPoolCString(pool, context, CYJSString(context, value));
149}
150/* }}} */
151/* Index Offsets {{{ */
152size_t CYGetIndex(apr_pool_t *pool, JSContextRef context, JSStringRef value) {
153 return CYGetIndex(CYPoolUTF8String(pool, context, value));
154}
155/* }}} */
156
157static JSClassRef All_;
158static JSClassRef Context_;
159static JSClassRef Functor_;
160static JSClassRef Global_;
161static JSClassRef Pointer_;
162static JSClassRef Struct_;
163
164JSStringRef Array_s;
165JSStringRef cy_s;
166JSStringRef length_s;
167JSStringRef message_s;
168JSStringRef name_s;
169JSStringRef pop_s;
170JSStringRef prototype_s;
171JSStringRef push_s;
172JSStringRef splice_s;
173JSStringRef toCYON_s;
174JSStringRef toJSON_s;
175
176static JSStringRef Result_;
177
178sqlite3 *Bridge_;
179
180void CYFinalize(JSObjectRef object) {
181 delete reinterpret_cast<CYData *>(JSObjectGetPrivate(object));
182}
183
9cad30fa
JF
184void Structor_(apr_pool_t *pool, sig::Type *&type) {
185 if (
186 type->primitive == sig::pointer_P &&
187 type->data.data.type != NULL &&
188 type->data.data.type->primitive == sig::struct_P &&
189 strcmp(type->data.data.type->name, "_objc_class") == 0
190 ) {
191 type->primitive = sig::typename_P;
192 type->data.data.type = NULL;
193 return;
194 }
195
196 if (type->primitive != sig::struct_P || type->name == NULL)
197 return;
198
199 sqlite3_stmt *statement;
200
201 _sqlcall(sqlite3_prepare(Bridge_,
202 "select "
203 "\"bridge\".\"mode\", "
204 "\"bridge\".\"value\" "
205 "from \"bridge\" "
206 "where"
207 " \"bridge\".\"mode\" in (3, 4) and"
208 " \"bridge\".\"name\" = ?"
209 " limit 1"
210 , -1, &statement, NULL));
211
212 _sqlcall(sqlite3_bind_text(statement, 1, type->name, -1, SQLITE_STATIC));
213
214 int mode;
215 const char *value;
216
217 if (_sqlcall(sqlite3_step(statement)) == SQLITE_DONE) {
218 mode = -1;
219 value = NULL;
220 } else {
221 mode = sqlite3_column_int(statement, 0);
222 value = sqlite3_column_pooled(pool, statement, 1);
223 }
224
225 _sqlcall(sqlite3_finalize(statement));
226
227 switch (mode) {
228 default:
229 _assert(false);
230 case -1:
231 break;
232
233 case 3: {
234 sig::Parse(pool, &type->data.signature, value, &Structor_);
235 } break;
236
237 case 4: {
238 sig::Signature signature;
239 sig::Parse(pool, &signature, value, &Structor_);
240 type = signature.elements[0].type;
241 } break;
242 }
243}
244
245JSClassRef Type_privateData::Class_;
246
247struct Context :
248 CYData
249{
250 JSGlobalContextRef context_;
251
252 Context(JSGlobalContextRef context) :
253 context_(context)
254 {
255 }
256};
257
258struct Pointer :
259 CYOwned
260{
261 Type_privateData *type_;
262 size_t length_;
263
264 Pointer(void *value, JSContextRef context, JSObjectRef owner, size_t length, sig::Type *type) :
265 CYOwned(value, context, owner),
266 type_(new(pool_) Type_privateData(type)),
267 length_(length)
268 {
269 }
270};
271
272struct Struct_privateData :
273 CYOwned
274{
275 Type_privateData *type_;
276
277 Struct_privateData(JSContextRef context, JSObjectRef owner) :
278 CYOwned(NULL, context, owner)
279 {
280 }
281};
282
14ec9e00 283typedef std::map<const char *, Type_privateData *, CYCStringLess> TypeMap;
9cad30fa
JF
284static TypeMap Types_;
285
286JSObjectRef CYMakeStruct(JSContextRef context, void *data, sig::Type *type, ffi_type *ffi, JSObjectRef owner) {
287 Struct_privateData *internal(new Struct_privateData(context, owner));
288 apr_pool_t *pool(internal->pool_);
289 Type_privateData *typical(new(pool) Type_privateData(type, ffi));
290 internal->type_ = typical;
291
292 if (owner != NULL)
293 internal->value_ = data;
294 else {
295 size_t size(typical->GetFFI()->size);
296 void *copy(apr_palloc(internal->pool_, size));
297 memcpy(copy, data, size);
298 internal->value_ = copy;
299 }
300
301 return JSObjectMake(context, Struct_, internal);
302}
303
304JSValueRef CYCastJSValue(JSContextRef context, bool value) {
305 return JSValueMakeBoolean(context, value);
306}
307
308JSValueRef CYCastJSValue(JSContextRef context, double value) {
309 return JSValueMakeNumber(context, value);
310}
311
312#define CYCastJSValue_(Type_) \
313 JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \
314 return JSValueMakeNumber(context, static_cast<double>(value)); \
315 }
316
317CYCastJSValue_(int)
318CYCastJSValue_(unsigned int)
319CYCastJSValue_(long int)
320CYCastJSValue_(long unsigned int)
321CYCastJSValue_(long long int)
322CYCastJSValue_(long long unsigned int)
323
324JSValueRef CYJSUndefined(JSContextRef context) {
325 return JSValueMakeUndefined(context);
326}
327
328double CYCastDouble(JSContextRef context, JSValueRef value) {
329 JSValueRef exception(NULL);
330 double number(JSValueToNumber(context, value, &exception));
331 CYThrow(context, exception);
332 return number;
333}
334
335bool CYCastBool(JSContextRef context, JSValueRef value) {
336 return JSValueToBoolean(context, value);
337}
338
339JSValueRef CYJSNull(JSContextRef context) {
340 return JSValueMakeNull(context);
341}
342
343JSValueRef CYCastJSValue(JSContextRef context, JSStringRef value) {
344 return value == NULL ? CYJSNull(context) : JSValueMakeString(context, value);
345}
346
347JSValueRef CYCastJSValue(JSContextRef context, const char *value) {
348 return CYCastJSValue(context, CYJSString(value));
349}
350
351JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) {
352 JSValueRef exception(NULL);
353 JSObjectRef object(JSValueToObject(context, value, &exception));
354 CYThrow(context, exception);
355 return object;
356}
357
358JSValueRef CYCallAsFunction(JSContextRef context, JSObjectRef function, JSObjectRef _this, size_t count, const JSValueRef arguments[]) {
359 JSValueRef exception(NULL);
360 JSValueRef value(JSObjectCallAsFunction(context, function, _this, count, arguments, &exception));
361 CYThrow(context, exception);
362 return value;
363}
364
365bool CYIsCallable(JSContextRef context, JSValueRef value) {
366 return value != NULL && JSValueIsObject(context, value) && JSObjectIsFunction(context, (JSObjectRef) value);
367}
368
369static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
370 if (count == 0)
371 printf("\n");
372 else {
373 CYPool pool;
374 printf("%s\n", CYPoolCString(pool, context, arguments[0]));
375 }
376
377 return CYJSUndefined(context);
378} CYCatch }
379
380static size_t Nonce_(0);
381
382static JSValueRef $cyq(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
383 CYPool pool;
384 const char *name(apr_psprintf(pool, "%s%"APR_SIZE_T_FMT"", CYPoolCString(pool, context, arguments[0]), Nonce_++));
385 return CYCastJSValue(context, name);
386}
387
388static JSValueRef Cycript_gc_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
389 JSGarbageCollect(context);
390 return CYJSUndefined(context);
391}
392
393const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSValueRef value, JSValueRef *exception) { CYTry {
394 switch (JSType type = JSValueGetType(context, value)) {
395 case kJSTypeUndefined:
396 return "undefined";
397 case kJSTypeNull:
398 return "null";
399 case kJSTypeBoolean:
400 return CYCastBool(context, value) ? "true" : "false";
401
402 case kJSTypeNumber: {
403 std::ostringstream str;
404 CYNumerify(str, CYCastDouble(context, value));
405 std::string value(str.str());
406 return apr_pstrmemdup(pool, value.c_str(), value.size());
407 } break;
408
409 case kJSTypeString: {
410 std::ostringstream str;
411 CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, value)));
412 CYStringify(str, string.data, string.size);
413 std::string value(str.str());
414 return apr_pstrmemdup(pool, value.c_str(), value.size());
415 } break;
416
417 case kJSTypeObject:
418 return CYPoolCCYON(pool, context, (JSObjectRef) value);
419 default:
420 throw CYJSError(context, "JSValueGetType() == 0x%x", type);
421 }
422} CYCatch }
423
424const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
425 JSValueRef exception(NULL);
426 const char *cyon(CYPoolCCYON(pool, context, value, &exception));
427 CYThrow(context, exception);
428 return cyon;
429}
430
431const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
432 JSValueRef toCYON(CYGetProperty(context, object, toCYON_s));
433 if (CYIsCallable(context, toCYON)) {
434 JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 0, NULL));
435 _assert(value != NULL);
436 return CYPoolCString(pool, context, value);
437 }
438
439 JSValueRef toJSON(CYGetProperty(context, object, toJSON_s));
440 if (CYIsCallable(context, toJSON)) {
441 JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))};
442 JSValueRef exception(NULL);
443 const char *cyon(CYPoolCCYON(pool, context, CYCallAsFunction(context, (JSObjectRef) toJSON, object, 1, arguments), &exception));
444 CYThrow(context, exception);
445 return cyon;
446 }
447
448 std::ostringstream str;
449
450 str << '{';
451
452 // XXX: this is, sadly, going to leak
453 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object));
454
455 bool comma(false);
456
457 for (size_t index(0), count(JSPropertyNameArrayGetCount(names)); index != count; ++index) {
458 JSStringRef name(JSPropertyNameArrayGetNameAtIndex(names, index));
459 JSValueRef value(CYGetProperty(context, object, name));
460
461 if (comma)
462 str << ',';
463 else
464 comma = true;
465
466 CYUTF8String string(CYPoolUTF8String(pool, context, name));
467 if (CYIsKey(string))
468 str << string.data;
469 else
470 CYStringify(str, string.data, string.size);
471
472 str << ':' << CYPoolCCYON(pool, context, value);
473 }
474
475 str << '}';
476
477 JSPropertyNameArrayRelease(names);
478
479 std::string string(str.str());
480 return apr_pstrmemdup(pool, string.c_str(), string.size());
481}
482
483static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
484 CYPool pool;
485 std::ostringstream str;
486
487 str << '[';
488
489 JSValueRef length(CYGetProperty(context, _this, length_s));
490 bool comma(false);
491
492 for (size_t index(0), count(CYCastDouble(context, length)); index != count; ++index) {
493 JSValueRef value(CYGetProperty(context, _this, index));
494
495 if (comma)
496 str << ',';
497 else
498 comma = true;
499
500 if (!JSValueIsUndefined(context, value))
501 str << CYPoolCCYON(pool, context, value);
502 else {
503 str << ',';
504 comma = false;
505 }
506 }
507
508 str << ']';
509
510 std::string value(str.str());
511 return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
512} CYCatch }
513
514JSObjectRef CYMakePointer(JSContextRef context, void *pointer, size_t length, sig::Type *type, ffi_type *ffi, JSObjectRef owner) {
515 Pointer *internal(new Pointer(pointer, context, owner, length, type));
516 return JSObjectMake(context, Pointer_, internal);
517}
518
519static JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) {
520 cy::Functor *internal(new cy::Functor(type, function));
521 return JSObjectMake(context, Functor_, internal);
522}
523
524static bool CYGetOffset(apr_pool_t *pool, JSContextRef context, JSStringRef value, ssize_t &index) {
525 return CYGetOffset(CYPoolCString(pool, context, value), index);
526}
527
528void *CYCastPointer_(JSContextRef context, JSValueRef value) {
529 switch (JSValueGetType(context, value)) {
530 case kJSTypeNull:
531 return NULL;
532 /*case kJSTypeObject:
533 if (JSValueIsObjectOfClass(context, value, Pointer_)) {
534 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate((JSObjectRef) value)));
535 return internal->value_;
536 }*/
537 default:
538 double number(CYCastDouble(context, value));
539 if (std::isnan(number))
540 throw CYJSError(context, "cannot convert value to pointer");
541 return reinterpret_cast<void *>(static_cast<uintptr_t>(static_cast<long long>(number)));
542 }
543}
544
545void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) {
546 switch (type->primitive) {
547 case sig::boolean_P:
548 *reinterpret_cast<bool *>(data) = JSValueToBoolean(context, value);
549 break;
550
551#define CYPoolFFI_(primitive, native) \
552 case sig::primitive ## _P: \
553 *reinterpret_cast<native *>(data) = CYCastDouble(context, value); \
554 break;
555
556 CYPoolFFI_(uchar, unsigned char)
557 CYPoolFFI_(char, char)
558 CYPoolFFI_(ushort, unsigned short)
559 CYPoolFFI_(short, short)
560 CYPoolFFI_(ulong, unsigned long)
561 CYPoolFFI_(long, long)
562 CYPoolFFI_(uint, unsigned int)
563 CYPoolFFI_(int, int)
564 CYPoolFFI_(ulonglong, unsigned long long)
565 CYPoolFFI_(longlong, long long)
566 CYPoolFFI_(float, float)
567 CYPoolFFI_(double, double)
568
569 case sig::array_P: {
570 uint8_t *base(reinterpret_cast<uint8_t *>(data));
571 JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL);
572 for (size_t index(0); index != type->data.data.size; ++index) {
573 ffi_type *field(ffi->elements[index]);
574
575 JSValueRef rhs;
576 if (aggregate == NULL)
577 rhs = value;
578 else {
579 rhs = CYGetProperty(context, aggregate, index);
580 if (JSValueIsUndefined(context, rhs))
581 throw CYJSError(context, "unable to extract array value");
582 }
583
584 CYPoolFFI(pool, context, type->data.data.type, field, base, rhs);
585 // XXX: alignment?
586 base += field->size;
587 }
588 } break;
589
590 case sig::pointer_P:
591 *reinterpret_cast<void **>(data) = CYCastPointer<void *>(context, value);
592 break;
593
594 case sig::string_P:
595 *reinterpret_cast<const char **>(data) = CYPoolCString(pool, context, value);
596 break;
597
598 case sig::struct_P: {
599 uint8_t *base(reinterpret_cast<uint8_t *>(data));
600 JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL);
601 for (size_t index(0); index != type->data.signature.count; ++index) {
602 sig::Element *element(&type->data.signature.elements[index]);
603 ffi_type *field(ffi->elements[index]);
604
605 JSValueRef rhs;
606 if (aggregate == NULL)
607 rhs = value;
608 else {
609 rhs = CYGetProperty(context, aggregate, index);
610 if (JSValueIsUndefined(context, rhs)) {
611 if (element->name != NULL)
612 rhs = CYGetProperty(context, aggregate, CYJSString(element->name));
613 else
614 goto undefined;
615 if (JSValueIsUndefined(context, rhs)) undefined:
616 throw CYJSError(context, "unable to extract structure value");
617 }
618 }
619
620 CYPoolFFI(pool, context, element->type, field, base, rhs);
621 // XXX: alignment?
622 base += field->size;
623 }
624 } break;
625
626 case sig::void_P:
627 break;
628
629 default:
630 if (hooks_ != NULL && hooks_->PoolFFI != NULL)
631 if ((*hooks_->PoolFFI)(pool, context, type, ffi, data, value))
632 return;
633
634 CYThrow("unimplemented signature code: '%c''\n", type->primitive);
635 }
636}
637
638JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) {
639 switch (type->primitive) {
640 case sig::boolean_P:
641 return CYCastJSValue(context, *reinterpret_cast<bool *>(data));
642
643#define CYFromFFI_(primitive, native) \
644 case sig::primitive ## _P: \
645 return CYCastJSValue(context, *reinterpret_cast<native *>(data)); \
646
647 CYFromFFI_(uchar, unsigned char)
648 CYFromFFI_(char, char)
649 CYFromFFI_(ushort, unsigned short)
650 CYFromFFI_(short, short)
651 CYFromFFI_(ulong, unsigned long)
652 CYFromFFI_(long, long)
653 CYFromFFI_(uint, unsigned int)
654 CYFromFFI_(int, int)
655 CYFromFFI_(ulonglong, unsigned long long)
656 CYFromFFI_(longlong, long long)
657 CYFromFFI_(float, float)
658 CYFromFFI_(double, double)
659
660 case sig::array_P:
661 if (void *pointer = data)
662 return CYMakePointer(context, pointer, type->data.data.size, type->data.data.type, NULL, owner);
663 else goto null;
664
665 case sig::pointer_P:
666 if (void *pointer = *reinterpret_cast<void **>(data))
667 return CYMakePointer(context, pointer, _not(size_t), type->data.data.type, NULL, owner);
668 else goto null;
669
670 case sig::string_P:
671 if (char *utf8 = *reinterpret_cast<char **>(data))
672 return CYCastJSValue(context, utf8);
673 else goto null;
674
675 case sig::struct_P:
676 return CYMakeStruct(context, data, type, ffi, owner);
677 case sig::void_P:
678 return CYJSUndefined(context);
679
680 null:
681 return CYJSNull(context);
682 default:
683 if (hooks_ != NULL && hooks_->FromFFI != NULL)
684 if (JSValueRef value = (*hooks_->FromFFI)(context, type, ffi, data, initialize, owner))
685 return value;
686
687 CYThrow("unimplemented signature code: '%c''\n", type->primitive);
688 }
689}
690
691static void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
692 Closure_privateData *internal(reinterpret_cast<Closure_privateData *>(arg));
693
694 JSContextRef context(internal->context_);
695
696 size_t count(internal->cif_.nargs);
697 JSValueRef values[count];
698
699 for (size_t index(0); index != count; ++index)
700 values[index] = CYFromFFI(context, internal->signature_.elements[1 + index].type, internal->cif_.arg_types[index], arguments[index]);
701
702 JSValueRef value(CYCallAsFunction(context, internal->function_, NULL, count, values));
703 CYPoolFFI(NULL, context, internal->signature_.elements[0].type, internal->cif_.rtype, result, value);
704}
705
706Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const char *type, void (*callback)(ffi_cif *, void *, void **, void *)) {
707 // XXX: in case of exceptions this will leak
708 // XXX: in point of fact, this may /need/ to leak :(
709 Closure_privateData *internal(new Closure_privateData(context, function, type));
710
711 ffi_closure *closure((ffi_closure *) _syscall(mmap(
712 NULL, sizeof(ffi_closure),
713 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
714 -1, 0
715 )));
716
717 ffi_status status(ffi_prep_closure(closure, &internal->cif_, callback, internal));
718 _assert(status == FFI_OK);
719
720 _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
721
722 internal->value_ = closure;
723
724 return internal;
725}
726
727static JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) {
728 Closure_privateData *internal(CYMakeFunctor_(context, function, type, &FunctionClosure_));
729 JSObjectRef object(JSObjectMake(context, Functor_, internal));
730 // XXX: see above notes about needing to leak
731 JSValueProtect(CYGetJSContext(context), object);
732 return object;
733}
734
735JSObjectRef CYGetCachedObject(JSContextRef context, JSStringRef name) {
736 return CYCastJSObject(context, CYGetProperty(context, CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s)), name));
737}
738
739static JSObjectRef CYMakeFunctor(JSContextRef context, JSValueRef value, const char *type) {
740 JSObjectRef Function(CYGetCachedObject(context, CYJSString("Function")));
741
742 JSValueRef exception(NULL);
743 bool function(JSValueIsInstanceOfConstructor(context, value, Function, &exception));
744 CYThrow(context, exception);
745
746 if (function) {
747 JSObjectRef function(CYCastJSObject(context, value));
748 return CYMakeFunctor(context, function, type);
749 } else {
750 void (*function)()(CYCastPointer<void (*)()>(context, value));
751 return CYMakeFunctor(context, function, type);
752 }
753}
754
755static bool Index_(apr_pool_t *pool, JSContextRef context, Struct_privateData *internal, JSStringRef property, ssize_t &index, uint8_t *&base) {
756 Type_privateData *typical(internal->type_);
757 sig::Type *type(typical->type_);
758 if (type == NULL)
759 return false;
760
761 const char *name(CYPoolCString(pool, context, property));
762 size_t length(strlen(name));
763 double number(CYCastDouble(name, length));
764
765 size_t count(type->data.signature.count);
766
767 if (std::isnan(number)) {
768 if (property == NULL)
769 return false;
770
771 sig::Element *elements(type->data.signature.elements);
772
773 for (size_t local(0); local != count; ++local) {
774 sig::Element *element(&elements[local]);
775 if (element->name != NULL && strcmp(name, element->name) == 0) {
776 index = local;
777 goto base;
778 }
779 }
780
781 return false;
782 } else {
783 index = static_cast<ssize_t>(number);
784 if (index != number || index < 0 || static_cast<size_t>(index) >= count)
785 return false;
786 }
787
788 base:
789 ffi_type **elements(typical->GetFFI()->elements);
790
791 base = reinterpret_cast<uint8_t *>(internal->value_);
792 for (ssize_t local(0); local != index; ++local)
793 base += elements[local]->size;
794
795 return true;
796}
797
798static JSValueRef Pointer_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
799 CYPool pool;
800 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
801
802 if (JSStringIsEqual(property, length_s))
803 return internal->length_ == _not(size_t) ? CYJSUndefined(context) : CYCastJSValue(context, internal->length_);
804
805 Type_privateData *typical(internal->type_);
806
807 if (typical->type_ == NULL)
808 return NULL;
809
810 ssize_t offset;
811 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
812 offset = 0;
813 else if (!CYGetOffset(pool, context, property, offset))
814 return NULL;
815
816 ffi_type *ffi(typical->GetFFI());
817
818 uint8_t *base(reinterpret_cast<uint8_t *>(internal->value_));
819 base += ffi->size * offset;
820
821 JSObjectRef owner(internal->GetOwner() ?: object);
822 return CYFromFFI(context, typical->type_, ffi, base, false, owner);
823} CYCatch }
824
825static bool Pointer_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
826 CYPool pool;
827 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
828 Type_privateData *typical(internal->type_);
829
830 if (typical->type_ == NULL)
831 return NULL;
832
833 ssize_t offset;
834 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
835 offset = 0;
836 else if (!CYGetOffset(pool, context, property, offset))
837 return NULL;
838
839 ffi_type *ffi(typical->GetFFI());
840
841 uint8_t *base(reinterpret_cast<uint8_t *>(internal->value_));
842 base += ffi->size * offset;
843
844 CYPoolFFI(NULL, context, typical->type_, ffi, base, value);
845 return true;
846} CYCatch }
847
848static JSValueRef Struct_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
849 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(_this)));
850 Type_privateData *typical(internal->type_);
851 return CYMakePointer(context, internal->value_, _not(size_t), typical->type_, typical->ffi_, _this);
852}
853
854static JSValueRef Struct_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
855 CYPool pool;
856 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
857 Type_privateData *typical(internal->type_);
858
859 ssize_t index;
860 uint8_t *base;
861
862 if (!Index_(pool, context, internal, property, index, base))
863 return NULL;
864
865 JSObjectRef owner(internal->GetOwner() ?: object);
866
867 return CYFromFFI(context, typical->type_->data.signature.elements[index].type, typical->GetFFI()->elements[index], base, false, owner);
868} CYCatch }
869
870static bool Struct_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
871 CYPool pool;
872 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
873 Type_privateData *typical(internal->type_);
874
875 ssize_t index;
876 uint8_t *base;
877
878 if (!Index_(pool, context, internal, property, index, base))
879 return false;
880
881 CYPoolFFI(NULL, context, typical->type_->data.signature.elements[index].type, typical->GetFFI()->elements[index], base, value);
882 return true;
883} CYCatch }
884
885static void Struct_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
886 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
887 Type_privateData *typical(internal->type_);
888 sig::Type *type(typical->type_);
889
890 if (type == NULL)
891 return;
892
893 size_t count(type->data.signature.count);
894 sig::Element *elements(type->data.signature.elements);
895
896 char number[32];
897
898 for (size_t index(0); index != count; ++index) {
899 const char *name;
900 name = elements[index].name;
901
902 if (name == NULL) {
903 sprintf(number, "%zu", index);
904 name = number;
905 }
906
907 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
908 }
909}
910
911JSValueRef CYCallFunction(apr_pool_t *pool, JSContextRef context, size_t setups, void *setup[], size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) { CYTry {
912 if (setups + count != signature->count - 1)
913 throw CYJSError(context, "incorrect number of arguments to ffi function");
914
915 size_t size(setups + count);
916 void *values[size];
917 memcpy(values, setup, sizeof(void *) * setups);
918
919 for (size_t index(setups); index != size; ++index) {
920 sig::Element *element(&signature->elements[index + 1]);
921 ffi_type *ffi(cif->arg_types[index]);
922 // XXX: alignment?
923 values[index] = new(pool) uint8_t[ffi->size];
924 CYPoolFFI(pool, context, element->type, ffi, values[index], arguments[index - setups]);
925 }
926
927 uint8_t value[cif->rtype->size];
928
929 if (hooks_ != NULL && hooks_->CallFunction != NULL)
930 (*hooks_->CallFunction)(context, cif, function, value, values);
931 else
932 ffi_call(cif, function, value, values);
933
934 return CYFromFFI(context, signature->elements[0].type, cif->rtype, value, initialize);
935} CYCatch }
936
937static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
938 CYPool pool;
939 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(object)));
940 return CYCallFunction(pool, context, 0, NULL, count, arguments, false, exception, &internal->signature_, &internal->cif_, internal->GetValue());
941}
942
943static JSObjectRef CYMakeType(JSContextRef context, const char *type) {
944 Type_privateData *internal(new Type_privateData(type));
945 return JSObjectMake(context, Type_privateData::Class_, internal);
946}
947
948static JSObjectRef CYMakeType(JSContextRef context, sig::Type *type) {
949 Type_privateData *internal(new Type_privateData(type));
950 return JSObjectMake(context, Type_privateData::Class_, internal);
951}
952
953static void *CYCastSymbol(const char *name) {
954 return dlsym(RTLD_DEFAULT, name);
955}
956
957static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
958 JSObjectRef global(CYGetGlobalObject(context));
959 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
960 if (JSValueRef value = CYGetProperty(context, cycript, property))
961 if (!JSValueIsUndefined(context, value))
962 return value;
963
964 CYPool pool;
965 CYUTF8String name(CYPoolUTF8String(pool, context, property));
966
967 if (hooks_ != NULL && hooks_->RuntimeProperty != NULL)
968 if (JSValueRef value = (*hooks_->RuntimeProperty)(context, name))
969 return value;
970
971 sqlite3_stmt *statement;
972
973 _sqlcall(sqlite3_prepare(Bridge_,
974 "select "
975 "\"bridge\".\"mode\", "
976 "\"bridge\".\"value\" "
977 "from \"bridge\" "
978 "where"
979 " \"bridge\".\"name\" = ?"
980 " limit 1"
981 , -1, &statement, NULL));
982
983 _sqlcall(sqlite3_bind_text(statement, 1, name.data, name.size, SQLITE_STATIC));
984
985 int mode;
986 const char *value;
987
988 if (_sqlcall(sqlite3_step(statement)) == SQLITE_DONE) {
989 mode = -1;
990 value = NULL;
991 } else {
992 mode = sqlite3_column_int(statement, 0);
993 value = sqlite3_column_pooled(pool, statement, 1);
994 }
995
996 _sqlcall(sqlite3_finalize(statement));
997
998 switch (mode) {
999 default:
1000 CYThrow("invalid mode from bridge table: %d", mode);
1001 case -1:
1002 return NULL;
1003
1004 case 0:
1005 return JSEvaluateScript(CYGetJSContext(context), CYJSString(value), NULL, NULL, 0, NULL);
1006
1007 case 1:
1008 if (void (*symbol)() = reinterpret_cast<void (*)()>(CYCastSymbol(name.data)))
1009 return CYMakeFunctor(context, symbol, value);
1010 else return NULL;
1011
1012 case 2:
1013 if (void *symbol = CYCastSymbol(name.data)) {
1014 // XXX: this is horrendously inefficient
1015 sig::Signature signature;
1016 sig::Parse(pool, &signature, value, &Structor_);
1017 ffi_cif cif;
1018 sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
1019 return CYFromFFI(context, signature.elements[0].type, cif.rtype, symbol);
1020 } else return NULL;
1021
1022 // XXX: implement case 3
1023 case 4:
1024 return CYMakeType(context, value);
1025 }
1026} CYCatch }
1027
1028static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1029 if (count != 2)
1030 throw CYJSError(context, "incorrect number of arguments to Functor constructor");
1031
1032 CYPool pool;
1033
1034 void *value(CYCastPointer<void *>(context, arguments[0]));
1035 const char *type(CYPoolCString(pool, context, arguments[1]));
1036
1037 sig::Signature signature;
1038 sig::Parse(pool, &signature, type, &Structor_);
1039
1040 return CYMakePointer(context, value, _not(size_t), signature.elements[0].type, NULL, NULL);
1041} CYCatch }
1042
1043static JSObjectRef Type_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1044 if (count != 1)
1045 throw CYJSError(context, "incorrect number of arguments to Type constructor");
1046 CYPool pool;
1047 const char *type(CYPoolCString(pool, context, arguments[0]));
1048 return CYMakeType(context, type);
1049} CYCatch }
1050
1051static JSValueRef Type_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1052 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1053
1054 sig::Type type;
1055
1056 if (JSStringIsEqualToUTF8CString(property, "$cyi")) {
1057 type.primitive = sig::pointer_P;
1058 type.data.data.size = 0;
1059 } else {
1060 CYPool pool;
1061 size_t index(CYGetIndex(pool, context, property));
1062 if (index == _not(size_t))
1063 return NULL;
1064 type.primitive = sig::array_P;
1065 type.data.data.size = index;
1066 }
1067
1068 type.name = NULL;
1069 type.flags = 0;
1070
1071 type.data.data.type = internal->type_;
1072
1073 return CYMakeType(context, &type);
1074} CYCatch }
1075
1076static JSValueRef Type_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1077 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1078
1079 if (count != 1)
1080 throw CYJSError(context, "incorrect number of arguments to type cast function");
1081 sig::Type *type(internal->type_);
1082 ffi_type *ffi(internal->GetFFI());
1083 // XXX: alignment?
1084 uint8_t value[ffi->size];
1085 CYPool pool;
1086 CYPoolFFI(pool, context, type, ffi, value, arguments[0]);
1087 return CYFromFFI(context, type, ffi, value);
1088} CYCatch }
1089
1090static JSObjectRef Type_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1091 if (count != 0)
1092 throw CYJSError(context, "incorrect number of arguments to type cast function");
1093 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1094
1095 sig::Type *type(internal->type_);
1096 size_t length;
1097
1098 if (type->primitive != sig::array_P)
1099 length = _not(size_t);
1100 else {
1101 length = type->data.data.size;
1102 type = type->data.data.type;
1103 }
1104
1105 void *value(malloc(internal->GetFFI()->size));
1106 return CYMakePointer(context, value, length, type, NULL, NULL);
1107} CYCatch }
1108
1109static JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1110 if (count != 2)
1111 throw CYJSError(context, "incorrect number of arguments to Functor constructor");
1112 CYPool pool;
1113 const char *type(CYPoolCString(pool, context, arguments[1]));
1114 return CYMakeFunctor(context, arguments[0], type);
1115} CYCatch }
1116
1117static JSValueRef CYValue_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1118 CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
1119 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
1120} CYCatch }
1121
1122static JSValueRef CYValue_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1123 return CYValue_callAsFunction_valueOf(context, object, _this, count, arguments, exception);
1124}
1125
1126static JSValueRef CYValue_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1127 CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
1128 char string[32];
1129 sprintf(string, "%p", internal->value_);
1130 return CYCastJSValue(context, string);
1131} CYCatch }
1132
1133static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1134 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(_this)));
1135 if (internal->length_ != _not(size_t)) {
1136 JSObjectRef Array(CYGetCachedObject(context, Array_s));
1137 JSObjectRef toCYON(CYCastJSObject(context, CYGetProperty(context, Array, toCYON_s)));
1138 return CYCallAsFunction(context, toCYON, _this, count, arguments);
1139 } else {
1140 char string[32];
1141 sprintf(string, "%p", internal->value_);
1142 return CYCastJSValue(context, string);
1143 }
1144} CYCatch }
1145
1146static JSValueRef Type_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1147 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1148 CYPool pool;
1149 const char *type(sig::Unparse(pool, internal->type_));
1150 return CYCastJSValue(context, CYJSString(type));
1151} CYCatch }
1152
1153static JSValueRef Type_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1154 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1155 CYPool pool;
1156 const char *type(sig::Unparse(pool, internal->type_));
1157 size_t size(strlen(type));
1158 char *cyon(new(pool) char[12 + size + 1]);
1159 memcpy(cyon, "new Type(\"", 10);
1160 cyon[12 + size] = '\0';
1161 cyon[12 + size - 2] = '"';
1162 cyon[12 + size - 1] = ')';
1163 memcpy(cyon + 10, type, size);
1164 return CYCastJSValue(context, CYJSString(cyon));
1165} CYCatch }
1166
1167static JSValueRef Type_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1168 return Type_callAsFunction_toString(context, object, _this, count, arguments, exception);
1169}
1170
1171static JSStaticFunction Pointer_staticFunctions[4] = {
1172 {"toCYON", &Pointer_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1173 {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1174 {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1175 {NULL, NULL, 0}
1176};
1177
1178static JSStaticFunction Struct_staticFunctions[2] = {
1179 {"$cya", &Struct_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1180 {NULL, NULL, 0}
1181};
1182
1183static JSStaticFunction Functor_staticFunctions[4] = {
1184 {"toCYON", &CYValue_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1185 {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1186 {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1187 {NULL, NULL, 0}
1188};
1189
1190namespace cy {
1191 JSStaticFunction const * const Functor::StaticFunctions = Functor_staticFunctions;
1192}
1193
1194static JSStaticFunction Type_staticFunctions[4] = {
1195 {"toCYON", &Type_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1196 {"toJSON", &Type_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1197 {"toString", &Type_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1198 {NULL, NULL, 0}
1199};
1200
1201static JSObjectRef (*JSObjectMakeArray$)(JSContextRef, size_t, const JSValueRef[], JSValueRef *);
1202
1203void CYSetArgs(int argc, const char *argv[]) {
1204 JSContextRef context(CYGetJSContext());
1205 JSValueRef args[argc];
1206 for (int i(0); i != argc; ++i)
1207 args[i] = CYCastJSValue(context, argv[i]);
1208
1209 JSObjectRef array;
1210 if (JSObjectMakeArray$ != NULL) {
1211 JSValueRef exception(NULL);
1212 array = (*JSObjectMakeArray$)(context, argc, args, &exception);
1213 CYThrow(context, exception);
1214 } else {
1215 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
1216 JSValueRef value(CYCallAsFunction(context, Array, NULL, argc, args));
1217 array = CYCastJSObject(context, value);
1218 }
1219
1220 JSObjectRef System(CYGetCachedObject(context, CYJSString("System")));
1221 CYSetProperty(context, System, CYJSString("args"), array);
1222}
1223
1224JSObjectRef CYGetGlobalObject(JSContextRef context) {
1225 return JSContextGetGlobalObject(context);
1226}
1227
1228const char *CYExecute(apr_pool_t *pool, const char *code) {
1229 JSContextRef context(CYGetJSContext());
1230 JSValueRef exception(NULL), result;
1231
1232 void *handle;
1233 if (hooks_ != NULL && hooks_->ExecuteStart != NULL)
1234 handle = (*hooks_->ExecuteStart)(context);
1235 else
1236 handle = NULL;
1237
1238 const char *json;
1239
1240 try {
1241 result = JSEvaluateScript(context, CYJSString(code), NULL, NULL, 0, &exception);
1242 } catch (const char *error) {
1243 return error;
1244 }
1245
1246 if (exception != NULL) { error:
1247 result = exception;
1248 exception = NULL;
1249 }
1250
1251 if (JSValueIsUndefined(context, result))
1252 return NULL;
1253
1254 try {
1255 json = CYPoolCCYON(pool, context, result, &exception);
1256 } catch (const char *error) {
1257 return error;
1258 }
1259
1260 if (exception != NULL)
1261 goto error;
1262
1263 CYSetProperty(context, CYGetGlobalObject(context), Result_, result);
1264
1265 if (hooks_ != NULL && hooks_->ExecuteEnd != NULL)
1266 (*hooks_->ExecuteEnd)(context, handle);
1267 return json;
1268}
1269
1270extern "C" void CydgetSetupContext(JSGlobalContextRef context) {
1271 CYSetupContext(context);
1272}
1273
09eee478
JF
1274static bool initialized_ = false;
1275
9cad30fa 1276void CYInitializeDynamic() {
09eee478
JF
1277 if (!initialized_)
1278 initialized_ = true;
1279 else return;
1280
9cad30fa
JF
1281 CYInitializeStatic();
1282
1283 _sqlcall(sqlite3_open("/usr/lib/libcycript.db", &Bridge_));
1284
1285 JSObjectMakeArray$ = reinterpret_cast<JSObjectRef (*)(JSContextRef, size_t, const JSValueRef[], JSValueRef *)>(dlsym(RTLD_DEFAULT, "JSObjectMakeArray"));
1286
1287 JSClassDefinition definition;
1288
1289 definition = kJSClassDefinitionEmpty;
1290 definition.className = "All";
1291 definition.getProperty = &All_getProperty;
1292 All_ = JSClassCreate(&definition);
1293
1294 definition = kJSClassDefinitionEmpty;
1295 definition.className = "Context";
1296 definition.finalize = &CYFinalize;
1297 Context_ = JSClassCreate(&definition);
1298
1299 definition = kJSClassDefinitionEmpty;
1300 definition.className = "Functor";
1301 definition.staticFunctions = cy::Functor::StaticFunctions;
1302 definition.callAsFunction = &Functor_callAsFunction;
1303 definition.finalize = &CYFinalize;
1304 Functor_ = JSClassCreate(&definition);
1305
1306 definition = kJSClassDefinitionEmpty;
1307 definition.className = "Pointer";
1308 definition.staticFunctions = Pointer_staticFunctions;
1309 definition.getProperty = &Pointer_getProperty;
1310 definition.setProperty = &Pointer_setProperty;
1311 definition.finalize = &CYFinalize;
1312 Pointer_ = JSClassCreate(&definition);
1313
1314 definition = kJSClassDefinitionEmpty;
1315 definition.className = "Struct";
1316 definition.staticFunctions = Struct_staticFunctions;
1317 definition.getProperty = &Struct_getProperty;
1318 definition.setProperty = &Struct_setProperty;
1319 definition.getPropertyNames = &Struct_getPropertyNames;
1320 definition.finalize = &CYFinalize;
1321 Struct_ = JSClassCreate(&definition);
1322
1323 definition = kJSClassDefinitionEmpty;
1324 definition.className = "Type";
1325 definition.staticFunctions = Type_staticFunctions;
1326 definition.getProperty = &Type_getProperty;
1327 definition.callAsFunction = &Type_callAsFunction;
1328 definition.callAsConstructor = &Type_callAsConstructor;
1329 definition.finalize = &CYFinalize;
1330 Type_privateData::Class_ = JSClassCreate(&definition);
1331
1332 definition = kJSClassDefinitionEmpty;
1333 //definition.getProperty = &Global_getProperty;
1334 Global_ = JSClassCreate(&definition);
1335
1336 Array_s = JSStringCreateWithUTF8CString("Array");
1337 cy_s = JSStringCreateWithUTF8CString("$cy");
1338 length_s = JSStringCreateWithUTF8CString("length");
1339 message_s = JSStringCreateWithUTF8CString("message");
1340 name_s = JSStringCreateWithUTF8CString("name");
1341 pop_s = JSStringCreateWithUTF8CString("pop");
1342 prototype_s = JSStringCreateWithUTF8CString("prototype");
1343 push_s = JSStringCreateWithUTF8CString("push");
1344 splice_s = JSStringCreateWithUTF8CString("splice");
1345 toCYON_s = JSStringCreateWithUTF8CString("toCYON");
1346 toJSON_s = JSStringCreateWithUTF8CString("toJSON");
1347
1348 Result_ = JSStringCreateWithUTF8CString("_");
1349
1350 if (hooks_ != NULL && hooks_->Initialize != NULL)
1351 (*hooks_->Initialize)();
1352}
1353
1354void CYThrow(JSContextRef context, JSValueRef value) {
1355 if (value != NULL)
1356 throw CYJSError(context, value);
1357}
1358
1359const char *CYJSError::PoolCString(apr_pool_t *pool) const {
1360 // XXX: this used to be CYPoolCString
1361 return CYPoolCCYON(pool, context_, value_);
1362}
1363
1364JSValueRef CYJSError::CastJSValue(JSContextRef context) const {
1365 // XXX: what if the context is different?
1366 return value_;
1367}
1368
1369JSValueRef CYCastJSError(JSContextRef context, const char *message) {
1370 JSObjectRef Error(CYGetCachedObject(context, CYJSString("Error")));
1371
1372 JSValueRef arguments[1] = {CYCastJSValue(context, message)};
1373
1374 JSValueRef exception(NULL);
1375 JSValueRef value(JSObjectCallAsConstructor(context, Error, 1, arguments, &exception));
1376 CYThrow(context, exception);
1377
1378 return value;
1379}
1380
1381JSValueRef CYPoolError::CastJSValue(JSContextRef context) const {
1382 return CYCastJSError(context, message_);
1383}
1384
1385CYJSError::CYJSError(JSContextRef context, const char *format, ...) {
1386 _assert(context != NULL);
1387
1388 CYPool pool;
1389
1390 va_list args;
1391 va_start(args, format);
1392 const char *message(apr_pvsprintf(pool, format, args));
1393 va_end(args);
1394
1395 value_ = CYCastJSError(context, message);
1396}
1397
1398JSGlobalContextRef CYGetJSContext(JSContextRef context) {
1399 return reinterpret_cast<Context *>(JSObjectGetPrivate(CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s))))->context_;
1400}
1401
1402extern "C" void CYSetupContext(JSGlobalContextRef context) {
1403 CYInitializeDynamic();
1404
1405 JSObjectRef global(CYGetGlobalObject(context));
1406
1407 JSObjectRef cy(JSObjectMake(context, Context_, new Context(context)));
1408 CYSetProperty(context, global, cy_s, cy, kJSPropertyAttributeDontEnum);
1409
1410/* Cache Globals {{{ */
1411 JSObjectRef Array(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array"))));
1412 CYSetProperty(context, cy, CYJSString("Array"), Array);
1413
1414 JSObjectRef Array_prototype(CYCastJSObject(context, CYGetProperty(context, Array, prototype_s)));
1415 CYSetProperty(context, cy, CYJSString("Array_prototype"), Array_prototype);
1416
1417 JSObjectRef Error(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Error"))));
1418 CYSetProperty(context, cy, CYJSString("Error"), Error);
1419
1420 JSObjectRef Function(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function"))));
1421 CYSetProperty(context, cy, CYJSString("Function"), Function);
1422
1423 JSObjectRef Function_prototype(CYCastJSObject(context, CYGetProperty(context, Function, prototype_s)));
1424 CYSetProperty(context, cy, CYJSString("Function_prototype"), Function_prototype);
1425
1426 JSObjectRef Object(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Object"))));
1427 CYSetProperty(context, cy, CYJSString("Object"), Object);
1428
1429 JSObjectRef Object_prototype(CYCastJSObject(context, CYGetProperty(context, Object, prototype_s)));
1430 CYSetProperty(context, cy, CYJSString("Object_prototype"), Object_prototype);
1431
1432 JSObjectRef String(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("String"))));
1433 CYSetProperty(context, cy, CYJSString("String"), String);
1434/* }}} */
1435
1436 CYSetProperty(context, Array_prototype, toCYON_s, &Array_callAsFunction_toCYON, kJSPropertyAttributeDontEnum);
1437
1438 JSObjectRef cycript(JSObjectMake(context, NULL, NULL));
1439 CYSetProperty(context, global, CYJSString("Cycript"), cycript);
1440 CYSetProperty(context, cycript, CYJSString("gc"), &Cycript_gc_callAsFunction);
1441
1442 JSObjectRef Functor(JSObjectMakeConstructor(context, Functor_, &Functor_new));
1443 JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Functor, prototype_s)), Function_prototype);
1444 CYSetProperty(context, cycript, CYJSString("Functor"), Functor);
1445
1446 CYSetProperty(context, cycript, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new));
1447 CYSetProperty(context, cycript, CYJSString("Type"), JSObjectMakeConstructor(context, Type_privateData::Class_, &Type_new));
1448
1449 JSObjectRef all(JSObjectMake(context, All_, NULL));
1450 CYSetProperty(context, cycript, CYJSString("all"), all);
1451
1452 JSObjectRef last(NULL), curr(global);
1453
1454 goto next; for (JSValueRef next;;) {
1455 if (JSValueIsNull(context, next))
1456 break;
1457 last = curr;
1458 curr = CYCastJSObject(context, next);
1459 next:
1460 next = JSObjectGetPrototype(context, curr);
1461 }
1462
1463 JSObjectSetPrototype(context, last, all);
1464
1465 CYSetProperty(context, global, CYJSString("$cyq"), &$cyq);
1466
1467 JSObjectRef System(JSObjectMake(context, NULL, NULL));
1468 CYSetProperty(context, cy, CYJSString("System"), Function);
1469
1470 CYSetProperty(context, global, CYJSString("system"), System);
1471 CYSetProperty(context, System, CYJSString("args"), CYJSNull(context));
1472 //CYSetProperty(context, System, CYJSString("global"), global);
1473 CYSetProperty(context, System, CYJSString("print"), &System_print);
1474
1475 if (hooks_ != NULL && hooks_->SetupContext != NULL)
1476 (*hooks_->SetupContext)(context);
1477}
1478
1479JSGlobalContextRef CYGetJSContext() {
1480 CYInitializeDynamic();
1481
1482 static JSGlobalContextRef context_;
1483
1484 if (context_ == NULL) {
1485 context_ = JSGlobalContextCreate(Global_);
1486 CYSetupContext(context_);
1487 }
1488
1489 return context_;
1490}