Bug 59401 - MethodInfo.Invoke fails for generic methods with large arguments on armv7
Summary: MethodInfo.Invoke fails for generic methods with large arguments on armv7
Status: CONFIRMED
Alias: None
Product: iOS
Classification: Xamarin
Component: Mono runtime / AOT compiler (show other bugs)
Version: XI 10.99 (xcode9)
Hardware: PC Windows
: --- normal
Target Milestone: Future Cycle (TBD)
Assignee: Zoltan Varga
URL:
Depends on:
Blocks:
 
Reported: 2017-09-11 21:28 UTC by henry.lisowski
Modified: 2017-09-20 14:48 UTC (History)
5 users (show)

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


Attachments
Test Case (10.72 KB, application/zip)
2017-09-12 02:48 UTC, Alex Soto [MSFT]
Details

Description henry.lisowski 2017-09-11 21:28:38 UTC
I have two structs, Vector4 and Matrix. Vector4 has 4 floats, Matrix has 16 floats.

I have another class called MagicProperty.
public class MagicProperty<T>{
    public T Value{get;set;}
    public MagicProperty(T val){
        Value = val;
    }
}
When creating instances of MagicProperty using Activator.CreateInstance, MagicProperty<Vector4> succeeds but MagicProperty<Matrix> fails.

For reference:

//Make sure constructors don't get removed
MagicProperty<Vector4> vecProp = new MagicProperty<Vector4>(new Vector4());
MagicProperty<Matrix> matrixProp = new MagicProperty<Matrix>(new Matrix());

Type vecType = typeof(MagicProperty<Vector4>);
Type matrType = typeof(MagicProperty<Matrix>);
//Works fine
object vecResult = Activator.CreateInstance(vecType, new Vector4());
//Fails
object result = Activator.CreateInstance(matrType, new Matrix());

I've used reflection to confirm that the constructor for MagicProperty does in fact exist. 

It looks like, because Matrix is "big" it's actually trying to split it up into multiple parameters maybe? Which means it no longer matches the method definition as expected.

The actual error is the following:

Attempting to JIT compile method '(wrapper runtime-invoke) :runtime_invoke_void__this___Matrix (object,intptr,intptr,intptr)' while running in aot-only mode. See https://developer.xamarin.com/guides/ios/advanced_topics/limitations/ for more information.
(System.ExecutionEngineException)
at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&)
at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00002] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.10.0.36/src/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:661


Here's the logs from where it fails:

2017-09-10 20:40:37.106 BugTestBench[313:29267] Unhandled managed exception:
Exception has been thrown by the target of an invocation. (System.Reflection.TargetInvocationException)
at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00012] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.10.0.36/src/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:667 
at System.Reflection.MonoCMethod.DoInvoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0007a] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.10.0.36/src/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:652 
at System.Reflection.MonoCMethod.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, Sys
tem.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.10.0.36/src/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:680 
at System.RuntimeType.CreateInstanceImpl (System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes, System.Threading.StackCrawlMark& stackMark) [0x001a7] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.10.0.36/src/mono/mcs/class/referencesource/mscorlib/system/rttype.cs:5419 
at System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes) [0x00064] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.10.0.36/src/mono/mcs/class/referencesource/mscorlib/system/activator.cs:107 
at System.Activator.CreateIns
tance (System.Type type, System.Object[] args) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.10.0.36/src/mono/mcs/class/referencesource/mscorlib/system/activator.cs:112
Comment 1 Alex Soto [MSFT] 2017-09-12 02:48:36 UTC
Created attachment 24692 [details]
Test Case
Comment 2 Alex Soto [MSFT] 2017-09-12 02:52:14 UTC
Hello Henry

I have tried to reproduce the issue based on your instructions without luck, it works fine for me on both simulator and device.

Please provide all your version information and if possible test the attached test case in comment #2 and modify it to your own crasher version or include your own test case.

The easiest way to get exact version information:

- On Visual Studio for Mac: "Visual Studio" menu, "About Visual Studio" item, "Show Details" button.

- On Visual Studio for Windows: "Help menu", "About Microsoft Visual Studio" item.
Then copy/paste the version information (you can use the "Copy Information" button).
Comment 3 henry.lisowski 2017-09-15 04:47:15 UTC
VS (Windows) Version: 15.2 (26430.14)

So I downloaded your attached test project, and initially I couldn't deploy it to my device.  I looked into it and I'm running an iPhone 5C, which requires ARMv7.  Once I added that to the project file (Changing <MtouchArch>ARM64</MtouchArch> to <MtouchArch>ARMv7, ARM64</MtouchArch>) It deployed to my device, and crashed the same way I described above.  It looks like this might be a bug that only happens on ARMv7, but since this is the only test device I have I can't confirm that it doesn't happen on ARM64.  Do you have an ARMv7 device you could try it on?
Comment 4 Alex Soto [MSFT] 2017-09-15 14:02:02 UTC
Indeed I can replicate the issue with an iPhone 5 and the instructions provided in comment #3

{System.ExecutionEngineException: Attempting to JIT compile method '(wrapper runtime-invoke) <Module>:runtime_invoke_void__this___Matrix (object,intptr,intptr,intptr)' while running in aot-only mode. See https://developer.xamarin.com/guides/ios/advanced_topics/limitations/ for more information.

  at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&)
  at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00002] in /Users/Alex/monotouch/xcode9/xamarin-macios/external/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:661 }
Comment 5 Zoltan Varga 2017-09-15 15:36:34 UTC
This happens because the AOT compiler doesn't know about the MagicProperty<Matrix>.ctor () method, and the generic code to handle this can't handle certain types like Matrix.
Comment 6 henry.lisowski 2017-09-15 17:43:02 UTC
What's different about the Matrix that would cause the failure when Vector4 does not?  They're both a struct with only floats, the only difference being a Matrix has 4 times the amount of floats.
Comment 7 Zoltan Varga 2017-09-15 17:51:52 UTC
Thats the reason.
Comment 8 henry.lisowski 2017-09-15 18:10:37 UTC
So it's a size issue?  If a struct is over a certain size the generic code breaks? Or is it the number of properties on the struct?  (Just trying to understand the problem a little better)
Comment 9 Zoltan Varga 2017-09-15 18:42:25 UTC
Its the size of the struct. Referencing the actual method might work around the issue, i.e. writing 
var v = new MagicProperty<Matrix> ();
somewhere.
Comment 10 henry.lisowski 2017-09-15 20:23:22 UTC
Calling the actual constructor of MagicProperty<Matrix> works fine.  The test case I'm using does this:

//Make sure constructors don't get removed
MagicProperty<Vector4> vecProp = new MagicProperty<Vector4>(new Vector4());
MagicProperty<Matrix> matrixProp = new MagicProperty<Matrix>(new Matrix());

Type vecType = typeof(MagicProperty<Vector4>);
Type matrType = typeof(MagicProperty<Matrix>);
//Works fine
object vecResult = Activator.CreateInstance(vecType, new Vector4());
//Fails
object result = Activator.CreateInstance(matrType, new Matrix());

So the constructor for MagicProperty<Matrix> isn't getting removed by linking (I even verified that using reflection at runtime).

So I can technically get around this by directly calling the constructor, but my current scenario requires using Activator.CreateInstance.  My current workaround has been to use a class version of Matrix instead of a struct, which works but creates a ton of garbage every frame that I'd like to avoid if possible.
Comment 11 Zoltan Varga 2017-09-19 20:53:19 UTC

*** This bug has been marked as a duplicate of bug 59184 ***

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