Added experimental (and for the time being undocumented) support for having ikvmc pre-generate proxy classes.

This commit is contained in:
jfrijters 2011-05-12 08:08:08 +00:00
Родитель 45760b34dd
Коммит 9be6d7f1ad
10 изменённых файлов: 757 добавлений и 23 удалений

Просмотреть файл

@ -79,6 +79,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="ikvmc\FakeTypes.cs" />
<Compile Include="ikvmc\Proxy.cs" />
<Compile Include="ikvmc\remapper.cs">
<SubType>Code</SubType>
</Compile>

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright (C) 2002-2010 Jeroen Frijters
Copyright (C) 2002-2011 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -778,6 +778,15 @@ class IkvmcCompiler
return 1;
}
}
else if(s.StartsWith("-proxy:")) // currently undocumented!
{
string proxy = s.Substring(7);
if(options.proxies.Contains(proxy))
{
StaticCompiler.IssueMessage(Message.DuplicateProxy, proxy);
}
options.proxies.Add(proxy);
}
else
{
Console.Error.WriteLine("Error: unrecognized option: {0}", s);

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright (C) 2002-2010 Jeroen Frijters
Copyright (C) 2002-2011 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -2961,6 +2961,10 @@ namespace IKVM.Internal
allwrappers.Add(wrapper);
}
}
foreach(string proxy in options.proxies)
{
ProxyGenerator.Create(this, proxy);
}
if(options.mainClass != null)
{
TypeWrapper wrapper = null;
@ -3278,6 +3282,7 @@ namespace IKVM.Internal
internal Dictionary<string, string> suppressWarnings = new Dictionary<string, string>();
internal Dictionary<string, string> errorWarnings = new Dictionary<string, string>();
internal string writeSuppressWarningsFile;
internal List<string> proxies = new List<string>();
internal CompilerOptions Copy()
{
@ -3353,6 +3358,10 @@ namespace IKVM.Internal
AssemblyLocationIgnored = 127,
InterfaceMethodCantBeInternal = 128,
UnknownWarning = 999,
// This is where the errors start
StartErrors = 4000,
UnableToCreateProxy = 4001,
DuplicateProxy = 4002,
}
static class StaticCompiler
@ -3563,25 +3572,32 @@ namespace IKVM.Internal
msg = "ignoring @ikvm.lang.Internal annotation on interface method" + Environment.NewLine +
" (\"{0}.{1}{2}\")";
break;
case Message.UnableToCreateProxy:
msg = "unable to create proxy \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.DuplicateProxy:
msg = "duplicate proxy \"{0}\"";
break;
case Message.UnknownWarning:
msg = "{0}";
break;
default:
throw new InvalidProgramException();
}
if(options.errorWarnings.ContainsKey(key)
|| options.errorWarnings.ContainsKey(((int)msgId).ToString()))
{
Console.Error.Write("{0} IKVMC{1:D4}: ", "Error", (int)msgId);
Console.Error.WriteLine(msg, values);
Environment.Exit(1);
}
Console.Error.Write("{0} IKVMC{1:D4}: ", msgId < Message.StartWarnings ? "Note" : "Warning", (int)msgId);
bool error = msgId >= Message.StartErrors
|| options.errorWarnings.ContainsKey(key)
|| options.errorWarnings.ContainsKey(((int)msgId).ToString());
Console.Error.Write("{0} IKVMC{1:D4}: ", error ? "Error" : msgId < Message.StartWarnings ? "Note" : "Warning", (int)msgId);
Console.Error.WriteLine(msg, values);
if(options != toplevel && options.path != null)
{
Console.Error.WriteLine(" (in {0})", options.path);
}
if(error)
{
Environment.Exit(1);
}
}
internal static void LinkageError(string msg, TypeWrapper actualType, TypeWrapper expectedType, params object[] values)

604
ikvmc/Proxy.cs Normal file
Просмотреть файл

