From 61933e1667bc5f4853a5bcee425ebc9785a366f0 Mon Sep 17 00:00:00 2001
From: "Jay Freeman (saurik)" <saurik@saurik.com>
Date: Wed, 14 Oct 2009 21:47:37 +0000
Subject: [PATCH] Added a lot of bridge supports, setup for enum and typedef,
 implemented cy object property storage, and slightly improved CYData
 factorization.

---
 Bridge.def    | 244 ++++++++++++++++++++++++++++++++++++++++++--------
 Library.mm    | 235 +++++++++++++++++++++++++++++++-----------------
 makefile      |   4 +-
 sig/parse.cpp |   7 +-
 4 files changed, 365 insertions(+), 125 deletions(-)

diff --git a/Bridge.def b/Bridge.def
index 1022df5..8b2cd2f 100644
--- a/Bridge.def
+++ b/Bridge.def
@@ -4,6 +4,7 @@ C nil null
 
 : applicationDidFinishLaunching: v12@0:4@8
 
+
 S CGPoint "x"f"y"f
 S CGRect "origin"{CGPoint}"size"{CGSize}
 S CGSize "width"f"height"f
@@ -110,12 +111,15 @@ C UIBarStyleDefault 0
 C UIBarStyleBlack 1
 C UIBarStyleBlackOpaque 2
 C UIBarStyleBlackTranslucent 3
+T UIBarStyle i
 
 C UIDataDetectorTypePhoneNumber (1<<0)
 C UIDataDetectorTypeLink (1<<1)
 C UIDataDetectorTypeNone 0
-# XXX: NSUIntegerMax
 C UIDataDetectorTypeAll -1
+T UIDataDetectorTypes {NSUInteger}
+
+S UIEdgeInsets "top"{CGFloat}"left"{CGFloat}"bottom"{CGFloat}"right"{CGFloat}
 
 # UINavigationBar
 
@@ -311,29 +315,29 @@ F UIVideoAtPathIsCompatibleWithSavedPhotosAlbum B@
 F UIGraphicsGetCurrentContext @
 F UIGraphicsPushContext v@
 F UIGraphicsPopContext v
-F UIGraphicsBeginImageContext v{CGSize=ff}
+F UIGraphicsBeginImageContext v{CGSize}
 F UIGraphicsGetImageFromCurrentImageContext @
 F UIGraphicsEndImageContext v
-F UIRectClip v{CGRect={CGPoint=ff}{CGSize=ff}}
-F UIRectFill v{CGRect={CGPoint=ff}{CGSize=ff}}
-F UIRectFillUsingBlendMode v{CGRect={CGPoint=ff}{CGSize=ff}}i
-F UIRectFrame v{CGRect={CGPoint=ff}{CGSize=ff}}
-F UIRectFrameUsingBlendMode v{CGRect={CGPoint=ff}{CGSize=ff}}i
-
-F CGPointFromString {CGPoint=ff}@
-F CGRectFromString  {CGRect={CGPoint=ff}{CGSize=ff}}@
-F CGSizeFromString {CGSize=ff}@
-F CGAffineTransformFromString {CGAffineTransform=ffffff}@
+F UIRectClip v{CGRect}
+F UIRectFill v{CGRect}
+F UIRectFillUsingBlendMode v{CGRect}{CGBlendMode}
+F UIRectFrame v{CGRect}
+F UIRectFrameUsingBlendMode v{CGRect}{CGBlendMode}
+
+F CGPointFromString {CGPoint}@
+F CGRectFromString  {CGRect}@
+F CGSizeFromString {CGSize}@
+F CGAffineTransformFromString {CGAffineTransform}@
 F UIEdgeInsetsFromString {UIEdgeInsets=ffff}@
-F NSStringFromCGPoint @{CGPoint=ff}
-F NSStringFromCGRect @{CGRect={CGPoint=ff}{CGSize=ff}}
-F NSStringFromCGSize @{CGSize=ff}
-F NSStringFromCGAffineTransform @{CGAffineTransform=ffffff}
+F NSStringFromCGPoint @{CGPoint}
+F NSStringFromCGRect @{CGRect}
+F NSStringFromCGSize @{CGSize}
+F NSStringFromCGAffineTransform @{CGAffineTransform}
 F NSStringFromUIEdgeInsets @{UIEdgeInsets=ffff}
 
 F UIEdgeInsetsMake {UIEdgeInsets=ffff}ffff
 F UIEdgeInsetsEqualToEdgeInsets B{UIEdgeInsets=ffff}{UIEdgeInsets=ffff}
