2003-05-30 16:08:59 +04:00
/ *
2011-11-23 10:20:34 +04:00
Copyright ( C ) 2002 - 2011 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 ;
2008-08-15 16:01:06 +04:00
using System.Collections.Generic ;
2010-01-28 12:18:33 +03:00
#if STATIC_COMPILER | | STUB_GENERATOR
2010-01-25 10:52:27 +03:00
using IKVM.Reflection ;
2008-11-14 11:42:07 +03:00
using IKVM.Reflection.Emit ;
2010-01-25 10:52:27 +03:00
using Type = IKVM . Reflection . Type ;
2009-08-28 10:47:16 +04:00
#else
2010-01-25 10:52:27 +03:00
using System.Reflection ;
2003-05-30 16:08:59 +04:00
using System.Reflection.Emit ;
2005-12-07 12:06:32 +03:00
#endif
2003-05-30 16:08:59 +04:00
using System.Diagnostics ;
2004-09-09 15:17:55 +04:00
using IKVM.Attributes ;
2008-08-21 10:40:22 +04:00
using System.Threading ;
2009-06-02 11:38:21 +04:00
using System.Runtime.InteropServices ;
2003-05-30 16:08:59 +04:00
2005-06-01 13:49:30 +04:00
namespace IKVM.Internal
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
[Flags]
enum MemberFlags : short
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
None = 0 ,
HideFromReflection = 1 ,
ExplicitOverride = 2 ,
2005-08-14 19:49:50 +04:00
MirandaMethod = 8 ,
2006-04-05 12:18:58 +04:00
AccessStub = 16 ,
2008-04-14 09:13:41 +04:00
InternalAccess = 32 , // member has "internal" access (@ikvm.lang.Internal)
PropertyAccessor = 64 ,
2008-05-09 09:57:55 +04:00
Intrinsic = 128 ,
2008-05-31 19:20:29 +04:00
CallerID = 256 ,
2011-11-17 21:09:10 +04:00
NonPublicTypeInSignature = 512 , // this flag is only available after linking and is not set for access stubs
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
class MemberWrapper
{
2009-06-02 11:38:21 +04:00
private HandleWrapper handle ;
2005-06-01 13:49:30 +04:00
private TypeWrapper declaringType ;
private Modifiers modifiers ;
private MemberFlags flags ;
2005-08-14 19:49:50 +04:00
private string name ;
private string sig ;
2005-06-01 13:49:30 +04:00
2009-06-02 11:38:21 +04:00
private sealed class HandleWrapper
{
internal readonly IntPtr Value ;
2010-05-29 17:59:27 +04:00
[System.Security.SecurityCritical]
2009-06-02 11:38:21 +04:00
internal HandleWrapper ( MemberWrapper obj )
{
Value = ( IntPtr ) GCHandle . Alloc ( obj , GCHandleType . WeakTrackResurrection ) ;
}
#if CLASSGC
2010-06-08 16:47:51 +04:00
[System.Security.SecuritySafeCritical]
2009-06-02 11:38:21 +04:00
~ HandleWrapper ( )
{
if ( ! Environment . HasShutdownStarted )
{
GCHandle h = ( GCHandle ) Value ;
if ( h . Target = = null )
{
h . Free ( ) ;
}
else
{
GC . ReRegisterForFinalize ( this ) ;
}
}
}
#endif
}
2005-08-14 19:49:50 +04:00
protected MemberWrapper ( TypeWrapper declaringType , string name , string sig , Modifiers modifiers , MemberFlags flags )
2005-06-01 13:49:30 +04:00
{
Debug . Assert ( declaringType ! = null ) ;
this . declaringType = declaringType ;
2005-08-14 19:49:50 +04:00
this . name = String . Intern ( name ) ;
this . sig = String . Intern ( sig ) ;
2005-06-01 13:49:30 +04:00
this . modifiers = modifiers ;
this . flags = flags ;
}
internal IntPtr Cookie
2003-05-30 16:08:59 +04:00
{
2010-04-12 10:38:46 +04:00
[System.Security.SecurityCritical]
2005-06-01 13:49:30 +04:00
get
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
lock ( this )
2003-05-30 16:08:59 +04:00
{
2009-06-02 11:38:21 +04:00
if ( handle = = null )
2005-06-01 13:49:30 +04:00
{
2009-06-02 11:38:21 +04:00
handle = new HandleWrapper ( this ) ;
2005-06-01 13:49:30 +04:00
}
2003-05-30 16:08:59 +04:00
}
2009-06-02 11:38:21 +04:00
return handle . Value ;
2003-05-30 16:08:59 +04:00
}
}
2010-04-12 10:38:46 +04:00
[System.Security.SecurityCritical]
2005-06-01 13:49:30 +04:00
internal static MemberWrapper FromCookieImpl ( IntPtr cookie )
2003-05-30 16:08:59 +04:00
{
2010-01-06 17:28:38 +03:00
return ( MemberWrapper ) GCHandle . FromIntPtr ( cookie ) . Target ;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper DeclaringType
2005-05-31 09:44:29 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return declaringType ;
}
2005-05-31 09:44:29 +04:00
}
2004-08-17 13:05:21 +04:00
2005-08-14 19:49:50 +04:00
internal string Name
{
get
{
return name ;
}
}
internal string Signature
{
get
{
return sig ;
}
}
2005-06-01 13:49:30 +04:00
internal bool IsAccessibleFrom ( TypeWrapper referencedType , TypeWrapper caller , TypeWrapper instance )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
if ( referencedType . IsAccessibleFrom ( caller ) )
{
2010-07-15 16:36:58 +04:00
return (
2005-06-01 13:49:30 +04:00
caller = = DeclaringType | |
2010-07-15 16:36:58 +04:00
IsPublicOrProtectedMemberAccessible ( caller , instance ) | |
2009-02-10 10:24:30 +03:00
( IsInternal & & DeclaringType . InternalsVisibleTo ( caller ) ) | |
2008-12-22 08:52:49 +03:00
( ! 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).
2011-11-17 21:32:54 +04:00
& & ( ! HasNonPublicTypeInSignature | | InPracticeInternalsVisibleTo ( caller ) ) ;
2005-06-01 13:49:30 +04:00
}
return false ;
2004-08-17 13:05:21 +04:00
}
2010-07-15 16:36:58 +04:00
private bool IsPublicOrProtectedMemberAccessible ( TypeWrapper caller , TypeWrapper instance )
2010-07-12 10:58:48 +04:00
{
2010-07-15 16:36:58 +04:00
if ( IsPublic | | ( IsProtected & & caller . IsSubTypeOf ( DeclaringType ) & & ( IsStatic | | instance . IsSubTypeOf ( caller ) ) ) )
2010-07-12 10:58:48 +04:00
{
2010-07-15 16:36:58 +04:00
return DeclaringType . IsPublic | | InPracticeInternalsVisibleTo ( caller ) ;
2010-07-12 10:58:48 +04:00
}
return false ;
}
2008-12-22 08:52:49 +03:00
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 ;
}
2011-11-17 17:53:02 +04:00
#endif
#if CLASSGC
if ( DeclaringType is DynamicTypeWrapper )
{
// if we are dynamic, we can just become friends with the caller
DeclaringType . GetClassLoader ( ) . GetTypeWrapperFactory ( ) . AddInternalsVisibleTo ( caller . TypeAsTBD . Assembly ) ;
return true ;
}
2008-12-22 08:52:49 +03:00
#endif
2009-02-10 10:24:30 +03:00
return DeclaringType . InternalsVisibleTo ( caller ) ;
2008-12-22 08:52:49 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsHideFromReflection
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( flags & MemberFlags . HideFromReflection ) ! = 0 ;
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal bool IsExplicitOverride
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( flags & MemberFlags . ExplicitOverride ) ! = 0 ;
}
2005-03-23 12:33:18 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsMirandaMethod
2005-05-17 17:18:16 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( flags & MemberFlags . MirandaMethod ) ! = 0 ;
}
2005-05-17 17:18:16 +04:00
}
2005-08-14 19:49:50 +04:00
internal bool IsAccessStub
{
get
{
return ( flags & MemberFlags . AccessStub ) ! = 0 ;
}
}
2008-04-14 09:13:41 +04:00
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 ;
}
}
}
2008-05-09 09:57:55 +04:00
internal bool IsIntrinsic
{
get
{
return ( flags & MemberFlags . Intrinsic ) ! = 0 ;
}
}
protected void SetIntrinsicFlag ( )
{
flags | = MemberFlags . Intrinsic ;
}
2008-12-22 08:52:49 +03:00
protected void SetNonPublicTypeInSignatureFlag ( )
{
flags | = MemberFlags . NonPublicTypeInSignature ;
}
2011-11-17 21:32:54 +04:00
internal bool HasNonPublicTypeInSignature
{
get { return ( flags & MemberFlags . NonPublicTypeInSignature ) ! = 0 ; }
}
2008-05-31 19:20:29 +04:00
internal bool HasCallerID
{
get
{
return ( flags & MemberFlags . CallerID ) ! = 0 ;
}
}
2005-06-01 13:49:30 +04:00
internal Modifiers Modifiers
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return modifiers ;
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal bool IsStatic
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( modifiers & Modifiers . Static ) ! = 0 ;
}
2003-05-30 16:08:59 +04:00
}
2006-04-05 12:18:58 +04:00
internal bool IsInternal
{
get
{
return ( flags & MemberFlags . InternalAccess ) ! = 0 ;
}
}
2005-06-01 13:49:30 +04:00
internal bool IsPublic
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( modifiers & Modifiers . Public ) ! = 0 ;
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal bool IsPrivate
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( modifiers & Modifiers . Private ) ! = 0 ;
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal bool IsProtected
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( modifiers & Modifiers . Protected ) ! = 0 ;
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal bool IsFinal
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( modifiers & Modifiers . Final ) ! = 0 ;
}
2003-05-30 16:08:59 +04:00
}
}
2003-12-20 01:19:18 +03:00
2008-08-21 10:53:48 +04:00
interface ICustomInvoke
{
2010-01-28 10:14:37 +03:00
#if ! STATIC_COMPILER & & ! FIRST_PASS & & ! STUB_GENERATOR
2008-08-25 08:16:59 +04:00
object Invoke ( object obj , object [ ] args , ikvm . @internal . CallerID callerID ) ;
2008-08-21 10:53:48 +04:00
#endif
}
2005-06-01 13:49:30 +04:00
abstract class MethodWrapper : MemberWrapper
2004-08-17 13:05:21 +04:00
{
2010-01-28 10:14:37 +03:00
#if ! STATIC_COMPILER & & ! FIRST_PASS & & ! STUB_GENERATOR
2008-08-21 10:40:22 +04:00
private static Dictionary < MethodWrapper , sun . reflect . MethodAccessor > invokenonvirtualCache ;
2007-05-29 20:27:08 +04:00
private volatile object reflectionMethod ;
#endif
2005-06-01 13:49:30 +04:00
internal static readonly MethodWrapper [ ] EmptyArray = new MethodWrapper [ 0 ] ;
private MethodBase method ;
private string [ ] declaredExceptions ;
private TypeWrapper returnTypeWrapper ;
private TypeWrapper [ ] parameterTypeWrappers ;
2003-12-20 01:19:18 +03:00
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
internal virtual void EmitCall ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
throw new InvalidOperationException ( ) ;
}
2003-12-20 01:19:18 +03:00
2008-06-03 16:10:07 +04:00
internal virtual void EmitCallvirt ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
throw new InvalidOperationException ( ) ;
}
2004-01-11 16:14:42 +03:00
2008-08-25 08:16:59 +04:00
internal virtual void EmitCallvirtReflect ( CodeEmitter ilgen )
{
EmitCallvirt ( ilgen ) ;
}
2010-09-14 16:29:22 +04:00
internal virtual void EmitNewobj ( CodeEmitter ilgen )
2006-08-26 17:00:50 +04:00
{
2010-09-14 16:29:22 +04:00
throw new InvalidOperationException ( ) ;
2006-08-26 17:00:50 +04:00
}
2010-09-14 18:15:07 +04:00
internal virtual bool EmitIntrinsic ( EmitIntrinsicContext context )
2003-07-31 16:49:29 +04:00
{
2010-09-14 18:15:07 +04:00
return Intrinsics . Emit ( context ) ;
2003-07-31 16:49:29 +04:00
}
2010-01-28 10:14:37 +03:00
#endif // STUB_GENERATOR
2009-08-28 10:47:16 +04:00
2008-03-03 10:05:19 +03:00
internal virtual bool IsDynamicOnly
{
get
{
return false ;
}
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal class GhostMethodWrapper : SmartMethodWrapper
2003-07-31 16:49:29 +04:00
{
2005-06-01 13:49:30 +04:00
private MethodInfo ghostMethod ;
internal GhostMethodWrapper ( 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 )
{
// make sure we weren't handed the ghostMethod in the wrapper value type
Debug . Assert ( method = = null | | method . DeclaringType . IsInterface ) ;
}
private void ResolveGhostMethod ( )
2004-06-14 14:36:38 +04:00
{
2004-08-17 13:05:21 +04:00
if ( ghostMethod = = null )
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
ghostMethod = DeclaringType . TypeAsSignatureType . GetMethod ( this . Name , this . GetParametersForDefineMethod ( ) ) ;
if ( ghostMethod = = null )
{
throw new InvalidOperationException ( "Unable to resolve ghost method" ) ;
}
2004-06-14 14:36:38 +04:00
}
}
2004-08-17 13:05:21 +04:00
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
protected override void CallvirtImpl ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
ResolveGhostMethod ( ) ;
ilgen . Emit ( OpCodes . Call , ghostMethod ) ;
}
2010-01-28 10:14:37 +03:00
#endif
2003-05-30 16:08:59 +04:00
}
2003-07-31 16:49:29 +04:00
2005-06-01 13:49:30 +04:00
internal static MethodWrapper Create ( TypeWrapper declaringType , string name , string sig , MethodBase method , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
2003-07-31 16:49:29 +04:00
{
2005-06-01 13:49:30 +04:00
Debug . Assert ( declaringType ! = null & & name ! = null & & sig ! = null & & method ! = null ) ;
if ( declaringType . IsGhost )
2003-07-31 16:49:29 +04:00
{
2005-06-01 13:49:30 +04:00
// HACK since our caller isn't aware of the ghost issues, we'll handle the method swapping
if ( method . DeclaringType . IsValueType )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
Type [ ] types = new Type [ parameterTypes . Length ] ;
for ( int i = 0 ; i < types . Length ; i + + )
{
types [ i ] = parameterTypes [ i ] . TypeAsSignatureType ;
}
method = declaringType . TypeAsBaseType . GetMethod ( method . Name , types ) ;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
return new GhostMethodWrapper ( declaringType , name , sig , method , returnType , parameterTypes , modifiers , flags ) ;
}
else if ( method is ConstructorInfo )
{
return new SmartConstructorMethodWrapper ( declaringType , name , sig , ( ConstructorInfo ) method , parameterTypes , modifiers , flags ) ;
}
else
{
return new SmartCallMethodWrapper ( declaringType , name , sig , ( MethodInfo ) method , returnType , parameterTypes , modifiers , flags , SimpleOpCode . Call , method . IsStatic ? SimpleOpCode . Call : SimpleOpCode . Callvirt ) ;
2003-07-31 16:49:29 +04:00
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal MethodWrapper ( TypeWrapper declaringType , string name , string sig , MethodBase method , TypeWrapper returnType , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
2005-08-14 19:49:50 +04:00
: base ( declaringType , name , sig , modifiers , flags )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
Profiler . Count ( "MethodWrapper" ) ;
this . method = method ;
Debug . Assert ( ( ( returnType = = null ) = = ( parameterTypes = = null ) ) | | ( returnType = = PrimitiveTypeWrapper . VOID ) ) ;
this . returnTypeWrapper = returnType ;
this . parameterTypeWrappers = parameterTypes ;
2008-05-09 09:57:55 +04:00
if ( Intrinsics . IsIntrinsic ( this ) )
{
SetIntrinsicFlag ( ) ;
}
2008-12-22 08:52:49 +03:00
UpdateNonPublicTypeInSignatureFlag ( ) ;
}
private void UpdateNonPublicTypeInSignatureFlag ( )
{
2011-11-23 10:20:34 +04:00
if ( ( IsPublic | | IsProtected ) & & ( returnTypeWrapper ! = null & & parameterTypeWrappers ! = null ) & & ! ( this is AccessStubMethodWrapper ) )
2008-12-22 08:52:49 +03:00
{
2009-02-04 09:50:22 +03:00
if ( ! returnTypeWrapper . IsPublic & & ! returnTypeWrapper . IsUnloadable )
2008-12-22 08:52:49 +03:00
{
SetNonPublicTypeInSignatureFlag ( ) ;
}
else
{
foreach ( TypeWrapper tw in parameterTypeWrappers )
{
2009-02-04 09:50:22 +03:00
if ( ! tw . IsPublic & & ! tw . IsUnloadable )
2008-12-22 08:52:49 +03:00
{
SetNonPublicTypeInSignatureFlag ( ) ;
break ;
}
}
}
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal void SetDeclaredExceptions ( string [ ] exceptions )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if ( exceptions = = null )
{
exceptions = new string [ 0 ] ;
}
this . declaredExceptions = ( string [ ] ) exceptions . Clone ( ) ;
2003-07-31 16:49:29 +04:00
}
2003-05-30 16:08:59 +04:00
2011-05-12 12:08:08 +04:00
internal string [ ] GetDeclaredExceptions ( )
{
return declaredExceptions ;
}
2010-01-28 10:14:37 +03:00
#if ! STATIC_COMPILER & & ! STUB_GENERATOR
2007-05-29 20:27:08 +04:00
internal object ToMethodOrConstructor ( bool copy )
{
#if FIRST_PASS
return null ;
2008-08-06 16:22:06 +04:00
#else
2007-05-29 20:27:08 +04:00
object method = reflectionMethod ;
if ( method = = null )
{
2011-12-08 11:56:09 +04:00
ClassLoaderWrapper loader = this . DeclaringType . GetClassLoader ( ) ;
2007-05-29 20:27:08 +04:00
TypeWrapper [ ] argTypes = GetParameters ( ) ;
java . lang . Class [ ] parameterTypes = new java . lang . Class [ argTypes . Length ] ;
for ( int i = 0 ; i < argTypes . Length ; i + + )
{
2011-12-08 11:56:09 +04:00
parameterTypes [ i ] = argTypes [ i ] . EnsureLoadable ( loader ) . ClassObject ;
2007-05-29 20:27:08 +04:00
}
2009-12-02 08:48:50 +03:00
java . lang . Class [ ] checkedExceptions = GetExceptions ( ) ;
2007-05-29 20:27:08 +04:00
if ( this . Name = = StringConstants . INIT )
{
2009-12-07 08:38:18 +03:00
method = new java . lang . reflect . Constructor (
2010-05-27 13:25:15 +04:00
this . DeclaringType . ClassObject ,
2007-05-29 20:27:08 +04:00
parameterTypes ,
checkedExceptions ,
( int ) this . Modifiers | ( this . IsInternal ? 0x40000000 : 0 ) ,
Array . IndexOf ( this . DeclaringType . GetMethods ( ) , this ) ,
this . DeclaringType . GetGenericMethodSignature ( this ) ,
2008-03-03 11:28:22 +03:00
null ,
null
2007-05-29 20:27:08 +04:00
) ;
}
else
{
2009-12-07 08:38:18 +03:00
method = new java . lang . reflect . Method (
2010-05-27 13:25:15 +04:00
this . DeclaringType . ClassObject ,
2007-05-29 20:27:08 +04:00
this . Name ,
parameterTypes ,
2011-12-08 11:56:09 +04:00
this . ReturnType . EnsureLoadable ( loader ) . ClassObject ,
2007-05-29 20:27:08 +04:00
checkedExceptions ,
( int ) this . Modifiers | ( this . IsInternal ? 0x40000000 : 0 ) ,
Array . IndexOf ( this . DeclaringType . GetMethods ( ) , this ) ,
this . DeclaringType . GetGenericMethodSignature ( this ) ,
2007-09-10 10:16:49 +04:00
null ,
null ,
null
2007-05-29 20:27:08 +04:00
) ;
}
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 )
{
2009-12-07 08:38:18 +03:00
return ctor . copy ( ) ;
2007-05-29 20:27:08 +04:00
}
2009-12-07 08:38:18 +03:00
return ( ( java . lang . reflect . Method ) method ) . copy ( ) ;
2007-05-29 20:27:08 +04:00
}
return method ;
#endif
}
2009-12-02 08:48:50 +03:00
#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 + + )
{
2010-05-27 13:25:15 +04:00
array [ i ] = this . DeclaringType . GetClassLoader ( ) . LoadClassByDottedName ( classes [ i ] ) . ClassObject ;
2009-12-02 08:48:50 +03:00
}
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
2007-05-29 20:27:08 +04:00
internal static MethodWrapper FromMethodOrConstructor ( object methodOrConstructor )
{
#if FIRST_PASS
return null ;
2008-08-06 16:22:06 +04:00
#else
2007-05-29 20:27:08 +04:00
java . lang . reflect . Method method = methodOrConstructor as java . lang . reflect . Method ;
if ( method ! = null )
{
2007-12-28 17:55:33 +03:00
return TypeWrapper . FromClass ( method . getDeclaringClass ( ) ) . GetMethods ( ) [ method . _slot ( ) ] ;
2007-05-29 20:27:08 +04:00
}
2007-12-28 17:55:33 +03:00
java . lang . reflect . Constructor constructor = ( java . lang . reflect . Constructor ) methodOrConstructor ;
return TypeWrapper . FromClass ( constructor . getDeclaringClass ( ) ) . GetMethods ( ) [ constructor . _slot ( ) ] ;
2007-05-29 20:27:08 +04:00
#endif
}
2010-01-28 10:14:37 +03:00
#endif // !STATIC_COMPILER && !STUB_GENERATOR
2007-05-29 20:27:08 +04:00
2010-04-12 10:38:46 +04:00
[System.Security.SecurityCritical]
2005-06-01 13:49:30 +04:00
internal static MethodWrapper FromCookie ( IntPtr cookie )
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
return ( MethodWrapper ) FromCookieImpl ( cookie ) ;
2003-11-17 15:01:50 +03:00
}
2003-05-30 16:08:59 +04:00
2005-06-01 13:49:30 +04:00
internal bool IsLinked
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
2006-12-05 10:52:25 +03:00
return parameterTypeWrappers ! = null ;
2005-06-01 13:49:30 +04:00
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal void Link ( )
2004-08-17 13:05:21 +04:00
{
2006-05-06 14:46:51 +04:00
lock ( this )
{
if ( parameterTypeWrappers ! = null )
{
return ;
}
}
ClassLoaderWrapper loader = this . DeclaringType . GetClassLoader ( ) ;
2010-01-28 09:37:48 +03:00
TypeWrapper ret = loader . RetTypeWrapperFromSigNoThrow ( Signature ) ;
TypeWrapper [ ] parameters = loader . ArgTypeWrapperListFromSigNoThrow ( Signature ) ;
2005-06-01 13:49:30 +04:00
lock ( this )
2003-06-10 17:28:47 +04:00
{
2011-08-16 17:40:05 +04:00
try
2003-06-10 17:28:47 +04:00
{
2011-08-16 17:40:05 +04:00
// critical code in the finally block to avoid Thread.Abort interrupting the thread
}
finally
{
if ( parameterTypeWrappers = = null )
2004-08-17 13:05:21 +04:00
{
2011-08-16 17:40:05 +04:00
Debug . Assert ( returnTypeWrapper = = null | | returnTypeWrapper = = PrimitiveTypeWrapper . VOID ) ;
returnTypeWrapper = ret ;
parameterTypeWrappers = parameters ;
UpdateNonPublicTypeInSignatureFlag ( ) ;
if ( method = = null )
2005-06-01 13:49:30 +04:00
{
2011-08-16 17:40:05 +04:00
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 ;
}
2005-06-01 13:49:30 +04:00
}
2004-08-17 13:05:21 +04:00
}
2003-06-10 17:28:47 +04:00
}
}
}
2009-03-06 09:43:40 +03:00
protected virtual void DoLinkMethod ( )
{
method = this . DeclaringType . LinkMethod ( this ) ;
}
2005-06-01 13:49:30 +04:00
[Conditional("DEBUG")]
internal void AssertLinked ( )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
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 ) ;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper ReturnType
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
AssertLinked ( ) ;
return returnTypeWrapper ;
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper [ ] GetParameters ( )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
AssertLinked ( ) ;
return parameterTypeWrappers ;
2004-08-17 13:05:21 +04:00
}
2011-12-07 15:28:17 +04:00
#if ! STUB_GENERATOR
internal DefineMethodHelper GetDefineMethodHelper ( )
{
return new DefineMethodHelper ( this ) ;
}
#endif
2005-06-01 13:49:30 +04:00
internal Type ReturnTypeForDefineMethod
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ReturnType . TypeAsSignatureType ;
}
2004-08-17 13:05:21 +04:00
}
2003-05-30 16:08:59 +04:00
2005-06-01 13:49:30 +04:00
internal Type [ ] GetParametersForDefineMethod ( )
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper [ ] wrappers = GetParameters ( ) ;
2008-05-31 19:20:29 +04:00
int len = wrappers . Length ;
if ( HasCallerID )
{
len + + ;
}
Type [ ] temp = new Type [ len ] ;
2005-06-01 13:49:30 +04:00
for ( int i = 0 ; i < wrappers . Length ; i + + )
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
temp [ i ] = wrappers [ i ] . TypeAsSignatureType ;
2003-11-17 15:01:50 +03:00
}
2008-05-31 19:20:29 +04:00
if ( HasCallerID )
{
temp [ len - 1 ] = CoreClasses . ikvm . @internal . CallerID . Wrapper . TypeAsSignatureType ;
}
2005-06-01 13:49:30 +04:00
return temp ;
2003-11-17 15:01:50 +03:00
}
2003-05-30 16:08:59 +04:00
2005-06-01 13:49:30 +04:00
// 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 ( )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
AssertLinked ( ) ;
return method ;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal string RealName
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
AssertLinked ( ) ;
return method . Name ;
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
// this returns the Java method's attributes in .NET terms (e.g. used to create stubs for this method)
internal MethodAttributes GetMethodAttributes ( )
2003-05-30 16:08:59 +04:00
{
2005-09-01 11:34:53 +04:00
MethodAttributes attribs = MethodAttributes . HideBySig ;
2005-06-01 13:49:30 +04:00
if ( IsStatic )
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
attribs | = MethodAttributes . Static ;
2004-06-14 14:36:38 +04:00
}
2005-06-01 13:49:30 +04:00
if ( IsPublic )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
attribs | = MethodAttributes . Public ;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
else if ( IsPrivate )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
attribs | = MethodAttributes . Private ;
}
else if ( IsProtected )
{
attribs | = MethodAttributes . FamORAssem ;
}
else
{
attribs | = MethodAttributes . Family ;
}
// constructors aren't virtual
2005-08-14 19:49:50 +04:00
if ( ! IsStatic & & ! IsPrivate & & Name ! = "<init>" )
2005-06-01 13:49:30 +04:00
{
attribs | = MethodAttributes . Virtual ;
}
if ( IsFinal )
{
attribs | = MethodAttributes . Final ;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
if ( IsAbstract )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
attribs | = MethodAttributes . Abstract ;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
return attribs ;
2003-05-30 16:08:59 +04:00
}
2004-06-14 14:36:38 +04:00
2005-06-01 13:49:30 +04:00
internal bool IsAbstract
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( Modifiers & Modifiers . Abstract ) ! = 0 ;
}
2004-06-14 14:36:38 +04:00
}
2005-06-01 13:49:30 +04:00
2010-01-28 10:14:37 +03:00
#if ! STATIC_COMPILER & & ! STUB_GENERATOR
2005-06-01 13:49:30 +04:00
[HideFromJava]
2010-01-06 17:28:38 +03:00
internal object InvokeJNI ( object obj , object [ ] args , bool nonVirtual , object callerID )
2008-05-31 19:20:29 +04:00
{
#if FIRST_PASS
return null ;
#else
2008-08-21 10:40:22 +04:00
if ( ReferenceEquals ( Name , StringConstants . INIT ) )
{
java . lang . reflect . Constructor cons = ( java . lang . reflect . Constructor ) ToMethodOrConstructor ( false ) ;
if ( obj = = null )
{
sun . reflect . ConstructorAccessor acc = cons . getConstructorAccessor ( ) ;
if ( acc = = null )
{
2009-12-07 08:38:18 +03:00
acc = ( sun . reflect . ConstructorAccessor ) IKVM . NativeCode . sun . reflect . ReflectionFactory . newConstructorAccessor0 ( null , cons ) ;
2008-08-21 10:40:22 +04:00
cons . setConstructorAccessor ( acc ) ;
}
return acc . newInstance ( args ) ;
}
else if ( method is MethodInfo )
{
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
// the type of this exception is a bit random (note that this can only happen through JNI reflection)
throw new java . lang . IncompatibleClassChangeError ( string . Format ( "Remapped type {0} doesn't support constructor invocation on an existing instance" , DeclaringType . Name ) ) ;
}
else if ( ! method . DeclaringType . IsInstanceOfType ( obj ) )
{
// we're trying to initialize an existing instance of a remapped type
throw new NotSupportedException ( "Unable to partially construct object of type " + obj . GetType ( ) . FullName + " to type " + method . DeclaringType . FullName ) ;
}
else
{
try
{
2009-03-08 09:21:14 +03:00
ResolveMethod ( ) ;
2010-01-06 17:28:38 +03:00
InvokeArgsProcessor proc = new InvokeArgsProcessor ( this , method , obj , UnboxArgs ( args ) , ( ikvm . @internal . CallerID ) callerID ) ;
2008-08-21 10:40:22 +04:00
object o = method . Invoke ( proc . GetObj ( ) , proc . GetArgs ( ) ) ;
TypeWrapper retType = this . ReturnType ;
if ( ! retType . IsUnloadable & & retType . IsGhost )
{
o = retType . GhostRefField . GetValue ( o ) ;
}
return o ;
}
catch ( ArgumentException x1 )
{
throw new java . lang . IllegalArgumentException ( x1 . Message ) ;
}
catch ( TargetInvocationException x )
{
throw new java . lang . reflect . InvocationTargetException ( ikvm . runtime . Util . mapException ( x . InnerException ) ) ;
}
}
}
else if ( nonVirtual
& & ! this . IsStatic
& & ! this . IsPrivate
& & ! this . IsAbstract
& & ! this . IsFinal
& & ! this . DeclaringType . IsFinal )
{
2008-08-25 08:16:59 +04:00
if ( this . DeclaringType . IsRemapped & & ! this . DeclaringType . TypeAsBaseType . IsInstanceOfType ( obj ) )
2008-08-21 10:40:22 +04:00
{
ResolveMethod ( ) ;
2008-08-25 08:16:59 +04:00
return InvokeNonvirtualRemapped ( obj , UnboxArgs ( args ) ) ;
2008-08-21 10:40:22 +04:00
}
else
{
if ( invokenonvirtualCache = = null )
{
Interlocked . CompareExchange ( ref invokenonvirtualCache , new Dictionary < MethodWrapper , sun . reflect . MethodAccessor > ( ) , null ) ;
}
sun . reflect . MethodAccessor acc ;
lock ( invokenonvirtualCache )
{
if ( ! invokenonvirtualCache . TryGetValue ( this , out acc ) )
{
acc = new IKVM . NativeCode . sun . reflect . ReflectionFactory . FastMethodAccessorImpl ( ( java . lang . reflect . Method ) ToMethodOrConstructor ( false ) , true ) ;
invokenonvirtualCache . Add ( this , acc ) ;
}
}
2010-01-06 17:28:38 +03:00
object val = acc . invoke ( obj , args , ( ikvm . @internal . CallerID ) callerID ) ;
2008-08-21 10:40:22 +04:00
if ( this . ReturnType . IsPrimitive & & this . ReturnType ! = PrimitiveTypeWrapper . VOID )
{
val = JVM . Unbox ( val ) ;
}
return val ;
}
}
else
{
java . lang . reflect . Method method = ( java . lang . reflect . Method ) ToMethodOrConstructor ( false ) ;
sun . reflect . MethodAccessor acc = method . getMethodAccessor ( ) ;
if ( acc = = null )
{
2009-12-07 08:38:18 +03:00
acc = ( sun . reflect . MethodAccessor ) IKVM . NativeCode . sun . reflect . ReflectionFactory . newMethodAccessor ( null , method ) ;
2008-08-21 10:40:22 +04:00
method . setMethodAccessor ( acc ) ;
}
2010-01-06 17:28:38 +03:00
object val = acc . invoke ( obj , args , ( ikvm . @internal . CallerID ) callerID ) ;
2008-08-21 10:40:22 +04:00
if ( this . ReturnType . IsPrimitive & & this . ReturnType ! = PrimitiveTypeWrapper . VOID )
{
val = JVM . Unbox ( val ) ;
}
return val ;
}
2008-05-31 19:20:29 +04:00
#endif
}
2008-08-21 10:40:22 +04:00
private object [ ] UnboxArgs ( object [ ] args )
{
TypeWrapper [ ] paramTypes = GetParameters ( ) ;
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
if ( paramTypes [ i ] . IsPrimitive )
{
args [ i ] = JVM . Unbox ( args [ i ] ) ;
}
}
return args ;
}
2010-01-28 10:14:37 +03:00
#endif // !STATIC_COMPILER && !STUB_GENERATOR
2008-05-31 19:20:29 +04:00
2010-01-28 10:14:37 +03:00
#if ! STATIC_COMPILER & & ! FIRST_PASS & & ! STUB_GENERATOR
2007-09-24 15:57:00 +04:00
internal void ResolveMethod ( )
{
2005-06-01 13:49:30 +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
{
2007-12-17 10:43:06 +03:00
method = method . Module . ResolveMethod ( ( ( MethodBuilder ) method ) . GetToken ( ) . Token ) ;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
if ( method is ConstructorBuilder )
2003-05-30 16:08:59 +04:00
{
2007-12-17 10:43:06 +03:00
method = method . Module . ResolveMethod ( ( ( ConstructorBuilder ) method ) . GetToken ( ) . Token ) ;
2003-05-30 16:08:59 +04:00
}
2004-06-14 14:36:38 +04:00
}
2005-06-01 13:49:30 +04:00
[HideFromJava]
2008-08-25 08:16:59 +04:00
protected virtual object InvokeNonvirtualRemapped ( object obj , object [ ] args )
2004-08-17 13:05:21 +04:00
{
2008-08-25 08:16:59 +04:00
throw new InvalidOperationException ( ) ;
2004-08-17 13:05:21 +04:00
}
2004-06-14 14:36:38 +04:00
2005-06-01 13:49:30 +04:00
private struct InvokeArgsProcessor
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
private object obj ;
private object [ ] args ;
2004-06-14 14:36:38 +04:00
2008-05-31 19:20:29 +04:00
internal InvokeArgsProcessor ( MethodWrapper mw , MethodBase method , object original_obj , object [ ] original_args , ikvm . @internal . CallerID callerID )
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper [ ] argTypes = mw . GetParameters ( ) ;
if ( ! mw . IsStatic & & method . IsStatic & & mw . Name ! = "<init>" )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
// we've been redirected to a static method, so we have to copy the 'obj' into the args
object [ ] nargs = new object [ original_args . Length + 1 ] ;
nargs [ 0 ] = original_obj ;
original_args . CopyTo ( nargs , 1 ) ;
this . obj = null ;
this . args = nargs ;
for ( int i = 0 ; i < argTypes . Length ; i + + )
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
if ( ! argTypes [ i ] . IsUnloadable & & argTypes [ i ] . IsGhost )
{
object v = Activator . CreateInstance ( argTypes [ i ] . TypeAsSignatureType ) ;
argTypes [ i ] . GhostRefField . SetValue ( v , args [ i + 1 ] ) ;
args [ i + 1 ] = v ;
}
2004-06-14 14:36:38 +04:00
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
else
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
this . obj = original_obj ;
this . args = original_args ;
for ( int i = 0 ; i < argTypes . Length ; i + + )
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
if ( ! argTypes [ i ] . IsUnloadable & & argTypes [ i ] . IsGhost )
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
if ( this . args = = original_args )
{
this . args = ( object [ ] ) args . Clone ( ) ;
}
object v = Activator . CreateInstance ( argTypes [ i ] . TypeAsSignatureType ) ;
argTypes [ i ] . GhostRefField . SetValue ( v , args [ i ] ) ;
this . args [ i ] = v ;
2004-06-14 14:36:38 +04:00
}
}
2003-05-30 16:08:59 +04:00
}
2008-05-31 19:20:29 +04:00
if ( mw . HasCallerID )
{
object [ ] nargs = new object [ args . Length + 1 ] ;
Array . Copy ( args , nargs , args . Length ) ;
nargs [ args . Length ] = callerID ;
args = nargs ;
}
2003-05-30 16:08:59 +04:00
}
2004-06-14 14:36:38 +04:00
2005-06-01 13:49:30 +04:00
internal object GetObj ( )
{
return obj ;
}
internal object [ ] GetArgs ( )
{
return args ;
}
2004-06-14 14:36:38 +04:00
}
2010-01-28 10:14:37 +03:00
#endif // !STATIC_COMPILER && !FIRST_PASS && !STUB_GENERATOR
2004-06-14 14:36:38 +04:00
2005-06-01 13:49:30 +04:00
internal static OpCode SimpleOpCodeToOpCode ( SimpleOpCode opc )
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
switch ( opc )
{
case SimpleOpCode . Call :
return OpCodes . Call ;
case SimpleOpCode . Callvirt :
return OpCodes . Callvirt ;
case SimpleOpCode . Newobj :
return OpCodes . Newobj ;
default :
throw new InvalidOperationException ( ) ;
}
2003-05-30 16:08:59 +04:00
}
2010-01-28 09:52:51 +03:00
internal virtual bool IsOptionalAttributeAnnotationValue
{
get { return false ; }
}
2003-05-30 16:08:59 +04:00
}
2005-01-03 11:26:21 +03:00
2009-07-16 10:26:47 +04: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 ( ) ;
}
}
2005-06-01 13:49:30 +04:00
class SmartMethodWrapper : MethodWrapper
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
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 )
2005-01-03 11:26:21 +03:00
{
}
2003-05-30 16:08:59 +04:00
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
protected virtual void PreEmit ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
}
2008-06-03 16:10:07 +04:00
internal sealed override void EmitCall ( CodeEmitter ilgen )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
AssertLinked ( ) ;
PreEmit ( ilgen ) ;
2004-08-17 13:05:21 +04:00
CallImpl ( ilgen ) ;
}
2005-06-01 13:49:30 +04:00
2008-06-03 16:10:07 +04:00
protected virtual void CallImpl ( CodeEmitter ilgen )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
throw new InvalidOperationException ( ) ;
2004-08-17 13:05:21 +04:00
}
2008-06-03 16:10:07 +04:00
internal sealed override void EmitCallvirt ( CodeEmitter ilgen )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
AssertLinked ( ) ;
PreEmit ( ilgen ) ;
if ( DeclaringType . IsNonPrimitiveValueType )
{
// callvirt isn't allowed on a value type
// TODO we need to check for a null reference
CallImpl ( ilgen ) ;
}
else
{
CallvirtImpl ( ilgen ) ;
}
2004-08-17 13:05:21 +04:00
}
2008-06-03 16:10:07 +04:00
protected virtual void CallvirtImpl ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
throw new InvalidOperationException ( ) ;
}
2004-08-17 13:05:21 +04:00
2010-09-14 16:29:22 +04:00
internal sealed override void EmitNewobj ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
AssertLinked ( ) ;
PreEmit ( ilgen ) ;
NewobjImpl ( ilgen ) ;
if ( DeclaringType . IsNonPrimitiveValueType )
{
DeclaringType . EmitBox ( ilgen ) ;
}
}
2004-08-17 13:05:21 +04:00
2008-06-03 16:10:07 +04:00
protected virtual void NewobjImpl ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
throw new InvalidOperationException ( ) ;
}
2010-01-28 10:14:37 +03:00
#endif // STUB_GENERATOR
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
enum SimpleOpCode : byte
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
Call ,
Callvirt ,
Newobj
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
sealed class SimpleCallMethodWrapper : MethodWrapper
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
private SimpleOpCode call ;
private SimpleOpCode callvirt ;
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
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 ;
}
2004-08-17 13:05:21 +04:00
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
internal override void EmitCall ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
ilgen . Emit ( SimpleOpCodeToOpCode ( call ) , ( MethodInfo ) GetMethod ( ) ) ;
}
2004-08-17 13:05:21 +04:00
2008-06-03 16:10:07 +04:00
internal override void EmitCallvirt ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
ilgen . Emit ( SimpleOpCodeToOpCode ( callvirt ) , ( MethodInfo ) GetMethod ( ) ) ;
}
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
sealed class SmartCallMethodWrapper : SmartMethodWrapper
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
private SimpleOpCode call ;
private SimpleOpCode callvirt ;
2003-12-20 01:19:18 +03:00
2005-06-01 13:49:30 +04:00
internal SmartCallMethodWrapper ( 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 ;
}
2003-12-20 01:19:18 +03:00
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
protected override void CallImpl ( CodeEmitter ilgen )
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
ilgen . Emit ( SimpleOpCodeToOpCode ( call ) , ( MethodInfo ) GetMethod ( ) ) ;
2003-12-20 01:19:18 +03:00
}
2008-06-03 16:10:07 +04:00
protected override void CallvirtImpl ( CodeEmitter ilgen )
2003-12-24 14:51:41 +03:00
{
2005-06-01 13:49:30 +04:00
ilgen . Emit ( SimpleOpCodeToOpCode ( callvirt ) , ( MethodInfo ) GetMethod ( ) ) ;
2003-12-24 14:51:41 +03:00
}
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2003-12-24 14:51:41 +03:00
}
2005-06-01 13:49:30 +04:00
sealed class SmartConstructorMethodWrapper : SmartMethodWrapper
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
internal SmartConstructorMethodWrapper ( TypeWrapper declaringType , string name , string sig , ConstructorInfo method , TypeWrapper [ ] parameterTypes , Modifiers modifiers , MemberFlags flags )
: base ( declaringType , name , sig , method , PrimitiveTypeWrapper . VOID , parameterTypes , modifiers , flags )
{
}
2003-12-20 01:19:18 +03:00
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
protected override void CallImpl ( CodeEmitter ilgen )
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
ilgen . Emit ( OpCodes . Call , ( ConstructorInfo ) GetMethod ( ) ) ;
2003-12-20 01:19:18 +03:00
}
2008-06-03 16:10:07 +04:00
protected override void NewobjImpl ( CodeEmitter ilgen )
2005-06-01 13:49:30 +04:00
{
ilgen . Emit ( OpCodes . Newobj , ( ConstructorInfo ) GetMethod ( ) ) ;
}
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2004-10-04 23:30:53 +04:00
}
2011-11-18 19:22:46 +04:00
sealed class AccessStubMethodWrapper : SmartMethodWrapper
{
2011-11-23 10:20:34 +04:00
private readonly MethodInfo stubVirtual ;
2011-11-18 19:22:46 +04:00
private readonly MethodInfo stubNonVirtual ;
2011-11-23 10:20:34 +04:00
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 )
2011-11-18 19:22:46 +04:00
{
2011-11-23 10:20:34 +04:00
this . stubVirtual = stubVirtual ;
2011-11-18 19:22:46 +04:00
this . stubNonVirtual = stubNonVirtual ;
}
#if ! STUB_GENERATOR
protected override void CallImpl ( CodeEmitter ilgen )
{
ilgen . Emit ( OpCodes . Call , stubNonVirtual ) ;
}
protected override void CallvirtImpl ( CodeEmitter ilgen )
{
2011-11-23 10:20:34 +04:00
ilgen . Emit ( OpCodes . Callvirt , stubVirtual ) ;
2011-11-18 19:22:46 +04:00
}
#endif // !STUB_GENERATOR
}
2005-06-01 13:49:30 +04:00
abstract class FieldWrapper : MemberWrapper
2003-05-30 16:08:59 +04:00
{
2010-01-28 10:14:37 +03:00
#if ! STATIC_COMPILER & & ! FIRST_PASS & & ! STUB_GENERATOR
2009-12-07 08:49:36 +03:00
private volatile java . lang . reflect . Field reflectionField ;
2008-08-21 10:40:22 +04:00
private sun . reflect . FieldAccessor jniAccessor ;
2007-05-29 20:27:08 +04:00
#endif
2005-06-01 13:49:30 +04:00
internal static readonly FieldWrapper [ ] EmptyArray = new FieldWrapper [ 0 ] ;
private FieldInfo field ;
private TypeWrapper fieldType ;
2003-05-30 16:08:59 +04:00
2005-08-14 19:49:50 +04:00
internal FieldWrapper ( TypeWrapper declaringType , TypeWrapper fieldType , string name , string sig , Modifiers modifiers , FieldInfo field , MemberFlags flags )
: base ( declaringType , name , sig , modifiers , flags )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
Debug . Assert ( name ! = null ) ;
Debug . Assert ( sig ! = null ) ;
this . fieldType = fieldType ;
this . field = field ;
2008-12-22 08:52:49 +03:00
UpdateNonPublicTypeInSignatureFlag ( ) ;
2003-05-30 16:08:59 +04:00
}
2006-04-05 12:18:58 +04:00
internal FieldWrapper ( TypeWrapper declaringType , TypeWrapper fieldType , string name , string sig , ExModifiers modifiers , FieldInfo field )
: this ( declaringType , fieldType , name , sig , modifiers . Modifiers , field ,
2006-10-10 20:24:48 +04:00
( modifiers . IsInternal ? MemberFlags . InternalAccess : MemberFlags . None ) )
2005-08-14 19:49:50 +04:00
{
}
2008-12-22 08:52:49 +03:00
private void UpdateNonPublicTypeInSignatureFlag ( )
{
2009-11-13 18:08:20 +03:00
if ( ( IsPublic | | IsProtected ) & & fieldType ! = null & & ! IsAccessStub )
2008-12-22 08:52:49 +03:00
{
2009-02-04 09:50:22 +03:00
if ( ! fieldType . IsPublic & & ! fieldType . IsUnloadable )
2008-12-22 08:52:49 +03:00
{
SetNonPublicTypeInSignatureFlag ( ) ;
}
}
}
2005-06-01 13:49:30 +04:00
internal FieldInfo GetField ( )
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
AssertLinked ( ) ;
return field ;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
[Conditional("DEBUG")]
internal void AssertLinked ( )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
if ( fieldType = = null )
{
2005-08-14 19:49:50 +04:00
Tracer . Error ( Tracer . Runtime , "AssertLinked failed: " + this . DeclaringType . Name + "::" + this . Name + " (" + this . Signature + ")" ) ;
2005-06-01 13:49:30 +04:00
}
2005-08-14 19:49:50 +04:00
Debug . Assert ( fieldType ! = null , this . DeclaringType . Name + "::" + this . Name + " (" + this . Signature + ")" ) ;
2003-05-30 16:08:59 +04:00
}
2004-08-17 13:05:21 +04:00
2010-01-28 10:14:37 +03:00
#if ! STATIC_COMPILER & & ! STUB_GENERATOR
2005-06-01 13:49:30 +04:00
// NOTE used (thru IKVM.Runtime.Util.GetFieldConstantValue) by ikvmstub to find out if the
// field is a constant (and if it is, to get its value)
internal object GetConstant ( )
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
AssertLinked ( ) ;
2010-01-28 11:44:57 +03:00
// only primitives and string can be literals in Java (because the other "primitives" (like uint),
2005-06-01 13:49:30 +04:00
// are treated as NonPrimitiveValueTypes)
2010-01-28 11:44:57 +03:00
if ( field ! = null & & field . IsLiteral & & ( fieldType . IsPrimitive | | fieldType = = CoreClasses . java . lang . String . Wrapper ) )
2004-08-17 13:05:21 +04:00
{
2010-01-28 11:44:57 +03:00
object val = field . GetRawConstantValue ( ) ;
if ( field . FieldType . IsEnum )
2005-06-01 13:49:30 +04:00
{
2010-01-28 11:44:57 +03:00
val = EnumHelper . GetPrimitiveValue ( EnumHelper . GetUnderlyingType ( field . FieldType ) , val ) ;
2004-08-17 13:05:21 +04:00
}
2010-01-28 11:44:57 +03:00
if ( fieldType . IsPrimitive )
2004-08-17 13:05:21 +04:00
{
2007-12-19 14:28:09 +03:00
return JVM . Box ( val ) ;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
return val ;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
return null ;
2004-08-17 13:05:21 +04:00
}
2007-05-29 20:27:08 +04:00
internal static FieldWrapper FromField ( object field )
{
#if FIRST_PASS
return null ;
2008-08-06 16:22:06 +04:00
#else
2007-05-29 20:27:08 +04:00
java . lang . reflect . Field f = ( java . lang . reflect . Field ) field ;
2010-04-28 18:22:51 +04:00
return TypeWrapper . FromClass ( f . getDeclaringClass ( ) ) . GetFields ( ) [ f . _slot ( ) ] ;
2007-05-29 20:27:08 +04:00
#endif
}
internal object ToField ( bool copy )
{
#if FIRST_PASS
return null ;
2008-08-06 16:22:06 +04:00
#else
2009-12-07 08:49:36 +03:00
java . lang . reflect . Field field = reflectionField ;
2007-05-29 20:27:08 +04:00
if ( field = = null )
{
2009-12-07 08:38:18 +03:00
field = new java . lang . reflect . Field (
2010-05-27 13:25:15 +04:00
this . DeclaringType . ClassObject ,
2007-05-29 20:27:08 +04:00
this . Name ,
2011-12-08 11:56:09 +04:00
this . FieldTypeWrapper . EnsureLoadable ( this . DeclaringType . GetClassLoader ( ) ) . ClassObject ,
2007-05-29 20:27:08 +04:00
( int ) this . Modifiers | ( this . IsInternal ? 0x40000000 : 0 ) ,
Array . IndexOf ( this . DeclaringType . GetFields ( ) , this ) ,
this . DeclaringType . GetGenericFieldSignature ( this ) ,
2008-03-03 11:28:22 +03:00
null
2007-05-29 20:27:08 +04:00
) ;
}
lock ( this )
{
if ( reflectionField = = null )
{
reflectionField = field ;
}
else
{
field = reflectionField ;
}
}
if ( copy )
{
2009-12-07 08:49:36 +03:00
field = field . copy ( ) ;
2007-05-29 20:27:08 +04:00
}
return field ;
#endif // FIRST_PASS
}
2010-01-28 10:14:37 +03:00
#endif // !STATIC_COMPILER && !STUB_GENERATOR
2004-08-17 13:05:21 +04:00
2010-04-12 10:38:46 +04:00
[System.Security.SecurityCritical]
2005-06-01 13:49:30 +04:00
internal static FieldWrapper FromCookie ( IntPtr cookie )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
return ( FieldWrapper ) FromCookieImpl ( cookie ) ;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper FieldTypeWrapper
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
AssertLinked ( ) ;
return fieldType ;
}
2003-05-30 16:08:59 +04:00
}
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
internal void EmitGet ( CodeEmitter ilgen )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
AssertLinked ( ) ;
EmitGetImpl ( ilgen ) ;
2003-05-30 16:08:59 +04:00
}
2008-06-03 16:10:07 +04:00
protected abstract void EmitGetImpl ( CodeEmitter ilgen ) ;
2003-10-17 12:08:31 +04:00
2008-06-03 16:10:07 +04:00
internal void EmitSet ( CodeEmitter ilgen )
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
AssertLinked ( ) ;
EmitSetImpl ( ilgen ) ;
2003-10-17 12:08:31 +04:00
}
2008-06-03 16:10:07 +04:00
protected abstract void EmitSetImpl ( CodeEmitter ilgen ) ;
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2005-06-01 13:49:30 +04:00
internal void Link ( )
2004-10-04 23:30:53 +04:00
{
2006-05-06 14:46:51 +04:00
lock ( this )
{
if ( fieldType ! = null )
{
return ;
}
}
2010-01-28 09:37:48 +03:00
TypeWrapper fld = this . DeclaringType . GetClassLoader ( ) . FieldTypeWrapperFromSigNoThrow ( Signature ) ;
2005-06-01 13:49:30 +04:00
lock ( this )
{
2011-08-16 17:40:05 +04:00
try
2005-06-01 13:49:30 +04:00
{
2011-08-16 17:40:05 +04:00
// critical code in the finally block to avoid Thread.Abort interrupting the thread
}
finally
{
if ( fieldType = = null )
2005-06-01 13:49:30 +04:00
{
2011-08-16 17:40:05 +04:00
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 ;
}
2005-06-01 13:49:30 +04:00
}
}
}
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
internal bool IsVolatile
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ( Modifiers & Modifiers . Volatile ) ! = 0 ;
}
2003-10-17 12:08:31 +04:00
}
2003-06-10 17:28:47 +04:00
2006-04-05 12:18:58 +04:00
internal static FieldWrapper Create ( TypeWrapper declaringType , TypeWrapper fieldType , FieldInfo fi , string name , string sig , ExModifiers modifiers )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
// volatile long & double field accesses must be made atomic
2006-04-05 12:18:58 +04:00
if ( ( modifiers . Modifiers & Modifiers . Volatile ) ! = 0 & & ( sig = = "J" | | sig = = "D" ) )
2005-06-01 13:49:30 +04:00
{
return new VolatileLongDoubleFieldWrapper ( declaringType , fieldType , fi , name , sig , modifiers ) ;
}
return new SimpleFieldWrapper ( declaringType , fieldType , fi , name , sig , modifiers ) ;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
2010-01-28 10:14:37 +03:00
#if ! STATIC_COMPILER & & ! STUB_GENERATOR
2008-04-14 09:13:41 +04:00
internal virtual void ResolveField ( )
2006-10-04 13:03:18 +04:00
{
FieldBuilder fb = field as FieldBuilder ;
if ( fb ! = null )
{
2007-12-17 10:43:06 +03:00
field = field . Module . ResolveField ( fb . GetToken ( ) . Token ) ;
2003-12-24 14:51:41 +03:00
}
2003-06-10 17:28:47 +04:00
}
2005-06-01 13:49:30 +04:00
2008-08-21 10:40:22 +04:00
internal object GetFieldAccessorJNI ( )
{
#if FIRST_PASS
return null ;
#else
if ( jniAccessor = = null )
{
2009-12-02 10:49:36 +03:00
jniAccessor = IKVM . NativeCode . sun . reflect . ReflectionFactory . NewFieldAccessorJNI ( this ) ;
2008-08-21 10:40:22 +04:00
}
return jniAccessor ;
#endif
}
2010-01-28 10:14:37 +03:00
#endif // !STATIC_COMPILER && !STUB_GENERATOR
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
sealed class SimpleFieldWrapper : FieldWrapper
2004-10-04 23:30:53 +04:00
{
2006-04-05 12:18:58 +04:00
internal SimpleFieldWrapper ( TypeWrapper declaringType , TypeWrapper fieldType , FieldInfo fi , string name , string sig , ExModifiers modifiers )
2005-06-01 13:49:30 +04:00
: base ( declaringType , fieldType , name , sig , modifiers , fi )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
Debug . Assert ( ! ( fieldType = = PrimitiveTypeWrapper . DOUBLE | | fieldType = = PrimitiveTypeWrapper . LONG ) | | ! IsVolatile ) ;
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
protected override void EmitGetImpl ( CodeEmitter ilgen )
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
if ( ! IsStatic & & 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
}
2005-06-01 13:49:30 +04:00
if ( IsVolatile )
{
ilgen . Emit ( OpCodes . Volatile ) ;
}
ilgen . Emit ( IsStatic ? OpCodes . Ldsfld : OpCodes . Ldfld , GetField ( ) ) ;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
2008-06-03 16:10:07 +04:00
protected override void EmitSetImpl ( CodeEmitter ilgen )
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
FieldInfo fi = GetField ( ) ;
if ( ! IsStatic & & DeclaringType . IsNonPrimitiveValueType )
{
2010-09-29 11:21:51 +04:00
CodeEmitterLocal temp = ilgen . DeclareLocal ( FieldTypeWrapper . TypeAsSignatureType ) ;
2005-06-01 13:49:30 +04:00
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 ) ;
2010-10-21 16:20:13 +04:00
if ( IsVolatile )
{
ilgen . EmitMemoryBarrier ( ) ;
}
2003-05-30 16:08:59 +04:00
}
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2003-05-30 16:08:59 +04:00
}
2003-11-17 15:01:50 +03:00
2005-06-01 13:49:30 +04:00
sealed class VolatileLongDoubleFieldWrapper : FieldWrapper
2005-01-03 11:26:21 +03:00
{
2006-04-05 12:18:58 +04:00
internal VolatileLongDoubleFieldWrapper ( TypeWrapper declaringType , TypeWrapper fieldType , FieldInfo fi , string name , string sig , ExModifiers modifiers )
2005-06-01 13:49:30 +04:00
: base ( declaringType , fieldType , name , sig , modifiers , fi )
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
Debug . Assert ( IsVolatile ) ;
Debug . Assert ( sig = = "J" | | sig = = "D" ) ;
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
protected override void EmitGetImpl ( CodeEmitter ilgen )
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
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 ) ;
}
2005-08-03 16:59:16 +04:00
if ( FieldTypeWrapper = = PrimitiveTypeWrapper . DOUBLE )
2005-06-01 13:49:30 +04:00
{
2006-07-26 18:16:52 +04:00
ilgen . Emit ( OpCodes . Call , ByteCodeHelperMethods . volatileReadDouble ) ;
2005-06-01 13:49:30 +04:00
}
else
{
2005-08-03 16:59:16 +04:00
Debug . Assert ( FieldTypeWrapper = = PrimitiveTypeWrapper . LONG ) ;
2006-07-26 18:16:52 +04:00
ilgen . Emit ( OpCodes . Call , ByteCodeHelperMethods . volatileReadLong ) ;
2005-06-01 13:49:30 +04:00
}
2004-08-17 13:05:21 +04:00
}
2008-06-03 16:10:07 +04:00
protected override void EmitSetImpl ( CodeEmitter ilgen )
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
FieldInfo fi = GetField ( ) ;
2010-09-29 11:21:51 +04:00
CodeEmitterLocal temp = ilgen . DeclareLocal ( FieldTypeWrapper . TypeAsSignatureType ) ;
2004-11-04 15:50:28 +03:00
ilgen . Emit ( OpCodes . Stloc , temp ) ;
2005-06-01 13:49:30 +04:00
if ( fi . IsStatic )
{
ilgen . Emit ( OpCodes . Ldsflda , fi ) ;
}
else
{
if ( DeclaringType . IsNonPrimitiveValueType )
{
ilgen . Emit ( OpCodes . Unbox , DeclaringType . TypeAsTBD ) ;
}
ilgen . Emit ( OpCodes . Ldflda , fi ) ;
}
2004-10-04 23:30:53 +04:00
ilgen . Emit ( OpCodes . Ldloc , temp ) ;
2005-08-03 16:59:16 +04:00
if ( FieldTypeWrapper = = PrimitiveTypeWrapper . DOUBLE )
2005-06-01 13:49:30 +04:00
{
2006-07-26 18:16:52 +04:00
ilgen . Emit ( OpCodes . Call , ByteCodeHelperMethods . volatileWriteDouble ) ;
2005-06-01 13:49:30 +04:00
}
else
{
2005-08-03 16:59:16 +04:00
Debug . Assert ( FieldTypeWrapper = = PrimitiveTypeWrapper . LONG ) ;
2006-07-26 18:16:52 +04:00
ilgen . Emit ( OpCodes . Call , ByteCodeHelperMethods . volatileWriteLong ) ;
2005-06-01 13:49:30 +04:00
}
2004-08-17 13:05:21 +04:00
}
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2004-10-04 23:30:53 +04:00
}
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-04-14 09:13:41 +04:00
// 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 ) ;
}
2008-05-31 19:20:29 +04:00
#if ! STATIC_COMPILER & & ! FIRST_PASS
2008-04-14 09:13:41 +04:00
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
}
2008-06-03 16:10:07 +04:00
protected override void EmitGetImpl ( CodeEmitter ilgen )
2008-04-14 09:13:41 +04:00
{
if ( getter = = null )
{
EmitThrowNoSuchMethodErrorForGetter ( ilgen , this . FieldTypeWrapper , this . IsStatic ) ;
}
else if ( getter . IsStatic )
{
getter . EmitCall ( ilgen ) ;
}
else
{
getter . EmitCallvirt ( ilgen ) ;
}
}
2008-06-03 16:10:07 +04:00
internal static void EmitThrowNoSuchMethodErrorForGetter ( CodeEmitter ilgen , TypeWrapper type , bool isStatic )
2008-04-14 09:13:41 +04:00
{
// HACK the branch around the throw is to keep the verifier happy
2008-06-03 16:10:07 +04:00
CodeEmitterLabel label = ilgen . DefineLabel ( ) ;
2008-04-14 09:13:41 +04:00
ilgen . Emit ( OpCodes . Ldc_I4_0 ) ;
ilgen . Emit ( OpCodes . Brtrue_S , label ) ;
2009-08-31 09:02:34 +04:00
ilgen . EmitThrow ( "java.lang.NoSuchMethodError" ) ;
2008-04-14 09:13:41 +04:00
ilgen . MarkLabel ( label ) ;
if ( ! isStatic )
{
ilgen . Emit ( OpCodes . Pop ) ;
}
ilgen . Emit ( OpCodes . Ldloc , ilgen . DeclareLocal ( type . TypeAsLocalOrStackType ) ) ;
}
2008-06-03 16:10:07 +04:00
protected override void EmitSetImpl ( CodeEmitter ilgen )
2008-04-14 09:13:41 +04:00
{
if ( setter = = null )
{
if ( this . IsFinal )
{
2010-10-01 12:11:49 +04:00
ilgen . Emit ( OpCodes . Pop ) ;
2008-04-14 09:13:41 +04:00
if ( ! this . IsStatic )
{
2010-10-01 12:11:49 +04:00
ilgen . Emit ( OpCodes . Pop ) ;
2008-04-14 09:13:41 +04:00
}
}
else
{
EmitThrowNoSuchMethodErrorForSetter ( ilgen , this . IsStatic ) ;
}
}
else if ( setter . IsStatic )
{
setter . EmitCall ( ilgen ) ;
}
else
{
setter . EmitCallvirt ( ilgen ) ;
}
}
2008-06-03 16:10:07 +04:00
internal static void EmitThrowNoSuchMethodErrorForSetter ( CodeEmitter ilgen , bool isStatic )
2008-04-14 09:13:41 +04:00
{
// HACK the branch around the throw is to keep the verifier happy
2008-06-03 16:10:07 +04:00
CodeEmitterLabel label = ilgen . DefineLabel ( ) ;
2008-04-14 09:13:41 +04:00
ilgen . Emit ( OpCodes . Ldc_I4_0 ) ;
ilgen . Emit ( OpCodes . Brtrue_S , label ) ;
2009-08-31 09:02:34 +04:00
ilgen . EmitThrow ( "java.lang.NoSuchMethodError" ) ;
2008-04-14 09:13:41 +04:00
ilgen . MarkLabel ( label ) ;
ilgen . Emit ( OpCodes . Pop ) ;
if ( ! isStatic )
{
ilgen . Emit ( OpCodes . Pop ) ;
}
}
}
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2008-04-14 09:13:41 +04:00
// 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 ;
}
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
protected override void EmitGetImpl ( CodeEmitter ilgen )
2008-04-14 09:13:41 +04:00
{
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 ) ;
}
}
2008-06-03 16:10:07 +04:00
protected override void EmitSetImpl ( CodeEmitter ilgen )
2008-04-14 09:13:41 +04:00
{
MethodInfo setter = property . GetSetMethod ( true ) ;
if ( setter = = null )
{
if ( this . IsFinal )
{
2010-10-01 12:11:49 +04:00
ilgen . Emit ( OpCodes . Pop ) ;
2008-04-14 09:13:41 +04:00
if ( ! this . IsStatic )
{
2010-10-01 12:11:49 +04:00
ilgen . Emit ( OpCodes . Pop ) ;
2008-04-14 09:13:41 +04:00
}
}
else
{
DynamicPropertyFieldWrapper . EmitThrowNoSuchMethodErrorForSetter ( ilgen , this . IsStatic ) ;
}
}
else if ( setter . IsStatic )
{
ilgen . Emit ( OpCodes . Call , setter ) ;
}
else
{
ilgen . Emit ( OpCodes . Callvirt , setter ) ;
}
}
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2008-04-14 09:13:41 +04:00
internal PropertyInfo GetProperty ( )
{
return property ;
}
}
2005-06-01 13:49:30 +04:00
sealed class ConstantFieldWrapper : FieldWrapper
{
2009-11-09 08:33:09 +03:00
// 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)
2005-06-01 13:49:30 +04:00
private object constant ;
2005-08-14 19:49:50 +04:00
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 )
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
Debug . Assert ( IsStatic ) ;
2009-12-29 14:24:57 +03:00
Debug . Assert ( constant = = null | | constant . GetType ( ) . IsPrimitive | | constant is string ) ;
2005-06-01 13:49:30 +04:00
this . constant = constant ;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
protected override void EmitGetImpl ( CodeEmitter ilgen )
2004-12-21 13:26:51 +03:00
{
2005-08-24 12:14:23 +04:00
// Reading a field should trigger the cctor, but since we're inlining the value
// we have to trigger it explicitly
2007-11-26 14:01:29 +03:00
DeclaringType . EmitRunClassConstructor ( ilgen ) ;
2005-08-24 12:14:23 +04:00
2005-06-01 13:49:30 +04:00
// 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)
2006-10-10 20:24:48 +04:00
object v = GetConstantValue ( ) ;
2005-06-01 13:49:30 +04:00
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 . Emit ( OpCodes . Ldc_I4 , ( ( IConvertible ) constant ) . ToInt32 ( 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 )
2004-12-21 13:26:51 +03:00
{
ilgen . Emit ( OpCodes . Ldc_I8 , ( long ) constant ) ;
}
2005-06-01 13:49:30 +04:00
else if ( constant is uint )
{
ilgen . Emit ( OpCodes . Ldc_I4 , unchecked ( ( int ) ( ( IConvertible ) constant ) . ToUInt32 ( null ) ) ) ;
}
else if ( constant is ulong )
{
ilgen . Emit ( OpCodes . Ldc_I8 , unchecked ( ( long ) ( ulong ) constant ) ) ;
}
2004-12-21 13:26:51 +03:00
else
{
2005-06-01 13:49:30 +04:00
throw new InvalidOperationException ( constant . GetType ( ) . FullName ) ;
2004-12-21 13:26:51 +03:00
}
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
2008-06-03 16:10:07 +04:00
protected override void EmitSetImpl ( CodeEmitter ilgen )
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
// 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
2010-10-01 12:11:49 +04:00
ilgen . Emit ( OpCodes . Pop ) ;
2004-10-04 23:30:53 +04:00
}
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2009-08-28 10:47:16 +04:00
2006-10-10 20:24:48 +04:00
internal object GetConstantValue ( )
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
if ( constant = = null )
{
2007-03-13 10:44:23 +03:00
FieldInfo field = GetField ( ) ;
2009-11-09 08:33:09 +03:00
constant = field . GetRawConstantValue ( ) ;
2005-06-01 13:49:30 +04:00
}
return constant ;
2003-11-17 15:01:50 +03:00
}
}
2005-08-14 19:49:50 +04:00
sealed class CompiledAccessStubFieldWrapper : FieldWrapper
{
private MethodInfo getter ;
private 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 ;
}
2011-11-25 16:03:57 +04:00
// 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 )
2005-08-14 19:49:50 +04:00
{
this . getter = property . GetGetMethod ( true ) ;
this . setter = property . GetSetMethod ( true ) ;
}
2010-01-28 10:14:37 +03:00
#if ! STUB_GENERATOR
2008-06-03 16:10:07 +04:00
protected override void EmitGetImpl ( CodeEmitter ilgen )
2005-08-14 19:49:50 +04:00
{
ilgen . Emit ( OpCodes . Call , getter ) ;
}
2008-06-03 16:10:07 +04:00
protected override void EmitSetImpl ( CodeEmitter ilgen )
2005-08-14 19:49:50 +04:00
{
ilgen . Emit ( OpCodes . Call , setter ) ;
}
2010-01-28 10:14:37 +03:00
#endif // !STUB_GENERATOR
2005-08-14 19:49:50 +04:00
}
2003-05-30 16:08:59 +04:00
}