Version 0.2
This commit is contained in:
parent
3d84879ed8
commit
34c96b090c
@ -46,6 +46,7 @@ System.IWellKnownStringEqualityComparer
|
|||||||
System.DivideByZeroException
|
System.DivideByZeroException
|
||||||
|
|
||||||
System.FormatException
|
System.FormatException
|
||||||
|
System.FormattableString
|
||||||
System.Func`*
|
System.Func`*
|
||||||
|
|
||||||
System.ICloneable
|
System.ICloneable
|
||||||
@ -89,6 +90,7 @@ System.Collections.ObjectModel.ReadOnlyCollection`1
|
|||||||
System.Collections.HashHelpers
|
System.Collections.HashHelpers
|
||||||
|
|
||||||
System.Collections.Generic.Comparer`1
|
System.Collections.Generic.Comparer`1
|
||||||
|
System.Collections.Generic.IComparer`1
|
||||||
System.Collections.Generic.ComparisonComparer`1
|
System.Collections.Generic.ComparisonComparer`1
|
||||||
System.Collections.Generic.ObjectComparer`1
|
System.Collections.Generic.ObjectComparer`1
|
||||||
System.Collections.Generic.GenericComparer`1
|
System.Collections.Generic.GenericComparer`1
|
||||||
@ -189,13 +191,18 @@ System.Reflection.CallingConventions
|
|||||||
System.Reflection.IntrospectionExtensions
|
System.Reflection.IntrospectionExtensions
|
||||||
System.Reflection.IReflect
|
System.Reflection.IReflect
|
||||||
System.Reflection.MemberInfo
|
System.Reflection.MemberInfo
|
||||||
|
System.Reflection.FieldAttributes
|
||||||
System.Reflection.FieldInfo
|
System.Reflection.FieldInfo
|
||||||
|
System.Reflection.EventAttributes
|
||||||
System.Reflection.EventInfo
|
System.Reflection.EventInfo
|
||||||
System.Reflection.ParameterAttributes
|
System.Reflection.ParameterAttributes
|
||||||
System.Reflection.ParameterInfo
|
System.Reflection.ParameterInfo
|
||||||
|
System.Reflection.PropertyAttributes
|
||||||
System.Reflection.PropertyInfo
|
System.Reflection.PropertyInfo
|
||||||
|
System.Reflection.MethodAttributes
|
||||||
System.Reflection.MethodInfo
|
System.Reflection.MethodInfo
|
||||||
System.Reflection.ConstructorInfo
|
System.Reflection.ConstructorInfo
|
||||||
|
System.Reflection.TypeAttributes
|
||||||
System.Reflection.TypeInfo
|
System.Reflection.TypeInfo
|
||||||
System.Reflection.MemberFilter
|
System.Reflection.MemberFilter
|
||||||
System.Reflection.Missing
|
System.Reflection.Missing
|
||||||
@ -204,7 +211,6 @@ System.Reflection.InterfaceMapping
|
|||||||
System.Reflection.InvalidFilterCriteriaException
|
System.Reflection.InvalidFilterCriteriaException
|
||||||
System.Reflection.IReflectableType
|
System.Reflection.IReflectableType
|
||||||
System.Reflection.ParameterModifier
|
System.Reflection.ParameterModifier
|
||||||
System.Reflection.TypeAttributes
|
|
||||||
System.Reflection.TypeFilter
|
System.Reflection.TypeFilter
|
||||||
System.Reflection.TargetParameterCountException
|
System.Reflection.TargetParameterCountException
|
||||||
System.Reflection.TargetInvocationException
|
System.Reflection.TargetInvocationException
|
||||||
@ -229,6 +235,7 @@ System.Runtime.CompilerServices.AsyncTaskCache
|
|||||||
System.Runtime.CompilerServices.AsyncTaskMethodBuilder
|
System.Runtime.CompilerServices.AsyncTaskMethodBuilder
|
||||||
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`*
|
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`*
|
||||||
System.Runtime.CompilerServices.AsyncVoidMethodBuilder
|
System.Runtime.CompilerServices.AsyncVoidMethodBuilder
|
||||||
|
System.Runtime.CompilerServices.FormattableStringFactory
|
||||||
System.Runtime.CompilerServices.IAsyncStateMachine
|
System.Runtime.CompilerServices.IAsyncStateMachine
|
||||||
System.Runtime.CompilerServices.TaskAwaiter
|
System.Runtime.CompilerServices.TaskAwaiter
|
||||||
System.Runtime.CompilerServices.TaskAwaiter`*
|
System.Runtime.CompilerServices.TaskAwaiter`*
|
||||||
|
@ -711,33 +711,34 @@ namespace system
|
|||||||
//
|
//
|
||||||
|
|
||||||
public static void Sort<T>(T[] array)
|
public static void Sort<T>(T[] array)
|
||||||
=> SortGeneric(array, array, 0, -1, false, null);
|
=> SortGeneric<T>(array, array, 0, -1, false, null);
|
||||||
|
|
||||||
public static void Sort<T>(T[] array, system.collections.generic.IComparer<T> comparer)
|
public static void Sort<T>(T[] array, IComparer<T> comparer)
|
||||||
=> SortGeneric(array, array, 0, -1, false, comparer);
|
=> SortGeneric<T>(array, array, 0, -1, false, comparer);
|
||||||
|
|
||||||
public static void Sort<T>(T[] array, int index, int length)
|
public static void Sort<T>(T[] array, int index, int length)
|
||||||
=> SortGeneric(array, array, index, length, true, null);
|
=> SortGeneric<T>(array, array, index, length, true, null);
|
||||||
|
|
||||||
public static void Sort<T>(T[] array, int index, int length, system.collections.generic.IComparer<T> comparer)
|
public static void Sort<T>(T[] array, int index, int length, IComparer<T> comparer)
|
||||||
=> SortGeneric(array, array, index, length, true, comparer);
|
=> SortGeneric<T>(array, array, index, length, true, comparer);
|
||||||
|
|
||||||
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items)
|
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items)
|
||||||
=> SortGeneric(keys, items, 0, -1, false, null);
|
=> SortGeneric<TKey>(keys, items, 0, -1, false, null);
|
||||||
|
|
||||||
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, system.collections.generic.IComparer<TKey> comparer)
|
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, IComparer<TKey> comparer)
|
||||||
=> SortGeneric(keys, items, 0, -1, false, comparer);
|
=> SortGeneric<TKey>(keys, items, 0, -1, false, comparer);
|
||||||
|
|
||||||
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length)
|
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length)
|
||||||
=> SortGeneric(keys, items, index, length, true, null);
|
=> SortGeneric<TKey>(keys, items, index, length, true, null);
|
||||||
|
|
||||||
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length,
|
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length,
|
||||||
system.collections.generic.IComparer<TKey> comparer)
|
IComparer<TKey> comparer)
|
||||||
=> SortGeneric(keys, items, index, length, true, comparer);
|
=> SortGeneric<TKey>(keys, items, index, length, true, comparer);
|
||||||
|
|
||||||
private static void SortGeneric(object keys_, object items_,
|
private static void SortGeneric<T>(object keys_, object items_,
|
||||||
int index, int length, bool haveLength,
|
int index, int length,
|
||||||
java.util.Comparator comparer)
|
bool haveLength,
|
||||||
|
IComparer<T> comparer)
|
||||||
{
|
{
|
||||||
ThrowIfNull(keys_);
|
ThrowIfNull(keys_);
|
||||||
var keys = GetProxy(keys_);
|
var keys = GetProxy(keys_);
|
||||||
@ -749,7 +750,8 @@ namespace system
|
|||||||
ThrowIfNull(items_);
|
ThrowIfNull(items_);
|
||||||
items = GetProxy(items_);
|
items = GetProxy(items_);
|
||||||
}
|
}
|
||||||
SortCommon(keys, items, index, length, haveLength, comparer);
|
SortCommon(keys, items, index, length, haveLength,
|
||||||
|
new system.collections.GenericComparerProxy<T>(comparer));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -1463,10 +1465,9 @@ namespace system
|
|||||||
// create the Array.Proxy<T> object, where T is the array element.
|
// create the Array.Proxy<T> object, where T is the array element.
|
||||||
// note that we use reflection to call the constructor, which takes
|
// note that we use reflection to call the constructor, which takes
|
||||||
// one additional hidden parameter for the generic type.
|
// one additional hidden parameter for the generic type.
|
||||||
var elementType =
|
|
||||||
system.RuntimeType.GetType(objClass.getComponentType());
|
|
||||||
var newProxyObject =
|
var newProxyObject =
|
||||||
ProxyConstructor.newInstance(new object[] { obj, elementType });
|
ProxyConstructor.newInstance(new object[] {
|
||||||
|
obj, GetArrayElementType(obj, objClass) });
|
||||||
proxy = ArrayProxyCache.GetOrAdd(obj, newProxyObject);
|
proxy = ArrayProxyCache.GetOrAdd(obj, newProxyObject);
|
||||||
}
|
}
|
||||||
if (ok == 2)
|
if (ok == 2)
|
||||||
@ -1526,6 +1527,38 @@ namespace system
|
|||||||
return (Array) (Array.ProxySyncRoot) proxy;
|
return (Array) (Array.ProxySyncRoot) proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static System.Type GetArrayElementType(
|
||||||
|
object arrayObject, java.lang.Class arrayClass)
|
||||||
|
{
|
||||||
|
// an array object does not keep generic type information
|
||||||
|
// for its component, so a Tuple<int,string>[] array becomes
|
||||||
|
// just Tuple$$2[]. casting to IEnumerable<Tuple<int,string>>
|
||||||
|
// would fail. below, we try to extract the concrete generic
|
||||||
|
// type from the first element in the array.
|
||||||
|
//
|
||||||
|
// first, check if the array component is a non-concrete
|
||||||
|
// generic type, and that the array has at least one element.
|
||||||
|
var elementType = system.RuntimeType.GetType(
|
||||||
|
arrayClass.getComponentType());
|
||||||
|
if ( elementType.IsGenericTypeDefinition
|
||||||
|
&& java.lang.reflect.Array.getLength(arrayObject) > 0)
|
||||||
|
{
|
||||||
|
// extract the first element, and make sure it is the same
|
||||||
|
// class as the array (so same number of generic argument)
|
||||||
|
var element0 = java.lang.reflect.Array.get(arrayObject, 0);
|
||||||
|
if ( (! object.ReferenceEquals(element0, null))
|
||||||
|
&& element0.GetType() is RuntimeType element0Type
|
||||||
|
&& ((RuntimeType) elementType).JavaClassForArray()
|
||||||
|
== element0Type.JavaClassForArray())
|
||||||
|
{
|
||||||
|
// return a concrete generic type
|
||||||
|
elementType = elementType.MakeGenericType(
|
||||||
|
element0Type.GetGenericArguments());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return elementType;
|
||||||
|
}
|
||||||
|
|
||||||
public static void MarkJagged(object obj)
|
public static void MarkJagged(object obj)
|
||||||
{
|
{
|
||||||
((Array) GetProxy(obj, cachedArrayType, false)).jagged = true;
|
((Array) GetProxy(obj, cachedArrayType, false)).jagged = true;
|
||||||
|
@ -3,30 +3,52 @@ namespace system.collections
|
|||||||
{
|
{
|
||||||
|
|
||||||
[java.attr.AsInterface]
|
[java.attr.AsInterface]
|
||||||
public abstract class IComparer : java.lang.Comparable, java.util.Comparator
|
public abstract class IComparer : java.util.Comparator
|
||||||
{
|
{
|
||||||
public abstract int Compare(object x, object y);
|
public abstract int Compare(object x, object y);
|
||||||
|
|
||||||
[java.attr.RetainName]
|
[java.attr.RetainName]
|
||||||
public int compareTo(object obj)
|
public int compare(object obj1, object obj2)
|
||||||
=> ((System.Collections.IComparer) this).Compare(this, obj);
|
=> this.Compare(obj1, obj2);
|
||||||
|
|
||||||
|
[java.attr.RetainName]
|
||||||
|
public bool equals(object otherComparer)
|
||||||
|
=> system.Object.Equals(this, otherComparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class GenericComparerProxy<T> : java.util.Comparator
|
||||||
|
{
|
||||||
|
System.Collections.Generic.IComparer<T> comparer;
|
||||||
|
|
||||||
|
public GenericComparerProxy(System.Collections.Generic.IComparer<T> _comparer)
|
||||||
|
=> comparer = _comparer;
|
||||||
|
|
||||||
[java.attr.RetainName]
|
[java.attr.RetainName]
|
||||||
public int compare(object obj1, object obj2)
|
public int compare(object obj1, object obj2)
|
||||||
=> ((System.Collections.IComparer) this).Compare(obj1, obj2);
|
=> comparer.Compare((T) obj1, (T) obj2);
|
||||||
|
|
||||||
[java.attr.RetainName]
|
[java.attr.RetainName]
|
||||||
public bool equals(object obj)
|
public bool equals(object otherComparer)
|
||||||
=> ((System.Collections.IComparer) this).Compare(this, obj) == 0;
|
=> system.Object.Equals(this, otherComparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
removing custom IComparer<T>. the idea was to be able to send an
|
||||||
|
object implementing this interface to a Java method that takes a
|
||||||
|
java.util.Comparator. this works for the non-generic IComparer,
|
||||||
|
but will not work for the generic counterpart. instead we have
|
||||||
|
a bridge (GenericComparerProxy above) which takes an IComparer<T>
|
||||||
|
object and returns a java.util.Comparator. for an example usage,
|
||||||
|
see SortGeneric<T> in system.Array.
|
||||||
|
|
||||||
namespace system.collections.generic
|
namespace system.collections.generic
|
||||||
{
|
{
|
||||||
|
|
||||||
[java.attr.AsInterface]
|
[java.attr.AsInterface]
|
||||||
public abstract class IComparer<T> : java.lang.Comparable, java.util.Comparator
|
public abstract class IComparer<T> : java.util.Comparator
|
||||||
{
|
{
|
||||||
// a generic variance field is created for this abstract class,
|
// a generic variance field is created for this abstract class,
|
||||||
// see also GenericUtil::CreateGenericVarianceField()
|
// see also GenericUtil::CreateGenericVarianceField()
|
||||||
@ -34,17 +56,12 @@ namespace system.collections.generic
|
|||||||
public abstract int Compare(T x, T y);
|
public abstract int Compare(T x, T y);
|
||||||
|
|
||||||
[java.attr.RetainName]
|
[java.attr.RetainName]
|
||||||
public int compareTo(object obj)
|
public int compare(object obj1, object obj2) => Compare(obj1, obj2);
|
||||||
=> ((System.Collections.Generic.IComparer<T>) this).Compare((T) (object) this, (T) obj);
|
|
||||||
|
|
||||||
[java.attr.RetainName]
|
|
||||||
public int compare(object obj1, object obj2)
|
|
||||||
=> ((System.Collections.Generic.IComparer<T>) this).Compare((T) obj1, (T) obj2);
|
|
||||||
|
|
||||||
[java.attr.RetainName]
|
[java.attr.RetainName]
|
||||||
public bool equals(object obj)
|
public bool equals(object obj)
|
||||||
=> ((System.Collections.Generic.IComparer<T>) this).Compare((T) (object) this, (T) obj) == 0;
|
=> throw new System.PlatformNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -263,22 +263,26 @@ namespace system
|
|||||||
|
|
||||||
static string FormatNames(java.lang.Class cls, long v, bool asFlags)
|
static string FormatNames(java.lang.Class cls, long v, bool asFlags)
|
||||||
{
|
{
|
||||||
|
var enumLiteralFlags = ( java.lang.reflect.Modifier.PUBLIC
|
||||||
|
| java.lang.reflect.Modifier.STATIC
|
||||||
|
| java.lang.reflect.Modifier.FINAL);
|
||||||
|
|
||||||
var fields = cls.getDeclaredFields();
|
var fields = cls.getDeclaredFields();
|
||||||
int n = fields.Length;
|
int n = fields.Length;
|
||||||
|
|
||||||
var s = asFlags
|
var s = asFlags
|
||||||
? ToStringMulti(v, fields, n)
|
? ToStringMulti(v, fields, n, enumLiteralFlags)
|
||||||
: ToStringSingle(v, fields, n);
|
: ToStringSingle(v, fields, n, enumLiteralFlags);
|
||||||
return s ?? java.lang.Long.toString(v);
|
return s ?? java.lang.Long.toString(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string ToStringSingle(long v, java.lang.reflect.Field[] fields, int n)
|
static string ToStringSingle(long v, java.lang.reflect.Field[] fields, int n,
|
||||||
|
int enumLiteralFlags)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
var f = fields[i];
|
var f = fields[i];
|
||||||
if (f.getModifiers() == ( java.lang.reflect.Modifier.PUBLIC
|
if (f.getModifiers() == enumLiteralFlags)
|
||||||
| java.lang.reflect.Modifier.STATIC))
|
|
||||||
{
|
{
|
||||||
f.setAccessible(true);
|
f.setAccessible(true);
|
||||||
if (f.getLong(null) == v)
|
if (f.getLong(null) == v)
|
||||||
@ -288,7 +292,8 @@ namespace system
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string ToStringMulti(long v, java.lang.reflect.Field[] fields, int n)
|
static string ToStringMulti(long v, java.lang.reflect.Field[] fields, int n,
|
||||||
|
int enumLiteralFlags)
|
||||||
{
|
{
|
||||||
var v0 = v;
|
var v0 = v;
|
||||||
var sb = new java.lang.StringBuilder();
|
var sb = new java.lang.StringBuilder();
|
||||||
@ -297,8 +302,7 @@ namespace system
|
|||||||
for (int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
var f = fields[i];
|
var f = fields[i];
|
||||||
if (f.getModifiers() == ( java.lang.reflect.Modifier.PUBLIC
|
if (f.getModifiers() == enumLiteralFlags)
|
||||||
| java.lang.reflect.Modifier.STATIC))
|
|
||||||
{
|
{
|
||||||
f.setAccessible(true);
|
f.setAccessible(true);
|
||||||
var fv = f.getLong(null);
|
var fv = f.getLong(null);
|
||||||
|
@ -89,7 +89,7 @@ namespace system
|
|||||||
|
|
||||||
if (! ( proxyType is RuntimeType proxyRuntimeType
|
if (! ( proxyType is RuntimeType proxyRuntimeType
|
||||||
&& proxyRuntimeType.IsCastableToGenericInterface(castToType,
|
&& proxyRuntimeType.IsCastableToGenericInterface(castToType,
|
||||||
(parentObject is system.Array.ProxySyncRoot parentArray) )))
|
(parentObject is system.Array.ProxySyncRoot) )))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -183,8 +183,8 @@ namespace system
|
|||||||
|
|
||||||
public static void ThrowInvalidCastException(object objToCast, System.Type castToType)
|
public static void ThrowInvalidCastException(object objToCast, System.Type castToType)
|
||||||
{
|
{
|
||||||
string msg = "Unable to cast object of type '" + objToCast.GetType().Name
|
string msg = "Unable to cast object of type '" + objToCast.GetType()
|
||||||
+ "' to type '" + castToType.Name + "'.";
|
+ "' to type '" + castToType + "'.";
|
||||||
throw new InvalidCastException(msg);
|
throw new InvalidCastException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,8 +200,20 @@ namespace system
|
|||||||
// this is a marker interface used by the system.RuntimeType constructor
|
// this is a marker interface used by the system.RuntimeType constructor
|
||||||
// to identify generic types. this is implemented by interface types;
|
// to identify generic types. this is implemented by interface types;
|
||||||
// class types implement IGenericObject, which derives from this type.
|
// class types implement IGenericObject, which derives from this type.
|
||||||
|
|
||||||
|
// it also makes it easy to specify ProGuard rules for Android 'R8':
|
||||||
|
|
||||||
|
// -keepclassmembers class * implements system.IGenericEntity {
|
||||||
|
// public static final java.lang.String ?generic?variance;
|
||||||
|
// public static final *** ?generic?info?class;
|
||||||
|
// private system.RuntimeType ?generic?type;
|
||||||
|
// public static final *** ?generic?info?method (...);
|
||||||
|
// <init>(...);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface IGenericObject : IGenericEntity
|
interface IGenericObject : IGenericEntity
|
||||||
{
|
{
|
||||||
// Returns the type of a generic object (i.e. its '-generic-type' field).
|
// Returns the type of a generic object (i.e. its '-generic-type' field).
|
||||||
|
@ -1285,7 +1285,7 @@ namespace system.globalization {
|
|||||||
var iterator = JavaCollator.getCollationElementIterator("" + ch0);
|
var iterator = JavaCollator.getCollationElementIterator("" + ch0);
|
||||||
if (iterator.next() != 0)
|
if (iterator.next() != 0)
|
||||||
{
|
{
|
||||||
throw new System.Globalization.CultureNotFoundException(
|
throw new PlatformNotSupportedException(
|
||||||
"unexpected value for UNICODE NULL");
|
"unexpected value for UNICODE NULL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,9 @@ namespace system.globalization {
|
|||||||
public static CultureInfo CurrentCulture
|
public static CultureInfo CurrentCulture
|
||||||
=> system.threading.Thread.CurrentThread.CurrentCulture;
|
=> system.threading.Thread.CurrentThread.CurrentCulture;
|
||||||
|
|
||||||
|
public static CultureInfo CurrentUICulture
|
||||||
|
=> system.threading.Thread.CurrentThread.CurrentCulture;
|
||||||
|
|
||||||
public static CultureInfo InvariantCulture => s_InvariantCultureInfo;
|
public static CultureInfo InvariantCulture => s_InvariantCultureInfo;
|
||||||
|
|
||||||
public virtual object Clone() => throw new System.NotImplementedException();
|
public virtual object Clone() => throw new System.NotImplementedException();
|
||||||
|
@ -9,7 +9,20 @@ namespace system
|
|||||||
[java.attr.RetainType] private java.util.UUID _uuid;
|
[java.attr.RetainType] private java.util.UUID _uuid;
|
||||||
private java.util.UUID uuid => _uuid ?? (_uuid = new java.util.UUID(0, 0));
|
private java.util.UUID uuid => _uuid ?? (_uuid = new java.util.UUID(0, 0));
|
||||||
|
|
||||||
public Guid(string g) => _uuid = java.util.UUID.fromString(g);
|
public Guid(string g)
|
||||||
|
{
|
||||||
|
if (g.Length == 32)
|
||||||
|
{
|
||||||
|
var g1 = (java.lang.CharSequence) (object) g;
|
||||||
|
g = new java.lang.StringBuilder(36)
|
||||||
|
.append(g1, 0, 0 + 8).append('-')
|
||||||
|
.append(g1, 8, 8 + 4).append('-')
|
||||||
|
.append(g1, 12, 12 + 4).append('-')
|
||||||
|
.append(g1, 16, 16 + 4).append('-')
|
||||||
|
.append(g1, 20, 20 + 12).ToString();
|
||||||
|
}
|
||||||
|
_uuid = java.util.UUID.fromString(g);
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() => uuid.ToString();
|
public override string ToString() => uuid.ToString();
|
||||||
public string ToString(string format) => ToString(format, null);
|
public string ToString(string format) => ToString(format, null);
|
||||||
|
@ -9,11 +9,7 @@ namespace system
|
|||||||
public abstract int CompareTo(object obj);
|
public abstract int CompareTo(object obj);
|
||||||
|
|
||||||
[java.attr.RetainName]
|
[java.attr.RetainName]
|
||||||
public int compareTo(object obj)
|
public int compareTo(object obj) => this.CompareTo(obj);
|
||||||
{
|
|
||||||
//return ((System.IComparable) this).CompareTo(obj);
|
|
||||||
return this.CompareTo(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,10 +49,28 @@ namespace system
|
|||||||
public static double Tan(double a) => java.lang.Math.tan(a);
|
public static double Tan(double a) => java.lang.Math.tan(a);
|
||||||
public static double Tanh(double a) => java.lang.Math.tanh(a);
|
public static double Tanh(double a) => java.lang.Math.tanh(a);
|
||||||
|
|
||||||
|
public static double Asin(double a) => java.lang.Math.asin(a);
|
||||||
|
public static double Asinh(double a) =>
|
||||||
|
java.lang.Math.log(a + java.lang.Math.sqrt(a * a + 1.0));
|
||||||
|
public static double Acos(double a) => java.lang.Math.acos(a);
|
||||||
|
public static double Acosh(double a) =>
|
||||||
|
java.lang.Math.log(a + java.lang.Math.sqrt(a * a - 1.0));
|
||||||
|
public static double Atan(double a) => java.lang.Math.atan(a);
|
||||||
|
public static double Atan2(double x, double y) => java.lang.Math.atan2(x, y);
|
||||||
|
public static double Atanh(double a) => 0.5 * java.lang.Math.log((1 + a) / (1 - a));
|
||||||
|
|
||||||
|
public static double Cbrt(double a) => java.lang.Math.cbrt(a);
|
||||||
|
public static double Exp(double a) => java.lang.Math.exp(a);
|
||||||
public static double Pow(double a, double b) => java.lang.Math.pow(a, b);
|
public static double Pow(double a, double b) => java.lang.Math.pow(a, b);
|
||||||
public static double Sqrt(double a) => java.lang.Math.sqrt(a);
|
public static double Sqrt(double a) => java.lang.Math.sqrt(a);
|
||||||
public static double ScaleB(double x, int n) => java.lang.Math.scalb(x, n);
|
public static double ScaleB(double x, int n) => java.lang.Math.scalb(x, n);
|
||||||
|
|
||||||
|
public static double Ceiling(double a) => java.lang.Math.ceil(a);
|
||||||
|
public static double Floor(double a) => java.lang.Math.floor(a);
|
||||||
|
public static double IEEERemainder(double x, double y) =>
|
||||||
|
java.lang.Math.IEEEremainder(x, y);
|
||||||
|
public static double CopySign(double x, double y) => java.lang.Math.copySign(x, y);
|
||||||
|
|
||||||
public static double Round(double a)
|
public static double Round(double a)
|
||||||
{
|
{
|
||||||
// java round clamps the values to Long.MIN_VALUE .. Long.MAX_VALUE
|
// java round clamps the values to Long.MIN_VALUE .. Long.MAX_VALUE
|
||||||
@ -74,6 +92,187 @@ namespace system
|
|||||||
|
|
||||||
public static void OverflowException()
|
public static void OverflowException()
|
||||||
=> throw new System.OverflowException("Arithmetic operation resulted in an overflow.");
|
=> throw new System.OverflowException("Arithmetic operation resulted in an overflow.");
|
||||||
|
|
||||||
|
public static double BitDecrement(double a)
|
||||||
|
{
|
||||||
|
// java.lang.Math.nextDown(double)
|
||||||
|
if (java.lang.Double.isNaN(a) || a == java.lang.Double.NEGATIVE_INFINITY)
|
||||||
|
return a;
|
||||||
|
if (a == 0.0)
|
||||||
|
return -java.lang.Double.MIN_VALUE;
|
||||||
|
return java.lang.Double.longBitsToDouble(
|
||||||
|
java.lang.Double.doubleToRawLongBits(a) +
|
||||||
|
((a > 0.0) ? -1L : 1L));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double BitIncrement(double a)
|
||||||
|
{
|
||||||
|
// java.lang.Math.nextUp(double)
|
||||||
|
if (java.lang.Double.isNaN(a) || a == java.lang.Double.POSITIVE_INFINITY)
|
||||||
|
return a;
|
||||||
|
a += 0.0;
|
||||||
|
return java.lang.Double.longBitsToDouble(
|
||||||
|
java.lang.Double.doubleToRawLongBits(a) +
|
||||||
|
((a >= 0.0) ? 1L : -1L));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double MaxMagnitude(double x, double y)
|
||||||
|
{
|
||||||
|
var ax = java.lang.Math.abs(x);
|
||||||
|
var ay = java.lang.Math.abs(y);
|
||||||
|
return ( (ax > ay)
|
||||||
|
|| (ax == ay && x >= 0.0)
|
||||||
|
|| java.lang.Double.isNaN(ax)) ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double MinMagnitude(double x, double y)
|
||||||
|
{
|
||||||
|
var ax = java.lang.Math.abs(x);
|
||||||
|
var ay = java.lang.Math.abs(y);
|
||||||
|
return ( (ax < ay)
|
||||||
|
|| (ax == ay && x < 0.0)
|
||||||
|
|| java.lang.Double.isNaN(ax)) ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Log(double a) => java.lang.Math.log(a);
|
||||||
|
public static double Log10(double a) => java.lang.Math.log10(a);
|
||||||
|
public static double Log2(double a) => java.lang.Math.log(a) / java.lang.Math.log(2.0);
|
||||||
|
public static int ILogB(double a) => (int) (java.lang.Math.log(a) / java.lang.Math.log(2.0));
|
||||||
|
|
||||||
|
public static double Log(double a, double b)
|
||||||
|
{
|
||||||
|
if (java.lang.Double.isNaN(a))
|
||||||
|
return a;
|
||||||
|
if (java.lang.Double.isNaN(b))
|
||||||
|
return b;
|
||||||
|
if ( (b == 1.0)
|
||||||
|
|| ( (a != 1.0)
|
||||||
|
&& ( b == 0.0
|
||||||
|
|| b == java.lang.Double.POSITIVE_INFINITY)))
|
||||||
|
return java.lang.Double.NaN;
|
||||||
|
return java.lang.Math.log(a) / java.lang.Math.log(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static class MathF
|
||||||
|
{
|
||||||
|
public static int Sign(float a) => (int) java.lang.Math.signum(a);
|
||||||
|
public static float Abs(float a) => (a < 0) ? -a : a;
|
||||||
|
public static float Min(float a, float b) => (a <= b) ? a : b;
|
||||||
|
public static float Max(float a, float b) => (a >= b) ? a : b;
|
||||||
|
|
||||||
|
public static float Sin(float a) => (float) java.lang.Math.sin(a);
|
||||||
|
public static float Sinh(float a) => (float) java.lang.Math.sinh(a);
|
||||||
|
public static float Cos(float a) => (float) java.lang.Math.cos(a);
|
||||||
|
public static float Cosh(float a) => (float) java.lang.Math.cosh(a);
|
||||||
|
public static float Tan(float a) => (float) java.lang.Math.tan(a);
|
||||||
|
public static float Tanh(float a) => (float) java.lang.Math.tanh(a);
|
||||||
|
|
||||||
|
public static float Asin(float a) => (float) java.lang.Math.asin(a);
|
||||||
|
public static float Asinh(float a) => (float)
|
||||||
|
java.lang.Math.log(a + java.lang.Math.sqrt((double) a * a + 1.0));
|
||||||
|
public static float Acos(float a) => (float) java.lang.Math.acos(a);
|
||||||
|
public static float Acosh(float a) => (float)
|
||||||
|
java.lang.Math.log(a + java.lang.Math.sqrt((double) a * a - 1.0));
|
||||||
|
public static float Atan(float a) => (float) java.lang.Math.atan(a);
|
||||||
|
public static float Atan2(float x, double y) => (float) java.lang.Math.atan2(x, y);
|
||||||
|
public static float Atanh(float a) =>
|
||||||
|
(float) java.lang.Math.log((1 + a) / (1 - a)) * 0.5f;
|
||||||
|
|
||||||
|
public static float Cbrt(float a) => (float) java.lang.Math.cbrt(a);
|
||||||
|
public static float Exp(float a) => (float) java.lang.Math.exp(a);
|
||||||
|
public static float Pow(float a, float b) => (float) java.lang.Math.pow(a, b);
|
||||||
|
public static float Sqrt(float a) => (float) java.lang.Math.sqrt(a);
|
||||||
|
public static float ScaleB(float x, int n) => (float) java.lang.Math.scalb(x, n);
|
||||||
|
|
||||||
|
public static float Ceiling(float a) => (float) java.lang.Math.ceil(a);
|
||||||
|
public static float Floor(float a) => (float) java.lang.Math.floor(a);
|
||||||
|
public static float IEEERemainder(float x, float y) =>
|
||||||
|
(float) java.lang.Math.IEEEremainder(x, y);
|
||||||
|
public static float CopySign(float x, float y) => java.lang.Math.copySign(x, y);
|
||||||
|
|
||||||
|
public static float Round(float a)
|
||||||
|
{
|
||||||
|
// java round clamps the values to Long.MIN_VALUE .. Long.MAX_VALUE
|
||||||
|
// so we have to use floor rather than round
|
||||||
|
if (a > System.Int64.MaxValue)
|
||||||
|
return (float) java.lang.Math.floor(a + 0.5);
|
||||||
|
else if (a < System.Int64.MinValue)
|
||||||
|
return (float) java.lang.Math.floor(a - 0.5);
|
||||||
|
else
|
||||||
|
return (float) java.lang.Math.round(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Truncate(float a)
|
||||||
|
{
|
||||||
|
if (! (java.lang.Float.isInfinite(a) || java.lang.Float.isNaN(a)))
|
||||||
|
a = (float) ((long) a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float BitDecrement(float a)
|
||||||
|
{
|
||||||
|
// java.lang.Math.nextDown(float)
|
||||||
|
if (java.lang.Float.isNaN(a) || a == java.lang.Float.NEGATIVE_INFINITY)
|
||||||
|
return a;
|
||||||
|
if (a == 0.0f)
|
||||||
|
return -java.lang.Float.MIN_VALUE;
|
||||||
|
return java.lang.Float.intBitsToFloat(
|
||||||
|
java.lang.Float.floatToRawIntBits(a) +
|
||||||
|
((a > 0.0f) ? -1 : 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float BitIncrement(float a)
|
||||||
|
{
|
||||||
|
// java.lang.Math.nextUp(float)
|
||||||
|
if (java.lang.Float.isNaN(a) || a == java.lang.Float.POSITIVE_INFINITY)
|
||||||
|
return a;
|
||||||
|
a += 0.0f;
|
||||||
|
return java.lang.Float.intBitsToFloat(
|
||||||
|
java.lang.Float.floatToRawIntBits(a) +
|
||||||
|
((a >= 0.0f) ? 1 : -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float MaxMagnitude(float x, float y)
|
||||||
|
{
|
||||||
|
var ax = java.lang.Math.abs(x);
|
||||||
|
var ay = java.lang.Math.abs(y);
|
||||||
|
return ( (ax > ay)
|
||||||
|
|| (ax == ay && x >= 0.0f)
|
||||||
|
|| java.lang.Float.isNaN(ax)) ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float MinMagnitude(float x, float y)
|
||||||
|
{
|
||||||
|
var ax = java.lang.Math.abs(x);
|
||||||
|
var ay = java.lang.Math.abs(y);
|
||||||
|
return ( (ax < ay)
|
||||||
|
|| (ax == ay && x < 0.0f)
|
||||||
|
|| java.lang.Float.isNaN(ax)) ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Log(float a) => (float) java.lang.Math.log(a);
|
||||||
|
public static float Log10(float a) => (float) java.lang.Math.log10(a);
|
||||||
|
public static float Log2(float a) => (float) (java.lang.Math.log(a) / java.lang.Math.log(2.0));
|
||||||
|
public static int ILogB(float a) => (int) (java.lang.Math.log(a) / java.lang.Math.log(2.0));
|
||||||
|
|
||||||
|
public static float Log(float a, float b)
|
||||||
|
{
|
||||||
|
if (java.lang.Float.isNaN(a))
|
||||||
|
return a;
|
||||||
|
if (java.lang.Float.isNaN(b))
|
||||||
|
return b;
|
||||||
|
if ( (b == 1.0f)
|
||||||
|
|| ( (a != 1.0f)
|
||||||
|
&& ( b == 0.0f
|
||||||
|
|| b == java.lang.Float.POSITIVE_INFINITY)))
|
||||||
|
return java.lang.Float.NaN;
|
||||||
|
return (float) (java.lang.Math.log(a) / java.lang.Math.log(b));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
124
Baselib/src/System/Reflection/FSharpCompat.cs
Normal file
124
Baselib/src/System/Reflection/FSharpCompat.cs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
|
||||||
|
namespace system.reflection
|
||||||
|
{
|
||||||
|
|
||||||
|
public static class FSharpCompat
|
||||||
|
{
|
||||||
|
|
||||||
|
// we don't yet translate .Net attributes to Java annotations,
|
||||||
|
// so we have to fake some attributes to support F# ToString()
|
||||||
|
|
||||||
|
public static object[] GetCustomAttributes_Type(java.lang.Class scanClass,
|
||||||
|
java.lang.Class attrClass)
|
||||||
|
{
|
||||||
|
// we manufacture a CompilationMapping attribute for a type
|
||||||
|
// type implements at least three specific interfaces.
|
||||||
|
// if it has a nested Tags class, it is a (discriminated union)
|
||||||
|
// SumType; otherwise it is a plain RecordType.
|
||||||
|
|
||||||
|
if (IsFSharpAttr(attrClass) && IsFSharpType(scanClass))
|
||||||
|
{
|
||||||
|
int sourceConstructFlags = IsFSharpSumType(scanClass)
|
||||||
|
? /* SumType */ 1 : /* RecordType */ 2;
|
||||||
|
|
||||||
|
return CreateAttr(attrClass, sourceConstructFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static object[] GetCustomAttributes_Property(java.lang.Class declClass,
|
||||||
|
java.lang.Class attrClass)
|
||||||
|
{
|
||||||
|
if (IsFSharpAttr(attrClass))
|
||||||
|
{
|
||||||
|
// we manufacture a CompilationMapping attribute for a property:
|
||||||
|
// - if declared directly in a class that is an "F# type"
|
||||||
|
// and is not also a SumType
|
||||||
|
// - if declared in an inner class, and the outer class
|
||||||
|
// is an "F# type" that is a SumType
|
||||||
|
|
||||||
|
bool isFSharp = IsFSharpType(declClass);
|
||||||
|
if (isFSharp)
|
||||||
|
{
|
||||||
|
if (IsFSharpSumType(declClass))
|
||||||
|
isFSharp = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var outerClass = declClass.getDeclaringClass();
|
||||||
|
if (outerClass != null)
|
||||||
|
isFSharp = IsFSharpType(outerClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFSharp)
|
||||||
|
{
|
||||||
|
return CreateAttr(attrClass, /* Field */ 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RuntimeType.EmptyObjectArray;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static bool IsFSharpType(java.lang.Class scanClass)
|
||||||
|
{
|
||||||
|
int requiredInterfaceCount = 0;
|
||||||
|
foreach (var ifc in scanClass.getInterfaces())
|
||||||
|
{
|
||||||
|
if ( ifc == (java.lang.Class)
|
||||||
|
typeof(System.Collections.IStructuralEquatable)
|
||||||
|
|| ifc == (java.lang.Class)
|
||||||
|
typeof(System.Collections.IStructuralComparable)
|
||||||
|
|| ifc == (java.lang.Class) typeof(System.IComparable))
|
||||||
|
requiredInterfaceCount++;
|
||||||
|
}
|
||||||
|
return (requiredInterfaceCount >= 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static bool IsFSharpSumType(java.lang.Class scanClass)
|
||||||
|
=> system.RuntimeType.FindInnerClass(scanClass, "Tags") != null;
|
||||||
|
|
||||||
|
|
||||||
|
private static bool IsFSharpAttr(java.lang.Class attrClass)
|
||||||
|
=> attrClass == (java.lang.Class)
|
||||||
|
typeof(Microsoft.FSharp.Core.CompilationMappingAttribute);
|
||||||
|
|
||||||
|
|
||||||
|
private static object[] CreateAttr(java.lang.Class attrClass,
|
||||||
|
int sourceConstructFlags)
|
||||||
|
{
|
||||||
|
foreach (var _constr in attrClass.getConstructors())
|
||||||
|
{
|
||||||
|
#pragma warning disable 0436
|
||||||
|
var constr = (java.lang.reflect.Constructor) (object) _constr;
|
||||||
|
#pragma warning restore 0436
|
||||||
|
var parameters = constr.getParameterTypes();
|
||||||
|
if ( parameters.Length == 2
|
||||||
|
&& parameters[0] == java.lang.Integer.TYPE
|
||||||
|
&& parameters[1].isMemberClass())
|
||||||
|
{
|
||||||
|
var created = constr.newInstance(new object[] {
|
||||||
|
java.lang.Integer.valueOf(sourceConstructFlags),
|
||||||
|
null
|
||||||
|
});
|
||||||
|
return new object[] { created };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace Microsoft.FSharp.Core
|
||||||
|
{
|
||||||
|
[java.attr.Discard] // discard in output
|
||||||
|
public class CompilationMappingAttribute { }
|
||||||
|
}
|
@ -51,7 +51,7 @@ namespace system.reflection
|
|||||||
|
|
||||||
public bool IsPrivate => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
|
public bool IsPrivate => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
|
||||||
|
|
||||||
public bool IsFamily => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family;
|
public bool IsFamily => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family;
|
||||||
|
|
||||||
public bool IsAssembly => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly;
|
public bool IsAssembly => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly;
|
||||||
|
|
||||||
|
@ -99,6 +99,12 @@ namespace system.reflection
|
|||||||
throw new NotImplementedException("Assembly.GetCustomAttributes");
|
throw new NotImplementedException("Assembly.GetCustomAttributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Properties
|
||||||
|
//
|
||||||
|
|
||||||
|
public override bool ReflectionOnly => false;
|
||||||
|
|
||||||
//
|
//
|
||||||
// ISerializable
|
// ISerializable
|
||||||
//
|
//
|
||||||
|
@ -127,7 +127,7 @@ namespace system.reflection
|
|||||||
object[] parameters, CultureInfo culture)
|
object[] parameters, CultureInfo culture)
|
||||||
{
|
{
|
||||||
if (parameters == null)
|
if (parameters == null)
|
||||||
parameters = new object[0];
|
parameters = system.RuntimeType.EmptyObjectArray;
|
||||||
int numParameters = parameters.Length;
|
int numParameters = parameters.Length;
|
||||||
|
|
||||||
if (HasUniqueArg)
|
if (HasUniqueArg)
|
||||||
|
@ -12,6 +12,7 @@ namespace system.reflection
|
|||||||
{
|
{
|
||||||
[java.attr.RetainType] public java.lang.reflect.Field JavaField;
|
[java.attr.RetainType] public java.lang.reflect.Field JavaField;
|
||||||
[java.attr.RetainType] public system.RuntimeType reflectedType;
|
[java.attr.RetainType] public system.RuntimeType reflectedType;
|
||||||
|
[java.attr.RetainType] private FieldAttributes cachedAttrs = 0;
|
||||||
|
|
||||||
//
|
//
|
||||||
// constructor
|
// constructor
|
||||||
@ -30,69 +31,83 @@ namespace system.reflection
|
|||||||
|
|
||||||
public static FieldInfo[] GetFields(BindingFlags bindingAttr, RuntimeType initialType)
|
public static FieldInfo[] GetFields(BindingFlags bindingAttr, RuntimeType initialType)
|
||||||
{
|
{
|
||||||
var list = new System.Collections.Generic.List<FieldInfo>();
|
var list = new java.util.ArrayList();
|
||||||
|
|
||||||
BindingFlagsIterator.Run(bindingAttr, initialType, MemberTypes.Field,
|
BindingFlagsIterator.Run(bindingAttr & ~BindingFlags.GetField,
|
||||||
|
initialType, MemberTypes.Field,
|
||||||
(javaAccessibleObject) =>
|
(javaAccessibleObject) =>
|
||||||
{
|
{
|
||||||
var javaField = (java.lang.reflect.Field) javaAccessibleObject;
|
var javaField = (java.lang.reflect.Field) javaAccessibleObject;
|
||||||
javaField.setAccessible(true);
|
javaField.setAccessible(true);
|
||||||
list.Add(new RuntimeFieldInfo(javaField, initialType));
|
list.add(new RuntimeFieldInfo(javaField, initialType));
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
return list.ToArray();
|
return (RuntimeFieldInfo[]) list.toArray(new RuntimeFieldInfo[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
public override System.Type FieldType
|
public override System.Type FieldType
|
||||||
=> system.RuntimeType.GetType(JavaField.getType());
|
=> system.RuntimeType.GetType(JavaField.getType());
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
public override object GetValue(object obj)
|
public override object GetValue(object obj)
|
||||||
=> throw new PlatformNotSupportedException();
|
=> system.RuntimeType.UnboxJavaReturnValue(JavaField.get(obj));
|
||||||
|
|
||||||
public override void SetValue(object obj, object value, BindingFlags invokeAttr,
|
public override void SetValue(object obj, object value, BindingFlags invokeAttr,
|
||||||
Binder binder, CultureInfo culture)
|
Binder binder, CultureInfo culture)
|
||||||
=> throw new PlatformNotSupportedException();
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
public override System.Reflection.FieldAttributes Attributes
|
public override FieldAttributes Attributes
|
||||||
=> throw new PlatformNotSupportedException();
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var attrs = cachedAttrs;
|
||||||
|
if (attrs == 0)
|
||||||
|
{
|
||||||
|
int modifiers = JavaField.getModifiers();
|
||||||
|
if ((modifiers & java.lang.reflect.Modifier.PUBLIC) != 0)
|
||||||
|
attrs |= FieldAttributes.Public;
|
||||||
|
if ((modifiers & java.lang.reflect.Modifier.PRIVATE) != 0)
|
||||||
|
attrs |= FieldAttributes.Private;
|
||||||
|
if ((modifiers & java.lang.reflect.Modifier.PROTECTED) != 0)
|
||||||
|
attrs |= FieldAttributes.Family;
|
||||||
|
if ((modifiers & java.lang.reflect.Modifier.TRANSIENT) != 0)
|
||||||
|
attrs |= FieldAttributes.NotSerialized;
|
||||||
|
|
||||||
public override System.Type DeclaringType
|
if ((modifiers & java.lang.reflect.Modifier.STATIC) != 0)
|
||||||
=> throw new PlatformNotSupportedException();
|
{
|
||||||
|
attrs |= FieldAttributes.Static;
|
||||||
|
if ( ((modifiers & java.lang.reflect.Modifier.FINAL) != 0)
|
||||||
|
&& JavaField.getType().isPrimitive()
|
||||||
|
&& JavaField.get(null) != null)
|
||||||
|
{
|
||||||
|
attrs |= FieldAttributes.Literal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override System.Type ReflectedType
|
cachedAttrs = attrs;
|
||||||
=> throw new PlatformNotSupportedException();
|
}
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Type ReflectedType => reflectedType;
|
||||||
|
|
||||||
|
public override Type DeclaringType
|
||||||
|
=> system.RuntimeType.GetType(JavaField.getDeclaringClass());
|
||||||
|
|
||||||
public override string Name => JavaField.getName();
|
public override string Name => JavaField.getName();
|
||||||
|
|
||||||
public override object GetRawConstantValue()
|
public override object GetRawConstantValue()
|
||||||
{
|
{
|
||||||
if ((JavaField.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0)
|
if (0 != (JavaField.getModifiers() & ( java.lang.reflect.Modifier.STATIC
|
||||||
|
| java.lang.reflect.Modifier.FINAL))
|
||||||
|
&& JavaField.getType().isPrimitive())
|
||||||
{
|
{
|
||||||
var value = JavaField.get(null);
|
return GetValue(null);
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case java.lang.Boolean boolBox:
|
|
||||||
return system.Boolean.Box(boolBox.booleanValue() ? 1 : 0);
|
|
||||||
case java.lang.Byte byteBox:
|
|
||||||
return system.SByte.Box(byteBox.byteValue());
|
|
||||||
case java.lang.Character charBox:
|
|
||||||
return system.Char.Box(charBox.charValue());
|
|
||||||
case java.lang.Short shortBox:
|
|
||||||
return system.Int16.Box(shortBox.shortValue());
|
|
||||||
case java.lang.Integer intBox:
|
|
||||||
return system.Int32.Box(intBox.intValue());
|
|
||||||
case java.lang.Long longBox:
|
|
||||||
return system.Int64.Box(longBox.longValue());
|
|
||||||
case java.lang.Float floatBox:
|
|
||||||
return system.Single.Box(floatBox.floatValue());
|
|
||||||
case java.lang.Double doubleBox:
|
|
||||||
return system.Double.Box(doubleBox.doubleValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw new System.NotSupportedException();
|
throw new System.NotSupportedException();
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ namespace system.reflection
|
|||||||
string originalName = javaMethod.getName();
|
string originalName = javaMethod.getName();
|
||||||
var compareName = RuntimeMethodInfo.AdjustedMethodName(originalName);
|
var compareName = RuntimeMethodInfo.AdjustedMethodName(originalName);
|
||||||
|
|
||||||
if (name == compareName)
|
if (name == compareName && CompareParameters(javaMethod, types))
|
||||||
{
|
{
|
||||||
javaMethod.setAccessible(true);
|
javaMethod.setAccessible(true);
|
||||||
var jmodifiers = javaMethod.getModifiers();
|
var jmodifiers = javaMethod.getModifiers();
|
||||||
@ -63,6 +63,26 @@ namespace system.reflection
|
|||||||
});
|
});
|
||||||
|
|
||||||
return foundMethod;
|
return foundMethod;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma warning disable 0436
|
||||||
|
static bool CompareParameters(java.lang.reflect.Method javaMethod, Type[] types)
|
||||||
|
{
|
||||||
|
if (types == null)
|
||||||
|
return true;
|
||||||
|
var paramTypes = javaMethod.getParameterTypes();
|
||||||
|
if (types.Length != paramTypes.Length)
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < paramTypes.Length; i++)
|
||||||
|
{
|
||||||
|
if (! object.ReferenceEquals(
|
||||||
|
types[i], system.RuntimeType.GetType(paramTypes[i])))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#pragma warning restore 0436
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -76,8 +96,6 @@ namespace system.reflection
|
|||||||
throw new PlatformNotSupportedException("non-null binder");
|
throw new PlatformNotSupportedException("non-null binder");
|
||||||
if (callConvention != CallingConventions.Any)
|
if (callConvention != CallingConventions.Any)
|
||||||
throw new PlatformNotSupportedException("calling convention must be Any");
|
throw new PlatformNotSupportedException("calling convention must be Any");
|
||||||
if (types != null && types.Length != 0)
|
|
||||||
throw new PlatformNotSupportedException("non-null types");
|
|
||||||
if (modifiers != null)
|
if (modifiers != null)
|
||||||
throw new PlatformNotSupportedException("non-null modifiers");
|
throw new PlatformNotSupportedException("non-null modifiers");
|
||||||
}
|
}
|
||||||
@ -337,7 +355,7 @@ namespace system.reflection
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
// GetParameters
|
||||||
//
|
//
|
||||||
|
|
||||||
public override ParameterInfo[] GetParameters()
|
public override ParameterInfo[] GetParameters()
|
||||||
|
@ -13,7 +13,7 @@ namespace system.reflection
|
|||||||
{
|
{
|
||||||
[java.attr.RetainType] public java.security.ProtectionDomain JavaDomain;
|
[java.attr.RetainType] public java.security.ProtectionDomain JavaDomain;
|
||||||
|
|
||||||
public override System.Type[] GetTypes() => new System.Type[0];
|
public override System.Type[] GetTypes() => system.RuntimeType.EmptyTypeArray;
|
||||||
|
|
||||||
public MetadataImport MetadataImport => _MetadataImport;
|
public MetadataImport MetadataImport => _MetadataImport;
|
||||||
public StructLayoutAttribute StructLayoutAttribute => _StructLayoutAttribute;
|
public StructLayoutAttribute StructLayoutAttribute => _StructLayoutAttribute;
|
||||||
|
275
Baselib/src/System/Reflection/RuntimePropertyInfo.cs
Normal file
275
Baselib/src/System/Reflection/RuntimePropertyInfo.cs
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace system.reflection
|
||||||
|
{
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public sealed class RuntimePropertyInfo : PropertyInfo, ISerializable
|
||||||
|
{
|
||||||
|
#pragma warning disable 0436
|
||||||
|
[java.attr.RetainType] private java.lang.reflect.Method JavaGetMethod;
|
||||||
|
[java.attr.RetainType] private java.lang.reflect.Method JavaSetMethod;
|
||||||
|
#pragma warning restore 0436
|
||||||
|
[java.attr.RetainType] private string propertyName;
|
||||||
|
[java.attr.RetainType] private system.RuntimeType propertyType;
|
||||||
|
[java.attr.RetainType] private system.RuntimeType reflectedType;
|
||||||
|
[java.attr.RetainType] private system.RuntimeType declaringType;
|
||||||
|
|
||||||
|
//
|
||||||
|
// GetMethod (called by system.RuntimeType.GetPropertyImpl)
|
||||||
|
//
|
||||||
|
|
||||||
|
public static PropertyInfo GetProperty(string name, BindingFlags bindingAttr,
|
||||||
|
Binder binder, Type returnType,
|
||||||
|
Type[] types, ParameterModifier[] modifiers,
|
||||||
|
RuntimeType initialType)
|
||||||
|
{
|
||||||
|
ThrowHelper.ThrowIfNull(name);
|
||||||
|
|
||||||
|
if (types != null && types.Length != 0) // if indexed property
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
#pragma warning disable 0436
|
||||||
|
java.lang.reflect.Method getMethod = null;
|
||||||
|
java.lang.Class getClass = null;
|
||||||
|
java.lang.reflect.Method setMethod = null;
|
||||||
|
java.lang.Class setClass = null;
|
||||||
|
#pragma warning restore 0436
|
||||||
|
|
||||||
|
BindingFlagsIterator.Run(bindingAttr & ~BindingFlags.GetProperty,
|
||||||
|
initialType, MemberTypes.Method,
|
||||||
|
(javaAccessibleObject) =>
|
||||||
|
{
|
||||||
|
#pragma warning disable 0436
|
||||||
|
var javaMethod = (java.lang.reflect.Method) javaAccessibleObject;
|
||||||
|
#pragma warning restore 0436
|
||||||
|
|
||||||
|
var cls = IsGetMethod(javaMethod, name, returnType);
|
||||||
|
if (cls != null)
|
||||||
|
{
|
||||||
|
getMethod = javaMethod;
|
||||||
|
getClass = cls;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cls = IsSetMethod(javaMethod, name, returnType);
|
||||||
|
if (cls != null)
|
||||||
|
{
|
||||||
|
setMethod = javaMethod;
|
||||||
|
setClass = cls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (getClass != null)
|
||||||
|
{
|
||||||
|
if (setClass != null && setClass != getClass)
|
||||||
|
setMethod = null;
|
||||||
|
}
|
||||||
|
else if (setClass != null)
|
||||||
|
{
|
||||||
|
getClass = setClass;
|
||||||
|
}
|
||||||
|
else // neither get nor set methods
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new RuntimePropertyInfo(getMethod, setMethod, getClass, initialType);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma warning disable 0436
|
||||||
|
static java.lang.Class IsGetMethod(java.lang.reflect.Method javaMethod,
|
||||||
|
string propertyName, Type propertyType)
|
||||||
|
{
|
||||||
|
if (javaMethod.getName() == "get_" + propertyName)
|
||||||
|
{
|
||||||
|
javaMethod.setAccessible(true);
|
||||||
|
var returnClass = javaMethod.getReturnType();
|
||||||
|
if ( object.ReferenceEquals(propertyType, null)
|
||||||
|
|| object.ReferenceEquals(propertyType,
|
||||||
|
system.RuntimeType.GetType(returnClass)))
|
||||||
|
{
|
||||||
|
return returnClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static java.lang.Class IsSetMethod(java.lang.reflect.Method javaMethod,
|
||||||
|
string propertyName, Type propertyType)
|
||||||
|
{
|
||||||
|
if (javaMethod.getName() == "set_" + propertyName)
|
||||||
|
{
|
||||||
|
javaMethod.setAccessible(true);
|
||||||
|
var paramClasses = javaMethod.getParameterTypes();
|
||||||
|
if (paramClasses.Length == 1)
|
||||||
|
{
|
||||||
|
var paramClass = paramClasses[0];
|
||||||
|
if ( object.ReferenceEquals(propertyType, null)
|
||||||
|
|| object.ReferenceEquals(propertyType,
|
||||||
|
system.RuntimeType.GetType(paramClass)))
|
||||||
|
{
|
||||||
|
return paramClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#pragma warning restore 0436
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GetProperties (called by system.RuntimeType.GetProperties()
|
||||||
|
//
|
||||||
|
|
||||||
|
public static PropertyInfo[] GetProperties(BindingFlags bindingAttr,
|
||||||
|
RuntimeType initialType)
|
||||||
|
{
|
||||||
|
var list = new java.util.ArrayList();
|
||||||
|
|
||||||
|
BindingFlagsIterator.Run(bindingAttr & ~BindingFlags.GetProperty,
|
||||||
|
initialType, MemberTypes.Method,
|
||||||
|
(javaAccessibleObject) =>
|
||||||
|
{
|
||||||
|
#pragma warning disable 0436
|
||||||
|
var javaMethod = (java.lang.reflect.Method) javaAccessibleObject;
|
||||||
|
#pragma warning restore 0436
|
||||||
|
if (javaMethod.getName().StartsWith("get_"))
|
||||||
|
{
|
||||||
|
javaMethod.setAccessible(true);
|
||||||
|
var returnClass = javaMethod.getReturnType();
|
||||||
|
if ( returnClass != java.lang.Void.TYPE
|
||||||
|
&& javaMethod.getParameterTypes().Length == 0)
|
||||||
|
{
|
||||||
|
list.add(new RuntimePropertyInfo(
|
||||||
|
javaMethod, null, returnClass, initialType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (RuntimePropertyInfo[]) list.toArray(new RuntimePropertyInfo[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// constructor
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma warning disable 0436
|
||||||
|
private RuntimePropertyInfo(java.lang.reflect.Method javaGetMethod,
|
||||||
|
java.lang.reflect.Method javaSetMethod,
|
||||||
|
java.lang.Class javaClass,
|
||||||
|
system.RuntimeType reflectedType)
|
||||||
|
#pragma warning restore 0436
|
||||||
|
{
|
||||||
|
var getOrSetMethod = javaGetMethod ?? javaSetMethod;
|
||||||
|
propertyName = getOrSetMethod.getName().Substring(4);
|
||||||
|
propertyType = (system.RuntimeType) system.RuntimeType.GetType(javaClass);
|
||||||
|
this.JavaGetMethod = javaGetMethod;
|
||||||
|
this.JavaSetMethod = javaSetMethod;
|
||||||
|
this.reflectedType = reflectedType;
|
||||||
|
this.declaringType = (system.RuntimeType) system.RuntimeType.GetType(
|
||||||
|
getOrSetMethod.getDeclaringClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
public override PropertyAttributes Attributes
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override MethodInfo[] GetAccessors(bool nonPublic)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override MethodInfo GetGetMethod(bool nonPublic)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override MethodInfo GetSetMethod(bool nonPublic)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override bool CanRead => (JavaGetMethod != null);
|
||||||
|
public override bool CanWrite => (JavaSetMethod != null);
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Type PropertyType => propertyType;
|
||||||
|
|
||||||
|
public override ParameterInfo[] GetIndexParameters()
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override object GetValue(object obj, BindingFlags invokeAttr,
|
||||||
|
Binder binder, object[] index, CultureInfo culture)
|
||||||
|
{
|
||||||
|
invokeAttr &= ~( BindingFlags.Public | BindingFlags.NonPublic
|
||||||
|
| BindingFlags.Instance | BindingFlags.GetProperty);
|
||||||
|
if (invokeAttr != BindingFlags.Default)
|
||||||
|
throw new PlatformNotSupportedException("bad binding flags " + invokeAttr);
|
||||||
|
if (binder != null)
|
||||||
|
throw new PlatformNotSupportedException("non-null binder");
|
||||||
|
if (culture != null)
|
||||||
|
throw new PlatformNotSupportedException("non-null culture");
|
||||||
|
|
||||||
|
if (index != null || JavaGetMethod == null)
|
||||||
|
throw new ArgumentException();
|
||||||
|
|
||||||
|
return system.RuntimeType.UnboxJavaReturnValue(
|
||||||
|
JavaGetMethod.invoke(obj, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(object obj, object value, BindingFlags invokeAttr,
|
||||||
|
Binder binder, object[] index, CultureInfo culture)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Type ReflectedType => reflectedType;
|
||||||
|
|
||||||
|
public override Type DeclaringType => declaringType;
|
||||||
|
|
||||||
|
public override string Name => propertyName;
|
||||||
|
|
||||||
|
//
|
||||||
|
// custom attributes
|
||||||
|
//
|
||||||
|
|
||||||
|
public override bool IsDefined(Type attributeType, bool inherit)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override object[] GetCustomAttributes(bool inherit)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
||||||
|
{
|
||||||
|
if (attributeType is system.RuntimeType attributeRuntimeType)
|
||||||
|
{
|
||||||
|
// we don't yet translate .Net attributes to Java annotations,
|
||||||
|
// so we have to fake some attributes to support F# ToString()
|
||||||
|
var attrs = system.reflection.FSharpCompat.GetCustomAttributes_Property(
|
||||||
|
declaringType.JavaClassForArray(),
|
||||||
|
attributeRuntimeType.JavaClassForArray());
|
||||||
|
if (attrs != null)
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ISerializable
|
||||||
|
//
|
||||||
|
|
||||||
|
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
564
Baselib/src/System/Reflection/RuntimeType2.cs
Normal file
564
Baselib/src/System/Reflection/RuntimeType2.cs
Normal file
@ -0,0 +1,564 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace system
|
||||||
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
// System/RuntimeType.cs contains methods required by the type
|
||||||
|
// system. System/Reflection/RuntimeType2.cs (this file) contains
|
||||||
|
// methods to provide run-time reflection support.
|
||||||
|
//
|
||||||
|
|
||||||
|
public partial class RuntimeType
|
||||||
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
// FullName
|
||||||
|
//
|
||||||
|
|
||||||
|
public override string FullName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
var declType = DeclaringType;
|
||||||
|
if (! object.ReferenceEquals(declType, null))
|
||||||
|
name = declType.FullName + "+";
|
||||||
|
else if (IsGenericParameter)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = Namespace;
|
||||||
|
if (name != null)
|
||||||
|
name += ".";
|
||||||
|
}
|
||||||
|
name += Name;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Name
|
||||||
|
//
|
||||||
|
|
||||||
|
public override string Name
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var generic = Generic;
|
||||||
|
|
||||||
|
if (JavaClass == null)
|
||||||
|
return GenericParameterName(generic);
|
||||||
|
if (JavaClass.isArray())
|
||||||
|
return (GetType(JavaClass.getComponentType()).Name) + "[]";
|
||||||
|
else
|
||||||
|
return ClassName(generic);
|
||||||
|
|
||||||
|
string ClassName(GenericData generic)
|
||||||
|
{
|
||||||
|
var name = JavaClass.getSimpleName();
|
||||||
|
int numArgsInDeclType = 0;
|
||||||
|
|
||||||
|
var declType = DeclaringType;
|
||||||
|
if (declType is RuntimeType declRuntimeType && declRuntimeType.Generic != null)
|
||||||
|
{
|
||||||
|
// a nested generic type duplicates the parameters of the parent
|
||||||
|
numArgsInDeclType = declRuntimeType.Generic.ArgumentTypes.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic != null)
|
||||||
|
{
|
||||||
|
int numArgs = generic.ArgumentTypes.Length;
|
||||||
|
int index = name.LastIndexOf("$$" + numArgs);
|
||||||
|
if (index != -1)
|
||||||
|
name = name.Substring(0, index);
|
||||||
|
numArgs -= numArgsInDeclType;
|
||||||
|
if (numArgs > 0)
|
||||||
|
name += "`" + numArgs.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
string GenericParameterName(GenericData generic)
|
||||||
|
{
|
||||||
|
if (generic != null)
|
||||||
|
{
|
||||||
|
// generic parameter
|
||||||
|
var argTypes = generic.PrimaryType.Generic.ArgumentTypes;
|
||||||
|
for (int i = 0; i < argTypes.Length; i++)
|
||||||
|
{
|
||||||
|
if (object.ReferenceEquals(argTypes[i], this))
|
||||||
|
{
|
||||||
|
var typeNames = generic.PrimaryType.JavaClass.getTypeParameters();
|
||||||
|
if (i < typeNames.Length)
|
||||||
|
{
|
||||||
|
// if we have a valid generic signature, extract parameter name
|
||||||
|
var nm = typeNames[i].getName();
|
||||||
|
if (! string.IsNullOrEmpty(nm))
|
||||||
|
return nm;
|
||||||
|
}
|
||||||
|
return "T" + i.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null; // invalid combination
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Namespace
|
||||||
|
//
|
||||||
|
|
||||||
|
public override string Namespace
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var javaClass = JavaClass;
|
||||||
|
if (javaClass == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (javaClass.isArray())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
javaClass = javaClass.getComponentType();
|
||||||
|
}
|
||||||
|
while (javaClass.isArray());
|
||||||
|
return GetType(javaClass).Namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
string dottedName = javaClass.getName();
|
||||||
|
int lastIndex = dottedName.LastIndexOf('.');
|
||||||
|
if (lastIndex <= 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
int firstIndex = 0;
|
||||||
|
string resultName = "";
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int nextIndex = dottedName.IndexOf('.', firstIndex);
|
||||||
|
var component = Char.ToUpperInvariant(dottedName[firstIndex])
|
||||||
|
+ dottedName.Substring(firstIndex + 1, nextIndex - firstIndex - 1);
|
||||||
|
resultName += component;
|
||||||
|
if (nextIndex == lastIndex)
|
||||||
|
return resultName;
|
||||||
|
resultName += ".";
|
||||||
|
firstIndex = nextIndex + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DeclaringType
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Type DeclaringType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var javaClass = JavaClass;
|
||||||
|
if (javaClass == null)
|
||||||
|
return null;
|
||||||
|
if (javaClass.isArray())
|
||||||
|
javaClass = javaClass.getComponentType();
|
||||||
|
var declClass = javaClass.getDeclaringClass();
|
||||||
|
return (declClass == null) ? null : GetType(declClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ReflectedType
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Type ReflectedType => DeclaringType;
|
||||||
|
|
||||||
|
//
|
||||||
|
// DeclaringMethod
|
||||||
|
//
|
||||||
|
|
||||||
|
public override MethodBase DeclaringMethod
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
//
|
||||||
|
// BaseType
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Type BaseType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ( JavaClass == null
|
||||||
|
|| object.ReferenceEquals(this, ObjectType)
|
||||||
|
|| IsInterface(this))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (object.ReferenceEquals(this, ExceptionType))
|
||||||
|
{
|
||||||
|
// CilType translates System.Exception to java.lang.Throwable,
|
||||||
|
// and here we map java.lang.Throwable to system.Exception,
|
||||||
|
// thereby creating an infinite loop in which system.Exception
|
||||||
|
// inherits from java.lang.Exception, which inherits from
|
||||||
|
// java.lang.Throwable, which is mapped to system.Exception.
|
||||||
|
// the workaround breaks the infinite loop.
|
||||||
|
return ObjectType;
|
||||||
|
}
|
||||||
|
return FromJavaGenericType(JavaClass.getGenericSuperclass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Module
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Module Module => Assembly.GetModules(false)[0];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Assembly
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Assembly Assembly => system.reflection.RuntimeAssembly.CurrentAssembly;
|
||||||
|
|
||||||
|
//
|
||||||
|
// AssemblyQualifiedName
|
||||||
|
//
|
||||||
|
|
||||||
|
public override string AssemblyQualifiedName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var name = FullName;
|
||||||
|
if (name != null)
|
||||||
|
name = Assembly.CreateQualifiedName(Assembly.FullName, name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GetCustomAttributes
|
||||||
|
//
|
||||||
|
|
||||||
|
public override object[] GetCustomAttributes(bool inherit) => EmptyObjectArray;
|
||||||
|
|
||||||
|
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
||||||
|
{
|
||||||
|
if (attributeType is system.RuntimeType attributeRuntimeType)
|
||||||
|
{
|
||||||
|
// we don't yet translate .Net attributes to Java annotations,
|
||||||
|
// so we have to fake some attributes to support F# ToString()
|
||||||
|
var attrs = system.reflection.FSharpCompat.GetCustomAttributes_Type(
|
||||||
|
this.JavaClass, attributeRuntimeType.JavaClass);
|
||||||
|
if (attrs != null)
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
return EmptyObjectArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// IsDefined
|
||||||
|
//
|
||||||
|
|
||||||
|
public override bool IsDefined(Type attributeType, bool inherit) => false;
|
||||||
|
|
||||||
|
//
|
||||||
|
// GetInterfaces
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Type[] GetInterfaces()
|
||||||
|
{
|
||||||
|
var output = new java.util.HashSet();
|
||||||
|
GetInterfacesInternal(JavaClass, output);
|
||||||
|
return (Type[]) output.toArray(System.Type.EmptyTypes);
|
||||||
|
|
||||||
|
void GetInterfacesInternal(java.lang.Class input, java.util.HashSet output)
|
||||||
|
{
|
||||||
|
foreach (var javaType in input.getGenericInterfaces())
|
||||||
|
{
|
||||||
|
output.add(FromJavaGenericType(javaType));
|
||||||
|
if (javaType is java.lang.Class classType)
|
||||||
|
GetInterfacesInternal(classType, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GetInterface
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Type GetInterface(string name, bool ignoreCase)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
throw new ArgumentNullException();
|
||||||
|
StringComparison cmp = ignoreCase
|
||||||
|
? System.StringComparison.InvariantCultureIgnoreCase
|
||||||
|
: System.StringComparison.InvariantCulture;
|
||||||
|
foreach (var ifc in GetInterfaces())
|
||||||
|
{
|
||||||
|
if (string.Compare(name, ifc.FullName, cmp) == 0)
|
||||||
|
return ifc;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GetNestedTypes
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Type[] GetNestedTypes(BindingFlags bindingAttr)
|
||||||
|
{
|
||||||
|
bool takePublic = (bindingAttr & BindingFlags.Public) != 0;
|
||||||
|
bool takeNonPublic = (bindingAttr & BindingFlags.NonPublic) != 0;
|
||||||
|
if (takePublic || takeNonPublic)
|
||||||
|
{
|
||||||
|
var innerClasses = JavaClass.getDeclaredClasses();
|
||||||
|
if (innerClasses.Length > 0)
|
||||||
|
{
|
||||||
|
var list = new java.util.ArrayList();
|
||||||
|
for (int i = 0; i < innerClasses.Length; i++)
|
||||||
|
{
|
||||||
|
var innerCls = innerClasses[i];
|
||||||
|
var isPublic = (0 != (innerCls.getModifiers()
|
||||||
|
& java.lang.reflect.Modifier.PUBLIC));
|
||||||
|
|
||||||
|
if (takePublic == isPublic || takeNonPublic != isPublic)
|
||||||
|
{
|
||||||
|
var innerType = GetType(innerCls);
|
||||||
|
var generic = ((RuntimeType) innerType).Generic;
|
||||||
|
list.add(generic != null ? generic.PrimaryType : innerType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Type[]) list.toArray(system.RuntimeType.EmptyTypeArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return system.RuntimeType.EmptyTypeArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GetNestedType
|
||||||
|
//
|
||||||
|
|
||||||
|
public override Type GetNestedType(string name, BindingFlags bindingAttr)
|
||||||
|
{
|
||||||
|
ThrowHelper.ThrowIfNull(name);
|
||||||
|
if ((bindingAttr & BindingFlags.IgnoreCase) != 0)
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
var innerCls = FindInnerClass(JavaClass, name);
|
||||||
|
if (innerCls != null)
|
||||||
|
{
|
||||||
|
bool takePublic = (bindingAttr & BindingFlags.Public) != 0;
|
||||||
|
bool takeNonPublic = (bindingAttr & BindingFlags.NonPublic) != 0;
|
||||||
|
var isPublic = (0 != (innerCls.getModifiers()
|
||||||
|
& java.lang.reflect.Modifier.PUBLIC));
|
||||||
|
|
||||||
|
if (takePublic == isPublic || takeNonPublic != isPublic)
|
||||||
|
{
|
||||||
|
var innerType = GetType(innerCls);
|
||||||
|
var generic = ((RuntimeType) innerType).Generic;
|
||||||
|
return (generic != null ? generic.PrimaryType : innerType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// FindInnerClass (public helper)
|
||||||
|
//
|
||||||
|
|
||||||
|
public static java.lang.Class FindInnerClass(
|
||||||
|
java.lang.Class javaClass, string name)
|
||||||
|
{
|
||||||
|
var innerClasses = javaClass.getDeclaredClasses();
|
||||||
|
for (int i = 0; i < innerClasses.Length; i++)
|
||||||
|
{
|
||||||
|
var innerCls = innerClasses[i];
|
||||||
|
if (innerCls.getSimpleName() == name)
|
||||||
|
return innerCls;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reflection on members of the type
|
||||||
|
//
|
||||||
|
|
||||||
|
public override EventInfo GetEvent(string name, BindingFlags bindingAttr)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override FieldInfo GetField(string name, BindingFlags bindingAttr)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override PropertyInfo GetPropertyImpl(
|
||||||
|
string name, BindingFlags bindingAttr, Binder binder, Type returnType,
|
||||||
|
Type[] types, ParameterModifier[] modifiers)
|
||||||
|
{
|
||||||
|
if (JavaClass == null) // if generic parameter
|
||||||
|
return null;
|
||||||
|
return system.reflection.RuntimePropertyInfo.GetProperty(
|
||||||
|
name, bindingAttr, binder, returnType, types, modifiers, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override MethodInfo GetMethodImpl(
|
||||||
|
string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention,
|
||||||
|
Type[] types, ParameterModifier[] modifiers)
|
||||||
|
{
|
||||||
|
if (JavaClass == null) // if generic parameter
|
||||||
|
return null;
|
||||||
|
return system.reflection.RuntimeMethodInfo.GetMethod(
|
||||||
|
name, bindingAttr, binder, callConvention, types, modifiers, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ConstructorInfo GetConstructorImpl(
|
||||||
|
BindingFlags bindingAttr, Binder binder, CallingConventions callConvention,
|
||||||
|
Type[] types, ParameterModifier[] modifiers)
|
||||||
|
{
|
||||||
|
if (JavaClass == null) // if generic parameter
|
||||||
|
return null;
|
||||||
|
return system.reflection.RuntimeConstructorInfo.GetConstructor(
|
||||||
|
bindingAttr, binder, callConvention, types, modifiers, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override EventInfo[] GetEvents(BindingFlags bindingAttr)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override FieldInfo[] GetFields(BindingFlags bindingAttr)
|
||||||
|
=> system.reflection.RuntimeFieldInfo.GetFields(bindingAttr, this);
|
||||||
|
|
||||||
|
public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
|
||||||
|
=> system.reflection.RuntimePropertyInfo.GetProperties(bindingAttr, this);
|
||||||
|
|
||||||
|
public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
|
||||||
|
=> throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
public override object InvokeMember(
|
||||||
|
string name, BindingFlags invokeAttr, Binder binder, object target, object[] args,
|
||||||
|
ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// reflection support - extract information from Java generic signatures
|
||||||
|
// (generated by MakeGenericSignature in GenericUtil)
|
||||||
|
//
|
||||||
|
|
||||||
|
Type FromJavaGenericType(java.lang.reflect.Type javaType)
|
||||||
|
{
|
||||||
|
if (javaType is java.lang.reflect.ParameterizedType parameterizedType)
|
||||||
|
{
|
||||||
|
// a ParameterizedType is GenericType<GenericArg1,...GenericArgN>
|
||||||
|
// where each GenericArg would be a TypeVariable or a Class
|
||||||
|
|
||||||
|
var primaryClass = (java.lang.Class) parameterizedType.getRawType();
|
||||||
|
var javaTypeArgs = parameterizedType.getActualTypeArguments();
|
||||||
|
int n = javaTypeArgs.Length;
|
||||||
|
var typeArgs = new Type[n];
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
typeArgs[i] = FromJavaGenericType(javaTypeArgs[i]);
|
||||||
|
return GetType(primaryClass, typeArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( javaType is java.lang.reflect.TypeVariable varType
|
||||||
|
&& varType.getGenericDeclaration() is java.lang.Class varClass)
|
||||||
|
{
|
||||||
|
// a TypeVariable is a GenericArg with a reference to the type
|
||||||
|
// it belongs to. if that type (in the java generics mechanism)
|
||||||
|
// corresponds to 'this' type, and if 'this' type is a concrete
|
||||||
|
// generic instance (as opposed to a generic definition), then
|
||||||
|
// we grab a concrete generic type from 'this' type instance.
|
||||||
|
//
|
||||||
|
// for example, with A<T1,T2> and B<T1,T2> : A<T2,T1>, then
|
||||||
|
// for generic instance B<int,bool>, we are able to resolve
|
||||||
|
// the base type as A<bool,int>.
|
||||||
|
|
||||||
|
var varName = varType.getName();
|
||||||
|
var primaryType = GetType(varClass) as RuntimeType;
|
||||||
|
var argTypes = primaryType?.Generic?.ArgumentTypes;
|
||||||
|
if (argTypes != null)
|
||||||
|
{
|
||||||
|
int n = argTypes.Length;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
if (argTypes[i].Name == varName)
|
||||||
|
{
|
||||||
|
if ( varClass == JavaClass
|
||||||
|
&& Generic != null && Generic.ArgumentTypes != null
|
||||||
|
&& (! object.ReferenceEquals(Generic.PrimaryType, this)))
|
||||||
|
{
|
||||||
|
return Generic.ArgumentTypes[i];
|
||||||
|
}
|
||||||
|
return argTypes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (javaType is java.lang.Class plainClass)
|
||||||
|
{
|
||||||
|
// a java generic Type may also be a java.lang.Class
|
||||||
|
return GetType(plainClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this is a java concept like GenericArrayType or WildcardType,
|
||||||
|
// or anything else we don't recognize, return System.Object
|
||||||
|
|
||||||
|
return ObjectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// UnboxJavaReturnValue
|
||||||
|
//
|
||||||
|
|
||||||
|
public static object UnboxJavaReturnValue(object value)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case java.lang.Boolean boolBox:
|
||||||
|
return system.Boolean.Box(boolBox.booleanValue() ? 1 : 0);
|
||||||
|
case java.lang.Byte byteBox:
|
||||||
|
return system.SByte.Box(byteBox.byteValue());
|
||||||
|
case java.lang.Character charBox:
|
||||||
|
return system.Char.Box(charBox.charValue());
|
||||||
|
case java.lang.Short shortBox:
|
||||||
|
return system.Int16.Box(shortBox.shortValue());
|
||||||
|
case java.lang.Integer intBox:
|
||||||
|
return system.Int32.Box(intBox.intValue());
|
||||||
|
case java.lang.Long longBox:
|
||||||
|
return system.Int64.Box(longBox.longValue());
|
||||||
|
case java.lang.Float floatBox:
|
||||||
|
return system.Single.Box(floatBox.floatValue());
|
||||||
|
case java.lang.Double doubleBox:
|
||||||
|
return system.Double.Box(doubleBox.doubleValue());
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,10 +5,7 @@ namespace system.resources
|
|||||||
public class ResourceManager
|
public class ResourceManager
|
||||||
{
|
{
|
||||||
|
|
||||||
public ResourceManager(string baseName, System.Reflection.Assembly assembly)
|
public ResourceManager(string baseName, System.Reflection.Assembly assembly) { }
|
||||||
{
|
|
||||||
Console.WriteLine($"Creating ResourceManager with base name '{baseName}' in assembly '{assembly}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetString(string name, System.Globalization.CultureInfo culture) => name;
|
public string GetString(string name, System.Globalization.CultureInfo culture) => name;
|
||||||
|
|
||||||
|
@ -7,8 +7,15 @@ using System.Runtime.Serialization;
|
|||||||
namespace system
|
namespace system
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
// System/RuntimeType.cs (this file) contains methods required
|
||||||
|
// by the type system. System/Reflection/RuntimeType2.cs
|
||||||
|
// contains methods to provide run-time reflection support.
|
||||||
|
//
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RuntimeType : system.reflection.TypeInfo, ISerializable, ICloneable
|
public partial class RuntimeType : system.reflection.TypeInfo,
|
||||||
|
ISerializable, ICloneable
|
||||||
{
|
{
|
||||||
|
|
||||||
private sealed class GenericData
|
private sealed class GenericData
|
||||||
@ -89,6 +96,26 @@ namespace system
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (searchClass == javaClass)
|
||||||
|
{
|
||||||
|
// if Android 'R8' (ProGuard) stripped the InnerClass
|
||||||
|
// attribute, then the above getDeclaredClasses() would
|
||||||
|
// return nothing. in this case we use an alternative
|
||||||
|
// approach of scanning for the -generic-info-class
|
||||||
|
// field; see also TypeBuilder.BuildJavaClass()
|
||||||
|
foreach (var field in javaClass.getDeclaredFields())
|
||||||
|
{
|
||||||
|
// search for field: public static final synthetic,
|
||||||
|
// with a type that is public final synthetic
|
||||||
|
if ( field.getModifiers() == 0x1019
|
||||||
|
&& field.getType().getModifiers() == 0x1011)
|
||||||
|
{
|
||||||
|
searchClass = field.getType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable 0436
|
#pragma warning disable 0436
|
||||||
@ -307,16 +334,17 @@ namespace system
|
|||||||
|
|
||||||
if (! TypeSystemInitialized)
|
if (! TypeSystemInitialized)
|
||||||
{
|
{
|
||||||
Console.WriteLine("\n!!! Exception occured during initialization of the type system:\n");
|
java.lang.System.@out.println("\n!!! Exception occured during initialization of the type system:\n");
|
||||||
var exc = exception;
|
var exc = exception;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Exception " + ((java.lang.Object) (object) exc).getClass()
|
java.lang.System.@out.println(
|
||||||
+ "\nMessage: " + ((java.lang.Throwable) exc).getMessage()
|
"Exception " + ((java.lang.Object) (object) exc).getClass()
|
||||||
+ "\n" + exc.StackTrace);
|
+ "\nMessage: " + ((java.lang.Throwable) exc).getMessage()
|
||||||
|
+ "\n" + exc.StackTrace);
|
||||||
if ((exc = exc.InnerException) == null)
|
if ((exc = exc.InnerException) == null)
|
||||||
break;
|
break;
|
||||||
Console.Write("Caused by Inner ");
|
java.lang.System.@out.print("Caused by Inner ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return exception;
|
return exception;
|
||||||
@ -419,203 +447,8 @@ namespace system
|
|||||||
public static bool op_Inequality(RuntimeType obj1, RuntimeType obj2)
|
public static bool op_Inequality(RuntimeType obj1, RuntimeType obj2)
|
||||||
=> ! object.ReferenceEquals(obj1, obj2);
|
=> ! object.ReferenceEquals(obj1, obj2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// MemberInfo
|
|
||||||
//
|
|
||||||
|
|
||||||
public override string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var generic = Generic;
|
|
||||||
|
|
||||||
if (JavaClass == null)
|
|
||||||
return GenericParameterName(generic);
|
|
||||||
if (JavaClass.isArray())
|
|
||||||
return (GetType(JavaClass.getComponentType()).Name) + "[]";
|
|
||||||
else
|
|
||||||
return ClassName(generic);
|
|
||||||
|
|
||||||
string ClassName(GenericData generic)
|
|
||||||
{
|
|
||||||
var name = JavaClass.getSimpleName();
|
|
||||||
int numArgsInDeclType = 0;
|
|
||||||
|
|
||||||
var declType = DeclaringType;
|
|
||||||
if (declType is RuntimeType declRuntimeType && declRuntimeType.Generic != null)
|
|
||||||
{
|
|
||||||
// a nested generic type duplicates the parameters of the parent
|
|
||||||
numArgsInDeclType = declRuntimeType.Generic.ArgumentTypes.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (generic != null)
|
|
||||||
{
|
|
||||||
int numArgs = generic.ArgumentTypes.Length;
|
|
||||||
int index = name.LastIndexOf("$$" + numArgs);
|
|
||||||
if (index != -1)
|
|
||||||
name = name.Substring(0, index);
|
|
||||||
numArgs -= numArgsInDeclType;
|
|
||||||
if (numArgs > 0)
|
|
||||||
name += "`" + numArgs.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
string GenericParameterName(GenericData generic)
|
|
||||||
{
|
|
||||||
if (generic != null)
|
|
||||||
{
|
|
||||||
// generic parameter
|
|
||||||
var argTypes = generic.PrimaryType.Generic.ArgumentTypes;
|
|
||||||
for (int i = 0; i < argTypes.Length; i++)
|
|
||||||
{
|
|
||||||
if (object.ReferenceEquals(argTypes[i], this))
|
|
||||||
{
|
|
||||||
var typeNames = generic.PrimaryType.JavaClass.getTypeParameters();
|
|
||||||
if (i < typeNames.Length)
|
|
||||||
{
|
|
||||||
// if we have a valid generic signature, extract parameter name
|
|
||||||
var nm = typeNames[i].getName();
|
|
||||||
if (! string.IsNullOrEmpty(nm))
|
|
||||||
return nm;
|
|
||||||
}
|
|
||||||
return "T" + i.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null; // invalid combination
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Type DeclaringType
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var javaClass = JavaClass;
|
|
||||||
if (javaClass == null)
|
|
||||||
return null;
|
|
||||||
if (javaClass.isArray())
|
|
||||||
javaClass = javaClass.getComponentType();
|
|
||||||
var declClass = javaClass.getDeclaringClass();
|
|
||||||
return (declClass == null) ? null : GetType(declClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Type ReflectedType => DeclaringType;
|
|
||||||
|
|
||||||
public override object[] GetCustomAttributes(bool inherit) => null;
|
|
||||||
public override object[] GetCustomAttributes(Type attributeType, bool inherit) => null;
|
|
||||||
public override bool IsDefined(Type attributeType, bool inherit) => false;
|
|
||||||
|
|
||||||
//
|
|
||||||
// _Type
|
|
||||||
//
|
|
||||||
|
|
||||||
public override Type BaseType
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if ( JavaClass == null
|
|
||||||
|| object.ReferenceEquals(this, ObjectType)
|
|
||||||
|| IsInterface(this))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (object.ReferenceEquals(this, ExceptionType))
|
|
||||||
{
|
|
||||||
// CilType translates System.Exception to java.lang.Throwable,
|
|
||||||
// and here we map java.lang.Throwable to system.Exception,
|
|
||||||
// thereby creating an infinite loop in which system.Exception
|
|
||||||
// inherits from java.lang.Exception, which inherits from
|
|
||||||
// java.lang.Throwable, which is mapped to system.Exception.
|
|
||||||
// the workaround breaks the infinite loop.
|
|
||||||
return ObjectType;
|
|
||||||
}
|
|
||||||
return FromJavaGenericType(JavaClass.getGenericSuperclass());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Namespace
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var javaClass = JavaClass;
|
|
||||||
if (javaClass == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (javaClass.isArray())
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
javaClass = javaClass.getComponentType();
|
|
||||||
}
|
|
||||||
while (javaClass.isArray());
|
|
||||||
return GetType(javaClass).Namespace;
|
|
||||||
}
|
|
||||||
|
|
||||||
string dottedName = javaClass.getName();
|
|
||||||
int lastIndex = dottedName.LastIndexOf('.');
|
|
||||||
if (lastIndex <= 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
int firstIndex = 0;
|
|
||||||
string resultName = "";
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int nextIndex = dottedName.IndexOf('.', firstIndex);
|
|
||||||
var component = Char.ToUpperInvariant(dottedName[firstIndex])
|
|
||||||
+ dottedName.Substring(firstIndex + 1, nextIndex - firstIndex - 1);
|
|
||||||
resultName += component;
|
|
||||||
if (nextIndex == lastIndex)
|
|
||||||
return resultName;
|
|
||||||
resultName += ".";
|
|
||||||
firstIndex = nextIndex + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string FullName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
string name;
|
|
||||||
var declType = DeclaringType;
|
|
||||||
if (! object.ReferenceEquals(declType, null))
|
|
||||||
name = declType.FullName + "+";
|
|
||||||
else if (IsGenericParameter)
|
|
||||||
return null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = Namespace;
|
|
||||||
if (name != null)
|
|
||||||
name += ".";
|
|
||||||
}
|
|
||||||
name += Name;
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Assembly Assembly => system.reflection.RuntimeAssembly.CurrentAssembly;
|
|
||||||
|
|
||||||
public override string AssemblyQualifiedName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var name = FullName;
|
|
||||||
if (name != null)
|
|
||||||
name = Assembly.CreateQualifiedName(Assembly.FullName, name);
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Module Module => Assembly.GetModules(false)[0];
|
|
||||||
|
|
||||||
public override System.Guid GUID => System.Guid.Empty;
|
public override System.Guid GUID => System.Guid.Empty;
|
||||||
|
|
||||||
public override Type UnderlyingSystemType => this;
|
public override Type UnderlyingSystemType => this;
|
||||||
|
|
||||||
// Attributes property
|
// Attributes property
|
||||||
@ -665,44 +498,6 @@ namespace system
|
|||||||
public override bool IsSerializable
|
public override bool IsSerializable
|
||||||
=> ((GetAttributeFlagsImpl() & TypeAttributes.Serializable) != 0);
|
=> ((GetAttributeFlagsImpl() & TypeAttributes.Serializable) != 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public override Type[] GetInterfaces()
|
|
||||||
{
|
|
||||||
var output = new java.util.HashSet();
|
|
||||||
GetInterfacesInternal(JavaClass, output);
|
|
||||||
return (Type[]) output.toArray(System.Type.EmptyTypes);
|
|
||||||
|
|
||||||
void GetInterfacesInternal(java.lang.Class input, java.util.HashSet output)
|
|
||||||
{
|
|
||||||
foreach (var javaType in input.getGenericInterfaces())
|
|
||||||
{
|
|
||||||
output.add(FromJavaGenericType(javaType));
|
|
||||||
if (javaType is java.lang.Class classType)
|
|
||||||
GetInterfacesInternal(classType, output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public override Type GetInterface(string name, bool ignoreCase)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
throw new ArgumentNullException();
|
|
||||||
StringComparison cmp = ignoreCase
|
|
||||||
? System.StringComparison.InvariantCultureIgnoreCase
|
|
||||||
: System.StringComparison.InvariantCulture;
|
|
||||||
foreach (var ifc in GetInterfaces())
|
|
||||||
{
|
|
||||||
if (string.Compare(name, ifc.FullName, cmp) == 0)
|
|
||||||
return ifc;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override bool IsCOMObjectImpl() => false;
|
protected override bool IsCOMObjectImpl() => false;
|
||||||
protected override bool IsByRefImpl() => false; // always false?
|
protected override bool IsByRefImpl() => false; // always false?
|
||||||
|
|
||||||
@ -744,16 +539,6 @@ namespace system
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type[] GetNestedTypes(BindingFlags bindingAttr)
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Type GetNestedType(string name, BindingFlags bindingAttr)
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Type[] GetGenericArguments()
|
public override Type[] GetGenericArguments()
|
||||||
{
|
{
|
||||||
if (Generic != null)
|
if (Generic != null)
|
||||||
@ -761,7 +546,7 @@ namespace system
|
|||||||
return (Type[]) java.util.Arrays.copyOf(
|
return (Type[]) java.util.Arrays.copyOf(
|
||||||
Generic.ArgumentTypes, Generic.ArgumentTypes.Length);
|
Generic.ArgumentTypes, Generic.ArgumentTypes.Length);
|
||||||
}
|
}
|
||||||
return new Type[0];
|
return EmptyTypeArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type GetGenericTypeDefinition()
|
public override Type GetGenericTypeDefinition()
|
||||||
@ -798,8 +583,6 @@ namespace system
|
|||||||
// Primitives types
|
// Primitives types
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override TypeCode GetTypeCodeImpl()
|
protected override TypeCode GetTypeCodeImpl()
|
||||||
=> (TypeCode) (((int) (CachedAttrs & AttrTypeCode) >> 24) + 1);
|
=> (TypeCode) (((int) (CachedAttrs & AttrTypeCode) >> 24) + 1);
|
||||||
|
|
||||||
@ -905,7 +688,7 @@ namespace system
|
|||||||
|
|
||||||
public object CallConstructor(bool publicOnly)
|
public object CallConstructor(bool publicOnly)
|
||||||
{
|
{
|
||||||
object[] args = (Generic == null) ? new object[0] : Generic.ArgumentTypes;
|
object[] args = (Generic == null) ? EmptyObjectArray : Generic.ArgumentTypes;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#pragma warning disable 0436
|
#pragma warning disable 0436
|
||||||
@ -1159,83 +942,10 @@ namespace system
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// reflection support - extract information from Java generic signatures
|
|
||||||
// (generated by MakeGenericSignature in GenericUtil)
|
|
||||||
//
|
|
||||||
|
|
||||||
Type FromJavaGenericType(java.lang.reflect.Type javaType)
|
|
||||||
{
|
|
||||||
if (javaType is java.lang.reflect.ParameterizedType parameterizedType)
|
|
||||||
{
|
|
||||||
// a ParameterizedType is GenericType<GenericArg1,...GenericArgN>
|
|
||||||
// where each GenericArg would be a TypeVariable or a Class
|
|
||||||
|
|
||||||
var primaryClass = (java.lang.Class) parameterizedType.getRawType();
|
|
||||||
var javaTypeArgs = parameterizedType.getActualTypeArguments();
|
|
||||||
int n = javaTypeArgs.Length;
|
|
||||||
var typeArgs = new Type[n];
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
typeArgs[i] = FromJavaGenericType(javaTypeArgs[i]);
|
|
||||||
return GetType(primaryClass, typeArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( javaType is java.lang.reflect.TypeVariable varType
|
|
||||||
&& varType.getGenericDeclaration() is java.lang.Class varClass)
|
|
||||||
{
|
|
||||||
// a TypeVariable is a GenericArg with a reference to the type
|
|
||||||
// it belongs to. if that type (in the java generics mechanism)
|
|
||||||
// corresponds to 'this' type, and if 'this' type is a concrete
|
|
||||||
// generic instance (as opposed to a generic definition), then
|
|
||||||
// we grab a concrete generic type from 'this' type instance.
|
|
||||||
//
|
|
||||||
// for example, with A<T1,T2> and B<T1,T2> : A<T2,T1>, then
|
|
||||||
// for generic instance B<int,bool>, we are able to resolve
|
|
||||||
// the base type as A<bool,int>.
|
|
||||||
|
|
||||||
var varName = varType.getName();
|
|
||||||
var primaryType = GetType(varClass) as RuntimeType;
|
|
||||||
var argTypes = primaryType?.Generic?.ArgumentTypes;
|
|
||||||
if (argTypes != null)
|
|
||||||
{
|
|
||||||
int n = argTypes.Length;
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
if (argTypes[i].Name == varName)
|
|
||||||
{
|
|
||||||
if ( varClass == JavaClass
|
|
||||||
&& Generic != null && Generic.ArgumentTypes != null
|
|
||||||
&& (! object.ReferenceEquals(Generic.PrimaryType, this)))
|
|
||||||
{
|
|
||||||
return Generic.ArgumentTypes[i];
|
|
||||||
}
|
|
||||||
return argTypes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (javaType is java.lang.Class plainClass)
|
|
||||||
{
|
|
||||||
// a java generic Type may also be a java.lang.Class
|
|
||||||
return GetType(plainClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this is a java concept like GenericArrayType or WildcardType,
|
|
||||||
// or anything else we don't recognize, return System.Object
|
|
||||||
|
|
||||||
return ObjectType;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Methods to create and retrieve type objects
|
// Methods to create and retrieve type objects
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static Type GetType(java.lang.Class cls, Type[] argTypes)
|
public static Type GetType(java.lang.Class cls, Type[] argTypes)
|
||||||
{
|
{
|
||||||
var key = new TypeKey(cls, argTypes);
|
var key = new TypeKey(cls, argTypes);
|
||||||
@ -1376,6 +1086,9 @@ namespace system
|
|||||||
|
|
||||||
if (TypeCache == null)
|
if (TypeCache == null)
|
||||||
{
|
{
|
||||||
|
EmptyObjectArray = new object[0];
|
||||||
|
EmptyTypeArray = new Type[0];
|
||||||
|
|
||||||
TypeCache = new java.util.concurrent.ConcurrentHashMap();
|
TypeCache = new java.util.concurrent.ConcurrentHashMap();
|
||||||
TypeLock = new java.util.concurrent.locks.ReentrantLock();
|
TypeLock = new java.util.concurrent.locks.ReentrantLock();
|
||||||
|
|
||||||
@ -1464,6 +1177,9 @@ namespace system
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[java.attr.RetainType] public static object[] EmptyObjectArray;
|
||||||
|
[java.attr.RetainType] public static Type[] EmptyTypeArray;
|
||||||
|
|
||||||
[java.attr.RetainType] private static java.util.concurrent.ConcurrentHashMap TypeCache;
|
[java.attr.RetainType] private static java.util.concurrent.ConcurrentHashMap TypeCache;
|
||||||
[java.attr.RetainType] private static java.util.concurrent.locks.ReentrantLock TypeLock;
|
[java.attr.RetainType] private static java.util.concurrent.locks.ReentrantLock TypeLock;
|
||||||
[java.attr.RetainType] private static java.lang.Class ValueTypeClass;
|
[java.attr.RetainType] private static java.lang.Class ValueTypeClass;
|
||||||
@ -1672,85 +1388,6 @@ namespace system
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Reflection on members of the type
|
|
||||||
//
|
|
||||||
|
|
||||||
public override MethodBase DeclaringMethod
|
|
||||||
=> throw new PlatformNotSupportedException();
|
|
||||||
|
|
||||||
protected override MethodInfo GetMethodImpl(
|
|
||||||
string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention,
|
|
||||||
Type[] types, ParameterModifier[] modifiers)
|
|
||||||
{
|
|
||||||
if (JavaClass == null) // if generic parameter
|
|
||||||
return null;
|
|
||||||
return system.reflection.RuntimeMethodInfo.GetMethod(
|
|
||||||
name, bindingAttr, binder, callConvention, types, modifiers, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override ConstructorInfo GetConstructorImpl(
|
|
||||||
BindingFlags bindingAttr, Binder binder, CallingConventions callConvention,
|
|
||||||
Type[] types, ParameterModifier[] modifiers)
|
|
||||||
{
|
|
||||||
if (JavaClass == null) // if generic parameter
|
|
||||||
return null;
|
|
||||||
return system.reflection.RuntimeConstructorInfo.GetConstructor(
|
|
||||||
bindingAttr, binder, callConvention, types, modifiers, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object InvokeMember(
|
|
||||||
string name, BindingFlags invokeAttr, Binder binder, object target, object[] args,
|
|
||||||
ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override PropertyInfo GetPropertyImpl(
|
|
||||||
string name, BindingFlags bindingAttr, Binder binder, Type returnType,
|
|
||||||
Type[] types, ParameterModifier[] modifiers)
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override FieldInfo GetField(string name, BindingFlags bindingAttr)
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override FieldInfo[] GetFields(BindingFlags bindingAttr)
|
|
||||||
{
|
|
||||||
return system.reflection.RuntimeFieldInfo.GetFields(bindingAttr, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override EventInfo GetEvent(string name, BindingFlags bindingAttr)
|
|
||||||
=> throw new PlatformNotSupportedException();
|
|
||||||
|
|
||||||
public override EventInfo[] GetEvents(BindingFlags bindingAttr)
|
|
||||||
=> throw new PlatformNotSupportedException();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// unimplemented methods from System.Type:
|
// unimplemented methods from System.Type:
|
||||||
// base implementations throw NotSupportedException
|
// base implementations throw NotSupportedException
|
||||||
|
@ -143,6 +143,13 @@ namespace system.text
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StringBuilder Append(object value)
|
||||||
|
{
|
||||||
|
if (value != null)
|
||||||
|
sb.append(value.ToString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public int Capacity
|
public int Capacity
|
||||||
{
|
{
|
||||||
get => sb.capacity();
|
get => sb.capacity();
|
||||||
|
@ -171,6 +171,18 @@ namespace SpaceFlint.CilToJava
|
|||||||
public List<CilType> Parameters;
|
public List<CilType> Parameters;
|
||||||
public CilType ReturnType;
|
public CilType ReturnType;
|
||||||
|
|
||||||
|
// any resolved generic types from return type and parameters,
|
||||||
|
// concatenated together. used to differentiate generic methods
|
||||||
|
// that differ only in return or parameters types. for example:
|
||||||
|
//
|
||||||
|
// interface I1<T> { int M(T v); }
|
||||||
|
// interface I2<T> { int M(T v); }
|
||||||
|
// class CC<T1,T2> : I1<T2>, I2<T1>
|
||||||
|
// int M(T1 v) => ...;
|
||||||
|
// int M(T2 v) => ...;
|
||||||
|
//
|
||||||
|
// see also InterfaceBuilder.BuildGenericProxy()
|
||||||
|
public string ResolvedGenericTypes;
|
||||||
|
|
||||||
|
|
||||||
public CilInterfaceMethod(CilMethod fromMethod)
|
public CilInterfaceMethod(CilMethod fromMethod)
|
||||||
@ -186,11 +198,14 @@ namespace SpaceFlint.CilToJava
|
|||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
name = name.Substring(idx + 1);
|
name = name.Substring(idx + 1);
|
||||||
|
|
||||||
|
ResolvedGenericTypes = "";
|
||||||
|
|
||||||
var returnType = (CilType) fromMethod.ReturnType;
|
var returnType = (CilType) fromMethod.ReturnType;
|
||||||
if (returnType.IsGenericParameter)
|
if (returnType.IsGenericParameter)
|
||||||
{
|
{
|
||||||
var genericMark = CilMain.GenericStack.Mark();
|
var genericMark = CilMain.GenericStack.Mark();
|
||||||
var (type, index) = CilMain.GenericStack.Resolve(returnType.JavaName);
|
var (type, index) = CilMain.GenericStack.Resolve(returnType.JavaName);
|
||||||
|
ResolvedGenericTypes = $"{type},{index};";
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
returnType = type;
|
returnType = type;
|
||||||
|
|
||||||
@ -208,6 +223,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
var genericMark = CilMain.GenericStack.Mark();
|
var genericMark = CilMain.GenericStack.Mark();
|
||||||
var (type, index) = CilMain.GenericStack.Resolve(parameter.JavaName);
|
var (type, index) = CilMain.GenericStack.Resolve(parameter.JavaName);
|
||||||
|
ResolvedGenericTypes += $"{type},{index};";
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
{
|
{
|
||||||
if (parameter.ArrayRank != 0)
|
if (parameter.ArrayRank != 0)
|
||||||
@ -342,6 +358,9 @@ namespace SpaceFlint.CilToJava
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fromMethod.HasCustomAttribute("Discard"))
|
||||||
|
continue; // skip if decorated with [java.attr.Discard]
|
||||||
|
|
||||||
var genericMark = CilMain.GenericStack.Mark();
|
var genericMark = CilMain.GenericStack.Mark();
|
||||||
var inputMethod = CilMain.GenericStack.EnterMethod(fromMethod);
|
var inputMethod = CilMain.GenericStack.EnterMethod(fromMethod);
|
||||||
|
|
||||||
|
@ -67,7 +67,8 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
|
|
||||||
internal static JavaClass CreateInnerClass(JavaClass outerClass, string innerName,
|
internal static JavaClass CreateInnerClass(JavaClass outerClass, string innerName,
|
||||||
JavaAccessFlags innerFlags = 0)
|
JavaAccessFlags innerFlags = 0,
|
||||||
|
bool markGenericEntity = false)
|
||||||
{
|
{
|
||||||
if (innerFlags == 0)
|
if (innerFlags == 0)
|
||||||
{
|
{
|
||||||
@ -85,6 +86,9 @@ namespace SpaceFlint.CilToJava
|
|||||||
innerClass.Fields = new List<JavaField>();
|
innerClass.Fields = new List<JavaField>();
|
||||||
innerClass.Methods = new List<JavaMethod>();
|
innerClass.Methods = new List<JavaMethod>();
|
||||||
|
|
||||||
|
if (markGenericEntity)
|
||||||
|
innerClass.AddInterface("system.IGenericEntity");
|
||||||
|
|
||||||
outerClass.AddInnerClass(innerClass);
|
outerClass.AddInnerClass(innerClass);
|
||||||
return innerClass;
|
return innerClass;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
Flags |= CONSTRUCTOR;
|
Flags |= CONSTRUCTOR;
|
||||||
Flags |= THIS_ARG | ARRAY_CALL;
|
Flags |= THIS_ARG | ARRAY_CALL;
|
||||||
|
|
||||||
ImportParameters(fromMethod);
|
ImportParameters(fromMethod, null);
|
||||||
ImportGenericParameters(fromMethod);
|
ImportGenericParameters(fromMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
DeclType = CilType.From(fromMethod.DeclaringType);
|
DeclType = CilType.From(fromMethod.DeclaringType);
|
||||||
|
|
||||||
SetMethodType(defMethod);
|
SetMethodType(defMethod);
|
||||||
bool appendSuffix = ImportParameters(fromMethod);
|
bool appendSuffix = ImportParameters(fromMethod, defMethod);
|
||||||
TranslateNameClrToJvm(fromMethod, appendSuffix);
|
TranslateNameClrToJvm(fromMethod, appendSuffix);
|
||||||
|
|
||||||
if (IsConstructor)
|
if (IsConstructor)
|
||||||
@ -166,7 +166,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool ImportParameters(MethodReference fromMethod)
|
bool ImportParameters(MethodReference fromMethod, MethodDefinition defMethod)
|
||||||
{
|
{
|
||||||
bool appendSuffix = false;
|
bool appendSuffix = false;
|
||||||
|
|
||||||
@ -194,7 +194,10 @@ namespace SpaceFlint.CilToJava
|
|||||||
nm += "array-" + paramType.ArrayRank + "-";
|
nm += "array-" + paramType.ArrayRank + "-";
|
||||||
if (paramType.IsByReference)
|
if (paramType.IsByReference)
|
||||||
nm = "-ref" + nm.Replace("&", "");
|
nm = "-ref" + nm.Replace("&", "");
|
||||||
nm += "$" + ((GenericParameter) fromParameterType.GetElementType()).Position;
|
nm += "$" + GenericParameterPosition(defMethod, i,
|
||||||
|
((GenericParameter)
|
||||||
|
fromParameterType.GetElementType()));
|
||||||
|
//nm += "$" + ((GenericParameter) fromParameterType.GetElementType()).Position;
|
||||||
paramType = CilType.WrapMethodGenericParameter(paramType, nm);
|
paramType = CilType.WrapMethodGenericParameter(paramType, nm);
|
||||||
Flags |= GEN_ARGS;
|
Flags |= GEN_ARGS;
|
||||||
}
|
}
|
||||||
@ -275,6 +278,70 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int GenericParameterPosition(MethodDefinition defMethod,
|
||||||
|
int parameterIndex,
|
||||||
|
GenericParameter parameter)
|
||||||
|
{
|
||||||
|
// when a method has parameters with a generic type, the
|
||||||
|
// method name gets a suffix like -generic-$n, where n is
|
||||||
|
// the index of the generic parameter in the generic type.
|
||||||
|
// e.g., method "int Mth(TY)" in class CA<TX,TY> would be
|
||||||
|
// named "Mth-generic-$1" because TY has generic index 1.
|
||||||
|
//
|
||||||
|
// however when the method overrides a base class method,
|
||||||
|
// the n should be the index of the generic parameter in
|
||||||
|
// the base type. e.g., "override int Mth(UZ)" in class
|
||||||
|
// CB<UX,UY,UZ> : CA<UY,UZ> translated to "Mth-generic-$2"
|
||||||
|
// (as UZ has generic index 2 in CB) would be incorrect,
|
||||||
|
// because it breaks the overload/override chain.
|
||||||
|
//
|
||||||
|
// the code below identifies that CB.Mth is an override
|
||||||
|
// of a generic base type method, and that CB.UZ maps to
|
||||||
|
// CA.TY in the base Mth(), and prefers the index of CA.TY
|
||||||
|
// (i.e. 1) over CB.UZ (i.e. 2), to correctly translate
|
||||||
|
// the override as "Mth-generic-$1".
|
||||||
|
|
||||||
|
if ( parameter.Type == GenericParameterType.Type
|
||||||
|
&& defMethod != null
|
||||||
|
&& defMethod.IsVirtual && (! defMethod.IsNewSlot))
|
||||||
|
{
|
||||||
|
var thisClass = defMethod.DeclaringType;
|
||||||
|
if (thisClass.BaseType is GenericInstanceType baseClass)
|
||||||
|
{
|
||||||
|
var baseGenericArgs = baseClass.GenericArguments;
|
||||||
|
|
||||||
|
foreach (var baseMethod in CilType.AsDefinition(baseClass).Methods)
|
||||||
|
{
|
||||||
|
if ( baseMethod.IsVirtual
|
||||||
|
&& CompareMethods(defMethod, baseMethod))
|
||||||
|
{
|
||||||
|
// we found a base class method that matches
|
||||||
|
// the overriding method, so take the position
|
||||||
|
// (i.e. the generic parameter index within
|
||||||
|
// generic type) from the base method parameter
|
||||||
|
|
||||||
|
if (baseMethod.Parameters[parameterIndex].ParameterType
|
||||||
|
.GetElementType() is GenericParameter baseParameter
|
||||||
|
&& baseGenericArgs.Count > baseParameter.Position
|
||||||
|
&& baseGenericArgs[baseParameter.Position] == parameter)
|
||||||
|
{
|
||||||
|
return baseParameter.Position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// in any other case, for example if this is not an
|
||||||
|
// overriding method, or if the base type is not generic,
|
||||||
|
// then select the position within the current type
|
||||||
|
|
||||||
|
return parameter.Position;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -485,9 +552,25 @@ namespace SpaceFlint.CilToJava
|
|||||||
{
|
{
|
||||||
var prefixType = MethodIsShadowing(defMethod);
|
var prefixType = MethodIsShadowing(defMethod);
|
||||||
|
|
||||||
if (prefixType == null && DeclType.IsInterface && (! DeclType.IsRetainName))
|
if (prefixType == null && (! DeclType.IsRetainName))
|
||||||
{
|
{
|
||||||
prefixType = DeclType;
|
if (DeclType.IsInterface)
|
||||||
|
{
|
||||||
|
prefixType = DeclType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if a class inherits from system.IDisposable, and
|
||||||
|
// defines a non-RetainName close() method, then we
|
||||||
|
// must rename the method to prevent collision with
|
||||||
|
// java.lang.AutoCloseable.close().
|
||||||
|
// see also ConvertInterfaceCall() in CodeCall module.
|
||||||
|
if ( defMethod.Name == "close" && (! IsRetainName)
|
||||||
|
&& DeclType.AssignableTo(SystemIDisposable))
|
||||||
|
{
|
||||||
|
prefixType = DeclType;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefixType != null)
|
if (prefixType != null)
|
||||||
@ -876,5 +959,8 @@ namespace SpaceFlint.CilToJava
|
|||||||
internal static readonly JavaMethodRef ValueClone =
|
internal static readonly JavaMethodRef ValueClone =
|
||||||
new JavaMethod("system-ValueMethod-Clone", CilType.SystemValueType);
|
new JavaMethod("system-ValueMethod-Clone", CilType.SystemValueType);
|
||||||
|
|
||||||
|
internal static readonly JavaType SystemIDisposable =
|
||||||
|
new JavaType(0, 0, "system.IDisposable");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
internal JavaStackMap stackMap;
|
internal JavaStackMap stackMap;
|
||||||
|
|
||||||
internal int lineNumber;
|
internal int lineNumber;
|
||||||
|
internal int numCastableInterfaces;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -51,8 +52,9 @@ namespace SpaceFlint.CilToJava
|
|||||||
o.defMethodBody = defMethod.Body;
|
o.defMethodBody = defMethod.Body;
|
||||||
o.newMethod = newMethod;
|
o.newMethod = newMethod;
|
||||||
o.method = myMethod;
|
o.method = myMethod;
|
||||||
|
o.numCastableInterfaces = numCastableInterfaces;
|
||||||
|
|
||||||
o.Process(numCastableInterfaces);
|
o.Process();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -77,7 +79,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Process(int numCastableInterfaces)
|
void Process()
|
||||||
{
|
{
|
||||||
code = newMethod.Code = new JavaCode(newMethod);
|
code = newMethod.Code = new JavaCode(newMethod);
|
||||||
var oldLabel = code.SetLabel(0xFFFF);
|
var oldLabel = code.SetLabel(0xFFFF);
|
||||||
@ -86,7 +88,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
arrays = new CodeArrays(code, locals);
|
arrays = new CodeArrays(code, locals);
|
||||||
exceptions = new CodeExceptions(defMethodBody, code, locals);
|
exceptions = new CodeExceptions(defMethodBody, code, locals);
|
||||||
|
|
||||||
InsertMethodInitCode(numCastableInterfaces);
|
InsertMethodInitCode();
|
||||||
|
|
||||||
code.SetLabel(oldLabel);
|
code.SetLabel(oldLabel);
|
||||||
|
|
||||||
@ -101,7 +103,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void InsertMethodInitCode(int numCastableInterfaces)
|
void InsertMethodInitCode()
|
||||||
{
|
{
|
||||||
if (method.IsStatic)
|
if (method.IsStatic)
|
||||||
{
|
{
|
||||||
@ -135,7 +137,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
// init the array of generic interfaces
|
// init the array of generic interfaces
|
||||||
InterfaceBuilder.InitInterfaceArrayField(
|
InterfaceBuilder.InitInterfaceArrayField(
|
||||||
method.DeclType, numCastableInterfaces, code);
|
method.DeclType, numCastableInterfaces, code, 0);
|
||||||
|
|
||||||
// in any constructor, we want to allocate boxed instance fields
|
// in any constructor, we want to allocate boxed instance fields
|
||||||
ValueUtil.InitializeInstanceFields(newMethod.Class, method.DeclType,
|
ValueUtil.InitializeInstanceFields(newMethod.Class, method.DeclType,
|
||||||
|
@ -180,6 +180,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
var currentClass = method.DeclType;
|
var currentClass = method.DeclType;
|
||||||
var callClass = callMethod.DeclType;
|
var callClass = callMethod.DeclType;
|
||||||
|
|
||||||
|
bool isCallToClone = false;
|
||||||
byte op;
|
byte op;
|
||||||
if (callMethod.IsStatic)
|
if (callMethod.IsStatic)
|
||||||
{
|
{
|
||||||
@ -245,10 +246,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (callMethod.Name == "clone" && callMethod.Parameters.Count == 0)
|
if (callMethod.Name == "clone" && callMethod.Parameters.Count == 0)
|
||||||
{
|
isCallToClone = true;
|
||||||
// if calling clone on the super object, implement Cloneable
|
|
||||||
code.Method.Class.AddInterface("java.lang.Cloneable");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -272,6 +270,22 @@ namespace SpaceFlint.CilToJava
|
|||||||
ClearMethodArguments(callMethod, (op == 0xB7));
|
ClearMethodArguments(callMethod, (op == 0xB7));
|
||||||
|
|
||||||
PushMethodReturnType(callMethod);
|
PushMethodReturnType(callMethod);
|
||||||
|
|
||||||
|
if (isCallToClone)
|
||||||
|
{
|
||||||
|
// if calling clone on the super object, implement Cloneable
|
||||||
|
code.Method.Class.AddInterface("java.lang.Cloneable");
|
||||||
|
|
||||||
|
if (numCastableInterfaces != 0)
|
||||||
|
{
|
||||||
|
code.NewInstruction(
|
||||||
|
0xC0 /* checkcast */, method.DeclType, null);
|
||||||
|
|
||||||
|
// init the array of generic interfaces
|
||||||
|
InterfaceBuilder.InitInterfaceArrayField(
|
||||||
|
method.DeclType, numCastableInterfaces, code, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -306,7 +320,12 @@ namespace SpaceFlint.CilToJava
|
|||||||
callClass = CilType.From(CilType.SystemValueType);
|
callClass = CilType.From(CilType.SystemValueType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (ConvertInterfaceCall(callClass, callMethod))
|
||||||
|
return true;
|
||||||
|
|
||||||
op = 0xB9; // invokeinterface
|
op = 0xB9; // invokeinterface
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -468,6 +487,40 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool ConvertInterfaceCall(CilType callClass, CilMethod callMethod)
|
||||||
|
{
|
||||||
|
// convert a call to System.IDisposable.Dispose() to call
|
||||||
|
// java.lang.AutoCloseable.close(), so a "using" statement
|
||||||
|
// can reference java classes imported by DotNetImporter.
|
||||||
|
//
|
||||||
|
// note that our system.IDisposable in baselib inherits from
|
||||||
|
// java.lang.AutoCloseable and has a default implementation
|
||||||
|
// of close() that calls Dispatch().
|
||||||
|
//
|
||||||
|
// see also handling of java.lang.AutoCloseable in DotNetImporter,
|
||||||
|
// and of close() method in CilMethod.InsertMethodNamePrefix.
|
||||||
|
|
||||||
|
if ( callClass.ClassName == CilMethod.SystemIDisposable.ClassName
|
||||||
|
&& callMethod.Name == "system-IDisposable-Dispose"
|
||||||
|
&& callMethod.Parameters.Count == 0)
|
||||||
|
{
|
||||||
|
if (method.DeclType.ClassName == CilMethod.SystemIDisposable.ClassName)
|
||||||
|
{
|
||||||
|
// we are compiling system.IDisposable.close(),
|
||||||
|
// and want to keep the call to Dispose() as is
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
code.NewInstruction(0xB9 /* invokeinterface */,
|
||||||
|
new JavaType(0, 0, "java.lang.AutoCloseable"),
|
||||||
|
new JavaMethodRef("close", JavaType.VoidType));
|
||||||
|
ClearMethodArguments(callMethod, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Translate_Constrained(CilMethod callMethod, object data)
|
bool Translate_Constrained(CilMethod callMethod, object data)
|
||||||
{
|
{
|
||||||
var typeRef = data as TypeReference;
|
var typeRef = data as TypeReference;
|
||||||
|
@ -763,6 +763,8 @@ namespace SpaceFlint.CilToJava
|
|||||||
indexLocalVars1 += indexLocalVars0;*/
|
indexLocalVars1 += indexLocalVars0;*/
|
||||||
int resetLength = resetLocals.Length;
|
int resetLength = resetLocals.Length;
|
||||||
|
|
||||||
|
bool canBreakEarly = true;
|
||||||
|
|
||||||
var inst = targetInst;
|
var inst = targetInst;
|
||||||
while (inst != branchInst)
|
while (inst != branchInst)
|
||||||
{
|
{
|
||||||
@ -794,6 +796,29 @@ namespace SpaceFlint.CilToJava
|
|||||||
(ushort) (inst.Offset + 1), resetLocals);
|
(ushort) (inst.Offset + 1), resetLocals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we hit a 'return' or 'throw', then we can (and should)
|
||||||
|
// break early, to minimize the area of effect, and the risk
|
||||||
|
// of breaking code between L.A and L.C. (consider that a
|
||||||
|
// .Net compiler may generate code between labels L.A and L.C
|
||||||
|
// that expects the local to be valid.)
|
||||||
|
|
||||||
|
var flowControl = inst.OpCode.FlowControl;
|
||||||
|
|
||||||
|
if ( flowControl == Mono.Cecil.Cil.FlowControl.Branch
|
||||||
|
|| flowControl == Mono.Cecil.Cil.FlowControl.Cond_Branch)
|
||||||
|
{
|
||||||
|
// indicate that we see non-sequential control flow
|
||||||
|
canBreakEarly = false;
|
||||||
|
}
|
||||||
|
else if ( canBreakEarly
|
||||||
|
&& ( flowControl == Mono.Cecil.Cil.FlowControl.Return
|
||||||
|
|| flowControl == Mono.Cecil.Cil.FlowControl.Throw))
|
||||||
|
{
|
||||||
|
// if we only saw sequential control flow, then we can
|
||||||
|
// break early as soon as we see a 'return' or a 'throw'
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
inst = inst.Next;
|
inst = inst.Next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,10 @@ namespace SpaceFlint.CilToJava
|
|||||||
byte op;
|
byte op;
|
||||||
if (! isStatic)
|
if (! isStatic)
|
||||||
{
|
{
|
||||||
|
if (method.IsConstructor &&
|
||||||
|
LoadFieldInConstructor(fldName, fldType, fldClass))
|
||||||
|
return true;
|
||||||
|
|
||||||
PopObjectAndLoadFromSpan(fldClass);
|
PopObjectAndLoadFromSpan(fldClass);
|
||||||
op = 0xB4; // getfield
|
op = 0xB4; // getfield
|
||||||
}
|
}
|
||||||
@ -180,6 +184,108 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool LoadFieldInConstructor(string fldName, CilType fldType, CilType fldClass)
|
||||||
|
{
|
||||||
|
// Java does not allow 'getfield' instructions on an 'uninitializedThis'
|
||||||
|
// until the call to super constructor. but in .Net this is permitted,
|
||||||
|
// and the F# compiler generates such code in some cases. we try to work
|
||||||
|
// around this, by identifying the constructor parameter that was used in
|
||||||
|
// an earlier 'putfield', and loading that, instead of doing 'getfield'.
|
||||||
|
|
||||||
|
bool isUninitializedThisField =
|
||||||
|
( method.IsConstructor && fldClass.Equals(method.DeclType)
|
||||||
|
&& stackMap.GetLocal(0).Equals(JavaStackMap.UninitializedThis));
|
||||||
|
if (! isUninitializedThisField)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// most recent instruction before the 'getfield'
|
||||||
|
// should have been 'ldarg.0', translated to 'aload_0'
|
||||||
|
int i = code.Instructions.Count - 1;
|
||||||
|
if (i > 0 && code.Instructions[i].Opcode == 0x19 /* aload */
|
||||||
|
&& code.Instructions[i].Data is int thisIndex
|
||||||
|
&& thisIndex == 0
|
||||||
|
// note that we pop the stack here
|
||||||
|
&& code.StackMap.PopStack(CilMain.Where)
|
||||||
|
.Equals(JavaStackMap.UninitializedThis))
|
||||||
|
{
|
||||||
|
// try to find an earlier 'putfield' instruction for the field
|
||||||
|
while (i-- > 0)
|
||||||
|
{
|
||||||
|
var inst = code.Instructions[i];
|
||||||
|
if ( inst.Opcode == 0xB5 /* putfield */
|
||||||
|
&& method.DeclType.Equals(inst.Class))
|
||||||
|
{
|
||||||
|
var instField = (JavaFieldRef) inst.Data;
|
||||||
|
if ( fldName == instField.Name
|
||||||
|
&& fldType.Equals(instField.Type))
|
||||||
|
{
|
||||||
|
// try to find the load instruction that was used
|
||||||
|
// to load the value, for that earlier 'putfield'
|
||||||
|
if (FindLoadLocal(i - 1, code.Instructions.Count - 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception("load from uninitialized this");
|
||||||
|
|
||||||
|
|
||||||
|
bool FindLoadLocal(int prevIdx, int lastIdx)
|
||||||
|
{
|
||||||
|
var prevInst = code.Instructions[prevIdx];
|
||||||
|
|
||||||
|
if ( prevIdx > 0 && prevInst.Opcode == 0xB8 /* invokestatic */
|
||||||
|
&& (JavaMethodRef) prevInst.Data is JavaMethodRef prevMethod)
|
||||||
|
{
|
||||||
|
if (prevMethod.Name == "Box")
|
||||||
|
{
|
||||||
|
// we possibly found the sequence used in boxing -
|
||||||
|
// xload value, invokestatic Value.Box(), putfield
|
||||||
|
|
||||||
|
prevInst = code.Instructions[prevIdx - 1];
|
||||||
|
}
|
||||||
|
else if ( prevIdx > 5 && prevMethod.Name == "Copy"
|
||||||
|
&& code.Instructions[prevIdx - 1].Opcode == 0x5A /* dup_x1 */
|
||||||
|
&& code.Instructions[prevIdx - 2].Opcode == 0xB8 /* invokestatic */
|
||||||
|
&& code.Instructions[prevIdx - 3].Opcode == 0x19 /* aload (type) */
|
||||||
|
&& code.Instructions[prevIdx - 4].Opcode == 0xB8 /* invokestatic */
|
||||||
|
&& code.Instructions[prevIdx - 5].Opcode == 0x19 /* aload (value) */)
|
||||||
|
{
|
||||||
|
// we possibly found the sequence used in generics -
|
||||||
|
// aload (local to use for store value)
|
||||||
|
// invokestatic Generic.Load
|
||||||
|
// aload (generic type parameter)
|
||||||
|
// invokestatic Generic.New
|
||||||
|
// dup_x1
|
||||||
|
// invokestatic Generic.Copy <=== prevIdx
|
||||||
|
// putfield
|
||||||
|
// (see also StoreInstance method in this module)
|
||||||
|
|
||||||
|
prevInst = code.Instructions[prevIdx - 5];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( prevInst.Opcode >= 0x15 /* iload, lload, fload, */
|
||||||
|
&& prevInst.Opcode <= 0x19 /* dload, aload */
|
||||||
|
&& prevInst.Data is int localIndex)
|
||||||
|
{
|
||||||
|
// if the instruction before the 'putfield' is a load
|
||||||
|
// from local, and assuming this local is a parameter,
|
||||||
|
// then we can just load this local again, to replace
|
||||||
|
// a 'getfield' instruction that cannot access 'this'
|
||||||
|
|
||||||
|
code.Instructions[lastIdx].Opcode = prevInst.Opcode;
|
||||||
|
code.Instructions[lastIdx].Data = localIndex;
|
||||||
|
stackMap.PushStack(code.StackMap.GetLocal(localIndex));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool StoreFieldValue(string fldName, CilType fldType, CilType fldClass,
|
bool StoreFieldValue(string fldName, CilType fldType, CilType fldClass,
|
||||||
bool isStatic, bool isVolatile)
|
bool isStatic, bool isVolatile)
|
||||||
{
|
{
|
||||||
|
@ -461,9 +461,10 @@ namespace SpaceFlint.CilToJava
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (localType.IsGenericParameter && (! localType.IsByReference))
|
if (localType.IsGenericParameter)
|
||||||
{
|
{
|
||||||
GenericUtil.ValueLoad(code);
|
if (! localType.IsByReference)
|
||||||
|
GenericUtil.ValueLoad(code);
|
||||||
localType = CilType.From(JavaType.ObjectType);
|
localType = CilType.From(JavaType.ObjectType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,7 +613,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
public List<(CilType, int)> GetUninitializedVariables()
|
public List<(CilType, int)> GetUninitializedVariables()
|
||||||
{
|
{
|
||||||
List<(CilType, int)> list = null;
|
List<(CilType, int)> list = null;
|
||||||
@ -629,7 +630,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
public (CilType, int) GetLocalFromLoadInst(Code op, object data)
|
public (CilType, int) GetLocalFromLoadInst(Code op, object data)
|
||||||
|
@ -346,13 +346,17 @@ namespace SpaceFlint.CilToJava
|
|||||||
if (CodeSpan.LoadStore(false, intoType, null, dataType, code))
|
if (CodeSpan.LoadStore(false, intoType, null, dataType, code))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( (! dataType.IsReference)
|
if ( intoType is BoxedType intoBoxedType
|
||||||
&& intoType is BoxedType intoBoxedType
|
&& dataType.PrimitiveType ==
|
||||||
&& dataType.PrimitiveType == intoBoxedType.UnboxedType.PrimitiveType)
|
intoBoxedType.UnboxedType.PrimitiveType)
|
||||||
{
|
{
|
||||||
// 'stobj primitive' with a primitive value on the stack
|
// 'stobj primitive' with a primitive value on the stack,
|
||||||
intoBoxedType.SetValueOV(code);
|
// or 'stobj primitive[]' with a primitive array on the stack
|
||||||
return;
|
if ((! dataType.IsReference) || dataType.IsArray)
|
||||||
|
{
|
||||||
|
intoBoxedType.SetValueOV(code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
code.StackMap.PushStack(intoType);
|
code.StackMap.PushStack(intoType);
|
||||||
|
@ -178,7 +178,8 @@ namespace SpaceFlint.CilToJava
|
|||||||
//
|
//
|
||||||
|
|
||||||
JavaClass CreateClass(JavaClass fromClass) =>
|
JavaClass CreateClass(JavaClass fromClass) =>
|
||||||
CilMain.CreateInnerClass(fromClass, fromClass.Name + "$$static", 0);
|
CilMain.CreateInnerClass(fromClass, fromClass.Name + "$$static", 0,
|
||||||
|
markGenericEntity: true);
|
||||||
|
|
||||||
//
|
//
|
||||||
// create a private instance field to hold the runtime type
|
// create a private instance field to hold the runtime type
|
||||||
@ -345,13 +346,14 @@ namespace SpaceFlint.CilToJava
|
|||||||
}
|
}
|
||||||
if (! anyVariance)
|
if (! anyVariance)
|
||||||
{
|
{
|
||||||
|
/* removed; see IComparer.cs in baselib
|
||||||
if (fromType.JavaName == "system.collections.generic.IComparer$$1")
|
if (fromType.JavaName == "system.collections.generic.IComparer$$1")
|
||||||
{
|
{
|
||||||
// force a variance string for an interface that we create
|
// force a variance string for an interface that we create
|
||||||
// as an abstract class; see also IComparer.cs in baselib
|
// as an abstract class; see also IComparer.cs in baselib
|
||||||
varianceString = "I";
|
varianceString = "I";
|
||||||
}
|
}
|
||||||
else
|
else*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,6 +489,16 @@ namespace SpaceFlint.CilToJava
|
|||||||
{
|
{
|
||||||
if (loadIndex < 0)
|
if (loadIndex < 0)
|
||||||
{
|
{
|
||||||
|
if ( code.Method.Class != null
|
||||||
|
&& (code.Method.Class
|
||||||
|
.Flags & JavaAccessFlags.ACC_INTERFACE) != 0)
|
||||||
|
{
|
||||||
|
// a method compiled as part of an interface does not
|
||||||
|
// have access to the generic-type member field
|
||||||
|
throw CilMain.Where.Exception(
|
||||||
|
"unsupported generic argument reference in interface method");
|
||||||
|
}
|
||||||
|
|
||||||
// generic type is accessible through the generic-type member field
|
// generic type is accessible through the generic-type member field
|
||||||
|
|
||||||
code.NewInstruction(0x19 /* aload */, null, (int) 0);
|
code.NewInstruction(0x19 /* aload */, null, (int) 0);
|
||||||
|
@ -74,7 +74,6 @@ namespace SpaceFlint.CilToJava
|
|||||||
// the RuntimeType constructor in baselib uses IGenericEntity
|
// the RuntimeType constructor in baselib uses IGenericEntity
|
||||||
// marker interface to identify generic classes. note that
|
// marker interface to identify generic classes. note that
|
||||||
// real generic types implement IGenericObject -> IGenericEntity.
|
// real generic types implement IGenericObject -> IGenericEntity.
|
||||||
|
|
||||||
theClass.AddInterface("system.IGenericEntity");
|
theClass.AddInterface("system.IGenericEntity");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,14 +123,14 @@ namespace SpaceFlint.CilToJava
|
|||||||
// if the class implements a generic interface for multiple types,
|
// if the class implements a generic interface for multiple types,
|
||||||
// then we need a method suffix to differentiate between the methods.
|
// then we need a method suffix to differentiate between the methods.
|
||||||
// see also: CilMethod::InsertMethodNamePrefix
|
// see also: CilMethod::InsertMethodNamePrefix
|
||||||
string methodSuffix = "";
|
/*string methodSuffix = "";
|
||||||
foreach (var genericType in ifc.GenericTypes)
|
foreach (var genericType in ifc.GenericTypes)
|
||||||
methodSuffix += "--" + CilMethod.GenericParameterSuffixName(genericType);
|
methodSuffix += "--" + CilMethod.GenericParameterSuffixName(genericType);*/
|
||||||
|
|
||||||
foreach (var ifcMethod in ifc.Methods)
|
foreach (var ifcMethod in ifc.Methods)
|
||||||
{
|
{
|
||||||
// build proxy classes: proxy sub-class -> this class
|
// build proxy classes: proxy sub-class -> this class
|
||||||
BuildGenericProxy(ifcMethod, methodSuffix, intoType, theMethods, ifcClass);
|
BuildGenericProxy(ifcMethod, /*methodSuffix,*/ intoType, theMethods, ifcClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,7 +146,8 @@ namespace SpaceFlint.CilToJava
|
|||||||
// reference as a parameter and initializes the instance field.
|
// reference as a parameter and initializes the instance field.
|
||||||
|
|
||||||
var newClass = CilMain.CreateInnerClass(parentClass,
|
var newClass = CilMain.CreateInnerClass(parentClass,
|
||||||
parentClass.Name + "$$generic" + ifcNumber.ToString());
|
parentClass.Name + "$$generic" + ifcNumber.ToString(),
|
||||||
|
markGenericEntity: true);
|
||||||
|
|
||||||
var fld = new JavaField();
|
var fld = new JavaField();
|
||||||
fld.Name = ParentFieldName;
|
fld.Name = ParentFieldName;
|
||||||
@ -199,7 +199,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
//
|
//
|
||||||
|
|
||||||
public static void InitInterfaceArrayField(CilType toType, int numCastableInterfaces,
|
public static void InitInterfaceArrayField(CilType toType, int numCastableInterfaces,
|
||||||
JavaCode code)
|
JavaCode code, int objectIndex)
|
||||||
{
|
{
|
||||||
// if a type has castable interface (as counted by CastableInterfaceCount),
|
// if a type has castable interface (as counted by CastableInterfaceCount),
|
||||||
// then we need to initialize the helper array field, for use by the
|
// then we need to initialize the helper array field, for use by the
|
||||||
@ -208,8 +208,14 @@ namespace SpaceFlint.CilToJava
|
|||||||
if (numCastableInterfaces == 0)
|
if (numCastableInterfaces == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
code.NewInstruction(0x19 /* aload */, null, (int) 0);
|
// objectIndex specifies the local index for the object reference,
|
||||||
|
// e.g. 0 for the 'this' object, or -1 for top of stack.
|
||||||
|
if (objectIndex == -1)
|
||||||
|
code.NewInstruction(0x59 /* dup */, null, null);
|
||||||
|
else
|
||||||
|
code.NewInstruction(0x19 /* aload */, null, objectIndex);
|
||||||
code.StackMap.PushStack(toType);
|
code.StackMap.PushStack(toType);
|
||||||
|
|
||||||
code.NewInstruction(0xBB /* new */, AtomicReferenceArrayType, null);
|
code.NewInstruction(0xBB /* new */, AtomicReferenceArrayType, null);
|
||||||
code.StackMap.PushStack(AtomicReferenceArrayType);
|
code.StackMap.PushStack(AtomicReferenceArrayType);
|
||||||
code.NewInstruction(0x59 /* dup */, null, null);
|
code.NewInstruction(0x59 /* dup */, null, null);
|
||||||
@ -381,7 +387,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void BuildGenericProxy(CilInterfaceMethod ifcMethod, string methodSuffix,
|
public static void BuildGenericProxy(CilInterfaceMethod ifcMethod, /*string methodSuffix,*/
|
||||||
CilType intoType, List<CilInterfaceMethod> classMethods,
|
CilType intoType, List<CilInterfaceMethod> classMethods,
|
||||||
JavaClass ifcClass)
|
JavaClass ifcClass)
|
||||||
{
|
{
|
||||||
@ -408,9 +414,23 @@ namespace SpaceFlint.CilToJava
|
|||||||
{
|
{
|
||||||
// more than one method may match, if a derived type overrides
|
// more than one method may match, if a derived type overrides
|
||||||
// or hides a method that also exists in a base type. but the
|
// or hides a method that also exists in a base type. but the
|
||||||
// derived (primary) type methods always come first.
|
// derived (primary) type methods always come first
|
||||||
if (targetMethod == null)
|
if (targetMethod == null)
|
||||||
targetMethod = clsMethod.Method;
|
targetMethod = clsMethod.Method;
|
||||||
|
|
||||||
|
// if a second method matches, and the set of generic types
|
||||||
|
// in its signature exactly matches the interface method we
|
||||||
|
// are looking for, then prefer this method. when a class
|
||||||
|
// implements same-name methods from multiple interfaces,
|
||||||
|
// this is needed to pick the right method.
|
||||||
|
// see also ResolvedGenericTypes in CilInterfaceMethod.
|
||||||
|
|
||||||
|
else if ( clsMethod.ResolvedGenericTypes.Length != 0
|
||||||
|
&& clsMethod.ResolvedGenericTypes
|
||||||
|
== ifcMethod.ResolvedGenericTypes)
|
||||||
|
{
|
||||||
|
targetMethod = clsMethod.Method;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,8 +100,24 @@ namespace SpaceFlint.CilToJava
|
|||||||
// Android 'D8' desugars static methods on an interface by
|
// Android 'D8' desugars static methods on an interface by
|
||||||
// moving into a separate class, so we do it ourselves.
|
// moving into a separate class, so we do it ourselves.
|
||||||
// see also system.RuntimeType.CreateGeneric() in baselib
|
// see also system.RuntimeType.CreateGeneric() in baselib
|
||||||
infoClass = CilMain.CreateInnerClass(jclass, jclass.Name + "$$info");
|
infoClass = CilMain.CreateInnerClass(jclass, jclass.Name + "$$info",
|
||||||
|
markGenericEntity: true);
|
||||||
CilMain.JavaClasses.Add(infoClass);
|
CilMain.JavaClasses.Add(infoClass);
|
||||||
|
|
||||||
|
// Android 'R8' (ProGuard) might discard this new class,
|
||||||
|
// so insert a dummy field with the type of the class.
|
||||||
|
// see also ProGuard rules in IGenericEntity in baselib
|
||||||
|
var infoClassField = new JavaField();
|
||||||
|
infoClassField.Name = "-generic-info-class";
|
||||||
|
infoClassField.Type = new JavaType(0, 0, infoClass.Name);
|
||||||
|
infoClassField.Class = jclass;
|
||||||
|
infoClassField.Flags = JavaAccessFlags.ACC_PUBLIC
|
||||||
|
| JavaAccessFlags.ACC_STATIC
|
||||||
|
| JavaAccessFlags.ACC_FINAL
|
||||||
|
| JavaAccessFlags.ACC_SYNTHETIC;
|
||||||
|
if (jclass.Fields == null)
|
||||||
|
jclass.Fields = new List<JavaField>(1);
|
||||||
|
jclass.Fields.Add(infoClassField);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericUtil.CreateGenericInfoMethod(infoClass, dataClass, myType);
|
GenericUtil.CreateGenericInfoMethod(infoClass, dataClass, myType);
|
||||||
@ -347,10 +363,12 @@ namespace SpaceFlint.CilToJava
|
|||||||
attrs &= ~FieldAttributes.Static;
|
attrs &= ~FieldAttributes.Static;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((attrs & FieldAttributes.InitOnly) != 0)
|
if (0 != (attrs & ( FieldAttributes.InitOnly
|
||||||
|
| FieldAttributes.Literal)))
|
||||||
{
|
{
|
||||||
flags |= JavaAccessFlags.ACC_FINAL;
|
flags |= JavaAccessFlags.ACC_FINAL;
|
||||||
attrs &= ~FieldAttributes.InitOnly;
|
attrs &= ~( FieldAttributes.InitOnly
|
||||||
|
| FieldAttributes.Literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((attrs & FieldAttributes.NotSerialized) != 0)
|
if ((attrs & FieldAttributes.NotSerialized) != 0)
|
||||||
@ -359,8 +377,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
attrs &= ~FieldAttributes.NotSerialized;
|
attrs &= ~FieldAttributes.NotSerialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
attrs &= ~( FieldAttributes.Literal
|
attrs &= ~( FieldAttributes.HasFieldRVA
|
||||||
| FieldAttributes.HasFieldRVA
|
|
||||||
| FieldAttributes.HasDefault
|
| FieldAttributes.HasDefault
|
||||||
| FieldAttributes.SpecialName
|
| FieldAttributes.SpecialName
|
||||||
| FieldAttributes.RTSpecialName);
|
| FieldAttributes.RTSpecialName);
|
||||||
@ -385,10 +402,8 @@ namespace SpaceFlint.CilToJava
|
|||||||
for (int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
var defMethod = cilType.Methods[i];
|
var defMethod = cilType.Methods[i];
|
||||||
/*
|
|
||||||
if (defMethod.HasCustomAttribute("Discard"))
|
if (defMethod.HasCustomAttribute("Discard"))
|
||||||
continue; // if decorated with [java.attr.Discard], don't export to java
|
continue; // if decorated with [java.attr.Discard], don't export to java
|
||||||
*/
|
|
||||||
|
|
||||||
var genericMark = CilMain.GenericStack.Mark();
|
var genericMark = CilMain.GenericStack.Mark();
|
||||||
var myMethod = CilMain.GenericStack.EnterMethod(defMethod);
|
var myMethod = CilMain.GenericStack.EnterMethod(defMethod);
|
||||||
|
@ -18,7 +18,7 @@ namespace SpaceFlint.CilToJava
|
|||||||
valueClass.Super = CilType.SystemValueType.ClassName;
|
valueClass.Super = CilType.SystemValueType.ClassName;
|
||||||
|
|
||||||
CreateDefaultConstructor(valueClass, fromType, numCastableInterfaces, true);
|
CreateDefaultConstructor(valueClass, fromType, numCastableInterfaces, true);
|
||||||
CreateValueMethods(valueClass, fromType);
|
CreateValueMethods(valueClass, fromType, numCastableInterfaces);
|
||||||
|
|
||||||
if ((valueClass.Flags & JavaAccessFlags.ACC_ABSTRACT) == 0)
|
if ((valueClass.Flags & JavaAccessFlags.ACC_ABSTRACT) == 0)
|
||||||
valueClass.Flags |= JavaAccessFlags.ACC_FINAL;
|
valueClass.Flags |= JavaAccessFlags.ACC_FINAL;
|
||||||
@ -58,7 +58,8 @@ namespace SpaceFlint.CilToJava
|
|||||||
}
|
}
|
||||||
|
|
||||||
// init the array of generic interfaces
|
// init the array of generic interfaces
|
||||||
InterfaceBuilder.InitInterfaceArrayField(fromType, numCastableInterfaces, code);
|
InterfaceBuilder.InitInterfaceArrayField(
|
||||||
|
fromType, numCastableInterfaces, code, 0);
|
||||||
|
|
||||||
if (initFields)
|
if (initFields)
|
||||||
{
|
{
|
||||||
@ -82,11 +83,12 @@ namespace SpaceFlint.CilToJava
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void CreateValueMethods(JavaClass valueClass, CilType fromType)
|
static void CreateValueMethods(JavaClass valueClass, CilType fromType,
|
||||||
|
int numCastableInterfaces)
|
||||||
{
|
{
|
||||||
CreateValueClearMethod(valueClass, fromType);
|
CreateValueClearMethod(valueClass, fromType);
|
||||||
CreateValueCopyToMethod(valueClass, fromType);
|
CreateValueCopyToMethod(valueClass, fromType);
|
||||||
CreateValueCloneMethod(valueClass, fromType);
|
CreateValueCloneMethod(valueClass, fromType, numCastableInterfaces);
|
||||||
|
|
||||||
//
|
//
|
||||||
// system-ValueMethod-Clear() resets all fields to their default value
|
// system-ValueMethod-Clear() resets all fields to their default value
|
||||||
@ -180,9 +182,11 @@ namespace SpaceFlint.CilToJava
|
|||||||
// any boxed fields
|
// any boxed fields
|
||||||
//
|
//
|
||||||
|
|
||||||
void CreateValueCloneMethod(JavaClass valueClass, CilType fromType)
|
void CreateValueCloneMethod(JavaClass valueClass, CilType fromType,
|
||||||
|
int numCastableInterfaces)
|
||||||
{
|
{
|
||||||
var code = CilMain.CreateHelperMethod(valueClass, CilMethod.ValueClone, 1, 3);
|
var code = CilMain.CreateHelperMethod(valueClass, CilMethod.ValueClone,
|
||||||
|
1, (numCastableInterfaces == 0) ? 3 : 5);
|
||||||
bool atLeastOneField = false;
|
bool atLeastOneField = false;
|
||||||
|
|
||||||
code.NewInstruction(0x19 /* aload */, null, (int) 0);
|
code.NewInstruction(0x19 /* aload */, null, (int) 0);
|
||||||
@ -215,7 +219,15 @@ namespace SpaceFlint.CilToJava
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! atLeastOneField)
|
if (! atLeastOneField)
|
||||||
code.NewInstruction(0xC0 /* checkcast */, CilType.SystemValueType, null);
|
code.NewInstruction(0xC0 /* checkcast */, fromType, null);
|
||||||
|
|
||||||
|
if (numCastableInterfaces != 0)
|
||||||
|
{
|
||||||
|
code.StackMap = new JavaStackMap();
|
||||||
|
// init the array of generic interfaces
|
||||||
|
InterfaceBuilder.InitInterfaceArrayField(
|
||||||
|
fromType, numCastableInterfaces, code, -1);
|
||||||
|
}
|
||||||
|
|
||||||
code.NewInstruction(fromType.ReturnOpcode, null, null);
|
code.NewInstruction(fromType.ReturnOpcode, null, null);
|
||||||
}
|
}
|
||||||
|
@ -189,6 +189,8 @@ namespace SpaceFlint.JavaBinary
|
|||||||
|
|
||||||
else if (inst.Data is double vDouble)
|
else if (inst.Data is double vDouble)
|
||||||
{
|
{
|
||||||
|
if (FillInstruction_ConstLoad_Double(inst, vDouble))
|
||||||
|
return;
|
||||||
constantIndex = wtr.ConstDouble(vDouble);
|
constantIndex = wtr.ConstDouble(vDouble);
|
||||||
op = 0x14;
|
op = 0x14;
|
||||||
}
|
}
|
||||||
@ -215,7 +217,11 @@ namespace SpaceFlint.JavaBinary
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (inst.Data is float vFloat)
|
else if (inst.Data is float vFloat)
|
||||||
|
{
|
||||||
|
if (FillInstruction_ConstLoad_Float(inst, vFloat))
|
||||||
|
return;
|
||||||
constantIndex = wtr.ConstFloat(vFloat);
|
constantIndex = wtr.ConstFloat(vFloat);
|
||||||
|
}
|
||||||
|
|
||||||
else if (inst.Data is string vString)
|
else if (inst.Data is string vString)
|
||||||
constantIndex = wtr.ConstString(vString);
|
constantIndex = wtr.ConstString(vString);
|
||||||
@ -284,6 +290,49 @@ namespace SpaceFlint.JavaBinary
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool FillInstruction_ConstLoad_Float(Instruction inst, float value)
|
||||||
|
{
|
||||||
|
if (value == 0.0f)
|
||||||
|
{
|
||||||
|
inst.Bytes = new byte[1];
|
||||||
|
inst.Bytes[0] = (byte) 11; // fconst_0
|
||||||
|
}
|
||||||
|
else if (value == 1.0f)
|
||||||
|
{
|
||||||
|
inst.Bytes = new byte[1];
|
||||||
|
inst.Bytes[0] = (byte) 12; // fconst_1
|
||||||
|
}
|
||||||
|
else if (value == 2.0f)
|
||||||
|
{
|
||||||
|
inst.Bytes = new byte[1];
|
||||||
|
inst.Bytes[0] = (byte) 13; // fconst_2
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool FillInstruction_ConstLoad_Double(Instruction inst, double value)
|
||||||
|
{
|
||||||
|
if (value == 0.0)
|
||||||
|
{
|
||||||
|
inst.Bytes = new byte[1];
|
||||||
|
inst.Bytes[0] = (byte) 14; // dconst_0
|
||||||
|
}
|
||||||
|
else if (value == 1.0)
|
||||||
|
{
|
||||||
|
inst.Bytes = new byte[1];
|
||||||
|
inst.Bytes[0] = (byte) 15; // dconst_1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool FillInstruction_Local(JavaWriter wtr, Instruction inst, byte op)
|
bool FillInstruction_Local(JavaWriter wtr, Instruction inst, byte op)
|
||||||
{
|
{
|
||||||
if (op == 0x84)
|
if (op == 0x84)
|
||||||
|
@ -589,7 +589,11 @@ namespace SpaceFlint.JavaBinary
|
|||||||
offset = (ushort) (offset - (lastOffset + 1));
|
offset = (ushort) (offset - (lastOffset + 1));
|
||||||
item.deltaOffset = offset;
|
item.deltaOffset = offset;
|
||||||
|
|
||||||
|
// discard any trailing 'top' elements for out-of-scape locals
|
||||||
int numLocals = frame.locals.Count;
|
int numLocals = frame.locals.Count;
|
||||||
|
while (numLocals > 0 && frame.locals[numLocals - 1].Equals(Top))
|
||||||
|
numLocals--;
|
||||||
|
|
||||||
var localsList = new List<JavaAttribute.StackMapTable.Slot>(numLocals);
|
var localsList = new List<JavaAttribute.StackMapTable.Slot>(numLocals);
|
||||||
for (int i = 0; i < numLocals; i += frame.locals[i].Category)
|
for (int i = 0; i < numLocals; i += frame.locals[i].Category)
|
||||||
localsList.Add(JavaTypeToVerificationType(frame.locals[i], wtr));
|
localsList.Add(JavaTypeToVerificationType(frame.locals[i], wtr));
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2020 spaceflint7
|
Copyright (c) 2020, 2021 spaceflint7
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -182,6 +182,22 @@ public class DotNetImporter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// arrange Java inner classes as CIL nested classes,
|
||||||
|
// and add Java outer classes to the CIL module itself
|
||||||
|
|
||||||
|
foreach (var jclass in classes2)
|
||||||
|
{
|
||||||
|
Where.Push($"class '{jclass.Name}'");
|
||||||
|
|
||||||
|
var cilType = typeMap[jclass.Name] as TypeDefinition;
|
||||||
|
AddClassToDeclaringType(cilType, jclass);
|
||||||
|
|
||||||
|
Where.Pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// establish links between classes and their
|
||||||
|
// super classes and interfaces
|
||||||
|
|
||||||
foreach (var jclass in classes2)
|
foreach (var jclass in classes2)
|
||||||
{
|
{
|
||||||
Where.Push($"class '{jclass.Name}'");
|
Where.Push($"class '{jclass.Name}'");
|
||||||
@ -335,7 +351,7 @@ public class DotNetImporter
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void LinkCilTypesByClass(TypeDefinition cilType, JavaClass jclass)
|
public void AddClassToDeclaringType(TypeDefinition cilType, JavaClass jclass)
|
||||||
{
|
{
|
||||||
if (jclass.IsInnerClass())
|
if (jclass.IsInnerClass())
|
||||||
{
|
{
|
||||||
@ -363,7 +379,12 @@ public class DotNetImporter
|
|||||||
{
|
{
|
||||||
module.Types.Add(cilType);
|
module.Types.Add(cilType);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void LinkCilTypesByClass(TypeDefinition cilType, JavaClass jclass)
|
||||||
|
{
|
||||||
var superName = jclass.Super;
|
var superName = jclass.Super;
|
||||||
if (superName == "java.lang.Enum")
|
if (superName == "java.lang.Enum")
|
||||||
superName = null;
|
superName = null;
|
||||||
@ -379,6 +400,16 @@ public class DotNetImporter
|
|||||||
cilType.Interfaces.Add(
|
cilType.Interfaces.Add(
|
||||||
new InterfaceImplementation(cilSuperTypeRef));
|
new InterfaceImplementation(cilSuperTypeRef));
|
||||||
}
|
}
|
||||||
|
if (jclass.Name == "java.lang.AutoCloseable")
|
||||||
|
{
|
||||||
|
// make java.lang.AutoCloseable extend System.IDisposable,
|
||||||
|
// to allow use of imported classes in "using" statement.
|
||||||
|
// see also ConvertInterfaceCall in CodeCall module.
|
||||||
|
var iDisposableRef = new TypeReference(
|
||||||
|
"System", "IDisposable", module, module.TypeSystem.CoreLibrary);
|
||||||
|
cilType.Interfaces.Add(
|
||||||
|
new InterfaceImplementation(iDisposableRef));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -707,7 +738,7 @@ public class DotNetImporter
|
|||||||
var method = new MethodDefinition(
|
var method = new MethodDefinition(
|
||||||
"op_Explicit", attrs, CilTypeReference(JavaType.ClassType));
|
"op_Explicit", attrs, CilTypeReference(JavaType.ClassType));
|
||||||
method.Parameters.Add(new ParameterDefinition(
|
method.Parameters.Add(new ParameterDefinition(
|
||||||
"type", 0, new TypeReference("System", "Type",
|
"source", 0, new TypeReference("System", "Type",
|
||||||
module, module.TypeSystem.CoreLibrary)));
|
module, module.TypeSystem.CoreLibrary)));
|
||||||
SetCommonMethodBody(method);
|
SetCommonMethodBody(method);
|
||||||
cilType.Methods.Add(method);
|
cilType.Methods.Add(method);
|
||||||
|
@ -44,7 +44,7 @@ public class DotNetPrinter
|
|||||||
{
|
{
|
||||||
txt.Write("{0}{1}",
|
txt.Write("{0}{1}",
|
||||||
(comma ? ", " : string.Empty),
|
(comma ? ", " : string.Empty),
|
||||||
intrface.InterfaceType.FullName);
|
intrface.InterfaceType?.FullName ?? "(null)");
|
||||||
|
|
||||||
comma = true;
|
comma = true;
|
||||||
}
|
}
|
||||||
|
@ -383,6 +383,20 @@ namespace Tests
|
|||||||
{
|
{
|
||||||
Console.WriteLine("Caught exception " + e.GetType());
|
Console.WriteLine("Caught exception " + e.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test generic cast
|
||||||
|
|
||||||
|
var tupleArray = new Tuple<int,string>[3] {
|
||||||
|
new Tuple<int,string>(1, "one"),
|
||||||
|
new Tuple<int,string>(2, "two"),
|
||||||
|
new Tuple<int,string>(3, "three"),
|
||||||
|
};
|
||||||
|
var tupleEnum =
|
||||||
|
((System.Collections.Generic.IEnumerable<Tuple<int,string>>) tupleArray)
|
||||||
|
.GetEnumerator();
|
||||||
|
while (tupleEnum.MoveNext())
|
||||||
|
System.Console.Write(tupleEnum.Current);
|
||||||
|
System.Console.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestValue(bool selector)
|
void TestValue(bool selector)
|
||||||
@ -425,6 +439,21 @@ namespace Tests
|
|||||||
list.Add(arr1);
|
list.Add(arr1);
|
||||||
var arr2 = list.ToArray();
|
var arr2 = list.ToArray();
|
||||||
PrintArray(arr2[0]);
|
PrintArray(arr2[0]);
|
||||||
|
|
||||||
|
var arr3 = new Guid[] {
|
||||||
|
new Guid("33333333333333333333333333333333"),
|
||||||
|
new Guid("22222222222222222222222222222222"),
|
||||||
|
new Guid("11111111111111111111111111111111"),
|
||||||
|
};
|
||||||
|
System.Array.Sort(arr3, new MyComparer<Guid>());
|
||||||
|
PrintArray(arr3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MyComparer<T> : System.Collections.Generic.IComparer<T>
|
||||||
|
where T : System.IComparable<T>
|
||||||
|
{
|
||||||
|
public int Compare(T x, T y) => x.CompareTo(y);
|
||||||
|
object Clone() => MemberwiseClone();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ namespace Tests
|
|||||||
TestGenericInterface2();
|
TestGenericInterface2();
|
||||||
TestGenericOverload3();
|
TestGenericOverload3();
|
||||||
TestGenericMethodWithEnum();
|
TestGenericMethodWithEnum();
|
||||||
|
TestGenericByRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -179,7 +180,7 @@ namespace Tests
|
|||||||
public virtual int Get(T2 v) => 2;
|
public virtual int Get(T2 v) => 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyOv2<T1,T2> : MyOv1<T1,T2>
|
class MyOv2<T1,T2> : MyOv1<T2,T1>
|
||||||
{
|
{
|
||||||
public override int Get(T1 v) => 3;
|
public override int Get(T1 v) => 3;
|
||||||
public override int Get(T2 v) => 4;
|
public override int Get(T2 v) => 4;
|
||||||
@ -190,6 +191,8 @@ namespace Tests
|
|||||||
var a = new MyOv1<int,bool>();
|
var a = new MyOv1<int,bool>();
|
||||||
Console.Write(a.Get(1));
|
Console.Write(a.Get(1));
|
||||||
Console.Write(a.Get(true));
|
Console.Write(a.Get(true));
|
||||||
|
Console.Write(((I1<bool>) a).Get(true));
|
||||||
|
Console.Write(((I2<int>) a).Get(1));
|
||||||
var b = new MyOv2<int,bool>();
|
var b = new MyOv2<int,bool>();
|
||||||
Console.Write(b.Get(1));
|
Console.Write(b.Get(1));
|
||||||
Console.WriteLine(b.Get(true));
|
Console.WriteLine(b.Get(true));
|
||||||
@ -224,6 +227,7 @@ namespace Tests
|
|||||||
public class CccC1<T1> : CccB1<T1,int> { public override void DoIt(ref T1 a, ref int b) => Console.Write("OK1 "); }
|
public class CccC1<T1> : CccB1<T1,int> { public override void DoIt(ref T1 a, ref int b) => Console.Write("OK1 "); }
|
||||||
public class CccC2<T1> : CccB1<T1,Version> { public override void DoIt(ref T1 a, ref Version b) => Console.Write("OK2 "); }
|
public class CccC2<T1> : CccB1<T1,Version> { public override void DoIt(ref T1 a, ref Version b) => Console.Write("OK2 "); }
|
||||||
public class CccC3<T1> : CccB1<T1,object> { public override void DoIt(ref T1 a, ref object b) => Console.Write("OK3 "); }
|
public class CccC3<T1> : CccB1<T1,object> { public override void DoIt(ref T1 a, ref object b) => Console.Write("OK3 "); }
|
||||||
|
public class CccC4<T0,T2,T1> : CccB1<T1,T2>{ public override void DoIt(ref T1 a, ref T2 b) => Console.Write("OK4 "); }
|
||||||
|
|
||||||
void TestGenericOverload3()
|
void TestGenericOverload3()
|
||||||
{
|
{
|
||||||
@ -235,10 +239,12 @@ namespace Tests
|
|||||||
CccB1<bool,int> c1 = new CccC1<bool>();
|
CccB1<bool,int> c1 = new CccC1<bool>();
|
||||||
CccB1<bool,Version> c2 = new CccC2<bool>();
|
CccB1<bool,Version> c2 = new CccC2<bool>();
|
||||||
CccB1<bool,object> c3 = new CccC3<bool>();
|
CccB1<bool,object> c3 = new CccC3<bool>();
|
||||||
|
CccB1<bool,object>c4 = new CccC4<int,object,bool>();
|
||||||
|
|
||||||
c1.DoIt(ref bFalse, ref iZero);
|
c1.DoIt(ref bFalse, ref iZero);
|
||||||
c2.DoIt(ref bFalse, ref vZero);
|
c2.DoIt(ref bFalse, ref vZero);
|
||||||
c3.DoIt(ref bFalse, ref oZero);
|
c3.DoIt(ref bFalse, ref oZero);
|
||||||
|
c4.DoIt(ref bFalse, ref oZero);
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,5 +264,20 @@ namespace Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// TestGenericByRef
|
||||||
|
//
|
||||||
|
|
||||||
|
void TestGenericByRef()
|
||||||
|
{
|
||||||
|
var guid = new Guid("12345678123456781234567812345678");
|
||||||
|
Helper<Guid>(ref guid, true);
|
||||||
|
|
||||||
|
void Helper<T>(ref T arg, bool cond) where T : IFormattable
|
||||||
|
{
|
||||||
|
Console.WriteLine(arg.ToString(cond ? "" : "D", null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,9 @@ namespace Tests
|
|||||||
DisplayGenericType(tT, "Type parameter T from Base<T>");
|
DisplayGenericType(tT, "Type parameter T from Base<T>");
|
||||||
//DisplayGenericType(tF, "Field type, G<Derived<V>>");
|
//DisplayGenericType(tF, "Field type, G<Derived<V>>");
|
||||||
DisplayGenericType(tNested, "Nested type in Derived<V>");
|
DisplayGenericType(tNested, "Nested type in Derived<V>");
|
||||||
|
|
||||||
|
DisplayGenericType(tDerived.GetNestedType("Nested"),
|
||||||
|
"Nested type in Derived<V> (2)");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DisplayGenericType(Type t, string caption)
|
public static void DisplayGenericType(Type t, string caption)
|
||||||
|
@ -13,6 +13,7 @@ namespace Tests
|
|||||||
{
|
{
|
||||||
TestSuppressGC();
|
TestSuppressGC();
|
||||||
TestUnhandledException();
|
TestUnhandledException();
|
||||||
|
TestUsing();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -46,6 +47,26 @@ namespace Tests
|
|||||||
=> Console.WriteLine("In Unhandled Exception Handler");
|
=> Console.WriteLine("In Unhandled Exception Handler");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// TestUnhandledException
|
||||||
|
//
|
||||||
|
|
||||||
|
public class MyDisposable : System.IDisposable
|
||||||
|
{
|
||||||
|
public void Dispose() => Console.Write("Disposed ");
|
||||||
|
public void close() => Console.Write("Closing ");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestUsing()
|
||||||
|
{
|
||||||
|
using (var myDisposable = new MyDisposable())
|
||||||
|
{
|
||||||
|
myDisposable.Dispose();
|
||||||
|
myDisposable.close();
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
|
|
||||||
#### Goal
|
#### Goal
|
||||||
|
|
||||||
- Set up development of an Android app using a .NET language
|
- Set up development of an Android app using a .NET language.
|
||||||
|
|
||||||
- Either in Visual Studio or using the command line `dotnet` tool.
|
- Either in Visual Studio or using the command line `dotnet` tool.
|
||||||
|
|
||||||
|
|
||||||
- Use Android Studio to build the app.
|
- Use Android Studio to build the app.
|
||||||
|
|
||||||
- With a Gradle plugin to compile .NET code.
|
- With a Gradle task to build the .NET project.
|
||||||
|
|
||||||
- And a Gradle build task to convert the .NET code to Java compiled form.
|
- And a Gradle task to convert the .NET code to Java compiled form.
|
||||||
|
|
||||||
|
|
||||||
- Most of development should be possible on Windows without requiring an Android device.
|
- Most of development should be possible on Windows without requiring an Android device.
|
||||||
@ -20,10 +20,10 @@
|
|||||||
#### Environment Variables
|
#### Environment Variables
|
||||||
|
|
||||||
- Set the environment variable `MSBUILD_EXE` to point to `MSBuild.exe` program file.
|
- Set the environment variable `MSBUILD_EXE` to point to `MSBuild.exe` program file.
|
||||||
- For example, `C:\Program Files (x86)\Microsoft Visual Studio\\2019\Community\MSBuild\Current\Bin\MSBuild.exe`
|
- For example, `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe`
|
||||||
|
|
||||||
|
|
||||||
- Set the environment variable `BLUEBONNET_DIR` to point to a directory containing `Bluebonnet.exe`, `PruneMerge.exe`, `Baselib.jar` and `Android.dll`.
|
- Set the environment variable `BLUEBONNET_DIR` to point to a directory containing `Bluebonnet.exe`, `Baselib.jar` and `Android.dll`.
|
||||||
|
|
||||||
- These files can be downloaded from the [Bluebonnet releases](https://github.com/spaceflint7/bluebonnet/releases) page.
|
- These files can be downloaded from the [Bluebonnet releases](https://github.com/spaceflint7/bluebonnet/releases) page.
|
||||||
|
|
||||||
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
- You may use some other project type or language instead of a C# console app.
|
- You may use some other project type or language instead of a C# console app.
|
||||||
|
|
||||||
- The project must be named `DotNet`.
|
- The project should be named `DotNet`.
|
||||||
|
|
||||||
|
|
||||||
- Edit `DotNet.csproj` to add a reference to Android DLL created by Bluebonnet:
|
- Edit `DotNet.csproj` to add a reference to Android DLL created by Bluebonnet:
|
||||||
@ -158,12 +158,13 @@
|
|||||||
- At the top of the `dependencies` section, insert:
|
- At the top of the `dependencies` section, insert:
|
||||||
|
|
||||||
implementation files("$buildDir/dotnet/dotnet.jar")
|
implementation files("$buildDir/dotnet/dotnet.jar")
|
||||||
|
implementation files("${System.env.BLUEBONNET_DIR}/baselib.jar")
|
||||||
|
|
||||||
- After the `dependencies` section, append:
|
- After the `dependencies` section, append:
|
||||||
|
|
||||||
task buildDotNet {
|
task buildDotNet {
|
||||||
doLast {
|
doLast {
|
||||||
delete("${buildDir}/dotnet/DotNet.jar")
|
delete("${buildDir}/dotnet/dotnet.jar")
|
||||||
exec {
|
exec {
|
||||||
workingDir "${project.rootDir}"
|
workingDir "${project.rootDir}"
|
||||||
commandLine System.env.MSBUILD_EXE ?: 'msbuild.exe',
|
commandLine System.env.MSBUILD_EXE ?: 'msbuild.exe',
|
||||||
@ -176,16 +177,8 @@
|
|||||||
}
|
}
|
||||||
exec {
|
exec {
|
||||||
commandLine "${System.env.BLUEBONNET_DIR}/Bluebonnet.exe",
|
commandLine "${System.env.BLUEBONNET_DIR}/Bluebonnet.exe",
|
||||||
"${buildDir}/dotnet/DotNet.dll",
|
"${buildDir}/dotnet/dotnet.dll",
|
||||||
"${buildDir}/dotnet/DotNet0.jar"
|
"${buildDir}/dotnet/dotnet.jar"
|
||||||
}
|
|
||||||
def manifest = new XmlSlurper().parse(android.sourceSets.main.manifest.srcFile)
|
|
||||||
exec {
|
|
||||||
commandLine "${System.env.BLUEBONNET_DIR}/PruneMerge.exe",
|
|
||||||
"${buildDir}/dotnet/DotNet0.jar",
|
|
||||||
"${System.env.BLUEBONNET_DIR}/Baselib.jar",
|
|
||||||
"${buildDir}/dotnet/DotNet.jar",
|
|
||||||
":${manifest.@package}${manifest.application.activity.'@android:name'}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,6 +232,7 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation files("$buildDir/dotnet/dotnet.jar")
|
implementation files("$buildDir/dotnet/dotnet.jar")
|
||||||
|
implementation files("${System.env.BLUEBONNET_DIR}/baselib.jar")
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||||
implementation 'com.google.android.material:material:1.4.0'
|
implementation 'com.google.android.material:material:1.4.0'
|
||||||
testImplementation 'junit:junit:4.+'
|
testImplementation 'junit:junit:4.+'
|
||||||
@ -248,8 +242,7 @@
|
|||||||
|
|
||||||
task buildDotNet {
|
task buildDotNet {
|
||||||
doLast {
|
doLast {
|
||||||
delete("${buildDir}/dotnet/DotNet.jar")
|
delete("${buildDir}/dotnet/dotnet.jar")
|
||||||
|
|
||||||
exec {
|
exec {
|
||||||
workingDir "${project.rootDir}"
|
workingDir "${project.rootDir}"
|
||||||
commandLine System.env.MSBUILD_EXE ?: 'msbuild.exe',
|
commandLine System.env.MSBUILD_EXE ?: 'msbuild.exe',
|
||||||
@ -262,23 +255,49 @@
|
|||||||
}
|
}
|
||||||
exec {
|
exec {
|
||||||
commandLine "${System.env.BLUEBONNET_DIR}/Bluebonnet.exe",
|
commandLine "${System.env.BLUEBONNET_DIR}/Bluebonnet.exe",
|
||||||
"${buildDir}/dotnet/DotNet.dll",
|
"${buildDir}/dotnet/dotnet.dll",
|
||||||
"${buildDir}/dotnet/DotNet0.jar"
|
"${buildDir}/dotnet/dotnet.jar"
|
||||||
}
|
|
||||||
def manifest = new XmlSlurper().parse(android.sourceSets.main.manifest.srcFile)
|
|
||||||
exec {
|
|
||||||
commandLine "${System.env.BLUEBONNET_DIR}/PruneMerge.exe",
|
|
||||||
"${buildDir}/dotnet/DotNet0.jar",
|
|
||||||
"${System.env.BLUEBONNET_DIR}/Baselib.jar",
|
|
||||||
"${buildDir}/dotnet/DotNet.jar",
|
|
||||||
":${manifest.@package}${manifest.application.activity.'@android:name'}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preBuild.dependsOn buildDotNet
|
preBuild.dependsOn buildDotNet
|
||||||
|
|
||||||
#### Gradle Build Script - Overview
|
#### ProGuard Rules
|
||||||
|
|
||||||
|
- If you wish to minify your release build using Android R8 (ProGuard), enter the following settings into your `app/proguard-rules.pro` file:
|
||||||
|
|
||||||
|
#
|
||||||
|
# these rules prevent discarding of generic types
|
||||||
|
#
|
||||||
|
-keepclassmembers class * implements system.IGenericEntity {
|
||||||
|
public static final java.lang.String ?generic?variance;
|
||||||
|
public static final *** ?generic?info?class;
|
||||||
|
private system.RuntimeType ?generic?type;
|
||||||
|
public static final *** ?generic?info?method (...);
|
||||||
|
<init>(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- Only if you wish to use F#, then enter the settings below as well. They are needed with C# code.
|
||||||
|
|
||||||
|
#
|
||||||
|
# F# printf
|
||||||
|
#
|
||||||
|
-keepclassmembers class microsoft.fsharp.core.PrintfImpl$ObjectPrinter {
|
||||||
|
*** GenericToString? (...);
|
||||||
|
}
|
||||||
|
-keepclassmembers class microsoft.fsharp.core.PrintfImpl$Specializations* {
|
||||||
|
*** * (...);
|
||||||
|
}
|
||||||
|
-keep class microsoft.fsharp.core.CompilationMappingAttribute { *; }
|
||||||
|
-keep class **$Tags { *; }
|
||||||
|
-keepclassmembers class * implements java.io.Serializable {
|
||||||
|
*** get_* ();
|
||||||
|
}
|
||||||
|
-keepattributes InnerClasses
|
||||||
|
|
||||||
|
#### To Summarize of All of the Above
|
||||||
|
|
||||||
- In place of Java source files, a new dependency was added on a JAR file - `dotnet.jar`.
|
- In place of Java source files, a new dependency was added on a JAR file - `dotnet.jar`.
|
||||||
|
|
||||||
@ -286,17 +305,14 @@
|
|||||||
|
|
||||||
- Run `MSBuild` on the .NET project, in `Release` configuration, with the preprocessor define `ANDROID`
|
- Run `MSBuild` on the .NET project, in `Release` configuration, with the preprocessor define `ANDROID`
|
||||||
|
|
||||||
- Run `Bluebonnet` on the resulting `dotnet.dll` to create `dotnet0.jar`
|
- Run `Bluebonnet` on the resulting `dotnet.dll` to create `dotnet.jar`
|
||||||
|
|
||||||
- Extract the class name for the main activity from the file `AndroidManifest.xml`
|
|
||||||
|
|
||||||
- Run `PruneMerge` to merge `Baselib.jar` (from Bluebonnet) and `dotnet0.jar` into the final `dotnet.jar`
|
|
||||||
|
|
||||||
- All unreferenced classes are discard from the output.
|
|
||||||
|
|
||||||
|
|
||||||
- The `buildDotNet` task was set to execute before the Gradle `preBuild` task.
|
- The `buildDotNet` task was set to execute before the Gradle `preBuild` task.
|
||||||
|
|
||||||
|
- ProGuard rules were added to prevent stripping fields and methods used by Bluebonnet to support .NET generic types.
|
||||||
|
|
||||||
#### Test It
|
#### Test It
|
||||||
|
|
||||||
- Compile and run the project in Android Studio.
|
- Compile and run the project in Android Studio.
|
||||||
|
39
USAGE.md
39
USAGE.md
@ -31,26 +31,51 @@ If the input assembly references other assemblies, they are searched in (1) the
|
|||||||
|
|
||||||
.NET C# code which references Java declarations (using a reference assembly, as described above) may use the following syntax to refer to a Java class:
|
.NET C# code which references Java declarations (using a reference assembly, as described above) may use the following syntax to refer to a Java class:
|
||||||
|
|
||||||
(java.lang.Class) typeof(sometype)
|
C#: (java.lang.Class) typeof(sometype)
|
||||||
|
|
||||||
|
F#: java.lang.Class.op_Explicit(typeof<sometype>) (F#)
|
||||||
|
|
||||||
where `sometype` can be any imported Java class, or non-generic .NET type.
|
where `sometype` can be any imported Java class, or non-generic .NET type.
|
||||||
|
|
||||||
#### Access to a Java class object
|
#### Delegates to Java functional interface
|
||||||
|
|
||||||
Java functional interfaces are supported via an artificial delegate, for example:
|
Java functional interfaces are supported via an artificial delegate, for example:
|
||||||
|
|
||||||
java.lang.Thread.setDefaultUncaughtExceptionHandler(
|
C#: java.lang.Thread.setDefaultUncaughtExceptionHandler(
|
||||||
( (java.lang.Thread.UncaughtExceptionHandler.Delegate) (
|
( (java.lang.Thread.UncaughtExceptionHandler.Delegate) (
|
||||||
(java.lang.Thread p1, java.lang.Throwable p2) =>
|
(java.lang.Thread p1, java.lang.Throwable p2) =>
|
||||||
{ .... }) ).AsInterface() );
|
{ ...code... }) ).AsInterface() );
|
||||||
|
|
||||||
In this example, `java.lang.Thread.UncaughtExceptionHandler` is the functional interface, which gets an artificial delegate named `Delegate` as a nested type. The C# lambda is cast to this delegate, and then the `AsInterface` method is invoked, to convert the delegate to a Java interface.
|
F#: java.lang.Thread.setDefaultUncaughtExceptionHandler(
|
||||||
|
(java.lang.Thread.UncaughtExceptionHandler.Delegate (
|
||||||
|
fun (p1: java.lang.Thread) (p2: java.lang.Throwable) ->
|
||||||
|
...code... )).AsInterface())
|
||||||
|
|
||||||
|
In this example, `java.lang.Thread.UncaughtExceptionHandler` is the functional interface, which gets an artificial delegate named `Delegate` as a nested type. The lambda is cast to this delegate, and then the `AsInterface` method is invoked, to convert the delegate to a Java interface.
|
||||||
|
|
||||||
|
#### Java interfaces in F# code
|
||||||
|
|
||||||
|
F# generates [explicit method overrides](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation) for implemented interfaces, which is not compatible with interfaces imported from Java. To work around this, a Java interface must be implemented twice in an F# type:
|
||||||
|
|
||||||
|
type MyType () =
|
||||||
|
|
||||||
|
// Declare the interface so that it is listed as implemented by the type.
|
||||||
|
// The actual method implementations are discarded.
|
||||||
|
|
||||||
|
interface java.lang.Thread.UncaughtExceptionHandler with
|
||||||
|
[<java.attr.Discard>] member this.uncaughtException (_, _) = ()
|
||||||
|
|
||||||
|
// Provide implicit implementations for the necessary methods.
|
||||||
|
// Parameters types must match the interface methods.
|
||||||
|
|
||||||
|
[<java.attr.RetainName>]
|
||||||
|
member this.uncaughtException (p1: java.lang.Thread, p2: java.lang.Throwable) = ()
|
||||||
|
|
||||||
# Attributes
|
# Attributes
|
||||||
|
|
||||||
Bluebonnet recognizes the following attributes:
|
Bluebonnet recognizes the following attributes:
|
||||||
|
|
||||||
- `[java.attr.DiscardAttribute]` on a top-level type (class/struct/interface/delegate) to exclude the type from output. For example, [Baselib/`Object.cs`](https://github.com/spaceflint7/bluebonnet/blob/master/Baselib/src/System/Object.cs) declares a `java.lang.Object` type with a `getClass` method, but there is no need to actually emit a Java class for `java.lang.Object`. For an example of this outside of Baselib, see [BNA/`Import.cs`](https://github.com/spaceflint7/bna/blob/master/BNA/src/Import.cs).
|
- `[java.attr.DiscardAttribute]` on a top-level type (class/struct/interface/delegate) or on a class method to exclude the type or method from output. For example, [Baselib/`Object.cs`](https://github.com/spaceflint7/bluebonnet/blob/master/Baselib/src/System/Object.cs) declares a `java.lang.Object` type with a `getClass` method, but there is no need to actually emit a Java class for `java.lang.Object`. For an example of this outside of Baselib, see [BNA/`Import.cs`](https://github.com/spaceflint7/bna/blob/master/BNA/src/Import.cs).
|
||||||
|
|
||||||
- `[java.attr.RetainTypeAttribute]` on a field data member indicates not to box the field. This is useful for fields that participate in a code hot path, as it eliminates double-references when accessing the field. It should not be used with fields which may be referenced directly from code outside their containing assembly.
|
- `[java.attr.RetainTypeAttribute]` on a field data member indicates not to box the field. This is useful for fields that participate in a code hot path, as it eliminates double-references when accessing the field. It should not be used with fields which may be referenced directly from code outside their containing assembly.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user