-F UIEdgeInsetsInsetRect {CGRect={CGPoint=ff}{CGSize=ff}}{CGRect={CGPoint=ff}{CGSize=ff}}{UIEdgeInsets=ffff}
+F UIEdgeInsetsInsetRect {CGRect}{CGRect}{UIEdgeInsets=ffff}
 
 # XXX: UIInterfaceOrientationIsPortrait
 # XXX: UIInterfaceOrientationIsLandscape
@@ -558,6 +562,26 @@ V kABWorkLabel @
 V kABHomeLabel @
 V kABOtherLabel @
 
+f CoreAnimation
+
+S CATransform3D "m11"{CGFloat}"m12"{CGFloat}"m13"{CGFloat}"m14"{CGFloat}"m21"{CGFloat}"m22"{CGFloat}"m23"{CGFloat}"m24"{CGFloat}"m31"{CGFloat}"m32"{CGFloat}"m33"{CGFloat}"m34"{CGFloat}"m41"{CGFloat}"m42"{CGFloat}"m43"{CGFloat}"m44"{CGFloat}
+
+F CACurrentMediaTime {CFTimeInterval}
+
+F CATransform3DIsIdentity B{CATransform3D}
+F CATransform3DEqualToTransform B{CATransform3D}{CATransform3D}
+F CATransform3DMakeTranslation {CATransform3D}{CGFloat}{CGFloat}{CGFloat}
+F CATransform3DMakeScale {CATransform3D}{CGFloat}{CGFloat}{CGFloat}
+F CATransform3DMakeRotation {CATransform3D}{CGFloat}{CGFloat}{CGFloat}{CGFloat}
+F CATransform3DTranslate {CATransform3D}{CATransform3D}{CGFloat}{CGFloat}{CGFloat}
+F CATransform3DScale {CATransform3D}{CATransform3D}{CGFloat}{CGFloat}{CGFloat}
+F CATransform3DRotate {CATransform3D}{CATransform3D}{CGFloat}{CGFloat}{CGFloat}{CGFloat}
+F CATransform3DConcat {CATransform3D}{CATransform3D}{CATransform3D}
+F CATransform3DInvert {CATransform3D}{CATransform3D}
+F CATransform3DMakeAffineTransform {CATransform3D}{CGAffineTransform}
+F CATransform3DIsAffine B{CATransform3D}
+F CATransform3DGetAffineTransform {CGAffineTransform}{CATransform3D}
+
 f CoreData
 
 C NSUndefinedAttributeType 0
@@ -719,31 +743,111 @@ F CFShowStr v@
 
 f CoreGraphics
 
-# CGAffineTransform
+T CGFloat f
 
-F CGAffineTransformMake {CGAffineTransform=ffffff}ffffff
-F CGAffineTransformMakeRotation {CGAffineTransform=ffffff}f
-F CGAffineTransformMakeScale {CGAffineTransform=ffffff}ff
-F CGAffineTransformMakeTranslation {CGAffineTransform=ffffff}ff
+# CFByteOrderUtils
 
-F CGAffineTransformTranslate {CGAffineTransform=ffffff}{CGAffineTransform=ffffff}ff
-F CGAffineTransformScale {CGAffineTransform=ffffff}{CGAffineTransform=ffffff}ff
-F CGAffineTransformRotate {CGAffineTransform=ffffff}{CGAffineTransform=ffffff}f
-F CGAffineTransformInvert {CGAffineTransform=ffffff}{CGAffineTransform=ffffff}
-F CGAffineTransformConcat {CGAffineTransform=ffffff}{CGAffineTransform=ffffff}{CGAffineTransform=ffffff}
+E __CFByteOrder
+C CFByteOrderUnknown 0
+C CFByteOrderLittleEndian 1
+C CFByteOrderBigEndian 2
+T CFByteOrder __CFByteOrder
 
