This is Xamarin's bug tracking system. For product support, please use the support links listed in your Xamarin Account.
Bug 12746 - Async generic method calls from interface, JIT compile exception
Summary: Async generic method calls from interface, JIT compile exception
Status: RESOLVED FIXED
Alias: None
Product: iOS
Classification: Xamarin
Component: XI runtime (show other bugs)
Version: 6.3.x
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Future Cycle (TBD)
Assignee: Zoltan Varga
URL:
Depends on:
Blocks:
 
Reported: 2013-06-18 16:01 UTC by Brendan Zagaeski (Xamarin Support)
Modified: 2016-01-11 21:50 UTC (History)
10 users (show)

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


Attachments
Example source code (5.08 KB, application/zip)
2013-06-18 16:01 UTC, Brendan Zagaeski (Xamarin Support)
Details
Test cases #2 (3.70 KB, application/zip)
2013-06-19 05:33 UTC, kissling
Details

Description Brendan Zagaeski (Xamarin Support) 2013-06-18 16:01:56 UTC
Created attachment 4148 [details]
Example source code

Created on behalf of Etan Kissling.

The attached example shows that synchronous calls to a generic method via an interface succeed, but async calls fail. The example also demonstrates a work-around.

This is probably similar to previous reports related to Generic Virtual Methods and AOT, but the dependence on async is potentially interesting.
http://docs.xamarin.com/guides/ios/advanced_topics/limitations#Generic_Virtual_Methods

--------

Output (from Etan Kissling, with Xamarin.iOS Beta):

Test 1 / Synchronous generic call from interface
Ok.

Test 2 / Asynchronous generic call from class
Ok.

Test 3 / Asynchronous generic call from interface
System.ExecutionEngineException: Attempting to JIT compile method 'AsyncGenerics.X:TestAsync<AsyncGenerics.IC> ()' while running with --aot-only. Seehttp://docs.xamarin.com/ios/about/limitations for more information.

at AsyncGenerics.AppDelegate+<Test3>c__async0.MoveNext () [0x0003e] in /***/AsyncGenerics/AppDelegate.cs:57

Test 4 / Asynchronous generic call from interface with workaround
Ok.

Test 5 / Asynchronous generic call from interface with unreachable workaround
System.ExecutionEngineException: Attempting to JIT compile method 'AsyncGenerics.X:TestAsync<AsyncGenerics.IE> ()' while running with --aot-only. Seehttp://docs.xamarin.com/ios/about/limitations for more information.

at AsyncGenerics.AppDelegate+<Test5>c__async2.MoveNext () [0x0003e] in /***/AsyncGenerics/AppDelegate.cs:88

Test 6 / Workaround from Test 4 still applies, even in another method
Ok.
Comment 1 kissling 2013-06-18 17:49:56 UTC
Note that the compiler is able to find the correct implementation when the method is called without the await keyword (Test 1) but cannot find it only when await is attached. Seems like the generated code by the await keyword is not treated properly by the compiler. 

The virtual method generic limitation should not apply here as the compiler can deduce the correct method properly without await.

The workaround consists of AOT compilation enforcement by referencing the code from unreachable code that the compiler does not detect. Test 4 shows the workaround by putting the reference inside a catch clause that is never executed. A similar workaround that's simpler to understand could consist of this:

            // HACK Ensure that awaited generic method calls are compiled AOT instead of JIT.
            for (bool hack = false; hack;)
            {
                // Unreachable code. Note that if the compiler detects this, the hack won't work.
                new X().TestAsync<IE>();
            } 


========================


As requested, here are the build numbers.


Xamarin Studio
Version 4.1.4 (build 117)
Installation UUID: 938751df-f7a5-457d-b87b-379763e0ada1
Runtime:
	Mono 3.0.10 ((no/eff4cb5)
	GTK 2.24.18
	GTK# (2.12.0.0)
	Package version: 300100000

Apple Developer Tools
Xcode 5.0 (3322.38)
Build 5A11314m

Xamarin.iOS
Version: 6.3.6.76 (Business Edition)
Hash: cdd868f
Branch: 
Build date: 2013-03-06 10:32:55-0400

Xamarin.Android
Version: 4.7.8 (Starter Edition)
Android SDK: /Users/etankissling/Library/Developer/Xamarin/android-sdk-mac_x86
	Supported Android versions:
		2.1   (API level 7)
		2.2   (API level 8)
		2.3   (API level 10)
		3.1   (API level 12)
		4.0   (API level 14)
		4.0.3 (API level 15)
Java SDK: /usr
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06-451-11M4406)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01-451, mixed mode)

Xamarin.Mac
Xamarin.Mac: Not Installed

