/* }}} */
 
 #include <substrate.h>
+#include "Struct.hpp"
 
 #include "sig/parse.hpp"
 #include "sig/ffi_type.hpp"
 
 typedef id jocData;
 
+struct ptrData {
+    void *value_;
+};
+
+static void ptr_finalize(JSObjectRef object) {
+    ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
+    free(data);
+}
+
 static void joc_finalize(JSObjectRef object) {
     id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
     [data release];
             void *&pointer(*reinterpret_cast<void **>(data));
             if (JSValueIsNull(context, value))
                 pointer = NULL;
-            else if (JSValueIsObjectOfClass(context, value, ptr_))
-                pointer = JSObjectGetPrivate((JSObjectRef) value);
-            else {
+            else if (JSValueIsObjectOfClass(context, value, ptr_)) {
+                ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate((JSObjectRef) value)));
+                pointer = data->value_;
+            } else {
                 JSValueRef exception(NULL);
                 double number(JSValueToNumber(context, value, &exception));
                 CYThrow(context, exception);
         } break;
 
         case sig::pointer_P: {
-            void *pointer(*reinterpret_cast<void **>(data));
-            value = pointer == NULL ? JSValueMakeNull(context) : JSObjectMake(context, ptr_, pointer);
+            if (void *pointer = *reinterpret_cast<void **>(data)) {
+                ptrData *data(reinterpret_cast<ptrData *>(malloc(sizeof(ptrData))));
+                data->value_ = pointer;
+                value = JSObjectMake(context, ptr_, data);
+            } else value = JSValueMakeNull(context);
         } break;
 
         case sig::string_P: {
     }
 }
 
+bool stret(ffi_type *ffi_type) {
+    return ffi_type->type == FFI_TYPE_STRUCT && (
+        ffi_type->size > OBJC_MAX_STRUCT_BY_VALUE ||
+        struct_forward_array[ffi_type->size] != 0
+    );
+}
+
 static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { _pooled
     const char *type;
 
     sig::Signature signature;
     sig::Parse(pool, &signature, type);
 
-    void (*function)() = reinterpret_cast<void (*)()>(&objc_msgSend);
-
     ffi_cif cif;
     sig::sig_ffi_cif(pool, &sig::sig_objc_ffi_type, &signature, &cif);
 
+    void (*function)() = stret(cif.rtype) ? reinterpret_cast<void (*)()>(&objc_msgSend_stret) : reinterpret_cast<void (*)()>(&objc_msgSend);
     return CYCallFunction(context, count, arguments, exception, &signature, &cif, function);
 }
 
     CYSetProperty(context, object, name, value);
 }
 
