Bug 6821 - Invalid IL code in (wrapper dynamic-method) / DynamicMethod.CreateDelegate
Summary: Invalid IL code in (wrapper dynamic-method) / DynamicMethod.CreateDelegate
Status: RESOLVED FIXED
Alias: None
Product: Runtime
Classification: Mono
Component: JIT ()
Version: unspecified
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-09-01 03:45 UTC by Ian Battersby
Modified: 2012-09-10 15:41 UTC (History)
5 users (show)

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


Attachments
Trace from invoking JsonFx through tests (8.38 KB, text/plain)
2012-09-01 03:45 UTC, Ian Battersby
Details
Example Demo App illustrating this issue (5.07 KB, application/zip)
2012-09-04 17:05 UTC, Ian Battersby
Details


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 GitHub or Developer Community 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 FIXED

Description Ian Battersby 2012-09-01 03:45:28 UTC
Created attachment 2442 [details]
Trace from invoking JsonFx through tests

Fair to say this is a bit above my knowledge-grade but am desperate to fix JsonFx for our project to stay Mono-compatible. Any help/guidance would be gratefully received, a fix even better!

Receiving "Invalid IL code in (wrapper dynamic-method)" in a library that uses dynamic generation (issue discussed on their list here - https://github.com/jsonfx/jsonfx/issues/8).

Trace:-
    xUnit.net console test runner (32-bit .NET 4.0.30319.17020)
    Copyright (C) 2007-11 Microsoft Corporation.

    xunit.dll:     Version 1.9.0.1566
    Test assembly: /Users/ian/code/Simple.Web/test/Simple.Web.JsonFx.Tests.dll

    Simple.Web.JsonFx.Tests.JsonFxContentTypeHandlerTests.PicksUpOrdersLinkFromCustomers [FAIL]
       JsonFx.Serialization.SerializationException : Invalid IL code in (wrapper dynamic-method) object: (object): IL_0001: call      0x00000001
       
       
       ---- System.InvalidProgramException : Invalid IL code in (wrapper dynamic-method) object: (object): IL_0001: call      0x00000001
       Stack Trace:
         at JsonFx.Serialization.DataWriter`1[JsonFx.Model.ModelTokenType].Write (System.Object data, System.IO.TextWriter output) [0x00000] in <filename unknown>:0 
         at Simple.Web.JsonFx.JsonMediaTypeHandler.Write (IContent content, System.IO.Stream outputStream) [0x00000] in <filename unknown>:0 
         at Simple.Web.JsonFx.Tests.JsonFxContentTypeHandlerTests.PicksUpOrdersLinkFromCustomers () [0x00000] in <filename unknown>:0 
         at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
         at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0 
       ----- Inner Stack Trace -----
         at (wrapper managed-to-native) System.Delegate:CreateDelegate_internal (System.Type,object,System.Reflection.MethodInfo,bool)
         at System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method, Boolean throwOnBindFailure, Boolean allowClosed) [0x00000] in <filename unknown>:0 
         at System.Delegate.CreateDelegate (System.Type type, System.Reflection.MethodInfo method, Boolean throwOnBindFailure) [0x00000] in <filename unknown>:0 
         at System.Delegate.CreateDelegate (System.Type type, System.Reflection.MethodInfo method) [0x00000] in <filename unknown>:0 
         at System.Reflection.Emit.DynamicMethod.CreateDelegate (System.Type delegateType) [0x00000] in <filename unknown>:0 
         at JsonFx.CodeGen.DynamicMethodGenerator.GetPropertyGetter (System.Reflection.PropertyInfo propertyInfo) [0x00000] in <filename unknown>:0 
         at JsonFx.Serialization.Resolvers.MemberMap..ctor (System.Reflection.PropertyInfo propertyInfo, DataName dataName, JsonFx.Serialization.Resolvers.ValueIgnoredDelegate isIgnored) [0x00000] in <filename unknown>:0 
         at JsonFx.Serialization.Resolvers.ResolverCache.BuildMap (System.Type objectType, IDictionary`2& maps) [0x00000] in <filename unknown>:0 
         at JsonFx.Serialization.Resolvers.ResolverCache.LoadTypeName (System.Type type) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetTypeName (System.Object value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetArrayTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, IEnumerable value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, System.Object value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetObjectTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, DataName typeName, IEnumerator`1 enumerator) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetArrayTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, IEnumerable value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, System.Object value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetArrayTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, IEnumerable value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, System.Object value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetTokens (System.Object value) [0x00000] in <filename unknown>:0 
         at JsonFx.Serialization.DataWriter`1[JsonFx.Model.ModelTokenType].Write (System.Object data, System.IO.TextWriter output) [0x00000] in <filename unknown>:0

    Tests complete: 1 of 2
    Simple.Web.JsonFx.Tests.JsonFxContentTypeHandlerTests.PicksUpOrdersLinkFromCustomer [FAIL]
       JsonFx.Serialization.SerializationException : Invalid IL code in (wrapper dynamic-method) object: (object): IL_0001: call      0x00000001
       
       
       ---- System.InvalidProgramException : Invalid IL code in (wrapper dynamic-method) object: (object): IL_0001: call      0x00000001
       Stack Trace:
         at JsonFx.Serialization.DataWriter`1[JsonFx.Model.ModelTokenType].Write (System.Object data, System.IO.TextWriter output) [0x00000] in <filename unknown>:0 
         at Simple.Web.JsonFx.JsonMediaTypeHandler.Write (IContent content, System.IO.Stream outputStream) [0x00000] in <filename unknown>:0 
         at Simple.Web.JsonFx.Tests.JsonFxContentTypeHandlerTests.PicksUpOrdersLinkFromCustomer () [0x00000] in <filename unknown>:0 
         at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
         at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0 
       ----- Inner Stack Trace -----
         at (wrapper managed-to-native) System.Delegate:CreateDelegate_internal (System.Type,object,System.Reflection.MethodInfo,bool)
         at System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method, Boolean throwOnBindFailure, Boolean allowClosed) [0x00000] in <filename unknown>:0 
         at System.Delegate.CreateDelegate (System.Type type, System.Reflection.MethodInfo method, Boolean throwOnBindFailure) [0x00000] in <filename unknown>:0 
         at System.Delegate.CreateDelegate (System.Type type, System.Reflection.MethodInfo method) [0x00000] in <filename unknown>:0 
         at System.Reflection.Emit.DynamicMethod.CreateDelegate (System.Type delegateType) [0x00000] in <filename unknown>:0 
         at JsonFx.CodeGen.DynamicMethodGenerator.GetPropertyGetter (System.Reflection.PropertyInfo propertyInfo) [0x00000] in <filename unknown>:0 
         at JsonFx.Serialization.Resolvers.MemberMap..ctor (System.Reflection.PropertyInfo propertyInfo, DataName dataName, JsonFx.Serialization.Resolvers.ValueIgnoredDelegate isIgnored) [0x00000] in <filename unknown>:0 
         at JsonFx.Serialization.Resolvers.ResolverCache.BuildMap (System.Type objectType, IDictionary`2& maps) [0x00000] in <filename unknown>:0 
         at JsonFx.Serialization.Resolvers.ResolverCache.LoadTypeName (System.Type type) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetTypeName (System.Object value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetArrayTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, IEnumerable value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, System.Object value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetObjectTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, DataName typeName, IEnumerator`1 enumerator) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetArrayTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, IEnumerable value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetTokens (System.Collections.Generic.List`1 tokens, ICycleDetector detector, System.Object value) [0x00000] in <filename unknown>:0 
         at JsonFx.Model.ModelWalker.GetTokens (System.Object value) [0x00000] in <filename unknown>:0 
         at JsonFx.Serialization.DataWriter`1[JsonFx.Model.ModelTokenType].Write (System.Object data, System.IO.TextWriter output) [0x00000] in <filename unknown>:0

    Tests complete: 2 of 2
    2 total, 2 failed, 0 skipped, took 0.456 seconds


Implementation:-
		/// <summary>
		/// Creates a field getter delegate for the specified property or field
		/// </summary>
		/// <param name="memberInfo">PropertyInfo or FieldInfo</param>
		/// <returns>GetterDelegate for property or field, null otherwise</returns>
		/// <remarks>
		/// Note: use with caution this method will expose private and protected constructors without safety checks.
		/// </remarks>
		public static GetterDelegate GetGetter(MemberInfo memberInfo)
		{
			if (memberInfo is PropertyInfo)
			{
				return DynamicMethodGenerator.GetPropertyGetter((PropertyInfo)memberInfo);
			}

			if (memberInfo is FieldInfo)
			{
				return DynamicMethodGenerator.GetFieldGetter((FieldInfo)memberInfo);
			}

			return null;
		}

		/// <summary>
		/// Creates a property getter delegate for the specified property
		/// </summary>
		/// <param name="propertyInfo"></param>
		/// <returns>GetterDelegate if property CanRead, otherwise null</returns>
		/// <remarks>
		/// Note: use with caution this method will expose private and protected constructors without safety checks.
		/// </remarks>
		public static GetterDelegate GetPropertyGetter(PropertyInfo propertyInfo)
		{
			if (propertyInfo == null)
			{
				throw new ArgumentNullException("propertyInfo");
			}

			if (!propertyInfo.CanRead)
			{
				return null;
			}

			MethodInfo methodInfo = propertyInfo.GetGetMethod(true);
			if (methodInfo == null)
			{
				return null;
			}

			Module module = methodInfo.DeclaringType.Module;

			// Create a dynamic method with a return type of object, and one parameter taking the instance.
			DynamicMethod dynamicMethod = new DynamicMethod(
				"",//propertyInfo.DeclaringType.FullName+".get_"+propertyInfo.Name,
				typeof(object),
				new Type[] { typeof(object) }
#if !SILVERLIGHT
				, module,
				true
#endif
				);

			// Get an ILGenerator and emit a body for the dynamic method,
			// using a stream size larger than the IL that will be emitted.
			ILGenerator il = dynamicMethod.GetILGenerator(64 * 5);
			if (!methodInfo.IsStatic)
			{
				// Load the target instance onto the evaluation stack
				il.Emit(OpCodes.Ldarg_0);
			}
			// Call the method that returns void
			//il.Emit(methodInfo.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, methodInfo);
			il.Emit(OpCodes.Call, methodInfo);
			if (propertyInfo.PropertyType.IsValueType)
			{
				// Load the return value as a reference type
				il.Emit(OpCodes.Box, propertyInfo.PropertyType);
			}
			// return property value from the method
			il.Emit(OpCodes.Ret);

			// produce a delegate that we can then call
			return (GetterDelegate)dynamicMethod.CreateDelegate(typeof(GetterDelegate));
		}

JsonFx on GitHub:-
https://github.com/jsonfx/jsonfx
Comment 1 Miguel de Icaza [MSFT] 2012-09-02 12:41:45 UTC
To debug this, you could try dumping the value of "methodInfo" which would tell us what kind of method you are trying to compile.

You might also want to print the "instance" of the object (whatever is loaded in Ldarg_0), maybe you are invoking a method in an incompatible object
Comment 2 Miguel de Icaza [MSFT] 2012-09-02 12:42:35 UTC
Also, when I said "a simple sample test case", i meant a standalone app that exhibits the problem.   

Otherwise the time required to investigate this bug takes too much time.
Comment 3 Miguel de Icaza [MSFT] 2012-09-02 12:53:28 UTC
See this other bug: 
https://bugzilla.xamarin.com/show_bug.cgi?id=6467

It could be a duplicate if you guys are sharing code.
Comment 4 Ian Battersby 2012-09-02 17:58:25 UTC
Yes, this certainly looks the same issue experienced by ServiceStack w/JsonFX.

Apologies, should have opened with a sample (standalone) app. Working on it now and hope to have something back in the next 24-48 hours; drawn a blank so far but persevering.
Comment 5 Songtive Team 2012-09-04 04:36:10 UTC
Ian, I'm ServiceStack core member. Miguel asked to help with the bug. 
In my case the problem was with the:

var generator = setter.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
generator.Emit(OpCodes.Ldarg_1);

The  thing is that property indexer contains two IL parameters (index,
value) instead of one as in setter method.  Mono  is quite strict for invalid code
that's why I got the error. The  fix was  quite easy - indexed properties should be excluded with:

type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance)
                .Where(t => t.GetIndexParameters().Length == 0) // ignore indexed properties
                .ToArray();

HTH
Comment 6 Stephen McKamey 2012-09-04 12:29:22 UTC
From the stack trace, this is the method which is failing for you:

https://github.com/jsonfx/jsonfx/blob/master/src/JsonFx/CodeGen/DynamicMethodGenerator.cs#L162

I've tried in the past to fix this but haven't had a Mono environment going to create a repro case. If you are able to fix this by tweaking the OpCodes and it still works on Windows I will happily merge and re-release new binaries. Here is the JsonFx bug:

https://github.com/jsonfx/jsonfx/issues/8

As Miguel says, it needs to be isolated. Perhaps ripping just that method I linked to will be sufficient to repro against a reflected PropertyInfo.
Comment 7 Ian Battersby 2012-09-04 15:43:57 UTC
Thanks Sergey, that also fixes the problem for me but have been trying to work out why and you've highlighted it right there with the two IL parameters.

Stephen, that is indeed the method failing and I did rip it out to replicate the issue in the demo app for Miguel but mysteriously it began to work. There is no question this was due to a case of PEBCAK so am back on this evening to try again; thankfully I have both environments at my fingertips. Once I've done this I'll see if I can get anywhere tweaking the OpCodes.

Much appreciate the help guys :-)
Comment 8 Miguel de Icaza [MSFT] 2012-09-04 16:07:32 UTC
Will close the bug for now.

Thanks Sergey!
Comment 9 Ian Battersby 2012-09-04 17:05:14 UTC
Created attachment 2458 [details]
Example Demo App illustrating this issue

This bug is obviously closed now, but attached is a quick example for completeness.
Comment 10 Stephen McKamey 2012-09-10 15:23:54 UTC
Ian, I added Sergey's suggestion for filtering out indexer properties. Can you test if that has solved your issue? A response on the originally filed issue would be most helpful:

https://github.com/jsonfx/jsonfx/issues/8
Comment 11 Ian Battersby 2012-09-10 15:31:12 UTC
Hi Stephen. This does indeed fix our issue, in fact I ended up with this workaround:

https://github.com/markrendle/Simple.Web/blob/master/Simple.Web.JsonFx/MonoCompatResolverStrategy.cs

I was trying to resolve the OpCodes opposed to just excluding the indexer properties, but if that's as easy for you guys then we can drop the above once released.
Comment 12 Stephen McKamey 2012-09-10 15:41:48 UTC
Hi Ian, very good. The OpCode needed would just require an additional index parameter. But indexer properties don't really make sense in the context of type serialization unless the type should be serialized as a JSON array. So excluding them everywhere works.

Thanks Sergey, Miguel and Ian for tracking this one down. It was only showing up for Mono users since the extra generated code was never actually being used. .NET must not verify the IL until execution rather than on generation.