2014-08-13 10:39:27 +01:00
/ *
2015-04-07 09:35:12 +01:00
Copyright ( C ) 2002 - 2014 Jeroen Frijters
2014-08-13 10:39:27 +01: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 ;
using System.Collections.Generic ;
#if STATIC_COMPILER | | STUB_GENERATOR
using IKVM.Reflection ;
using IKVM.Reflection.Emit ;
using Type = IKVM . Reflection . Type ;
#else
using System.Reflection ;
using System.Reflection.Emit ;
#endif
using System.Diagnostics ;
using IKVM.Attributes ;
using System.Threading ;
using System.Runtime.InteropServices ;
namespace IKVM.Internal
{
[Flags]
enum MemberFlags : short
{
None = 0 ,
HideFromReflection = 1 ,
ExplicitOverride = 2 ,
MirandaMethod = 8 ,
AccessStub = 16 ,
InternalAccess = 32 , // member has "internal" access (@ikvm.lang.Internal)
PropertyAccessor = 64 ,
Intrinsic = 128 ,
CallerID = 256 ,
NonPublicTypeInSignature = 512 , // this flag is only available after linking and is not set for access stubs
DelegateInvokeWithByRefParameter = 1024 ,
Type2FinalField = 2048 ,
}
abstract class MemberWrapper
{
private HandleWrapper handle ;
private readonly TypeWrapper declaringType ;
2015-04-07 09:35:12 +01:00
protected readonly Modifiers modifiers ;
2014-08-13 10:39:27 +01:00
private MemberFlags flags ;
private readonly string name ;
private readonly string sig ;
private sealed class HandleWrapper
{
internal readonly IntPtr Value ;
[System.Security.SecurityCritical]
internal HandleWrapper ( MemberWrapper obj )
{
Value = ( IntPtr ) GCHandle . Alloc ( obj , GCHandleType . WeakTrackResurrection ) ;
}
#if CLASSGC
[System.Security.SecuritySafeCritical]
~ HandleWrapper ( )
{
if ( ! Environment . HasShutdownStarted )
{
GCHandle h = ( GCHandle ) Value ;
if ( h . Target = = null )
{
h . Free ( ) ;
}
else
{
GC . ReRegisterForFinalize ( this ) ;
}
}
}
#endif
}
protected MemberWrapper ( TypeWrapper declaringType , string name , string sig , Modifiers modifiers , MemberFlags flags )
{
Debug . Assert ( declaringType ! = null ) ;
this . declaringType = declaringType ;
this . name = String . Intern ( name ) ;
this . sig = String . Intern ( sig ) ;
this . modifiers = modifiers ;
this . flags = flags ;
}
internal IntPtr Cookie
{
[System.Security.SecurityCritical]
get
{
lock ( this )
{
if ( handle = = null )
{
handle = new HandleWrapper ( this ) ;
}
}
return handle . Value ;
}
}
[System.Security.SecurityCritical]
internal static MemberWrapper FromCookieImpl ( IntPtr cookie )
{
return ( MemberWrapper ) GCHandle . FromIntPtr ( cookie ) . Target ;
}
internal TypeWrapper DeclaringType
{
get
{
return declaringType ;
}
}
internal string Name
{
get
{
return name ;
}
}
internal string Signature
{
get
{
return sig ;
}
}
internal bool IsAccessibleFrom ( TypeWrapper referencedType , TypeWrapper caller , TypeWrapper instance )
{
if ( referencedType . IsAccessibleFrom ( caller ) )
{
return (
caller = = DeclaringType | |
IsPublicOrProtectedMemberAccessible ( caller , instance ) | |
( IsInternal & & DeclaringType . InternalsVisibleTo ( caller ) ) | |
( ! IsPrivate & & DeclaringType . IsPackageAccessibleFrom ( caller ) ) )
// The JVM supports accessing members that have non-public types in their signature from another package,
// but the CLI doesn't. It would be nice if we worked around that by emitting extra accessors, but for now
// we'll simply disallow such access across assemblies (unless the appropriate InternalsVisibleToAttribute exists).
& & ( ! ( HasNonPublicTypeInSignature | | IsType2FinalField ) | | InPracticeInternalsVisibleTo ( caller ) ) ;
}
return false ;
}
private bool IsPublicOrProtectedMemberAccessible ( TypeWrapper caller , TypeWrapper instance )
{
if ( IsPublic | | ( IsProtected & & caller . IsSubTypeOf ( DeclaringType ) & & ( IsStatic | | instance . IsUnloadable | | instance . IsSubTypeOf ( caller ) ) ) )
{
return DeclaringType . IsPublic | | InPracticeInternalsVisibleTo ( caller ) ;
}
return false ;
}
private bool InPracticeInternalsVisibleTo ( TypeWrapper caller )
{
#if ! STATIC_COMPILER
if ( DeclaringType . TypeAsTBD . Assembly . Equals ( caller . TypeAsTBD . Assembly ) )
{
// both the caller and the declaring type are in the same assembly
// so we know that the internals are visible
// (this handles the case where we're running in dynamic mode)
return true ;
}
#endif
#if CLASSGC
if ( DeclaringType . IsDynamic )
{
// if we are dynamic, we can just become friends with the caller
DeclaringType . GetClassLoader ( ) . GetTypeWrapperFactory ( ) . AddInternalsVisibleTo ( caller . TypeAsTBD . Assembly ) ;
return true ;
}
#endif
return DeclaringType . InternalsVisibleTo ( caller ) ;
}
internal bool IsHideFromReflection
{
get
{
return ( flags & MemberFlags . HideFromReflection ) ! = 0 ;
}
}
internal bool IsExplicitOverride
{
get
{
return ( flags & MemberFlags . ExplicitOverride ) ! = 0 ;
}
}
internal bool IsMirandaMethod
{
get
{
return ( flags & MemberFlags . MirandaMethod ) ! = 0 ;
}
}
internal bool IsAccessStub
{
get
{
return ( flags & MemberFlags . AccessStub ) ! = 0 ;
}
}
internal bool IsPropertyAccessor
{
get
{
return ( flags & MemberFlags . PropertyAccessor ) ! = 0 ;
}
set
{
// this is unsynchronized, so it may only be called during the JavaTypeImpl constructor
if ( value )
{
flags | = MemberFlags . PropertyAccessor ;
}
else
{
flags & = ~ MemberFlags . PropertyAccessor ;
}
}
}
internal bool IsIntrinsic
{
get
{
return ( flags & MemberFlags . Intrinsic ) ! = 0 ;
}
}
protected void SetIntrinsicFlag ( )
{
flags | = MemberFlags . Intrinsic ;
}
protected void SetNonPublicTypeInSignatureFlag ( )
{
flags | = MemberFlags . NonPublicTypeInSignature ;
}
internal bool HasNonPublicTypeInSignature
{
get { return ( flags & MemberFlags . NonPublicTypeInSignature ) ! = 0 ; }
}
protected void SetType2FinalField ( )
{
flags | = MemberFlags . Type2FinalField ;
}
internal bool IsType2FinalField
{
get { return ( flags & MemberFlags . Type2FinalField ) ! = 0 ; }
}
internal bool HasCallerID
{
get
{
return ( flags & MemberFlags . CallerID ) ! = 0 ;
}
}
internal bool IsDelegateInvokeWithByRefParameter
{
get { return ( flags & MemberFlags . DelegateInvokeWithByRefParameter ) ! = 0 ; }
}
internal Modifiers Modifiers
{
get
{
return modifiers ;
}
}
internal bool IsStatic
{
get
{
return ( modifiers & Modifiers . Static ) ! = 0 ;
}
}
internal bool IsInternal
{
get
{
return ( flags & MemberFlags . InternalAccess ) ! = 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 ;
}
}
}
abstract class MethodWrapper : MemberWrapper
{
#if ! STATIC_COMPILER & & ! FIRST_PASS & & ! STUB_GENERATOR
2015-04-07 09:35:12 +01:00
private volatile java . lang . reflect . Executable reflectionMethod ;
2014-08-13 10:39:27 +01:00
#endif
internal static readonly MethodWrapper [ ] EmptyArray = new MethodWrapper [ 0 ] ;
private MethodBase method ;
private string [ ] declaredExceptions ;
private TypeWrapper returnTypeWrapper ;
private TypeWrapper [ ] parameterTypeWrappers ;
#if EMITTERS
internal virtual void EmitCall ( CodeEmitter ilgen )
{
throw new InvalidOperationException ( ) ;
}
internal virtual void EmitCallvirt ( CodeEmitter ilgen )
{
throw new InvalidOperationException ( ) ;
}
internal virtual void EmitCallvirtReflect ( CodeEmitter ilgen )
{
EmitCallvirt ( ilgen ) ;
}
internal virtual void EmitNewobj ( CodeEmitter ilgen )
{
throw new InvalidOperationException ( ) ;
}
internal virtual bool EmitIntrinsic ( EmitIntrinsicContext context )
{
return Intrinsics . Emit ( context ) ;
}
#endif // EMITTERS
internal virtual bool IsDynamicOnly
{
get
{
return false ;
}
}
internal MethodWrapper ( TypeWrapper declaringType , string name , string sig , MethodBase method , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
: base ( declaringType , name , sig , modifiers , flags )
{
Profiler . Count ( "MethodWrapper" ) ;
this . method = method ;
Debug . Assert ( ( ( returnType = = null ) = = ( parameterTypes = = null ) ) | | ( returnType = = PrimitiveTypeWrapper . VOID ) ) ;
this . returnTypeWrapper = returnType ;
this . parameterTypeWrappers = parameterTypes ;
if ( Intrinsics . IsIntrinsic ( this ) )
{
SetIntrinsicFlag ( ) ;
}
UpdateNonPublicTypeInSignatureFlag ( ) ;
}
private void UpdateNonPublicTypeInSignatureFlag ( )
{
if ( ( IsPublic | | IsProtected ) & & ( returnTypeWrapper ! = null & & parameterTypeWrappers ! = null ) & & ! ( this is AccessStubMethodWrapper ) & & ! ( this is AccessStubConstructorMethodWrapper ) )
{
if ( ! returnTypeWrapper . IsPublic & & ! returnTypeWrapper . IsUnloadable )
{
SetNonPublicTypeInSignatureFlag ( ) ;
}
else
{
foreach ( TypeWrapper tw in parameterTypeWrappers )
{
if ( ! tw . IsPublic & & ! tw . IsUnloadable )
{
SetNonPublicTypeInSignatureFlag ( ) ;
break ;
}
}
}
}
}
internal void SetDeclaredExceptions ( string [ ] exceptions )
{
if ( exceptions = = null )
{
exceptions = new string [ 0 ] ;
}
this . declaredExceptions = ( string [ ] ) exceptions . Clone ( ) ;
}
internal string [ ] GetDeclaredExceptions ( )
{
return declaredExceptions ;
}
#if ! STATIC_COMPILER & & ! STUB_GENERATOR
2015-04-07 09:35:12 +01:00
internal java . lang . reflect . Executable ToMethodOrConstructor ( bool copy )
2014-08-13 10:39:27 +01:00
{
#if FIRST_PASS
return null ;
#else
2015-04-07 09:35:12 +01:00
java . lang . reflect . Executable method = reflectionMethod ;
2014-08-13 10:39:27 +01:00
if ( method = = null )
{
Link ( ) ;
ClassLoaderWrapper loader = this . DeclaringType . GetClassLoader ( ) ;
TypeWrapper [ ] argTypes = GetParameters ( ) ;
java . lang . Class [ ] parameterTypes = new java . lang . Class [ argTypes . Length ] ;
for ( int i = 0 ; i < argTypes . Length ; i + + )
{
parameterTypes [ i ] = argTypes [ i ] . EnsureLoadable ( loader ) . ClassObject ;
}
java . lang . Class [ ] checkedExceptions = GetExceptions ( ) ;
if ( this . IsConstructor )
{
method = new java . lang . reflect . Constructor (
this . DeclaringType . ClassObject ,
parameterTypes ,
checkedExceptions ,
( int ) this . Modifiers | ( this . IsInternal ? 0x40000000 : 0 ) ,
Array . IndexOf ( this . DeclaringType . GetMethods ( ) , this ) ,
this . DeclaringType . GetGenericMethodSignature ( this ) ,
null ,
null
) ;
}
else
{
method = new java . lang . reflect . Method (
this . DeclaringType . ClassObject ,
this . Name ,
parameterTypes ,
this . ReturnType . EnsureLoadable ( loader ) . ClassObject ,
checkedExceptions ,
( int ) this . Modifiers | ( this . IsInternal ? 0x40000000 : 0 ) ,
Array . IndexOf ( this . DeclaringType . GetMethods ( ) , this ) ,
this . DeclaringType . GetGenericMethodSignature ( this ) ,
null ,
null ,
null
) ;
}
lock ( this )
{
if ( reflectionMethod = = null )
{
reflectionMethod = method ;
}
else
{
method = reflectionMethod ;
}
}
}
if ( copy )
{
java . lang . reflect . Constructor ctor = method as java . lang . reflect . Constructor ;
if ( ctor ! = null )
{
return ctor . copy ( ) ;
}
return ( ( java . lang . reflect . Method ) method ) . copy ( ) ;
}
return method ;
#endif
}
#if ! FIRST_PASS
private java . lang . Class [ ] GetExceptions ( )
{
string [ ] classes = declaredExceptions ;
Type [ ] types = Type . EmptyTypes ;
if ( classes = = null )
{
// 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)
if ( method ! = null & & ! ( method is MethodBuilder ) )
{
ThrowsAttribute attr = AttributeHelper . GetThrows ( method ) ;
if ( attr ! = null )
{
classes = attr . classes ;
types = attr . types ;
}
}
}
if ( classes ! = null )
{
java . lang . Class [ ] array = new java . lang . Class [ classes . Length ] ;
for ( int i = 0 ; i < classes . Length ; i + + )
{
array [ i ] = this . DeclaringType . GetClassLoader ( ) . LoadClassByDottedName ( classes [ i ] ) . ClassObject ;
}
return array ;
}
else
{
java . lang . Class [ ] array = new java . lang . Class [ types . Length ] ;
for ( int i = 0 ; i < types . Length ; i + + )
{
array [ i ] = types [ i ] ;
}
return array ;
}
}
#endif // !FIRST_PASS
2015-04-07 09:35:12 +01:00
internal static MethodWrapper FromExecutable ( java . lang . reflect . Executable executable )
2014-08-13 10:39:27 +01:00
{
#if FIRST_PASS
return null ;
#else
2015-04-07 09:35:12 +01:00
return TypeWrapper . FromClass ( executable . getDeclaringClass ( ) ) . GetMethods ( ) [ executable . _slot ( ) ] ;
2014-08-13 10:39:27 +01:00
#endif
}
#endif // !STATIC_COMPILER && !STUB_GENERATOR
[System.Security.SecurityCritical]
internal static MethodWrapper FromCookie ( IntPtr cookie )
{
return ( MethodWrapper ) FromCookieImpl ( cookie ) ;
}
internal bool IsLinked
{
get
{
return parameterTypeWrappers ! = null ;
}
}
internal void Link ( )
{
lock ( this )
{
if ( parameterTypeWrappers ! = null )
{
return ;
}
}
ClassLoaderWrapper loader = this . DeclaringType . GetClassLoader ( ) ;
TypeWrapper ret = loader . RetTypeWrapperFromSigNoThrow ( Signature ) ;
TypeWrapper [ ] parameters = loader . ArgTypeWrapperListFromSigNoThrow ( Signature ) ;
lock ( this )
{
try
{
// critical code in the finally block to avoid Thread.Abort interrupting the thread
}
finally
{
if ( parameterTypeWrappers = = null )
{
Debug . Assert ( returnTypeWrapper = = null | | returnTypeWrapper = = PrimitiveTypeWrapper . VOID ) ;
returnTypeWrapper = ret ;
parameterTypeWrappers = parameters ;
UpdateNonPublicTypeInSignatureFlag ( ) ;
if ( method = = null )
{
try
{
DoLinkMethod ( ) ;
}
catch
{
// HACK if linking fails, we unlink to make sure
// that the next link attempt will fail again
returnTypeWrapper = null ;
parameterTypeWrappers = null ;
throw ;
}
}
}
}
}
}
protected virtual void DoLinkMethod ( )
{
method = this . DeclaringType . LinkMethod ( this ) ;
}
[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 ) ;
}
internal TypeWrapper ReturnType
{
get
{
AssertLinked ( ) ;
return returnTypeWrapper ;
}
}
internal TypeWrapper [ ] GetParameters ( )
{
AssertLinked ( ) ;
return parameterTypeWrappers ;
}
#if ! STUB_GENERATOR
internal DefineMethodHelper GetDefineMethodHelper ( )
{
return new DefineMethodHelper ( this ) ;
}
#endif
internal Type ReturnTypeForDefineMethod
{
get
{
return ReturnType . TypeAsSignatureType ;
}
}
internal Type [ ] GetParametersForDefineMethod ( )
{
TypeWrapper [ ] wrappers = GetParameters ( ) ;
int len = wrappers . Length ;
if ( HasCallerID )
{
len + + ;
}
Type [ ] temp = new Type [ len ] ;
for ( int i = 0 ; i < wrappers . Length ; i + + )
{
temp [ i ] = wrappers [ i ] . TypeAsSignatureType ;
}
if ( HasCallerID )
{
temp [ len - 1 ] = CoreClasses . ikvm . @internal . CallerID . Wrapper . TypeAsSignatureType ;
}
return temp ;
}
// we expose the underlying MethodBase object,
// for Java types, this is the method that contains the compiled Java bytecode
// for remapped types, this is the mbCore method (not the helper)
// Note that for some artificial methods (notably wrap() in enums), method is null
internal MethodBase GetMethod ( )
{
AssertLinked ( ) ;
return method ;
}
internal string RealName
{
get
{
AssertLinked ( ) ;
return method . Name ;
}
}
internal bool IsAbstract
{
get
{
return ( Modifiers & Modifiers . Abstract ) ! = 0 ;
}
}
internal bool RequiresNonVirtualDispatcher
{
get
{
return ! IsConstructor
& & ! IsStatic
& & ! IsPrivate
& & ! IsAbstract
& & ! IsFinal
& & ! DeclaringType . IsFinal ;
}
}
#if ! STATIC_COMPILER & & ! STUB_GENERATOR
internal Type GetDelegateType ( )
{
TypeWrapper [ ] paramTypes = GetParameters ( ) ;
if ( paramTypes . Length > MethodHandleUtil . MaxArity )
{
Type type = DeclaringType . TypeAsBaseType . Assembly . GetType (
ReturnType = = PrimitiveTypeWrapper . VOID ? "__<>NVIV`" + paramTypes . Length : "__<>NVI`" + ( paramTypes . Length + 1 ) ) ;
if ( type = = null )
{
type = DeclaringType . GetClassLoader ( ) . GetTypeWrapperFactory ( ) . DefineDelegate ( paramTypes . Length , ReturnType = = PrimitiveTypeWrapper . VOID ) ;
}
Type [ ] types = new Type [ paramTypes . Length + ( ReturnType = = PrimitiveTypeWrapper . VOID ? 0 : 1 ) ] ;
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
types [ i ] = paramTypes [ i ] . TypeAsSignatureType ;
}
if ( ReturnType ! = PrimitiveTypeWrapper . VOID )
{
types [ types . Length - 1 ] = ReturnType . TypeAsSignatureType ;
}
return type . MakeGenericType ( types ) ;
}
2015-04-07 09:35:12 +01:00
return MethodHandleUtil . CreateMemberWrapperDelegateType ( paramTypes , ReturnType ) ;
2014-08-13 10:39:27 +01:00
}
internal void ResolveMethod ( )
{
#if ! FIRST_PASS
// if we've still got the builder object, we need to replace it with the real thing before we can call it
MethodBuilder mb = method as MethodBuilder ;
if ( mb ! = null )
{
method = mb . Module . ResolveMethod ( mb . GetToken ( ) . Token ) ;
}
#endif
}
[HideFromJava]
internal virtual object InvokeNonvirtualRemapped ( object obj , object [ ] args )
{
throw new InvalidOperationException ( ) ;
}
[HideFromJava]
protected static object InvokeAndUnwrapException ( MethodBase mb , object obj , object [ ] args )
{
#if FIRST_PASS
return null ;
#else
try
{
return mb . Invoke ( obj , args ) ;
}
catch ( TargetInvocationException x )
{
throw ikvm . runtime . Util . mapException ( x . InnerException ) ;
}
#endif
}
[HideFromJava]
internal virtual object Invoke ( object obj , object [ ] args )
{
return InvokeAndUnwrapException ( method , obj , args ) ;
}
[HideFromJava]
internal virtual object CreateInstance ( object [ ] args )
{
#if FIRST_PASS
return null ;
#else
try
{
return ( ( ConstructorInfo ) method ) . Invoke ( args ) ;
}
catch ( TargetInvocationException x )
{
throw ikvm . runtime . Util . mapException ( x . InnerException ) ;
}
#endif
}
#endif // !STATIC_COMPILER && !STUB_GENERATOR
internal static OpCode SimpleOpCodeToOpCode ( SimpleOpCode opc )
{
switch ( opc )
{
case SimpleOpCode . Call :
return OpCodes . Call ;
case SimpleOpCode . Callvirt :
return OpCodes . Callvirt ;
case SimpleOpCode . Newobj :
return OpCodes . Newobj ;
default :
throw new InvalidOperationException ( ) ;
}
}
internal virtual bool IsOptionalAttributeAnnotationValue
{
get { return false ; }
}
internal bool IsConstructor
{
get { return ( object ) Name = = ( object ) StringConstants . INIT ; }
}
2015-04-07 09:35:12 +01:00
internal bool IsVirtual
{
get
{
return ( modifiers & ( Modifiers . Static | Modifiers . Private ) ) = = 0
& & ! IsConstructor ;
}
}
2014-08-13 10:39:27 +01:00
}
// placeholder for <clinit> method that exist in ClassFile but not in TypeWrapper
// (because it is optimized away)
sealed class DummyMethodWrapper : MethodWrapper
{
internal DummyMethodWrapper ( TypeWrapper tw )
: base ( tw , StringConstants . CLINIT , StringConstants . SIG_VOID , null , PrimitiveTypeWrapper . VOID , TypeWrapper . EmptyArray , Modifiers . Static , MemberFlags . None )
{
}
protected override void DoLinkMethod ( )
{
// we're pre-linked (because we pass the signature types to the base constructor)
throw new InvalidOperationException ( ) ;
}
}
abstract class SmartMethodWrapper : MethodWrapper
{
internal SmartMethodWrapper ( TypeWrapper declaringType , string name , string sig , MethodBase method , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
: base ( declaringType , name , sig , method , returnType , parameterTypes , modifiers , flags )
{
}
#if EMITTERS
internal sealed override void EmitCall ( CodeEmitter ilgen )
{
AssertLinked ( ) ;
CallImpl ( ilgen ) ;
}
protected virtual void CallImpl ( CodeEmitter ilgen )
{
throw new InvalidOperationException ( ) ;
}
internal sealed override void EmitCallvirt ( CodeEmitter ilgen )
{
AssertLinked ( ) ;
if ( DeclaringType . IsNonPrimitiveValueType )
{
// callvirt isn't allowed on a value type
// (we don't need to check for a null reference, because we're always dealing with an unboxed value)
CallImpl ( ilgen ) ;
}
else
{
CallvirtImpl ( ilgen ) ;
}
}
protected virtual void CallvirtImpl ( CodeEmitter ilgen )
{
throw new InvalidOperationException ( ) ;
}
internal sealed override void EmitNewobj ( CodeEmitter ilgen )
{
AssertLinked ( ) ;
NewobjImpl ( ilgen ) ;
if ( DeclaringType . IsNonPrimitiveValueType )
{
DeclaringType . EmitBox ( ilgen ) ;
}
}
protected virtual void NewobjImpl ( CodeEmitter ilgen )
{
throw new InvalidOperationException ( ) ;
}
#endif // EMITTERS
}
enum SimpleOpCode : byte
{
Call ,
Callvirt ,
Newobj
}
sealed class SimpleCallMethodWrapper : MethodWrapper
{
private readonly SimpleOpCode call ;
private readonly SimpleOpCode callvirt ;
internal SimpleCallMethodWrapper ( TypeWrapper declaringType , string name , string sig , MethodInfo method , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags , SimpleOpCode call , SimpleOpCode callvirt )
: base ( declaringType , name , sig , method , returnType , parameterTypes , modifiers , flags )
{
this . call = call ;
this . callvirt = callvirt ;
}
#if EMITTERS
internal override void EmitCall ( CodeEmitter ilgen )
{
ilgen . Emit ( SimpleOpCodeToOpCode ( call ) , GetMethod ( ) ) ;
}
internal override void EmitCallvirt ( CodeEmitter ilgen )
{
ilgen . Emit ( SimpleOpCodeToOpCode ( callvirt ) , GetMethod ( ) ) ;
}
#endif // EMITTERS
}
sealed class TypicalMethodWrapper : SmartMethodWrapper
{
internal TypicalMethodWrapper ( TypeWrapper declaringType , string name , string sig , MethodBase method , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
: base ( declaringType , name , sig , method , returnType , parameterTypes , modifiers , flags )
{
}
#if EMITTERS
protected override void CallImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , GetMethod ( ) ) ;
}
protected override void CallvirtImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Callvirt , GetMethod ( ) ) ;
}
protected override void NewobjImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Newobj , GetMethod ( ) ) ;
}
#endif // EMITTERS
}
abstract class MirandaMethodWrapper : SmartMethodWrapper
{
private readonly MethodWrapper ifmethod ;
private MirandaMethodWrapper ( TypeWrapper declaringType , MethodWrapper ifmethod , Modifiers modifiers )
: base ( declaringType , ifmethod . Name , ifmethod . Signature , null , null , null , modifiers , MemberFlags . HideFromReflection | MemberFlags . MirandaMethod )
{
this . ifmethod = ifmethod ;
}
private sealed class AbstractMirandaMethodWrapper : MirandaMethodWrapper
{
internal AbstractMirandaMethodWrapper ( TypeWrapper declaringType , MethodWrapper ifmethod )
: base ( declaringType , ifmethod , Modifiers . Public | Modifiers . Abstract )
{
}
}
private sealed class DefaultMirandaMethodWrapper : MirandaMethodWrapper
{
internal DefaultMirandaMethodWrapper ( TypeWrapper declaringType , MethodWrapper ifmethod )
: base ( declaringType , ifmethod , Modifiers . Public )
{
}
}
private sealed class ErrorMirandaMethodWrapper : MirandaMethodWrapper
{
private string error ;
internal ErrorMirandaMethodWrapper ( TypeWrapper declaringType , MethodWrapper ifmethod , string error )
: base ( declaringType , ifmethod , Modifiers . Public )
{
this . error = error ;
}
protected override MirandaMethodWrapper AddConflictError ( MethodWrapper mw )
{
error + = " " + mw . DeclaringType . Name + "." + mw . Name ;
return this ;
}
internal override string Error
{
get { return error ; }
}
}
internal static MirandaMethodWrapper Create ( TypeWrapper declaringType , MethodWrapper ifmethod )
{
2015-04-07 09:35:12 +01:00
DefaultMirandaMethodWrapper dmmw = ifmethod as DefaultMirandaMethodWrapper ;
if ( dmmw ! = null )
{
return new DefaultMirandaMethodWrapper ( declaringType , dmmw . BaseMethod ) ;
}
2014-08-13 10:39:27 +01:00
return ifmethod . IsAbstract
? ( MirandaMethodWrapper ) new AbstractMirandaMethodWrapper ( declaringType , ifmethod )
: ( MirandaMethodWrapper ) new DefaultMirandaMethodWrapper ( declaringType , ifmethod ) ;
}
internal MirandaMethodWrapper Update ( MethodWrapper mw )
{
if ( ifmethod = = mw )
{
// an interface can be implemented multiple times
return this ;
}
2015-04-07 09:35:12 +01:00
else if ( ifmethod . DeclaringType . ImplementsInterface ( mw . DeclaringType ) )
{
// we can override a base interface without problems
return this ;
}
2014-08-13 10:39:27 +01:00
else if ( mw . DeclaringType . ImplementsInterface ( ifmethod . DeclaringType ) )
{
return Create ( DeclaringType , mw ) ;
}
else if ( ! ifmethod . IsAbstract & & ! mw . IsAbstract )
{
return AddConflictError ( mw ) ;
}
else if ( ! ifmethod . IsAbstract & & mw . IsAbstract )
{
return new ErrorMirandaMethodWrapper ( DeclaringType , mw , DeclaringType . Name + "." + Name + Signature ) ;
}
else
{
return this ;
}
}
protected virtual MirandaMethodWrapper AddConflictError ( MethodWrapper mw )
{
return new ErrorMirandaMethodWrapper ( DeclaringType , ifmethod , "Conflicting default methods:" )
. AddConflictError ( ifmethod )
. AddConflictError ( mw ) ;
}
2015-04-07 09:35:12 +01:00
internal bool IsConflictError
{
get { return Error ! = null & & Error . StartsWith ( "Conflicting default methods:" ) ; }
}
2014-08-13 10:39:27 +01:00
internal MethodWrapper BaseMethod
{
get { return ifmethod ; }
}
internal virtual string Error
{
get { return null ; }
}
#if EMITTERS
protected override void CallImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , GetMethod ( ) ) ;
}
protected override void CallvirtImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Callvirt , GetMethod ( ) ) ;
}
#endif // EMITTERS
}
sealed class GhostMethodWrapper : SmartMethodWrapper
{
private MethodInfo ghostMethod ;
2015-04-07 09:35:12 +01:00
private MethodInfo defaultImpl ;
2014-08-13 10:39:27 +01:00
internal GhostMethodWrapper ( TypeWrapper declaringType , string name , string sig , MethodBase method , MethodInfo ghostMethod , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
: base ( declaringType , name , sig , method , returnType , parameterTypes , modifiers , flags )
{
// make sure we weren't handed the ghostMethod in the wrapper value type
Debug . Assert ( method = = null | | method . DeclaringType . IsInterface ) ;
this . ghostMethod = ghostMethod ;
}
2015-04-07 09:35:12 +01:00
#if EMITTERS
protected override void CallImpl ( CodeEmitter ilgen )
2014-08-13 10:39:27 +01:00
{
2015-04-07 09:35:12 +01:00
ilgen . Emit ( OpCodes . Call , defaultImpl ) ;
2014-08-13 10:39:27 +01:00
}
protected override void CallvirtImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , ghostMethod ) ;
}
#endif
#if ! STATIC_COMPILER & & ! STUB_GENERATOR & & ! FIRST_PASS
[HideFromJava]
internal override object Invoke ( object obj , object [ ] args )
{
return InvokeAndUnwrapException ( ghostMethod , DeclaringType . GhostWrap ( obj ) , args ) ;
}
#endif
2015-04-07 09:35:12 +01:00
internal void SetDefaultImpl ( MethodInfo impl )
{
this . defaultImpl = impl ;
}
internal MethodInfo GetDefaultImpl ( )
{
return defaultImpl ;
}
#if STATIC_COMPILER
internal void SetGhostMethod ( MethodBuilder mb )
{
this . ghostMethod = mb ;
}
internal MethodBuilder GetGhostMethod ( )
{
return ( MethodBuilder ) ghostMethod ;
}
#endif
2014-08-13 10:39:27 +01:00
}
sealed class AccessStubMethodWrapper : SmartMethodWrapper
{
private readonly MethodInfo stubVirtual ;
private readonly MethodInfo stubNonVirtual ;
internal AccessStubMethodWrapper ( TypeWrapper declaringType , string name , string sig , MethodInfo core , MethodInfo stubVirtual , MethodInfo stubNonVirtual , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
: base ( declaringType , name , sig , core , returnType , parameterTypes , modifiers , flags )
{
this . stubVirtual = stubVirtual ;
this . stubNonVirtual = stubNonVirtual ;
}
#if EMITTERS
protected override void CallImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , stubNonVirtual ) ;
}
protected override void CallvirtImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Callvirt , stubVirtual ) ;
}
#endif // EMITTERS
}
sealed class AccessStubConstructorMethodWrapper : SmartMethodWrapper
{
private readonly ConstructorInfo stub ;
internal AccessStubConstructorMethodWrapper ( TypeWrapper declaringType , string sig , ConstructorInfo core , ConstructorInfo stub , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
: base ( declaringType , StringConstants . INIT , sig , core , PrimitiveTypeWrapper . VOID , parameterTypes , modifiers , flags )
{
this . stub = stub ;
}
#if EMITTERS
protected override void CallImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , stub ) ;
}
protected override void NewobjImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Newobj , stub ) ;
}
#endif // EMITTERS
}
2015-04-07 09:35:12 +01:00
sealed class DefaultInterfaceMethodWrapper : SmartMethodWrapper
{
private MethodInfo impl ;
internal DefaultInterfaceMethodWrapper ( TypeWrapper declaringType , string name , string sig , MethodInfo ifmethod , MethodInfo impl , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
: base ( declaringType , name , sig , ifmethod , returnType , parameterTypes , modifiers , flags )
{
this . impl = impl ;
}
internal static MethodInfo GetImpl ( MethodWrapper mw )
{
DefaultInterfaceMethodWrapper dimw = mw as DefaultInterfaceMethodWrapper ;
if ( dimw ! = null )
{
return dimw . impl ;
}
else
{
return ( ( GhostMethodWrapper ) mw ) . GetDefaultImpl ( ) ;
}
}
internal static void SetImpl ( MethodWrapper mw , MethodInfo impl )
{
DefaultInterfaceMethodWrapper dimw = mw as DefaultInterfaceMethodWrapper ;
if ( dimw ! = null )
{
dimw . impl = impl ;
}
else
{
( ( GhostMethodWrapper ) mw ) . SetDefaultImpl ( impl ) ;
}
}
#if EMITTERS
protected override void CallImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , impl ) ;
}
protected override void CallvirtImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Callvirt , GetMethod ( ) ) ;
}
#endif // EMITTERS
}
sealed class PrivateInterfaceMethodWrapper : SmartMethodWrapper
{
internal PrivateInterfaceMethodWrapper ( TypeWrapper declaringType , string name , string sig , MethodBase method , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
: base ( declaringType , name , sig , method , returnType , parameterTypes , modifiers , flags )
{
}
#if EMITTERS
protected override void CallImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , GetMethod ( ) ) ;
}
protected override void CallvirtImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , GetMethod ( ) ) ;
}
#endif // EMITTERS
}
2014-08-13 10:39:27 +01:00
abstract class FieldWrapper : MemberWrapper
{
#if ! STATIC_COMPILER & & ! FIRST_PASS & & ! STUB_GENERATOR
private volatile java . lang . reflect . Field reflectionField ;
private sun . reflect . FieldAccessor jniAccessor ;
#endif
internal static readonly FieldWrapper [ ] EmptyArray = new FieldWrapper [ 0 ] ;
private FieldInfo field ;
private TypeWrapper fieldType ;
internal FieldWrapper ( TypeWrapper declaringType , TypeWrapper fieldType , string name , string sig , Modifiers modifiers , FieldInfo field , MemberFlags flags )
: base ( declaringType , name , sig , modifiers , flags )
{
Debug . Assert ( name ! = null ) ;
Debug . Assert ( sig ! = null ) ;
this . fieldType = fieldType ;
this . field = field ;
UpdateNonPublicTypeInSignatureFlag ( ) ;
#if STATIC_COMPILER
if ( IsFinal
& & DeclaringType . IsPublic
& & ! DeclaringType . IsInterface
& & ( IsPublic | | ( IsProtected & & ! DeclaringType . IsFinal ) )
& & ! DeclaringType . GetClassLoader ( ) . StrictFinalFieldSemantics
& & DeclaringType . IsDynamic
& & ! ( this is ConstantFieldWrapper )
& & ! ( this is DynamicPropertyFieldWrapper ) )
{
SetType2FinalField ( ) ;
}
#endif
}
internal FieldWrapper ( TypeWrapper declaringType , TypeWrapper fieldType , string name , string sig , ExModifiers modifiers , FieldInfo field )
: this ( declaringType , fieldType , name , sig , modifiers . Modifiers , field ,
( modifiers . IsInternal ? MemberFlags . InternalAccess : MemberFlags . None ) )
{
}
private void UpdateNonPublicTypeInSignatureFlag ( )
{
if ( ( IsPublic | | IsProtected ) & & fieldType ! = null & & ! IsAccessStub )
{
if ( ! fieldType . IsPublic & & ! fieldType . IsUnloadable )
{
SetNonPublicTypeInSignatureFlag ( ) ;
}
}
}
internal FieldInfo GetField ( )
{
AssertLinked ( ) ;
return field ;
}
[Conditional("DEBUG")]
internal void AssertLinked ( )
{
if ( fieldType = = null )
{
Tracer . Error ( Tracer . Runtime , "AssertLinked failed: " + this . DeclaringType . Name + "::" + this . Name + " (" + this . Signature + ")" ) ;
}
Debug . Assert ( fieldType ! = null , this . DeclaringType . Name + "::" + this . Name + " (" + this . Signature + ")" ) ;
}
#if ! STATIC_COMPILER & & ! STUB_GENERATOR
internal static FieldWrapper FromField ( java . lang . reflect . Field field )
{
#if FIRST_PASS
return null ;
#else
int slot = field . _slot ( ) ;
if ( slot = = - 1 )
{
// it's a Field created by Unsafe.objectFieldOffset(Class,String) so we must resolve based on the name
foreach ( FieldWrapper fw in TypeWrapper . FromClass ( field . getDeclaringClass ( ) ) . GetFields ( ) )
{
if ( fw . Name = = field . getName ( ) )
{
return fw ;
}
}
}
return TypeWrapper . FromClass ( field . getDeclaringClass ( ) ) . GetFields ( ) [ slot ] ;
#endif
}
internal object ToField ( bool copy )
{
return ToField ( copy , null ) ;
}
internal object ToField ( bool copy , int? fieldIndex )
{
#if FIRST_PASS
return null ;
#else
java . lang . reflect . Field field = reflectionField ;
if ( field = = null )
{
const Modifiers ReflectionFieldModifiersMask = Modifiers . Public | Modifiers . Private | Modifiers . Protected | Modifiers . Static
| Modifiers . Final | Modifiers . Volatile | Modifiers . Transient | Modifiers . Synthetic | Modifiers . Enum ;
Link ( ) ;
field = new java . lang . reflect . Field (
this . DeclaringType . ClassObject ,
this . Name ,
this . FieldTypeWrapper . EnsureLoadable ( this . DeclaringType . GetClassLoader ( ) ) . ClassObject ,
( int ) ( this . Modifiers & ReflectionFieldModifiersMask ) | ( this . IsInternal ? 0x40000000 : 0 ) ,
fieldIndex ? ? Array . IndexOf ( this . DeclaringType . GetFields ( ) , this ) ,
this . DeclaringType . GetGenericFieldSignature ( this ) ,
null
) ;
}
lock ( this )
{
if ( reflectionField = = null )
{
reflectionField = field ;
}
else
{
field = reflectionField ;
}
}
if ( copy )
{
field = field . copy ( ) ;
}
return field ;
#endif // FIRST_PASS
}
#endif // !STATIC_COMPILER && !STUB_GENERATOR
[System.Security.SecurityCritical]
internal static FieldWrapper FromCookie ( IntPtr cookie )
{
return ( FieldWrapper ) FromCookieImpl ( cookie ) ;
}
internal TypeWrapper FieldTypeWrapper
{
get
{
AssertLinked ( ) ;
return fieldType ;
}
}
#if EMITTERS
internal void EmitGet ( CodeEmitter ilgen )
{
AssertLinked ( ) ;
EmitGetImpl ( ilgen ) ;
}
protected abstract void EmitGetImpl ( CodeEmitter ilgen ) ;
internal void EmitSet ( CodeEmitter ilgen )
{
AssertLinked ( ) ;
EmitSetImpl ( ilgen ) ;
}
protected abstract void EmitSetImpl ( CodeEmitter ilgen ) ;
#endif // EMITTERS
#if STATIC_COMPILER
internal bool IsLinked
{
get { return fieldType ! = null ; }
}
#endif
internal void Link ( )
{
lock ( this )
{
if ( fieldType ! = null )
{
return ;
}
}
TypeWrapper fld = this . DeclaringType . GetClassLoader ( ) . FieldTypeWrapperFromSigNoThrow ( Signature ) ;
lock ( this )
{
try
{
// critical code in the finally block to avoid Thread.Abort interrupting the thread
}
finally
{
if ( fieldType = = null )
{
fieldType = fld ;
UpdateNonPublicTypeInSignatureFlag ( ) ;
try
{
field = this . DeclaringType . LinkField ( this ) ;
}
catch
{
// HACK if linking fails, we unlink to make sure
// that the next link attempt will fail again
fieldType = null ;
throw ;
}
}
}
}
}
internal bool IsVolatile
{
get
{
return ( Modifiers & Modifiers . Volatile ) ! = 0 ;
}
}
internal static FieldWrapper Create ( TypeWrapper declaringType , TypeWrapper fieldType , FieldInfo fi , string name , string sig , ExModifiers modifiers )
{
// volatile long & double field accesses must be made atomic
if ( ( modifiers . Modifiers & Modifiers . Volatile ) ! = 0 & & ( sig = = "J" | | sig = = "D" ) )
{
return new VolatileLongDoubleFieldWrapper ( declaringType , fieldType , fi , name , sig , modifiers ) ;
}
return new SimpleFieldWrapper ( declaringType , fieldType , fi , name , sig , modifiers ) ;
}
#if ! STATIC_COMPILER & & ! STUB_GENERATOR
internal virtual void ResolveField ( )
{
FieldBuilder fb = field as FieldBuilder ;
if ( fb ! = null )
{
field = fb . Module . ResolveField ( fb . GetToken ( ) . Token ) ;
}
}
internal object GetFieldAccessorJNI ( )
{
#if FIRST_PASS
return null ;
#else
if ( jniAccessor = = null )
{
Interlocked . CompareExchange ( ref jniAccessor , Java_sun_reflect_ReflectionFactory . NewFieldAccessorJNI ( this ) , null ) ;
}
return jniAccessor ;
#endif
}
#if ! FIRST_PASS
internal abstract object GetValue ( object obj ) ;
internal abstract void SetValue ( object obj , object value ) ;
#endif
#endif // !STATIC_COMPILER && !STUB_GENERATOR
}
sealed class SimpleFieldWrapper : FieldWrapper
{
internal SimpleFieldWrapper ( TypeWrapper declaringType , TypeWrapper fieldType , FieldInfo fi , string name , string sig , ExModifiers modifiers )
: base ( declaringType , fieldType , name , sig , modifiers , fi )
{
Debug . Assert ( ! ( fieldType = = PrimitiveTypeWrapper . DOUBLE | | fieldType = = PrimitiveTypeWrapper . LONG ) | | ! IsVolatile ) ;
}
#if EMITTERS
protected override void EmitGetImpl ( CodeEmitter ilgen )
{
if ( ! IsStatic & & DeclaringType . IsNonPrimitiveValueType )
{
ilgen . Emit ( OpCodes . Unbox , DeclaringType . TypeAsTBD ) ;
}
if ( IsVolatile )
{
ilgen . Emit ( OpCodes . Volatile ) ;
}
ilgen . Emit ( IsStatic ? OpCodes . Ldsfld : OpCodes . Ldfld , GetField ( ) ) ;
}
protected override void EmitSetImpl ( CodeEmitter ilgen )
{
FieldInfo fi = GetField ( ) ;
if ( ! IsStatic & & DeclaringType . IsNonPrimitiveValueType )
{
CodeEmitterLocal temp = ilgen . DeclareLocal ( FieldTypeWrapper . TypeAsSignatureType ) ;
ilgen . Emit ( OpCodes . Stloc , temp ) ;
ilgen . Emit ( OpCodes . Unbox , DeclaringType . TypeAsTBD ) ;
ilgen . Emit ( OpCodes . Ldloc , temp ) ;
}
if ( IsVolatile )
{
ilgen . Emit ( OpCodes . Volatile ) ;
}
ilgen . Emit ( IsStatic ? OpCodes . Stsfld : OpCodes . Stfld , fi ) ;
if ( IsVolatile )
{
ilgen . EmitMemoryBarrier ( ) ;
}
}
#endif // EMITTERS
#if ! STATIC_COMPILER & & ! STUB_GENERATOR & & ! FIRST_PASS
internal override object GetValue ( object obj )
{
return GetField ( ) . GetValue ( obj ) ;
}
internal override void SetValue ( object obj , object value )
{
GetField ( ) . SetValue ( obj , value ) ;
}
#endif // !STATIC_COMPILER && !STUB_GENERATOR && !FIRST_PASS
}
sealed class VolatileLongDoubleFieldWrapper : FieldWrapper
{
internal VolatileLongDoubleFieldWrapper ( TypeWrapper declaringType , TypeWrapper fieldType , FieldInfo fi , string name , string sig , ExModifiers modifiers )
: base ( declaringType , fieldType , name , sig , modifiers , fi )
{
Debug . Assert ( IsVolatile ) ;
Debug . Assert ( sig = = "J" | | sig = = "D" ) ;
}
#if EMITTERS
protected override void EmitGetImpl ( CodeEmitter ilgen )
{
FieldInfo fi = GetField ( ) ;
if ( fi . IsStatic )
{
ilgen . Emit ( OpCodes . Ldsflda , fi ) ;
}
else
{
if ( DeclaringType . IsNonPrimitiveValueType )
{
ilgen . Emit ( OpCodes . Unbox , DeclaringType . TypeAsTBD ) ;
}
ilgen . Emit ( OpCodes . Ldflda , fi ) ;
}
if ( FieldTypeWrapper = = PrimitiveTypeWrapper . DOUBLE )
{
ilgen . Emit ( OpCodes . Call , ByteCodeHelperMethods . volatileReadDouble ) ;
}
else
{
Debug . Assert ( FieldTypeWrapper = = PrimitiveTypeWrapper . LONG ) ;
ilgen . Emit ( OpCodes . Call , ByteCodeHelperMethods . volatileReadLong ) ;
}
}
protected override void EmitSetImpl ( CodeEmitter ilgen )
{
FieldInfo fi = GetField ( ) ;
CodeEmitterLocal temp = ilgen . DeclareLocal ( FieldTypeWrapper . TypeAsSignatureType ) ;
ilgen . Emit ( OpCodes . Stloc , temp ) ;
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 ) ;
if ( FieldTypeWrapper = = PrimitiveTypeWrapper . DOUBLE )
{
ilgen . Emit ( OpCodes . Call , ByteCodeHelperMethods . volatileWriteDouble ) ;
}
else
{
Debug . Assert ( FieldTypeWrapper = = PrimitiveTypeWrapper . LONG ) ;
ilgen . Emit ( OpCodes . Call , ByteCodeHelperMethods . volatileWriteLong ) ;
}
}
#endif // EMITTERS
#if ! STATIC_COMPILER & & ! STUB_GENERATOR & & ! FIRST_PASS
#if NO_REF_EMIT
internal static readonly object lockObject = new object ( ) ;
#endif
internal override object GetValue ( object obj )
{
#if NO_REF_EMIT
lock ( lockObject )
{
return GetField ( ) . GetValue ( obj ) ;
}
#else
throw new InvalidOperationException ( ) ;
#endif
}
internal override void SetValue ( object obj , object value )
{
#if NO_REF_EMIT
lock ( lockObject )
{
GetField ( ) . SetValue ( obj , value ) ;
}
#else
throw new InvalidOperationException ( ) ;
#endif
}
#endif // !STATIC_COMPILER && !STUB_GENERATOR && !FIRST_PASS
}
#if ! STUB_GENERATOR
// this class represents a .NET property defined in Java with the ikvm.lang.Property annotation
sealed class DynamicPropertyFieldWrapper : FieldWrapper
{
private readonly MethodWrapper getter ;
private readonly MethodWrapper setter ;
private PropertyBuilder pb ;
private MethodWrapper GetMethod ( string name , string sig , bool isstatic )
{
if ( name ! = null )
{
MethodWrapper mw = this . DeclaringType . GetMethodWrapper ( name , sig , false ) ;
if ( mw ! = null & & mw . IsStatic = = isstatic )
{
mw . IsPropertyAccessor = true ;
return mw ;
}
Tracer . Error ( Tracer . Compiler , "Property '{0}' accessor '{1}' not found in class '{2}'" , this . Name , name , this . DeclaringType . Name ) ;
}
return null ;
}
internal DynamicPropertyFieldWrapper ( TypeWrapper declaringType , ClassFile . Field fld )
: base ( declaringType , null , fld . Name , fld . Signature , new ExModifiers ( fld . Modifiers , fld . IsInternal ) , null )
{
getter = GetMethod ( fld . PropertyGetter , "()" + fld . Signature , fld . IsStatic ) ;
setter = GetMethod ( fld . PropertySetter , "(" + fld . Signature + ")V" , fld . IsStatic ) ;
}
#if ! STATIC_COMPILER & & ! FIRST_PASS
internal override void ResolveField ( )
{
if ( getter ! = null )
{
getter . ResolveMethod ( ) ;
}
if ( setter ! = null )
{
setter . ResolveMethod ( ) ;
}
}
#endif
internal PropertyBuilder GetPropertyBuilder ( )
{
AssertLinked ( ) ;
return pb ;
}
internal void DoLink ( TypeBuilder tb )
{
if ( getter ! = null )
{
getter . Link ( ) ;
}
if ( setter ! = null )
{
setter . Link ( ) ;
}
pb = tb . DefineProperty ( this . Name , PropertyAttributes . None , this . FieldTypeWrapper . TypeAsSignatureType , Type . EmptyTypes ) ;
if ( getter ! = null )
{
pb . SetGetMethod ( ( MethodBuilder ) getter . GetMethod ( ) ) ;
}
if ( setter ! = null )
{
pb . SetSetMethod ( ( MethodBuilder ) setter . GetMethod ( ) ) ;
}
#if STATIC_COMPILER
AttributeHelper . SetModifiers ( pb , this . Modifiers , this . IsInternal ) ;
#endif
}
#if EMITTERS
protected override void EmitGetImpl ( CodeEmitter ilgen )
{
if ( getter = = null )
{
EmitThrowNoSuchMethodErrorForGetter ( ilgen , this . FieldTypeWrapper , this . IsStatic ) ;
}
else if ( getter . IsStatic )
{
getter . EmitCall ( ilgen ) ;
}
else
{
getter . EmitCallvirt ( ilgen ) ;
}
}
internal static void EmitThrowNoSuchMethodErrorForGetter ( CodeEmitter ilgen , TypeWrapper type , bool isStatic )
{
// HACK the branch around the throw is to keep the verifier happy
CodeEmitterLabel label = ilgen . DefineLabel ( ) ;
ilgen . Emit ( OpCodes . Ldc_I4_0 ) ;
ilgen . EmitBrtrue ( label ) ;
ilgen . EmitThrow ( "java.lang.NoSuchMethodError" ) ;
ilgen . MarkLabel ( label ) ;
if ( ! isStatic )
{
ilgen . Emit ( OpCodes . Pop ) ;
}
ilgen . Emit ( OpCodes . Ldloc , ilgen . DeclareLocal ( type . TypeAsLocalOrStackType ) ) ;
}
protected override void EmitSetImpl ( CodeEmitter ilgen )
{
if ( setter = = null )
{
if ( this . IsFinal )
{
ilgen . Emit ( OpCodes . Pop ) ;
if ( ! this . IsStatic )
{
ilgen . Emit ( OpCodes . Pop ) ;
}
}
else
{
EmitThrowNoSuchMethodErrorForSetter ( ilgen , this . IsStatic ) ;
}
}
else if ( setter . IsStatic )
{
setter . EmitCall ( ilgen ) ;
}
else
{
setter . EmitCallvirt ( ilgen ) ;
}
}
internal static void EmitThrowNoSuchMethodErrorForSetter ( CodeEmitter ilgen , bool isStatic )
{
// HACK the branch around the throw is to keep the verifier happy
CodeEmitterLabel label = ilgen . DefineLabel ( ) ;
ilgen . Emit ( OpCodes . Ldc_I4_0 ) ;
ilgen . EmitBrtrue ( label ) ;
ilgen . EmitThrow ( "java.lang.NoSuchMethodError" ) ;
ilgen . MarkLabel ( label ) ;
ilgen . Emit ( OpCodes . Pop ) ;
if ( ! isStatic )
{
ilgen . Emit ( OpCodes . Pop ) ;
}
}
#endif // EMITTERS
#if ! STATIC_COMPILER & & ! FIRST_PASS
internal override object GetValue ( object obj )
{
if ( getter = = null )
{
throw new java . lang . NoSuchMethodError ( ) ;
}
return getter . Invoke ( obj , new object [ 0 ] ) ;
}
internal override void SetValue ( object obj , object value )
{
if ( setter = = null )
{
throw new java . lang . NoSuchMethodError ( ) ;
}
setter . Invoke ( obj , new object [ ] { value } ) ;
}
#endif
}
#endif // !STUB_GENERATOR
// this class represents a .NET property defined in Java with the ikvm.lang.Property annotation
sealed class CompiledPropertyFieldWrapper : FieldWrapper
{
private readonly PropertyInfo property ;
internal CompiledPropertyFieldWrapper ( TypeWrapper declaringType , PropertyInfo property , ExModifiers modifiers )
: base ( declaringType , ClassLoaderWrapper . GetWrapperFromType ( property . PropertyType ) , property . Name , ClassLoaderWrapper . GetWrapperFromType ( property . PropertyType ) . SigName , modifiers , null )
{
this . property = property ;
}
#if EMITTERS
protected override void EmitGetImpl ( CodeEmitter ilgen )
{
MethodInfo getter = property . GetGetMethod ( true ) ;
if ( getter = = null )
{
DynamicPropertyFieldWrapper . EmitThrowNoSuchMethodErrorForGetter ( ilgen , this . FieldTypeWrapper , this . IsStatic ) ;
}
else if ( getter . IsStatic )
{
ilgen . Emit ( OpCodes . Call , getter ) ;
}
else
{
ilgen . Emit ( OpCodes . Callvirt , getter ) ;
}
}
protected override void EmitSetImpl ( CodeEmitter ilgen )
{
MethodInfo setter = property . GetSetMethod ( true ) ;
if ( setter = = null )
{
if ( this . IsFinal )
{
ilgen . Emit ( OpCodes . Pop ) ;
if ( ! this . IsStatic )
{
ilgen . Emit ( OpCodes . Pop ) ;
}
}
else
{
DynamicPropertyFieldWrapper . EmitThrowNoSuchMethodErrorForSetter ( ilgen , this . IsStatic ) ;
}
}
else if ( setter . IsStatic )
{
ilgen . Emit ( OpCodes . Call , setter ) ;
}
else
{
ilgen . Emit ( OpCodes . Callvirt , setter ) ;
}
}
#endif // EMITTERS
#if ! STATIC_COMPILER & & ! STUB_GENERATOR & & ! FIRST_PASS
internal override object GetValue ( object obj )
{
MethodInfo getter = property . GetGetMethod ( true ) ;
if ( getter = = null )
{
throw new java . lang . NoSuchMethodError ( ) ;
}
return getter . Invoke ( obj , new object [ 0 ] ) ;
}
internal override void SetValue ( object obj , object value )
{
MethodInfo setter = property . GetSetMethod ( true ) ;
if ( setter = = null )
{
throw new java . lang . NoSuchMethodError ( ) ;
}
setter . Invoke ( obj , new object [ ] { value } ) ;
}
#endif
internal PropertyInfo GetProperty ( )
{
return property ;
}
}
sealed class ConstantFieldWrapper : FieldWrapper
{
// NOTE this field wrapper can resprent a .NET enum, but in that case "constant" contains the raw constant value (i.e. the boxed underlying primitive value, not a boxed enum)
private object constant ;
internal ConstantFieldWrapper ( TypeWrapper declaringType , TypeWrapper fieldType , string name , string sig , Modifiers modifiers , FieldInfo field , object constant , MemberFlags flags )
: base ( declaringType , fieldType , name , sig , modifiers , field , flags )
{
Debug . Assert ( IsStatic ) ;
Debug . Assert ( constant = = null | | constant . GetType ( ) . IsPrimitive | | constant is string ) ;
this . constant = constant ;
}
#if EMITTERS
protected override void EmitGetImpl ( CodeEmitter ilgen )
{
// Reading a field should trigger the cctor, but since we're inlining the value
// we have to trigger it explicitly
DeclaringType . EmitRunClassConstructor ( 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, or when we're accessing an unsigned primitive .NET field)
object v = GetConstantValue ( ) ;
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 )
{
ilgen . EmitLdc_I4 ( ( ( IConvertible ) constant ) . ToInt32 ( null ) ) ;
}
else if ( constant is string )
{
ilgen . Emit ( OpCodes . Ldstr , ( string ) constant ) ;
}
else if ( constant is float )
{
ilgen . EmitLdc_R4 ( ( float ) constant ) ;
}
else if ( constant is double )
{
ilgen . EmitLdc_R8 ( ( double ) constant ) ;
}
else if ( constant is long )
{
ilgen . EmitLdc_I8 ( ( long ) constant ) ;
}
else if ( constant is uint )
{
ilgen . EmitLdc_I4 ( unchecked ( ( int ) ( ( IConvertible ) constant ) . ToUInt32 ( null ) ) ) ;
}
else if ( constant is ulong )
{
ilgen . EmitLdc_I8 ( unchecked ( ( long ) ( ulong ) constant ) ) ;
}
else
{
throw new InvalidOperationException ( constant . GetType ( ) . FullName ) ;
}
}
protected override void EmitSetImpl ( CodeEmitter 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 ) ;
}
#endif // EMITTERS
internal object GetConstantValue ( )
{
if ( constant = = null )
{
FieldInfo field = GetField ( ) ;
constant = field . GetRawConstantValue ( ) ;
}
return constant ;
}
#if ! STUB_GENERATOR & & ! STATIC_COMPILER & & ! FIRST_PASS
internal override object GetValue ( object obj )
{
FieldInfo field = GetField ( ) ;
return FieldTypeWrapper . IsPrimitive | | field = = null
? GetConstantValue ( )
: field . GetValue ( null ) ;
}
internal override void SetValue ( object obj , object value )
{
}
#endif
}
sealed class CompiledAccessStubFieldWrapper : FieldWrapper
{
private readonly MethodInfo getter ;
private readonly MethodInfo setter ;
private static Modifiers GetModifiers ( PropertyInfo property )
{
// NOTE we only support the subset of modifiers that is expected for "access stub" properties
MethodInfo getter = property . GetGetMethod ( true ) ;
Modifiers modifiers = getter . IsPublic ? Modifiers . Public : Modifiers . Protected ;
if ( ! property . CanWrite )
{
modifiers | = Modifiers . Final ;
}
if ( getter . IsStatic )
{
modifiers | = Modifiers . Static ;
}
return modifiers ;
}
// constructor for type 1 access stubs
internal CompiledAccessStubFieldWrapper ( TypeWrapper wrapper , PropertyInfo property , TypeWrapper propertyType )
: this ( wrapper , property , null , propertyType , GetModifiers ( property ) , MemberFlags . HideFromReflection | MemberFlags . AccessStub )
{
}
// constructor for type 2 access stubs
internal CompiledAccessStubFieldWrapper ( TypeWrapper wrapper , PropertyInfo property , FieldInfo field , TypeWrapper propertyType )
: this ( wrapper , property , field , propertyType , AttributeHelper . GetModifiersAttribute ( property ) . Modifiers , MemberFlags . AccessStub )
{
}
private CompiledAccessStubFieldWrapper ( TypeWrapper wrapper , PropertyInfo property , FieldInfo field , TypeWrapper propertyType , Modifiers modifiers , MemberFlags flags )
: base ( wrapper , propertyType , property . Name , propertyType . SigName , modifiers , field , flags )
{
this . getter = property . GetGetMethod ( true ) ;
this . setter = property . GetSetMethod ( true ) ;
}
#if EMITTERS
protected override void EmitGetImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , getter ) ;
}
protected override void EmitSetImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , setter ) ;
}
#endif // EMITTERS
#if ! STATIC_COMPILER & & ! STUB_GENERATOR & & ! FIRST_PASS
internal override object GetValue ( object obj )
{
// we can only be invoked on type 2 access stubs (because type 1 access stubs are HideFromReflection), so we know we have a field
return GetField ( ) . GetValue ( obj ) ;
}
internal override void SetValue ( object obj , object value )
{
// we can only be invoked on type 2 access stubs (because type 1 access stubs are HideFromReflection), so we know we have a field
GetField ( ) . SetValue ( obj , value ) ;
}
#endif // !STATIC_COMPILER && !STUB_GENERATOR && !FIRST_PASS
}
}