Bug 15440 - Linker strips default constructor which was not stripped in 6.x releases
Summary: Linker strips default constructor which was not stripped in 6.x releases
Status: RESOLVED FEATURE
Alias: None
Product: iOS
Classification: Xamarin
Component: Tools ()
Version: 7.0.2.x
Hardware: PC Mac OS
: --- minor
Target Milestone: Untriaged
Assignee: Sebastien Pouliot
URL:
Depends on:
Blocks:
 
Reported: 2013-10-16 14:16 UTC by Michael Bayne
Modified: 2015-04-16 11:00 UTC (History)
2 users (show)

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


Attachments
Example project that crashes. (4.19 MB, application/zip)
2013-10-16 14:16 UTC, Michael Bayne
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 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 FEATURE

Description Michael Bayne 2013-10-16 14:16:20 UTC
Created attachment 5152 [details]
Example project that crashes.

IKVM has the following code:

namespace IKVM.NativeCode.sun.reflect {
	public sealed class State {
		internal int Value;
	}

	static class Reflection {
		private static readonly ConditionalWeakTable<MethodBase, State> isHideFromJavaCache = new ConditionalWeakTable<MethodBase, State>();

		internal static bool IsHideFromJava(MethodBase mb) {
			State state = isHideFromJavaCache.GetOrCreateValue(mb);
			if (state.Value == 0) {
				state.Value = IsHideFromJavaImpl(mb);
			}
			return state.Value == 1;
		}
// ...
}

which worked fine in MonoTouch 6.x releases, with linking enabled. But in 7.x, I get the following error when this code is triggered:

Oct 16 11:09:23 Wocket hello[2652] <Warning>: Unhandled managed exception: Default constructor not found for type IKVM.NativeCode.sun.reflect.State (System.MissingMethodException)
	  at System.Activator.CreateInstance (System.Type type, Boolean nonPublic) [0x00000] in <filename unknown>:0 
	  at System.Activator.CreateInstance (System.Type type) [0x00000] in <filename unknown>:0 
	  at System.Activator.CreateInstance[State] () [0x00000] in <filename unknown>:0 
	  at System.Runtime.CompilerServices.ConditionalWeakTable`2[System.Reflection.MethodBase,IKVM.NativeCode.sun.reflect.State].<GetOrCreateValue>m__1C (System.Reflection.MethodBase k) [0x00000] in <filename unknown>:0 
	  at System.Runtime.CompilerServices.ConditionalWeakTable`2[System.Reflection.MethodBase,IKVM.NativeCode.sun.reflect.State].GetValue (System.Reflection.MethodBase key, System.Runtime.CompilerServices.CreateValueCallback createValueCallback) [0x00000] in <filename unknown>:0 
	  at System.Runtime.CompilerServices.ConditionalWeakTable`2[System.Reflection.MethodBase,IKVM.NativeCode.sun.reflect.State].GetOrCreateValue (System.Reflection.MethodBase key) [0x00000] in <filename unknown>:0 
	  at IKVM.NativeCode.sun.reflect.Reflection.IsHideFromJava (System.Reflection.MethodBase mb) [0x00000] in <filename unknown>:0 
	  at IKVM.Internal.ExceptionHelper.IsHideFromJava (System.Reflection.MethodBase mb) [0x00000] in <filename unknown>:0 
	  at IKVM.Internal.ExceptionHelper+ExceptionInfoHelper.Append (System.Collections.Generic.List`1 stackTrace, System.Diagnostics.StackTrace st, Int32 skip, Boolean isLast) [0x00000] in <filename unknown>:0 
	  at IKVM.Internal.ExceptionHelper+ExceptionInfoHelper.get_StackTrace (System.Exception t) [0x00000] in <filename unknown>:0 
	  at IKVM.Internal.ExceptionHelper.computeStackTrace (System.Exception x, System.Diagnostics.StackTrace part1, System.Diagnostics.StackTrace part2) [0x00000] in <filename unknown>:0 
	  at java.lang.Throwable.getOurStackTrace () [0x00000] in <filename unknown>:0 
	  at java.lang.Throwable.getStackTrace () [0x00000] in <filename unknown>:0 
	  at java.lang.Throwable.instancehelper_getStackTrace (System.Exception this) [0x00000] in <filename unknown>:0 
	  at IKVM.Internal.ExceptionHelper.BuildStackTrace (System.Exception x) [0x00000] in <filename unknown>:0 
	  at IKVM.Internal.ExceptionHelper.printStackTrace (System.Exception x, java.io.PrintWriter printWriter) [0x00000] in <filename unknown>:0 
	  at java.lang.Throwable.printStackTrace (java.io.PrintWriter s) [0x00000] in <filename unknown>:0 
	  at java.lang.Throwable.instancehelper_printStackTrace (System.Exception this, java.io.PrintWriter s) [0x00000] in <filename unknown>:0 
	  at playn.ios.IOSLog.logImpl (playn.core.Level level, System.String msg, System.Exception e) [0x00000] in <filename unknown>:0 
	  at playn.core.LogImpl.log (playn.core.Level level, System.String msg, System.Exception e) [0x00000] in <filename unknown>:0 
	  at playn.core.LogImpl.warn (System.String msg, System.Exception e) [0x00000] in <filename unknown>:0 
	  at playn.sample.hello.core.HelloGame$1.onPointerEnd (Event event) [0x00000] in <filename unknown>:0 
	  at playn.core.PointerImpl.onPointerEnd (playn.core.Impl event, Boolean preventDefault) [0x00000] in <filename unknown>:0 
	  at playn.ios.IOSPointer.onTouchesEnded (MonoTouch.Foundation.NSSet nss, MonoTouch.UIKit.UIEvent uie) [0x00000] in <filename unknown>:0 
	  at playn.ios.IOSRootViewController.TouchesEnded (MonoTouch.Foundation.NSSet nss, MonoTouch.UIKit.UIEvent uie) [0x00000] in <filename unknown>:0 
	  at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
	  at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00000] in <filename unknown>:0 
	  at playn.sample.hello.ios.Application.Main (System.String[] args) [0x00000] in <filename unknown>:0 