-F CGPointApplyAffineTransform {CGPoint=ff}{CGPoint=ff}{CGAffineTransform=ffffff}
-F CGSizeApplyAffineTransform {CGSize=ff}{CGSize=ff}{CGAffineTransform=ffffff}
-F CGRectApplyAffineTransform {CGRect={CGPoint=ff}{CGSize=ff}}{CGRect={CGPoint=ff}{CGSize=ff}}{CGAffineTransform=ffffff}
+# CGAffineTransform
+
+F CGAffineTransformMake {CGAffineTransform}{CGFloat}{CGFloat}{CGFloat}{CGFloat}{CGFloat}{CGFloat}
+F CGAffineTransformMakeRotation {CGAffineTransform}{CGFloat}
+F CGAffineTransformMakeScale {CGAffineTransform}{CGFloat}{CGFloat}
+F CGAffineTransformMakeTranslation {CGAffineTransform}{CGFloat}{CGFloat}
+
+F CGAffineTransformTranslate {CGAffineTransform}{CGAffineTransform}{CGFloat}{CGFloat}
+F CGAffineTransformScale {CGAffineTransform}{CGAffineTransform}{CGFloat}{CGFloat}
+F CGAffineTransformRotate {CGAffineTransform}{CGAffineTransform}{CGFloat}
+F CGAffineTransformInvert {CGAffineTransform}{CGAffineTransform}
+F CGAffineTransformConcat {CGAffineTransform}{CGAffineTransform}{CGAffineTransform}
+
+F CGPointApplyAffineTransform {CGPoint}{CGPoint}{CGAffineTransform}
+F CGSizeApplyAffineTransform {CGSize}{CGSize}{CGAffineTransform}
+F CGRectApplyAffineTransform {CGRect}{CGRect}{CGAffineTransform}
+
+F CGAffineTransformIsIdentity B{CGAffineTransform}
+F CGAffineTransformEqualToTransform B{CGAffineTransform}{CGAffineTransform}
+
+S CGAffineTransform "a"{CGFloat}"b"{CGFloat}"c"{CGFloat}"d"{CGFloat}"tx"{CGFloat}"ty"{CGFloat}
+
+V CGAffineTransformIdentity {CGAffineTransform}
+
+# CGContext
+
+T CGContextRef ^{CGContext}
+
+E CGBlendMode
+C kCGBlendModeNormal 0
+C kCGBlendModeMultiply 1
+C kCGBlendModeScreen 2
+C kCGBlendModeOverlay 3
+C kCGBlendModeDarken 4
+C kCGBlendModeLighten 5
+C kCGBlendModeColorDodge 6
+C kCGBlendModeColorBurn 7
+C kCGBlendModeSoftLight 8
+C kCGBlendModeHardLight 9
+C kCGBlendModeDifference 10
+C kCGBlendModeExclusion 11
+C kCGBlendModeHue 12
+C kCGBlendModeSaturation 13
+C kCGBlendModeColor 14
+C kCGBlendModeLuminosity 15
+C kCGBlendModeClear 16
+C kCGBlendModeCopy 17
+C kCGBlendModeSourceIn 18
+C kCGBlendModeSourceOut 19
+C kCGBlendModeSourceAtop 20
+C kCGBlendModeDestinationOver 21
+C kCGBlendModeDestinationIn 22
+C kCGBlendModeDestinationOut 23
+C kCGBlendModeDestinationAtop 24
+C kCGBlendModeXOR 25
+C kCGBlendModePlusDarker 26
+C kCGBlendModePlusLighter 27
+
+E CGInterpolationQuality
+C kCGInterpolationDefault 0
+C kCGInterpolationNone 1
+C kCGInterpolationLow 2
+C kCGInterpolationHigh 3
+
+E CGLineCap
+C kCGLineCapButt 0
+C kCGLineCapRound 1
+C kCGLineCapSquare 2
+
+E CGLineJoin
+C kCGLineJoinMiter 0
+C kCGLineJoinRound 1
+C kCGLineJoinBevel 2
+
+E CGTextDrawingMode
+C kCGTextFill 0
+C kCGTextStroke 1
+C kCGTextFillStroke 2
+C kCGTextInvisible 3
+C kCGTextFillClip 4
+C kCGTextStrokeClip 5
+C kCGTextFillStrokeClip 6
+C kCGTextClip 7
+
+E CGTextEncoding
+C kCGEncodingFontSpecific 0
+C kCGEncodingMacRoman 1
 
-F CGAffineTransformIsIdentity B{CGAffineTransform=ffffff}
-F CGAffineTransformEqualToTransform B{CGAffineTransform=ffffff}{CGAffineTransform=ffffff}
+f CoreLocation
 
-S CGAffineTransform "a"f"b"f"c"f"d"f"tx"f"ty"f
+T CLLocationDegrees d
 
-V CGAffineTransformIdentity {CGAffineTransform=ffffff}
+S CLLocationCoordinate2D "latitude"{CLLocationDegrees}"longitude"{CLLocationDegrees}
 