Build Information
Release ID: 401040117
Git revision: e0f38912731e43ed9d3f1a410dd4fd907e7f1ba0
Build date: 2013-06-11 19:29:58+0000
Xamarin addins: 8fd84026361c1969794b85bee48efab97a5f33b3

Operating System
Mac OS X 10.8.4
Darwin Etans-MacBook-Pro.local 12.4.0 Darwin Kernel Version 12.4.0
    Wed May  1 17:57:12 PDT 2013
    root:xnu-2050.24.15~1/RELEASE_X86_64 x86_64
Comment 2 kissling 2013-06-19 05:33:44 UTC
Created attachment 4153 [details]
Test cases #2



I've conducted additional tests on this issue. Here are the results:

- Synchronous generic calls work fine both when invoked from X and from IX.
   public void Void<T>() where T : class
   public T T<T>() where T : class

- This also applies to methods that are not async but return a Task.
   public Task TaskNoAsync<T>() where T : class
   public Task<T> TaskTNoAsync<T>() where T : class

- Problems arise, when this returned Task is now awaited.
   await TaskNoAsync<T>();
   await TaskTNoAsync<T>();
   In this case, the proposed workaround does NOT work, and a JIT compilation 
   exception is thrown for both X and IX.

- When a method returns a Task, and is marked as async, the workaround is 
   necessary in order to call the method from an interface synchronously.
   public async Task TaskAsync<T>() where T : class
   public async Task<T> TaskTAsync<T>() where T : class
   This works when called from X, but from IX, the workaround is necessary.
   The workaround involves calling the method from X in unreachable code.
   Calling it from IX in this code is not sufficient.

   for (bool hack = false; hack;)
      x.TaskAsync<T>();
      x.TaskTAsync<T>();
   }

   When this workaround is applied, ix.TaskAsync<T>() and 
   ix.TaskTAsync<T>() works.

- When the Tasks returned by methods marked with async are awaited, no
   errors occur when called from x, and the workaround is again necessary
   to call from interfaces.
   await TaskTAsync<T>();
   await TaskTAsync<T>();
   This is interesting, as await does not work at all on Tasks that are returned
   from generic methods without the async keyword.

- On the iOS Simulator, all tests run without problems and without the workaround.

- Tested on iOS 6.0.1 and iOS 7.0 Beta 1. Both with the same results.

Raw results from the new test set:


                              +-------------+-------------+
                invoked from  |   new X()   | (IX)new X() |
                              +-------------+-------------+
               Void<INormal>  |      o      |      o      |
                              +-------------+-------------+
        TaskNoAsync<INormal>  |      o      |      o      |
                              +-------------+-------------+
  await TaskNoAsync<INormal>  |      x      |      x      |
  await TaskNoAsync<IHacked>  |      x      |      x      |
                              +-------------+-------------+
          TaskAsync<INormal>  |      o      |      x      |
          TaskAsync<IHacked>  |      o      |      o      |
                              +-------------+-------------+
    await TaskAsync<INormal>  |      o      |      x      |
    await TaskAsync<IHacked>  |      o      |      o      |
                              +-------------+-------------+
                  T<INormal>  |      o      |      o      |
                              +-------------+-------------+
       TaskTNoAsync<INormal>  |      o      |      o      |
                              +-------------+-------------+
 await TaskTNoAsync<INormal>  |      x      |      x      |
 await TaskTNoAsync<IHacked>  |      x      |      x      |
                              +-------------+-------------+
         TaskTAsync<INormal>  |      o      |      x      |
         TaskTAsync<IHacked>  |      o      |      o      |
                              +-------------+-------------+
   await TaskTAsync<INormal>  |      o      |      x      |
   await TaskTAsync<IHacked>  |      o      |      o      |
                              +-------------+-------------+
Comment 3 Brendan Zagaeski (Xamarin Support) 2013-06-19 19:02:14 UTC
Note that for each `Task<T>` case in Test cases #2, the result is the same as the corresponding `Task` case.

Additionally, the error message for all the cases marked "x" is the same as the original error message: "Attempting to JIT compile method..."
Comment 6 Marek Safar 2013-07-17 02:24:19 UTC
This is runtime issue or limitation (check with Zoltan)
Comment 7 Zoltan Varga 2013-07-17 15:11:59 UTC
Thanks for the tests. There are currently problems with calling async generic methods in a generic way,
i.e. AMethod<AConcreteType> works, while AMethod<T> fails.
Comment 8 Zoltan Varga 2013-07-22 20:03:27 UTC
The tests run fine with mono master, so this will be fixed in a future release of xamarin.ios.
Comment 9 Ricky Kaare Engelharth 2013-08-13 02:34:03 UTC
I just ran into the same issue, but found a workaround that allows me to keep my original method signature.

