1 /* Cycript - Inlining/Optimizing JavaScript Compiler 
   2  * Copyright (C) 2009  Jay Freeman (saurik) 
   5 /* Modified BSD License {{{ */ 
   7  *        Redistribution and use in source and binary 
   8  * forms, with or without modification, are permitted 
   9  * provided that the following conditions are met: 
  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 
  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. 
  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. 
  42 #include "Internal.hpp" 
  47 #include "cycript.hpp" 
  49 #include "sig/parse.hpp" 
  50 #include "sig/ffi_type.hpp" 
  52 #include "Pooling.hpp" 
  57 #include <ext/stdio_filebuf.h> 
  65 #include "Cycript.tab.hh" 
  68 #include "JavaScript.hpp" 
  73     catch (NSException *error) { \ 
  74         CYThrow(context, error, exception); \ 
  81 char *sqlite3_column_pooled(apr_pool_t 
*pool
, sqlite3_stmt 
*stmt
, int n
) { 
  82     if (const unsigned char *value 
= sqlite3_column_text(stmt
, n
)) 
  83         return apr_pstrdup(pool
, (const char *) value
); 
  87 struct CYHooks 
*hooks_
; 
  90 template <typename Type_
> 
  91 _finline 
size_t iconv_(size_t (*iconv
)(iconv_t
, Type_
, size_t *, char **, size_t *), iconv_t cd
, char **inbuf
, size_t *inbytesleft
, char **outbuf
, size_t *outbytesleft
) { 
  92     return iconv(cd
, const_cast<Type_
>(inbuf
), inbytesleft
, outbuf
, outbytesleft
); 
  96 #define UCS_2_INTERNAL "UCS-2" 
  98 #define UCS_2_INTERNAL "UCS-2-INTERNAL" 
 101 CYUTF8String 
CYPoolUTF8String(apr_pool_t 
*pool
, CYUTF16String utf16
) { 
 102     _assert(pool 
!= NULL
); 
 104     const char *in(reinterpret_cast<const char *>(utf16
.data
)); 
 106     iconv_t 
conversion(_syscall(iconv_open("UTF-8", UCS_2_INTERNAL
))); 
 108     // XXX: this is wrong 
 109     size_t size(utf16
.size 
* 5); 
 110     char *out(new(pool
) char[size
]); 
 111     CYUTF8String 
utf8(out
, size
); 
 113     size 
= utf16
.size 
* 2; 
 114     _syscall(iconv_(&iconv
, conversion
, const_cast<char **>(&in
), &size
, &out
, &utf8
.size
)); 
 117     utf8
.size 
= out 
- utf8
.data
; 
 119     _syscall(iconv_close(conversion
)); 
 124 CYUTF16String 
CYPoolUTF16String(apr_pool_t 
*pool
, CYUTF8String utf8
) { 
 125     _assert(pool 
!= NULL
); 
 127     const char *in(utf8
.data
); 
 129     iconv_t 
conversion(_syscall(iconv_open(UCS_2_INTERNAL
, "UTF-8"))); 
 131     // XXX: this is wrong 
 132     size_t size(utf8
.size 
* 5); 
 133     uint16_t *temp(new (pool
) uint16_t[size
]); 
 134     CYUTF16String 
utf16(temp
, size 
* 2); 
 135     char *out(reinterpret_cast<char *>(temp
)); 
 138     _syscall(iconv_(&iconv
, conversion
, const_cast<char **>(&in
), &size
, &out
, &utf16
.size
)); 
 140     utf16
.size 
= reinterpret_cast<uint16_t *>(out
) - utf16
.data
; 
 141     temp
[utf16
.size
] = 0; 
 143     _syscall(iconv_close(conversion
)); 
 148 /* JavaScript Properties {{{ */ 
 149 JSValueRef 
CYGetProperty(JSContextRef context
, JSObjectRef object
, size_t index
) { 
 150     JSValueRef 
exception(NULL
); 
 151     JSValueRef 
value(JSObjectGetPropertyAtIndex(context
, object
, index
, &exception
)); 
 152     CYThrow(context
, exception
); 
 156 JSValueRef 
CYGetProperty(JSContextRef context
, JSObjectRef object
, JSStringRef name
) { 
 157     JSValueRef 
exception(NULL
); 
 158     JSValueRef 
value(JSObjectGetProperty(context
, object
, name
, &exception
)); 
 159     CYThrow(context
, exception
); 
 163 void CYSetProperty(JSContextRef context
, JSObjectRef object
, size_t index
, JSValueRef value
) { 
 164     JSValueRef 
exception(NULL
); 
 165     JSObjectSetPropertyAtIndex(context
, object
, index
, value
, &exception
); 
 166     CYThrow(context
, exception
); 
 169 void CYSetProperty(JSContextRef context
, JSObjectRef object
, JSStringRef name
, JSValueRef value
, JSPropertyAttributes attributes
) { 
 170     JSValueRef 
exception(NULL
); 
 171     JSObjectSetProperty(context
, object
, name
, value
, attributes
, &exception
); 
 172     CYThrow(context
, exception
); 
 175 void CYSetProperty(JSContextRef context
, JSObjectRef object
, JSStringRef name
, JSValueRef (*callback
)(JSContextRef
, JSObjectRef
, JSObjectRef
, size_t, const JSValueRef
[], JSValueRef 
*), JSPropertyAttributes attributes
) { 
 176     CYSetProperty(context
, object
, name
, JSObjectMakeFunctionWithCallback(context
, name
, callback
), attributes
); 
 179 /* JavaScript Strings {{{ */ 
 180 JSStringRef 
CYCopyJSString(const char *value
) { 
 181     return value 
== NULL 
? NULL 
: JSStringCreateWithUTF8CString(value
); 
 184 JSStringRef 
CYCopyJSString(JSStringRef value
) { 
 185     return value 
== NULL 
? NULL 
: JSStringRetain(value
); 
 188 JSStringRef 
CYCopyJSString(CYUTF8String value
) { 
 189     // XXX: this is very wrong; it needs to convert to UTF16 and then create from there 
 190     return CYCopyJSString(value
.data
); 
 193 JSStringRef 
CYCopyJSString(JSContextRef context
, JSValueRef value
) { 
 194     if (JSValueIsNull(context
, value
)) 
 196     JSValueRef 
exception(NULL
); 
 197     JSStringRef 
string(JSValueToStringCopy(context
, value
, &exception
)); 
 198     CYThrow(context
, exception
); 
 202 static CYUTF16String 
CYCastUTF16String(JSStringRef value
) { 
 203     return CYUTF16String(JSStringGetCharactersPtr(value
), JSStringGetLength(value
)); 
 206 CYUTF8String 
CYPoolUTF8String(apr_pool_t 
*pool
, JSContextRef context
, JSStringRef value
) { 
 207     return CYPoolUTF8String(pool
, CYCastUTF16String(value
)); 
 210 const char *CYPoolCString(apr_pool_t 
*pool
, JSContextRef context
, JSStringRef value
) { 
 211     CYUTF8String 
utf8(CYPoolUTF8String(pool
, context
, value
)); 
 212     _assert(memchr(utf8
.data
, '\0', utf8
.size
) == NULL
); 
 216 const char *CYPoolCString(apr_pool_t 
*pool
, JSContextRef context
, JSValueRef value
) { 
 217     return JSValueIsNull(context
, value
) ? NULL 
: CYPoolCString(pool
, context
, CYJSString(context
, value
)); 
 221 /* Index Offsets {{{ */ 
 222 size_t CYGetIndex(const CYUTF8String 
&value
) { 
 223     if (value
.data
[0] != '0') { 
 225         for (size_t i(0); i 
!= value
.size
; ++i
) { 
 226             if (!DigitRange_
[value
.data
[i
]]) 
 229             index 
+= value
.data
[i
] - '0'; 
 232     } else if (value
.size 
== 1) 
 238 size_t CYGetIndex(apr_pool_t 
*pool
, JSContextRef context
, JSStringRef value
) { 
 239     return CYGetIndex(CYPoolUTF8String(pool
, context
, value
)); 
 242 // XXX: this isn't actually right 
 243 bool CYGetOffset(const char *value
, ssize_t 
&index
) { 
 244     if (value
[0] != '0') { 
 246         index 
= strtol(value
, &end
, 10); 
 247         if (value 
+ strlen(value
) == end
) 
 249     } else if (value
[1] == '\0') { 
 258 /* JavaScript *ify {{{ */ 
 259 void CYStringify(std::ostringstream 
&str
, const char *data
, size_t size
) { 
 260     unsigned quot(0), apos(0); 
 261     for (const char *value(data
), *end(data 
+ size
); value 
!= end
; ++value
) 
 264         else if (*value 
== '\'') 
 267     bool single(quot 
> apos
); 
 269     str 
<< (single 
? '\'' : '"'); 
 271     for (const char *value(data
), *end(data 
+ size
); value 
!= end
; ++value
) 
 273             case '\\': str 
<< "\\\\"; break; 
 274             case '\b': str 
<< "\\b"; break; 
 275             case '\f': str 
<< "\\f"; break; 
 276             case '\n': str 
<< "\\n"; break; 
 277             case '\r': str 
<< "\\r"; break; 
 278             case '\t': str 
<< "\\t"; break; 
 279             case '\v': str 
<< "\\v"; break; 
 294                 // this test is designed to be "awesome", generating neither warnings nor incorrect results 
 295                 if (*value 
< 0x20 || *value 
>= 0x7f) 
 296                     str 
<< "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(uint8_t(*value
)); 
 301     str 
<< (single 
? '\'' : '"'); 
 304 void CYNumerify(std::ostringstream 
&str
, double value
) { 
 306     // XXX: I want this to print 1e3 rather than 1000 
 307     sprintf(string
, "%.17g", value
); 
 311 bool CYIsKey(CYUTF8String value
) { 
 312     const char *data(value
.data
); 
 313     size_t size(value
.size
); 
 318     if (DigitRange_
[data
[0]]) { 
 319         size_t index(CYGetIndex(value
)); 
 320         if (index 
== _not(size_t)) 
 323         if (!WordStartRange_
[data
[0]]) 
 325         for (size_t i(1); i 
!= size
; ++i
) 
 326             if (!WordEndRange_
[data
[i
]]) 
 334 static JSClassRef All_
; 
 335 static JSClassRef Context_
; 
 336 static JSClassRef Functor_
; 
 337 static JSClassRef Global_
; 
 338 static JSClassRef Pointer_
; 
 339 static JSClassRef Struct_
; 
 343 JSStringRef length_s
; 
 344 JSStringRef message_s
; 
 347 JSStringRef prototype_s
; 
 349 JSStringRef splice_s
; 
 350 JSStringRef toCYON_s
; 
 351 JSStringRef toJSON_s
; 
 353 static JSStringRef Result_
; 
 357 void CYFinalize(JSObjectRef object
) { 
 358     delete reinterpret_cast<CYData 
*>(JSObjectGetPrivate(object
)); 
 361 struct CStringMapLess 
: 
 362     std::binary_function
<const char *, const char *, bool> 
 364     _finline 
bool operator ()(const char *lhs
, const char *rhs
) const { 
 365         return strcmp(lhs
, rhs
) < 0; 
 369 void Structor_(apr_pool_t 
*pool
, sig::Type 
*&type
) { 
 371         type
->primitive 
== sig::pointer_P 
&& 
 372         type
->data
.data
.type 
!= NULL 
&& 
 373         type
->data
.data
.type
->primitive 
== sig::struct_P 
&& 
 374         strcmp(type
->data
.data
.type
->name
, "_objc_class") == 0 
 376         type
->primitive 
= sig::typename_P
; 
 377         type
->data
.data
.type 
= NULL
; 
 381     if (type
->primitive 
!= sig::struct_P 
|| type
->name 
== NULL
) 
 384     sqlite3_stmt 
*statement
; 
 386     _sqlcall(sqlite3_prepare(Bridge_
, 
 388             "\"bridge\".\"mode\", " 
 389             "\"bridge\".\"value\" " 
 392             " \"bridge\".\"mode\" in (3, 4) and" 
 393             " \"bridge\".\"name\" = ?" 
 395     , -1, &statement
, NULL
)); 
 397     _sqlcall(sqlite3_bind_text(statement
, 1, type
->name
, -1, SQLITE_STATIC
)); 
 402     if (_sqlcall(sqlite3_step(statement
)) == SQLITE_DONE
) { 
 406         mode 
= sqlite3_column_int(statement
, 0); 
 407         value 
= sqlite3_column_pooled(pool
, statement
, 1); 
 410     _sqlcall(sqlite3_finalize(statement
)); 
 419             sig::Parse(pool
, &type
->data
.signature
, value
, &Structor_
); 
 423             sig::Signature signature
; 
 424             sig::Parse(pool
, &signature
, value
, &Structor_
); 
 425             type 
= signature
.elements
[0].type
; 
 430 JSClassRef 
Type_privateData::Class_
; 
 435     JSGlobalContextRef context_
; 
 437     Context(JSGlobalContextRef context
) : 
 446     Type_privateData 
*type_
; 
 449     Pointer(void *value
, JSContextRef context
, JSObjectRef owner
, size_t length
, sig::Type 
*type
) : 
 450         CYOwned(value
, context
, owner
), 
 451         type_(new(pool_
) Type_privateData(type
)), 
 457 struct Struct_privateData 
: 
 460     Type_privateData 
*type_
; 
 462     Struct_privateData(JSContextRef context
, JSObjectRef owner
) : 
 463         CYOwned(NULL
, context
, owner
) 
 468 typedef std::map
<const char *, Type_privateData 
*, CStringMapLess
> TypeMap
; 
 469 static TypeMap Types_
; 
 471 JSObjectRef 
CYMakeStruct(JSContextRef context
, void *data
, sig::Type 
*type
, ffi_type 
*ffi
, JSObjectRef owner
) { 
 472     Struct_privateData 
*internal(new Struct_privateData(context
, owner
)); 
 473     apr_pool_t 
*pool(internal
->pool_
); 
 474     Type_privateData 
*typical(new(pool
) Type_privateData(type
, ffi
)); 
 475     internal
->type_ 
= typical
; 
 478         internal
->value_ 
= data
; 
 480         size_t size(typical
->GetFFI()->size
); 
 481         void *copy(apr_palloc(internal
->pool_
, size
)); 
 482         memcpy(copy
, data
, size
); 
 483         internal
->value_ 
= copy
; 
 486     return JSObjectMake(context
, Struct_
, internal
); 
 489 JSValueRef 
CYCastJSValue(JSContextRef context
, bool value
) { 
 490     return JSValueMakeBoolean(context
, value
); 
 493 JSValueRef 
CYCastJSValue(JSContextRef context
, double value
) { 
 494     return JSValueMakeNumber(context
, value
); 
 497 #define CYCastJSValue_(Type_) \ 
 498     JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \ 
 499         return JSValueMakeNumber(context, static_cast<double>(value)); \ 
 503 CYCastJSValue_(unsigned int) 
 504 CYCastJSValue_(long int) 
 505 CYCastJSValue_(long unsigned int) 
 506 CYCastJSValue_(long long int) 
 507 CYCastJSValue_(long long unsigned int) 
 509 JSValueRef 
CYJSUndefined(JSContextRef context
) { 
 510     return JSValueMakeUndefined(context
); 
 513 double CYCastDouble(const char *value
, size_t size
) { 
 515     double number(strtod(value
, &end
)); 
 516     if (end 
!= value 
+ size
) 
 521 double CYCastDouble(const char *value
) { 
 522     return CYCastDouble(value
, strlen(value
)); 
 525 double CYCastDouble(JSContextRef context
, JSValueRef value
) { 
 526     JSValueRef 
exception(NULL
); 
 527     double number(JSValueToNumber(context
, value
, &exception
)); 
 528     CYThrow(context
, exception
); 
 532 bool CYCastBool(JSContextRef context
, JSValueRef value
) { 
 533     return JSValueToBoolean(context
, value
); 
 536 JSValueRef 
CYJSNull(JSContextRef context
) { 
 537     return JSValueMakeNull(context
); 
 540 JSValueRef 
CYCastJSValue(JSContextRef context
, JSStringRef value
) { 
 541     return value 
== NULL 
? CYJSNull(context
) : JSValueMakeString(context
, value
); 
 544 JSValueRef 
CYCastJSValue(JSContextRef context
, const char *value
) { 
 545     return CYCastJSValue(context
, CYJSString(value
)); 
 548 JSObjectRef 
CYCastJSObject(JSContextRef context
, JSValueRef value
) { 
 549     JSValueRef 
exception(NULL
); 
 550     JSObjectRef 
object(JSValueToObject(context
, value
, &exception
)); 
 551     CYThrow(context
, exception
); 
 555 JSValueRef 
CYCallAsFunction(JSContextRef context
, JSObjectRef function
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[]) { 
 556     JSValueRef 
exception(NULL
); 
 557     JSValueRef 
value(JSObjectCallAsFunction(context
, function
, _this
, count
, arguments
, &exception
)); 
 558     CYThrow(context
, exception
); 
 562 bool CYIsCallable(JSContextRef context
, JSValueRef value
) { 
 563     return value 
!= NULL 
&& JSValueIsObject(context
, value
) && JSObjectIsFunction(context
, (JSObjectRef
) value
); 
 566 static JSValueRef 
System_print(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
 571         printf("%s\n", CYPoolCString(pool
, context
, arguments
[0])); 
 574     return CYJSUndefined(context
); 
 577 static size_t Nonce_(0); 
 579 static JSValueRef $
cyq(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { 
 581     const char *name(apr_psprintf(pool
, "%s%"APR_SIZE_T_FMT
"", CYPoolCString(pool
, context
, arguments
[0]), Nonce_
++)); 
 582     return CYCastJSValue(context
, name
); 
 585 static JSValueRef 
Cycript_gc_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { 
 586     JSGarbageCollect(context
); 
 587     return CYJSUndefined(context
); 
 590 const char *CYPoolCCYON(apr_pool_t 
*pool
, JSContextRef context
, JSValueRef value
, JSValueRef 
*exception
) { CYTry 
{ 
 591     switch (JSType type 
= JSValueGetType(context
, value
)) { 
 592         case kJSTypeUndefined
: 
 597             return CYCastBool(context
, value
) ? "true" : "false"; 
 599         case kJSTypeNumber
: { 
 600             std::ostringstream str
; 
 601             CYNumerify(str
, CYCastDouble(context
, value
)); 
 602             std::string 
value(str
.str()); 
 603             return apr_pstrmemdup(pool
, value
.c_str(), value
.size()); 
 606         case kJSTypeString
: { 
 607             std::ostringstream str
; 
 608             CYUTF8String 
string(CYPoolUTF8String(pool
, context
, CYJSString(context
, value
))); 
 609             CYStringify(str
, string
.data
, string
.size
); 
 610             std::string 
value(str
.str()); 
 611             return apr_pstrmemdup(pool
, value
.c_str(), value
.size()); 
 615             return CYPoolCCYON(pool
, context
, (JSObjectRef
) value
); 
 617             throw CYJSError(context
, "JSValueGetType() == 0x%x", type
); 
 621 const char *CYPoolCCYON(apr_pool_t 
*pool
, JSContextRef context
, JSValueRef value
) { 
 622     JSValueRef 
exception(NULL
); 
 623     const char *cyon(CYPoolCCYON(pool
, context
, value
, &exception
)); 
 624     CYThrow(context
, exception
); 
 628 const char *CYPoolCCYON(apr_pool_t 
*pool
, JSContextRef context
, JSObjectRef object
) { 
 629     JSValueRef 
toCYON(CYGetProperty(context
, object
, toCYON_s
)); 
 630     if (CYIsCallable(context
, toCYON
)) { 
 631         JSValueRef 
value(CYCallAsFunction(context
, (JSObjectRef
) toCYON
, object
, 0, NULL
)); 
 632         _assert(value 
!= NULL
); 
 633         return CYPoolCString(pool
, context
, value
); 
 636     JSValueRef 
toJSON(CYGetProperty(context
, object
, toJSON_s
)); 
 637     if (CYIsCallable(context
, toJSON
)) { 
 638         JSValueRef arguments
[1] = {CYCastJSValue(context
, CYJSString(""))}; 
 639         JSValueRef 
exception(NULL
); 
 640         const char *cyon(CYPoolCCYON(pool
, context
, CYCallAsFunction(context
, (JSObjectRef
) toJSON
, object
, 1, arguments
), &exception
)); 
 641         CYThrow(context
, exception
); 
 645     std::ostringstream str
; 
 649     // XXX: this is, sadly, going to leak 
 650     JSPropertyNameArrayRef 
names(JSObjectCopyPropertyNames(context
, object
)); 
 654     for (size_t index(0), count(JSPropertyNameArrayGetCount(names
)); index 
!= count
; ++index
) { 
 655         JSStringRef 
name(JSPropertyNameArrayGetNameAtIndex(names
, index
)); 
 656         JSValueRef 
value(CYGetProperty(context
, object
, name
)); 
 663         CYUTF8String 
string(CYPoolUTF8String(pool
, context
, name
)); 
 667             CYStringify(str
, string
.data
, string
.size
); 
 669         str 
<< ':' << CYPoolCCYON(pool
, context
, value
); 
 674     JSPropertyNameArrayRelease(names
); 
 676     std::string 
string(str
.str()); 
 677     return apr_pstrmemdup(pool
, string
.c_str(), string
.size()); 
 680 static JSValueRef 
Array_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
 682     std::ostringstream str
; 
 686     JSValueRef 
length(CYGetProperty(context
, _this
, length_s
)); 
 689     for (size_t index(0), count(CYCastDouble(context
, length
)); index 
!= count
; ++index
) { 
 690         JSValueRef 
value(CYGetProperty(context
, _this
, index
)); 
 697         if (!JSValueIsUndefined(context
, value
)) 
 698             str 
<< CYPoolCCYON(pool
, context
, value
); 
 707     std::string 
value(str
.str()); 
 708     return CYCastJSValue(context
, CYJSString(CYUTF8String(value
.c_str(), value
.size()))); 
 711 JSObjectRef 
CYMakePointer(JSContextRef context
, void *pointer
, size_t length
, sig::Type 
*type
, ffi_type 
*ffi
, JSObjectRef owner
) { 
 712     Pointer 
*internal(new Pointer(pointer
, context
, owner
, length
, type
)); 
 713     return JSObjectMake(context
, Pointer_
, internal
); 
 716 static JSObjectRef 
CYMakeFunctor(JSContextRef context
, void (*function
)(), const char *type
) { 
 717     cy::Functor 
*internal(new cy::Functor(type
, function
)); 
 718     return JSObjectMake(context
, Functor_
, internal
); 
 721 static bool CYGetOffset(apr_pool_t 
*pool
, JSContextRef context
, JSStringRef value
, ssize_t 
&index
) { 
 722     return CYGetOffset(CYPoolCString(pool
, context
, value
), index
); 
 725 void *CYCastPointer_(JSContextRef context
, JSValueRef value
) { 
 726     switch (JSValueGetType(context
, value
)) { 
 729         /*case kJSTypeObject: 
 730             if (JSValueIsObjectOfClass(context, value, Pointer_)) { 
 731                 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate((JSObjectRef) value))); 
 732                 return internal->value_; 
 735             double number(CYCastDouble(context
, value
)); 
 736             if (std::isnan(number
)) 
 737                 throw CYJSError(context
, "cannot convert value to pointer"); 
 738             return reinterpret_cast<void *>(static_cast<uintptr_t>(static_cast<long long>(number
))); 
 742 void CYPoolFFI(apr_pool_t 
*pool
, JSContextRef context
, sig::Type 
*type
, ffi_type 
*ffi
, void *data
, JSValueRef value
) { 
 743     switch (type
->primitive
) { 
 745             *reinterpret_cast<bool *>(data
) = JSValueToBoolean(context
, value
); 
 748 #define CYPoolFFI_(primitive, native) \ 
 749         case sig::primitive ## _P: \ 
 750             *reinterpret_cast<native *>(data) = CYCastDouble(context, value); \ 
 753         CYPoolFFI_(uchar
, unsigned char) 
 754         CYPoolFFI_(char, char) 
 755         CYPoolFFI_(ushort
, unsigned short) 
 756         CYPoolFFI_(short, short) 
 757         CYPoolFFI_(ulong
, unsigned long) 
 758         CYPoolFFI_(long, long) 
 759         CYPoolFFI_(uint
, unsigned int) 
 761         CYPoolFFI_(ulonglong
, unsigned long long) 
 762         CYPoolFFI_(longlong
, long long) 
 763         CYPoolFFI_(float, float) 
 764         CYPoolFFI_(double, double) 
 767             uint8_t *base(reinterpret_cast<uint8_t *>(data
)); 
 768             JSObjectRef 
aggregate(JSValueIsObject(context
, value
) ? (JSObjectRef
) value 
: NULL
); 
 769             for (size_t index(0); index 
!= type
->data
.data
.size
; ++index
) { 
 770                 ffi_type 
*field(ffi
->elements
[index
]); 
 773                 if (aggregate 
== NULL
) 
 776                     rhs 
= CYGetProperty(context
, aggregate
, index
); 
 777                     if (JSValueIsUndefined(context
, rhs
)) 
 778                         throw CYJSError(context
, "unable to extract array value"); 
 781                 CYPoolFFI(pool
, context
, type
->data
.data
.type
, field
, base
, rhs
); 
 788             *reinterpret_cast<void **>(data
) = CYCastPointer
<void *>(context
, value
); 
 792             *reinterpret_cast<const char **>(data
) = CYPoolCString(pool
, context
, value
); 
 795         case sig::struct_P
: { 
 796             uint8_t *base(reinterpret_cast<uint8_t *>(data
)); 
 797             JSObjectRef 
aggregate(JSValueIsObject(context
, value
) ? (JSObjectRef
) value 
: NULL
); 
 798             for (size_t index(0); index 
!= type
->data
.signature
.count
; ++index
) { 
 799                 sig::Element 
*element(&type
->data
.signature
.elements
[index
]); 
 800                 ffi_type 
*field(ffi
->elements
[index
]); 
 803                 if (aggregate 
== NULL
) 
 806                     rhs 
= CYGetProperty(context
, aggregate
, index
); 
 807                     if (JSValueIsUndefined(context
, rhs
)) { 
 808                         if (element
->name 
!= NULL
) 
 809                             rhs 
= CYGetProperty(context
, aggregate
, CYJSString(element
->name
)); 
 812                         if (JSValueIsUndefined(context
, rhs
)) undefined
: 
 813                             throw CYJSError(context
, "unable to extract structure value"); 
 817                 CYPoolFFI(pool
, context
, element
->type
, field
, base
, rhs
); 
 827             if (hooks_ 
!= NULL 
&& hooks_
->PoolFFI 
!= NULL
) 
 828                 if ((*hooks_
->PoolFFI
)(pool
, context
, type
, ffi
, data
, value
)) 
 831             CYThrow("unimplemented signature code: '%c''\n", type
->primitive
); 
 835 JSValueRef 
CYFromFFI(JSContextRef context
, sig::Type 
*type
, ffi_type 
*ffi
, void *data
, bool initialize
, JSObjectRef owner
) { 
 836     switch (type
->primitive
) { 
 838             return CYCastJSValue(context
, *reinterpret_cast<bool *>(data
)); 
 840 #define CYFromFFI_(primitive, native) \ 
 841         case sig::primitive ## _P: \ 
 842             return CYCastJSValue(context, *reinterpret_cast<native *>(data)); \ 
 844         CYFromFFI_(uchar, unsigned char) 
 845         CYFromFFI_(char, char) 
 846         CYFromFFI_(ushort
, unsigned short) 
 847         CYFromFFI_(short, short) 
 848         CYFromFFI_(ulong
, unsigned long) 
 849         CYFromFFI_(long, long) 
 850         CYFromFFI_(uint
, unsigned int) 
 852         CYFromFFI_(ulonglong
, unsigned long long) 
 853         CYFromFFI_(longlong
, long long) 
 854         CYFromFFI_(float, float) 
 855         CYFromFFI_(double, double) 
 858             if (void *pointer 
= data
) 
 859                 return CYMakePointer(context
, pointer
, type
->data
.data
.size
, type
->data
.data
.type
, NULL
, owner
); 
 863             if (void *pointer 
= *reinterpret_cast<void **>(data
)) 
 864                 return CYMakePointer(context
, pointer
, _not(size_t), type
->data
.data
.type
, NULL
, owner
); 
 868             if (char *utf8 
= *reinterpret_cast<char **>(data
)) 
 869                 return CYCastJSValue(context
, utf8
); 
 873             return CYMakeStruct(context
, data
, type
, ffi
, owner
); 
 875             return CYJSUndefined(context
); 
 878             return CYJSNull(context
); 
 880             if (hooks_ 
!= NULL 
&& hooks_
->FromFFI 
!= NULL
) 
 881                 if (JSValueRef value 
= (*hooks_
->FromFFI
)(context
, type
, ffi
, data
, initialize
, owner
)) 
 884             CYThrow("unimplemented signature code: '%c''\n", type
->primitive
); 
 888 static void FunctionClosure_(ffi_cif 
*cif
, void *result
, void **arguments
, void *arg
) { 
 889     Closure_privateData 
*internal(reinterpret_cast<Closure_privateData 
*>(arg
)); 
 891     JSContextRef 
context(internal
->context_
); 
 893     size_t count(internal
->cif_
.nargs
); 
 894     JSValueRef values
[count
]; 
 896     for (size_t index(0); index 
!= count
; ++index
) 
 897         values
[index
] = CYFromFFI(context
, internal
->signature_
.elements
[1 + index
].type
, internal
->cif_
.arg_types
[index
], arguments
[index
]); 
 899     JSValueRef 
value(CYCallAsFunction(context
, internal
->function_
, NULL
, count
, values
)); 
 900     CYPoolFFI(NULL
, context
, internal
->signature_
.elements
[0].type
, internal
->cif_
.rtype
, result
, value
); 
 903 Closure_privateData 
*CYMakeFunctor_(JSContextRef context
, JSObjectRef function
, const char *type
, void (*callback
)(ffi_cif 
*, void *, void **, void *)) { 
 904     // XXX: in case of exceptions this will leak 
 905     // XXX: in point of fact, this may /need/ to leak :( 
 906     Closure_privateData 
*internal(new Closure_privateData(context
, function
, type
)); 
 908     ffi_closure 
*closure((ffi_closure 
*) _syscall(mmap( 
 909         NULL
, sizeof(ffi_closure
), 
 910         PROT_READ 
| PROT_WRITE
, MAP_ANON 
| MAP_PRIVATE
, 
 914     ffi_status 
status(ffi_prep_closure(closure
, &internal
->cif_
, callback
, internal
)); 
 915     _assert(status 
== FFI_OK
); 
 917     _syscall(mprotect(closure
, sizeof(*closure
), PROT_READ 
| PROT_EXEC
)); 
 919     internal
->value_ 
= closure
; 
 924 static JSObjectRef 
CYMakeFunctor(JSContextRef context
, JSObjectRef function
, const char *type
) { 
 925     Closure_privateData 
*internal(CYMakeFunctor_(context
, function
, type
, &FunctionClosure_
)); 
 926     JSObjectRef 
object(JSObjectMake(context
, Functor_
, internal
)); 
 927     // XXX: see above notes about needing to leak 
 928     JSValueProtect(CYGetJSContext(context
), object
); 
 932 JSObjectRef 
CYGetCachedObject(JSContextRef context
, JSStringRef name
) { 
 933     return CYCastJSObject(context
, CYGetProperty(context
, CYCastJSObject(context
, CYGetProperty(context
, CYGetGlobalObject(context
), cy_s
)), name
)); 
 936 static JSObjectRef 
CYMakeFunctor(JSContextRef context
, JSValueRef value
, const char *type
) { 
 937     JSObjectRef 
Function(CYGetCachedObject(context
, CYJSString("Function"))); 
 939     JSValueRef 
exception(NULL
); 
 940     bool function(JSValueIsInstanceOfConstructor(context
, value
, Function
, &exception
)); 
 941     CYThrow(context
, exception
); 
 944         JSObjectRef 
function(CYCastJSObject(context
, value
)); 
 945         return CYMakeFunctor(context
, function
, type
); 
 947         void (*function
)()(CYCastPointer
<void (*)()>(context
, value
)); 
 948         return CYMakeFunctor(context
, function
, type
); 
 952 static bool Index_(apr_pool_t 
*pool
, JSContextRef context
, Struct_privateData 
*internal
, JSStringRef property
, ssize_t 
&index
, uint8_t *&base
) { 
 953     Type_privateData 
*typical(internal
->type_
); 
 954     sig::Type 
*type(typical
->type_
); 
 958     const char *name(CYPoolCString(pool
, context
, property
)); 
 959     size_t length(strlen(name
)); 
 960     double number(CYCastDouble(name
, length
)); 
 962     size_t count(type
->data
.signature
.count
); 
 964     if (std::isnan(number
)) { 
 965         if (property 
== NULL
) 
 968         sig::Element 
*elements(type
->data
.signature
.elements
); 
 970         for (size_t local(0); local 
!= count
; ++local
) { 
 971             sig::Element 
*element(&elements
[local
]); 
 972             if (element
->name 
!= NULL 
&& strcmp(name
, element
->name
) == 0) { 
 980         index 
= static_cast<ssize_t
>(number
); 
 981         if (index 
!= number 
|| index 
< 0 || static_cast<size_t>(index
) >= count
) 
 986     ffi_type 
**elements(typical
->GetFFI()->elements
); 
 988     base 
= reinterpret_cast<uint8_t *>(internal
->value_
); 
 989     for (ssize_t 
local(0); local 
!= index
; ++local
) 
 990         base 
+= elements
[local
]->size
; 
 995 static JSValueRef 
Pointer_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef 
*exception
) { CYTry 
{ 
 997     Pointer 
*internal(reinterpret_cast<Pointer 
*>(JSObjectGetPrivate(object
))); 
 999     if (JSStringIsEqual(property
, length_s
)) 
1000         return internal
->length_ 
== _not(size_t) ? CYJSUndefined(context
) : CYCastJSValue(context
, internal
->length_
); 
1002     Type_privateData 
*typical(internal
->type_
); 
1004     if (typical
->type_ 
== NULL
) 
1008     if (JSStringIsEqualToUTF8CString(property
, "$cyi")) 
1010     else if (!CYGetOffset(pool
, context
, property
, offset
)) 
1013     ffi_type 
*ffi(typical
->GetFFI()); 
1015     uint8_t *base(reinterpret_cast<uint8_t *>(internal
->value_
)); 
1016     base 
+= ffi
->size 
* offset
; 
1018     JSObjectRef 
owner(internal
->GetOwner() ?: object
); 
1019     return CYFromFFI(context
, typical
->type_
, ffi
, base
, false, owner
); 
1022 static bool Pointer_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef value
, JSValueRef 
*exception
) { CYTry 
{ 
1024     Pointer 
*internal(reinterpret_cast<Pointer 
*>(JSObjectGetPrivate(object
))); 
1025     Type_privateData 
*typical(internal
->type_
); 
1027     if (typical
->type_ 
== NULL
) 
1031     if (JSStringIsEqualToUTF8CString(property
, "$cyi")) 
1033     else if (!CYGetOffset(pool
, context
, property
, offset
)) 
1036     ffi_type 
*ffi(typical
->GetFFI()); 
1038     uint8_t *base(reinterpret_cast<uint8_t *>(internal
->value_
)); 
1039     base 
+= ffi
->size 
* offset
; 
1041     CYPoolFFI(NULL
, context
, typical
->type_
, ffi
, base
, value
); 
1045 static JSValueRef Struct_callAsFunction_$
cya(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { 
1046     Struct_privateData 
*internal(reinterpret_cast<Struct_privateData 
*>(JSObjectGetPrivate(_this
))); 
1047     Type_privateData 
*typical(internal
->type_
); 
1048     return CYMakePointer(context
, internal
->value_
, _not(size_t), typical
->type_
, typical
->ffi_
, _this
); 
1051 static JSValueRef 
Struct_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef 
*exception
) { CYTry 
{ 
1053     Struct_privateData 
*internal(reinterpret_cast<Struct_privateData 
*>(JSObjectGetPrivate(object
))); 
1054     Type_privateData 
*typical(internal
->type_
); 
1059     if (!Index_(pool
, context
, internal
, property
, index
, base
)) 
1062     JSObjectRef 
owner(internal
->GetOwner() ?: object
); 
1064     return CYFromFFI(context
, typical
->type_
->data
.signature
.elements
[index
].type
, typical
->GetFFI()->elements
[index
], base
, false, owner
); 
1067 static bool Struct_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef value
, JSValueRef 
*exception
) { CYTry 
{ 
1069     Struct_privateData 
*internal(reinterpret_cast<Struct_privateData 
*>(JSObjectGetPrivate(object
))); 
1070     Type_privateData 
*typical(internal
->type_
); 
1075     if (!Index_(pool
, context
, internal
, property
, index
, base
)) 
1078     CYPoolFFI(NULL
, context
, typical
->type_
->data
.signature
.elements
[index
].type
, typical
->GetFFI()->elements
[index
], base
, value
); 
1082 static void Struct_getPropertyNames(JSContextRef context
, JSObjectRef object
, JSPropertyNameAccumulatorRef names
) { 
1083     Struct_privateData 
*internal(reinterpret_cast<Struct_privateData 
*>(JSObjectGetPrivate(object
))); 
1084     Type_privateData 
*typical(internal
->type_
); 
1085     sig::Type 
*type(typical
->type_
); 
1090     size_t count(type
->data
.signature
.count
); 
1091     sig::Element 
*elements(type
->data
.signature
.elements
); 
1095     for (size_t index(0); index 
!= count
; ++index
) { 
1097         name 
= elements
[index
].name
; 
1100             sprintf(number
, "%zu", index
); 
1104         JSPropertyNameAccumulatorAddName(names
, CYJSString(name
)); 
1108 JSValueRef 
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 
{ 
1109     if (setups 
+ count 
!= signature
->count 
- 1) 
1110         throw CYJSError(context
, "incorrect number of arguments to ffi function"); 
1112     size_t size(setups 
+ count
); 
1114     memcpy(values
, setup
, sizeof(void *) * setups
); 
1116     for (size_t index(setups
); index 
!= size
; ++index
) { 
1117         sig::Element 
*element(&signature
->elements
[index 
+ 1]); 
1118         ffi_type 
*ffi(cif
->arg_types
[index
]); 
1120         values
[index
] = new(pool
) uint8_t[ffi
->size
]; 
1121         CYPoolFFI(pool
, context
, element
->type
, ffi
, values
[index
], arguments
[index 
- setups
]); 
1124     uint8_t value
[cif
->rtype
->size
]; 
1126     if (hooks_ 
!= NULL 
&& hooks_
->CallFunction 
!= NULL
) 
1127         (*hooks_
->CallFunction
)(context
, cif
, function
, value
, values
); 
1129         ffi_call(cif
, function
, value
, values
); 
1131     return CYFromFFI(context
, signature
->elements
[0].type
, cif
->rtype
, value
, initialize
); 
1134 static JSValueRef 
Functor_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { 
1136     cy::Functor 
*internal(reinterpret_cast<cy::Functor 
*>(JSObjectGetPrivate(object
))); 
1137     return CYCallFunction(pool
, context
, 0, NULL
, count
, arguments
, false, exception
, &internal
->signature_
, &internal
->cif_
, internal
->GetValue()); 
1140 static JSObjectRef 
CYMakeType(JSContextRef context
, const char *type
) { 
1141     Type_privateData 
*internal(new Type_privateData(type
)); 
1142     return JSObjectMake(context
, Type_privateData::Class_
, internal
); 
1145 static JSObjectRef 
CYMakeType(JSContextRef context
, sig::Type 
*type
) { 
1146     Type_privateData 
*internal(new Type_privateData(type
)); 
1147     return JSObjectMake(context
, Type_privateData::Class_
, internal
); 
1150 static void *CYCastSymbol(const char *name
) { 
1151     return dlsym(RTLD_DEFAULT
, name
); 
1154 static JSValueRef 
All_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef 
*exception
) { CYTry 
{ 
1155     JSObjectRef 
global(CYGetGlobalObject(context
)); 
1156     JSObjectRef 
cycript(CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Cycript")))); 
1157     if (JSValueRef value 
= CYGetProperty(context
, cycript
, property
)) 
1158         if (!JSValueIsUndefined(context
, value
)) 
1162     CYUTF8String 
name(CYPoolUTF8String(pool
, context
, property
)); 
1164     if (hooks_ 
!= NULL 
&& hooks_
->RuntimeProperty 
!= NULL
) 
1165         if (JSValueRef value 
= (*hooks_
->RuntimeProperty
)(context
, name
)) 
1168     sqlite3_stmt 
*statement
; 
1170     _sqlcall(sqlite3_prepare(Bridge_
, 
1172             "\"bridge\".\"mode\", " 
1173             "\"bridge\".\"value\" " 
1176             " \"bridge\".\"name\" = ?" 
1178     , -1, &statement
, NULL
)); 
1180     _sqlcall(sqlite3_bind_text(statement
, 1, name
.data
, name
.size
, SQLITE_STATIC
)); 
1185     if (_sqlcall(sqlite3_step(statement
)) == SQLITE_DONE
) { 
1189         mode 
= sqlite3_column_int(statement
, 0); 
1190         value 
= sqlite3_column_pooled(pool
, statement
, 1); 
1193     _sqlcall(sqlite3_finalize(statement
)); 
1197             CYThrow("invalid mode from bridge table: %d", mode
); 
1202             return JSEvaluateScript(CYGetJSContext(context
), CYJSString(value
), NULL
, NULL
, 0, NULL
); 
1205             if (void (*symbol
)() = reinterpret_cast<void (*)()>(CYCastSymbol(name
.data
))) 
1206                 return CYMakeFunctor(context
, symbol
, value
); 
1210             if (void *symbol 
= CYCastSymbol(name
.data
)) { 
1211                 // XXX: this is horrendously inefficient 
1212                 sig::Signature signature
; 
1213                 sig::Parse(pool
, &signature
, value
, &Structor_
); 
1215                 sig::sig_ffi_cif(pool
, &sig::ObjectiveC
, &signature
, &cif
); 
1216                 return CYFromFFI(context
, signature
.elements
[0].type
, cif
.rtype
, symbol
); 
1219         // XXX: implement case 3 
1221             return CYMakeType(context
, value
); 
1225 static JSObjectRef 
Pointer_new(JSContextRef context
, JSObjectRef object
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1227         throw CYJSError(context
, "incorrect number of arguments to Functor constructor"); 
1231     void *value(CYCastPointer
<void *>(context
, arguments
[0])); 
1232     const char *type(CYPoolCString(pool
, context
, arguments
[1])); 
1234     sig::Signature signature
; 
1235     sig::Parse(pool
, &signature
, type
, &Structor_
); 
1237     return CYMakePointer(context
, value
, _not(size_t), signature
.elements
[0].type
, NULL
, NULL
); 
1240 static JSObjectRef 
Type_new(JSContextRef context
, JSObjectRef object
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1242         throw CYJSError(context
, "incorrect number of arguments to Type constructor"); 
1244     const char *type(CYPoolCString(pool
, context
, arguments
[0])); 
1245     return CYMakeType(context
, type
); 
1248 static JSValueRef 
Type_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef 
*exception
) { CYTry 
{ 
1249     Type_privateData 
*internal(reinterpret_cast<Type_privateData 
*>(JSObjectGetPrivate(object
))); 
1253     if (JSStringIsEqualToUTF8CString(property
, "$cyi")) { 
1254         type
.primitive 
= sig::pointer_P
; 
1255         type
.data
.data
.size 
= 0; 
1258         size_t index(CYGetIndex(pool
, context
, property
)); 
1259         if (index 
== _not(size_t)) 
1261         type
.primitive 
= sig::array_P
; 
1262         type
.data
.data
.size 
= index
; 
1268     type
.data
.data
.type 
= internal
->type_
; 
1270     return CYMakeType(context
, &type
); 
1273 static JSValueRef 
Type_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1274     Type_privateData 
*internal(reinterpret_cast<Type_privateData 
*>(JSObjectGetPrivate(object
))); 
1277         throw CYJSError(context
, "incorrect number of arguments to type cast function"); 
1278     sig::Type 
*type(internal
->type_
); 
1279     ffi_type 
*ffi(internal
->GetFFI()); 
1281     uint8_t value
[ffi
->size
]; 
1283     CYPoolFFI(pool
, context
, type
, ffi
, value
, arguments
[0]); 
1284     return CYFromFFI(context
, type
, ffi
, value
); 
1287 static JSObjectRef 
Type_callAsConstructor(JSContextRef context
, JSObjectRef object
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1289         throw CYJSError(context
, "incorrect number of arguments to type cast function"); 
1290     Type_privateData 
*internal(reinterpret_cast<Type_privateData 
*>(JSObjectGetPrivate(object
))); 
1292     sig::Type 
*type(internal
->type_
); 
1295     if (type
->primitive 
!= sig::array_P
) 
1296         length 
= _not(size_t); 
1298         length 
= type
->data
.data
.size
; 
1299         type 
= type
->data
.data
.type
; 
1302     void *value(malloc(internal
->GetFFI()->size
)); 
1303     return CYMakePointer(context
, value
, length
, type
, NULL
, NULL
); 
1306 static JSObjectRef 
Functor_new(JSContextRef context
, JSObjectRef object
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1308         throw CYJSError(context
, "incorrect number of arguments to Functor constructor"); 
1310     const char *type(CYPoolCString(pool
, context
, arguments
[1])); 
1311     return CYMakeFunctor(context
, arguments
[0], type
); 
1314 static JSValueRef 
CYValue_callAsFunction_valueOf(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1315     CYValue 
*internal(reinterpret_cast<CYValue 
*>(JSObjectGetPrivate(_this
))); 
1316     return CYCastJSValue(context
, reinterpret_cast<uintptr_t>(internal
->value_
)); 
1319 static JSValueRef 
CYValue_callAsFunction_toJSON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { 
1320     return CYValue_callAsFunction_valueOf(context
, object
, _this
, count
, arguments
, exception
); 
1323 static JSValueRef 
CYValue_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1324     CYValue 
*internal(reinterpret_cast<CYValue 
*>(JSObjectGetPrivate(_this
))); 
1326     sprintf(string
, "%p", internal
->value_
); 
1327     return CYCastJSValue(context
, string
); 
1330 static JSValueRef 
Pointer_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1331     Pointer 
*internal(reinterpret_cast<Pointer 
*>(JSObjectGetPrivate(_this
))); 
1332     if (internal
->length_ 
!= _not(size_t)) { 
1333         JSObjectRef 
Array(CYGetCachedObject(context
, Array_s
)); 
1334         JSObjectRef 
toCYON(CYCastJSObject(context
, CYGetProperty(context
, Array
, toCYON_s
))); 
1335         return CYCallAsFunction(context
, toCYON
, _this
, count
, arguments
); 
1338         sprintf(string
, "%p", internal
->value_
); 
1339         return CYCastJSValue(context
, string
); 
1343 static JSValueRef 
Type_callAsFunction_toString(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1344     Type_privateData 
*internal(reinterpret_cast<Type_privateData 
*>(JSObjectGetPrivate(_this
))); 
1346     const char *type(sig::Unparse(pool
, internal
->type_
)); 
1347     return CYCastJSValue(context
, CYJSString(type
)); 
1350 static JSValueRef 
Type_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { CYTry 
{ 
1351     Type_privateData 
*internal(reinterpret_cast<Type_privateData 
*>(JSObjectGetPrivate(_this
))); 
1353     const char *type(sig::Unparse(pool
, internal
->type_
)); 
1354     size_t size(strlen(type
)); 
1355     char *cyon(new(pool
) char[12 + size 
+ 1]); 
1356     memcpy(cyon
, "new Type(\"", 10); 
1357     cyon
[12 + size
] = '\0'; 
1358     cyon
[12 + size 
- 2] = '"'; 
1359     cyon
[12 + size 
- 1] = ')'; 
1360     memcpy(cyon 
+ 10, type
, size
); 
1361     return CYCastJSValue(context
, CYJSString(cyon
)); 
1364 static JSValueRef 
Type_callAsFunction_toJSON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef 
*exception
) { 
1365     return Type_callAsFunction_toString(context
, object
, _this
, count
, arguments
, exception
); 
1368 static JSStaticFunction Pointer_staticFunctions
[4] = { 
1369     {"toCYON", &Pointer_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1370     {"toJSON", &CYValue_callAsFunction_toJSON
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1371     {"valueOf", &CYValue_callAsFunction_valueOf
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1375 static JSStaticFunction Struct_staticFunctions
[2] = { 
1376     {"$cya", &Struct_callAsFunction_$cya
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1380 static JSStaticFunction Functor_staticFunctions
[4] = { 
1381     {"toCYON", &CYValue_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1382     {"toJSON", &CYValue_callAsFunction_toJSON
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1383     {"valueOf", &CYValue_callAsFunction_valueOf
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1388     JSStaticFunction 
const * const Functor::StaticFunctions 
= Functor_staticFunctions
; 
1391 static JSStaticFunction Type_staticFunctions
[4] = { 
1392     {"toCYON", &Type_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1393     {"toJSON", &Type_callAsFunction_toJSON
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1394     {"toString", &Type_callAsFunction_toString
, kJSPropertyAttributeDontEnum 
| kJSPropertyAttributeDontDelete
}, 
1398 static JSObjectRef (*JSObjectMakeArray$
)(JSContextRef
, size_t, const JSValueRef
[], JSValueRef 
*); 
1400 void CYSetArgs(int argc
, const char *argv
[]) { 
1401     JSContextRef 
context(CYGetJSContext()); 
1402     JSValueRef args
[argc
]; 
1403     for (int i(0); i 
!= argc
; ++i
) 
1404         args
[i
] = CYCastJSValue(context
, argv
[i
]); 
1407     if (JSObjectMakeArray$ 
!= NULL
) { 
1408         JSValueRef 
exception(NULL
); 
1409         array 
= (*JSObjectMakeArray$
)(context
, argc
, args
, &exception
); 
1410         CYThrow(context
, exception
); 
1412         JSObjectRef 
Array(CYGetCachedObject(context
, CYJSString("Array"))); 
1413         JSValueRef 
value(CYCallAsFunction(context
, Array
, NULL
, argc
, args
)); 
1414         array 
= CYCastJSObject(context
, value
); 
1417     JSObjectRef 
System(CYGetCachedObject(context
, CYJSString("System"))); 
1418     CYSetProperty(context
, System
, CYJSString("args"), array
); 
1421 JSObjectRef 
CYGetGlobalObject(JSContextRef context
) { 
1422     return JSContextGetGlobalObject(context
); 
1425 const char *CYExecute(apr_pool_t 
*pool
, const char *code
) { 
1426     JSContextRef 
context(CYGetJSContext()); 
1427     JSValueRef 
exception(NULL
), result
; 
1430     if (hooks_ 
!= NULL 
&& hooks_
->ExecuteStart 
!= NULL
) 
1431         handle 
= (*hooks_
->ExecuteStart
)(context
); 
1438         result 
= JSEvaluateScript(context
, CYJSString(code
), NULL
, NULL
, 0, &exception
); 
1439     } catch (const char *error
) { 
1443     if (exception 
!= NULL
) { error
: 
1448     if (JSValueIsUndefined(context
, result
)) 
1452         json 
= CYPoolCCYON(pool
, context
, result
, &exception
); 
1453     } catch (const char *error
) { 
1457     if (exception 
!= NULL
) 
1460     CYSetProperty(context
, CYGetGlobalObject(context
), Result_
, result
); 
1462     if (hooks_ 
!= NULL 
&& hooks_
->ExecuteEnd 
!= NULL
) 
1463         (*hooks_
->ExecuteEnd
)(context
, handle
); 
1467 extern "C" void CydgetSetupContext(JSGlobalContextRef context
) { 
1468     CYSetupContext(context
); 
1471 extern "C" void CydgetPoolParse(apr_pool_t 
*pool
, const uint16_t **data
, size_t *size
) { 
1472     CYDriver 
driver(""); 
1473     cy::parser 
parser(driver
); 
1475     CYUTF8String 
utf8(CYPoolUTF8String(pool
, CYUTF16String(*data
, *size
))); 
1477     driver
.data_ 
= utf8
.data
; 
1478     driver
.size_ 
= utf8
.size
; 
1480     if (parser
.parse() != 0 || !driver
.errors_
.empty()) 
1483     CYContext 
context(driver
.pool_
); 
1484     driver
.program_
->Replace(context
); 
1485     std::ostringstream str
; 
1487     out 
<< *driver
.program_
; 
1488     std::string 
code(str
.str()); 
1490     CYUTF16String 
utf16(CYPoolUTF16String(pool
, CYUTF8String(code
.c_str(), code
.size()))); 
1496 static apr_pool_t 
*Pool_
; 
1498 static bool initialized_
; 
1500 void CYInitialize() { 
1502         initialized_ 
= true; 
1505     _aprcall(apr_initialize()); 
1506     _aprcall(apr_pool_create(&Pool_
, NULL
)); 
1507     _sqlcall(sqlite3_open("/usr/lib/libcycript.db", &Bridge_
)); 
1509     JSObjectMakeArray$ 
= reinterpret_cast<JSObjectRef (*)(JSContextRef
, size_t, const JSValueRef
[], JSValueRef 
*)>(dlsym(RTLD_DEFAULT
, "JSObjectMakeArray")); 
1511     JSClassDefinition definition
; 
1513     definition 
= kJSClassDefinitionEmpty
; 
1514     definition
.className 
= "All"; 
1515     definition
.getProperty 
= &All_getProperty
; 
1516     All_ 
= JSClassCreate(&definition
); 
1518     definition 
= kJSClassDefinitionEmpty
; 
1519     definition
.className 
= "Context"; 
1520     definition
.finalize 
= &CYFinalize
; 
1521     Context_ 
= JSClassCreate(&definition
); 
1523     definition 
= kJSClassDefinitionEmpty
; 
1524     definition
.className 
= "Functor"; 
1525     definition
.staticFunctions 
= cy::Functor::StaticFunctions
; 
1526     definition
.callAsFunction 
= &Functor_callAsFunction
; 
1527     definition
.finalize 
= &CYFinalize
; 
1528     Functor_ 
= JSClassCreate(&definition
); 
1530     definition 
= kJSClassDefinitionEmpty
; 
1531     definition
.className 
= "Pointer"; 
1532     definition
.staticFunctions 
= Pointer_staticFunctions
; 
1533     definition
.getProperty 
= &Pointer_getProperty
; 
1534     definition
.setProperty 
= &Pointer_setProperty
; 
1535     definition
.finalize 
= &CYFinalize
; 
1536     Pointer_ 
= JSClassCreate(&definition
); 
1538     definition 
= kJSClassDefinitionEmpty
; 
1539     definition
.className 
= "Struct"; 
1540     definition
.staticFunctions 
= Struct_staticFunctions
; 
1541     definition
.getProperty 
= &Struct_getProperty
; 
1542     definition
.setProperty 
= &Struct_setProperty
; 
1543     definition
.getPropertyNames 
= &Struct_getPropertyNames
; 
1544     definition
.finalize 
= &CYFinalize
; 
1545     Struct_ 
= JSClassCreate(&definition
); 
1547     definition 
= kJSClassDefinitionEmpty
; 
1548     definition
.className 
= "Type"; 
1549     definition
.staticFunctions 
= Type_staticFunctions
; 
1550     definition
.getProperty 
= &Type_getProperty
; 
1551     definition
.callAsFunction 
= &Type_callAsFunction
; 
1552     definition
.callAsConstructor 
= &Type_callAsConstructor
; 
1553     definition
.finalize 
= &CYFinalize
; 
1554     Type_privateData::Class_ 
= JSClassCreate(&definition
); 
1556     definition 
= kJSClassDefinitionEmpty
; 
1557     //definition.getProperty = &Global_getProperty; 
1558     Global_ 
= JSClassCreate(&definition
); 
1560     Array_s 
= JSStringCreateWithUTF8CString("Array"); 
1561     cy_s 
= JSStringCreateWithUTF8CString("$cy"); 
1562     length_s 
= JSStringCreateWithUTF8CString("length"); 
1563     message_s 
= JSStringCreateWithUTF8CString("message"); 
1564     name_s 
= JSStringCreateWithUTF8CString("name"); 
1565     pop_s 
= JSStringCreateWithUTF8CString("pop"); 
1566     prototype_s 
= JSStringCreateWithUTF8CString("prototype"); 
1567     push_s 
= JSStringCreateWithUTF8CString("push"); 
1568     splice_s 
= JSStringCreateWithUTF8CString("splice"); 
1569     toCYON_s 
= JSStringCreateWithUTF8CString("toCYON"); 
1570     toJSON_s 
= JSStringCreateWithUTF8CString("toJSON"); 
1572     Result_ 
= JSStringCreateWithUTF8CString("_"); 
1574     if (hooks_ 
!= NULL 
&& hooks_
->Initialize 
!= NULL
) 
1575         (*hooks_
->Initialize
)(); 
1578 apr_pool_t 
*CYGetGlobalPool() { 
1583 void CYThrow(JSContextRef context
, JSValueRef value
) { 
1585         throw CYJSError(context
, value
); 
1588 const char *CYJSError::PoolCString(apr_pool_t 
*pool
) const { 
1589     // XXX: this used to be CYPoolCString 
1590     return CYPoolCCYON(pool
, context_
, value_
); 
1593 JSValueRef 
CYJSError::CastJSValue(JSContextRef context
) const { 
1594     // XXX: what if the context is different? 
1598 void CYThrow(const char *format
, ...) { 
1600     va_start(args
, format
); 
1601     throw CYPoolError(format
, args
); 
1602     // XXX: does this matter? :( 
1606 const char *CYPoolError::PoolCString(apr_pool_t 
*pool
) const { 
1607     return apr_pstrdup(pool
, message_
); 
1610 CYPoolError::CYPoolError(const char *format
, ...) { 
1612     va_start(args
, format
); 
1613     message_ 
= apr_pvsprintf(pool_
, format
, args
); 
1617 CYPoolError::CYPoolError(const char *format
, va_list args
) { 
1618     message_ 
= apr_pvsprintf(pool_
, format
, args
); 
1621 JSValueRef 
CYCastJSError(JSContextRef context
, const char *message
) { 
1622     JSObjectRef 
Error(CYGetCachedObject(context
, CYJSString("Error"))); 
1624     JSValueRef arguments
[1] = {CYCastJSValue(context
, message
)}; 
1626     JSValueRef 
exception(NULL
); 
1627     JSValueRef 
value(JSObjectCallAsConstructor(context
, Error
, 1, arguments
, &exception
)); 
1628     CYThrow(context
, exception
); 
1633 JSValueRef 
CYPoolError::CastJSValue(JSContextRef context
) const { 
1634     return CYCastJSError(context
, message_
); 
1637 CYJSError::CYJSError(JSContextRef context
, const char *format
, ...) { 
1638     _assert(context 
!= NULL
); 
1643     va_start(args
, format
); 
1644     const char *message(apr_pvsprintf(pool
, format
, args
)); 
1647     value_ 
= CYCastJSError(context
, message
); 
1650 JSGlobalContextRef 
CYGetJSContext(JSContextRef context
) { 
1651     return reinterpret_cast<Context 
*>(JSObjectGetPrivate(CYCastJSObject(context
, CYGetProperty(context
, CYGetGlobalObject(context
), cy_s
))))->context_
; 
1654 extern "C" void CYSetupContext(JSGlobalContextRef context
) { 
1657     JSObjectRef 
global(CYGetGlobalObject(context
)); 
1659     JSObjectRef 
cy(JSObjectMake(context
, Context_
, new Context(context
))); 
1660     CYSetProperty(context
, global
, cy_s
, cy
, kJSPropertyAttributeDontEnum
); 
1662 /* Cache Globals {{{ */ 
1663     JSObjectRef 
Array(CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Array")))); 
1664     CYSetProperty(context
, cy
, CYJSString("Array"), Array
); 
1666     JSObjectRef 
Array_prototype(CYCastJSObject(context
, CYGetProperty(context
, Array
, prototype_s
))); 
1667     CYSetProperty(context
, cy
, CYJSString("Array_prototype"), Array_prototype
); 
1669     JSObjectRef 
Error(CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Error")))); 
1670     CYSetProperty(context
, cy
, CYJSString("Error"), Error
); 
1672     JSObjectRef 
Function(CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Function")))); 
1673     CYSetProperty(context
, cy
, CYJSString("Function"), Function
); 
1675     JSObjectRef 
Function_prototype(CYCastJSObject(context
, CYGetProperty(context
, Function
, prototype_s
))); 
1676     CYSetProperty(context
, cy
, CYJSString("Function_prototype"), Function_prototype
); 
1678     JSObjectRef 
Object(CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Object")))); 
1679     CYSetProperty(context
, cy
, CYJSString("Object"), Object
); 
1681     JSObjectRef 
Object_prototype(CYCastJSObject(context
, CYGetProperty(context
, Object
, prototype_s
))); 
1682     CYSetProperty(context
, cy
, CYJSString("Object_prototype"), Object_prototype
); 
1684     JSObjectRef 
String(CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("String")))); 
1685     CYSetProperty(context
, cy
, CYJSString("String"), String
); 
1688     CYSetProperty(context
, Array_prototype
, toCYON_s
, &Array_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum
); 
1690     JSObjectRef 
cycript(JSObjectMake(context
, NULL
, NULL
)); 
1691     CYSetProperty(context
, global
, CYJSString("Cycript"), cycript
); 
1692     CYSetProperty(context
, cycript
, CYJSString("gc"), &Cycript_gc_callAsFunction
); 
1694     JSObjectRef 
Functor(JSObjectMakeConstructor(context
, Functor_
, &Functor_new
)); 
1695     JSObjectSetPrototype(context
, CYCastJSObject(context
, CYGetProperty(context
, Functor
, prototype_s
)), Function_prototype
); 
1696     CYSetProperty(context
, cycript
, CYJSString("Functor"), Functor
); 
1698     CYSetProperty(context
, cycript
, CYJSString("Pointer"), JSObjectMakeConstructor(context
, Pointer_
, &Pointer_new
)); 
1699     CYSetProperty(context
, cycript
, CYJSString("Type"), JSObjectMakeConstructor(context
, Type_privateData::Class_
, &Type_new
)); 
1701     JSObjectRef 
all(JSObjectMake(context
, All_
, NULL
)); 
1702     CYSetProperty(context
, cycript
, CYJSString("all"), all
); 
1704     JSObjectRef 
last(NULL
), curr(global
); 
1706     goto next
; for (JSValueRef next
;;) { 
1707         if (JSValueIsNull(context
, next
)) 
1710         curr 
= CYCastJSObject(context
, next
); 
1712         next 
= JSObjectGetPrototype(context
, curr
); 
1715     JSObjectSetPrototype(context
, last
, all
); 
1717     CYSetProperty(context
, global
, CYJSString("$cyq"), &$cyq
); 
1719     JSObjectRef 
System(JSObjectMake(context
, NULL
, NULL
)); 
1720     CYSetProperty(context
, cy
, CYJSString("System"), Function
); 
1722     CYSetProperty(context
, global
, CYJSString("system"), System
); 
1723     CYSetProperty(context
, System
, CYJSString("args"), CYJSNull(context
)); 
1724     //CYSetProperty(context, System, CYJSString("global"), global); 
1725     CYSetProperty(context
, System
, CYJSString("print"), &System_print
); 
1727     if (hooks_ 
!= NULL 
&& hooks_
->SetupContext 
!= NULL
) 
1728         (*hooks_
->SetupContext
)(context
); 
1731 JSGlobalContextRef 
CYGetJSContext() { 
1734     static JSGlobalContextRef context_
; 
1736     if (context_ 
== NULL
) { 
1737         context_ 
= JSGlobalContextCreate(Global_
); 
1738         CYSetupContext(context_
);