-f CoreLocation
+T CLLocationAccuracy d
 
 V kCLLocationAccuracyBest d
 V kCLLocationAccuracyNearestTenMeters d
@@ -751,6 +855,9 @@ V kCLLocationAccuracyHundredMeters d
 V kCLLocationAccuracyKilometer d
 V kCLLocationAccuracyThreeKilometers d
 
+T CLLocationSpeed d
+T CLLocationDirection d
+
 V kCLDistanceFilterNone d
 V kCLHeadingFilterNone d
 
@@ -763,13 +870,56 @@ V kCLErrorDomain @
 
 f Foundation
 
-S _NSRange "location"I"length"I
+T NSAppleEventManagerSuspensionID ^r{__NSAppleEventManagerSuspension}
+
+E _NSByteOrder
+C NS_UnknownByteOrder CFByteOrderUnknown
+C NS_LittleEndian CFByteOrderLittleEndian
+C NS_BigEndian CFByteOrderBigEndian
+
+# NSComparator
+
+C NSOrderedAscending -1
+C NSOrderedSame 0
+C NSOrderedDescending 1
+T NSComparisonResult {NSInteger}
+
+# NSDecimal
+
+T NSEnumerationOptions {NSUInteger}
+# NSHashEnumerator
+T NSHashTable {_NSHashTable}
+# NSHashTableCallBacks
+
+T NSHashTableOptions {NSUInteger}
+T NSInteger l
+
+# NSMapEnumerator
+
+T NSMapTable {_NSMapTable}
+# NSMapTableKeyCallBacks
+
+T NSMapTableOptions {NSUInteger}
+# NSMapTableValueCallBacks
+
+T NSPoint {_NSPoint}
+T NSPointArray ^{NSPoint}
+T NSPointPointer ^{NSPoint}
+
+S _NSRange "location"{NSUInteger}"length"{NSUInteger}
+T NSRange {_NSRange}
+T NSRangePointer ^{NSRange}
+
+S _NSRect "origin"{NSPoint}"size"{NSSize}
+T NSRectArray ^{NSRect}
 
 C NSMinXEdge 0
 C NSMinYEdge 1
 C NSMaxXEdge 2
 C NSMaxYEdge 3
 
+T NSRectPointer ^{NSRect}
+
 C NSApplicationDirectory 1
 C NSDemoApplicationDirectory 2
 C NSDeveloperApplicationDirectory 3
@@ -795,12 +945,27 @@ C NSPreferencePanesDirectory 22
 C NSItemReplacementDirectory 99
 C NSAllApplicationsDirectory 100
 C NSAllLibrariesDirectory 101
+T NSSearchPathDirectory {NSUInteger}
 
 C NSUserDomainMask 1
 C NSLocalDomainMask 2
 C NSNetworkDomainMask 4
 C NSSystemDomainMask 8
 C NSAllDomainsMask 0x0ffff
+T NSSearchPathDomainMask {NSUInteger}
+
+S _NSSize "width"{CGFloat}"height"{CGFloat}
+T NSSize {_NSSize}
+
+T NSSizePointer ^{NSSize}
+T NSSocketNativeHandle i
+T NSStringEncoding {NSUInteger}
+S NSSwappedDouble "v"Q
+S NSSwappedFloat "v"L
+T NSTimeInterval d
+# NSUncaughtExceptionHandler
+T NSUInteger L
+T NSZone {_NSZone}
 
 f MapKit
 
@@ -820,7 +985,7 @@ C MKPinAnnotationColorGreen 1
 C MKPinAnnotationColorPurple 2
 
 # MKCoordinateRegionMake
-# MKCoordinateRegionMakeWithDistance
+F MKCoordinateRegionMakeWithDistance {MKCoordinateRegion}{CLLocationCoordinate2D}{CLLocationDistance}{CLLocationDistance}
 # MKCoordinateSpanMake
 
 C RTLD_LAZY 0x1
@@ -836,7 +1001,10 @@ C RTLD_NEXT -1
 C RTLD_DEFAULT -2
 C RTLD_SELF -3
 
-# XXX: dladdr
+S dl_info "dli_fname"*"dli_fbase"v^"dli_sname"*"dli_saddr"^v
+T Dl_info {dl_info}
+
+F dladdr i^rv^{dl_info}
 F dlclose i^v
 F dlerror *
 F dlopen ^v*i
