ikvm-fork/runtime/MemberWrapper.cs

1660 строки
44 KiB
C#
Исходник Обычный вид История

2003-05-30 16:08:59 +04:00
/*
2004-08-17 13:05:21 +04:00
Copyright (C) 2002, 2003, 2004 Jeroen Frijters
2003-05-30 16:08:59 +04:00
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;
2004-08-17 13:05:21 +04:00
using System.Collections;
2003-05-30 16:08:59 +04:00
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
2004-09-09 15:17:55 +04:00
using IKVM.Attributes;
using IKVM.Internal;
using IKVM.Runtime;
2003-05-30 16:08:59 +04:00
2004-10-19 17:43:55 +04:00
using ILGenerator = CountingILGenerator;
2004-08-17 13:05:21 +04:00
[Flags]
enum MemberFlags : short
{
None = 0,
HideFromReflection = 1,
ExplicitOverride = 2
}
2003-05-30 16:08:59 +04:00
class MemberWrapper
{
private System.Runtime.InteropServices.GCHandle handle;
private TypeWrapper declaringType;
private Modifiers modifiers;
2004-08-17 13:05:21 +04:00
private MemberFlags flags;
2003-05-30 16:08:59 +04:00
protected MemberWrapper(TypeWrapper declaringType, Modifiers modifiers, bool hideFromReflection)
2004-08-17 13:05:21 +04:00
: this(declaringType, modifiers, hideFromReflection ? MemberFlags.HideFromReflection : MemberFlags.None)
{
}
protected MemberWrapper(TypeWrapper declaringType, Modifiers modifiers, MemberFlags flags)
2003-05-30 16:08:59 +04:00
{
2003-07-07 18:18:27 +04:00
Debug.Assert(declaringType != null);
2003-05-30 16:08:59 +04:00
this.declaringType = declaringType;
this.modifiers = modifiers;
2004-08-17 13:05:21 +04:00
this.flags = flags;
2003-05-30 16:08:59 +04:00
}
~MemberWrapper()
{
if(handle.IsAllocated)
{
handle.Free();
}
}
internal IntPtr Cookie
{
get
{
lock(this)
{
if(!handle.IsAllocated)
{
handle = System.Runtime.InteropServices.GCHandle.Alloc(this, System.Runtime.InteropServices.GCHandleType.Weak);
}
}
return (IntPtr)handle;
}
}
internal static MemberWrapper FromCookieImpl(IntPtr cookie)
{
return (MemberWrapper)((System.Runtime.InteropServices.GCHandle)cookie).Target;
}
internal TypeWrapper DeclaringType
{
get
{
return declaringType;
}
}
2004-08-17 13:05:21 +04:00
internal bool IsAccessibleFrom(TypeWrapper caller, TypeWrapper instance)
{
return IsPublic ||
caller == DeclaringType ||
(IsProtected && (IsStatic ? caller.IsSubTypeOf(DeclaringType) : instance.IsSubTypeOf(caller))) ||
(!IsPrivate && caller.IsInSamePackageAs(DeclaringType));
}
2003-05-30 16:08:59 +04:00
internal bool IsHideFromReflection
{
get
{
2004-08-17 13:05:21 +04:00
return (flags & MemberFlags.HideFromReflection) != 0;
}
}
internal bool IsExplicitOverride
{
get
{
return (flags & MemberFlags.ExplicitOverride) != 0;
2003-05-30 16:08:59 +04:00
}
}
internal Modifiers Modifiers
{
get
{
return modifiers;
}
}
internal bool IsStatic
{
get
{
return (modifiers & Modifiers.Static) != 0;
}
}
internal bool IsPublic
{
get
{
return (modifiers & Modifiers.Public) != 0;
}
}
internal bool IsPrivate
{
get
{
return (modifiers & Modifiers.Private) != 0;
}
}
internal bool IsProtected
{
get
{
return (modifiers & Modifiers.Protected) != 0;
}
}
internal bool IsFinal
{
get
{
return (modifiers & Modifiers.Final) != 0;
}
}
}
2004-08-17 13:05:21 +04:00
abstract class MethodWrapper : MemberWrapper
2003-05-30 16:08:59 +04:00
{
private MethodDescriptor md;
2004-06-14 14:36:38 +04:00
private MethodBase method;
2003-11-17 15:01:50 +03:00
private string[] declaredExceptions;
2004-08-17 13:05:21 +04:00
private TypeWrapper returnTypeWrapper;
private TypeWrapper[] parameterTypeWrappers;
2003-05-30 16:08:59 +04:00
2004-08-17 13:05:21 +04:00
internal virtual void EmitCall(ILGenerator ilgen)
2003-12-20 01:19:18 +03:00
{
2004-08-17 13:05:21 +04:00
throw new InvalidOperationException();
}
2003-12-20 01:19:18 +03:00
2004-08-17 13:05:21 +04:00
internal virtual void EmitCallvirt(ILGenerator ilgen)
{
throw new InvalidOperationException();
}
2003-12-20 01:19:18 +03:00
2004-08-17 13:05:21 +04:00
internal virtual void EmitNewobj(ILGenerator ilgen)
{
throw new InvalidOperationException();
2003-12-20 01:19:18 +03:00
}
2004-08-17 13:05:21 +04:00
internal class GhostMethodWrapper : SmartMethodWrapper
2003-05-30 16:08:59 +04:00
{
2004-08-17 13:05:21 +04:00
private MethodInfo ghostMethod;
2004-01-11 16:14:42 +03:00
2004-08-17 13:05:21 +04:00
internal GhostMethodWrapper(TypeWrapper declaringType, MethodDescriptor md, MethodBase method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, MemberFlags flags)
: base(declaringType, md, method, returnType, parameterTypes, modifiers, flags)
2003-07-31 16:49:29 +04:00
{
2004-08-17 13:05:21 +04:00
// make sure we weren't handed the ghostMethod in the wrapper value type
2004-09-05 13:37:58 +04:00
Debug.Assert(method == null || method.DeclaringType.IsInterface);
2003-07-31 16:49:29 +04:00
}
2004-08-17 13:05:21 +04:00
private void ResolveGhostMethod()
2003-07-31 16:49:29 +04:00
{
2004-08-17 13:05:21 +04:00
if(ghostMethod == null)
2004-06-14 14:36:38 +04:00
{
2004-08-17 13:05:21 +04:00
ghostMethod = DeclaringType.TypeAsParameterType.GetMethod(this.Name, this.GetParametersForDefineMethod());
if(ghostMethod == null)
2004-06-14 14:36:38 +04:00
{
2004-08-17 13:05:21 +04:00
throw new InvalidOperationException("Unable to resolve ghost method");
2004-06-14 14:36:38 +04:00
}
}
2003-07-31 16:49:29 +04:00
}
2004-08-17 13:05:21 +04:00
protected override void CallvirtImpl(ILGenerator ilgen)
2003-05-30 16:08:59 +04:00
{
2004-08-17 13:05:21 +04:00
ResolveGhostMethod();
ilgen.Emit(OpCodes.Call, ghostMethod);
2003-05-30 16:08:59 +04:00
}
2004-08-17 13:05:21 +04:00
internal override object Invoke(object obj, object[] args, bool nonVirtual)
2003-05-30 16:08:59 +04:00
{
2004-08-17 13:05:21 +04:00
object wrapper = Activator.CreateInstance(DeclaringType.TypeAsParameterType);
DeclaringType.GhostRefField.SetValue(wrapper, obj);
ResolveGhostMethod();
return InvokeImpl(ghostMethod, wrapper, args, nonVirtual);
2003-05-30 16:08:59 +04:00
}
}
2004-08-17 13:05:21 +04:00
internal static MethodWrapper Create(TypeWrapper declaringType, MethodDescriptor md, MethodBase method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, bool hideFromReflection)
2003-07-31 16:49:29 +04:00
{
2004-08-17 13:05:21 +04:00
Debug.Assert(declaringType != null && md != null && method != null);
2003-07-31 16:49:29 +04:00
2004-08-17 13:05:21 +04:00
if(declaringType.IsGhost)
2003-07-31 16:49:29 +04:00
{
2004-08-17 13:05:21 +04:00
// HACK since our caller isn't aware of the ghost issues, we'll handle the method swapping
if(method.DeclaringType.IsValueType)
2003-07-31 16:49:29 +04:00
{
2004-08-17 13:05:21 +04:00
Type[] types = new Type[parameterTypes.Length];
for(int i = 0; i < types.Length; i++)
{
types[i] = parameterTypes[i].TypeAsParameterType;
}
method = declaringType.TypeAsBaseType.GetMethod(method.Name, types);
2003-07-31 16:49:29 +04:00
}
2004-08-17 13:05:21 +04:00
return new GhostMethodWrapper(declaringType, md, method, returnType, parameterTypes, modifiers, hideFromReflection ? MemberFlags.HideFromReflection : MemberFlags.None);
}
else if(method is ConstructorInfo)
{
return new SmartConstructorMethodWrapper(declaringType, md, (ConstructorInfo)method, parameterTypes, modifiers, hideFromReflection);
}
else
{
return new SmartCallMethodWrapper(declaringType, md, (MethodInfo)method, returnType, parameterTypes, modifiers, hideFromReflection, OpCodes.Call, method.IsStatic ? OpCodes.Call : OpCodes.Callvirt);
2003-07-31 16:49:29 +04:00
}
}
2004-08-17 13:05:21 +04:00
internal MethodWrapper(TypeWrapper declaringType, MethodDescriptor md, MethodBase method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, MemberFlags flags)
: base(declaringType, modifiers, flags)
2003-05-30 16:08:59 +04:00
{
Profiler.Count("MethodWrapper");
this.md = md;
2004-06-14 14:36:38 +04:00
this.method = method;
2004-08-17 13:05:21 +04:00
Debug.Assert(((returnType == null) == (parameterTypes == null)) || (returnType == PrimitiveTypeWrapper.VOID));
this.returnTypeWrapper = returnType;
this.parameterTypeWrappers = parameterTypes;
2003-05-30 16:08:59 +04:00
}
2003-11-17 15:01:50 +03:00
internal void SetDeclaredExceptions(string[] exceptions)
{
if(exceptions == null)
{
exceptions = new string[0];
}
this.declaredExceptions = (string[])exceptions.Clone();
}
2004-09-09 15:17:55 +04:00
internal void SetDeclaredExceptions(IKVM.Internal.MapXml.Throws[] throws)
2003-11-17 15:01:50 +03:00
{
if(throws != null)
{
declaredExceptions = new string[throws.Length];
for(int i = 0; i < throws.Length; i++)
{
declaredExceptions[i] = throws[i].Class;
}
}
}
2003-05-30 16:08:59 +04:00
internal static MethodWrapper FromCookie(IntPtr cookie)
{
return (MethodWrapper)FromCookieImpl(cookie);
}
internal MethodDescriptor Descriptor
{
get
{
return md;
}
}
internal string Name
{
get
{
return md.Name;
}
}
2004-08-17 13:05:21 +04:00
internal string Signature
2003-06-10 17:28:47 +04:00
{
get
{
2004-08-17 13:05:21 +04:00
return md.Signature;
}
}
internal bool IsLinked
{
get
{
return method != null;
}
}
internal void Link()
{
lock(this)
{
if(parameterTypeWrappers == null)
2003-06-10 17:28:47 +04:00
{
2004-08-17 13:05:21 +04:00
Debug.Assert(returnTypeWrapper == null || returnTypeWrapper == PrimitiveTypeWrapper.VOID);
ClassLoaderWrapper loader = this.DeclaringType.GetClassLoader();
string sig = md.Signature;
// TODO we need to use the actual classCache here
System.Collections.Hashtable classCache = new System.Collections.Hashtable();
returnTypeWrapper = ClassFile.RetTypeWrapperFromSig(loader, classCache, sig);
parameterTypeWrappers = ClassFile.ArgTypeWrapperListFromSig(loader, classCache, sig);
if(method == null)
2003-06-10 17:28:47 +04:00
{
2004-08-17 13:05:21 +04:00
try
{
method = this.DeclaringType.LinkMethod(this);
}
catch
{
// HACK if linking fails, we unlink to make sure
// that the next link attempt will fail again
returnTypeWrapper = null;
parameterTypeWrappers = null;
throw;
}
2003-06-10 17:28:47 +04:00
}
}
}
}
2004-08-17 13:05:21 +04:00
[Conditional("DEBUG")]
internal void AssertLinked()
{
if(!(parameterTypeWrappers != null && returnTypeWrapper != null))
{
Tracer.Error(Tracer.Runtime, "AssertLinked failed: " + this.DeclaringType.Name + "::" + this.Name + this.Signature);
}
Debug.Assert(parameterTypeWrappers != null && returnTypeWrapper != null, this.DeclaringType.Name + "::" + this.Name + this.Signature);
}
2003-05-30 16:08:59 +04:00
internal TypeWrapper ReturnType
{
get
{
2004-08-17 13:05:21 +04:00
AssertLinked();
return returnTypeWrapper;
2003-05-30 16:08:59 +04:00
}
}
internal TypeWrapper[] GetParameters()
{
2004-08-17 13:05:21 +04:00
AssertLinked();
return parameterTypeWrappers;
}
internal Type ReturnTypeForDefineMethod
{
get
{
return ReturnType.TypeAsParameterType;
}
}
internal Type[] GetParametersForDefineMethod()
{
TypeWrapper[] wrappers = GetParameters();
Type[] temp = new Type[wrappers.Length];
for(int i = 0; i < wrappers.Length; i++)
{
temp[i] = wrappers[i].TypeAsParameterType;
}
return temp;
2003-05-30 16:08:59 +04:00
}
2003-12-24 14:51:41 +03:00
internal string[] GetExceptions()
2003-11-17 15:01:50 +03:00
{
// remapped types and dynamically compiled types have declaredExceptions set
if(declaredExceptions != null)
{
2003-12-24 14:51:41 +03:00
return (string[])declaredExceptions.Clone();
2003-11-17 15:01:50 +03:00
}
2004-06-14 14:36:38 +04:00
// NOTE if method is a MethodBuilder, GetCustomAttributes doesn't work (and if
// the method had any declared exceptions, the declaredExceptions field would have
// been set)
2004-06-20 12:01:27 +04:00
if(method != null && !(method is MethodBuilder))
2003-11-17 15:01:50 +03:00
{
2004-06-14 14:36:38 +04:00
object[] attributes = method.GetCustomAttributes(typeof(ThrowsAttribute), false);
2004-05-14 13:31:54 +04:00
if(attributes.Length == 1)
2003-11-17 15:01:50 +03:00
{
2004-05-14 13:31:54 +04:00
return ((ThrowsAttribute)attributes[0]).Classes;
2003-11-17 15:01:50 +03:00
}
}
2003-12-24 14:51:41 +03:00
return new string[0];
2003-11-17 15:01:50 +03:00
}
2003-05-30 16:08:59 +04:00
// we expose the underlying MethodBase object,
// for Java types, this is the method that contains the compiled Java bytecode
2004-06-14 14:36:38 +04:00
// for remapped types, this is the mbCore method (not the helper)
2004-06-25 13:38:07 +04:00
// Note that for some artificial methods (notably wrap() in enums), method is null
2003-05-30 16:08:59 +04:00
internal MethodBase GetMethod()
{
2004-08-17 13:05:21 +04:00
AssertLinked();
2004-06-14 14:36:38 +04:00
return method;
2003-05-30 16:08:59 +04:00
}
2003-11-17 15:01:50 +03:00
internal string RealName
{
get
{
2004-08-17 13:05:21 +04:00
AssertLinked();
2004-06-14 14:36:38 +04:00
return method.Name;
2003-11-17 15:01:50 +03:00
}
}
2003-05-30 16:08:59 +04:00
// this returns the Java method's attributes in .NET terms (e.g. used to create stubs for this method)
internal MethodAttributes GetMethodAttributes()
{
MethodAttributes attribs = 0;
if(IsStatic)
{
attribs |= MethodAttributes.Static;
}
if(IsPublic)
{
attribs |= MethodAttributes.Public;
}
else if(IsPrivate)
{
attribs |= MethodAttributes.Private;
}
else if(IsProtected)
{
attribs |= MethodAttributes.FamORAssem;
}
else
{
attribs |= MethodAttributes.Family;
}
// constructors aren't virtual
if(!IsStatic && !IsPrivate && md.Name != "<init>")
{
attribs |= MethodAttributes.Virtual;
}
if(IsFinal)
{
attribs |= MethodAttributes.Final;
}
if(IsAbstract)
{
attribs |= MethodAttributes.Abstract;
}
return attribs;
}
internal bool IsAbstract
{
get
{
return (Modifiers & Modifiers.Abstract) != 0;
}
}
2004-11-29 12:48:01 +03:00
[HideFromJava]
2003-08-26 15:24:17 +04:00
internal virtual object Invoke(object obj, object[] args, bool nonVirtual)
2003-05-30 16:08:59 +04:00
{
2004-08-17 13:05:21 +04:00
AssertLinked();
2004-06-14 14:36:38 +04:00
// if we've still got the builder object, we need to replace it with the real thing before we can call it
if(method is MethodBuilder)
2003-05-30 16:08:59 +04:00
{
2004-06-14 14:36:38 +04:00
bool found = false;
int token = ((MethodBuilder)method).GetToken().Token;
ModuleBuilder module = (ModuleBuilder)((MethodBuilder)method).GetModule();
foreach(MethodInfo mi in this.DeclaringType.TypeAsTBD.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
{
if(module.GetMethodToken(mi).Token == token)
{
found = true;
method = mi;
break;
}
}
if(!found)
2003-05-30 16:08:59 +04:00
{
2004-08-17 13:05:21 +04:00
throw new InvalidOperationException("Failed to fixate method: " + this.DeclaringType.Name + "." + this.Name + this.Signature);
2003-05-30 16:08:59 +04:00
}
2004-06-14 14:36:38 +04:00
}
if(method is ConstructorBuilder)
{
bool found = false;
int token = ((ConstructorBuilder)method).GetToken().Token;
ModuleBuilder module = (ModuleBuilder)((ConstructorBuilder)method).GetModule();
foreach(ConstructorInfo ci in this.DeclaringType.TypeAsTBD.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
2003-05-30 16:08:59 +04:00
{
2004-06-14 14:36:38 +04:00
if(module.GetConstructorToken(ci).Token == token)
{
found = true;
method = ci;
break;
}
2003-05-30 16:08:59 +04:00
}
2004-06-14 14:36:38 +04:00
if(!found)
2003-05-30 16:08:59 +04:00
{
2004-08-17 13:05:21 +04:00
throw new InvalidOperationException("Failed to fixate constructor: " + this.DeclaringType.Name + "." + this.Name + this.Signature);
2003-05-30 16:08:59 +04:00
}
}
2004-06-14 14:36:38 +04:00
return InvokeImpl(method, obj, args, nonVirtual);
}
2004-08-17 13:05:21 +04:00
private delegate object Invoker(IntPtr pFunc, object obj, object[] args);
2004-11-29 12:48:01 +03:00
[HideFromJava]
2004-06-14 14:36:38 +04:00
internal object InvokeImpl(MethodBase method, object obj, object[] args, bool nonVirtual)
{
Debug.Assert(!(method is MethodBuilder || method is ConstructorBuilder));
if(IsStatic)
{
// Java allows bogus 'obj' to be specified for static methods
obj = null;
}
2003-05-30 16:08:59 +04:00
else
{
if(md.Name == "<init>")
{
2004-06-14 14:36:38 +04:00
if(method is MethodInfo)
2003-05-30 16:08:59 +04:00
{
2004-06-14 14:36:38 +04:00
Debug.Assert(method.IsStatic);
// we're dealing with a constructor on a remapped type, if obj is supplied, it means
// that we should call the constructor on an already existing instance, but that isn't
// possible with remapped types
2004-01-11 16:14:42 +03:00
if(obj != null)
2003-05-30 16:08:59 +04:00
{
2004-06-14 14:36:38 +04:00
// the type of this exception is a bit random (note that this can only happen through JNI reflection or
// if there is a bug in serialization [which uses the ObjectInputStream.callConstructor() in classpath.cs)
throw JavaException.IncompatibleClassChangeError("Remapped type {0} doesn't support constructor invocation on an existing instance", DeclaringType.Name);
2003-05-30 16:08:59 +04:00
}
}
2004-06-14 14:36:38 +04:00
else if(obj == null)
2004-01-11 16:14:42 +03:00
{
2004-06-14 14:36:38 +04:00
// calling <init> without an instance means that we're constructing a new instance
// NOTE this means that we cannot detect a NullPointerException when calling <init> (does JNI require this?)
try
{
InvokeArgsProcessor proc = new InvokeArgsProcessor(this, method, null, args);
object o = ((ConstructorInfo)method).Invoke(proc.GetArgs());
// since we just constructed an instance, it can't possibly be a ghost
return o;
}
catch(ArgumentException x1)
{
throw JavaException.IllegalArgumentException(x1.Message);
}
catch(TargetInvocationException x)
{
2004-11-29 16:58:21 +03:00
throw JavaException.InvocationTargetException(IKVM.Runtime.Util.MapException(x.InnerException));
2004-06-14 14:36:38 +04:00
}
2003-05-30 16:08:59 +04:00
}
2004-06-17 13:14:51 +04:00
else if(!method.DeclaringType.IsInstanceOfType(obj))
{
// we're trying to initialize an existing instance of a remapped type
if(obj is System.Exception && (args == null || args.Length == 0))
{
2004-06-17 16:01:54 +04:00
// HACK special case for deserialization of java.lang.Throwable subclasses
// we don't call the constructor here, it will be called by Throwable.readObject()
return null;
2004-06-17 13:14:51 +04:00
}
else
{
// NOTE this will also happen if you try to deserialize a .NET object
// (i.e. a type that doesn't derive from our java.lang.Object).
// We might want to support that in the future (it's fairly easy, because
// the call to Object.<init> can just be ignored)
throw new NotSupportedException("Unable to partially construct object of type " + obj.GetType().FullName + " to type " + method.DeclaringType.FullName);
}
}
2003-05-30 16:08:59 +04:00
}
2004-06-14 14:36:38 +04:00
else if(nonVirtual && !method.IsStatic)
2003-05-30 16:08:59 +04:00
{
2004-08-17 13:05:21 +04:00
Invoker invoker = NonvirtualInvokeHelper.GetInvoker(this);
try
{
InvokeArgsProcessor proc = new InvokeArgsProcessor(this, method, obj, args);
return invoker(method.MethodHandle.GetFunctionPointer(), proc.GetObj(), proc.GetArgs());
}
catch(ArgumentException x1)
{
throw JavaException.IllegalArgumentException(x1.Message);
}
catch(TargetInvocationException x)
{
2004-11-29 16:58:21 +03:00
throw JavaException.InvocationTargetException(IKVM.Runtime.Util.MapException(x.InnerException));
2004-08-17 13:05:21 +04:00
}
2003-05-30 16:08:59 +04:00
}
2004-06-14 14:36:38 +04:00
}
try
{
InvokeArgsProcessor proc = new InvokeArgsProcessor(this, method, obj, args);
object o = method.Invoke(proc.GetObj(), proc.GetArgs());
2004-08-17 13:05:21 +04:00
TypeWrapper retType = this.ReturnType;
2004-06-14 14:36:38 +04:00
if(!retType.IsUnloadable && retType.IsGhost)
2003-05-30 16:08:59 +04:00
{
2004-08-17 13:05:21 +04:00
o = retType.GhostRefField.GetValue(o);
2004-06-14 14:36:38 +04:00
}
return o;
}
catch(ArgumentException x1)
{
throw JavaException.IllegalArgumentException(x1.Message);
}
catch(TargetInvocationException x)
{
2004-11-29 16:58:21 +03:00
throw JavaException.InvocationTargetException(IKVM.Runtime.Util.MapException(x.InnerException));
2004-06-14 14:36:38 +04:00
}
}
2004-08-17 13:05:21 +04:00
private class NonvirtualInvokeHelper
{
private static Hashtable cache;
private static ModuleBuilder module;
private class KeyGen : IHashCodeProvider, IComparer
{
public int GetHashCode(object o)
{
MethodWrapper mw = (MethodWrapper)o;
return mw.Signature.GetHashCode();
}
public int Compare(object x, object y)
{
MethodWrapper mw1 = (MethodWrapper)x;
MethodWrapper mw2 = (MethodWrapper)y;
if(mw1.ReturnType == mw2.ReturnType)
{
TypeWrapper[] p1 = mw1.GetParameters();
TypeWrapper[] p2 = mw2.GetParameters();
if(p1.Length == p2.Length)
{
for(int i = 0; i < p1.Length; i++)
{
if(p1[i] != p2[i])
{
return 1;
}
}
return 0;
}
}
return 1;
}
}
static NonvirtualInvokeHelper()
{
KeyGen keygen = new KeyGen();
cache = new Hashtable(keygen, keygen);
AssemblyName name = new AssemblyName();
name.Name = "NonvirtualInvoker";
2004-09-05 13:37:58 +04:00
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(name, ClassLoaderWrapper.IsSaveDebugImage ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run);
if(ClassLoaderWrapper.IsSaveDebugImage)
{
module = ab.DefineDynamicModule("NonvirtualInvoker", "NonvirtualInvoker.dll");
ClassLoaderWrapper.RegisterForSaveDebug(ab);
}
else
{
module = ab.DefineDynamicModule("NonvirtualInvoker");
}
2004-08-17 13:05:21 +04:00
}
internal static Invoker GetInvoker(MethodWrapper mw)
{
lock(cache.SyncRoot)
{
Invoker inv = (Invoker)cache[mw];
if(inv == null)
{
inv = CreateInvoker(mw);
cache[mw] = inv;
}
return inv;
}
}
private static Invoker CreateInvoker(MethodWrapper mw)
{
// TODO we need to support byref arguments...
TypeBuilder typeBuilder = module.DefineType("class" + cache.Count);
MethodBuilder methodBuilder = typeBuilder.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.Static, typeof(object), new Type[] { typeof(IntPtr), typeof(object), typeof(object[]) });
ILGenerator ilgen = methodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_1);
TypeWrapper[] paramTypes = mw.GetParameters();
for(int i = 0; i < paramTypes.Length; i++)
{
ilgen.Emit(OpCodes.Ldarg_2);
ilgen.Emit(OpCodes.Ldc_I4, i);
ilgen.Emit(OpCodes.Ldelem_Ref);
if(paramTypes[i].IsUnloadable)
{
// no need to do anything
}
else if(paramTypes[i].IsPrimitive)
{
ilgen.Emit(OpCodes.Unbox, paramTypes[i].TypeAsTBD);
ilgen.Emit(OpCodes.Ldobj, paramTypes[i].TypeAsTBD);
}
else if(paramTypes[i].IsNonPrimitiveValueType)
{
paramTypes[i].EmitUnbox(ilgen);
}
}
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.EmitCalli(OpCodes.Calli, CallingConventions.HasThis, mw.ReturnTypeForDefineMethod, mw.GetParametersForDefineMethod(), null);
if(mw.ReturnType.IsUnloadable)
{
// no need to do anything
}
else if(mw.ReturnType == PrimitiveTypeWrapper.VOID)
{
ilgen.Emit(OpCodes.Ldnull);
}
else if(mw.ReturnType.IsGhost)
{
mw.ReturnType.EmitConvParameterToStackType(ilgen);
}
else if(mw.ReturnType.IsPrimitive)
{
ilgen.Emit(OpCodes.Box, mw.ReturnType.TypeAsTBD);
}
ilgen.Emit(OpCodes.Ret);
Type type = typeBuilder.CreateType();
return (Invoker)Delegate.CreateDelegate(typeof(Invoker), type.GetMethod("Invoke"));
}
}
2004-06-14 14:36:38 +04:00
private struct InvokeArgsProcessor
{
private object obj;
private object[] args;
internal InvokeArgsProcessor(MethodWrapper mw, MethodBase method, object original_obj, object[] original_args)
{
2004-08-17 13:05:21 +04:00
TypeWrapper[] argTypes = mw.GetParameters();
2004-06-14 14:36:38 +04:00
if(!mw.IsStatic && method.IsStatic && mw.md.Name != "<init>")
{
// we've been redirected to a static method, so we have to copy the 'obj' into the args
args = new object[original_args.Length + 1];
args[0] = original_obj;
original_args.CopyTo(args, 1);
this.obj = null;
this.args = args;
for(int i = 0; i < argTypes.Length; i++)
2003-05-30 16:08:59 +04:00
{
2004-06-14 14:36:38 +04:00
if(!argTypes[i].IsUnloadable && argTypes[i].IsGhost)
{
object v = Activator.CreateInstance(argTypes[i].TypeAsParameterType);
argTypes[i].GhostRefField.SetValue(v, args[i + 1]);
args[i + 1] = v;
}
2003-05-30 16:08:59 +04:00
}
}
else
{
2004-06-14 14:36:38 +04:00
this.obj = original_obj;
this.args = original_args;
for(int i = 0; i < argTypes.Length; i++)
2003-05-30 16:08:59 +04:00
{
2004-06-14 14:36:38 +04:00
if(!argTypes[i].IsUnloadable && argTypes[i].IsGhost)
{
if(this.args == original_args)
{
this.args = (object[])args.Clone();
}
object v = Activator.CreateInstance(argTypes[i].TypeAsParameterType);
argTypes[i].GhostRefField.SetValue(v, args[i]);
this.args[i] = v;
}
2003-05-30 16:08:59 +04:00
}
}
2004-06-14 14:36:38 +04:00
}
internal object GetObj()
{
return obj;
}
internal object[] GetArgs()
{
return args;
2003-05-30 16:08:59 +04:00
}
}
}
2004-08-17 13:05:21 +04:00
class SmartMethodWrapper : MethodWrapper
{
internal SmartMethodWrapper(TypeWrapper declaringType, MethodDescriptor md, MethodBase method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, MemberFlags flags)
: base(declaringType, md, method, returnType, parameterTypes, modifiers, flags)
{
}
protected virtual void PreEmit(ILGenerator ilgen)
{
}
protected void PostEmit(ILGenerator ilgen)
{
TypeWrapper retType = this.ReturnType;
if(!retType.IsUnloadable)
{
if(retType.IsNonPrimitiveValueType)
{
retType.EmitBox(ilgen);
}
else if(retType.IsGhost)
{
LocalBuilder local = ilgen.DeclareLocal(retType.TypeAsParameterType);
ilgen.Emit(OpCodes.Stloc, local);
ilgen.Emit(OpCodes.Ldloca, local);
ilgen.Emit(OpCodes.Ldfld, retType.GhostRefField);
}
}
}
internal sealed override void EmitCall(ILGenerator ilgen)
{
AssertLinked();
PreEmit(ilgen);
CallImpl(ilgen);
PostEmit(ilgen);
}
protected virtual void CallImpl(ILGenerator ilgen)
{
throw new InvalidOperationException();
}
internal sealed override void EmitCallvirt(ILGenerator ilgen)
{
AssertLinked();
PreEmit(ilgen);
if(DeclaringType.IsNonPrimitiveValueType)
{
// callvirt isn't allowed on a value type
CallImpl(ilgen);
}
else
{
CallvirtImpl(ilgen);
}
PostEmit(ilgen);
}
protected virtual void CallvirtImpl(ILGenerator ilgen)
{
throw new InvalidOperationException();
}
internal sealed override void EmitNewobj(ILGenerator ilgen)
{
AssertLinked();
PreEmit(ilgen);
NewobjImpl(ilgen);
if(DeclaringType.IsNonPrimitiveValueType)
{
// HACK after constructing a new object, we don't want the custom boxing rule to run
// (because that would turn "new IntPtr" into a null reference)
ilgen.Emit(OpCodes.Box, DeclaringType.TypeAsTBD);
}
}
protected virtual void NewobjImpl(ILGenerator ilgen)
{
throw new InvalidOperationException();
}
}
sealed class SimpleCallMethodWrapper : MethodWrapper
{
private OpCode call;
private OpCode callvirt;
internal SimpleCallMethodWrapper(TypeWrapper declaringType, MethodDescriptor md, MethodInfo method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, bool hideFromReflection, OpCode call, OpCode callvirt)
: base(declaringType, md, method, returnType, parameterTypes, modifiers, hideFromReflection ? MemberFlags.HideFromReflection : MemberFlags.None)
{
this.call = call;
this.callvirt = callvirt;
}
internal override void EmitCall(ILGenerator ilgen)
{
ilgen.Emit(call, (MethodInfo)GetMethod());
}
internal override void EmitCallvirt(ILGenerator ilgen)
{
ilgen.Emit(callvirt, (MethodInfo)GetMethod());
}
}
sealed class SmartCallMethodWrapper : SmartMethodWrapper
{
private OpCode call;
private OpCode callvirt;
internal SmartCallMethodWrapper(TypeWrapper declaringType, MethodDescriptor md, MethodInfo method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, bool hideFromReflection, OpCode call, OpCode callvirt)
: this(declaringType, md, method, returnType, parameterTypes, modifiers, hideFromReflection ? MemberFlags.HideFromReflection : MemberFlags.None, call, callvirt)
{
}
internal SmartCallMethodWrapper(TypeWrapper declaringType, MethodDescriptor md, MethodInfo method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, MemberFlags flags, OpCode call, OpCode callvirt)
: base(declaringType, md, method, returnType, parameterTypes, modifiers, flags)
{
this.call = call;
this.callvirt = callvirt;
}
protected override void CallImpl(ILGenerator ilgen)
{
ilgen.Emit(call, (MethodInfo)GetMethod());
}
protected override void CallvirtImpl(ILGenerator ilgen)
{
ilgen.Emit(callvirt, (MethodInfo)GetMethod());
}
}
sealed class SmartConstructorMethodWrapper : SmartMethodWrapper
{
internal SmartConstructorMethodWrapper(TypeWrapper declaringType, MethodDescriptor md, ConstructorInfo method, TypeWrapper[] parameterTypes, Modifiers modifiers, MemberFlags flags)
: base(declaringType, md, method, PrimitiveTypeWrapper.VOID, parameterTypes, modifiers, flags)
{
}
internal SmartConstructorMethodWrapper(TypeWrapper declaringType, MethodDescriptor md, ConstructorInfo method, TypeWrapper[] parameterTypes, Modifiers modifiers, bool hideFromReflection)
: base(declaringType, md, method, PrimitiveTypeWrapper.VOID, parameterTypes, modifiers, hideFromReflection ? MemberFlags.HideFromReflection : MemberFlags.None)
{
}
protected override void CallImpl(ILGenerator ilgen)
{
ilgen.Emit(OpCodes.Call, (ConstructorInfo)GetMethod());
}
protected override void NewobjImpl(ILGenerator ilgen)
{
ilgen.Emit(OpCodes.Newobj, (ConstructorInfo)GetMethod());
}
}
2003-12-20 01:19:18 +03:00
// This class tests if reflection on a constant field triggers the class constructor to run
// (it shouldn't run, but on .NET 1.0 & 1.1 it does)
2004-08-17 13:05:21 +04:00
sealed class ReflectionOnConstant
2003-12-20 01:19:18 +03:00
{
private static bool isBroken;
2003-12-24 14:51:41 +03:00
private static System.Collections.Hashtable warnOnce;
2003-12-20 01:19:18 +03:00
static ReflectionOnConstant()
{
typeof(Helper).GetField("foo", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
}
internal static bool IsBroken
{
get
{
return isBroken;
}
}
2003-12-24 14:51:41 +03:00
internal static void IssueWarning(FieldInfo field)
{
2004-03-08 18:18:47 +03:00
// FXBUG .NET (1.0 & 1.1)
// FieldInfo.GetValue() on a literal causes the type initializer to run and
2003-12-24 14:51:41 +03:00
// we don't want that.
// TODO may need to find a workaround, for now we just spit out a warning
if(ReflectionOnConstant.IsBroken && field.DeclaringType.TypeInitializer != null)
{
2004-03-08 18:18:47 +03:00
if(Tracer.FxBug.TraceWarning)
2003-12-24 14:51:41 +03:00
{
if(warnOnce == null)
{
warnOnce = new System.Collections.Hashtable();
}
if(!warnOnce.ContainsKey(field.DeclaringType.FullName))
{
warnOnce.Add(field.DeclaringType.FullName, null);
2004-03-08 18:18:47 +03:00
Tracer.Warning(Tracer.FxBug, "Running type initializer for {0} due to CLR bug", field.DeclaringType.FullName);
2003-12-24 14:51:41 +03:00
}
}
}
}
2003-12-20 01:19:18 +03:00
private class Helper
{
internal const int foo = 1;
static Helper()
{
isBroken = true;
}
}
}
2004-10-04 23:30:53 +04:00
abstract class FieldWrapper : MemberWrapper
2003-05-30 16:08:59 +04:00
{
private string name;
private string sig;
private FieldInfo field;
2003-06-10 17:28:47 +04:00
private TypeWrapper fieldType;
2003-05-30 16:08:59 +04:00
2004-10-04 23:30:53 +04:00
internal FieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, string name, string sig, Modifiers modifiers, FieldInfo field)
2003-05-30 16:08:59 +04:00
: base(declaringType, modifiers, false)
{
2003-07-07 18:18:27 +04:00
Debug.Assert(fieldType != null);
Debug.Assert(name != null);
Debug.Assert(sig != null);
2003-05-30 16:08:59 +04:00
this.name = name;
this.sig = sig;
2003-06-10 17:28:47 +04:00
this.fieldType = fieldType;
2003-08-21 14:06:34 +04:00
this.field = field;
2004-10-04 23:30:53 +04:00
}
internal FieldInfo GetField()
{
AssertLinked();
return field;
2004-08-17 13:05:21 +04:00
}
[Conditional("DEBUG")]
internal void AssertLinked()
{
if(fieldType == null)
{
Tracer.Error(Tracer.Runtime, "AssertLinked failed: " + this.DeclaringType.Name + "::" + this.name + " (" + this.sig + ")");
}
Debug.Assert(fieldType != null, this.DeclaringType.Name + "::" + this.name + " (" + this.sig+ ")");
2003-05-30 16:08:59 +04:00
}
2004-11-16 14:11:53 +03:00
// HACK used (thru IKVM.Runtime.Util.GetFieldConstantValue) by ikvmstub to find out if the
2004-03-16 20:10:09 +03:00
// field is a constant (and if it is, to get its value)
2003-08-21 14:06:34 +04:00
internal object GetConstant()
{
2004-08-17 13:05:21 +04:00
AssertLinked();
2003-08-21 14:06:34 +04:00
// NOTE only pritimives and string can be literals in Java (because the other "primitives" (like uint),
// are treated as NonPrimitiveValueTypes)
2004-11-16 14:11:53 +03:00
if(field != null && (fieldType.IsPrimitive || fieldType == CoreClasses.java.lang.String.Wrapper))
2003-08-21 14:06:34 +04:00
{
2004-11-16 14:11:53 +03:00
object val = null;
if(field.IsLiteral)
{
ReflectionOnConstant.IssueWarning(field);
val = field.GetValue(null);
}
else
{
// In Java, instance fields can also have a ConstantValue attribute so we emulate that
// with ConstantValueAttribute (for consumption by ikvmstub only)
object[] attrib = field.GetCustomAttributes(typeof(ConstantValueAttribute), false);
if(attrib.Length == 1)
{
val = ((ConstantValueAttribute)attrib[0]).GetConstantValue();
}
}
2003-08-21 14:06:34 +04:00
if(val != null && !(val is string))
{
2004-11-29 16:58:21 +03:00
return JVM.Library.box(val);
2003-08-21 14:06:34 +04:00
}
return val;
}
return null;
}
2003-05-30 16:08:59 +04:00
internal static FieldWrapper FromCookie(IntPtr cookie)
{
return (FieldWrapper)FromCookieImpl(cookie);
}
internal string Name
{
get
{
return name;
}
}
internal TypeWrapper FieldTypeWrapper
{
get
{
2004-08-17 13:05:21 +04:00
AssertLinked();
2003-06-10 17:28:47 +04:00
return fieldType;
2003-05-30 16:08:59 +04:00
}
}
2004-08-17 13:05:21 +04:00
internal void EmitGet(ILGenerator ilgen)
{
AssertLinked();
EmitGetImpl(ilgen);
}
2004-10-04 23:30:53 +04:00
protected abstract void EmitGetImpl(ILGenerator ilgen);
2004-08-17 13:05:21 +04:00
internal void EmitSet(ILGenerator ilgen)
{
AssertLinked();
EmitSetImpl(ilgen);
}
2004-10-04 23:30:53 +04:00
protected abstract void EmitSetImpl(ILGenerator ilgen);
2004-08-17 13:05:21 +04:00
internal void Link()
{
lock(this)
{
if(fieldType == null)
{
// TODO we need to use the actual classCache here
System.Collections.Hashtable classCache = new System.Collections.Hashtable();
fieldType = ClassFile.FieldTypeWrapperFromSig(this.DeclaringType.GetClassLoader(), classCache, sig);
try
{
this.DeclaringType.LinkField(this);
}
catch
{
// HACK if linking fails, we unlink to make sure
// that the next link attempt will fail again
fieldType = null;
2004-08-30 19:56:23 +04:00
throw;
2004-08-17 13:05:21 +04:00
}
}
}
}
2003-05-30 16:08:59 +04:00
internal bool IsVolatile
{
get
{
return (Modifiers & Modifiers.Volatile) != 0;
}
}
2004-10-04 23:30:53 +04:00
internal static FieldWrapper Create(TypeWrapper declaringType, TypeWrapper fieldType, FieldInfo fi, string name, string sig, Modifiers modifiers)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
if(fieldType.IsUnloadable)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
// TODO we might need to emit code to check the type dynamically
// TODO the fact that the type is unloadable now, doesn't mean it will be unloadable when a method
// that accesses this field is compiled, that means that that method may need to emit a cast
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
else
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
if(fieldType.IsGhost)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
return new GhostFieldWrapper(declaringType, fieldType, fi, name, sig, modifiers);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
if((modifiers & Modifiers.Volatile) != 0)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
// long & double field accesses must be made atomic
if(fi.FieldType == typeof(long) || fi.FieldType == typeof(double))
{
return new VolatileLongDoubleFieldWrapper(declaringType, fieldType, fi, name, sig, modifiers);
}
2003-05-30 16:08:59 +04:00
}
}
2004-10-04 23:30:53 +04:00
if(declaringType.IsNonPrimitiveValueType)
{
return new NonPrimitiveValueTypeFieldWrapper(declaringType, fieldType, fi, name, sig, modifiers);
}
else
{
return new SimpleFieldWrapper(declaringType, fieldType, fi, name, sig, modifiers);
}
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
private void LookupField()
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
BindingFlags bindings = BindingFlags.Public | BindingFlags.NonPublic;
if(IsStatic)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
bindings |= BindingFlags.Static;
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
else
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
bindings |= BindingFlags.Instance;
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
// TODO instead of looking up the field by name, we should use the Token to find it.
field = DeclaringType.TypeAsTBD.GetField(name, bindings);
Debug.Assert(field != null);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
internal virtual void SetValue(object obj, object val)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
AssertLinked();
// TODO this is a broken implementation (for one thing, it needs to support redirection)
if(field == null || field is FieldBuilder)
{
LookupField();
}
if(fieldType.IsGhost)
{
object temp = field.GetValue(obj);
fieldType.GhostRefField.SetValue(temp, val);
val = temp;
}
try
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
field.SetValue(obj, val);
}
catch(FieldAccessException x)
{
throw JavaException.IllegalAccessException(x.Message);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
}
2003-05-30 16:08:59 +04:00
2004-10-04 23:30:53 +04:00
internal virtual object GetValue(object obj)
{
AssertLinked();
// TODO this is a broken implementation (for one thing, it needs to support redirection)
if(field == null || field is FieldBuilder)
{
LookupField();
}
if(field.IsLiteral)
{
// on a non-broken CLR GetValue on a literal will not trigger type initialization, but on Java it should
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(field.DeclaringType.TypeHandle);
}
object val = field.GetValue(obj);
if(fieldType.IsGhost)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
val = fieldType.GhostRefField.GetValue(val);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
return val;
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
}
2003-05-30 16:08:59 +04:00
2004-10-04 23:30:53 +04:00
sealed class SimpleFieldWrapper : FieldWrapper
{
internal SimpleFieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, FieldInfo fi, string name, string sig, Modifiers modifiers)
: base(declaringType, fieldType, name, sig, modifiers, fi)
2003-10-17 12:08:31 +04:00
{
2004-10-04 23:30:53 +04:00
Debug.Assert(!declaringType.IsNonPrimitiveValueType);
Debug.Assert(!fieldType.IsGhost);
Debug.Assert(fieldType != PrimitiveTypeWrapper.DOUBLE || fieldType != PrimitiveTypeWrapper.LONG || !IsVolatile);
}
2003-10-17 12:08:31 +04:00
2004-10-04 23:30:53 +04:00
protected override void EmitGetImpl(ILGenerator ilgen)
{
if(IsVolatile)
{
ilgen.Emit(OpCodes.Volatile);
}
ilgen.Emit(IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, GetField());
2004-10-05 18:02:44 +04:00
if(!FieldTypeWrapper.IsUnloadable && FieldTypeWrapper.IsNonPrimitiveValueType)
2003-10-17 12:08:31 +04:00
{
2004-10-04 23:30:53 +04:00
FieldTypeWrapper.EmitBox(ilgen);
2003-10-17 12:08:31 +04:00
}
2004-10-04 23:30:53 +04:00
}
2003-10-17 12:08:31 +04:00
2004-10-04 23:30:53 +04:00
protected override void EmitSetImpl(ILGenerator ilgen)
{
2004-10-05 18:02:44 +04:00
if(!FieldTypeWrapper.IsUnloadable && FieldTypeWrapper.IsNonPrimitiveValueType)
2004-10-04 23:30:53 +04:00
{
FieldTypeWrapper.EmitUnbox(ilgen);
}
if(IsVolatile)
2003-10-17 12:08:31 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Volatile);
2003-10-17 12:08:31 +04:00
}
2004-10-04 23:30:53 +04:00
ilgen.Emit(IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, GetField());
2003-10-17 12:08:31 +04:00
}
2004-10-04 23:30:53 +04:00
}
sealed class VolatileLongDoubleFieldWrapper : FieldWrapper
{
private static MethodInfo volatileReadDouble = typeof(System.Threading.Thread).GetMethod("VolatileRead", new Type[] { Type.GetType("System.Double&") });
private static MethodInfo volatileReadLong = typeof(System.Threading.Thread).GetMethod("VolatileRead", new Type[] { Type.GetType("System.Int64&") });
private static MethodInfo volatileWriteDouble = typeof(System.Threading.Thread).GetMethod("VolatileWrite", new Type[] { Type.GetType("System.Double&"), typeof(double) });
private static MethodInfo volatileWriteLong = typeof(System.Threading.Thread).GetMethod("VolatileWrite", new Type[] { Type.GetType("System.Int64&"), typeof(long) });
2003-10-17 12:08:31 +04:00
2004-10-04 23:30:53 +04:00
internal VolatileLongDoubleFieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, FieldInfo fi, string name, string sig, Modifiers modifiers)
: base(declaringType, fieldType, name, sig, modifiers, fi)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
Debug.Assert(IsVolatile);
Debug.Assert(fieldType == PrimitiveTypeWrapper.DOUBLE || fieldType == PrimitiveTypeWrapper.LONG);
2003-06-10 17:28:47 +04:00
}
2004-10-04 23:30:53 +04:00
protected override void EmitGetImpl(ILGenerator ilgen)
2003-06-10 17:28:47 +04:00
{
2004-10-04 23:30:53 +04:00
FieldInfo fi = GetField();
if(fi.IsStatic)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Ldsflda, fi);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
else
2003-06-10 17:28:47 +04:00
{
2004-10-04 23:30:53 +04:00
if(DeclaringType.IsNonPrimitiveValueType)
2003-12-24 14:51:41 +03:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
2003-12-24 14:51:41 +03:00
}
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Ldflda, fi);
2003-06-10 17:28:47 +04:00
}
2004-10-04 23:30:53 +04:00
if(fi.FieldType == typeof(double))
2003-10-17 12:08:31 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Call, volatileReadDouble);
2003-10-17 12:08:31 +04:00
}
2004-10-04 23:30:53 +04:00
else
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
Debug.Assert(fi.FieldType == typeof(long));
ilgen.Emit(OpCodes.Call, volatileReadLong);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
}
protected override void EmitSetImpl(ILGenerator ilgen)
{
FieldInfo fi = GetField();
LocalBuilder temp = ilgen.DeclareLocal(fi.FieldType);
ilgen.Emit(OpCodes.Stloc, temp);
if(fi.IsStatic)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Ldsflda, fi);
}
else
{
if(DeclaringType.IsNonPrimitiveValueType)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Ldflda, fi);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Ldloc, temp);
if(fi.FieldType == typeof(double))
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Call, volatileWriteDouble);
2003-05-30 16:08:59 +04:00
}
else
{
2004-10-04 23:30:53 +04:00
Debug.Assert(fi.FieldType == typeof(long));
ilgen.Emit(OpCodes.Call, volatileWriteLong);
2003-05-30 16:08:59 +04:00
}
}
2004-10-04 23:30:53 +04:00
}
2003-05-30 16:08:59 +04:00
2004-10-04 23:30:53 +04:00
sealed class GhostFieldWrapper : FieldWrapper
{
internal GhostFieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, FieldInfo fi, string name, string sig, Modifiers modifiers)
: base(declaringType, fieldType, name, sig, modifiers, fi)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
Debug.Assert(fieldType.IsGhost);
}
protected override void EmitGetImpl(ILGenerator ilgen)
{
FieldInfo fi = GetField();
if(fi.IsStatic)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Ldsflda, fi);
2003-05-30 16:08:59 +04:00
}
else
{
2004-10-04 23:30:53 +04:00
if(DeclaringType.IsNonPrimitiveValueType)
{
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
}
ilgen.Emit(OpCodes.Ldflda, fi);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
if(IsVolatile)
{
ilgen.Emit(OpCodes.Volatile);
}
ilgen.Emit(OpCodes.Ldfld, FieldTypeWrapper.GhostRefField);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
protected override void EmitSetImpl(ILGenerator ilgen)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
FieldInfo fi = GetField();
LocalBuilder temp = ilgen.DeclareLocal(FieldTypeWrapper.TypeAsLocalOrStackType);
ilgen.Emit(OpCodes.Stloc, temp);
if(fi.IsStatic)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Ldsflda, fi);
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
else
2003-10-17 12:08:31 +04:00
{
2004-10-04 23:30:53 +04:00
if(DeclaringType.IsNonPrimitiveValueType)
{
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
}
ilgen.Emit(OpCodes.Ldflda, fi);
2003-10-17 12:08:31 +04:00
}
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Ldloc, temp);
if(IsVolatile)
2003-12-24 14:51:41 +03:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Volatile);
2003-12-24 14:51:41 +03:00
}
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Stfld, FieldTypeWrapper.GhostRefField);
}
}
sealed class NonPrimitiveValueTypeFieldWrapper : FieldWrapper
{
internal NonPrimitiveValueTypeFieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, FieldInfo fi, string name, string sig, Modifiers modifiers)
: base(declaringType, fieldType, name, sig, modifiers, fi)
{
Debug.Assert(declaringType.IsNonPrimitiveValueType);
Debug.Assert(!fieldType.IsGhost);
Debug.Assert(fieldType != PrimitiveTypeWrapper.DOUBLE || fieldType != PrimitiveTypeWrapper.LONG || !IsVolatile);
}
protected override void EmitGetImpl(ILGenerator ilgen)
{
if(!IsStatic)
2003-12-24 14:51:41 +03:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
}
if(IsVolatile)
{
ilgen.Emit(OpCodes.Volatile);
}
ilgen.Emit(IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, GetField());
2004-10-05 18:02:44 +04:00
if(!FieldTypeWrapper.IsUnloadable && FieldTypeWrapper.IsNonPrimitiveValueType)
2004-10-04 23:30:53 +04:00
{
FieldTypeWrapper.EmitBox(ilgen);
2003-12-24 14:51:41 +03:00
}
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
protected override void EmitSetImpl(ILGenerator ilgen)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
if(!IsStatic)
2003-05-30 16:08:59 +04:00
{
2004-10-04 23:30:53 +04:00
FieldInfo fi = GetField();
LocalBuilder temp = ilgen.DeclareLocal(FieldTypeWrapper.TypeAsLocalOrStackType);
ilgen.Emit(OpCodes.Stloc, temp);
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
ilgen.Emit(OpCodes.Ldloc, temp);
2003-05-30 16:08:59 +04:00
}
2004-10-05 18:02:44 +04:00
if(!FieldTypeWrapper.IsUnloadable && FieldTypeWrapper.IsNonPrimitiveValueType)
2003-12-24 14:51:41 +03:00
{
2004-10-04 23:30:53 +04:00
FieldTypeWrapper.EmitUnbox(ilgen);
2003-12-24 14:51:41 +03:00
}
2004-10-04 23:30:53 +04:00
if(IsVolatile)
2003-10-17 12:08:31 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Volatile);
2003-10-17 12:08:31 +04:00
}
2004-10-04 23:30:53 +04:00
ilgen.Emit(IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, GetField());
2003-05-30 16:08:59 +04:00
}
2004-10-04 23:30:53 +04:00
}
2003-11-17 15:01:50 +03:00
2004-10-04 23:30:53 +04:00
sealed class GetterFieldWrapper : FieldWrapper
{
private MethodInfo getter;
// NOTE fi may be null!
internal GetterFieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, FieldInfo fi, string name, string sig, Modifiers modifiers, MethodInfo getter)
: base(declaringType, fieldType, name, sig, modifiers, fi)
2003-11-17 15:01:50 +03:00
{
2004-10-04 23:30:53 +04:00
Debug.Assert(!IsVolatile);
this.getter = getter;
}
2003-11-17 15:01:50 +03:00
2004-10-04 23:30:53 +04:00
protected override void EmitGetImpl(ILGenerator ilgen)
{
if(IsStatic)
{
ilgen.Emit(OpCodes.Call, getter);
}
else
{
if(DeclaringType.IsNonPrimitiveValueType)
{
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
ilgen.Emit(OpCodes.Call, getter);
}
else
{
ilgen.Emit(getter.IsStatic ? OpCodes.Call : OpCodes.Callvirt, getter);
}
}
2004-11-04 15:50:28 +03:00
if(FieldTypeWrapper.IsUnloadable)
{
// no need to do anything
}
else if(FieldTypeWrapper.IsGhost)
2004-10-04 23:30:53 +04:00
{
LocalBuilder temp = ilgen.DeclareLocal(FieldTypeWrapper.TypeAsFieldType);
ilgen.Emit(OpCodes.Stloc, temp);
ilgen.Emit(OpCodes.Ldloca, temp);
ilgen.Emit(OpCodes.Ldfld, FieldTypeWrapper.GhostRefField);
}
else if(FieldTypeWrapper.IsNonPrimitiveValueType)
2003-11-17 15:01:50 +03:00
{
2004-10-04 23:30:53 +04:00
FieldTypeWrapper.EmitBox(ilgen);
2004-08-17 13:05:21 +04:00
}
2004-10-04 23:30:53 +04:00
}
2004-08-17 13:05:21 +04:00
2004-10-04 23:30:53 +04:00
protected override void EmitSetImpl(ILGenerator ilgen)
{
FieldInfo fi = GetField();
2004-11-04 15:50:28 +03:00
if(FieldTypeWrapper.IsUnloadable)
2004-10-04 23:30:53 +04:00
{
2004-11-04 15:50:28 +03:00
LocalBuilder temp = ilgen.DeclareLocal(typeof(object));
ilgen.Emit(OpCodes.Stloc, temp);
if(DeclaringType.IsNonPrimitiveValueType)
2004-10-04 23:30:53 +04:00
{
2004-11-04 15:50:28 +03:00
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
2004-10-04 23:30:53 +04:00
}
ilgen.Emit(OpCodes.Ldloc, temp);
2004-11-04 15:50:28 +03:00
ilgen.Emit(IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fi);
2004-10-04 23:30:53 +04:00
}
else
2004-08-17 13:05:21 +04:00
{
2004-11-04 15:50:28 +03:00
LocalBuilder temp = ilgen.DeclareLocal(FieldTypeWrapper.TypeAsLocalOrStackType);
ilgen.Emit(OpCodes.Stloc, temp);
if(FieldTypeWrapper.IsGhost)
2004-10-04 23:30:53 +04:00
{
2004-11-04 15:50:28 +03:00
if(fi.IsStatic)
{
ilgen.Emit(OpCodes.Ldsflda, fi);
}
else
{
if(DeclaringType.IsNonPrimitiveValueType)
{
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
}
ilgen.Emit(OpCodes.Ldflda, fi);
}
ilgen.Emit(OpCodes.Ldloc, temp);
ilgen.Emit(OpCodes.Stfld, FieldTypeWrapper.GhostRefField);
2004-10-04 23:30:53 +04:00
}
2004-11-04 15:50:28 +03:00
else
2004-10-04 23:30:53 +04:00
{
2004-11-04 15:50:28 +03:00
if(DeclaringType.IsNonPrimitiveValueType)
{
ilgen.Emit(OpCodes.Unbox, DeclaringType.TypeAsTBD);
}
ilgen.Emit(OpCodes.Ldloc, temp);
if(FieldTypeWrapper.IsNonPrimitiveValueType)
{
FieldTypeWrapper.EmitUnbox(ilgen);
}
ilgen.Emit(IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fi);
2004-10-04 23:30:53 +04:00
}
2004-08-17 13:05:21 +04:00
}
2004-10-04 23:30:53 +04:00
}
}
2004-08-17 13:05:21 +04:00
2004-10-04 23:30:53 +04:00
// NOTE this type is only used for remapped fields, dynamically compiled classes are always finished before we
// allow reflection (so we can look at the underlying field in that case)
sealed class ConstantFieldWrapper : FieldWrapper
{
private object constant;
internal ConstantFieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, string name, string sig, Modifiers modifiers, FieldInfo field, object constant)
: base(declaringType, fieldType, name, sig, modifiers, field)
{
this.constant = constant;
}
protected override void EmitGetImpl(ILGenerator ilgen)
{
// NOTE even though you're not supposed to access a constant static final (the compiler is supposed
// to inline them), we have to support it (because it does happen, e.g. if the field becomes final
// after the referencing class was compiled)
object v = GetValue(null);
if(v == null)
{
ilgen.Emit(OpCodes.Ldnull);
}
else if(constant is int ||
constant is short || constant is ushort ||
constant is byte || constant is sbyte ||
constant is char ||
constant is bool)
2004-08-17 13:05:21 +04:00
{
2004-10-04 23:30:53 +04:00
ilgen.Emit(OpCodes.Ldc_I4, ((IConvertible)constant).ToInt32(null));
2003-11-17 15:01:50 +03:00
}
2004-10-04 23:30:53 +04:00
else if(constant is uint)
{
ilgen.Emit(OpCodes.Ldc_I4, unchecked((int)((IConvertible)constant).ToUInt32(null)));
}
else if(constant is string)
{
ilgen.Emit(OpCodes.Ldstr, (string)constant);
}
else if(constant is float)
{
ilgen.Emit(OpCodes.Ldc_R4, (float)constant);
}
else if(constant is double)
{
ilgen.Emit(OpCodes.Ldc_R8, (double)constant);
}
else if(constant is long)
{
ilgen.Emit(OpCodes.Ldc_I8, (long)constant);
}
else if(constant is ulong)
{
ilgen.Emit(OpCodes.Ldc_I8, unchecked((long)(ulong)constant));
}
else
{
2004-11-29 12:48:01 +03:00
throw new InvalidOperationException(constant.GetType().FullName);
2004-10-04 23:30:53 +04:00
}
}
2003-11-17 15:01:50 +03:00
2004-10-04 23:30:53 +04:00
protected override void EmitSetImpl(ILGenerator ilgen)
{
// when constant static final fields are updated, the JIT normally doesn't see that (because the
// constant value is inlined), so we emulate that behavior by emitting a Pop
ilgen.Emit(OpCodes.Pop);
}
internal override object GetValue(object obj)
{
if(constant == null)
2003-11-17 15:01:50 +03:00
{
2004-10-04 23:30:53 +04:00
constant = GetField().GetValue(null);
2003-11-17 15:01:50 +03:00
}
2004-10-04 23:30:53 +04:00
return constant;
2003-11-17 15:01:50 +03:00
}
2003-05-30 16:08:59 +04:00
}