One of the methods causing the problem for me was this one:

    public async Task<T> GetAsync<T>(string url) where T : ServiceResource
    {
        using (var client = Session.Current.ServiceClient.Create())
        {
            return await client.GetAsync<T>(url);
        }
    }

And I can make it work by  moving the await to an internal method without the generic parameter, like this:

    public Task<T> GetAsync<T>(string url) where T : ServiceResource
    {
        return GetAsync(typeof(T), url).ContinueWith<T>(t => (T)t.Result);
    }

    private async Task<Object> GetAsync(Type outputType, string url) 
    {
        using (var client = Session.Current.ServiceClient.Create())
        {
            return await client.GetAsync(outputType, url);
        }
    }

I still hope for a fix though.
Comment 10 Seifer 2013-08-14 09:38:14 UTC
I have found the next working workaround:

    public Task<T> GetAsync<T>(string url) where T : ServiceResource
    {
        var taskSource = new TaskCompletionSource<T>();

        using (var client = Session.Current.ServiceClient.Create())
        {
            client.GetAsync<T>(url).ContinueWith(t => {
                 if (t.IsCanceled) taskSource.SetCanceled();
                 else if (t.IsFaulted) taskSource.SetException(t.Exception);
                 else if (t.IsCompleted) taskSource.SetResult(t.Result);
            });
            return taskSource.Task;
        }
    }
Comment 11 PJ 2013-11-19 16:44:42 UTC
This bug was targeted for a past milestone, moving to the next non-hotfix active milestone.
Comment 13 Zoltan Varga 2014-03-17 18:33:33 UTC
@Valentin: What was the error message ? Is there a desk case for it ?
Comment 14 André Bires 2014-03-18 07:48:18 UTC
We were getting the same exception that related above, something like:

Asynchronous generic call from interface
System.ExecutionEngineException: Attempting to JIT compile method
'(...)' while running with --aot-only.
Seehttp://docs.xamarin.com/ios/about/limitations for more information.

I've send the sample codes to Valetin (the problematic version and the fix - using one of the workarounds in this page) but I can provide specific details if you need.
Comment 15 Zoltan Varga 2014-03-18 15:09:55 UTC
What is the name of the method in the 'Attemptin to JIT compile method' message ?
Comment 16 André Bires 2014-03-19 15:05:14 UTC
Unhandled Exception:

System.ExecutionEngineException: Attempting to JIT compile method 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<Cemig.PocketAgency.Contract.Models.Account>:Start<Cemig.PocketAgency.Http.Providers.BaseProvider/<ActionAsync>d__0`1<Cemig.PocketAgency.Contract.Models.Account>> (Cemig.PocketAgency.Http.Providers.BaseProvider/<ActionAsync>d__0`1<Cemig.PocketAgency.Contract.Models.Account>&)' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.
Comment 17 GouriKumari 2016-01-11 21:50:00 UTC
I retested with the attached testcase and the exception is no longer occurring.  However, the generic call from interface returns "Never Reached". I am closing this message and if the results are not expected one, please reopen it. 

##Test Log: https://gist.github.com/GouriKumari/1a2beef127d5a9de7197

## Test Env:

=== Xamarin Studio ===

Version 5.10.1 (build 6)
Installation UUID: 5ed3a124-4b77-4c6f-beb9-c830fd815e2a
Runtime:
	Mono 4.2.1 (explicit/6dd2d0d)
	GTK+ 2.24.23 (Raleigh theme)

	Package version: 402010102

=== Xamarin.Profiler ===

Not Installed

=== Xamarin.Android ===

Version: 6.0.0.34 (Starter Edition)
Android SDK: /Users/gourikumari/Library/Developer/Xamarin/android-sdk-mac_x86
	Supported Android versions:
		2.3   (API level 10)
		4.0.3 (API level 15)
		4.4   (API level 19)

SDK Tools Version: 22.6.3
SDK Platform Tools Version: 19.0.2
SDK Build Tools Version: 19.1

Java SDK: /usr
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

=== Xamarin Android Player ===

Not Installed

=== Apple Developer Tools ===

Xcode 7.2 (9548)
Build 7C68

=== Xamarin.Mac ===

Version: 2.4.0.109 (Starter Edition)

=== Xamarin.iOS ===

Version: 9.5.1.143 (Business Edition)
Hash: 28b5d0d
Branch: master
Build date: 2016-01-11 07:30:34-0500

=== Build Information ===

Release ID: 510010006
Git revision: 0b60eecdb531933734519c13257d16a780274aab
Build date: 2015-12-04 20:28:20-05
Xamarin addins: 9876fd7c9837977178411ec7375b4352c0a0d6af
Build lane: monodevelop-lion-cycle6-baseline

=== Operating System ===

Mac OS X 10.10.5

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