Maybe this is just a result of linking being less conservative in 7.x but I wanted to bring it up in case it was an unintentional regression of some capability of magically noticing the use of ConditionalWeakTable.GetOrCreateValue.

I've also attached a project that demonstrates the crash if that's useful. You have to build and deploy it to a device, and then tap anywhere on the screen to trigger the crash.
Comment 1 Sebastien Pouliot 2013-10-16 14:31:54 UTC
I'll have a look at your test case. Thanks for providing one.

Out of curiosity do you recall which 6.x version worked ?

FWIW there's almost no change in the linker between 6.4.x and 7.0. However there were many (minor) changes between 6.2.x and 6.4 (e.g. new version of Cecil, adjustments for mono 3.0 BCL) but the behaviour should be identical.

i.e. normally default constructor will be removed if:
* unused; or
* not obviously used for serialization (e.g. [Serializable] or [Xml*] attributes)

but nothing magical wrt ConditionalWeakTable (not that I'm denying magic is being used elsewhere ;-)
Comment 2 Michael Bayne 2013-10-16 14:43:59 UTC
I don't know the exact release, but I think it was 6.2.x, or in any case it was close to the final release before the move to the Mono 3 runtime.

I was also surprised (after looking at the code) that it worked in the first place, so maybe it was some sort of fluke.

The full source for IKVM, if that turns out to be useful, is here:

https://github.com/samskivert/ikvm-monotouch

The file in question here:

https://github.com/samskivert/ikvm-monotouch/blob/master/runtime/openjdk.cs

I can certainly change IKVM to avoid using reflection in this case, but I worry a bit about what other surprises are lurking in the corners waiting to be discovered.

The example project I sent might be compilable with 6.2.x. When I updated things for the Mono 3 transition, I just ended up having to be less sloppy about the assembly versions referenced by the IKVM.* DLLs, but I didn't have to change any IKVM code. So in theory those same DLLs should compile with the older MonoTouch.
Comment 3 Sebastien Pouliot 2013-10-16 14:57:35 UTC
Thanks for the extra details!

> so maybe it was some sort of fluke.

Yup. I don't think the linker regressed (in this case) but I'm curious why it kept it before (that could be something that was indirectly fixed by the move to the new cecil/BCL).

> but I worry a bit about what other surprises are lurking in the corners waiting to be discovered.

There has not been many reported issues. That's why I said the linker code did not change much between 6.4 to 7.0 :-) 

Still surprises are, by definition, not things we can expect/control. Let us know if you find any - it often gives us clue on how we can add some "magic" to reduce the extra work required to link code.
Comment 4 Sebastien Pouliot 2013-10-17 16:44:58 UTC
I tried with the current linker. I can duplicate the error and it's a "valid" one (I don't see any other hint that would cause State default ctor to be kept around). Adding:

      new IKVM.NativeCode.sun.reflect.State ();

to the Main() method fix this, i.e. the linker detect the .ctor is needed and keep it.

I'll check with a mono 2.10 based linker to see why this could work before - but it won't be immediately (next time I have to check something in the old code).
Comment 5 Sebastien Pouliot 2015-04-16 11:00:09 UTC
Sadly I never had time to go back (and satisfy my curiosity) to see why it was not linked before - still the new behaviour is the correct one so I'm closing the issue.