diff --git a/Library.mm b/Library.mm
index e66f581..5d292ae 100644
--- a/Library.mm
+++ b/Library.mm
@@ -123,39 +123,46 @@ static NSArray *Bridge_;
 
 struct CYData {
     apr_pool_t *pool_;
-    void *value_;
-
-    CYData() {
-    }
-
-    CYData(void *value) :
-        value_(value)
-    {
-    }
 
     virtual ~CYData() {
     }
 
-    void *operator new(size_t size) {
+    static void *operator new(size_t size) {
         apr_pool_t *pool;
         apr_pool_create(&pool, NULL);
         void *data(apr_palloc(pool, size));
         reinterpret_cast<CYData *>(data)->pool_ = pool;
-        return data;;
+        return data;
+    }
+
+    static void operator delete(void *data) {
+        apr_pool_destroy(reinterpret_cast<CYData *>(data)->pool_);
     }
 
     static void Finalize(JSObjectRef object) {
-        CYData *data(reinterpret_cast<CYData *>(JSObjectGetPrivate(object)));
-        data->~CYData();
-        apr_pool_destroy(data->pool_);
+        delete reinterpret_cast<CYData *>(JSObjectGetPrivate(object));
     }
 };
 
-struct Selector_privateData :
+struct CYValue :
     CYData
+{
+    void *value_;
+
+    CYValue() {
+    }
+
+    CYValue(void *value) :
+        value_(value)
+    {
+    }
+};
+
+struct Selector_privateData :
+    CYValue
 {
     Selector_privateData(SEL value) :
-        CYData(value)
+        CYValue(value)
     {
     }
 
@@ -165,7 +172,7 @@ struct Selector_privateData :
 };
 
 struct Instance :
-    CYData
+    CYValue
 {
     enum Flags {
         None          = 0,
@@ -176,14 +183,15 @@ struct Instance :
     Flags flags_;
 
     Instance(id value, Flags flags) :
-        CYData(value),
+        CYValue(value),
         flags_(flags)
     {
     }
 
     virtual ~Instance() {
         if ((flags_ & Transient) == 0)
-            [GetValue() release];
+            // XXX: does this handle background threads correctly?
+            [GetValue() performSelector:@selector(release) withObject:nil afterDelay:0];
     }
 
     static JSObjectRef Make(JSContextRef context, id object, Flags flags) {
@@ -320,13 +328,13 @@ struct Type_privateData {
 };
 
 struct Pointer :
-    CYData
+    CYValue
 {
     JSObjectRef owner_;
     Type_privateData *type_;
 
     Pointer(void *value, sig::Type *type, JSObjectRef owner) :
-        CYData(value),
+        CYValue(value),
         owner_(owner),
         type_(new(pool_) Type_privateData(pool_, type))
     {
@@ -334,7 +342,7 @@ struct Pointer :
 };
 
 struct Struct_privateData :
-    CYData
+    CYValue
 {
     JSObjectRef owner_;
     Type_privateData *type_;
@@ -371,25 +379,29 @@ void Structor_(apr_pool_t *pool, const char *name, const char *types, sig::Type
         return;
 
     CYPoolTry {
-        if (NSMutableArray *entry = [[Bridge_ objectAtIndex:2] objectForKey:[NSString stringWithUTF8String:name]]) {
+        if (NSMutableArray *entry = [[Bridge_ objectAtIndex:2] objectForKey:[NSString stringWithUTF8String:name]])
             switch ([[entry objectAtIndex:0] intValue]) {
-                case 0:
-                    static CYPool Pool_;
-                    sig::Parse(Pool_, &type->data.signature, [[entry objectAtIndex:1] UTF8String], &Structor_);
-                break;
+                case 0: {
+                    sig::Parse(pool, &type->data.signature, [[entry objectAtIndex:1] UTF8String], &Structor_);
+                } break;
+
+                case 1: {
+                    sig::Signature signature;
+                    sig::Parse(pool, &signature, [[entry objectAtIndex:1] UTF8String], &Structor_);
+                    type = signature.elements[0].type;
+                } break;
             }
-        }
     } CYPoolCatch()
 }
 
 struct Functor_privateData :
-    CYData
+    CYValue
 {
     sig::Signature signature_;
     ffi_cif cif_;
 
     Functor_privateData(const char *type, void (*value)()) :
-        CYData(reinterpret_cast<void *>(value))
+        CYValue(reinterpret_cast<void *>(value))
     {
         sig::Parse(pool_, &signature_, type, &Structor_);
         sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_);
@@ -481,6 +493,7 @@ bool CYGetIndex(apr_pool_t *pool, NSString *value, ssize_t &index) {
 
 @interface NSObject (Cycript)
 
+- (JSValueRef) cy$JSValueInContext:(JSContextRef)context;
 - (JSType) cy$JSType;
 
 - (NSObject *) cy$toJSON:(NSString *)key;
@@ -501,10 +514,6 @@ bool CYGetIndex(apr_pool_t *pool, NSString *value, ssize_t &index) {
 - (void *) cy$symbol;
 @end
 
-@interface NSNumber (Cycript)
-- (void *) cy$symbol;
-@end
-
 struct PropertyAttributes {
     CYPool pool_;
 
@@ -593,6 +602,10 @@ struct PropertyAttributes {
 
 @implementation NSObject (Cycript)
 
+- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
+    return CYMakeInstance(context, self, false);
+}
+
 - (JSType) cy$JSType {
     return kJSTypeObject;
 }
@@ -789,10 +802,6 @@ struct PropertyAttributes {
     return [self cy$JSType] != kJSTypeBoolean ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, [self boolValue]);
 }
 
-- (void *) cy$symbol {
-    return [self pointerValue];
-}
-
 @end
 
 @implementation NSString (Cycript)
@@ -1295,6 +1304,56 @@ const char *CYPoolCYONString(apr_pool_t *pool, JSContextRef context, JSValueRef
     } else return NULL;
 }
 
+struct CYInternal :
+    CYData
+{
+    JSObjectRef object_;
+
+    CYInternal() :
+        object_(NULL)
+    {
+    }
+
+    ~CYInternal() {
+        // XXX: delete object_? ;(
+    }
+
+    static CYInternal *Get(id self) {
+        CYInternal *internal(NULL);
+        if (object_getInstanceVariable(self, "cy$internal_", reinterpret_cast<void **>(&internal)) == NULL) {
+            // XXX: do something epic? ;P
+        }
+
+        return internal;
+    }
+
+    static CYInternal *Set(id self) {
+        CYInternal *internal(NULL);
+        if (Ivar ivar = object_getInstanceVariable(self, "cy$internal_", reinterpret_cast<void **>(&internal))) {
+            if (internal == NULL) {
+                internal = new CYInternal();
+                object_setIvar(self, ivar, reinterpret_cast<id>(internal));
+            }
+        } else {
+            // XXX: do something epic? ;P
+        }
+
+        return internal;
+    }
+
+    JSValueRef GetProperty(JSContextRef context, JSStringRef name) {
+        if (object_ == NULL)
+            return NULL;
+        return CYGetProperty(context, object_, name);
+    }
+
+    void SetProperty(JSContextRef context, JSStringRef name, JSValueRef value) {
+        if (object_ == NULL)
+            object_ = JSObjectMake(context, NULL, NULL);
+        CYSetProperty(context, object_, name, value);
+    }
+};
+
 static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
     CYPool pool;
 
@@ -1302,6 +1361,10 @@ static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object,
         NSString *self(CYCastNSObject(pool, context, object));
         NSString *name(CYCastNSString(pool, property));
 
+        if (CYInternal *internal = CYInternal::Get(self))
+            if (JSValueRef value = internal->GetProperty(context, property))
+                return value;
+
         CYPoolTry {
             if (NSObject *data = [self cy$getProperty:name])
                 return CYCastJSValue(context, data);
@@ -1340,6 +1403,11 @@ static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStr
             }
         }
 
+        if (CYInternal *internal = CYInternal::Set(self)) {
+            internal->SetProperty(context, property, value);
+            return true;
+        }
+
         return false;
     } CYCatch
 }
@@ -1928,31 +1996,34 @@ static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObje
     return CYSendMessage(pool, context, self, _cmd, count - 2, arguments + 2, uninitialized, exception);
 }
 
-static JSValueRef CYJSValueInContext(id self, SEL _cmd, JSContextRef context) {
-    // XXX: the offset of this Ivar could be recomputed and stored in some form of closure during $objc_registerClassPair
-
-    JSObjectRef value;
-    object_getInstanceVariable(self, "cy$value_", reinterpret_cast<void **>(&value));
+void dealloc_(id self, SEL sel) {
+    CYInternal *internal;
+    object_getInstanceVariable(self, "cy$internal_", reinterpret_cast<void **>(&internal));
+    if (internal != NULL)
+        delete internal;
+    if (Method dealloc = class_getInstanceMethod(object_getClass(self), @selector(cy$dealloc)))
+        reinterpret_cast<void (*)(id, SEL)>(method_getImplementation(dealloc))(self, sel);
+}
 
-    if (value == NULL) {
-        value = CYMakeInstance(context, self, false);
-        object_setInstanceVariable(self, "cy$value_", value);
+MSHook(void, objc_registerClassPair, Class _class) {
+    Class super(class_getSuperclass(_class));
+    if (super == NULL || class_getInstanceVariable(super, "cy$internal_") == NULL) {
+        class_addIvar(_class, "cy$internal_", sizeof(CYInternal *), log2(sizeof(CYInternal *)), "^{CYInternal}");
+        if (!class_addMethod(_class, @selector(dealloc), reinterpret_cast<IMP>(&dealloc_), "v8@0:4")) {
+            Method dealloc(class_getInstanceMethod(_class, @selector(dealloc)));
+            class_addMethod(_class, @selector(cy$dealloc), method_getImplementation(dealloc), method_getTypeEncoding(dealloc));
+            method_setImplementation(dealloc, reinterpret_cast<IMP>(&dealloc_));
+        }
     }
 
-    return value;
+    _objc_registerClassPair(_class);
 }
 
-static JSValueRef $objc_registerClassPair(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+static JSValueRef objc_registerClassPair_(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     CYTry {
         CYPool pool;
-
         Class _class(CYCastNSObject(pool, context, object));
-        if (class_getInstanceMethod(_class, @selector(cy$JSValueInContext:)) == NULL) {
-            class_addIvar(_class, "cy$value_", sizeof(JSObjectRef), log2(sizeof(JSObjectRef)), "^v");
-            class_addMethod(_class, @selector(cy$JSValueInContext:), reinterpret_cast<IMP>(&CYJSValueInContext), "^v12@0:4^v8");
-        }
-
-        objc_registerClassPair(_class);
+        $objc_registerClassPair(_class);
         return CYJSUndefined(context);
     } CYCatch
 }
@@ -2015,50 +2086,50 @@ JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count,
     } CYCatch
 }
 
-JSValueRef CYData_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
-    CYData *data(reinterpret_cast<CYData *>(JSObjectGetPrivate(object)));
-    return CYCastJSValue(context, reinterpret_cast<uintptr_t>(data->value_));
+JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+    CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(object)));
+    return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
 }
 
 JSValueRef Selector_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
     return Function_;
 }
 
-static JSValueRef CYData_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+static JSValueRef CYValue_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     CYTry {
-        CYData *data(reinterpret_cast<CYData *>(JSObjectGetPrivate(_this)));
-        return CYCastJSValue(context, reinterpret_cast<uintptr_t>(data->value_));
+        CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
+        return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
     } CYCatch
 }
 
