diff --git a/ikvmc/CompilerClassLoader.cs b/ikvmc/CompilerClassLoader.cs index 0bfc454d..8cae42cb 100644 --- a/ikvmc/CompilerClassLoader.cs +++ b/ikvmc/CompilerClassLoader.cs @@ -432,6 +432,26 @@ namespace IKVM.Internal return null; } + // HACK when we're compiling multiple targets with -sharedclassloader, each target will have its own CompilerClassLoader, + // so we need to consider them equivalent (because they represent the same class loader). + internal bool IsEquivalentTo(ClassLoaderWrapper other) + { + if (this == other) + { + return true; + } + CompilerClassLoader ccl = other as CompilerClassLoader; + if (ccl != null && options.sharedclassloader != null && options.sharedclassloader.Contains(ccl)) + { + if (!internalsVisibleTo.Contains(ccl)) + { + AddInternalsVisibleToAttribute(ccl); + } + return true; + } + return false; + } + internal override bool InternalsVisibleToImpl(TypeWrapper wrapper, TypeWrapper friend) { Debug.Assert(wrapper.GetClassLoader() == this); @@ -442,19 +462,18 @@ namespace IKVM.Internal return true; } CompilerClassLoader ccl = other as CompilerClassLoader; - if (ccl != null - && options.sharedclassloader != null - && options.sharedclassloader.Contains(ccl)) + if (ccl != null) { - AddInternalsVisibleToAttribute(ccl.assemblyBuilder); - internalsVisibleTo.Add(other); + AddInternalsVisibleToAttribute(ccl); return true; } return false; } - private void AddInternalsVisibleToAttribute(AssemblyBuilder asm) + private void AddInternalsVisibleToAttribute(CompilerClassLoader ccl) { + internalsVisibleTo.Add(ccl); + AssemblyBuilder asm = ccl.assemblyBuilder; AssemblyName asmName = asm.GetName(); string name = asmName.Name; byte[] pubkey = asmName.GetPublicKey(); diff --git a/runtime/DynamicTypeWrapper.cs b/runtime/DynamicTypeWrapper.cs index 74fde4a3..131f1d3e 100644 --- a/runtime/DynamicTypeWrapper.cs +++ b/runtime/DynamicTypeWrapper.cs @@ -547,12 +547,6 @@ namespace IKVM.Internal } } #if STATIC_COMPILER - if (wrapper.IsPublic) - { - List fieldsArray = new List(fields); - AddAccessStubFields(fieldsArray, wrapper); - fields = fieldsArray.ToArray(); - } ((AotTypeWrapper)wrapper).AddMapXmlFields(ref fields); #endif wrapper.SetFields(fields); @@ -1129,29 +1123,6 @@ namespace IKVM.Internal } } - private void AddAccessStubFields(List fields, TypeWrapper tw) - { - do - { - if (!tw.IsPublic) - { - foreach (FieldWrapper fw in tw.GetFields()) - { - if ((fw.IsPublic || fw.IsProtected) - && !ContainsMemberWrapper(fields, fw.Name, fw.Signature)) - { - fields.Add(new AotAccessStubFieldWrapper(wrapper, fw)); - } - } - } - foreach (TypeWrapper iface in tw.Interfaces) - { - AddAccessStubFields(fields, iface); - } - tw = tw.BaseTypeWrapper; - } while (tw != null && !tw.IsPublic); - } - private static bool CheckInnerOuterNames(string inner, string outer) { // do some sanity checks on the inner/outer class names @@ -1252,11 +1223,6 @@ namespace IKVM.Internal internal override FieldInfo LinkField(FieldWrapper fw) { - if (fw.IsAccessStub) - { - ((AotAccessStubFieldWrapper)fw).DoLink(typeBuilder); - return null; - } if (fw is DynamicPropertyFieldWrapper) { ((DynamicPropertyFieldWrapper)fw).DoLink(typeBuilder); @@ -1313,6 +1279,7 @@ namespace IKVM.Internal MethodAttributes methodAttribs = MethodAttributes.HideBySig; #if STATIC_COMPILER bool setModifiers = fld.IsInternal || (fld.Modifiers & (Modifiers.Synthetic | Modifiers.Enum)) != 0; + bool hideFromJava = false; #endif bool isWrappedFinal = false; if (fld.IsPrivate) @@ -1334,6 +1301,17 @@ namespace IKVM.Internal attribs |= FieldAttributes.Assembly; methodAttribs |= MethodAttributes.Assembly; } + +#if STATIC_COMPILER + if (wrapper.IsPublic && (fw.IsPublic || fw.IsProtected) && !fw.FieldTypeWrapper.IsPublic) + { + // this field is going to get a type 2 access stub, so we hide the actual field + attribs &= ~FieldAttributes.FieldAccessMask; + attribs |= FieldAttributes.Assembly; + hideFromJava = true; + } +#endif + if (fld.IsStatic) { attribs |= FieldAttributes.Static; @@ -1391,6 +1369,10 @@ namespace IKVM.Internal { AttributeHelper.SetConstantValue(field, constantValue); } + if (hideFromJava) + { + AttributeHelper.HideFromJava(field); + } #endif // STATIC_COMPILER if (isWrappedFinal) { @@ -1511,30 +1493,12 @@ namespace IKVM.Internal classFile.Link(wrapper); for (int i = 0; i < fields.Length; i++) { -#if STATIC_COMPILER - if (fields[i] is AotAccessStubFieldWrapper) - { - // HACK we skip access stubs, because we want to do the methods first - // (to prevent the stub method from taking the name of a real method) - continue; - } -#endif fields[i].Link(); } for (int i = 0; i < methods.Length; i++) { methods[i].Link(); } -#if STATIC_COMPILER - // HACK second pass for the access stubs (see above) - for (int i = 0; i < fields.Length; i++) - { - if (fields[i] is AotAccessStubFieldWrapper) - { - fields[i].Link(); - } - } -#endif // this is the correct lock, FinishCore doesn't call any user code and mutates global state, // so it needs to be protected by a lock. lock (this) @@ -3911,6 +3875,13 @@ namespace IKVM.Internal // See if there is any additional metadata wrapper.EmitMapXmlMetadata(typeBuilder, classFile, fields, methods); + + // if we have public fields that have non-public field types, we need access stubs + if (wrapper.IsPublic) + { + AddType1FieldAccessStubs(wrapper); + AddType2FieldAccessStubs(); + } #endif // STATIC_COMPILER for (int i = 0; i < classFile.Methods.Length; i++) @@ -4083,6 +4054,118 @@ namespace IKVM.Internal return type; } +#if STATIC_COMPILER + private void AddType1FieldAccessStubs(TypeWrapper tw) + { + do + { + if (!tw.IsPublic) + { + foreach (FieldWrapper fw in tw.GetFields()) + { + if ((fw.IsPublic || fw.IsProtected) + && wrapper.GetFieldWrapper(fw.Name, fw.Signature) == fw) + { + GenerateAccessStub(fw, true); + } + } + } + foreach (TypeWrapper iface in tw.Interfaces) + { + AddType1FieldAccessStubs(iface); + } + tw = tw.BaseTypeWrapper; + } while (tw != null && !tw.IsPublic); + } + + private void AddType2FieldAccessStubs() + { + foreach (FieldWrapper fw in wrapper.GetFields()) + { + if ((fw.IsPublic || fw.IsProtected) && !fw.FieldTypeWrapper.IsPublic) + { + GenerateAccessStub(fw, false); + } + } + } + + private void GenerateAccessStub(FieldWrapper fw, bool type1) + { + if (fw is ConstantFieldWrapper) + { + // constants cannot have a type 2 access stub, because constant types are always public + Debug.Assert(type1); + + FieldAttributes attribs = fw.IsPublic ? FieldAttributes.Public : FieldAttributes.FamORAssem; + attribs |= FieldAttributes.Static | FieldAttributes.Literal; + FieldBuilder fb = typeBuilder.DefineField(fw.Name, fw.FieldTypeWrapper.TypeAsSignatureType, attribs); + AttributeHelper.HideFromReflection(fb); + fb.SetConstant(((ConstantFieldWrapper)fw).GetConstantValue()); + } + else + { + string name = fw.Name; + // If there is a potential for property name clashes (e.g. we have multiple fields with the same name in this class, + // or the current class hides a field in the base class) we will mangle the name as a precaution. We could use a more + // complicated scheme which would result in less mangling, but it is exceedingly unlikely to encounter a class with + // these field name clashes, because Java cannot handle them either. + foreach (FieldWrapper field in wrapper.GetFields()) + { + if (field != fw && !field.IsPrivate && field.Name == name) + { + name = "<>" + fw.Name + fw.Signature; + break; + } + } + Type propType = fw.FieldTypeWrapper.GetPublicBaseTypeWrapper().TypeAsSignatureType; + PropertyBuilder pb = typeBuilder.DefineProperty(name, PropertyAttributes.None, propType, Type.EmptyTypes); + if (type1) + { + AttributeHelper.HideFromReflection(pb); + } + else + { + AttributeHelper.SetNameSig(pb, fw.Name, fw.Signature); + AttributeHelper.SetModifiers(pb, fw.Modifiers, fw.IsInternal); + } + MethodAttributes attribs = fw.IsPublic ? MethodAttributes.Public : MethodAttributes.FamORAssem; + attribs |= MethodAttributes.HideBySig; + if (fw.IsStatic) + { + attribs |= MethodAttributes.Static; + } + MethodBuilder getter = typeBuilder.DefineMethod(wrapper.GenerateUniqueMethodName("get_" + fw.Name, propType, Type.EmptyTypes), attribs, propType, Type.EmptyTypes); + AttributeHelper.HideFromJava(getter); + pb.SetGetMethod(getter); + CodeEmitter ilgen = CodeEmitter.Create(getter); + if (!fw.IsStatic) + { + ilgen.Emit(OpCodes.Ldarg_0); + } + fw.EmitGet(ilgen); + ilgen.Emit(OpCodes.Ret); + if (!fw.IsFinal) + { + MethodBuilder setter = typeBuilder.DefineMethod(wrapper.GenerateUniqueMethodName("set_" + fw.Name, Types.Void, new Type[] { propType }), attribs, null, new Type[] { propType }); + AttributeHelper.HideFromJava(setter); + pb.SetSetMethod(setter); + ilgen = CodeEmitter.Create(setter); + ilgen.Emit(OpCodes.Ldarg_0); + if (!fw.IsStatic) + { + ilgen.Emit(OpCodes.Ldarg_1); + } + if (propType != fw.FieldTypeWrapper.TypeAsSignatureType) + { + ilgen.Emit(OpCodes.Castclass, fw.FieldTypeWrapper.TypeAsSignatureType); + } + fw.EmitSet(ilgen); + ilgen.Emit(OpCodes.Ret); + } + } + } +#endif // STATIC_COMPILER + private void ImplementInterfaceMethodStubs(Dictionary doneSet, TypeWrapper interfaceTypeWrapper) { Debug.Assert(interfaceTypeWrapper.IsInterface); diff --git a/runtime/MemberWrapper.cs b/runtime/MemberWrapper.cs index e9c0fa9f..0cf3e536 100644 --- a/runtime/MemberWrapper.cs +++ b/runtime/MemberWrapper.cs @@ -1162,7 +1162,7 @@ namespace IKVM.Internal private void UpdateNonPublicTypeInSignatureFlag() { - if ((IsPublic || IsProtected) && fieldType != null) + if ((IsPublic || IsProtected) && fieldType != null && !IsAccessStub) { if (!fieldType.IsPublic && !fieldType.IsUnloadable) { @@ -1843,91 +1843,6 @@ namespace IKVM.Internal } } - // This type is used during AOT compilation only! - sealed class AotAccessStubFieldWrapper : FieldWrapper - { - private FieldWrapper basefield; - private MethodBuilder getter; - private MethodBuilder setter; - - internal AotAccessStubFieldWrapper(TypeWrapper wrapper, FieldWrapper basefield) - : base(wrapper, null, basefield.Name, basefield.Signature, basefield.Modifiers, null, MemberFlags.AccessStub | MemberFlags.HideFromReflection) - { - this.basefield = basefield; - } - - private string GenerateUniqueMethodName(string basename, Type returnType, Type[] parameterTypes) - { - return ((DynamicTypeWrapper)this.DeclaringType).GenerateUniqueMethodName(basename, returnType, parameterTypes); - } - - internal void DoLink(TypeBuilder typeBuilder) - { - basefield.Link(); - if(basefield is ConstantFieldWrapper) - { - FieldAttributes attribs = basefield.IsPublic ? FieldAttributes.Public : FieldAttributes.FamORAssem; - attribs |= FieldAttributes.Static | FieldAttributes.Literal; - FieldBuilder fb = typeBuilder.DefineField(Name, basefield.FieldTypeWrapper.TypeAsSignatureType, attribs); - AttributeHelper.HideFromReflection(fb); - fb.SetConstant(((ConstantFieldWrapper)basefield).GetConstantValue()); - } - else - { - Type propType = basefield.FieldTypeWrapper.TypeAsSignatureType; - PropertyBuilder pb = typeBuilder.DefineProperty(Name, PropertyAttributes.None, propType, Type.EmptyTypes); - AttributeHelper.HideFromReflection(pb); - MethodAttributes attribs = basefield.IsPublic ? MethodAttributes.Public : MethodAttributes.FamORAssem; - attribs |= MethodAttributes.HideBySig; - if(basefield.IsStatic) - { - attribs |= MethodAttributes.Static; - } - getter = typeBuilder.DefineMethod(GenerateUniqueMethodName("get_" + Name, propType, Type.EmptyTypes), attribs, propType, Type.EmptyTypes); - AttributeHelper.HideFromJava(getter); - pb.SetGetMethod(getter); - CodeEmitter ilgen = CodeEmitter.Create(getter); - if(!basefield.IsStatic) - { - ilgen.Emit(OpCodes.Ldarg_0); - } - basefield.EmitGet(ilgen); - ilgen.Emit(OpCodes.Ret); - if(!basefield.IsFinal) - { - setter = typeBuilder.DefineMethod(GenerateUniqueMethodName("set_" + Name, Types.Void, new Type[] { propType }), attribs, null, new Type[] { propType }); - AttributeHelper.HideFromJava(setter); - pb.SetSetMethod(setter); - ilgen = CodeEmitter.Create(setter); - ilgen.Emit(OpCodes.Ldarg_0); - if(!basefield.IsStatic) - { - ilgen.Emit(OpCodes.Ldarg_1); - } - basefield.EmitSet(ilgen); - ilgen.Emit(OpCodes.Ret); - } - } - } - - protected override void EmitGetImpl(CodeEmitter ilgen) - { - if(basefield is ConstantFieldWrapper) - { - basefield.EmitGet(ilgen); - } - else - { - ilgen.Emit(OpCodes.Call, getter); - } - } - - protected override void EmitSetImpl(CodeEmitter ilgen) - { - ilgen.Emit(OpCodes.Call, setter); - } - } - sealed class CompiledAccessStubFieldWrapper : FieldWrapper { private MethodInfo getter; @@ -1949,8 +1864,8 @@ namespace IKVM.Internal return modifiers; } - internal CompiledAccessStubFieldWrapper(TypeWrapper wrapper, PropertyInfo property) - : base(wrapper, ClassLoaderWrapper.GetWrapperFromType(property.PropertyType), property.Name, ClassLoaderWrapper.GetWrapperFromType(property.PropertyType).SigName, GetModifiers(property), null, MemberFlags.AccessStub | MemberFlags.HideFromReflection) + private CompiledAccessStubFieldWrapper(TypeWrapper wrapper, PropertyInfo property, TypeWrapper propertyType, string name, string signature, Modifiers modifiers, MemberFlags flags) + : base(wrapper, propertyType, name, signature, modifiers, null, flags) { this.getter = property.GetGetMethod(true); this.setter = property.GetSetMethod(true); @@ -1965,5 +1880,55 @@ namespace IKVM.Internal { ilgen.Emit(OpCodes.Call, setter); } + + internal static bool TryGet(TypeWrapper wrapper, PropertyInfo property, out FieldWrapper accessStub) + { + NameSigAttribute nameSig = AttributeHelper.GetNameSig(property); + bool hideFromReflection = AttributeHelper.IsHideFromReflection(property); + + if (nameSig != null || hideFromReflection) + { + TypeWrapper type; + string name; + string sig; + if (nameSig == null) + { + type = ClassLoaderWrapper.GetWrapperFromType(property.PropertyType); + name = property.Name; + sig = type.SigName; + } + else + { + type = ClassFile.FieldTypeWrapperFromSig(wrapper.GetClassLoader(), nameSig.Sig); + name = nameSig.Name; + sig = nameSig.Sig; + } + Modifiers modifiers; + MemberFlags flags = MemberFlags.AccessStub; + if (hideFromReflection) + { + // it's a Type 1 access stub (to make inherited fields visible) + flags |= MemberFlags.HideFromReflection; + modifiers = GetModifiers(property); + } + else + { + // it's a Type 2 access stub (to make fields that have a non-public field type visible) + ModifiersAttribute attr = AttributeHelper.GetModifiersAttribute(property); + modifiers = attr.Modifiers; + if (attr.IsInternal) + { + flags |= MemberFlags.InternalAccess; + } + } + accessStub = new CompiledAccessStubFieldWrapper(wrapper, property, type, name, sig, modifiers, flags); + return true; + } + else + { + accessStub = null; + return false; + } + } } } diff --git a/runtime/TypeWrapper.cs b/runtime/TypeWrapper.cs index 7918cae5..62f486b0 100644 --- a/runtime/TypeWrapper.cs +++ b/runtime/TypeWrapper.cs @@ -1022,6 +1022,12 @@ namespace IKVM.Internal fb.SetCustomAttribute(customAttributeBuilder); } + internal static void SetNameSig(PropertyBuilder pb, string name, string sig) + { + CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeofNameSigAttribute.GetConstructor(new Type[] { Types.String, Types.String }), new object[] { name, sig }); + pb.SetCustomAttribute(customAttributeBuilder); + } + internal static byte[] FreezeDryType(Type type) { System.IO.MemoryStream mem = new System.IO.MemoryStream(); @@ -1167,6 +1173,29 @@ namespace IKVM.Internal } } + internal static NameSigAttribute GetNameSig(PropertyInfo property) + { +#if !STATIC_COMPILER + if(!property.DeclaringType.Assembly.ReflectionOnly) + { + object[] attr = property.GetCustomAttributes(typeof(NameSigAttribute), false); + return attr.Length == 1 ? (NameSigAttribute)attr[0] : null; + } + else +#endif + { + foreach(CustomAttributeData cad in CustomAttributeData.GetCustomAttributes(property)) + { + if(MatchTypes(cad.Constructor.DeclaringType, typeofNameSigAttribute)) + { + IList args = cad.ConstructorArguments; + return new NameSigAttribute((string)args[0].Value, (string)args[1].Value); + } + } + return null; + } + } + internal static NameSigAttribute GetNameSig(MethodBase method) { #if !STATIC_COMPILER @@ -2931,7 +2960,23 @@ namespace IKVM.Internal internal bool IsPackageAccessibleFrom(TypeWrapper wrapper) { - return MatchingPackageNames(name, wrapper.name) && InternalsVisibleTo(wrapper); + if (MatchingPackageNames(name, wrapper.name)) + { +#if STATIC_COMPILER + CompilerClassLoader ccl = GetClassLoader() as CompilerClassLoader; + if (ccl != null) + { + // this is a hack for multi target -sharedclassloader compilation + // (during compilation we have multiple CompilerClassLoader instances to represent the single shared runtime class loader) + return ccl.IsEquivalentTo(wrapper.GetClassLoader()); + } +#endif + return GetClassLoader() == wrapper.GetClassLoader(); + } + else + { + return false; + } } private static bool MatchingPackageNames(string name1, string name2) @@ -3524,6 +3569,21 @@ namespace IKVM.Internal } return interfaces; } + + internal TypeWrapper GetPublicBaseTypeWrapper() + { + if (this.IsInterface) + { + return CoreClasses.java.lang.Object.Wrapper; + } + for (TypeWrapper tw = this; ; tw = tw.BaseTypeWrapper) + { + if (tw.IsPublic) + { + return tw; + } + } + } } sealed class UnloadableTypeWrapper : TypeWrapper @@ -4422,11 +4482,12 @@ namespace IKVM.Internal PropertyInfo property = m as PropertyInfo; if(property != null) { - // Only AccessStub properties (marked by HideFromReflectionAttribute) + // Only AccessStub properties (marked by HideFromReflectionAttribute or NameSigAttribute) // are considered here - if(AttributeHelper.IsHideFromReflection(property)) + FieldWrapper accessStub; + if(CompiledAccessStubFieldWrapper.TryGet(this, property, out accessStub)) { - fields.Add(new CompiledAccessStubFieldWrapper(this, property)); + fields.Add(accessStub); } else { diff --git a/runtime/compiler.cs b/runtime/compiler.cs index c17e497e..4c047314 100644 --- a/runtime/compiler.cs +++ b/runtime/compiler.cs @@ -319,7 +319,7 @@ sealed class Compiler v.type != VerifierTypeWrapper.UninitializedThis && (v.type != tw || tw.TypeAsLocalOrStackType != tw.TypeAsSignatureType)) { - v.builder = ilGenerator.DeclareLocal(v.type.TypeAsLocalOrStackType); + v.builder = ilGenerator.DeclareLocal(GetLocalBuilderType(v.type)); if(debug && v.name != null) { v.builder.SetLocalSymInfo(v.name); @@ -763,7 +763,7 @@ sealed class Compiler else { types[i] = StackType.Other; - locals[i] = compiler.ilGenerator.AllocTempLocal(type.TypeAsLocalOrStackType); + locals[i] = compiler.ilGenerator.AllocTempLocal(compiler.GetLocalBuilderType(type)); } } @@ -1852,7 +1852,7 @@ sealed class Compiler // this could be done a little more efficiently, but since in practice this // code never runs (for code compiled from Java source) it doesn't // really matter - LocalBuilder newobj = ilGenerator.DeclareLocal(thisType.TypeAsLocalOrStackType); + LocalBuilder newobj = ilGenerator.DeclareLocal(GetLocalBuilderType(thisType)); ilGenerator.Emit(OpCodes.Stloc, newobj); LocalBuilder[] tempstack = new LocalBuilder[stackfix.Length]; for(int j = 0; j < stackfix.Length; j++) @@ -1870,7 +1870,7 @@ sealed class Compiler } else if(!VerifierTypeWrapper.IsNew(stacktype)) { - LocalBuilder lb = ilGenerator.DeclareLocal(stacktype.TypeAsLocalOrStackType); + LocalBuilder lb = ilGenerator.DeclareLocal(GetLocalBuilderType(stacktype)); ilGenerator.Emit(OpCodes.Stloc, lb); tempstack[j] = lb; } @@ -1903,7 +1903,7 @@ sealed class Compiler if(locals[j].builder == null) { // for invokespecial the resulting type can never be null - locals[j].builder = ilGenerator.DeclareLocal(locals[j].type.TypeAsLocalOrStackType); + locals[j].builder = ilGenerator.DeclareLocal(GetLocalBuilderType(locals[j].type)); } ilGenerator.Emit(OpCodes.Ldloc, newobj); ilGenerator.Emit(OpCodes.Stloc, locals[j].builder); @@ -1937,7 +1937,7 @@ sealed class Compiler if(locals[j].builder == null) { // for invokespecial the resulting type can never be null - locals[j].builder = ilGenerator.DeclareLocal(locals[j].type.TypeAsLocalOrStackType); + locals[j].builder = ilGenerator.DeclareLocal(GetLocalBuilderType(locals[j].type)); } ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Stloc, locals[j].builder); @@ -3104,7 +3104,7 @@ sealed class Compiler else if(args[i].IsInterfaceOrInterfaceArray) { TypeWrapper tw = ma.GetStackTypeWrapper(instructionIndex, args.Length - 1 - i); - if(!tw.IsUnloadable && !tw.IsAssignableTo(args[i])) + if(tw.IsUnloadable || NeedsInterfaceDownCast(tw, args[i])) { needsCast = true; firstCastArg = i; @@ -3153,7 +3153,7 @@ sealed class Compiler if(!args[i].IsUnloadable && !args[i].IsGhost) { TypeWrapper tw = ma.GetStackTypeWrapper(instructionIndex, args.Length - 1 - i); - if(tw.IsUnloadable || (args[i].IsInterfaceOrInterfaceArray && !tw.IsAssignableTo(args[i]))) + if(tw.IsUnloadable || (args[i].IsInterfaceOrInterfaceArray && NeedsInterfaceDownCast(tw, args[i]))) { ilGenerator.EmitAssertType(args[i].TypeAsTBD); Profiler.Count("InterfaceDownCast"); @@ -3225,6 +3225,15 @@ sealed class Compiler } } + private bool NeedsInterfaceDownCast(TypeWrapper tw, TypeWrapper arg) + { + if (!tw.IsAccessibleFrom(clazz)) + { + tw = tw.GetPublicBaseTypeWrapper(); + } + return !tw.IsAssignableTo(arg); + } + private void DynamicGetPutField(Instruction instr, int i) { NormalizedByteCode bytecode = instr.NormalizedOpCode; @@ -3470,7 +3479,7 @@ sealed class Compiler { if(v.builder == null) { - v.builder = ilGenerator.DeclareLocal(v.type.TypeAsLocalOrStackType); + v.builder = ilGenerator.DeclareLocal(GetLocalBuilderType(v.type)); if(debug && v.name != null) { v.builder.SetLocalSymInfo(v.name); @@ -3510,7 +3519,7 @@ sealed class Compiler { if(v.builder == null) { - v.builder = ilGenerator.DeclareLocal(v.type.TypeAsLocalOrStackType); + v.builder = ilGenerator.DeclareLocal(GetLocalBuilderType(v.type)); if(debug && v.name != null) { v.builder.SetLocalSymInfo(v.name); @@ -3520,4 +3529,20 @@ sealed class Compiler } return v; } + + private Type GetLocalBuilderType(TypeWrapper tw) + { + if (tw.IsUnloadable) + { + return Types.Object; + } + else if (tw.IsAccessibleFrom(clazz)) + { + return tw.TypeAsLocalOrStackType; + } + else + { + return tw.GetPublicBaseTypeWrapper().TypeAsLocalOrStackType; + } + } }