@ -0,0 +1,604 @@
/*
Copyright (C) 2011 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Collections.Generic;
using IKVM.Reflection;
using IKVM.Reflection.Emit;
using Type = IKVM.Reflection.Type;
namespace IKVM.Internal
{
static class ProxyGenerator
{
private static readonly TypeWrapper proxyClass;
private static readonly TypeWrapper errorClass;
private static readonly TypeWrapper runtimeExceptionClass;
private static readonly MethodWrapper undeclaredThrowableExceptionConstructor;
private static readonly FieldWrapper invocationHandlerField;
private static readonly TypeWrapper javaLangReflectMethod;
private static readonly TypeWrapper javaLangNoSuchMethodException;
private static readonly MethodWrapper javaLangNoClassDefFoundErrorConstructor;
private static readonly MethodWrapper javaLangThrowable_getMessage;
private static readonly MethodWrapper javaLangClass_getMethod;
private static readonly TypeWrapper invocationHandlerClass;
private static readonly MethodWrapper invokeMethod;
private static readonly MethodWrapper proxyConstructor;
private static readonly MethodWrapper hashCodeMethod;
private static readonly MethodWrapper equalsMethod;
private static readonly MethodWrapper toStringMethod;
static ProxyGenerator()
{
ClassLoaderWrapper bootClassLoader = ClassLoaderWrapper.GetBootstrapClassLoader();
proxyClass = bootClassLoader.LoadClassByDottedNameFast("java.lang.reflect.Proxy");
errorClass = bootClassLoader.LoadClassByDottedNameFast("java.lang.Error");
runtimeExceptionClass = bootClassLoader.LoadClassByDottedNameFast("java.lang.RuntimeException");
undeclaredThrowableExceptionConstructor = bootClassLoader.LoadClassByDottedNameFast("java.lang.reflect.UndeclaredThrowableException").GetMethodWrapper("<init>", "(Ljava.lang.Throwable;)V", false);
undeclaredThrowableExceptionConstructor.Link();
invocationHandlerField = proxyClass.GetFieldWrapper("h", "Ljava.lang.reflect.InvocationHandler;");
invocationHandlerField.Link();
javaLangReflectMethod = bootClassLoader.LoadClassByDottedNameFast("java.lang.reflect.Method");
javaLangNoSuchMethodException = bootClassLoader.LoadClassByDottedNameFast("java.lang.NoSuchMethodException");
javaLangNoClassDefFoundErrorConstructor = bootClassLoader.LoadClassByDottedNameFast("java.lang.NoClassDefFoundError").GetMethodWrapper("<init>", "(Ljava.lang.String;)V", false);
javaLangNoClassDefFoundErrorConstructor.Link();
javaLangThrowable_getMessage = bootClassLoader.LoadClassByDottedNameFast("java.lang.Throwable").GetMethodWrapper("getMessage", "()Ljava.lang.String;", false);
javaLangThrowable_getMessage.Link();
javaLangClass_getMethod = CoreClasses.java.lang.Class.Wrapper.GetMethodWrapper("getMethod", "(Ljava.lang.String;[Ljava.lang.Class;)Ljava.lang.reflect.Method;", false);
javaLangClass_getMethod.Link();
invocationHandlerClass = bootClassLoader.LoadClassByDottedNameFast("java.lang.reflect.InvocationHandler");
invokeMethod = invocationHandlerClass.GetMethodWrapper("invoke", "(Ljava.lang.Object;Ljava.lang.reflect.Method;[Ljava.lang.Object;)Ljava.lang.Object;", false);
proxyConstructor = proxyClass.GetMethodWrapper("<init>", "(Ljava.lang.reflect.InvocationHandler;)V", false);
proxyConstructor.Link();
hashCodeMethod = CoreClasses.java.lang.Object.Wrapper.GetMethodWrapper("hashCode", "()I", false);
equalsMethod = CoreClasses.java.lang.Object.Wrapper.GetMethodWrapper("equals", "(Ljava.lang.Object;)Z", false);
toStringMethod = CoreClasses.java.lang.Object.Wrapper.GetMethodWrapper("toString", "()Ljava.lang.String;", false);
}
internal static void Create(CompilerClassLoader loader, string proxy)
{
string[] interfaces = proxy.Split(',');
TypeWrapper[] wrappers = new TypeWrapper[interfaces.Length];
for (int i = 0; i < interfaces.Length; i++)
{
try
{
wrappers[i] = loader.LoadClassByDottedNameFast(interfaces[i]);
}
catch (RetargetableJavaException)
{
}
if (wrappers[i] == null)
{
StaticCompiler.IssueMessage(Message.UnableToCreateProxy, proxy, "unable to load interface " + interfaces[i]);
return;
}
}
Create(loader, proxy, wrappers);
}
private static void Create(CompilerClassLoader loader, string proxy, TypeWrapper[] interfaces)
{
List<ProxyMethod> methods;
try
{
methods = CheckAndCollect(loader, interfaces);
}
catch (RetargetableJavaException x)
{
StaticCompiler.IssueMessage(Message.UnableToCreateProxy, proxy, x.Message);
return;
}
catch (ProxyException x)
{
StaticCompiler.IssueMessage(Message.UnableToCreateProxy, proxy, x.Message);
return;
}
CreateNoFail(loader, interfaces, methods);
}
private static List<ProxyMethod> CheckAndCollect(CompilerClassLoader loader, TypeWrapper[] interfaces)
{
List<MethodWrapper> methods = new List<MethodWrapper>();
// The java.lang.Object methods precede any interface methods.
methods.Add(equalsMethod);
methods.Add(hashCodeMethod);
methods.Add(toStringMethod);
// Add the interfaces methods in order.
foreach (TypeWrapper tw in interfaces)
{
if (!tw.IsInterface)
{
throw new ProxyException(tw.Name + " is not an interface");
}
if (tw.IsRemapped)
{
// TODO handle java.lang.Comparable
throw new ProxyException(tw.Name + " is a remapped interface (not currently supported)");
}
foreach (MethodWrapper mw in GetInterfaceMethods(tw))
{
// Check for duplicates
if (!MethodExists(methods, mw))
{
methods.Add(mw);
}
}
}
// TODO verify restrictions
// Collect declared exceptions.
Dictionary<string, TypeWrapper[]> exceptions = new Dictionary<string, TypeWrapper[]>();
foreach (MethodWrapper mw in methods)
{
Add(loader, exceptions, mw);
}
// Build the definitive proxy method list.
List<ProxyMethod> proxyMethods = new List<ProxyMethod>();
foreach (MethodWrapper mw in methods)
{
proxyMethods.Add(new ProxyMethod(mw, exceptions[mw.Signature]));
}
return proxyMethods;
}
private static bool MethodExists(List<MethodWrapper> methods, MethodWrapper mw)
{
foreach (MethodWrapper mw1 in methods)
{
// TODO what do we do with differing return types?
if (mw1.Name == mw.Name && mw1.Signature == mw.Signature)
{
return true;
}
}
return false;
}
private static void Add(CompilerClassLoader loader, Dictionary<string, TypeWrapper[]> exceptions, MethodWrapper mw)
{
string signature = mw.Signature;
TypeWrapper[] newExceptionTypes = LoadTypes(loader, mw.GetDeclaredExceptions());
TypeWrapper[] curExceptionTypes;
if (exceptions.TryGetValue(signature, out curExceptionTypes))
{
exceptions[signature] = Merge(newExceptionTypes, curExceptionTypes);
}
else
{
exceptions.Add(signature, newExceptionTypes);
}
}
private static TypeWrapper[] Merge(TypeWrapper[] newExceptionTypes, TypeWrapper[] curExceptionTypes)
{
List<TypeWrapper> list = new List<TypeWrapper>();
foreach (TypeWrapper twNew in newExceptionTypes)
{
TypeWrapper match = null;
foreach (TypeWrapper twCur in curExceptionTypes)
{
if (twNew.IsAssignableTo(twCur))
{
if (match == null || twCur.IsAssignableTo(match))
{
match = twCur;
}
}
}
if (match != null && !list.Contains(match))
{
list.Add(match);
}
}
return list.ToArray();
}
private static void CreateNoFail(CompilerClassLoader loader, TypeWrapper[] interfaces, List<ProxyMethod> methods)
{
DynamicClassLoader factory = (DynamicClassLoader)loader.GetTypeWrapperFactory();
TypeBuilder tb = factory.DefineProxy(proxyClass, interfaces);
AttributeHelper.SetImplementsAttribute(tb, interfaces);
CreateConstructor(tb);
for (int i = 0; i < methods.Count; i++)
{
methods[i].fb = tb.DefineField("m" + i, javaLangReflectMethod.TypeAsSignatureType, FieldAttributes.Private | FieldAttributes.Static);
}
foreach (ProxyMethod method in methods)
{
CreateMethod(tb, method);
}
CreateStaticInitializer(tb, methods);
}
private static void CreateConstructor(TypeBuilder tb)
{
ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { invocationHandlerClass.TypeAsSignatureType });
CodeEmitter ilgen = CodeEmitter.Create(cb);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
proxyConstructor.EmitCall(ilgen);
ilgen.Emit(OpCodes.Ret);
ilgen.DoEmit();
}
private static void CreateMethod(TypeBuilder tb, ProxyMethod pm)
{
MethodBuilder mb = tb.DefineMethod(pm.mw.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, pm.mw.ReturnType.TypeAsSignatureType, pm.mw.GetParametersForDefineMethod());
List<string> exceptions = new List<string>();
foreach (TypeWrapper tw in pm.exceptions)
{
exceptions.Add(tw.Name);
}
AttributeHelper.SetThrowsAttribute(mb, exceptions.ToArray());
CodeEmitter ilgen = CodeEmitter.Create(mb);
ilgen.BeginExceptionBlock();
ilgen.Emit(OpCodes.Ldarg_0);
invocationHandlerField.EmitGet(ilgen);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldsfld, pm.fb);
TypeWrapper[] parameters = pm.mw.GetParameters();
if (parameters.Length == 0)
{
ilgen.Emit(OpCodes.Ldnull);
}
else
{
ilgen.Emit_Ldc_I4(parameters.Length);
ilgen.Emit(OpCodes.Newarr, Types.Object);
for (int i = 0; i < parameters.Length; i++)
{
ilgen.Emit(OpCodes.Dup);
ilgen.Emit_Ldc_I4(i);
ilgen.Emit(OpCodes.Ldarg, (short)i);
if (parameters[i].IsNonPrimitiveValueType)
{
parameters[i].EmitBox(ilgen);
}
else if (parameters[i].IsPrimitive)
{
Boxer.EmitBox(ilgen, parameters[i]);
}
ilgen.Emit(OpCodes.Stelem_Ref);
}
}
invokeMethod.EmitCallvirt(ilgen);
TypeWrapper returnType = pm.mw.ReturnType;
CodeEmitterLocal returnValue = null;
if (returnType != PrimitiveTypeWrapper.VOID)
{
returnValue = ilgen.DeclareLocal(returnType.TypeAsSignatureType);
if (returnType.IsNonPrimitiveValueType)
{
returnType.EmitUnbox(ilgen);
}
else if (returnType.IsPrimitive)
{
Boxer.EmitUnbox(ilgen, returnType);
}
else if (returnType != CoreClasses.java.lang.Object.Wrapper)
{
ilgen.EmitCastclass(returnType.TypeAsSignatureType);
}
ilgen.Emit(OpCodes.Stloc, returnValue);
}
CodeEmitterLabel returnLabel = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Leave, returnLabel);
// TODO consider using a filter here (but we would need to add filter support to CodeEmitter)
ilgen.BeginCatchBlock(Types.Exception);
ilgen.Emit_Ldc_I4(0);
ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.mapException.MakeGenericMethod(Types.Exception));
CodeEmitterLocal exception = ilgen.DeclareLocal(Types.Exception);
ilgen.Emit(OpCodes.Stloc, exception);
CodeEmitterLabel rethrow = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Ldloc, exception);
errorClass.EmitInstanceOf(null, ilgen);
ilgen.Emit(OpCodes.Brtrue, rethrow);
ilgen.Emit(OpCodes.Ldloc, exception);
runtimeExceptionClass.EmitInstanceOf(null, ilgen);
ilgen.Emit(OpCodes.Brtrue, rethrow);
foreach (TypeWrapper tw in pm.exceptions)
{
ilgen.Emit(OpCodes.Ldloc, exception);
tw.EmitInstanceOf(null, ilgen);
ilgen.Emit(OpCodes.Brtrue, rethrow);
}
ilgen.Emit(OpCodes.Ldloc, exception);
undeclaredThrowableExceptionConstructor.EmitNewobj(ilgen);
ilgen.Emit(OpCodes.Throw);
ilgen.MarkLabel(rethrow);
ilgen.Emit(OpCodes.Rethrow);
ilgen.EndExceptionBlock();
ilgen.MarkLabel(returnLabel);
if (returnValue != null)
{
ilgen.Emit(OpCodes.Ldloc, returnValue);
}
ilgen.Emit(OpCodes.Ret);
ilgen.DoEmit();
}
private static void CreateStaticInitializer(TypeBuilder tb, List<ProxyMethod> methods)
{
ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes);
CodeEmitter ilgen = CodeEmitter.Create(cb);
CodeEmitterLocal callerID = ilgen.DeclareLocal(CoreClasses.ikvm.@internal.CallerID.Wrapper.TypeAsSignatureType);
TypeBuilder tbCallerID = DynamicTypeWrapper.FinishContext.EmitCreateCallerID(tb, ilgen);
ilgen.Emit(OpCodes.Stloc, callerID);
// HACK we shouldn't create the nested type here (the outer type must be created first)
tbCallerID.CreateType();
ilgen.BeginExceptionBlock();
foreach (ProxyMethod method in methods)
{
method.mw.DeclaringType.EmitClassLiteral(ilgen);
ilgen.Emit(OpCodes.Ldstr, method.mw.Name);
TypeWrapper[] parameters = method.mw.GetParameters();
ilgen.Emit(OpCodes.Ldc_I4, parameters.Length);
ilgen.Emit(OpCodes.Newarr, CoreClasses.java.lang.Class.Wrapper.TypeAsArrayType);
for (int i = 0; i < parameters.Length; i++)
{
ilgen.Emit(OpCodes.Dup);
ilgen.Emit(OpCodes.Ldc_I4, i);
parameters[i].EmitClassLiteral(ilgen);
ilgen.Emit(OpCodes.Stelem_Ref);
}
if (javaLangClass_getMethod.HasCallerID)
{
ilgen.Emit(OpCodes.Ldloc, callerID);
}
javaLangClass_getMethod.EmitCallvirt(ilgen);
ilgen.Emit(OpCodes.Stsfld, method.fb);
}
CodeEmitterLabel label = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Leave_S, label);
ilgen.BeginCatchBlock(javaLangNoSuchMethodException.TypeAsExceptionType);
javaLangThrowable_getMessage.EmitCallvirt(ilgen);
javaLangNoClassDefFoundErrorConstructor.EmitNewobj(ilgen);
ilgen.Emit(OpCodes.Throw);
ilgen.EndExceptionBlock();
ilgen.MarkLabel(label);
ilgen.Emit(OpCodes.Ret);
ilgen.DoEmit();
}
private sealed class ProxyMethod
{
internal readonly MethodWrapper mw;
internal readonly TypeWrapper[] exceptions;
internal FieldBuilder fb;
internal ProxyMethod(MethodWrapper mw, TypeWrapper[] exceptions)
{
this.mw = mw;
this.exceptions = exceptions;
}
}
private static IEnumerable<MethodWrapper> GetInterfaceMethods(TypeWrapper tw)
{
Dictionary<string, MethodWrapper> methods = new Dictionary<string, MethodWrapper>();
foreach (MethodWrapper mw in tw.GetMethods())
{
methods.Add(mw.Name + mw.Signature, mw);
}
foreach (TypeWrapper iface in tw.Interfaces)
{
foreach (MethodWrapper mw in GetInterfaceMethods(iface))
{
if (!methods.ContainsKey(mw.Name + mw.Signature))
{
methods.Add(mw.Name + mw.Signature, mw);
}
}
}
return methods.Values;
}
private static TypeWrapper[] LoadTypes(ClassLoaderWrapper loader, string[] classes)
{
if (classes == null || classes.Length == 0)
{
return TypeWrapper.EmptyArray;
}
TypeWrapper[] tw = new TypeWrapper[classes.Length];
for (int i = 0; i < tw.Length; i++)
{
tw[i] = loader.LoadClassByDottedName(classes[i]);
}
return tw;
}
private sealed class ProxyException : Exception
{
internal ProxyException(string msg)
: base(msg)
{
}
}
}
static class Boxer
{
private static readonly TypeWrapper javaLangByte;
private static readonly MethodWrapper byteValue;
private static readonly MethodWrapper valueOfByte;
private static readonly TypeWrapper javaLangBoolean;
private static readonly MethodWrapper booleanValue;
private static readonly MethodWrapper valueOfBoolean;
private static readonly TypeWrapper javaLangShort;
private static readonly MethodWrapper shortValue;
private static readonly MethodWrapper valueOfShort;
private static readonly TypeWrapper javaLangCharacter;
private static readonly MethodWrapper charValue;
private static readonly MethodWrapper valueOfCharacter;
private static readonly TypeWrapper javaLangInteger;
private static readonly MethodWrapper intValue;
private static readonly MethodWrapper valueOfInteger;
private static readonly TypeWrapper javaLangFloat;
private static readonly MethodWrapper floatValue;
private static readonly MethodWrapper valueOfFloat;
private static readonly TypeWrapper javaLangLong;
private static readonly MethodWrapper longValue;
private static readonly MethodWrapper valueOfLong;
private static readonly TypeWrapper javaLangDouble;
private static readonly MethodWrapper doubleValue;
private static readonly MethodWrapper valueOfDouble;
static Boxer()
{
ClassLoaderWrapper bootClassLoader = ClassLoaderWrapper.GetBootstrapClassLoader();
javaLangByte = bootClassLoader.LoadClassByDottedNameFast("java.lang.Byte");
byteValue = javaLangByte.GetMethodWrapper("byteValue", "()B", false);
byteValue.Link();
valueOfByte = javaLangByte.GetMethodWrapper("valueOf", "(B)Ljava.lang.Byte;", false);
valueOfByte.Link();
javaLangBoolean = bootClassLoader.LoadClassByDottedNameFast("java.lang.Boolean");
booleanValue = javaLangBoolean.GetMethodWrapper("booleanValue", "()Z", false);
booleanValue.Link();
valueOfBoolean = javaLangBoolean.GetMethodWrapper("valueOf", "(Z)Ljava.lang.Boolean;", false);
valueOfBoolean.Link();
javaLangShort = bootClassLoader.LoadClassByDottedNameFast("java.lang.Short");
shortValue = javaLangShort.GetMethodWrapper("shortValue", "()S", false);
shortValue.Link();
valueOfShort = javaLangShort.GetMethodWrapper("valueOf", "(S)Ljava.lang.Short;", false);
valueOfShort.Link();
javaLangCharacter = bootClassLoader.LoadClassByDottedNameFast("java.lang.Character");
charValue = javaLangCharacter.GetMethodWrapper("charValue", "()C", false);
charValue.Link();
valueOfCharacter = javaLangCharacter.GetMethodWrapper("valueOf", "(C)Ljava.lang.Character;", false);
valueOfCharacter.Link();
javaLangInteger = bootClassLoader.LoadClassByDottedNameFast("java.lang.Integer");
intValue = javaLangInteger.GetMethodWrapper("intValue", "()I", false);
intValue.Link();
valueOfInteger = javaLangInteger.GetMethodWrapper("valueOf", "(I)Ljava.lang.Integer;", false);
valueOfInteger.Link();
javaLangFloat = bootClassLoader.LoadClassByDottedNameFast("java.lang.Float");
floatValue = javaLangFloat.GetMethodWrapper("floatValue", "()F", false);
floatValue.Link();
valueOfFloat = javaLangFloat.GetMethodWrapper("valueOf", "(F)Ljava.lang.Float;", false);
valueOfFloat.Link();
javaLangLong = bootClassLoader.LoadClassByDottedNameFast("java.lang.Long");
longValue = javaLangLong.GetMethodWrapper("longValue", "()J", false);
longValue.Link();
valueOfLong = javaLangLong.GetMethodWrapper("valueOf", "(J)Ljava.lang.Long;", false);
valueOfLong.Link();
javaLangDouble = bootClassLoader.LoadClassByDottedNameFast("java.lang.Double");
doubleValue = javaLangDouble.GetMethodWrapper("doubleValue", "()D", false);
doubleValue.Link();
valueOfDouble = javaLangDouble.GetMethodWrapper("valueOf", "(D)Ljava.lang.Double;", false);
valueOfDouble.Link();
}
internal static void EmitUnbox(CodeEmitter ilgen, TypeWrapper tw)
{
if (tw == PrimitiveTypeWrapper.BYTE)
{
javaLangByte.EmitCheckcast(null, ilgen);
byteValue.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.BOOLEAN)
{
javaLangBoolean.EmitCheckcast(null, ilgen);
booleanValue.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.SHORT)
{
javaLangShort.EmitCheckcast(null, ilgen);
shortValue.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.CHAR)
{
javaLangCharacter.EmitCheckcast(null, ilgen);
charValue.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.INT)
{
javaLangInteger.EmitCheckcast(null, ilgen);
intValue.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.FLOAT)
{
javaLangFloat.EmitCheckcast(null, ilgen);
floatValue.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.LONG)
{
javaLangLong.EmitCheckcast(null, ilgen);
longValue.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.DOUBLE)
{
javaLangDouble.EmitCheckcast(null, ilgen);
doubleValue.EmitCall(ilgen);
}
else
{
throw new InvalidOperationException();
}
}
internal static void EmitBox(CodeEmitter ilgen, TypeWrapper tw)
{
if (tw == PrimitiveTypeWrapper.BYTE)
{
valueOfByte.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.BOOLEAN)
{
valueOfBoolean.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.SHORT)
{
valueOfShort.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.CHAR)
{
valueOfCharacter.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.INT)
{
valueOfInteger.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.FLOAT)
{
valueOfFloat.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.LONG)
{
valueOfLong.EmitCall(ilgen);
}
else if (tw == PrimitiveTypeWrapper.DOUBLE)
{
valueOfDouble.EmitCall(ilgen);
}
else
{
throw new InvalidOperationException();
}
}
}
}

Просмотреть файл

@ -17,6 +17,7 @@
<include name="Compiler.cs" />
<include name="CompilerClassLoader.cs" />
<include name="FakeTypes.cs" />
<include name="Proxy.cs" />
<include name="remapper.cs" />
<include name="../runtime/AssemblyClassLoader.cs" />
<include name="../runtime/atomic.cs" />

Просмотреть файл

@ -498,6 +498,7 @@ public class Proxy implements java.io.Serializable {
proxyPkg = ""; // use the unnamed package
}
generate: do
{
/*
* Choose a name for the proxy class to generate.
@ -512,6 +513,10 @@ public class Proxy implements java.io.Serializable {
* defined a class with the chosen name.
*/
proxyClass = getPrecompiledProxy(loader, proxyName, interfaces);
if (proxyClass != null)
break generate;
/*
* Generate the specified proxy class.
*/
@ -531,6 +536,7 @@ public class Proxy implements java.io.Serializable {
throw new IllegalArgumentException(e.toString());
}
}
while (false);
// add to set of all generated proxy classes, for isProxyClass
proxyClasses.put(proxyClass, null);
@ -660,4 +666,6 @@ public class Proxy implements java.io.Serializable {
private static native Class defineClass0(ClassLoader loader, String name,
byte[] b, int off, int len);
private static native Class getPrecompiledProxy(ClassLoader loader, String proxyName, Class[] interfaces);
}

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright (C) 2002-2010 Jeroen Frijters
Copyright (C) 2002-2011 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -49,6 +49,8 @@ namespace IKVM.Internal
#if STATIC_COMPILER
private TypeBuilder proxyHelperContainer;
private List<TypeBuilder> proxyHelpers;
private TypeBuilder proxiesContainer;
private List<TypeBuilder> proxies;
#endif // STATIC_COMPILER
private Dictionary<string, TypeBuilder> unloadables;
private TypeBuilder unloadableContainer;
@ -250,8 +252,42 @@ namespace IKVM.Internal
}
proxyHelpers.Add(proxyHelperContainer.DefineNestedType(MangleNestedTypeName(type.FullName), TypeAttributes.NestedPublic | TypeAttributes.Interface | TypeAttributes.Abstract, null, new Type[] { type }));
}
internal TypeBuilder DefineProxy(TypeWrapper proxyClass, TypeWrapper[] interfaces)
{
if (proxiesContainer == null)
{
proxiesContainer = moduleBuilder.DefineType("__<Proxies>", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract);
AttributeHelper.HideFromJava(proxiesContainer);
AttributeHelper.SetEditorBrowsableNever(proxiesContainer);
proxies = new List<TypeBuilder>();
}
Type[] ifaces = new Type[interfaces.Length];
for (int i = 0; i < ifaces.Length; i++)
{
ifaces[i] = interfaces[i].TypeAsBaseType;
}
TypeBuilder tb = proxiesContainer.DefineNestedType(GetProxyNestedName(interfaces), TypeAttributes.NestedPublic | TypeAttributes.Class | TypeAttributes.Sealed, proxyClass.TypeAsBaseType, ifaces);
proxies.Add(tb);
return tb;
}
#endif
private static string GetProxyNestedName(TypeWrapper[] interfaces)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (TypeWrapper tw in interfaces)
{
sb.Append(tw.Name.Length).Append('|').Append(tw.Name);
}
return MangleNestedTypeName(sb.ToString());
}
internal static string GetProxyName(TypeWrapper[] interfaces)
{
return "__<Proxies>+" + GetProxyNestedName(interfaces);
}
internal static string GetProxyHelperName(Type type)
{
return "__<Proxy>+" + MangleNestedTypeName(type.FullName);
@ -347,6 +383,14 @@ namespace IKVM.Internal
tb.CreateType();
}
}
if(proxiesContainer != null)
{
proxiesContainer.CreateType();
foreach(TypeBuilder tb in proxies)
{
tb.CreateType();
}
}
#endif // STATIC_COMPILER
}

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright (C) 2002-2010 Jeroen Frijters
Copyright (C) 2002-2011 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -5121,10 +5121,10 @@ namespace IKVM.Internal
private void EmitCallerIDInitialization(CodeEmitter ilGenerator, FieldInfo callerIDField)
{
{
TypeWrapper tw = CoreClasses.ikvm.@internal.CallerID.Wrapper;
// we need to prohibit this optimization at runtime, because proxy classes may be injected into the boot class loader,
// but they don't actually have access to core library internals
#if STATIC_COMPILER
TypeWrapper tw = CoreClasses.ikvm.@internal.CallerID.Wrapper;
if (tw.GetClassLoader() == wrapper.GetClassLoader())
{
MethodWrapper create = tw.GetMethodWrapper("create", "(Lcli.System.RuntimeTypeHandle;)Likvm.internal.CallerID;", false);
@ -5135,21 +5135,28 @@ namespace IKVM.Internal
else
#endif
{
typeCallerID = typeBuilder.DefineNestedType("__<CallerID>", TypeAttributes.Sealed | TypeAttributes.NestedPrivate, tw.TypeAsBaseType);
ConstructorBuilder cb = typeCallerID.DefineConstructor(MethodAttributes.Assembly, CallingConventions.Standard, null);
CodeEmitter ctorIlgen = CodeEmitter.Create(cb);
ctorIlgen.Emit(OpCodes.Ldarg_0);
MethodWrapper mw = tw.GetMethodWrapper("<init>", "()V", false);
mw.Link();
mw.EmitCall(ctorIlgen);
ctorIlgen.Emit(OpCodes.Ret);
ctorIlgen.DoEmit();
ilGenerator.Emit(OpCodes.Newobj, cb);
typeCallerID = EmitCreateCallerID(typeBuilder, ilGenerator);
}
ilGenerator.Emit(OpCodes.Stsfld, callerIDField);
}
}
internal static TypeBuilder EmitCreateCallerID(TypeBuilder typeBuilder, CodeEmitter ilGenerator)
{
TypeWrapper tw = CoreClasses.ikvm.@internal.CallerID.Wrapper;
TypeBuilder typeCallerID = typeBuilder.DefineNestedType("__<CallerID>", TypeAttributes.Sealed | TypeAttributes.NestedPrivate, tw.TypeAsBaseType);
ConstructorBuilder cb = typeCallerID.DefineConstructor(MethodAttributes.Assembly, CallingConventions.Standard, null);
CodeEmitter ctorIlgen = CodeEmitter.Create(cb);
ctorIlgen.Emit(OpCodes.Ldarg_0);
MethodWrapper mw = tw.GetMethodWrapper("<init>", "()V", false);
mw.Link();
mw.EmitCall(ctorIlgen);
ctorIlgen.Emit(OpCodes.Ret);
ctorIlgen.DoEmit();
ilGenerator.Emit(OpCodes.Newobj, cb);
return typeCallerID;
}
private void EmitConstantValueInitialization(FieldWrapper[] fields, CodeEmitter ilGenerator)
{
ClassFile.Field[] flds = classFile.Fields;

Просмотреть файл

@ -483,6 +483,11 @@ namespace IKVM.Internal
this.declaredExceptions = (string[])exceptions.Clone();
}
internal string[] GetDeclaredExceptions()
{
return declaredExceptions;
}
#if !STATIC_COMPILER && !STUB_GENERATOR
internal object ToMethodOrConstructor(bool copy)
{

Просмотреть файл

@ -3544,6 +3544,45 @@ namespace IKVM.NativeCode.java
{
return ClassLoader.defineClass1(classLoader, name, b, off, len, null, null);
}
public static jlClass getPrecompiledProxy(jlClassLoader classLoader, string proxyName, jlClass[] interfaces)
{
AssemblyClassLoader acl = ClassLoaderWrapper.GetClassLoaderWrapper(classLoader) as AssemblyClassLoader;
if (acl == null)
{
return null;
}
TypeWrapper[] wrappers = new TypeWrapper[interfaces.Length];
for (int i = 0; i < wrappers.Length; i++)
{
wrappers[i] = TypeWrapper.FromClass(interfaces[i]);
}
// TODO support multi assembly class loaders
Type type = acl.MainAssembly.GetType(DynamicClassLoader.GetProxyName(wrappers));
if (type == null)
{
return null;
}
TypeWrapper tw = CompiledTypeWrapper.newInstance(proxyName, type);
TypeWrapper tw2 = acl.RegisterInitiatingLoader(tw);
if (tw != tw2)
{
return null;
}
TypeWrapper[] wrappers2 = tw.Interfaces;
if (wrappers.Length != wrappers.Length)
{
return null;
}
for (int i = 0; i < wrappers.Length; i++)
{
if (wrappers[i] != wrappers2[i])
{
return null;
}
}
return tw.ClassObject;
}
}
static class Field