+#ifdef __SIZEOF_INT128__
+CYFromFFI_(signed __int128)
+CYFromFFI_(unsigned __int128)
+#endif
+
+template <>
+JSValueRef Primitive<bool>::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ return CYCastJSValue(context, *reinterpret_cast<bool *>(data));
+}
+
+template <>
+JSValueRef Primitive<char>::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ uint16_t string(uint8_t(*reinterpret_cast<char *>(data)));
+ JSValueRef value(CYCastJSValue(context, CYJSString(CYUTF16String(&string, 1))));
+ JSObjectRef typed(_jsccall(JSObjectCallAsConstructor, context, CYGetCachedObject(context, CYJSString("String")), 1, &value));
+ CYSetProperty(context, typed, cyt_s, CYMakeType(context, sig::Primitive<char>()), kJSPropertyAttributeDontEnum);
+ CYSetPrototype(context, typed, CYGetCachedValue(context, CYJSString("Character_prototype")));
+ return typed;
+}
+
+JSValueRef Void::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ return CYJSUndefined(context);
+}
+
+JSValueRef Unknown::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ _assert(false);
+}
+
+JSValueRef String::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ if (char *value = *reinterpret_cast<char **>(data))
+ return CYPrivate<CString>::Make(context, value, context, owner);
+ return CYJSNull(context);
+}
+
+JSValueRef Bits::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ _assert(false);
+}
+
+JSValueRef Pointer::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ if (void *value = *reinterpret_cast<void **>(data))
+ return CYMakePointer(context, value, type, NULL, owner);
+ return CYJSNull(context);
+}
+
+JSValueRef Array::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ return CYPrivate<CArray>::Make(context, data, size, type, ffi->elements[0], context, owner);
+}
+
+JSValueRef Enum::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ return type.FromFFI(context, ffi, data, initialize, owner);
+}
+
+JSValueRef Aggregate::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ _assert(!overlap);
+ _assert(signature.count != _not(size_t));
+ return CYPrivate<Struct_privateData>::Make(context, data, *this, ffi, context, owner);
+}
+
+JSValueRef Function::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ return CYMakeFunctor(context, reinterpret_cast<void (*)()>(data), variadic, signature);
+}
+
+}
+
+void CYExecuteClosure(ffi_cif *cif, void *result, void **arguments, void *arg) {
+ Closure_privateData *internal(reinterpret_cast<Closure_privateData *>(arg));
+
+ JSContextRef context(internal->function_);
+
+ size_t count(internal->cif_.nargs);
+ JSValueRef values[count];
+
+ for (size_t index(0); index != count; ++index)
+ values[index] = internal->signature_.elements[1 + index].type->FromFFI(context, internal->cif_.arg_types[index], arguments[index]);
+
+ JSValueRef value(internal->adapter_(context, count, values, internal->function_));
+ internal->signature_.elements[0].type->PoolFFI(NULL, context, internal->cif_.rtype, result, value);
+}
+
+static JSValueRef FunctionAdapter_(JSContextRef context, size_t count, JSValueRef values[], JSObjectRef function) {
+ return CYCallAsFunction(context, function, NULL, count, values);
+}
+
+#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__))
+static void CYFreeFunctor(void *data) {
+ ffi_closure_free(data);
+}
+#else
+static void CYFreeFunctor(void *data) {
+ _syscall(munmap(data, sizeof(ffi_closure)));
+}
+#endif
+
+Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const sig::Signature &signature, JSValueRef (*adapter)(JSContextRef, size_t, JSValueRef[], JSObjectRef)) {
+ // XXX: in case of exceptions this will leak
+ Closure_privateData *internal(new Closure_privateData(context, function, adapter, signature));
+
+#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__))
+ void *executable;
+ ffi_closure *writable(reinterpret_cast<ffi_closure *>(ffi_closure_alloc(sizeof(ffi_closure), &executable)));
+
+ ffi_status status(ffi_prep_closure_loc(writable, &internal->cif_, &CYExecuteClosure, internal, executable));
+ _assert(status == FFI_OK);
+
+ internal->pool_->atexit(&CYFreeFunctor, writable);
+ internal->value_ = reinterpret_cast<void (*)()>(executable);
+#else
+ ffi_closure *closure((ffi_closure *) _syscall(mmap(
+ NULL, sizeof(ffi_closure),
+ PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
+ -1, 0
+ )));
+
+ ffi_status status(ffi_prep_closure(closure, &internal->cif_, &CYExecuteClosure, internal));
+ _assert(status == FFI_OK);
+
+ _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
+
+ internal->pool_->atexit(&CYFreeFunctor, closure);
+ internal->value_ = reinterpret_cast<void (*)()>(closure);
+#endif
+
+ return internal;
+}
+
+static JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const sig::Signature &signature) {
+ Closure_privateData *internal(CYMakeFunctor_(context, function, signature, &FunctionAdapter_));
+ JSObjectRef object(JSObjectMake(context, cy::Functor::Class_, internal));
+ // XXX: see above notes about needing to leak
+ JSValueProtect(CYGetJSContext(context), object);
+ return object;
+}
+
+JSValueRef CYGetCachedValue(JSContextRef context, JSStringRef name) {
+ return CYGetProperty(context, CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s)), name);
+}
+
+JSObjectRef CYGetCachedObject(JSContextRef context, JSStringRef name) {
+ return CYCastJSObject(context, CYGetCachedValue(context, name));
+}
+
+static JSValueRef CYMakeFunctor(JSContextRef context, JSValueRef value, bool variadic, const sig::Signature &signature) {
+ JSObjectRef Function(CYGetCachedObject(context, CYJSString("Function")));
+
+ bool function(_jsccall(JSValueIsInstanceOfConstructor, context, value, Function));
+ if (function) {
+ JSObjectRef function(CYCastJSObject(context, value));
+ return CYMakeFunctor(context, function, signature);
+ } else {
+ void (*function)()(CYCastPointer<void (*)()>(context, value));
+ return CYMakeFunctor(context, function, variadic, signature);
+ }
+}
+
+static JSValueRef CString_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
+ CYPool pool;
+ CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(object)));
+
+ ssize_t offset;