Bug 17550 - JSValue.From() does not include overloads that accept Actions and Funcs
Summary: JSValue.From() does not include overloads that accept Actions and Funcs
Status: NEW
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll (show other bugs)
Version: 7.0.6.x
Hardware: PC Mac OS
: --- enhancement
Target Milestone: Untriaged
Assignee: Bugzilla
Depends on:
Reported: 2014-02-02 19:18 UTC by Brendan Zagaeski (Xamarin Support)
Modified: 2015-08-24 18:31 UTC (History)
2 users (show)

See Also:
Is this bug a regression?: ---
Last known good build:


Description Brendan Zagaeski (Xamarin Support) 2014-02-02 19:18:26 UTC
## Summary
The C# bindings for the JavaScriptCore library are missing `JSValue.From()` overloads that accept `Actions` and `Funcs`. Consequently, the bindings do not currently allow callbacks to C# methods from JavaScript.

## Complications

1. The Objective-C wrapper layer for JavaScriptCore only requires that the callback methods be of type `NSBlock` (a subclass of `NSObject`). Since the usual Xamarin binding mechanism for blocks requires a fixed delegate type signature, I suspect that it cannot accommodate this situation.

2. C# does not allow a parameter type of "any kind of delegate." Therefore, to expose functionality similar to the Objective-C version, I think the corresponding C# `JSValue.From()` overload would need either to:

A. Require the user to wrap up the callback delegate within a `void`, parameterless delegate (an `Action`).


B. Require the user to pass in a `MethodInfo` object rather than an `Action`. This option might not work: I'm not sure if `MethodInfo` contains all the necessary information.

## A little more background

The JavaScriptCore library allows the user to create a JavaScript function that calls a native C function [1]. In Objective-C, this feature is wrapped up in the `[JSObjCClassInfo wrapperForObject:]` method [2]. The C# bindings do not expose this feature. One problem is that `Actions` and `Funcs` are not subclasses of `NSObject`. Because of this, the `wrapperForObject:` method has no way to convert them to JavaScript objects.

> [1] See the JSObjectMakeFunctionWithCallback() function on:
> http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/API/JSObjectRef.cpp

> [2] See: http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/API/JSWrapperMap.mm
Note: the `wrapperForObject:` method is usually called indirectly as the result of a call to `[JSValue valueWithObject:inContext:]`, which is defined in:
> http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/API/JSValue.mm

## Possible solutions?

### Write a new JavaScriptCore binding that P/Invokes the C API

One way to work around the problem might be to re-write the Objective-C binding layer in C#. In this scenario, the C# binding would skip the Objective-C layer entirely. Instead it would directly P/Invoke the JavaScriptCore C API functions. Unfortunately, I think it would be necessary to recreate the whole Objective-C binding layer. One example that demonstrates this problem is that the Objective-C layer wraps the native C `JSValueRef` type into a `JSValue` Objective-C class. So the existing binding for `JSValue` would not be compatible with a `JSValue.From()` method that directly P/Invoked `JSObjectMakeFunctionWithCallback()`.

Maybe writing a P/Invoke, C API version of JavaScriptCore would be an interesting GSoC project?

### Create `NSBlocks` from C# `Actions` at runtime

Another solution might be to make the new `JSValue.From()` overload (that takes `Actions` or `MethodInfos`) include some fancy logic to create an intermediary callback `NSBlock` for _any_ input delegate at runtime. On the other hand, I think this might require creating new trampoline types at runtime, and I'm not sure that's technically possible considering that SRE is unavailable on iOS.

## Version information
Comment 1 David 2015-07-21 10:38:18 UTC
Any plans for adding this functionality?
Comment 2 Brendan Zagaeski (Xamarin Support) 2015-07-21 12:41:43 UTC
In case it's helpful for anyone looking for this feature, you can now (as of Xamarin.iOS 8.10 and higher) export entire C# objects to JavaScript using a different JavaScriptCore mechanism.

See Bug 23474, Comment 3 through Bug 23474, Comment 5 for more details about that.

That alternate strategy might be sufficient for many use cases.

Note You need to log in before you can comment on or make changes to this bug.