Skip to content

Commit

Permalink
Merge pull request #551 from ikvmnet/rmworkarounds
Browse files Browse the repository at this point in the history
Remove pre-Roslyn Workarounds
  • Loading branch information
wasabii committed Jul 12, 2024
2 parents f5d765b + 7129cea commit b42168e
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 331 deletions.
80 changes: 34 additions & 46 deletions src/IKVM.Runtime/ReflectUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Jeroen Frijters
#if IMPORTER || EXPORTER
using IKVM.Reflection;
using IKVM.Reflection.Emit;

using Type = IKVM.Reflection.Type;
#else
using System.Reflection;
Expand Down Expand Up @@ -56,7 +57,7 @@ internal static Assembly GetAssembly(Type type)
internal static bool IsDynamicAssembly(Assembly asm)
{
#if IMPORTER || EXPORTER
return false;
return false;
#else
return asm.IsDynamic;
#endif
Expand Down Expand Up @@ -100,7 +101,7 @@ internal static bool ContainsTypeBuilder(Type type)
internal static bool IsVector(Type type)
{
#if IMPORTER || EXPORTER
return type.__IsVector;
return type.__IsVector;
#else
// there's no API to distinguish an array of rank 1 from a vector,
// so we check if the type name ends in [], which indicates it's a vector
Expand All @@ -126,20 +127,7 @@ internal static bool IsDynamicMethod(MethodInfo method)

internal static MethodBuilder DefineTypeInitializer(TypeBuilder typeBuilder, RuntimeClassLoader loader)
{
MethodAttributes attr = MethodAttributes.Static | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName;
if (typeBuilder.IsInterface && loader.WorkaroundInterfacePrivateMethods)
{
// LAMESPEC the ECMA spec says (part. I, sect. 8.5.3.2) that all interface members must be public, so we make
// the class constructor public.
// NOTE it turns out that on .NET 2.0 this isn't necessary anymore (neither Ref.Emit nor the CLR verifier complain about it),
// but the C# compiler still considers interfaces with non-public methods to be invalid, so to keep interop with C# we have
// to keep making the .cctor method public.
attr |= MethodAttributes.Public;
}
else
{
attr |= MethodAttributes.Private;
}
var attr = MethodAttributes.Static | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.Private;
return typeBuilder.DefineMethod(ConstructorInfo.TypeConstructorName, attr, null, Type.EmptyTypes);
}

Expand Down Expand Up @@ -217,36 +205,36 @@ private static bool MatchTypes(Type[] t1, Type[] t2)

#if IMPORTER

internal static Type GetMissingType(Type type)
{
while (type.HasElementType)
{
type = type.GetElementType();
}
if (type.__IsMissing)
{
return type;
}
else if (type.__ContainsMissingType)
{
if (type.IsGenericType)
{
foreach (Type arg in type.GetGenericArguments())
{
Type t1 = GetMissingType(arg);
if (t1.__IsMissing)
{
return t1;
}
}
}
throw new NotImplementedException(type.FullName);
}
else
{
return type;
}
}
internal static Type GetMissingType(Type type)
{
while (type.HasElementType)
{
type = type.GetElementType();
}
if (type.__IsMissing)
{
return type;
}
else if (type.__ContainsMissingType)
{
if (type.IsGenericType)
{
foreach (Type arg in type.GetGenericArguments())
{
Type t1 = GetMissingType(arg);
if (t1.__IsMissing)
{
return t1;
}
}
}
throw new NotImplementedException(type.FullName);
}
else
{
return type;
}
}

#endif

Expand Down
81 changes: 5 additions & 76 deletions src/IKVM.Runtime/RuntimeByteCodeJavaType.FinishContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@ private bool EmitInterlockedCompareAndSet(RuntimeJavaMethod method, string field
{
return false;
}

var fieldType = parameters[firstValueIndex];
if (fieldType != parameters[firstValueIndex + 1])
{
Expand Down Expand Up @@ -1070,71 +1070,14 @@ private TypeBuilder DefineNestedInteropType(string name)
return tb;
}

private void AddInterfaceFieldsInterop(RuntimeJavaField[] fields)
void AddInterfaceFieldsInterop(RuntimeJavaField[] fields)
{
if (classFile.IsInterface && classFile.IsPublic && !wrapper.IsGhost && classFile.Fields.Length > 0 && wrapper.classLoader.WorkaroundInterfaceFields)
{
TypeBuilder tbFields = DefineNestedInteropType(NestedTypeName.Fields);
CodeEmitter ilgenClinit = null;
for (int i = 0; i < classFile.Fields.Length; i++)
{
ClassFile.Field f = classFile.Fields[i];
if (f.ConstantValue != null)
{
FieldAttributes attribs = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
FieldBuilder fb = tbFields.DefineField(f.Name, fields[i].FieldTypeWrapper.TypeAsSignatureType, attribs);
fb.SetConstant(f.ConstantValue);
}
else
{
FieldAttributes attribs = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.InitOnly;
FieldBuilder fb = tbFields.DefineField(f.Name, fields[i].FieldTypeWrapper.TypeAsPublicSignatureType, attribs);
if (ilgenClinit == null)
{
ilgenClinit = context.CodeEmitterFactory.Create(ReflectUtil.DefineTypeInitializer(tbFields, wrapper.classLoader));
}
wrapper.GetFieldWrapper(f.Name, f.Signature).EmitGet(ilgenClinit);
ilgenClinit.Emit(OpCodes.Stsfld, fb);
}
}
if (ilgenClinit != null)
{
ilgenClinit.Emit(OpCodes.Ret);
ilgenClinit.DoEmit();
}
}

}

private void AddInterfaceMethodsInterop(RuntimeJavaMethod[] methods)
void AddInterfaceMethodsInterop(RuntimeJavaMethod[] methods)
{
if (classFile.IsInterface && classFile.IsPublic && classFile.MajorVersion >= 52 && !wrapper.IsGhost && methods.Length > 0 && wrapper.classLoader.WorkaroundInterfaceStaticMethods)
{
TypeBuilder tbMethods = null;
foreach (var mw in methods)
{
if (mw.IsStatic && mw.IsPublic && mw.Name != StringConstants.CLINIT && ParametersAreAccessible(mw))
{
if (tbMethods == null)
{
tbMethods = DefineNestedInteropType(NestedTypeName.Methods);
}
var mb = mw.GetDefineMethodHelper().DefineMethod(wrapper.GetClassLoader().GetTypeWrapperFactory(), tbMethods, mw.Name, MethodAttributes.Public | MethodAttributes.Static, null, true);
var ilgen = context.CodeEmitterFactory.Create(mb);
var parameters = mw.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
ilgen.EmitLdarg(i);
if (!parameters[i].IsUnloadable && !parameters[i].IsPublic)
{
parameters[i].EmitCheckcast(ilgen);
}
}
mw.EmitCall(ilgen);
ilgen.Emit(OpCodes.Ret);
ilgen.DoEmit();
}
}
}

}

private void CreateDefaultMethodInterop(ref TypeBuilder tbDefaultMethods, MethodBuilder defaultMethod, RuntimeJavaMethod mw)
Expand Down Expand Up @@ -2336,20 +2279,6 @@ internal TypeBuilder DefineAnonymousClass()

MethodBuilder DefineHelperMethod(string name, Type returnType, Type[] parameterTypes)
{
#if IMPORTER
// FXBUG csc.exe doesn't like non-public methods in interfaces, so for public interfaces we move
// the helper methods into a nested type.
if (wrapper.IsPublic && wrapper.IsInterface && wrapper.classLoader.WorkaroundInterfacePrivateMethods)
{
if (interfaceHelperMethodsTypeBuilder == null)
{
interfaceHelperMethodsTypeBuilder = typeBuilder.DefineNestedType(NestedTypeName.InterfaceHelperMethods, TypeAttributes.NestedPrivate | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit);
RegisterNestedTypeBuilder(interfaceHelperMethodsTypeBuilder);
}
return interfaceHelperMethodsTypeBuilder.DefineMethod(name, MethodAttributes.PrivateScope | MethodAttributes.Static, returnType, parameterTypes);
}
#endif

return typeBuilder.DefineMethod(name, MethodAttributes.PrivateScope | MethodAttributes.Static, returnType, parameterTypes);
}

Expand Down
11 changes: 0 additions & 11 deletions src/IKVM.Runtime/RuntimeByteCodeJavaType.JavaTypeImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2784,17 +2784,6 @@ MethodBuilder GenerateMethod(int index, ClassFile.Method m, ref bool setModifier
if (classFile.IsInterface && !m.IsPublic && !wrapper.IsGhost)
{
var tb = typeBuilder;
#if IMPORTER
if (wrapper.IsPublic && wrapper.classLoader.WorkaroundInterfacePrivateMethods)
{
// FXBUG csc.exe doesn't like non-public methods in interfaces, so we put them in a nested type
if (privateInterfaceMethods == null)
privateInterfaceMethods = typeBuilder.DefineNestedType(NestedTypeName.PrivateInterfaceMethods, TypeAttributes.NestedPrivate | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit);
tb = privateInterfaceMethods;
attribs &= ~MethodAttributes.MemberAccessMask;
attribs |= MethodAttributes.Assembly;
}
#endif
if (m.IsStatic)
{
mb = methods[index].GetDefineMethodHelper().DefineMethod(wrapper, tb, name, attribs);
Expand Down
36 changes: 0 additions & 36 deletions src/IKVM.Runtime/RuntimeClassLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,42 +195,6 @@ RuntimeJavaType RegisterInitiatingLoaderCritical(RuntimeJavaType tw)

internal bool EnableOptimizations => (codegenoptions & CodeGenOptions.DisableOptimizations) == 0;

internal bool WorkaroundAbstractMethodWidening
{
get
{
// pre-Roslyn C# compiler doesn't like widening access to abstract methods
return true;
}
}

internal bool WorkaroundInterfaceFields
{
get
{
// pre-Roslyn C# compiler doesn't allow access to interface fields
return true;
}
}

internal bool WorkaroundInterfacePrivateMethods
{
get
{
// pre-Roslyn C# compiler doesn't like interfaces that have non-public methods
return true;
}
}

internal bool WorkaroundInterfaceStaticMethods
{
get
{
// pre-Roslyn C# compiler doesn't allow access to interface static methods
return true;
}
}

#if !IMPORTER && !EXPORTER
#if FIRST_PASS == false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
using BasicType = global::java.lang.invoke.LambdaForm.BasicType;
using Class = global::java.lang.Class;
using Name = global::java.lang.invoke.LambdaForm.Name;
using Opcodes = jdk.@internal.org.objectweb.asm.Opcodes.__Fields;
using Opcodes = jdk.@internal.org.objectweb.asm.Opcodes;
using VerifyType = global::sun.invoke.util.VerifyType;
using Wrapper = global::sun.invoke.util.Wrapper;
#endif
Expand Down
Loading

0 comments on commit b42168e

Please sign in to comment.