-static JSValueRef CYData_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
-    return CYData_callAsFunction_valueOf(context, object, _this, count, arguments, exception);
+static JSValueRef CYValue_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+    return CYValue_callAsFunction_valueOf(context, object, _this, count, arguments, exception);
 }
 
-static JSValueRef CYData_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+static JSValueRef CYValue_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     CYTry {
-        CYData *data(reinterpret_cast<CYData *>(JSObjectGetPrivate(_this)));
+        CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
         char string[32];
-        sprintf(string, "%p", data->value_);
+        sprintf(string, "%p", internal->value_);
         return CYCastJSValue(context, string);
     } CYCatch
 }
 
 static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     CYTry {
-        Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
+        Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
         CYPoolTry {
-            return CYCastJSValue(context, CYJSString([data->GetValue() cy$toCYON]));
+            return CYCastJSValue(context, CYJSString([internal->GetValue() cy$toCYON]));
         } CYPoolCatch(NULL)
     } CYCatch
 }
 
 static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     CYTry {
-        Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
+        Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
         CYPoolTry {
             NSString *key(count == 0 ? nil : CYCastNSString(NULL, CYJSString(context, arguments[0])));
-            return CYCastJSValue(context, CYJSString([data->GetValue() cy$toJSON:key]));
+            return CYCastJSValue(context, CYJSString([internal->GetValue() cy$toJSON:key]));
         } CYPoolCatch(NULL)
     } CYCatch
 }
