#include <objc/runtime.h>
#endif
+#ifdef __APPLE__
+#include <malloc/malloc.h>
+#include <mach/mach.h>
+#endif
+
#include "Error.hpp"
#include "JavaScript.hpp"
#include "String.hpp"
return JSObjectMake(context, Message_, internal);
}
-static IMP CYMakeMessage(JSContextRef context, JSValueRef value, const char *type) {
+static IMP CYMakeMessage(JSContextRef context, JSValueRef value, const char *encoding) {
JSObjectRef function(CYCastJSObject(context, value));
- Closure_privateData *internal(CYMakeFunctor_(context, function, type, &MessageClosure_));
+ CYPool pool;
+ sig::Signature signature;
+ sig::Parse(pool, &signature, encoding, &Structor_);
+ Closure_privateData *internal(CYMakeFunctor_(context, function, signature, &MessageClosure_));
// XXX: see notes in Library.cpp about needing to leak
return reinterpret_cast<IMP>(internal->GetValue());
}
return NULL;
} CYCatch(NULL) }
-static void ObjectiveC_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
#ifdef __APPLE__
- size_t size(objc_getClassList(NULL, 0));
+static Class *CYCopyClassList(size_t &size) {
+ size = objc_getClassList(NULL, 0);
Class *data(reinterpret_cast<Class *>(malloc(sizeof(Class) * size)));
- get:
- size_t writ(objc_getClassList(data, size));
- if (size < writ) {
+ for (;;) {
+ size_t writ(objc_getClassList(data, size));
+ if (writ <= size) {
+ size = writ;
+ return data;
+ }
+
+ Class *copy(reinterpret_cast<Class *>(realloc(data, sizeof(Class) * writ)));
+ if (copy == NULL) {
+ free(data);
+ return NULL;
+ }
+
+ data = copy;
size = writ;
- if (Class *copy = reinterpret_cast<Class *>(realloc(data, sizeof(Class) * writ))) {
- data = copy;
- goto get;
- } else goto done;
}
+}
+#endif
- for (size_t i(0); i != writ; ++i)
- JSPropertyNameAccumulatorAddName(names, CYJSString(class_getName(data[i])));
-
- done:
- free(data);
+static void ObjectiveC_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
+#ifdef __APPLE__
+ size_t size;
+ if (Class *data = CYCopyClassList(size)) {
+ for (size_t i(0); i != size; ++i)
+ JSPropertyNameAccumulatorAddName(names, CYJSString(class_getName(data[i])));
+ free(data);
+ }
#else
void *state(NULL);
while (Class _class = objc_next_class(&state))
JSPropertyNameAccumulatorAddName(names, CYJSString("nil"));
}
+#ifdef __APPLE__
+static kern_return_t CYReadMemory(task_t task, vm_address_t address, vm_size_t size, void **data) {
+ *data = reinterpret_cast<void *>(address);
+ return KERN_SUCCESS;
+}
+
+struct CYChoice {
+ std::set<Class> query_;
+ JSContextRef context_;
+ JSObjectRef results_;
+};
+
+struct CYObjectStruct {
+ Class isa_;
+};
+
+static void choose_(task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count) {
+ CYChoice *choice(reinterpret_cast<CYChoice *>(baton));
+ JSContextRef context(choice->context_);
+
+ for (unsigned i(0); i != count; ++i) {
+ vm_range_t &range(ranges[i]);
+ void *data(reinterpret_cast<void *>(range.address));
+ size_t size(range.size);
+
+ if (size < sizeof(CYObjectStruct))
+ continue;
+
+ uintptr_t *pointers(reinterpret_cast<uintptr_t *>(data));
+#ifdef __arm64__
+ Class isa(reinterpret_cast<Class>(pointers[0] & 0x1fffffff8));
+#else
+ Class isa(reinterpret_cast<Class>(pointers[0]));
+#endif
+
+ std::set<Class>::const_iterator result(choice->query_.find(isa));
+ if (result == choice->query_.end())
+ continue;
+
+ // XXX: if (size < class_getInstanceSize(*result))
+ if ((class_getInstanceSize(*result) + 15) / 16 * 16 != size)
+ continue;
+ CYArrayPush(context, choice->results_, CYCastJSValue(context, reinterpret_cast<id>(data)));
+ }
+}
+
+static JSValueRef choose(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+ if (count != 1)
+ throw CYJSError(context, "choose() takes a class argument");
+
+ CYPool pool;
+ Class _class(CYCastNSObject(&pool, context, arguments[0]));
+
+ vm_address_t *zones(NULL);
+ unsigned size(0);
+ kern_return_t error(malloc_get_all_zones(0, &CYReadMemory, &zones, &size));
+ _assert(error == KERN_SUCCESS);
+
+ JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
+ JSObjectRef results(_jsccall(JSObjectCallAsConstructor, context, Array, 0, NULL));
+
+ CYChoice choice;
+ choice.context_ = context;
+ choice.results_ = results;
+
+ size_t number;
+ Class *classes(CYCopyClassList(number));
+ _assert(classes != NULL);
+
+ for (size_t i(0); i != number; ++i)
+ for (Class current(classes[i]); current != Nil; current = class_getSuperclass(current))
+ if (current == _class) {
+ choice.query_.insert(classes[i]);
+ break;
+ }
+
+ free(classes);
+
+ for (unsigned i(0); i != size; ++i) {
+ const malloc_zone_t *zone(reinterpret_cast<const malloc_zone_t *>(zones[i]));
+ if (zone == NULL || zone->introspect == NULL)
+ continue;
+
+ zone->introspect->enumerator(mach_task_self(), &choice, MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], &CYReadMemory, &choose_);
+ }
+
+ return results;
+} CYCatch(NULL) }
+#endif
+
#ifdef __APPLE__
#if defined(__i386__) || defined(__x86_64__)
#define OBJC_MAX_STRUCT_BY_VALUE 8
else
method = NULL;
- if (const char *type = CYPoolTypeEncoding(pool, context, sel, method))
- return CYCastJSValue(context, CYJSString(type));
+ const char *encoding(CYPoolTypeEncoding(pool, context, sel, method));
+ if (encoding == NULL)
+ return CYJSNull(context);
- return CYJSNull(context);
+ sig::Signature signature;
+ sig::Parse(pool, &signature, encoding, &Structor_);
+ return CYMakeType(context, &signature);
} CYCatch(NULL) }
static JSStaticValue Selector_staticValues[2] = {
JSObjectRef box(JSObjectMakeFunctionWithCallback(context, CYJSString("box"), &Instance_box_callAsFunction));
CYSetProperty(context, Instance, CYJSString("box"), box);
-#if defined(__APPLE__) && defined(__arm__) && 0
- CYSetProperty(context, all, CYJSString("objc_registerClassPair"), &objc_registerClassPair_, kJSPropertyAttributeDontEnum);
+#ifdef __APPLE__
+ CYSetProperty(context, all, CYJSString("choose"), &choose, kJSPropertyAttributeDontEnum);
#endif
CYSetProperty(context, all, CYJSString("objc_msgSend"), &$objc_msgSend, kJSPropertyAttributeDontEnum);