+JSValueRef ptr_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef *exception) {
+    ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
+    return JSValueMakeNumber(context, reinterpret_cast<uintptr_t>(data->value_));
+}
+
+static JSStaticValue ptr_staticValues[2] = {
+    {"value", &ptr_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
+    {NULL, NULL, NULL, 0}
+};
+
 MSInitialize { _pooled
     apr_initialize();
 
 
     definition = kJSClassDefinitionEmpty;
     definition.className = "ptr";
+    definition.staticValues = ptr_staticValues;
+    definition.finalize = &ptr_finalize;
     ptr_ = JSClassCreate(&definition);
 
     definition = kJSClassDefinitionEmpty;
 #define CYSetFunction_(name, type) \
     CYSetFunction(context, global, #name, reinterpret_cast<void (*)()>(&name), type)
 
+    CYSetFunction_(class_addIvar, "B#*LC*");
+    CYSetFunction_(class_addMethod, "B#:^?*");
+    CYSetFunction_(class_addProtocol, "B#@");
+    CYSetFunction_(class_conformsToProtocol, "B#@");
+    CYSetFunction_(class_copyIvarList, "^^{objc_ivar=}#^I");
+    CYSetFunction_(class_copyMethodList, "^^{objc_method=}#^I");
+    CYSetFunction_(class_copyPropertyList, "^^{objc_property=}#^I");
+    CYSetFunction_(class_copyProtocolList, "^@#^I");
     CYSetFunction_(class_createInstance, "@#L");
+    CYSetFunction_(class_getClassMethod, "^{objc_method=}#:");
+    CYSetFunction_(class_getClassVariable, "^{objc_ivar=}#*");
+    CYSetFunction_(class_getInstanceMethod, "^{objc_method=}#:");
     CYSetFunction_(class_getInstanceSize, "L#");
+    CYSetFunction_(class_getInstanceVariable, "^{objc_ivar=}#*");
     CYSetFunction_(class_getIvarLayout, "*#");
+    CYSetFunction_(class_getMethodImplementation, "^?#:");
+    CYSetFunction_(class_getMethodImplementation_stret, "^?#:");
     CYSetFunction_(class_getName, "*#");
+    CYSetFunction_(class_getProperty, "^{objc_property=}#*");
     CYSetFunction_(class_getSuperclass, "##");
     CYSetFunction_(class_getVersion, "i#");
+    CYSetFunction_(class_getWeakIvarLayout, "*#");
     CYSetFunction_(class_isMetaClass, "B#");
+    CYSetFunction_(class_replaceMethod, "^?#:^?*");
     CYSetFunction_(class_respondsToSelector, "B#:");
+    CYSetFunction_(class_setIvarLayout, "v#*");
     CYSetFunction_(class_setSuperclass, "###");
     CYSetFunction_(class_setVersion, "v#i");
+    CYSetFunction_(class_setWeakIvarLayout, "v#*");
+    CYSetFunction_(ivar_getName, "*^{objc_ivar=}");
+    CYSetFunction_(ivar_getOffset, "i^{objc_ivar=}");
+    CYSetFunction_(ivar_getTypeEncoding, "*^{objc_ivar=}");
+    CYSetFunction_(method_copyArgumentType, "^c^{objc_method=}I");
+    CYSetFunction_(method_copyReturnType, "^c^{objc_method=}");
+    CYSetFunction_(method_exchangeImplementations, "v^{objc_method=}^{objc_method=}");
+    CYSetFunction_(method_getArgumentType, "v^{objc_method=}I^cL");
+    CYSetFunction_(method_getImplementation, "^?^{objc_method=}");
+    CYSetFunction_(method_getName, ":^{objc_method=}");
+    CYSetFunction_(method_getNumberOfArguments, "I^{objc_method=}");
+    CYSetFunction_(method_getReturnType, "v^{objc_method=}^cL");
+    CYSetFunction_(method_getTypeEncoding, "*^{objc_method=}");
+    CYSetFunction_(method_setImplementation, "^?^{objc_method=}^?");
     CYSetFunction_(objc_allocateClassPair, "##*L");
+    CYSetFunction_(objc_copyProtocolList, "^@^I");
+    CYSetFunction_(objc_duplicateClass, "##*L");
     CYSetFunction_(objc_getClass, "#*");
+    CYSetFunction_(objc_getClassList, "i^#i");
     CYSetFunction_(objc_getFutureClass, "#*");
     CYSetFunction_(objc_getMetaClass, "@*");
+    CYSetFunction_(objc_getProtocol, "@*");
     CYSetFunction_(objc_getRequiredClass, "@*");
     CYSetFunction_(objc_lookUpClass, "@*");
     CYSetFunction_(objc_registerClassPair, "v#");
     CYSetFunction_(object_dispose, "@@");
     CYSetFunction_(object_getClass, "#@");
     CYSetFunction_(object_getClassName, "*@");
+    CYSetFunction_(object_getIndexedIvars, "^v@");
+    CYSetFunction_(object_getInstanceVariable, "^{objc_ivar=}@*^^v");
+    CYSetFunction_(object_getIvar, "@@^{objc_ivar=}");
     CYSetFunction_(object_setClass, "#@#");
+    CYSetFunction_(object_setInstanceVariable, "^{objc_ivar=}@*^v");
+    CYSetFunction_(object_setIvar, "v@^{objc_ivar=}@");
+    CYSetFunction_(property_getAttributes, "*^{objc_property=}");
+    CYSetFunction_(property_getName, "*^{objc_property=}");
+    CYSetFunction_(protocol_conformsToProtocol, "B@@");
+    CYSetFunction_(protocol_copyMethodDescriptionList, "^{objc_method_description=:*}@BB^I");
+    CYSetFunction_(protocol_copyPropertyList, "^{objc_property=}@^I");
+    CYSetFunction_(protocol_copyProtocolList, "^@@^I");
+    CYSetFunction_(protocol_getMethodDescription, "{objc_method_description=:*}@:BB");
+    CYSetFunction_(protocol_getName, "*@");
+    CYSetFunction_(protocol_getProperty, "^{objc_property=}@*BB");
+    CYSetFunction_(protocol_isEqual, "B@@");
     CYSetFunction_(sel_getName, "*:");
     CYSetFunction_(sel_getUid, ":*");
     CYSetFunction_(sel_isEqual, "B::");