@@ -2111,22 +2182,22 @@ static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef
     } CYCatch
 }
 
-static JSStaticValue CYData_staticValues[2] = {
-    {"value", &CYData_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
+static JSStaticValue CYValue_staticValues[2] = {
+    {"value", &CYValue_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
     {NULL, NULL, NULL, 0}
 };
 
 static JSStaticFunction Pointer_staticFunctions[4] = {
-    {"toCYON", &CYData_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
-    {"toJSON", &CYData_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
-    {"valueOf", &CYData_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"toCYON", &CYValue_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {NULL, NULL, 0}
 };
 
 static JSStaticFunction Functor_staticFunctions[4] = {
-    {"toCYON", &CYData_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
-    {"toJSON", &CYData_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
-    {"valueOf", &CYData_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"toCYON", &CYValue_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {NULL, NULL, 0}
 };
 
@@ -2220,7 +2291,7 @@ MSInitialize { _pooled
 
     definition = kJSClassDefinitionEmpty;
     definition.className = "Selector";
-    definition.staticValues = CYData_staticValues;
+    definition.staticValues = CYValue_staticValues;
     //definition.staticValues = Selector_staticValues;
     definition.staticFunctions = Selector_staticFunctions;
     definition.callAsFunction = &Selector_callAsFunction;
@@ -2229,7 +2300,7 @@ MSInitialize { _pooled
 
     definition = kJSClassDefinitionEmpty;
     definition.className = "Instance";
-    definition.staticValues = CYData_staticValues;
+    definition.staticValues = CYValue_staticValues;
     definition.staticFunctions = Instance_staticFunctions;
     definition.getProperty = &Instance_getProperty;
     definition.setProperty = &Instance_setProperty;
@@ -2259,7 +2330,9 @@ MSInitialize { _pooled
     CYSetProperty(context, global, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new));
     CYSetProperty(context, global, CYJSString("Selector"), JSObjectMakeConstructor(context, Selector_, &Selector_new));
 
-    CYSetProperty(context, global, CYJSString("objc_registerClassPair"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_registerClassPair"), &$objc_registerClassPair));
+    MSHookFunction(&objc_registerClassPair, MSHake(objc_registerClassPair));
+
+    CYSetProperty(context, global, CYJSString("objc_registerClassPair"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_registerClassPair"), &objc_registerClassPair_));
     CYSetProperty(context, global, CYJSString("objc_msgSend"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_msgSend"), &$objc_msgSend));
 
     System_ = JSObjectMake(context, NULL, NULL);
diff --git a/makefile b/makefile
index 20c4123..70b88a9 100644
--- a/makefile
+++ b/makefile
@@ -26,7 +26,7 @@ libcycript.plist: Bridge.def
 	    echo '},{'; \
 	    grep '^:' Bridge.def | sed -e 's/^: \([^ ]*\) \(.*\)/"\1" = "\2";/'; \
 	    echo '},{'; \
-	    grep '^S' Bridge.def | sed -e 's/^S/0/' | sed -e 's/"/\\"/g;s/^\([^ ]*\) \([^ ]*\) \(.*\)$$/\2 = (\1, \"\3\");/'; \
+	    grep '^[EST]' Bridge.def | sed -e 's/^S/0/;s/^T/1/;s/^E/2/' | sed -e 's/^2\(.*\)$$/1\1 i/' | sed -e 's/"/\\"/g;s/^\([^ ]*\) \([^ ]*\) \(.*\)$$/\2 = (\1, \"\3\");/'; \
 	    echo '})'; \
 	} >$@
 
@@ -60,7 +60,7 @@ lex.cy.o: lex.cy.c Cycript.tab.hh Parser.hpp Pooling.hpp
 libcycript.dylib: ffi_type.o parse.o Output.o Cycript.tab.o lex.cy.o Library.o
 	$(target)g++ $(flags) -dynamiclib -o $@ $(filter %.o,$^) \
 	    -install_name /usr/lib/libcycript.dylib \
-	    -lobjc -lapr-1 -lffi \
+	    -lobjc -lapr-1 -lffi -lsubstrate \
 	    -framework CoreFoundation -framework Foundation \
 	    -framework CFNetwork \
 	    -framework JavaScriptCore -framework WebCore
diff --git a/sig/parse.cpp b/sig/parse.cpp
index 3452e5a..18f0668 100644
--- a/sig/parse.cpp
+++ b/sig/parse.cpp
@@ -160,13 +160,12 @@ struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named, C
 
         case '^':
             type->primitive = pointer_P;
-            if (**name == 'v') {
-                type->data.data.type = NULL;
-                ++*name;
-            } else if (**name == '"') {
+            if (**name == '"') {
                 type->data.data.type = NULL;
             } else {
                 type->data.data.type = Parse_(pool, name, eos, named, callback);
+                if (type->data.data.type->primitive == void_P)
+                    type->data.data.type = NULL;
             }
         break;
 
-- 
2.50.0

