Bug 40608 - AOT failure when converting native int to object
Summary: AOT failure when converting native int to object
Status: RESOLVED ANSWERED
Alias: None
Product: iOS
Classification: Xamarin
Component: Mono runtime / AOT compiler ()
Version: XI 9.8 (tvOS / C7)
Hardware: PC Windows
: Normal normal
Target Milestone: (C7)
Assignee: Zoltan Varga
URL:
Depends on:
Blocks:
 
Reported: 2016-04-21 12:50 UTC by Virgile Bello
Modified: 2016-05-12 18:56 UTC (History)
3 users (show)

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

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED ANSWERED

Description Virgile Bello 2016-04-21 12:50:10 UTC
I have the following IL code:

.method public hidebysig static 
	object PtrToObject (
		native int obj
	) cil managed 
{
	// Method begins at RVA 0x4dd4
	// Code size 8 (0x8)
	.maxstack 1
	.locals (
		[0] object
	)

	IL_0000: ldarg obj
	IL_0004: conv.i
	IL_0005: stloc.0
	IL_0006: ldloc.0
	IL_0007: ret
}


This was working with Xamarin.iOS C6, but not with C7 anymore:

System.ExecutionEngineException: Attempting to JIT compile method 'SiliconStudio.Xenko.Updater.UpdateEngineHelper:PtrToObject (intptr)' while running with --aot-only

I agree this isn't standard C#/.NET code, but it is still valid IL code (and one of the only way to convert a pinned intptr back to object -- the other workaround is using FieldOffset union).

Ideally, this kind of piece of code should be added to a new aot-tests.il (I have a few others similar piece of IL code on which I often have regressions).
Comment 1 Virgile Bello 2016-04-21 12:50:49 UTC
Additional note, the stloc.0/ldloc.0 is superfluous, but C6 wouldn't work without.
Comment 2 Virgile Bello 2016-04-21 13:59:07 UTC
Sorry, conv.i is not necessary as well (I was trying a variant). Still happens with or without anyway.
Comment 3 Virgile Bello 2016-04-21 15:42:15 UTC
After some checking, it seems to be triggered by target_type_is_incompatible() checks.

It happens for both:
(1) stloc.0 (native int (stack) => object local)
(2) ret (native int (stack) => return type object)

Since (1) was working with C6, I tried to look for a change in the related code but couldn't find anything (except if maybe dont_verify was true for some reason?), I still have the same bug on 4.2.

Is there some way to disable some of the checks when we know they are OK to do? I would rather avoid doing the FieldOffset trick.

Here is some test code that can be added in mono/mini/iltests.il:

 .method static public int32 test_0_ptr_to_object_1 () il managed {
  .locals init ( object obj )
  ldc.i4.0
  conv.i
  stloc.0
  ldloc.0
  pop
  ldc.i4.0
  ret
 }

and

 .method static public object PtrToObject(native int) il managed {
  ldarg.0
  ret
 }

 .method static public int32 test_0_ptr_to_object_2 () il managed {
  .locals init ( object obj )
  ldc.i4.0
  conv.i
  call object Tests::PtrToObject(native int)
  pop
  ldc.i4.0
  ret
 }
Comment 4 Zoltan Varga 2016-04-21 21:43:30 UTC
Something like this will work:

  		  .locals init ( object obj )
		  ldloca.s 0
		  ldc.i4.0
		  conv.i
		  stind.i
Comment 5 Virgile Bello 2016-04-22 08:33:24 UTC
Thanks, this workaround seems to work with both Mono and .NET Native (CoreCLR/RT test pending)!
Didn't try this as I thought it would check type the same way as return/stloc.
I will investigate little bit more and add this pattern to iltests.il to make sure it doesn't break in the future

Still, do you think it's a bad idea to allow the simpler form work as well? (it has the advantage of working with value types too)

 ldarg.0
 ret

Ideally, runtime should be compatible:
- object => native int is allowed by Mono, .NET and .NET native (compatible)
- native int => object is allowed by .NET and .NET native but not by Mono nor CoreCLR (incompatible)

Since we are running on many platforms (including Win10 UWP AOT), it is quite difficult to find proper IL that works on every runtime variants, and we would rather avoid having different IL for different platforms.

Note that CoreCLR doesn't support it either but since .NET does it should be easy to have it included.

Thanks for your help.
Comment 6 Zoltan Varga 2016-04-23 01:45:24 UTC
The form in comment #4 is valid il, i.e. it should be accepted by all .net implementations. This is because ldloca pushes a managed pointer (&) on the stack, which no longer has a type associated with it.