2006-02-23 16:20:51 +03:00
/ *
2012-01-26 10:43:40 +04:00
Copyright ( C ) 2002 - 2012 Jeroen Frijters
2006-02-23 16:20:51 +03: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
* /
2006-04-12 17:01:13 +04:00
2006-02-23 16:20:51 +03:00
using System ;
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 ;
2006-02-23 16:20:51 +03:00
using System.Resources ;
using System.IO ;
2008-08-08 10:26:37 +04:00
using System.Collections.Generic ;
2006-02-23 16:20:51 +03:00
using System.Xml ;
using System.Diagnostics ;
using System.Text.RegularExpressions ;
using System.Text ;
using System.Threading ;
using IKVM.Attributes ;
2007-03-15 11:04:35 +03:00
using System.Security.Permissions ;
using System.Security ;
2008-12-23 10:11:29 +03:00
using System.Runtime.CompilerServices ;
2006-02-23 16:20:51 +03:00
namespace IKVM.Internal
{
2012-08-06 16:12:03 +04:00
sealed class CompilerClassLoader : ClassLoaderWrapper
2006-02-23 16:20:51 +03:00
{
2012-03-24 12:54:12 +04:00
private Dictionary < string , ClassItem > classes ;
2011-12-14 11:56:53 +04:00
private Dictionary < string , RemapperTypeWrapper > remapped = new Dictionary < string , RemapperTypeWrapper > ( ) ;
2006-02-23 16:20:51 +03:00
private string assemblyName ;
private string assemblyFile ;
private string assemblyDir ;
private bool targetIsModule ;
private AssemblyBuilder assemblyBuilder ;
private IKVM . Internal . MapXml . Attribute [ ] assemblyAttributes ;
private CompilerOptions options ;
2006-08-14 11:57:03 +04:00
private AssemblyClassLoader [ ] referencedAssemblies ;
2008-08-08 10:26:37 +04:00
private Dictionary < string , string > nameMappings = new Dictionary < string , string > ( ) ;
2008-12-23 10:11:29 +03:00
private Dictionary < string , string > packages ;
2008-08-08 10:26:37 +04:00
private Dictionary < string , List < TypeWrapper > > ghosts ;
2006-08-29 15:56:09 +04:00
private TypeWrapper [ ] mappedExceptions ;
private bool [ ] mappedExceptionsAllSubClasses ;
2008-08-14 11:42:56 +04:00
private Dictionary < string , IKVM . Internal . MapXml . Class > mapxml_Classes ;
private Dictionary < MethodKey , IKVM . Internal . MapXml . InstructionList > mapxml_MethodBodies ;
private Dictionary < MethodKey , IKVM . Internal . MapXml . ReplaceMethodCall [ ] > mapxml_ReplacedMethods ;
2011-05-12 14:15:52 +04:00
private Dictionary < MethodKey , IKVM . Internal . MapXml . InstructionList > mapxml_MethodPrologues ;
2008-08-08 10:26:37 +04:00
private Dictionary < string , string > baseClasses ;
2008-08-13 17:04:47 +04:00
private IKVM . Internal . MapXml . Root map ;
private List < object > assemblyAnnotations ;
private List < string > classesToCompile ;
private List < CompilerClassLoader > peerReferences = new List < CompilerClassLoader > ( ) ;
2008-11-14 11:24:50 +03:00
private Dictionary < string , string > peerLoading = new Dictionary < string , string > ( ) ;
2008-11-18 08:28:15 +03:00
private Dictionary < string , TypeWrapper > importedStubTypes = new Dictionary < string , TypeWrapper > ( ) ;
2008-12-23 10:11:29 +03:00
private List < ClassLoaderWrapper > internalsVisibleTo = new List < ClassLoaderWrapper > ( ) ;
private List < TypeWrapper > dynamicallyImportedTypes = new List < TypeWrapper > ( ) ;
2010-08-05 17:43:00 +04:00
private List < string > jarList = new List < string > ( ) ;
2011-12-14 13:04:57 +04:00
private List < TypeWrapper > allwrappers ;
2006-02-23 16:20:51 +03:00
2012-03-24 12:54:12 +04:00
internal CompilerClassLoader ( AssemblyClassLoader [ ] referencedAssemblies , CompilerOptions options , string path , bool targetIsModule , string assemblyName , Dictionary < string , ClassItem > classes )
2006-09-01 11:53:36 +04:00
: base ( options . codegenoptions , null )
2006-02-23 16:20:51 +03:00
{
2006-08-14 11:57:03 +04:00
this . referencedAssemblies = referencedAssemblies ;
2006-02-23 16:20:51 +03:00
this . options = options ;
this . classes = classes ;
this . assemblyName = assemblyName ;
FileInfo assemblyPath = new FileInfo ( path ) ;
this . assemblyFile = assemblyPath . Name ;
this . assemblyDir = assemblyPath . DirectoryName ;
this . targetIsModule = targetIsModule ;
Tracer . Info ( Tracer . Compiler , "Instantiate CompilerClassLoader for {0}" , assemblyName ) ;
}
2009-12-01 10:08:52 +03:00
internal bool ReserveName ( string javaName )
{
return ! classes . ContainsKey ( javaName ) & & GetTypeWrapperFactory ( ) . ReserveName ( javaName ) ;
}
2006-08-14 11:57:03 +04:00
internal void AddNameMapping ( string javaName , string typeName )
{
nameMappings . Add ( javaName , typeName ) ;
}
internal void AddReference ( AssemblyClassLoader acl )
{
AssemblyClassLoader [ ] temp = new AssemblyClassLoader [ referencedAssemblies . Length + 1 ] ;
Array . Copy ( referencedAssemblies , 0 , temp , 0 , referencedAssemblies . Length ) ;
temp [ temp . Length - 1 ] = acl ;
referencedAssemblies = temp ;
}
2008-08-13 17:04:47 +04:00
internal void AddReference ( CompilerClassLoader ccl )
{
peerReferences . Add ( ccl ) ;
}
2007-12-17 13:59:02 +03:00
internal AssemblyName GetAssemblyName ( )
{
return assemblyBuilder . GetName ( ) ;
}
2009-05-17 10:11:58 +04:00
private static PermissionSet Combine ( PermissionSet p1 , PermissionSet p2 )
{
if ( p1 = = null )
{
return p2 ;
}
if ( p2 = = null )
{
return p1 ;
}
return p1 . Union ( p2 ) ;
}
2006-09-12 13:57:36 +04:00
internal ModuleBuilder CreateModuleBuilder ( )
2006-02-23 16:20:51 +03:00
{
AssemblyName name = new AssemblyName ( ) ;
name . Name = assemblyName ;
2010-05-07 16:05:52 +04:00
if ( options . keyPair ! = null )
{
name . KeyPair = options . keyPair ;
}
else if ( options . publicKey ! = null )
{
name . SetPublicKey ( options . publicKey ) ;
}
2010-04-14 18:43:21 +04:00
name . Version = options . version ;
2009-05-26 09:00:38 +04:00
assemblyBuilder =
2010-01-25 10:52:27 +03:00
StaticCompiler . Universe
2009-05-26 09:00:38 +04:00
. DefineDynamicAssembly ( name , AssemblyBuilderAccess . ReflectionOnly , assemblyDir ) ;
2006-02-23 16:20:51 +03:00
ModuleBuilder moduleBuilder ;
2006-08-29 10:28:34 +04:00
moduleBuilder = assemblyBuilder . DefineDynamicModule ( assemblyName , assemblyFile , this . EmitDebugInfo ) ;
if ( this . EmitStackTraceInfo )
2006-02-23 16:20:51 +03:00
{
AttributeHelper . SetSourceFile ( moduleBuilder , null ) ;
}
2006-08-29 10:28:34 +04:00
if ( this . EmitDebugInfo | | this . EmitStackTraceInfo )
2006-02-23 16:20:51 +03:00
{
2009-10-14 18:58:41 +04:00
CustomAttributeBuilder debugAttr = new CustomAttributeBuilder ( JVM . Import ( typeof ( DebuggableAttribute ) ) . GetConstructor ( new Type [ ] { Types . Boolean , Types . Boolean } ) , new object [ ] { true , this . EmitDebugInfo } ) ;
2006-02-23 16:20:51 +03:00
assemblyBuilder . SetCustomAttribute ( debugAttr ) ;
2009-05-24 10:54:24 +04:00
}
2009-06-18 10:14:55 +04:00
AttributeHelper . SetRuntimeCompatibilityAttribute ( assemblyBuilder ) ;
2009-06-22 10:12:47 +04:00
if ( options . baseAddress ! = 0 )
{
moduleBuilder . __ImageBase = options . baseAddress ;
}
2012-03-21 15:33:10 +04:00
if ( options . fileAlignment ! = 0 )
{
moduleBuilder . __FileAlignment = options . fileAlignment ;
}
2012-03-21 16:38:22 +04:00
if ( options . highentropyva )
{
moduleBuilder . __DllCharacteristics | = DllCharacteristics . HighEntropyVA ;
}
2006-02-23 16:20:51 +03:00
return moduleBuilder ;
}
2008-11-14 11:29:19 +03:00
public override string ToString ( )
{
return "CompilerClassLoader:" + options . assembly ;
}
2006-07-10 13:37:06 +04:00
protected override TypeWrapper LoadClassImpl ( string name , bool throwClassNotFoundException )
2006-02-23 16:20:51 +03:00
{
2006-08-14 11:57:03 +04:00
foreach ( AssemblyClassLoader acl in referencedAssemblies )
2006-07-10 13:37:06 +04:00
{
2006-08-14 11:57:03 +04:00
TypeWrapper tw = acl . DoLoad ( name ) ;
if ( tw ! = null )
{
return tw ;
}
2006-07-10 13:37:06 +04:00
}
2008-11-14 11:24:50 +03:00
if ( ! peerLoading . ContainsKey ( name ) )
2008-08-13 17:04:47 +04:00
{
2008-11-14 11:24:50 +03:00
peerLoading . Add ( name , null ) ;
2008-08-13 17:04:47 +04:00
try
{
foreach ( CompilerClassLoader ccl in peerReferences )
{
2009-11-04 08:18:37 +03:00
TypeWrapper tw = ccl . PeerLoad ( name ) ;
if ( tw ! = null )
2008-08-13 17:04:47 +04:00
{
2009-11-04 08:18:37 +03:00
return tw ;
}
}
if ( options . sharedclassloader ! = null & & options . sharedclassloader [ 0 ] ! = this )
{
TypeWrapper tw = options . sharedclassloader [ 0 ] . PeerLoad ( name ) ;
if ( tw ! = null )
{
return tw ;
2008-08-13 17:04:47 +04:00
}
}
}
finally
{
2008-11-14 11:24:50 +03:00
peerLoading . Remove ( name ) ;
2008-08-13 17:04:47 +04:00
}
}
2008-09-21 13:48:57 +04:00
TypeWrapper tw1 = GetTypeWrapperCompilerHook ( name ) ;
if ( tw1 ! = null )
{
return tw1 ;
}
2009-11-04 08:18:37 +03:00
// HACK the peer loading mess above may have indirectly loaded the classes without returning it,
// so we try once more here
tw1 = GetLoadedClass ( name ) ;
if ( tw1 ! = null )
{
return tw1 ;
}
2008-09-21 13:48:57 +04:00
return LoadGenericClass ( name ) ;
2006-07-10 13:37:06 +04:00
}
2009-11-04 08:18:37 +03:00
private TypeWrapper PeerLoad ( string name )
{
// To keep the performance acceptable in cases where we're compiling many targets, we first check if the load can
// possibly succeed on this class loader, otherwise we'll end up doing a lot of futile recursive loading attempts.
if ( classes . ContainsKey ( name ) | | remapped . ContainsKey ( name ) | | GetLoadedClass ( name ) ! = null )
{
TypeWrapper tw = LoadClassByDottedNameFast ( name ) ;
// HACK we don't want to load classes referenced by peers, hence the "== this" check
if ( tw ! = null & & tw . GetClassLoader ( ) = = this )
{
return tw ;
}
}
if ( options . sharedclassloader ! = null & & options . sharedclassloader [ 0 ] = = this )
{
foreach ( CompilerClassLoader ccl in options . sharedclassloader )
{
if ( ccl ! = this )
{
TypeWrapper tw = ccl . PeerLoad ( name ) ;
if ( tw ! = null )
{
return tw ;
}
}
}
}
return null ;
}
2006-07-10 13:37:06 +04:00
private TypeWrapper GetTypeWrapperCompilerHook ( string name )
{
2011-12-14 11:56:53 +04:00
RemapperTypeWrapper rtw ;
if ( remapped . TryGetValue ( name , out rtw ) )
{
return rtw ;
}
else
2006-02-23 16:20:51 +03:00
{
2012-03-24 12:54:12 +04:00
ClassItem classdef ;
2008-08-08 10:26:37 +04:00
if ( classes . TryGetValue ( name , out classdef ) )
2006-02-23 16:20:51 +03:00
{
classes . Remove ( name ) ;
ClassFile f ;
try
{
2006-08-29 10:28:34 +04:00
ClassFileParseOptions cfp = ClassFileParseOptions . LocalVariableTable ;
if ( this . EmitStackTraceInfo )
{
cfp | = ClassFileParseOptions . LineNumberTable ;
}
2012-03-24 12:54:12 +04:00
f = new ClassFile ( classdef . data , 0 , classdef . data . Length , name , cfp ) ;
2006-02-23 16:20:51 +03:00
}
catch ( ClassFormatError x )
{
2010-07-16 12:50:40 +04:00
StaticCompiler . IssueMessage ( options , Message . ClassFormatError , name , x . Message ) ;
2006-02-23 16:20:51 +03:00
return null ;
}
if ( options . removeUnusedFields )
{
f . RemoveUnusedFields ( ) ;
}
2006-04-05 12:18:58 +04:00
if ( f . IsPublic & & options . privatePackages ! = null )
{
foreach ( string p in options . privatePackages )
{
if ( f . Name . StartsWith ( p ) )
{
f . SetInternal ( ) ;
break ;
}
}
}
2009-10-28 14:25:20 +03:00
if ( f . IsPublic & & options . publicPackages ! = null )
{
bool found = false ;
foreach ( string package in options . publicPackages )
{
if ( f . Name . StartsWith ( package ) )
{
found = true ;
break ;
}
}
if ( ! found )
{
f . SetInternal ( ) ;
}
}
2006-10-12 09:59:24 +04:00
if ( ! f . IsInterface
& & ! f . IsAbstract
& & ! f . IsPublic
2010-08-18 11:17:30 +04:00
& & ! f . IsInternal
2006-10-12 09:59:24 +04:00
& & ! f . IsFinal
& & ! baseClasses . ContainsKey ( f . Name )
2010-05-21 10:27:22 +04:00
& & ! options . targetIsModule
& & options . sharedclassloader = = null )
2006-10-12 09:59:24 +04:00
{
f . SetEffectivelyFinal ( ) ;
}
2012-03-24 12:54:12 +04:00
if ( f . SourceFileAttribute ! = null )
{
if ( classdef . path ! = null )
{
string sourceFile = Path . GetFullPath ( Path . Combine ( Path . GetDirectoryName ( classdef . path ) , f . SourceFileAttribute ) ) ;
if ( File . Exists ( sourceFile ) )
{
f . SourcePath = sourceFile ;
}
}
2012-03-24 14:02:59 +04:00
if ( f . SourcePath = = null )
2012-03-24 12:54:12 +04:00
{
2012-03-24 14:02:59 +04:00
if ( options . sourcepath ! = null )
{
string package = f . Name ;
int index = package . LastIndexOf ( '.' ) ;
package = index = = - 1 ? "" : package . Substring ( 0 , index ) . Replace ( '.' , '/' ) ;
f . SourcePath = Path . GetFullPath ( Path . Combine ( options . sourcepath + "/" + package , f . SourceFileAttribute ) ) ;
}
else
{
f . SourcePath = f . SourceFileAttribute ;
}
2012-03-24 12:54:12 +04:00
}
}
2007-05-02 10:04:07 +04:00
try
{
2011-12-14 11:56:53 +04:00
TypeWrapper type = DefineClass ( f , null ) ;
2008-11-18 08:28:15 +03:00
if ( f . IKVMAssemblyAttribute ! = null )
{
importedStubTypes . Add ( f . Name , type ) ;
}
2011-12-14 11:56:53 +04:00
return type ;
2007-05-02 10:04:07 +04:00
}
catch ( ClassFormatError x )
{
2010-07-16 12:50:40 +04:00
StaticCompiler . IssueMessage ( options , Message . ClassFormatError , name , x . Message ) ;
2007-05-02 10:04:07 +04:00
return null ;
}
catch ( IllegalAccessError x )
{
2010-07-16 12:50:40 +04:00
StaticCompiler . IssueMessage ( options , Message . IllegalAccessError , name , x . Message ) ;
2007-05-02 10:04:07 +04:00
return null ;
}
catch ( VerifyError x )
{
2010-07-16 12:50:40 +04:00
StaticCompiler . IssueMessage ( options , Message . VerificationError , name , x . Message ) ;
2007-05-02 10:04:07 +04:00
return null ;
}
catch ( NoClassDefFoundError x )
{
2010-07-16 12:50:40 +04:00
StaticCompiler . IssueMessage ( options , Message . NoClassDefFoundError , name , x . Message ) ;
2007-05-02 10:04:07 +04:00
return null ;
}
catch ( RetargetableJavaException x )
{
2010-07-16 12:50:40 +04:00
StaticCompiler . IssueMessage ( options , Message . GenericUnableToCompileError , name , x . GetType ( ) . Name , x . Message ) ;
2007-05-02 10:04:07 +04:00
return null ;
}
2006-02-23 16:20:51 +03:00
}
2011-12-14 11:56:53 +04:00
else
{
return null ;
}
2006-02-23 16:20:51 +03:00
}
}
2009-02-04 10:10:59 +03:00
internal override Type GetGenericTypeDefinition ( string name )
2007-05-23 16:46:29 +04:00
{
foreach ( AssemblyClassLoader loader in referencedAssemblies )
{
2009-02-04 10:10:59 +03:00
Type type = loader . GetGenericTypeDefinition ( name ) ;
2007-05-23 16:46:29 +04:00
if ( type ! = null )
{
return type ;
}
}
return null ;
}
2009-11-13 18:08:20 +03:00
// HACK when we're compiling multiple targets with -sharedclassloader, each target will have its own CompilerClassLoader,
// so we need to consider them equivalent (because they represent the same class loader).
internal bool IsEquivalentTo ( ClassLoaderWrapper other )
{
if ( this = = other )
{
return true ;
}
CompilerClassLoader ccl = other as CompilerClassLoader ;
if ( ccl ! = null & & options . sharedclassloader ! = null & & options . sharedclassloader . Contains ( ccl ) )
{
if ( ! internalsVisibleTo . Contains ( ccl ) )
{
AddInternalsVisibleToAttribute ( ccl ) ;
}
return true ;
}
return false ;
}
2009-02-10 10:24:30 +03:00
internal override bool InternalsVisibleToImpl ( TypeWrapper wrapper , TypeWrapper friend )
2008-12-23 10:11:29 +03:00
{
2009-02-10 10:24:30 +03:00
Debug . Assert ( wrapper . GetClassLoader ( ) = = this ) ;
ClassLoaderWrapper other = friend . GetClassLoader ( ) ;
2008-12-23 10:11:29 +03:00
// TODO ideally we should also respect InternalsVisibleToAttribute.Annotation here
if ( this = = other | | internalsVisibleTo . Contains ( other ) )
{
return true ;
}
CompilerClassLoader ccl = other as CompilerClassLoader ;
2009-11-13 18:08:20 +03:00
if ( ccl ! = null )
2008-12-23 10:11:29 +03:00
{
2009-11-13 18:08:20 +03:00
AddInternalsVisibleToAttribute ( ccl ) ;
2008-12-23 10:11:29 +03:00
return true ;
}
return false ;
}
2009-11-13 18:08:20 +03:00
private void AddInternalsVisibleToAttribute ( CompilerClassLoader ccl )
2008-12-23 10:11:29 +03:00
{
2009-11-13 18:08:20 +03:00
internalsVisibleTo . Add ( ccl ) ;
AssemblyBuilder asm = ccl . assemblyBuilder ;
2008-12-23 10:11:29 +03:00
AssemblyName asmName = asm . GetName ( ) ;
string name = asmName . Name ;
byte [ ] pubkey = asmName . GetPublicKey ( ) ;
if ( pubkey = = null & & asmName . KeyPair ! = null )
{
pubkey = asmName . KeyPair . PublicKey ;
}
if ( pubkey ! = null & & pubkey . Length ! = 0 )
{
StringBuilder sb = new StringBuilder ( name ) ;
sb . Append ( ", PublicKey=" ) ;
foreach ( byte b in pubkey )
{
sb . AppendFormat ( "{0:X2}" , b ) ;
}
name = sb . ToString ( ) ;
}
2009-10-14 18:58:41 +04:00
CustomAttributeBuilder cab = new CustomAttributeBuilder ( JVM . Import ( typeof ( InternalsVisibleToAttribute ) ) . GetConstructor ( new Type [ ] { Types . String } ) , new object [ ] { name } ) ;
2008-12-23 10:11:29 +03:00
this . assemblyBuilder . SetCustomAttribute ( cab ) ;
}
2008-08-08 10:26:37 +04:00
internal void SetMain ( MethodInfo m , PEFileKinds target , Dictionary < string , string > props , bool noglobbing , Type apartmentAttributeType )
2006-02-23 16:20:51 +03:00
{
2011-07-12 11:41:24 +04:00
MethodBuilder mainStub = this . GetTypeWrapperFactory ( ) . ModuleBuilder . DefineGlobalMethod ( "main" , MethodAttributes . Public | MethodAttributes . Static , Types . Int32 , new Type [ ] { Types . String . MakeArrayType ( ) } ) ;
2006-02-23 16:20:51 +03:00
if ( apartmentAttributeType ! = null )
{
mainStub . SetCustomAttribute ( new CustomAttributeBuilder ( apartmentAttributeType . GetConstructor ( Type . EmptyTypes ) , new object [ 0 ] ) ) ;
}
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( mainStub ) ;
2010-09-29 11:21:51 +04:00
CodeEmitterLocal rc = ilgen . DeclareLocal ( Types . Int32 ) ;
2006-08-17 12:14:47 +04:00
TypeWrapper startupType = LoadClassByDottedName ( "ikvm.runtime.Startup" ) ;
2006-02-23 16:20:51 +03:00
if ( props . Count > 0 )
{
2010-05-20 08:26:35 +04:00
ilgen . Emit ( OpCodes . Newobj , JVM . Import ( typeof ( System . Collections . Generic . Dictionary < string , string > ) ) . GetConstructor ( Type . EmptyTypes ) ) ;
2008-08-08 10:26:37 +04:00
foreach ( KeyValuePair < string , string > kv in props )
2006-02-23 16:20:51 +03:00
{
ilgen . Emit ( OpCodes . Dup ) ;
2008-08-08 10:26:37 +04:00
ilgen . Emit ( OpCodes . Ldstr , kv . Key ) ;
ilgen . Emit ( OpCodes . Ldstr , kv . Value ) ;
2010-06-10 12:44:40 +04:00
if ( kv . Value . IndexOf ( '%' ) < kv . Value . LastIndexOf ( '%' ) )
{
ilgen . Emit ( OpCodes . Call , JVM . Import ( typeof ( Environment ) ) . GetMethod ( "ExpandEnvironmentVariables" , new Type [ ] { Types . String } ) ) ;
}
2010-05-20 08:26:35 +04:00
ilgen . Emit ( OpCodes . Callvirt , JVM . Import ( typeof ( System . Collections . Generic . Dictionary < string , string > ) ) . GetMethod ( "Add" ) ) ;
2006-02-23 16:20:51 +03:00
}
2010-05-20 08:26:35 +04:00
startupType . GetMethodWrapper ( "setProperties" , "(Lcli.System.Collections.IDictionary;)V" , false ) . EmitCall ( ilgen ) ;
2006-02-23 16:20:51 +03:00
}
ilgen . BeginExceptionBlock ( ) ;
2006-08-17 12:14:47 +04:00
startupType . GetMethodWrapper ( "enterMainThread" , "()V" , false ) . EmitCall ( ilgen ) ;
2011-07-12 11:41:24 +04:00
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
if ( ! noglobbing )
2006-02-23 16:20:51 +03:00
{
2011-07-12 11:41:24 +04:00
ilgen . Emit ( OpCodes . Ldc_I4_0 ) ;
startupType . GetMethodWrapper ( "glob" , "([Ljava.lang.String;I)[Ljava.lang.String;" , false ) . EmitCall ( ilgen ) ;
2006-02-23 16:20:51 +03:00
}
ilgen . Emit ( OpCodes . Call , m ) ;
2010-10-05 08:54:09 +04:00
CodeEmitterLabel label = ilgen . DefineLabel ( ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitLeave ( label ) ;
2009-10-14 18:58:41 +04:00
ilgen . BeginCatchBlock ( Types . Exception ) ;
2006-08-17 12:14:47 +04:00
LoadClassByDottedName ( "ikvm.runtime.Util" ) . GetMethodWrapper ( "mapException" , "(Ljava.lang.Throwable;)Ljava.lang.Throwable;" , false ) . EmitCall ( ilgen ) ;
2010-09-29 11:21:51 +04:00
CodeEmitterLocal exceptionLocal = ilgen . DeclareLocal ( Types . Exception ) ;
2006-02-23 16:20:51 +03:00
ilgen . Emit ( OpCodes . Stloc , exceptionLocal ) ;
TypeWrapper threadTypeWrapper = ClassLoaderWrapper . LoadClassCritical ( "java.lang.Thread" ) ;
2010-09-29 11:21:51 +04:00
CodeEmitterLocal threadLocal = ilgen . DeclareLocal ( threadTypeWrapper . TypeAsLocalOrStackType ) ;
2006-02-23 16:20:51 +03:00
threadTypeWrapper . GetMethodWrapper ( "currentThread" , "()Ljava.lang.Thread;" , false ) . EmitCall ( ilgen ) ;
ilgen . Emit ( OpCodes . Stloc , threadLocal ) ;
ilgen . Emit ( OpCodes . Ldloc , threadLocal ) ;
threadTypeWrapper . GetMethodWrapper ( "getThreadGroup" , "()Ljava.lang.ThreadGroup;" , false ) . EmitCallvirt ( ilgen ) ;
ilgen . Emit ( OpCodes . Ldloc , threadLocal ) ;
ilgen . Emit ( OpCodes . Ldloc , exceptionLocal ) ;
ClassLoaderWrapper . LoadClassCritical ( "java.lang.ThreadGroup" ) . GetMethodWrapper ( "uncaughtException" , "(Ljava.lang.Thread;Ljava.lang.Throwable;)V" , false ) . EmitCallvirt ( ilgen ) ;
ilgen . Emit ( OpCodes . Ldc_I4_1 ) ;
ilgen . Emit ( OpCodes . Stloc , rc ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitLeave ( label ) ;
2006-02-23 16:20:51 +03:00
ilgen . BeginFinallyBlock ( ) ;
2006-08-17 12:14:47 +04:00
startupType . GetMethodWrapper ( "exitMainThread" , "()V" , false ) . EmitCall ( ilgen ) ;
2010-10-05 08:54:09 +04:00
ilgen . Emit ( OpCodes . Endfinally ) ;
2006-02-23 16:20:51 +03:00
ilgen . EndExceptionBlock ( ) ;
2010-10-05 08:54:09 +04:00
ilgen . MarkLabel ( label ) ;
2006-02-23 16:20:51 +03:00
ilgen . Emit ( OpCodes . Ldloc , rc ) ;
ilgen . Emit ( OpCodes . Ret ) ;
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-02-23 16:20:51 +03:00
assemblyBuilder . SetEntryPoint ( mainStub , target ) ;
}
2010-10-11 16:15:28 +04:00
private void PrepareSave ( )
2006-02-23 16:20:51 +03:00
{
2006-09-01 11:53:36 +04:00
( ( DynamicClassLoader ) this . GetTypeWrapperFactory ( ) ) . FinishAll ( ) ;
2010-10-11 16:15:28 +04:00
}
2006-02-23 16:20:51 +03:00
2010-10-11 16:15:28 +04:00
private void Save ( )
{
2006-08-14 11:57:03 +04:00
ModuleBuilder mb = GetTypeWrapperFactory ( ) . ModuleBuilder ;
2009-02-19 11:12:05 +03:00
if ( targetIsModule )
2006-08-14 11:57:03 +04:00
{
2009-02-19 11:12:05 +03:00
// HACK force all referenced assemblies to end up as references in the assembly
// (even if they are otherwise unused), to make sure that the assembly class loader
// delegates to them at runtime.
// NOTE now we only do this for modules, when we're an assembly we store the exported
// assemblies in the ikvm.exports resource.
for ( int i = 0 ; i < referencedAssemblies . Length ; i + + )
2006-08-14 11:57:03 +04:00
{
2009-02-19 11:12:05 +03:00
Type [ ] types = referencedAssemblies [ i ] . MainAssembly . GetExportedTypes ( ) ;
if ( types . Length > 0 )
{
mb . GetTypeToken ( types [ 0 ] ) ;
}
2006-08-14 11:57:03 +04:00
}
}
mb . CreateGlobalFunctions ( ) ;
2010-08-05 17:43:00 +04:00
AddJavaModuleAttribute ( mb ) ;
2006-08-14 11:57:03 +04:00
2009-02-19 11:12:05 +03:00
// add a package list and export map
2008-12-23 10:11:29 +03:00
if ( options . sharedclassloader = = null | | options . sharedclassloader [ 0 ] = = this )
2006-08-14 11:57:03 +04:00
{
2006-10-09 12:29:42 +04:00
string [ ] list = new string [ packages . Count ] ;
packages . Keys . CopyTo ( list , 0 ) ;
2009-10-14 18:58:41 +04:00
mb . SetCustomAttribute ( new CustomAttributeBuilder ( JVM . LoadType ( typeof ( PackageListAttribute ) ) . GetConstructor ( new Type [ ] { JVM . Import ( typeof ( string [ ] ) ) } ) , new object [ ] { list } ) ) ;
2009-02-19 11:12:05 +03:00
// We can't add the resource when we're a module, because a multi-module assembly has a single resource namespace
// and since you cannot combine -target:module with -sharedclassloader we don't need an export map
// (the wildcard exports have already been added above, by making sure that we statically reference the assemblies).
if ( ! targetIsModule )
{
WriteExportMap ( ) ;
}
2008-12-23 10:11:29 +03:00
}
2006-02-23 16:20:51 +03:00
if ( targetIsModule )
{
2010-11-29 11:16:54 +03:00
Tracer . Info ( Tracer . Compiler , "CompilerClassLoader saving {0} in {1}" , assemblyFile , assemblyDir ) ;
2012-03-25 13:10:28 +04:00
try
{
GetTypeWrapperFactory ( ) . ModuleBuilder . __Save ( options . pekind , options . imageFileMachine ) ;
}
catch ( IOException x )
{
throw new FatalCompilerErrorException ( Message . ErrorWritingFile , GetTypeWrapperFactory ( ) . ModuleBuilder . FullyQualifiedName , x . Message ) ;
}
2006-02-23 16:20:51 +03:00
}
else
{
Tracer . Info ( Tracer . Compiler , "CompilerClassLoader saving {0} in {1}" , assemblyFile , assemblyDir ) ;
2012-03-25 13:10:28 +04:00
try
{
assemblyBuilder . Save ( assemblyFile , options . pekind , options . imageFileMachine ) ;
}
catch ( IOException x )
{
throw new FatalCompilerErrorException ( Message . ErrorWritingFile , Path . Combine ( assemblyDir , assemblyFile ) , x . Message ) ;
}
2006-02-23 16:20:51 +03:00
}
}
2010-08-05 17:43:00 +04:00
private void AddJavaModuleAttribute ( ModuleBuilder mb )
{
Type typeofJavaModuleAttribute = JVM . LoadType ( typeof ( JavaModuleAttribute ) ) ;
PropertyInfo [ ] propInfos = new PropertyInfo [ ] {
typeofJavaModuleAttribute . GetProperty ( "Jars" )
} ;
object [ ] propValues = new object [ ] {
jarList . ToArray ( )
} ;
if ( nameMappings . Count > 0 )
{
string [ ] list = new string [ nameMappings . Count * 2 ] ;
int i = 0 ;
foreach ( KeyValuePair < string , string > kv in nameMappings )
{
list [ i + + ] = kv . Key ;
list [ i + + ] = kv . Value ;
}
CustomAttributeBuilder cab = new CustomAttributeBuilder ( typeofJavaModuleAttribute . GetConstructor ( new Type [ ] { JVM . Import ( typeof ( string [ ] ) ) } ) , new object [ ] { list } , propInfos , propValues ) ;
mb . SetCustomAttribute ( cab ) ;
}
else
{
CustomAttributeBuilder cab = new CustomAttributeBuilder ( typeofJavaModuleAttribute . GetConstructor ( Type . EmptyTypes ) , new object [ 0 ] , propInfos , propValues ) ;
mb . SetCustomAttribute ( cab ) ;
}
}
2009-11-30 12:12:36 +03:00
private static void AddExportMapEntry ( Dictionary < string , List < string > > map , CompilerClassLoader ccl , string name )
2008-12-23 10:11:29 +03:00
{
2009-11-30 12:12:36 +03:00
string assemblyName = ccl . assemblyBuilder . FullName ;
2008-12-23 10:11:29 +03:00
List < string > list ;
2009-11-30 12:12:36 +03:00
if ( ! map . TryGetValue ( assemblyName , out list ) )
2008-12-23 10:11:29 +03:00
{
list = new List < string > ( ) ;
2009-11-30 12:12:36 +03:00
map . Add ( assemblyName , list ) ;
2009-02-19 11:12:05 +03:00
}
if ( list ! = null ) // if list is null, we already have a wildcard export for this assembly
{
list . Add ( name ) ;
2008-12-23 10:11:29 +03:00
}
}
2009-11-30 12:12:36 +03:00
private void AddWildcardExports ( Dictionary < string , List < string > > exportedNamesPerAssembly )
2008-12-23 10:11:29 +03:00
{
2009-02-19 11:12:05 +03:00
foreach ( AssemblyClassLoader acl in referencedAssemblies )
{
2009-11-30 12:12:36 +03:00
exportedNamesPerAssembly [ acl . MainAssembly . FullName ] = null ;
2009-02-19 11:12:05 +03:00
}
2009-02-22 11:18:37 +03:00
}
private void WriteExportMap ( )
{
2009-11-30 12:12:36 +03:00
Dictionary < string , List < string > > exportedNamesPerAssembly = new Dictionary < string , List < string > > ( ) ;
2009-02-22 11:18:37 +03:00
AddWildcardExports ( exportedNamesPerAssembly ) ;
2008-12-23 10:11:29 +03:00
foreach ( TypeWrapper tw in dynamicallyImportedTypes )
{
AddExportMapEntry ( exportedNamesPerAssembly , ( CompilerClassLoader ) tw . GetClassLoader ( ) , tw . Name ) ;
}
2009-10-23 10:25:09 +04:00
if ( options . sharedclassloader = = null )
{
foreach ( CompilerClassLoader ccl in peerReferences )
{
2009-11-30 12:12:36 +03:00
exportedNamesPerAssembly [ ccl . assemblyBuilder . FullName ] = null ;
2009-10-23 10:25:09 +04:00
}
}
else
2008-12-23 10:11:29 +03:00
{
2009-02-19 11:12:05 +03:00
foreach ( CompilerClassLoader ccl in options . sharedclassloader )
2008-12-23 10:11:29 +03:00
{
2009-02-19 11:12:05 +03:00
if ( ccl ! = this )
2008-12-23 10:11:29 +03:00
{
2009-02-22 11:18:37 +03:00
ccl . AddWildcardExports ( exportedNamesPerAssembly ) ;
2009-02-19 11:12:05 +03:00
if ( ccl . options . resources ! = null )
2008-12-23 10:11:29 +03:00
{
2009-02-19 11:12:05 +03:00
foreach ( string name in ccl . options . resources . Keys )
{
AddExportMapEntry ( exportedNamesPerAssembly , ccl , name ) ;
}
2008-12-23 10:11:29 +03:00
}
2009-02-19 11:12:05 +03:00
if ( ccl . options . externalResources ! = null )
2008-12-23 10:11:29 +03:00
{
2009-02-19 11:12:05 +03:00
foreach ( string name in ccl . options . externalResources . Keys )
{
AddExportMapEntry ( exportedNamesPerAssembly , ccl , name ) ;
}
2008-12-23 10:11:29 +03:00
}
}
}
}
MemoryStream ms = new MemoryStream ( ) ;
BinaryWriter bw = new BinaryWriter ( ms ) ;
bw . Write ( exportedNamesPerAssembly . Count ) ;
2009-11-30 12:12:36 +03:00
foreach ( KeyValuePair < string , List < string > > kv in exportedNamesPerAssembly )
2008-12-23 10:11:29 +03:00
{
2009-11-30 12:12:36 +03:00
bw . Write ( kv . Key ) ;
2009-02-19 11:12:05 +03:00
if ( kv . Value = = null )
{
// wildcard export
bw . Write ( 0 ) ;
}
else
2008-12-23 10:11:29 +03:00
{
2009-02-19 11:12:05 +03:00
Debug . Assert ( kv . Value . Count ! = 0 ) ;
bw . Write ( kv . Value . Count ) ;
foreach ( string name in kv . Value )
{
bw . Write ( JVM . PersistableHash ( name ) ) ;
}
2008-12-23 10:11:29 +03:00
}
}
ms . Position = 0 ;
this . GetTypeWrapperFactory ( ) . ModuleBuilder . DefineManifestResource ( "ikvm.exports" , ms , ResourceAttributes . Public ) ;
}
2010-08-05 17:43:00 +04:00
internal void AddResources ( Dictionary < string , List < ResourceItem > > resources , bool compressedResources )
2006-02-23 16:20:51 +03:00
{
Tracer . Info ( Tracer . Compiler , "CompilerClassLoader adding resources..." ) ;
2010-08-05 17:43:00 +04:00
// BUG we need to call GetTypeWrapperFactory() to make sure that the assemblyBuilder is created (when building an empty target)
2006-07-26 18:16:52 +04:00
ModuleBuilder moduleBuilder = this . GetTypeWrapperFactory ( ) . ModuleBuilder ;
2010-08-05 17:43:00 +04:00
Dictionary < string , Dictionary < string , ResourceItem > > jars = new Dictionary < string , Dictionary < string , ResourceItem > > ( ) ;
foreach ( KeyValuePair < string , List < ResourceItem > > kv in resources )
{
foreach ( ResourceItem item in kv . Value )
{
int count = 0 ;
string jarName = item . jar ;
retry :
Dictionary < string , ResourceItem > jar ;
if ( ! jars . TryGetValue ( jarName , out jar ) )
{
jar = new Dictionary < string , ResourceItem > ( ) ;
jars . Add ( jarName , jar ) ;
}
if ( jar . ContainsKey ( kv . Key ) )
{
jarName = Path . GetFileNameWithoutExtension ( item . jar ) + "-" + ( count + + ) + Path . GetExtension ( item . jar ) ;
goto retry ;
}
jar . Add ( kv . Key , item ) ;
}
}
foreach ( KeyValuePair < string , Dictionary < string , ResourceItem > > jar in jars )
2006-02-23 16:20:51 +03:00
{
2008-03-14 12:13:59 +03:00
MemoryStream mem = new MemoryStream ( ) ;
2010-08-05 17:43:00 +04:00
using ( ICSharpCode . SharpZipLib . Zip . ZipOutputStream zip = new ICSharpCode . SharpZipLib . Zip . ZipOutputStream ( mem ) )
2006-02-23 16:20:51 +03:00
{
2010-08-05 17:43:00 +04:00
foreach ( KeyValuePair < string , ResourceItem > kv in jar . Value )
2006-08-29 10:28:34 +04:00
{
2010-08-05 17:43:00 +04:00
ICSharpCode . SharpZipLib . Zip . ZipEntry zipEntry = new ICSharpCode . SharpZipLib . Zip . ZipEntry ( kv . Key ) ;
if ( kv . Value . zipEntry = = null )
{
zipEntry . CompressionMethod = ICSharpCode . SharpZipLib . Zip . CompressionMethod . Stored ;
}
else
{
zipEntry . Comment = kv . Value . zipEntry . Comment ;
zipEntry . CompressionMethod = kv . Value . zipEntry . CompressionMethod ;
zipEntry . DosTime = kv . Value . zipEntry . DosTime ;
zipEntry . ExternalFileAttributes = kv . Value . zipEntry . ExternalFileAttributes ;
zipEntry . ExtraData = kv . Value . zipEntry . ExtraData ;
zipEntry . Flags = kv . Value . zipEntry . Flags ;
}
if ( compressedResources | | zipEntry . CompressionMethod ! = ICSharpCode . SharpZipLib . Zip . CompressionMethod . Stored )
{
zip . SetLevel ( 9 ) ;
zipEntry . CompressionMethod = ICSharpCode . SharpZipLib . Zip . CompressionMethod . Deflated ;
}
zip . PutNextEntry ( zipEntry ) ;
if ( kv . Value . data ! = null )
{
zip . Write ( kv . Value . data , 0 , kv . Value . data . Length ) ;
}
zip . CloseEntry ( ) ;
2006-08-29 10:28:34 +04:00
}
2006-02-23 16:20:51 +03:00
}
2010-08-05 17:43:00 +04:00
mem = new MemoryStream ( mem . ToArray ( ) ) ;
string name = jar . Key ;
if ( options . targetIsModule )
2008-03-14 12:13:59 +03:00
{
2010-08-05 17:43:00 +04:00
name = Path . GetFileNameWithoutExtension ( name ) + "-" + moduleBuilder . ModuleVersionId . ToString ( "N" ) + Path . GetExtension ( name ) ;
2008-03-14 12:13:59 +03:00
}
2010-08-05 17:43:00 +04:00
jarList . Add ( name ) ;
2008-03-14 12:13:59 +03:00
moduleBuilder . DefineManifestResource ( name , mem , ResourceAttributes . Public ) ;
2006-02-23 16:20:51 +03:00
}
}
private static MethodAttributes MapMethodAccessModifiers ( IKVM . Internal . MapXml . MapModifiers mod )
{
const IKVM . Internal . MapXml . MapModifiers access = IKVM . Internal . MapXml . MapModifiers . Public | IKVM . Internal . MapXml . MapModifiers . Protected | IKVM . Internal . MapXml . MapModifiers . Private ;
switch ( mod & access )
{
case IKVM . Internal . MapXml . MapModifiers . Public :
return MethodAttributes . Public ;
case IKVM . Internal . MapXml . MapModifiers . Protected :
return MethodAttributes . FamORAssem ;
case IKVM . Internal . MapXml . MapModifiers . Private :
return MethodAttributes . Private ;
default :
return MethodAttributes . Assembly ;
}
}
private static FieldAttributes MapFieldAccessModifiers ( IKVM . Internal . MapXml . MapModifiers mod )
{
const IKVM . Internal . MapXml . MapModifiers access = IKVM . Internal . MapXml . MapModifiers . Public | IKVM . Internal . MapXml . MapModifiers . Protected | IKVM . Internal . MapXml . MapModifiers . Private ;
switch ( mod & access )
{
case IKVM . Internal . MapXml . MapModifiers . Public :
return FieldAttributes . Public ;
case IKVM . Internal . MapXml . MapModifiers . Protected :
return FieldAttributes . FamORAssem ;
case IKVM . Internal . MapXml . MapModifiers . Private :
return FieldAttributes . Private ;
default :
return FieldAttributes . Assembly ;
}
}
2012-08-06 16:12:03 +04:00
private sealed class RemapperTypeWrapper : TypeWrapper
2006-02-23 16:20:51 +03:00
{
2006-03-23 14:57:41 +03:00
private CompilerClassLoader classLoader ;
2006-02-23 16:20:51 +03:00
private TypeBuilder typeBuilder ;
private TypeBuilder helperTypeBuilder ;
private Type shadowType ;
private IKVM . Internal . MapXml . Class classDef ;
2012-01-03 18:26:36 +04:00
private TypeWrapper baseTypeWrapper ;
2006-02-23 16:20:51 +03:00
private TypeWrapper [ ] interfaceWrappers ;
2006-03-23 14:57:41 +03:00
internal override ClassLoaderWrapper GetClassLoader ( )
{
return classLoader ;
}
2006-02-23 16:20:51 +03:00
internal override bool IsRemapped
{
get
{
return true ;
}
}
private static TypeWrapper GetBaseWrapper ( IKVM . Internal . MapXml . Class c )
{
if ( ( c . Modifiers & IKVM . Internal . MapXml . MapModifiers . Interface ) ! = 0 )
{
return null ;
}
if ( c . Name = = "java.lang.Object" )
{
return null ;
}
return CoreClasses . java . lang . Object . Wrapper ;
}
internal RemapperTypeWrapper ( CompilerClassLoader classLoader , IKVM . Internal . MapXml . Class c , IKVM . Internal . MapXml . Root map )
2012-01-03 18:26:36 +04:00
: base ( ( Modifiers ) c . Modifiers , c . Name )
2006-02-23 16:20:51 +03:00
{
2006-03-23 14:57:41 +03:00
this . classLoader = classLoader ;
2012-01-03 18:26:36 +04:00
this . baseTypeWrapper = GetBaseWrapper ( c ) ;
2006-02-23 16:20:51 +03:00
classDef = c ;
bool baseIsSealed = false ;
2010-05-20 08:59:13 +04:00
shadowType = StaticCompiler . Universe . GetType ( c . Shadows , true ) ;
2006-02-23 16:20:51 +03:00
classLoader . SetRemappedType ( shadowType , this ) ;
Type baseType = shadowType ;
Type baseInterface = null ;
if ( baseType . IsInterface )
{
baseInterface = baseType ;
}
TypeAttributes attrs = TypeAttributes . Public ;
if ( ( c . Modifiers & IKVM . Internal . MapXml . MapModifiers . Interface ) = = 0 )
{
attrs | = TypeAttributes . Class ;
if ( baseType . IsSealed )
{
baseIsSealed = true ;
2007-11-26 19:00:15 +03:00
attrs | = TypeAttributes . Abstract | TypeAttributes . Sealed ;
2006-02-23 16:20:51 +03:00
}
}
else
{
attrs | = TypeAttributes . Interface | TypeAttributes . Abstract ;
baseType = null ;
}
if ( ( c . Modifiers & IKVM . Internal . MapXml . MapModifiers . Abstract ) ! = 0 )
{
attrs | = TypeAttributes . Abstract ;
}
string name = c . Name . Replace ( '/' , '.' ) ;
2009-10-14 18:58:41 +04:00
typeBuilder = classLoader . GetTypeWrapperFactory ( ) . ModuleBuilder . DefineType ( name , attrs , baseIsSealed ? Types . Object : baseType ) ;
2006-02-23 16:20:51 +03:00
if ( c . Attributes ! = null )
{
foreach ( IKVM . Internal . MapXml . Attribute custattr in c . Attributes )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( classLoader , typeBuilder , custattr ) ;
2006-02-23 16:20:51 +03:00
}
}
if ( baseInterface ! = null )
{
typeBuilder . AddInterfaceImplementation ( baseInterface ) ;
}
2006-08-29 10:28:34 +04:00
if ( classLoader . EmitStackTraceInfo )
2006-02-23 16:20:51 +03:00
{
2012-01-20 20:13:07 +04:00
AttributeHelper . SetSourceFile ( typeBuilder , Path . GetFileName ( classLoader . options . remapfile ) ) ;
2006-02-23 16:20:51 +03:00
}
if ( baseIsSealed )
{
2006-04-05 12:18:58 +04:00
AttributeHelper . SetModifiers ( typeBuilder , ( Modifiers ) c . Modifiers , false ) ;
2006-02-23 16:20:51 +03:00
}
if ( c . scope = = IKVM . Internal . MapXml . Scope . Public )
{
// FXBUG we would like to emit an attribute with a Type argument here, but that doesn't work because
// of a bug in SetCustomAttribute that causes type arguments to be serialized incorrectly (if the type
// is in the same assembly). Normally we use AttributeHelper.FreezeDry to get around this, but that doesn't
// work in this case (no attribute is emitted at all). So we work around by emitting a string instead
AttributeHelper . SetRemappedClass ( classLoader . assemblyBuilder , name , shadowType ) ;
AttributeHelper . SetRemappedType ( typeBuilder , shadowType ) ;
}
2008-08-08 10:26:37 +04:00
List < MethodWrapper > methods = new List < MethodWrapper > ( ) ;
2006-02-23 16:20:51 +03:00
if ( c . Constructors ! = null )
{
foreach ( IKVM . Internal . MapXml . Constructor m in c . Constructors )
{
methods . Add ( new RemappedConstructorWrapper ( this , m ) ) ;
}
}
if ( c . Methods ! = null )
{
foreach ( IKVM . Internal . MapXml . Method m in c . Methods )
{
2006-04-05 12:18:58 +04:00
methods . Add ( new RemappedMethodWrapper ( this , m , map , false ) ) ;
}
}
// add methods from our super classes (e.g. Throwable should have Object's methods)
if ( ! this . IsFinal & & ! this . IsInterface & & this . BaseTypeWrapper ! = null )
{
foreach ( MethodWrapper mw in BaseTypeWrapper . GetMethods ( ) )
{
RemappedMethodWrapper rmw = mw as RemappedMethodWrapper ;
if ( rmw ! = null & & ( rmw . IsPublic | | rmw . IsProtected ) )
{
if ( ! FindMethod ( methods , rmw . Name , rmw . Signature ) )
{
methods . Add ( new RemappedMethodWrapper ( this , rmw . XmlMethod , map , true ) ) ;
}
}
2006-02-23 16:20:51 +03:00
}
}
2008-08-08 10:26:37 +04:00
SetMethods ( methods . ToArray ( ) ) ;
2006-02-23 16:20:51 +03:00
}
2012-01-03 18:26:36 +04:00
internal sealed override TypeWrapper BaseTypeWrapper
{
get { return baseTypeWrapper ; }
}
2011-12-14 13:04:57 +04:00
internal void LoadInterfaces ( IKVM . Internal . MapXml . Class c )
{
if ( c . Interfaces ! = null )
{
interfaceWrappers = new TypeWrapper [ c . Interfaces . Length ] ;
for ( int i = 0 ; i < c . Interfaces . Length ; i + + )
{
interfaceWrappers [ i ] = classLoader . LoadClassByDottedName ( c . Interfaces [ i ] . Name ) ;
}
}
else
{
interfaceWrappers = TypeWrapper . EmptyArray ;
}
}
2008-08-08 10:26:37 +04:00
private static bool FindMethod ( List < MethodWrapper > methods , string name , string sig )
2006-04-05 12:18:58 +04:00
{
foreach ( MethodWrapper mw in methods )
{
if ( mw . Name = = name & & mw . Signature = = sig )
{
return true ;
}
}
return false ;
}
2006-02-23 16:20:51 +03:00
abstract class RemappedMethodBaseWrapper : MethodWrapper
{
internal RemappedMethodBaseWrapper ( RemapperTypeWrapper typeWrapper , string name , string sig , Modifiers modifiers )
: base ( typeWrapper , name , sig , null , null , null , modifiers , MemberFlags . None )
{
}
internal abstract MethodBase DoLink ( ) ;
internal abstract void Finish ( ) ;
}
sealed class RemappedConstructorWrapper : RemappedMethodBaseWrapper
{
private IKVM . Internal . MapXml . Constructor m ;
private MethodBuilder mbHelper ;
internal RemappedConstructorWrapper ( RemapperTypeWrapper typeWrapper , IKVM . Internal . MapXml . Constructor m )
: base ( typeWrapper , "<init>" , m . Sig , ( Modifiers ) m . Modifiers )
{
this . m = m ;
}
2008-06-03 16:10:07 +04:00
internal override void EmitCall ( CodeEmitter ilgen )
2006-02-23 16:20:51 +03:00
{
2012-08-15 12:17:51 +04:00
ilgen . Emit ( OpCodes . Call , GetMethod ( ) ) ;
2006-02-23 16:20:51 +03:00
}
2010-09-14 16:29:22 +04:00
internal override void EmitNewobj ( CodeEmitter ilgen )
2006-02-23 16:20:51 +03:00
{
if ( mbHelper ! = null )
{
ilgen . Emit ( OpCodes . Call , mbHelper ) ;
}
else
{
2012-08-15 12:17:51 +04:00
ilgen . Emit ( OpCodes . Newobj , GetMethod ( ) ) ;
2006-02-23 16:20:51 +03:00
}
}
internal override MethodBase DoLink ( )
{
MethodAttributes attr = MapMethodAccessModifiers ( m . Modifiers ) ;
RemapperTypeWrapper typeWrapper = ( RemapperTypeWrapper ) DeclaringType ;
Type [ ] paramTypes = typeWrapper . GetClassLoader ( ) . ArgTypeListFromSig ( m . Sig ) ;
2012-09-11 16:00:46 +04:00
MethodBuilder cbCore = null ;
2006-02-23 16:20:51 +03:00
if ( typeWrapper . shadowType . IsSealed )
{
mbHelper = typeWrapper . typeBuilder . DefineMethod ( "newhelper" , attr | MethodAttributes . Static , CallingConventions . Standard , typeWrapper . shadowType , paramTypes ) ;
if ( m . Attributes ! = null )
{
foreach ( IKVM . Internal . MapXml . Attribute custattr in m . Attributes )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( DeclaringType . GetClassLoader ( ) , mbHelper , custattr ) ;
2006-02-23 16:20:51 +03:00
}
}
2008-08-14 09:42:43 +04:00
SetParameters ( DeclaringType . GetClassLoader ( ) , mbHelper , m . Params ) ;
2006-04-05 12:18:58 +04:00
AttributeHelper . SetModifiers ( mbHelper , ( Modifiers ) m . Modifiers , false ) ;
2006-02-23 16:20:51 +03:00
AttributeHelper . SetNameSig ( mbHelper , "<init>" , m . Sig ) ;
AddDeclaredExceptions ( mbHelper , m . throws ) ;
}
else
{
2012-09-11 16:00:46 +04:00
cbCore = ReflectUtil . DefineConstructor ( typeWrapper . typeBuilder , attr , paramTypes ) ;
2006-02-23 16:20:51 +03:00
if ( m . Attributes ! = null )
{
foreach ( IKVM . Internal . MapXml . Attribute custattr in m . Attributes )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( DeclaringType . GetClassLoader ( ) , cbCore , custattr ) ;
2006-02-23 16:20:51 +03:00
}
}
2008-08-14 09:42:43 +04:00
SetParameters ( DeclaringType . GetClassLoader ( ) , cbCore , m . Params ) ;
2006-02-23 16:20:51 +03:00
AddDeclaredExceptions ( cbCore , m . throws ) ;
}
return cbCore ;
}
internal override void Finish ( )
{
// TODO we should insert method tracing (if enabled)
Type [ ] paramTypes = this . GetParametersForDefineMethod ( ) ;
2012-09-11 16:00:46 +04:00
MethodBuilder cbCore = GetMethod ( ) as MethodBuilder ;
2006-02-23 16:20:51 +03:00
if ( cbCore ! = null )
{
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( cbCore ) ;
2006-02-23 16:20:51 +03:00
// TODO we need to support ghost (and other funky?) parameter types
if ( m . body ! = null )
{
// TODO do we need return type conversion here?
2008-08-14 09:42:43 +04:00
m . body . Emit ( DeclaringType . GetClassLoader ( ) , ilgen ) ;
2006-02-23 16:20:51 +03:00
}
else
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i + 1 ) ;
2006-02-23 16:20:51 +03:00
}
if ( m . redirect ! = null )
{
throw new NotImplementedException ( ) ;
}
else
{
ConstructorInfo baseCon = DeclaringType . TypeAsTBD . GetConstructor ( paramTypes ) ;
if ( baseCon = = null )
{
// TODO better error handling
throw new InvalidOperationException ( "base class constructor not found: " + DeclaringType . Name + ".<init>" + m . Sig ) ;
}
ilgen . Emit ( OpCodes . Call , baseCon ) ;
}
ilgen . Emit ( OpCodes . Ret ) ;
}
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-08-29 10:28:34 +04:00
if ( this . DeclaringType . GetClassLoader ( ) . EmitStackTraceInfo )
{
ilgen . EmitLineNumberTable ( cbCore ) ;
}
2006-02-23 16:20:51 +03:00
}
if ( mbHelper ! = null )
{
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( mbHelper ) ;
2006-02-23 16:20:51 +03:00
if ( m . redirect ! = null )
{
2008-08-14 09:42:43 +04:00
m . redirect . Emit ( DeclaringType . GetClassLoader ( ) , ilgen ) ;
2006-02-23 16:20:51 +03:00
}
else if ( m . alternateBody ! = null )
{
2008-08-14 09:42:43 +04:00
m . alternateBody . Emit ( DeclaringType . GetClassLoader ( ) , ilgen ) ;
2006-02-23 16:20:51 +03:00
}
else if ( m . body ! = null )
{
// <body> doesn't make sense for helper constructors (which are actually factory methods)
throw new InvalidOperationException ( ) ;
}
else
{
ConstructorInfo baseCon = DeclaringType . TypeAsTBD . GetConstructor ( paramTypes ) ;
if ( baseCon = = null )
{
// TODO better error handling
throw new InvalidOperationException ( "constructor not found: " + DeclaringType . Name + ".<init>" + m . Sig ) ;
}
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i ) ;
2006-02-23 16:20:51 +03:00
}
ilgen . Emit ( OpCodes . Newobj , baseCon ) ;
ilgen . Emit ( OpCodes . Ret ) ;
}
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-08-29 10:28:34 +04:00
if ( this . DeclaringType . GetClassLoader ( ) . EmitStackTraceInfo )
{
ilgen . EmitLineNumberTable ( mbHelper ) ;
}
2006-02-23 16:20:51 +03:00
}
}
}
sealed class RemappedMethodWrapper : RemappedMethodBaseWrapper
{
private IKVM . Internal . MapXml . Method m ;
private IKVM . Internal . MapXml . Root map ;
private MethodBuilder mbHelper ;
2008-08-08 10:26:37 +04:00
private List < RemapperTypeWrapper > overriders = new List < RemapperTypeWrapper > ( ) ;
2006-04-05 12:18:58 +04:00
private bool inherited ;
2006-02-23 16:20:51 +03:00
2006-04-05 12:18:58 +04:00
internal RemappedMethodWrapper ( RemapperTypeWrapper typeWrapper , IKVM . Internal . MapXml . Method m , IKVM . Internal . MapXml . Root map , bool inherited )
2006-02-23 16:20:51 +03:00
: base ( typeWrapper , m . Name , m . Sig , ( Modifiers ) m . Modifiers )
{
this . m = m ;
this . map = map ;
2006-04-05 12:18:58 +04:00
this . inherited = inherited ;
}
internal IKVM . Internal . MapXml . Method XmlMethod
{
get
{
return m ;
}
2006-02-23 16:20:51 +03:00
}
2008-06-03 16:10:07 +04:00
internal override void EmitCall ( CodeEmitter ilgen )
2006-02-23 16:20:51 +03:00
{
2011-10-18 14:57:18 +04:00
if ( ! IsStatic & & IsFinal )
{
// When calling a final instance method on a remapped type from a class derived from a .NET class (i.e. a cli.System.Object or cli.System.Exception derived base class)
// then we can't call the java.lang.Object or java.lang.Throwable methods and we have to go through the instancehelper_ method. Note that since the method
// is final, this won't affect the semantics.
EmitCallvirt ( ilgen ) ;
}
else
{
ilgen . Emit ( OpCodes . Call , ( MethodInfo ) GetMethod ( ) ) ;
}
2006-02-23 16:20:51 +03:00
}
2008-06-03 16:10:07 +04:00
internal override void EmitCallvirt ( CodeEmitter ilgen )
2006-02-23 16:20:51 +03:00
{
2008-12-23 09:12:05 +03:00
EmitCallvirtImpl ( ilgen , this . IsProtected & & ! mbHelper . IsPublic ) ;
}
private void EmitCallvirtImpl ( CodeEmitter ilgen , bool cloneOrFinalizeHack )
{
if ( mbHelper ! = null & & ! cloneOrFinalizeHack )
2006-02-23 16:20:51 +03:00
{
ilgen . Emit ( OpCodes . Call , mbHelper ) ;
}
else
{
ilgen . Emit ( OpCodes . Callvirt , ( MethodInfo ) GetMethod ( ) ) ;
}
}
internal override MethodBase DoLink ( )
{
RemapperTypeWrapper typeWrapper = ( RemapperTypeWrapper ) DeclaringType ;
if ( typeWrapper . IsInterface )
{
if ( m . @override = = null )
{
throw new InvalidOperationException ( typeWrapper . Name + "." + m . Name + m . Sig ) ;
}
MethodInfo interfaceMethod = typeWrapper . shadowType . GetMethod ( m . @override . Name , typeWrapper . GetClassLoader ( ) . ArgTypeListFromSig ( m . Sig ) ) ;
if ( interfaceMethod = = null )
{
throw new InvalidOperationException ( typeWrapper . Name + "." + m . Name + m . Sig ) ;
}
// if any of the remapped types has a body for this interface method, we need a helper method
// to special invocation through this interface for that type
2008-08-08 10:26:37 +04:00
List < IKVM . Internal . MapXml . Class > specialCases = null ;
2006-02-23 16:20:51 +03:00
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
{
if ( c . Methods ! = null )
{
foreach ( IKVM . Internal . MapXml . Method mm in c . Methods )
{
if ( mm . Name = = m . Name & & mm . Sig = = m . Sig & & mm . body ! = null )
{
if ( specialCases = = null )
{
2008-08-08 10:26:37 +04:00
specialCases = new List < IKVM . Internal . MapXml . Class > ( ) ;
2006-02-23 16:20:51 +03:00
}
specialCases . Add ( c ) ;
break ;
}
}
}
}
2011-06-27 17:15:17 +04:00
string [ ] throws ;
if ( m . throws = = null )
{
throws = new string [ 0 ] ;
}
else
{
throws = new string [ m . throws . Length ] ;
for ( int i = 0 ; i < throws . Length ; i + + )
{
throws [ i ] = m . throws [ i ] . Class ;
}
}
AttributeHelper . SetRemappedInterfaceMethod ( typeWrapper . typeBuilder , m . Name , m . @override . Name , throws ) ;
2006-02-23 16:20:51 +03:00
MethodBuilder helper = null ;
if ( specialCases ! = null )
{
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen ;
2006-02-23 16:20:51 +03:00
Type [ ] temp = typeWrapper . GetClassLoader ( ) . ArgTypeListFromSig ( m . Sig ) ;
Type [ ] argTypes = new Type [ temp . Length + 1 ] ;
temp . CopyTo ( argTypes , 1 ) ;
argTypes [ 0 ] = typeWrapper . shadowType ;
if ( typeWrapper . helperTypeBuilder = = null )
{
2012-09-13 15:50:15 +04:00
typeWrapper . helperTypeBuilder = typeWrapper . typeBuilder . DefineNestedType ( "__Helper" , TypeAttributes . NestedPublic | TypeAttributes . Class | TypeAttributes . Sealed | TypeAttributes . Abstract ) ;
2006-02-23 16:20:51 +03:00
AttributeHelper . HideFromJava ( typeWrapper . helperTypeBuilder ) ;
}
helper = typeWrapper . helperTypeBuilder . DefineMethod ( m . Name , MethodAttributes . HideBySig | MethodAttributes . Public | MethodAttributes . Static , typeWrapper . GetClassLoader ( ) . RetTypeWrapperFromSig ( m . Sig ) . TypeAsSignatureType , argTypes ) ;
if ( m . Attributes ! = null )
{
foreach ( IKVM . Internal . MapXml . Attribute custattr in m . Attributes )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( DeclaringType . GetClassLoader ( ) , helper , custattr ) ;
2006-02-23 16:20:51 +03:00
}
}
2008-08-14 09:42:43 +04:00
SetParameters ( DeclaringType . GetClassLoader ( ) , helper , m . Params ) ;
2008-06-03 16:10:07 +04:00
ilgen = CodeEmitter . Create ( helper ) ;
2006-02-23 16:20:51 +03:00
foreach ( IKVM . Internal . MapXml . Class c in specialCases )
{
TypeWrapper tw = typeWrapper . GetClassLoader ( ) . LoadClassByDottedName ( c . Name ) ;
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
ilgen . Emit ( OpCodes . Isinst , tw . TypeAsTBD ) ;
ilgen . Emit ( OpCodes . Dup ) ;
2008-06-03 16:10:07 +04:00
CodeEmitterLabel label = ilgen . DefineLabel ( ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrfalse ( label ) ;
2006-02-23 16:20:51 +03:00
for ( int i = 1 ; i < argTypes . Length ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i ) ;
2006-02-23 16:20:51 +03:00
}
MethodWrapper mw = tw . GetMethodWrapper ( m . Name , m . Sig , false ) ;
mw . Link ( ) ;
mw . EmitCallvirt ( ilgen ) ;
ilgen . Emit ( OpCodes . Ret ) ;
ilgen . MarkLabel ( label ) ;
ilgen . Emit ( OpCodes . Pop ) ;
}
for ( int i = 0 ; i < argTypes . Length ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i ) ;
2006-02-23 16:20:51 +03:00
}
ilgen . Emit ( OpCodes . Callvirt , interfaceMethod ) ;
ilgen . Emit ( OpCodes . Ret ) ;
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-02-23 16:20:51 +03:00
}
mbHelper = helper ;
return interfaceMethod ;
}
else
{
MethodBuilder mbCore = null ;
Type [ ] paramTypes = typeWrapper . GetClassLoader ( ) . ArgTypeListFromSig ( m . Sig ) ;
Type retType = typeWrapper . GetClassLoader ( ) . RetTypeWrapperFromSig ( m . Sig ) . TypeAsSignatureType ;
if ( typeWrapper . shadowType . IsSealed & & ( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Static ) = = 0 )
{
// skip instance methods in sealed types, but we do need to add them to the overriders
if ( typeWrapper . BaseTypeWrapper ! = null & & ( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Private ) = = 0 )
{
RemappedMethodWrapper baseMethod = typeWrapper . BaseTypeWrapper . GetMethodWrapper ( m . Name , m . Sig , true ) as RemappedMethodWrapper ;
if ( baseMethod ! = null & &
! baseMethod . IsFinal & &
! baseMethod . IsPrivate & &
( baseMethod . m . @override ! = null | |
baseMethod . m . redirect ! = null | |
baseMethod . m . body ! = null | |
baseMethod . m . alternateBody ! = null ) )
{
baseMethod . overriders . Add ( typeWrapper ) ;
}
}
}
else
{
MethodInfo overrideMethod = null ;
2012-12-30 15:20:15 +04:00
MethodAttributes attr = m . MethodAttributes | MapMethodAccessModifiers ( m . Modifiers ) | MethodAttributes . HideBySig ;
2006-02-23 16:20:51 +03:00
if ( ( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Static ) ! = 0 )
{
attr | = MethodAttributes . Static ;
}
else if ( ( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Private ) = = 0 & & ( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Final ) = = 0 )
{
attr | = MethodAttributes . Virtual | MethodAttributes . NewSlot | MethodAttributes . CheckAccessOnOverride ;
2009-08-06 10:38:42 +04:00
if ( ! typeWrapper . shadowType . IsSealed )
{
MethodInfo autoOverride = typeWrapper . shadowType . GetMethod ( m . Name , BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic , null , paramTypes , null ) ;
if ( autoOverride ! = null & & autoOverride . ReturnType = = retType & & ! autoOverride . IsFinal )
{
// the method we're processing is overriding a method in its shadowType (which is the actual base type)
attr & = ~ MethodAttributes . NewSlot ;
}
}
2006-02-23 16:20:51 +03:00
if ( typeWrapper . BaseTypeWrapper ! = null )
{
RemappedMethodWrapper baseMethod = typeWrapper . BaseTypeWrapper . GetMethodWrapper ( m . Name , m . Sig , true ) as RemappedMethodWrapper ;
if ( baseMethod ! = null )
{
baseMethod . overriders . Add ( typeWrapper ) ;
if ( baseMethod . m . @override ! = null )
{
overrideMethod = typeWrapper . BaseTypeWrapper . TypeAsTBD . GetMethod ( baseMethod . m . @override . Name , BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic , null , paramTypes , null ) ;
if ( overrideMethod = = null )
{
throw new InvalidOperationException ( ) ;
}
}
}
}
}
mbCore = typeWrapper . typeBuilder . DefineMethod ( m . Name , attr , CallingConventions . Standard , retType , paramTypes ) ;
if ( m . Attributes ! = null )
{
foreach ( IKVM . Internal . MapXml . Attribute custattr in m . Attributes )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( DeclaringType . GetClassLoader ( ) , mbCore , custattr ) ;
2006-02-23 16:20:51 +03:00
}
}
2008-08-14 09:42:43 +04:00
SetParameters ( DeclaringType . GetClassLoader ( ) , mbCore , m . Params ) ;
2006-04-05 12:18:58 +04:00
if ( overrideMethod ! = null & & ! inherited )
2006-02-23 16:20:51 +03:00
{
typeWrapper . typeBuilder . DefineMethodOverride ( mbCore , overrideMethod ) ;
}
2006-04-05 12:18:58 +04:00
if ( inherited )
{
AttributeHelper . HideFromReflection ( mbCore ) ;
}
2006-02-23 16:20:51 +03:00
AddDeclaredExceptions ( mbCore , m . throws ) ;
}
2009-08-06 10:18:43 +04:00
if ( ( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Static ) = = 0 & & ! IsHideFromJava ( m ) )
2006-02-23 16:20:51 +03:00
{
// instance methods must have an instancehelper method
MethodAttributes attr = MapMethodAccessModifiers ( m . Modifiers ) | MethodAttributes . HideBySig | MethodAttributes . Static ;
2006-11-20 12:21:38 +03:00
// NOTE instancehelpers for protected methods are made internal
// and special cased in DotNetTypeWrapper.LazyPublishMembers
2006-02-23 16:20:51 +03:00
if ( ( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Protected ) ! = 0 )
{
attr & = ~ MethodAttributes . MemberAccessMask ;
2006-11-20 12:21:38 +03:00
attr | = MethodAttributes . Assembly ;
2006-02-23 16:20:51 +03:00
}
Type [ ] exParamTypes = new Type [ paramTypes . Length + 1 ] ;
Array . Copy ( paramTypes , 0 , exParamTypes , 1 , paramTypes . Length ) ;
exParamTypes [ 0 ] = typeWrapper . shadowType ;
mbHelper = typeWrapper . typeBuilder . DefineMethod ( "instancehelper_" + m . Name , attr , CallingConventions . Standard , retType , exParamTypes ) ;
if ( m . Attributes ! = null )
{
foreach ( IKVM . Internal . MapXml . Attribute custattr in m . Attributes )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( DeclaringType . GetClassLoader ( ) , mbHelper , custattr ) ;
2006-02-23 16:20:51 +03:00
}
}
IKVM . Internal . MapXml . Param [ ] parameters ;
if ( m . Params = = null )
{
parameters = new IKVM . Internal . MapXml . Param [ 1 ] ;
}
else
{
parameters = new IKVM . Internal . MapXml . Param [ m . Params . Length + 1 ] ;
m . Params . CopyTo ( parameters , 1 ) ;
}
parameters [ 0 ] = new IKVM . Internal . MapXml . Param ( ) ;
parameters [ 0 ] . Name = "this" ;
2008-08-14 09:42:43 +04:00
SetParameters ( DeclaringType . GetClassLoader ( ) , mbHelper , parameters ) ;
2006-02-23 16:20:51 +03:00
if ( ! typeWrapper . IsFinal )
{
AttributeHelper . SetEditorBrowsableNever ( mbHelper ) ;
}
2006-04-05 12:18:58 +04:00
AttributeHelper . SetModifiers ( mbHelper , ( Modifiers ) m . Modifiers , false ) ;
2006-02-23 16:20:51 +03:00
AttributeHelper . SetNameSig ( mbHelper , m . Name , m . Sig ) ;
AddDeclaredExceptions ( mbHelper , m . throws ) ;
2011-11-28 17:23:02 +04:00
mbHelper . SetCustomAttribute ( new CustomAttributeBuilder ( JVM . Import ( typeof ( ObsoleteAttribute ) ) . GetConstructor ( new Type [ ] { Types . String } ) , new object [ ] { "This function will be removed from future versions. Please use extension methods from ikvm.extensions namespace instead." } ) ) ;
2006-02-23 16:20:51 +03:00
}
return mbCore ;
}
}
2009-08-06 10:18:43 +04:00
private static bool IsHideFromJava ( IKVM . Internal . MapXml . Method m )
{
if ( m . Attributes ! = null )
{
foreach ( MapXml . Attribute attr in m . Attributes )
{
if ( attr . Type = = "IKVM.Attributes.HideFromJavaAttribute" )
{
return true ;
}
}
}
2012-12-30 15:20:15 +04:00
return m . Name . StartsWith ( "__<" , StringComparison . Ordinal ) ;
2009-08-06 10:18:43 +04:00
}
2006-02-23 16:20:51 +03:00
internal override void Finish ( )
{
// TODO we should insert method tracing (if enabled)
Type [ ] paramTypes = this . GetParametersForDefineMethod ( ) ;
MethodBuilder mbCore = GetMethod ( ) as MethodBuilder ;
// NOTE sealed types don't have instance methods (only instancehelpers)
if ( mbCore ! = null )
{
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( mbCore ) ;
2006-02-23 16:20:51 +03:00
MethodInfo baseMethod = null ;
if ( m . @override ! = null )
{
baseMethod = DeclaringType . TypeAsTBD . GetMethod ( m . @override . Name , BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic , null , paramTypes , null ) ;
if ( baseMethod = = null )
{
throw new InvalidOperationException ( ) ;
}
( ( TypeBuilder ) DeclaringType . TypeAsBaseType ) . DefineMethodOverride ( mbCore , baseMethod ) ;
}
// TODO we need to support ghost (and other funky?) parameter types
if ( m . body ! = null )
{
// we manually walk the instruction list, because we need to special case the ret instructions
2008-08-14 09:42:43 +04:00
IKVM . Internal . MapXml . CodeGenContext context = new IKVM . Internal . MapXml . CodeGenContext ( DeclaringType . GetClassLoader ( ) ) ;
2006-02-23 16:20:51 +03:00
foreach ( IKVM . Internal . MapXml . Instruction instr in m . body . invoke )
{
if ( instr is IKVM . Internal . MapXml . Ret )
{
this . ReturnType . EmitConvStackTypeToSignatureType ( ilgen , null ) ;
}
instr . Generate ( context , ilgen ) ;
}
}
else
{
if ( m . redirect ! = null & & m . redirect . LineNumber ! = - 1 )
{
ilgen . SetLineNumber ( ( ushort ) m . redirect . LineNumber ) ;
}
int thisOffset = 0 ;
if ( ( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Static ) = = 0 )
{
thisOffset = 1 ;
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
}
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i + thisOffset ) ;
2006-02-23 16:20:51 +03:00
}
if ( m . redirect ! = null )
{
EmitRedirect ( DeclaringType . TypeAsTBD , ilgen ) ;
}
else
{
if ( baseMethod = = null )
{
throw new InvalidOperationException ( DeclaringType . Name + "." + m . Name + m . Sig ) ;
}
ilgen . Emit ( OpCodes . Call , baseMethod ) ;
}
this . ReturnType . EmitConvStackTypeToSignatureType ( ilgen , null ) ;
ilgen . Emit ( OpCodes . Ret ) ;
}
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-08-29 10:28:34 +04:00
if ( this . DeclaringType . GetClassLoader ( ) . EmitStackTraceInfo )
{
ilgen . EmitLineNumberTable ( mbCore ) ;
}
2006-02-23 16:20:51 +03:00
}
// NOTE static methods don't have helpers
2007-01-04 10:46:38 +03:00
// NOTE for interface helpers we don't have to do anything,
// because they've already been generated in DoLink
// (currently this only applies to Comparable.compareTo).
if ( mbHelper ! = null & & ! this . DeclaringType . IsInterface )
2006-02-23 16:20:51 +03:00
{
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( mbHelper ) ;
2006-02-23 16:20:51 +03:00
// check "this" for null
if ( m . @override ! = null & & m . redirect = = null & & m . body = = null & & m . alternateBody = = null )
{
// we're going to be calling the overridden version, so we don't need the null check
}
2007-04-23 12:20:15 +04:00
else if ( ! m . NoNullCheck )
2006-02-23 16:20:51 +03:00
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
2009-08-31 09:02:34 +04:00
ilgen . EmitNullCheck ( ) ;
2006-02-23 16:20:51 +03:00
}
if ( mbCore ! = null & &
( m . @override = = null | | m . redirect ! = null ) & &
( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Private ) = = 0 & & ( m . Modifiers & IKVM . Internal . MapXml . MapModifiers . Final ) = = 0 )
{
// TODO we should have a way to supress this for overridden methods
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
ilgen . Emit ( OpCodes . Isinst , DeclaringType . TypeAsBaseType ) ;
ilgen . Emit ( OpCodes . Dup ) ;
2008-06-03 16:10:07 +04:00
CodeEmitterLabel skip = ilgen . DefineLabel ( ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrfalse ( skip ) ;
2006-02-23 16:20:51 +03:00
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i + 1 ) ;
2006-02-23 16:20:51 +03:00
}
ilgen . Emit ( OpCodes . Callvirt , mbCore ) ;
this . ReturnType . EmitConvStackTypeToSignatureType ( ilgen , null ) ;
ilgen . Emit ( OpCodes . Ret ) ;
ilgen . MarkLabel ( skip ) ;
ilgen . Emit ( OpCodes . Pop ) ;
}
foreach ( RemapperTypeWrapper overrider in overriders )
{
RemappedMethodWrapper mw = ( RemappedMethodWrapper ) overrider . GetMethodWrapper ( Name , Signature , false ) ;
if ( mw . m . redirect = = null & & mw . m . body = = null & & mw . m . alternateBody = = null )
{
// the overridden method doesn't actually do anything special (that means it will end
// up calling the .NET method it overrides), so we don't need to special case this
}
else
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
ilgen . Emit ( OpCodes . Isinst , overrider . TypeAsTBD ) ;
ilgen . Emit ( OpCodes . Dup ) ;
2008-06-03 16:10:07 +04:00
CodeEmitterLabel skip = ilgen . DefineLabel ( ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrfalse ( skip ) ;
2006-02-23 16:20:51 +03:00
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i + 1 ) ;
2006-02-23 16:20:51 +03:00
}
mw . Link ( ) ;
2008-12-23 09:12:05 +03:00
mw . EmitCallvirtImpl ( ilgen , false ) ;
2006-02-23 16:20:51 +03:00
this . ReturnType . EmitConvStackTypeToSignatureType ( ilgen , null ) ;
ilgen . Emit ( OpCodes . Ret ) ;
ilgen . MarkLabel ( skip ) ;
ilgen . Emit ( OpCodes . Pop ) ;
}
}
if ( m . body ! = null | | m . alternateBody ! = null )
{
IKVM . Internal . MapXml . InstructionList body = m . alternateBody = = null ? m . body : m . alternateBody ;
// we manually walk the instruction list, because we need to special case the ret instructions
2008-08-14 09:42:43 +04:00
IKVM . Internal . MapXml . CodeGenContext context = new IKVM . Internal . MapXml . CodeGenContext ( DeclaringType . GetClassLoader ( ) ) ;
2006-02-23 16:20:51 +03:00
foreach ( IKVM . Internal . MapXml . Instruction instr in body . invoke )
{
if ( instr is IKVM . Internal . MapXml . Ret )
{
this . ReturnType . EmitConvStackTypeToSignatureType ( ilgen , null ) ;
}
instr . Generate ( context , ilgen ) ;
}
}
else
{
if ( m . redirect ! = null & & m . redirect . LineNumber ! = - 1 )
{
ilgen . SetLineNumber ( ( ushort ) m . redirect . LineNumber ) ;
}
Type shadowType = ( ( RemapperTypeWrapper ) DeclaringType ) . shadowType ;
for ( int i = 0 ; i < paramTypes . Length + 1 ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i ) ;
2006-02-23 16:20:51 +03:00
}
if ( m . redirect ! = null )
{
EmitRedirect ( shadowType , ilgen ) ;
}
else if ( m . @override ! = null )
{
MethodInfo baseMethod = shadowType . GetMethod ( m . @override . Name , BindingFlags . Instance | BindingFlags . Public , null , paramTypes , null ) ;
if ( baseMethod = = null )
{
throw new InvalidOperationException ( DeclaringType . Name + "." + m . Name + m . Sig ) ;
}
ilgen . Emit ( OpCodes . Callvirt , baseMethod ) ;
}
else
{
RemappedMethodWrapper baseMethod = DeclaringType . BaseTypeWrapper . GetMethodWrapper ( Name , Signature , true ) as RemappedMethodWrapper ;
if ( baseMethod = = null | | baseMethod . m . @override = = null )
{
throw new InvalidOperationException ( DeclaringType . Name + "." + m . Name + m . Sig ) ;
}
MethodInfo overrideMethod = shadowType . GetMethod ( baseMethod . m . @override . Name , BindingFlags . Instance | BindingFlags . Public , null , paramTypes , null ) ;
if ( overrideMethod = = null )
{
throw new InvalidOperationException ( DeclaringType . Name + "." + m . Name + m . Sig ) ;
}
ilgen . Emit ( OpCodes . Callvirt , overrideMethod ) ;
}
this . ReturnType . EmitConvStackTypeToSignatureType ( ilgen , null ) ;
ilgen . Emit ( OpCodes . Ret ) ;
}
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-08-29 10:28:34 +04:00
if ( this . DeclaringType . GetClassLoader ( ) . EmitStackTraceInfo )
{
ilgen . EmitLineNumberTable ( mbHelper ) ;
}
2006-02-23 16:20:51 +03:00
}
// do we need a helper for non-virtual reflection invocation?
if ( m . nonvirtualAlternateBody ! = null | | ( m . @override ! = null & & overriders . Count > 0 ) )
{
RemapperTypeWrapper typeWrapper = ( RemapperTypeWrapper ) DeclaringType ;
Type [ ] argTypes = new Type [ paramTypes . Length + 1 ] ;
argTypes [ 0 ] = typeWrapper . TypeAsSignatureType ;
this . GetParametersForDefineMethod ( ) . CopyTo ( argTypes , 1 ) ;
MethodBuilder mb = typeWrapper . typeBuilder . DefineMethod ( "nonvirtualhelper/" + this . Name , MethodAttributes . Private | MethodAttributes . Static , this . ReturnTypeForDefineMethod , argTypes ) ;
if ( m . Attributes ! = null )
{
foreach ( IKVM . Internal . MapXml . Attribute custattr in m . Attributes )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( DeclaringType . GetClassLoader ( ) , mb , custattr ) ;
2006-02-23 16:20:51 +03:00
}
}
2008-08-14 09:42:43 +04:00
SetParameters ( DeclaringType . GetClassLoader ( ) , mb , m . Params ) ;
2006-02-23 16:20:51 +03:00
AttributeHelper . HideFromJava ( mb ) ;
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( mb ) ;
2006-02-23 16:20:51 +03:00
if ( m . nonvirtualAlternateBody ! = null )
{
2008-08-14 09:42:43 +04:00
m . nonvirtualAlternateBody . Emit ( DeclaringType . GetClassLoader ( ) , ilgen ) ;
2006-02-23 16:20:51 +03:00
}
else
{
Type shadowType = ( ( RemapperTypeWrapper ) DeclaringType ) . shadowType ;
MethodInfo baseMethod = shadowType . GetMethod ( m . @override . Name , BindingFlags . Instance | BindingFlags . Public , null , paramTypes , null ) ;
if ( baseMethod = = null )
{
throw new InvalidOperationException ( DeclaringType . Name + "." + m . Name + m . Sig ) ;
}
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i + 1 ) ;
2006-02-23 16:20:51 +03:00
}
ilgen . Emit ( OpCodes . Call , baseMethod ) ;
ilgen . Emit ( OpCodes . Ret ) ;
}
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-02-23 16:20:51 +03:00
}
}
2008-06-03 16:10:07 +04:00
private void EmitRedirect ( Type baseType , CodeEmitter ilgen )
2006-02-23 16:20:51 +03:00
{
string redirName = m . redirect . Name ;
string redirSig = m . redirect . Sig ;
if ( redirName = = null )
{
redirName = m . Name ;
}
if ( redirSig = = null )
{
redirSig = m . Sig ;
}
2008-08-14 09:42:43 +04:00
ClassLoaderWrapper classLoader = DeclaringType . GetClassLoader ( ) ;
2006-02-23 16:20:51 +03:00
// HACK if the class name contains a comma, we assume it is a .NET type
if ( m . redirect . Class = = null | | m . redirect . Class . IndexOf ( ',' ) > = 0 )
{
// TODO better error handling
2010-05-20 08:59:13 +04:00
Type type = m . redirect . Class = = null ? baseType : StaticCompiler . Universe . GetType ( m . redirect . Class , true ) ;
2006-02-23 16:20:51 +03:00
Type [ ] redirParamTypes = classLoader . ArgTypeListFromSig ( redirSig ) ;
MethodInfo mi = type . GetMethod ( m . redirect . Name , redirParamTypes ) ;
if ( mi = = null )
{
throw new InvalidOperationException ( ) ;
}
ilgen . Emit ( OpCodes . Call , mi ) ;
}
else
{
2008-08-14 09:42:43 +04:00
TypeWrapper tw = classLoader . LoadClassByDottedName ( m . redirect . Class ) ;
2006-02-23 16:20:51 +03:00
MethodWrapper mw = tw . GetMethodWrapper ( redirName , redirSig , false ) ;
if ( mw = = null )
{
throw new InvalidOperationException ( "Missing redirect method: " + tw . Name + "." + redirName + redirSig ) ;
}
mw . Link ( ) ;
mw . EmitCall ( ilgen ) ;
}
}
}
2008-08-14 09:42:43 +04:00
private static void SetParameters ( ClassLoaderWrapper loader , MethodBuilder mb , IKVM . Internal . MapXml . Param [ ] parameters )
2006-02-23 16:20:51 +03:00
{
if ( parameters ! = null )
{
for ( int i = 0 ; i < parameters . Length ; i + + )
{
ParameterBuilder pb = mb . DefineParameter ( i + 1 , ParameterAttributes . None , parameters [ i ] . Name ) ;
if ( parameters [ i ] . Attributes ! = null )
{
for ( int j = 0 ; j < parameters [ i ] . Attributes . Length ; j + + )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( loader , pb , parameters [ i ] . Attributes [ j ] ) ;
2006-02-23 16:20:51 +03:00
}
}
}
}
}
2011-12-14 13:04:57 +04:00
internal void Process2ndPassStep1 ( )
2006-02-23 16:20:51 +03:00
{
2011-12-14 13:04:57 +04:00
if ( ! shadowType . IsSealed )
2006-02-23 16:20:51 +03:00
{
2011-12-14 13:04:57 +04:00
foreach ( TypeWrapper ifaceTypeWrapper in interfaceWrappers )
2006-02-23 16:20:51 +03:00
{
2011-12-14 13:04:57 +04:00
typeBuilder . AddInterfaceImplementation ( ifaceTypeWrapper . TypeAsBaseType ) ;
2006-02-23 16:20:51 +03:00
}
}
2011-12-14 13:04:57 +04:00
AttributeHelper . SetImplementsAttribute ( typeBuilder , interfaceWrappers ) ;
2006-02-23 16:20:51 +03:00
}
internal void Process2ndPassStep2 ( IKVM . Internal . MapXml . Root map )
{
IKVM . Internal . MapXml . Class c = classDef ;
TypeBuilder tb = typeBuilder ;
2008-08-08 10:26:37 +04:00
List < FieldWrapper > fields = new List < FieldWrapper > ( ) ;
2006-02-23 16:20:51 +03:00
// TODO fields should be moved to the RemapperTypeWrapper constructor as well
if ( c . Fields ! = null )
{
foreach ( IKVM . Internal . MapXml . Field f in c . Fields )
{
{
2009-03-16 08:28:11 +03:00
FieldAttributes attr = MapFieldAccessModifiers ( f . Modifiers ) ;
2006-02-23 16:20:51 +03:00
if ( f . Constant ! = null )
{
attr | = FieldAttributes . Literal ;
}
else if ( ( f . Modifiers & IKVM . Internal . MapXml . MapModifiers . Final ) ! = 0 )
{
attr | = FieldAttributes . InitOnly ;
}
2009-03-16 08:28:11 +03:00
if ( ( f . Modifiers & IKVM . Internal . MapXml . MapModifiers . Static ) ! = 0 )
{
attr | = FieldAttributes . Static ;
}
2006-02-23 16:20:51 +03:00
FieldBuilder fb = tb . DefineField ( f . Name , GetClassLoader ( ) . FieldTypeWrapperFromSig ( f . Sig ) . TypeAsSignatureType , attr ) ;
if ( f . Attributes ! = null )
{
foreach ( IKVM . Internal . MapXml . Attribute custattr in f . Attributes )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( classLoader , fb , custattr ) ;
2006-02-23 16:20:51 +03:00
}
}
object constant ;
if ( f . Constant ! = null )
{
switch ( f . Sig [ 0 ] )
{
case 'J' :
constant = long . Parse ( f . Constant ) ;
break ;
default :
// TODO support other types
throw new NotImplementedException ( "remapped constant field of type: " + f . Sig ) ;
}
fb . SetConstant ( constant ) ;
2006-10-10 20:24:48 +04:00
fields . Add ( new ConstantFieldWrapper ( this , GetClassLoader ( ) . FieldTypeWrapperFromSig ( f . Sig ) , f . Name , f . Sig , ( Modifiers ) f . Modifiers , fb , constant , MemberFlags . None ) ) ;
2006-02-23 16:20:51 +03:00
}
else
{
2006-04-05 12:18:58 +04:00
fields . Add ( FieldWrapper . Create ( this , GetClassLoader ( ) . FieldTypeWrapperFromSig ( f . Sig ) , fb , f . Name , f . Sig , new ExModifiers ( ( Modifiers ) f . Modifiers , false ) ) ) ;
2006-02-23 16:20:51 +03:00
}
}
}
}
2008-08-08 10:26:37 +04:00
SetFields ( fields . ToArray ( ) ) ;
2006-02-23 16:20:51 +03:00
}
internal void Process3rdPass ( )
{
foreach ( RemappedMethodBaseWrapper m in GetMethods ( ) )
{
m . Link ( ) ;
}
}
2011-12-14 11:56:53 +04:00
internal void Process4thPass ( ICollection < RemapperTypeWrapper > remappedTypes )
2006-02-23 16:20:51 +03:00
{
foreach ( RemappedMethodBaseWrapper m in GetMethods ( ) )
{
m . Finish ( ) ;
}
if ( classDef . Clinit ! = null )
{
2012-09-11 16:00:46 +04:00
MethodBuilder cb = ReflectUtil . DefineTypeInitializer ( typeBuilder ) ;
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( cb ) ;
2006-02-23 16:20:51 +03:00
// TODO emit code to make sure super class is initialized
2008-08-14 09:42:43 +04:00
classDef . Clinit . body . Emit ( classLoader , ilgen ) ;
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-02-23 16:20:51 +03:00
}
// FXBUG because the AppDomain.TypeResolve event doesn't work correctly for inner classes,
// we need to explicitly finish the interface we implement (if they are ghosts, we need the nested __Interface type)
if ( classDef . Interfaces ! = null )
{
foreach ( IKVM . Internal . MapXml . Interface iface in classDef . Interfaces )
{
GetClassLoader ( ) . LoadClassByDottedName ( iface . Name ) . Finish ( ) ;
}
}
CreateShadowInstanceOf ( remappedTypes ) ;
CreateShadowCheckCast ( remappedTypes ) ;
if ( ! shadowType . IsInterface )
{
// For all inherited methods, we emit a method that hides the inherited method and
// annotate it with EditorBrowsableAttribute(EditorBrowsableState.Never) to make
// sure the inherited methods don't show up in Intellisense.
2008-08-08 10:26:37 +04:00
Dictionary < string , MethodBuilder > methods = new Dictionary < string , MethodBuilder > ( ) ;
2009-08-06 10:21:37 +04:00
foreach ( MethodWrapper mw in GetMethods ( ) )
{
MethodBuilder mb = mw . GetMethod ( ) as MethodBuilder ;
if ( mb ! = null )
{
methods . Add ( MakeMethodKey ( mb ) , mb ) ;
}
}
2006-02-23 16:20:51 +03:00
foreach ( MethodInfo mi in typeBuilder . BaseType . GetMethods ( BindingFlags . Public | BindingFlags . Instance | BindingFlags . Static | BindingFlags . FlattenHierarchy ) )
{
string key = MakeMethodKey ( mi ) ;
if ( ! methods . ContainsKey ( key ) )
{
ParameterInfo [ ] paramInfo = mi . GetParameters ( ) ;
Type [ ] paramTypes = new Type [ paramInfo . Length ] ;
for ( int i = 0 ; i < paramInfo . Length ; i + + )
{
paramTypes [ i ] = paramInfo [ i ] . ParameterType ;
}
MethodBuilder mb = typeBuilder . DefineMethod ( mi . Name , mi . Attributes & ( MethodAttributes . MemberAccessMask | MethodAttributes . SpecialName | MethodAttributes . Static ) , mi . ReturnType , paramTypes ) ;
AttributeHelper . HideFromJava ( mb ) ;
AttributeHelper . SetEditorBrowsableNever ( mb ) ;
2007-03-15 11:04:35 +03:00
CopyLinkDemands ( mb , mi ) ;
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( mb ) ;
2006-02-23 16:20:51 +03:00
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( i ) ;
2006-02-23 16:20:51 +03:00
}
if ( ! mi . IsStatic )
{
2012-07-03 18:45:51 +04:00
ilgen . EmitLdarg ( paramTypes . Length ) ;
2006-11-16 10:32:44 +03:00
ilgen . Emit ( OpCodes . Callvirt , mi ) ;
}
else
{
ilgen . Emit ( OpCodes . Call , mi ) ;
2006-02-23 16:20:51 +03:00
}
ilgen . Emit ( OpCodes . Ret ) ;
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-02-23 16:20:51 +03:00
methods [ key ] = mb ;
}
}
foreach ( PropertyInfo pi in typeBuilder . BaseType . GetProperties ( BindingFlags . Public | BindingFlags . Instance | BindingFlags . Static ) )
{
ParameterInfo [ ] paramInfo = pi . GetIndexParameters ( ) ;
Type [ ] paramTypes = new Type [ paramInfo . Length ] ;
for ( int i = 0 ; i < paramInfo . Length ; i + + )
{
paramTypes [ i ] = paramInfo [ i ] . ParameterType ;
}
PropertyBuilder pb = typeBuilder . DefineProperty ( pi . Name , PropertyAttributes . None , pi . PropertyType , paramTypes ) ;
2012-03-19 13:47:52 +04:00
if ( pi . GetGetMethod ( ) ! = null )
2006-02-23 16:20:51 +03:00
{
2012-09-13 19:19:35 +04:00
pb . SetGetMethod ( methods [ MakeMethodKey ( pi . GetGetMethod ( ) ) ] ) ;
2006-02-23 16:20:51 +03:00
}
2012-03-19 13:47:52 +04:00
if ( pi . GetSetMethod ( ) ! = null )
2006-02-23 16:20:51 +03:00
{
2012-09-13 19:19:35 +04:00
pb . SetSetMethod ( methods [ MakeMethodKey ( pi . GetSetMethod ( ) ) ] ) ;
2006-02-23 16:20:51 +03:00
}
AttributeHelper . SetEditorBrowsableNever ( pb ) ;
}
}
typeBuilder . CreateType ( ) ;
if ( helperTypeBuilder ! = null )
{
helperTypeBuilder . CreateType ( ) ;
}
}
2007-03-15 11:04:35 +03:00
private static void CopyLinkDemands ( MethodBuilder mb , MethodInfo mi )
{
2010-01-25 10:52:27 +03:00
foreach ( CustomAttributeData cad in CustomAttributeData . __GetDeclarativeSecurity ( mi ) )
{
if ( cad . ConstructorArguments . Count = = 0 | | ( int ) cad . ConstructorArguments [ 0 ] . Value = = ( int ) SecurityAction . LinkDemand )
{
mb . __AddDeclarativeSecurity ( cad . __ToBuilder ( ) ) ;
}
}
2007-03-15 11:04:35 +03:00
}
2006-02-23 16:20:51 +03:00
private static string MakeMethodKey ( MethodInfo method )
{
StringBuilder sb = new StringBuilder ( ) ;
sb . Append ( method . ReturnType . AssemblyQualifiedName ) . Append ( ":" ) . Append ( method . Name ) ;
ParameterInfo [ ] paramInfo = method . GetParameters ( ) ;
Type [ ] paramTypes = new Type [ paramInfo . Length ] ;
for ( int i = 0 ; i < paramInfo . Length ; i + + )
{
paramTypes [ i ] = paramInfo [ i ] . ParameterType ;
sb . Append ( ":" ) . Append ( paramInfo [ i ] . ParameterType . AssemblyQualifiedName ) ;
}
return sb . ToString ( ) ;
}
2011-12-14 11:56:53 +04:00
private void CreateShadowInstanceOf ( ICollection < RemapperTypeWrapper > remappedTypes )
2006-02-23 16:20:51 +03:00
{
// FXBUG .NET 1.1 doesn't allow static methods on interfaces
if ( typeBuilder . IsInterface )
{
return ;
}
MethodAttributes attr = MethodAttributes . SpecialName | MethodAttributes . Public | MethodAttributes . Static ;
2009-10-14 18:58:41 +04:00
MethodBuilder mb = typeBuilder . DefineMethod ( "__<instanceof>" , attr , Types . Boolean , new Type [ ] { Types . Object } ) ;
2006-02-23 16:20:51 +03:00
AttributeHelper . HideFromJava ( mb ) ;
AttributeHelper . SetEditorBrowsableNever ( mb ) ;
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( mb ) ;
2006-02-23 16:20:51 +03:00
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
ilgen . Emit ( OpCodes . Isinst , shadowType ) ;
2008-06-03 16:10:07 +04:00
CodeEmitterLabel retFalse = ilgen . DefineLabel ( ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrfalse ( retFalse ) ;
2006-02-23 16:20:51 +03:00
if ( ! shadowType . IsSealed )
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
ilgen . Emit ( OpCodes . Isinst , typeBuilder ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrtrue ( retFalse ) ;
2006-02-23 16:20:51 +03:00
}
2009-10-14 18:58:41 +04:00
if ( shadowType = = Types . Object )
2006-02-23 16:20:51 +03:00
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
2009-10-14 18:58:41 +04:00
ilgen . Emit ( OpCodes . Isinst , Types . Array ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrtrue ( retFalse ) ;
2006-02-23 16:20:51 +03:00
}
foreach ( RemapperTypeWrapper r in remappedTypes )
{
if ( ! r . shadowType . IsInterface & & r . shadowType . IsSubclassOf ( shadowType ) )
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
ilgen . Emit ( OpCodes . Isinst , r . shadowType ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrtrue ( retFalse ) ;
2006-02-23 16:20:51 +03:00
}
}
ilgen . Emit ( OpCodes . Ldc_I4_1 ) ;
ilgen . Emit ( OpCodes . Ret ) ;
ilgen . MarkLabel ( retFalse ) ;
ilgen . Emit ( OpCodes . Ldc_I4_0 ) ;
ilgen . Emit ( OpCodes . Ret ) ;
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-02-23 16:20:51 +03:00
}
2011-12-14 11:56:53 +04:00
private void CreateShadowCheckCast ( ICollection < RemapperTypeWrapper > remappedTypes )
2006-02-23 16:20:51 +03:00
{
// FXBUG .NET 1.1 doesn't allow static methods on interfaces
if ( typeBuilder . IsInterface )
{
return ;
}
MethodAttributes attr = MethodAttributes . SpecialName | MethodAttributes . Public | MethodAttributes . Static ;
2009-10-14 18:58:41 +04:00
MethodBuilder mb = typeBuilder . DefineMethod ( "__<checkcast>" , attr , shadowType , new Type [ ] { Types . Object } ) ;
2006-02-23 16:20:51 +03:00
AttributeHelper . HideFromJava ( mb ) ;
AttributeHelper . SetEditorBrowsableNever ( mb ) ;
2008-06-03 16:10:07 +04:00
CodeEmitter ilgen = CodeEmitter . Create ( mb ) ;
2006-02-23 16:20:51 +03:00
2008-06-03 16:10:07 +04:00
CodeEmitterLabel fail = ilgen . DefineLabel ( ) ;
2006-02-23 16:20:51 +03:00
bool hasfail = false ;
if ( ! shadowType . IsSealed )
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
ilgen . Emit ( OpCodes . Isinst , typeBuilder ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrtrue ( fail ) ;
2006-02-23 16:20:51 +03:00
hasfail = true ;
}
2009-10-14 18:58:41 +04:00
if ( shadowType = = Types . Object )
2006-02-23 16:20:51 +03:00
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
2009-10-14 18:58:41 +04:00
ilgen . Emit ( OpCodes . Isinst , Types . Array ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrtrue ( fail ) ;
2006-02-23 16:20:51 +03:00
hasfail = true ;
}
foreach ( RemapperTypeWrapper r in remappedTypes )
{
if ( ! r . shadowType . IsInterface & & r . shadowType . IsSubclassOf ( shadowType ) )
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
ilgen . Emit ( OpCodes . Isinst , r . shadowType ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrtrue ( fail ) ;
2006-02-23 16:20:51 +03:00
hasfail = true ;
}
}
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
2009-08-31 09:02:34 +04:00
ilgen . EmitCastclass ( shadowType ) ;
2006-02-23 16:20:51 +03:00
ilgen . Emit ( OpCodes . Ret ) ;
if ( hasfail )
{
ilgen . MarkLabel ( fail ) ;
2009-10-14 18:58:41 +04:00
ilgen . ThrowException ( JVM . Import ( typeof ( InvalidCastException ) ) ) ;
2006-02-23 16:20:51 +03:00
}
2010-09-30 08:03:32 +04:00
ilgen . DoEmit ( ) ;
2006-02-23 16:20:51 +03:00
}
internal override MethodBase LinkMethod ( MethodWrapper mw )
{
return ( ( RemappedMethodBaseWrapper ) mw ) . DoLink ( ) ;
}
internal override TypeWrapper DeclaringTypeWrapper
{
get
{
// at the moment we don't support nested remapped types
return null ;
}
}
internal override void Finish ( )
{
if ( BaseTypeWrapper ! = null )
{
BaseTypeWrapper . Finish ( ) ;
}
foreach ( TypeWrapper iface in Interfaces )
{
iface . Finish ( ) ;
}
foreach ( MethodWrapper m in GetMethods ( ) )
{
m . Link ( ) ;
}
foreach ( FieldWrapper f in GetFields ( ) )
{
f . Link ( ) ;
}
}
internal override TypeWrapper [ ] InnerClasses
{
get
{
return TypeWrapper . EmptyArray ;
}
}
internal override TypeWrapper [ ] Interfaces
{
get
{
return interfaceWrappers ;
}
}
internal override Type TypeAsTBD
{
get
{
return shadowType ;
}
}
internal override Type TypeAsBaseType
{
get
{
return typeBuilder ;
}
}
internal override bool IsMapUnsafeException
{
get
{
// any remapped exceptions are automatically unsafe
2009-10-14 18:58:41 +04:00
return shadowType = = Types . Exception | | shadowType . IsSubclassOf ( Types . Exception ) ;
2006-02-23 16:20:51 +03:00
}
}
2009-07-14 10:27:41 +04:00
internal override bool IsFastClassLiteralSafe
{
get { return true ; }
}
2006-02-23 16:20:51 +03:00
}
2012-09-13 17:21:35 +04:00
internal static void AddDeclaredExceptions ( MethodBuilder mb , IKVM . Internal . MapXml . Throws [ ] throws )
2011-08-08 15:28:05 +04:00
{
if ( throws ! = null )
{
string [ ] exceptions = new string [ throws . Length ] ;
for ( int i = 0 ; i < exceptions . Length ; i + + )
{
exceptions [ i ] = throws [ i ] . Class ;
}
AttributeHelper . SetThrowsAttribute ( mb , exceptions ) ;
}
}
2008-08-13 17:04:47 +04:00
internal void EmitRemappedTypes ( )
2006-02-23 16:20:51 +03:00
{
Tracer . Info ( Tracer . Compiler , "Emit remapped types" ) ;
assemblyAttributes = map . assembly . Attributes ;
2007-05-27 12:13:44 +04:00
if ( map . assembly . Classes ! = null )
2006-02-23 16:20:51 +03:00
{
2007-05-27 12:13:44 +04:00
// 1st pass, put all types in remapped to make them loadable
bool hasRemappedTypes = false ;
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
2006-02-23 16:20:51 +03:00
{
2007-05-27 12:13:44 +04:00
if ( c . Shadows ! = null )
{
remapped . Add ( c . Name , new RemapperTypeWrapper ( this , c , map ) ) ;
hasRemappedTypes = true ;
}
2006-02-23 16:20:51 +03:00
}
2007-05-27 12:13:44 +04:00
if ( hasRemappedTypes )
{
SetupGhosts ( map ) ;
2011-12-14 13:04:57 +04:00
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
{
if ( c . Shadows ! = null )
{
remapped [ c . Name ] . LoadInterfaces ( c ) ;
}
}
2007-05-27 12:13:44 +04:00
}
2008-12-23 09:14:42 +03:00
}
}
2006-02-23 16:20:51 +03:00
2008-12-23 09:14:42 +03:00
internal void EmitRemappedTypes2ndPass ( )
{
if ( map ! = null & & map . assembly ! = null & & map . assembly . Classes ! = null )
{
2007-05-27 12:13:44 +04:00
// 2nd pass, resolve interfaces, publish methods/fields
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
2006-02-23 16:20:51 +03:00
{
2007-05-27 12:13:44 +04:00
if ( c . Shadows ! = null )
{
RemapperTypeWrapper typeWrapper = ( RemapperTypeWrapper ) remapped [ c . Name ] ;
2011-12-14 13:04:57 +04:00
typeWrapper . Process2ndPassStep1 ( ) ;
2007-05-27 12:13:44 +04:00
}
2006-02-23 16:20:51 +03:00
}
2007-05-27 12:13:44 +04:00
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
2006-02-23 16:20:51 +03:00
{
2007-05-27 12:13:44 +04:00
if ( c . Shadows ! = null )
{
RemapperTypeWrapper typeWrapper = ( RemapperTypeWrapper ) remapped [ c . Name ] ;
typeWrapper . Process2ndPassStep2 ( map ) ;
}
2006-02-23 16:20:51 +03:00
}
}
}
2006-08-29 15:56:09 +04:00
internal bool IsMapUnsafeException ( TypeWrapper tw )
{
if ( mappedExceptions ! = null )
{
for ( int i = 0 ; i < mappedExceptions . Length ; i + + )
{
if ( mappedExceptions [ i ] . IsSubTypeOf ( tw ) | |
( mappedExceptionsAllSubClasses [ i ] & & tw . IsSubTypeOf ( mappedExceptions [ i ] ) ) )
{
return true ;
}
}
}
return false ;
}
internal void LoadMappedExceptions ( IKVM . Internal . MapXml . Root map )
{
if ( map . exceptionMappings ! = null )
{
mappedExceptionsAllSubClasses = new bool [ map . exceptionMappings . Length ] ;
mappedExceptions = new TypeWrapper [ map . exceptionMappings . Length ] ;
for ( int i = 0 ; i < mappedExceptions . Length ; i + + )
{
string dst = map . exceptionMappings [ i ] . dst ;
if ( dst [ 0 ] = = '*' )
{
mappedExceptionsAllSubClasses [ i ] = true ;
dst = dst . Substring ( 1 ) ;
}
2008-08-14 09:42:43 +04:00
mappedExceptions [ i ] = LoadClassByDottedName ( dst ) ;
2006-08-29 15:56:09 +04:00
}
2008-08-14 10:51:32 +04:00
// HACK we need to find the <exceptionMapping /> element and bind it
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
{
if ( c . Methods ! = null )
{
foreach ( IKVM . Internal . MapXml . Method m in c . Methods )
{
if ( m . body ! = null & & m . body . invoke ! = null )
{
foreach ( IKVM . Internal . MapXml . Instruction instr in m . body . invoke )
{
IKVM . Internal . MapXml . EmitExceptionMapping eem = instr as IKVM . Internal . MapXml . EmitExceptionMapping ;
if ( eem ! = null )
{
eem . mapping = map . exceptionMappings ;
}
}
}
}
}
}
2006-08-29 15:56:09 +04:00
}
}
2008-06-03 13:17:31 +04:00
internal sealed class ExceptionMapEmitter
2006-08-29 15:56:09 +04:00
{
private IKVM . Internal . MapXml . ExceptionMapping [ ] map ;
internal ExceptionMapEmitter ( IKVM . Internal . MapXml . ExceptionMapping [ ] map )
{
this . map = map ;
}
2008-08-14 10:51:32 +04:00
internal void Emit ( IKVM . Internal . MapXml . CodeGenContext context , CodeEmitter ilgen )
2006-08-29 15:56:09 +04:00
{
MethodWrapper mwSuppressFillInStackTrace = CoreClasses . java . lang . Throwable . Wrapper . GetMethodWrapper ( "__<suppressFillInStackTrace>" , "()V" , false ) ;
mwSuppressFillInStackTrace . Link ( ) ;
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
2009-10-23 10:06:48 +04:00
ilgen . Emit ( OpCodes . Callvirt , Compiler . getTypeMethod ) ;
2006-08-29 15:56:09 +04:00
for ( int i = 0 ; i < map . Length ; i + + )
{
ilgen . Emit ( OpCodes . Dup ) ;
2010-05-20 08:59:13 +04:00
ilgen . Emit ( OpCodes . Ldtoken , StaticCompiler . Universe . GetType ( map [ i ] . src , true ) ) ;
2009-10-23 10:06:48 +04:00
ilgen . Emit ( OpCodes . Call , Compiler . getTypeFromHandleMethod ) ;
2006-08-29 15:56:09 +04:00
ilgen . Emit ( OpCodes . Ceq ) ;
2008-06-03 16:10:07 +04:00
CodeEmitterLabel label = ilgen . DefineLabel ( ) ;
2012-07-03 18:45:51 +04:00
ilgen . EmitBrfalse ( label ) ;
2006-08-29 15:56:09 +04:00
ilgen . Emit ( OpCodes . Pop ) ;
if ( map [ i ] . code ! = null )
{
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
2008-04-21 08:18:32 +04:00
if ( map [ i ] . code . invoke ! = null )
{
foreach ( MapXml . Instruction instr in map [ i ] . code . invoke )
{
MapXml . NewObj newobj = instr as MapXml . NewObj ;
if ( newobj ! = null
& & newobj . Class ! = null
2008-08-14 10:51:32 +04:00
& & context . ClassLoader . LoadClassByDottedName ( newobj . Class ) . IsSubTypeOf ( CoreClasses . java . lang . Throwable . Wrapper ) )
2008-04-21 08:18:32 +04:00
{
mwSuppressFillInStackTrace . EmitCall ( ilgen ) ;
}
instr . Generate ( context , ilgen ) ;
}
}
2006-08-29 15:56:09 +04:00
ilgen . Emit ( OpCodes . Ret ) ;
}
else
{
2008-08-14 10:51:32 +04:00
TypeWrapper tw = context . ClassLoader . LoadClassByDottedName ( map [ i ] . dst ) ;
2006-08-29 15:56:09 +04:00
MethodWrapper mw = tw . GetMethodWrapper ( "<init>" , "()V" , false ) ;
mw . Link ( ) ;
mwSuppressFillInStackTrace . EmitCall ( ilgen ) ;
mw . EmitNewobj ( ilgen ) ;
ilgen . Emit ( OpCodes . Ret ) ;
}
ilgen . MarkLabel ( label ) ;
}
ilgen . Emit ( OpCodes . Pop ) ;
ilgen . Emit ( OpCodes . Ldarg_0 ) ;
ilgen . Emit ( OpCodes . Ret ) ;
}
}
2008-08-13 17:04:47 +04:00
internal void LoadMapXml ( )
2006-08-29 15:56:09 +04:00
{
2007-05-27 12:13:44 +04:00
if ( map . assembly . Classes ! = null )
2006-08-29 15:56:09 +04:00
{
2008-08-14 11:42:56 +04:00
mapxml_Classes = new Dictionary < string , IKVM . Internal . MapXml . Class > ( ) ;
mapxml_MethodBodies = new Dictionary < MethodKey , IKVM . Internal . MapXml . InstructionList > ( ) ;
mapxml_ReplacedMethods = new Dictionary < MethodKey , IKVM . Internal . MapXml . ReplaceMethodCall [ ] > ( ) ;
2011-05-12 14:15:52 +04:00
mapxml_MethodPrologues = new Dictionary < MethodKey , IKVM . Internal . MapXml . InstructionList > ( ) ;
2007-05-27 12:13:44 +04:00
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
2006-08-29 15:56:09 +04:00
{
2011-05-25 13:23:36 +04:00
// if it is not a remapped type, it must be a container for native, patched or augmented methods
2007-05-27 12:13:44 +04:00
if ( c . Shadows = = null )
2006-08-29 15:56:09 +04:00
{
2007-05-27 12:13:44 +04:00
string className = c . Name ;
2008-08-14 11:42:56 +04:00
mapxml_Classes . Add ( className , c ) ;
2011-05-25 13:23:36 +04:00
AddMapXmlMethods ( className , c . Constructors ) ;
AddMapXmlMethods ( className , c . Methods ) ;
if ( c . Clinit ! = null )
2006-08-29 15:56:09 +04:00
{
2011-05-25 13:23:36 +04:00
AddMapXmlMethod ( className , c . Clinit ) ;
2006-08-29 15:56:09 +04:00
}
}
}
}
}
2011-05-25 13:23:36 +04:00
private void AddMapXmlMethods ( string className , IKVM . Internal . MapXml . MethodBase [ ] methods )
{
if ( methods ! = null )
{
foreach ( IKVM . Internal . MapXml . MethodBase method in methods )
{
AddMapXmlMethod ( className , method ) ;
}
}
}
private void AddMapXmlMethod ( string className , IKVM . Internal . MapXml . MethodBase method )
{
if ( method . body ! = null )
{
mapxml_MethodBodies . Add ( method . ToMethodKey ( className ) , method . body ) ;
}
if ( method . ReplaceMethodCalls ! = null )
{
mapxml_ReplacedMethods . Add ( method . ToMethodKey ( className ) , method . ReplaceMethodCalls ) ;
}
if ( method . prologue ! = null )
{
mapxml_MethodPrologues . Add ( method . ToMethodKey ( className ) , method . prologue ) ;
}
}
2011-05-12 14:15:52 +04:00
internal IKVM . Internal . MapXml . InstructionList GetMethodPrologue ( MethodKey method )
{
if ( mapxml_MethodPrologues = = null )
{
return null ;
}
IKVM . Internal . MapXml . InstructionList prologue ;
mapxml_MethodPrologues . TryGetValue ( method , out prologue ) ;
return prologue ;
}
2007-06-12 15:45:23 +04:00
internal IKVM . Internal . MapXml . ReplaceMethodCall [ ] GetReplacedMethodsFor ( MethodWrapper mw )
{
2008-08-14 11:42:56 +04:00
if ( mapxml_ReplacedMethods = = null )
2007-06-14 10:36:35 +04:00
{
return null ;
}
2008-08-14 11:42:56 +04:00
IKVM . Internal . MapXml . ReplaceMethodCall [ ] rmc ;
mapxml_ReplacedMethods . TryGetValue ( new MethodKey ( mw . DeclaringType . Name , mw . Name , mw . Signature ) , out rmc ) ;
return rmc ;
}
internal Dictionary < string , IKVM . Internal . MapXml . Class > GetMapXmlClasses ( )
{
return mapxml_Classes ;
2007-06-12 15:45:23 +04:00
}
2008-08-14 11:42:56 +04:00
internal Dictionary < MethodKey , IKVM . Internal . MapXml . InstructionList > GetMapXmlMethodBodies ( )
2006-08-29 15:56:09 +04:00
{
2008-08-14 11:42:56 +04:00
return mapxml_MethodBodies ;
2006-08-29 15:56:09 +04:00
}
internal IKVM . Internal . MapXml . Param [ ] GetXmlMapParameters ( string classname , string method , string sig )
{
2008-08-14 11:42:56 +04:00
if ( mapxml_Classes ! = null )
2006-08-29 15:56:09 +04:00
{
2008-08-14 11:42:56 +04:00
IKVM . Internal . MapXml . Class clazz ;
if ( mapxml_Classes . TryGetValue ( classname , out clazz ) )
2006-08-29 15:56:09 +04:00
{
if ( method = = "<init>" & & clazz . Constructors ! = null )
{
for ( int i = 0 ; i < clazz . Constructors . Length ; i + + )
{
if ( clazz . Constructors [ i ] . Sig = = sig )
{
return clazz . Constructors [ i ] . Params ;
}
}
}
else if ( clazz . Methods ! = null )
{
for ( int i = 0 ; i < clazz . Methods . Length ; i + + )
{
if ( clazz . Methods [ i ] . Name = = method & & clazz . Methods [ i ] . Sig = = sig )
{
return clazz . Methods [ i ] . Params ;
}
}
}
}
}
return null ;
}
internal bool IsGhost ( TypeWrapper tw )
{
return ghosts ! = null & & tw . IsInterface & & ghosts . ContainsKey ( tw . Name ) ;
}
private void SetupGhosts ( IKVM . Internal . MapXml . Root map )
{
2008-08-08 10:26:37 +04:00
ghosts = new Dictionary < string , List < TypeWrapper > > ( ) ;
2006-08-29 15:56:09 +04:00
// find the ghost interfaces
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
{
if ( c . Shadows ! = null & & c . Interfaces ! = null )
{
// NOTE we don't support interfaces that inherit from other interfaces
// (actually, if they are explicitly listed it would probably work)
2008-08-14 09:42:43 +04:00
TypeWrapper typeWrapper = GetLoadedClass ( c . Name ) ;
2006-08-29 15:56:09 +04:00
foreach ( IKVM . Internal . MapXml . Interface iface in c . Interfaces )
{
2008-08-14 09:42:43 +04:00
TypeWrapper ifaceWrapper = GetLoadedClass ( iface . Name ) ;
2006-08-29 15:56:09 +04:00
if ( ifaceWrapper = = null | | ! ifaceWrapper . TypeAsTBD . IsAssignableFrom ( typeWrapper . TypeAsTBD ) )
{
AddGhost ( iface . Name , typeWrapper ) ;
}
}
}
}
// we manually add the array ghost interfaces
2009-10-14 18:58:41 +04:00
TypeWrapper array = ClassLoaderWrapper . GetWrapperFromType ( Types . Array ) ;
2006-08-29 15:56:09 +04:00
AddGhost ( "java.io.Serializable" , array ) ;
AddGhost ( "java.lang.Cloneable" , array ) ;
}
private void AddGhost ( string interfaceName , TypeWrapper implementer )
{
2008-08-08 10:26:37 +04:00
List < TypeWrapper > list ;
if ( ! ghosts . TryGetValue ( interfaceName , out list ) )
2006-08-29 15:56:09 +04:00
{
2008-08-08 10:26:37 +04:00
list = new List < TypeWrapper > ( ) ;
2006-08-29 15:56:09 +04:00
ghosts [ interfaceName ] = list ;
}
list . Add ( implementer ) ;
}
internal TypeWrapper [ ] GetGhostImplementers ( TypeWrapper wrapper )
{
2008-08-08 10:26:37 +04:00
List < TypeWrapper > list ;
if ( ! ghosts . TryGetValue ( wrapper . Name , out list ) )
2006-08-29 15:56:09 +04:00
{
return TypeWrapper . EmptyArray ;
}
2008-08-08 10:26:37 +04:00
return list . ToArray ( ) ;
2006-08-29 15:56:09 +04:00
}
2006-02-23 16:20:51 +03:00
internal void FinishRemappedTypes ( )
{
// 3rd pass, link the methods. Note that a side effect of the linking is the
// twiddling with the overriders array in the base methods, so we need to do this
// as a separate pass before we compile the methods
foreach ( RemapperTypeWrapper typeWrapper in remapped . Values )
{
typeWrapper . Process3rdPass ( ) ;
}
// 4th pass, implement methods/fields and bake the type
foreach ( RemapperTypeWrapper typeWrapper in remapped . Values )
{
typeWrapper . Process4thPass ( remapped . Values ) ;
}
if ( assemblyAttributes ! = null )
{
foreach ( IKVM . Internal . MapXml . Attribute attr in assemblyAttributes )
{
2008-08-14 09:42:43 +04:00
AttributeHelper . SetCustomAttribute ( this , assemblyBuilder , attr ) ;
2006-02-23 16:20:51 +03:00
}
}
}
2006-04-10 13:09:09 +04:00
2006-02-23 16:20:51 +03:00
private static bool IsSigned ( Assembly asm )
{
byte [ ] key = asm . GetName ( ) . GetPublicKey ( ) ;
return key ! = null & & key . Length ! = 0 ;
}
2010-10-06 08:27:38 +04:00
internal static bool IsCoreAssembly ( Assembly asm )
2008-02-10 11:55:18 +03:00
{
2010-05-20 10:00:48 +04:00
return asm . IsDefined ( StaticCompiler . GetRuntimeType ( "IKVM.Attributes.RemappedClassAttribute" ) , false ) ;
2008-02-10 11:55:18 +03:00
}
2008-08-13 17:04:47 +04:00
private bool CheckCompilingCoreAssembly ( )
{
2011-12-14 13:04:57 +04:00
if ( map ! = null & & map . assembly ! = null & & map . assembly . Classes ! = null )
2008-08-13 17:04:47 +04:00
{
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
{
if ( c . Shadows ! = null & & c . Name = = "java.lang.Object" )
{
return true ;
}
}
}
return false ;
}
2009-12-10 12:04:52 +03:00
internal static int Compile ( string runtimeAssembly , List < CompilerOptions > optionsList )
2008-08-13 17:04:47 +04:00
{
2009-12-10 12:04:52 +03:00
try
{
if ( runtimeAssembly = = null )
{
2010-01-25 10:52:27 +03:00
// we assume that the runtime is in the same directory as the compiler
runtimeAssembly = Path . Combine ( typeof ( CompilerClassLoader ) . Assembly . Location , ".." + Path . DirectorySeparatorChar + "IKVM.Runtime.dll" ) ;
2009-12-10 12:04:52 +03:00
}
2010-01-25 10:52:27 +03:00
StaticCompiler . runtimeAssembly = StaticCompiler . LoadFile ( runtimeAssembly ) ;
StaticCompiler . runtimeJniAssembly = StaticCompiler . LoadFile ( Path . Combine ( StaticCompiler . runtimeAssembly . Location , ".." + Path . DirectorySeparatorChar + "IKVM.Runtime.JNI.dll" ) ) ;
2009-12-10 12:04:52 +03:00
}
catch ( FileNotFoundException )
{
if ( StaticCompiler . runtimeAssembly = = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . RuntimeNotFound ) ;
2009-12-10 12:04:52 +03:00
}
StaticCompiler . IssueMessage ( Message . NoJniRuntime ) ;
}
Tracer . Info ( Tracer . Compiler , "Loaded runtime assembly: {0}" , StaticCompiler . runtimeAssembly . FullName ) ;
2008-11-14 11:29:19 +03:00
bool compilingCoreAssembly = false ;
2008-08-13 17:04:47 +04:00
List < CompilerClassLoader > compilers = new List < CompilerClassLoader > ( ) ;
foreach ( CompilerOptions options in optionsList )
{
CompilerClassLoader compiler = null ;
2008-11-14 11:29:19 +03:00
int rc = CreateCompiler ( options , ref compiler , ref compilingCoreAssembly ) ;
2008-08-13 17:04:47 +04:00
if ( rc ! = 0 )
{
return rc ;
}
compilers . Add ( compiler ) ;
2008-12-23 10:11:29 +03:00
if ( options . sharedclassloader ! = null )
{
options . sharedclassloader . Add ( compiler ) ;
}
2008-08-13 17:04:47 +04:00
}
foreach ( CompilerClassLoader compiler1 in compilers )
{
foreach ( CompilerClassLoader compiler2 in compilers )
{
2009-11-04 08:18:37 +03:00
if ( compiler1 ! = compiler2
& & ( compiler1 . options . crossReferenceAllPeers | | ( compiler1 . options . peerReferences ! = null & & Array . IndexOf ( compiler1 . options . peerReferences , compiler2 . options . assembly ) ! = - 1 ) ) )
2008-08-13 17:04:47 +04:00
{
compiler1 . AddReference ( compiler2 ) ;
}
}
}
2010-05-06 10:11:56 +04:00
Dictionary < CompilerClassLoader , Type > mainAssemblyTypes = new Dictionary < CompilerClassLoader , Type > ( ) ;
2008-08-13 17:04:47 +04:00
foreach ( CompilerClassLoader compiler in compilers )
{
2008-12-23 10:11:29 +03:00
if ( compiler . options . sharedclassloader ! = null )
{
2010-05-06 10:11:56 +04:00
Type mainAssemblyType ;
if ( ! mainAssemblyTypes . TryGetValue ( compiler . options . sharedclassloader [ 0 ] , out mainAssemblyType ) )
2008-12-23 10:11:29 +03:00
{
TypeBuilder tb = compiler . options . sharedclassloader [ 0 ] . GetTypeWrapperFactory ( ) . ModuleBuilder . DefineType ( "__<MainAssembly>" , TypeAttributes . NotPublic | TypeAttributes . Abstract | TypeAttributes . SpecialName ) ;
AttributeHelper . HideFromJava ( tb ) ;
2010-05-06 10:11:56 +04:00
mainAssemblyType = tb . CreateType ( ) ;
mainAssemblyTypes . Add ( compiler . options . sharedclassloader [ 0 ] , mainAssemblyType ) ;
2008-12-23 10:11:29 +03:00
}
if ( compiler . options . sharedclassloader [ 0 ] ! = compiler )
{
2010-05-06 10:11:56 +04:00
( ( AssemblyBuilder ) compiler . GetTypeWrapperFactory ( ) . ModuleBuilder . Assembly ) . __AddTypeForwarder ( mainAssemblyType ) ;
2008-12-23 10:11:29 +03:00
}
}
2011-12-14 13:04:57 +04:00
compiler . CompilePass1 ( ) ;
}
2011-12-14 16:06:52 +04:00
foreach ( CompilerClassLoader compiler in compilers )
{
compiler . CompilePass2 ( ) ;
}
2011-12-14 13:04:57 +04:00
if ( compilingCoreAssembly )
{
RuntimeHelperTypes . Create ( compilers [ 0 ] ) ;
}
foreach ( CompilerClassLoader compiler in compilers )
{
compiler . EmitRemappedTypes2ndPass ( ) ;
}
foreach ( CompilerClassLoader compiler in compilers )
{
2011-12-14 16:06:52 +04:00
int rc = compiler . CompilePass3 ( ) ;
2008-08-13 17:04:47 +04:00
if ( rc ! = 0 )
{
return rc ;
}
}
2012-03-25 13:10:28 +04:00
Tracer . Info ( Tracer . Compiler , "CompilerClassLoader.Save..." ) ;
foreach ( CompilerClassLoader compiler in compilers )
2010-05-06 10:07:13 +04:00
{
2012-03-25 13:10:28 +04:00
compiler . PrepareSave ( ) ;
2010-05-06 10:07:13 +04:00
}
2012-03-25 13:10:28 +04:00
if ( StaticCompiler . errorCount > 0 )
2008-12-23 10:11:29 +03:00
{
2010-05-06 10:07:13 +04:00
return 1 ;
2008-12-23 10:11:29 +03:00
}
2012-03-25 13:10:28 +04:00
foreach ( CompilerClassLoader compiler in compilers )
{
compiler . Save ( ) ;
}
2011-06-28 10:17:40 +04:00
return StaticCompiler . errorCount = = 0 ? 0 : 1 ;
2008-08-13 17:04:47 +04:00
}
2008-11-14 11:29:19 +03:00
private static int CreateCompiler ( CompilerOptions options , ref CompilerClassLoader loader , ref bool compilingCoreAssembly )
2006-02-23 16:20:51 +03:00
{
Tracer . Info ( Tracer . Compiler , "JVM.Compile path: {0}, assembly: {1}" , options . path , options . assembly ) ;
2006-04-10 13:09:09 +04:00
AssemblyName runtimeAssemblyName = StaticCompiler . runtimeAssembly . GetName ( ) ;
bool allReferencesAreStrongNamed = IsSigned ( StaticCompiler . runtimeAssembly ) ;
2008-08-08 10:26:37 +04:00
List < Assembly > references = new List < Assembly > ( ) ;
2009-11-04 08:18:37 +03:00
foreach ( Assembly reference in options . references ? ? new Assembly [ 0 ] )
2006-02-23 16:20:51 +03:00
{
2012-03-25 13:10:28 +04:00
references . Add ( reference ) ;
allReferencesAreStrongNamed & = IsSigned ( reference ) ;
Tracer . Info ( Tracer . Compiler , "Loaded reference assembly: {0}" , reference . FullName ) ;
// if it's an IKVM compiled assembly, make sure that it was compiled
// against same version of the runtime
foreach ( AssemblyName asmref in reference . GetReferencedAssemblies ( ) )
2006-02-23 16:20:51 +03:00
{
2012-03-25 13:10:28 +04:00
if ( asmref . Name = = runtimeAssemblyName . Name )
2006-02-23 16:20:51 +03:00
{
2012-03-25 13:10:28 +04:00
if ( IsSigned ( StaticCompiler . runtimeAssembly ) )
2006-02-23 16:20:51 +03:00
{
2012-03-25 13:10:28 +04:00
// TODO we really should support binding redirects here to allow different revisions to be mixed
if ( asmref . FullName ! = runtimeAssemblyName . FullName )
2006-02-23 16:20:51 +03:00
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . RuntimeMismatch , reference . Location , runtimeAssemblyName . FullName , asmref . FullName ) ;
2006-02-23 16:20:51 +03:00
}
2012-03-25 13:10:28 +04:00
}
else
{
if ( asmref . GetPublicKeyToken ( ) ! = null & & asmref . GetPublicKeyToken ( ) . Length ! = 0 )
2006-02-23 16:20:51 +03:00
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . RuntimeMismatch , reference . Location , runtimeAssemblyName . FullName , asmref . FullName ) ;
2006-02-23 16:20:51 +03:00
}
}
}
}
}
2008-08-08 10:26:37 +04:00
List < object > assemblyAnnotations = new List < object > ( ) ;
Dictionary < string , string > baseClasses = new Dictionary < string , string > ( ) ;
2006-02-23 16:20:51 +03:00
Tracer . Info ( Tracer . Compiler , "Parsing class files" ) ;
2012-03-24 12:54:12 +04:00
foreach ( KeyValuePair < string , ClassItem > kv in options . classes )
2006-02-23 16:20:51 +03:00
{
2006-10-09 16:32:33 +04:00
ClassFile f ;
try
2006-02-23 16:20:51 +03:00
{
2012-03-24 12:54:12 +04:00
byte [ ] buf = kv . Value . data ;
2006-10-09 16:32:33 +04:00
f = new ClassFile ( buf , 0 , buf . Length , null , ClassFileParseOptions . None ) ;
if ( ! f . IsInterface & & f . SuperClass ! = null )
2006-02-23 16:20:51 +03:00
{
2006-10-09 16:32:33 +04:00
baseClasses [ f . SuperClass ] = f . SuperClass ;
2006-08-29 10:28:34 +04:00
}
2007-07-25 20:28:20 +04:00
// NOTE the "assembly" type in the unnamed package is a magic type
// that acts as the placeholder for assembly attributes
if ( f . Name = = "assembly" & & f . Annotations ! = null )
{
assemblyAnnotations . AddRange ( f . Annotations ) ;
}
2006-10-09 16:32:33 +04:00
}
catch ( ClassFormatError )
{
continue ;
}
if ( options . mainClass = = null & & ( options . guessFileKind | | options . target ! = PEFileKinds . Dll ) )
{
2006-08-29 10:28:34 +04:00
foreach ( ClassFile . Method m in f . Methods )
{
if ( m . IsPublic & & m . IsStatic & & m . Name = = "main" & & m . Signature = = "([Ljava.lang.String;)V" )
{
StaticCompiler . IssueMessage ( Message . MainMethodFound , f . Name ) ;
options . mainClass = f . Name ;
break ;
}
2006-02-23 16:20:51 +03:00
}
}
2006-08-29 10:28:34 +04:00
}
2012-03-24 12:54:12 +04:00
Dictionary < string , ClassItem > h = new Dictionary < string , ClassItem > ( ) ;
2008-01-03 12:39:12 +03:00
// HACK remove "assembly" type that exists only as a placeholder for assembly attributes
options . classes . Remove ( "assembly" ) ;
2012-03-24 12:54:12 +04:00
foreach ( KeyValuePair < string , ClassItem > kv in options . classes )
2006-08-29 10:28:34 +04:00
{
2008-08-08 10:26:37 +04:00
string name = kv . Key ;
2006-02-23 16:20:51 +03:00
bool excluded = false ;
for ( int j = 0 ; j < options . classesToExclude . Length ; j + + )
{
if ( Regex . IsMatch ( name , options . classesToExclude [ j ] ) )
{
excluded = true ;
break ;
}
}
if ( h . ContainsKey ( name ) )
{
2006-07-26 18:16:52 +04:00
StaticCompiler . IssueMessage ( Message . DuplicateClassName , name ) ;
2006-02-23 16:20:51 +03:00
excluded = true ;
}
if ( ! excluded )
{
2008-08-08 10:26:37 +04:00
h [ name ] = kv . Value ;
2006-02-23 16:20:51 +03:00
}
}
options . classes = null ;
if ( options . guessFileKind & & options . mainClass = = null )
{
options . target = PEFileKinds . Dll ;
}
if ( options . target = = PEFileKinds . Dll & & options . mainClass ! = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . MainClassRequiresExe ) ;
2006-02-23 16:20:51 +03:00
}
if ( options . target ! = PEFileKinds . Dll & & options . mainClass = = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ExeRequiresMainClass ) ;
2006-02-23 16:20:51 +03:00
}
if ( options . target = = PEFileKinds . Dll & & options . props . Count ! = 0 )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . PropertiesRequireExe ) ;
2006-02-23 16:20:51 +03:00
}
if ( options . path = = null )
{
if ( options . target = = PEFileKinds . Dll )
{
if ( options . targetIsModule )
{
options . path = options . assembly + ".netmodule" ;
}
else
{
options . path = options . assembly + ".dll" ;
}
}
else
{
options . path = options . assembly + ".exe" ;
}
2006-07-26 18:16:52 +04:00
StaticCompiler . IssueMessage ( Message . OutputFileIs , options . path ) ;
2006-02-23 16:20:51 +03:00
}
if ( options . targetIsModule )
{
2007-10-21 11:15:40 +04:00
if ( options . classLoader ! = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ModuleCannotHaveClassLoader ) ;
2007-10-21 11:15:40 +04:00
}
2006-02-23 16:20:51 +03:00
// TODO if we're overwriting a user specified assembly name, we need to emit a warning
options . assembly = new FileInfo ( options . path ) . Name ;
}
Tracer . Info ( Tracer . Compiler , "Constructing compiler" ) ;
2006-08-14 11:57:03 +04:00
AssemblyClassLoader [ ] referencedAssemblies = new AssemblyClassLoader [ references . Count ] ;
for ( int i = 0 ; i < references . Count ; i + + )
{
2011-11-15 09:51:38 +04:00
AssemblyClassLoader acl = AssemblyClassLoader . FromAssembly ( references [ i ] ) ;
if ( acl . MainAssembly ! = references [ i ] )
{
StaticCompiler . IssueMessage ( options , Message . NonPrimaryAssemblyReference , references [ i ] . GetName ( ) . Name , acl . MainAssembly . GetName ( ) . Name ) ;
}
if ( Array . IndexOf ( referencedAssemblies , acl ) ! = - 1 )
{
StaticCompiler . IssueMessage ( options , Message . DuplicateAssemblyReference , acl . MainAssembly . FullName ) ;
}
referencedAssemblies [ i ] = acl ;
2006-08-14 11:57:03 +04:00
}
2010-04-14 18:43:21 +04:00
loader = new CompilerClassLoader ( referencedAssemblies , options , options . path , options . targetIsModule , options . assembly , h ) ;
2006-10-09 16:32:33 +04:00
loader . baseClasses = baseClasses ;
2008-08-13 17:04:47 +04:00
loader . assemblyAnnotations = assemblyAnnotations ;
loader . classesToCompile = new List < string > ( h . Keys ) ;
2006-02-23 16:20:51 +03:00
if ( options . remapfile ! = null )
{
Tracer . Info ( Tracer . Compiler , "Loading remapped types (1) from {0}" , options . remapfile ) ;
System . Xml . Serialization . XmlSerializer ser = new System . Xml . Serialization . XmlSerializer ( typeof ( IKVM . Internal . MapXml . Root ) ) ;
ser . UnknownElement + = new System . Xml . Serialization . XmlElementEventHandler ( ser_UnknownElement ) ;
ser . UnknownAttribute + = new System . Xml . Serialization . XmlAttributeEventHandler ( ser_UnknownAttribute ) ;
2010-10-14 19:48:11 +04:00
FileStream fs ;
try
{
2011-09-29 17:16:51 +04:00
fs = File . OpenRead ( options . remapfile ) ;
2010-10-14 19:48:11 +04:00
}
catch ( Exception x )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ErrorReadingFile , options . remapfile , x . Message ) ;
2010-10-14 19:48:11 +04:00
}
try
2006-02-23 16:20:51 +03:00
{
XmlTextReader rdr = new XmlTextReader ( fs ) ;
IKVM . Internal . MapXml . Root . xmlReader = rdr ;
2010-10-14 19:48:11 +04:00
IKVM . Internal . MapXml . Root map ;
try
{
map = ( IKVM . Internal . MapXml . Root ) ser . Deserialize ( rdr ) ;
}
catch ( InvalidOperationException x )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ErrorParsingMapFile , options . remapfile , x . Message ) ;
2010-10-14 19:48:11 +04:00
}
if ( ! loader . ValidateAndSetMap ( map ) )
2009-12-11 11:06:10 +03:00
{
return 1 ;
}
2008-08-13 17:04:47 +04:00
}
2010-10-14 19:48:11 +04:00
finally
{
fs . Close ( ) ;
}
2008-08-13 17:04:47 +04:00
if ( loader . CheckCompilingCoreAssembly ( ) )
{
2008-11-14 11:29:19 +03:00
compilingCoreAssembly = true ;
2008-08-13 17:04:47 +04:00
ClassLoaderWrapper . SetBootstrapClassLoader ( loader ) ;
2006-02-23 16:20:51 +03:00
}
}
2008-02-10 11:59:36 +03:00
// If we do not yet have a reference to the core assembly and we are not compiling the core assembly,
// try to find the core assembly by looking at the assemblies that the runtime references
2008-11-14 11:29:19 +03:00
if ( JVM . CoreAssembly = = null & & ! compilingCoreAssembly )
2006-02-23 16:20:51 +03:00
{
2008-02-10 11:55:18 +03:00
foreach ( AssemblyName name in StaticCompiler . runtimeAssembly . GetReferencedAssemblies ( ) )
2007-11-26 11:38:38 +03:00
{
2008-02-10 11:55:18 +03:00
Assembly asm = null ;
2007-11-26 11:38:38 +03:00
try
{
2010-01-25 10:52:27 +03:00
asm = LoadReferencedAssembly ( StaticCompiler . runtimeAssembly . Location + "/../" + name . Name + ".dll" ) ;
2007-11-26 11:38:38 +03:00
}
catch ( FileNotFoundException )
{
2008-02-10 11:55:18 +03:00
}
if ( asm ! = null & & IsCoreAssembly ( asm ) )
{
JVM . CoreAssembly = asm ;
break ;
2007-11-26 11:38:38 +03:00
}
}
2006-02-23 16:20:51 +03:00
if ( JVM . CoreAssembly = = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . BootstrapClassesMissing ) ;
2006-02-23 16:20:51 +03:00
}
// we need to scan again for remapped types, now that we've loaded the core library
ClassLoaderWrapper . LoadRemappedTypes ( ) ;
}
2008-11-14 11:29:19 +03:00
if ( ! compilingCoreAssembly )
2008-08-13 17:04:47 +04:00
{
allReferencesAreStrongNamed & = IsSigned ( JVM . CoreAssembly ) ;
2009-09-07 08:46:01 +04:00
loader . AddReference ( AssemblyClassLoader . FromAssembly ( JVM . CoreAssembly ) ) ;
2008-08-13 17:04:47 +04:00
}
2010-05-07 16:05:52 +04:00
if ( ( options . keyPair ! = null | | options . publicKey ! = null ) & & ! allReferencesAreStrongNamed )
2006-02-23 16:20:51 +03:00
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . StrongNameRequiresStrongNamedRefs ) ;
2006-02-23 16:20:51 +03:00
}
2008-08-13 17:04:47 +04:00
if ( loader . map ! = null )
2007-06-28 14:32:50 +04:00
{
2008-08-13 17:04:47 +04:00
loader . LoadMapXml ( ) ;
2007-06-28 14:32:50 +04:00
}
2008-11-14 11:29:19 +03:00
if ( ! compilingCoreAssembly )
2008-03-03 10:05:19 +03:00
{
FakeTypes . Load ( JVM . CoreAssembly ) ;
}
2008-08-13 17:04:47 +04:00
return 0 ;
}
2008-03-03 10:05:19 +03:00
2009-02-04 10:19:06 +03:00
private static Assembly LoadReferencedAssembly ( string r )
{
2009-10-21 08:54:39 +04:00
Assembly asm = StaticCompiler . LoadFile ( r ) ;
2009-02-04 10:19:06 +03:00
return asm ;
}
2012-01-26 10:43:40 +04:00
private bool IsStub ( string className )
{
// this function is needed because when using generics a type may be loaded before the stub is seen
// and without this check that would cause a spurious IKVMC0109 warning
2012-03-24 12:54:12 +04:00
ClassItem classdef ;
2012-01-26 10:43:40 +04:00
if ( classes . TryGetValue ( className , out classdef ) )
{
try
{
2012-03-24 12:54:12 +04:00
return new ClassFile ( classdef . data , 0 , classdef . data . Length , className , ClassFileParseOptions . RelaxedClassNameValidation ) . IKVMAssemblyAttribute ! = null ;
2012-01-26 10:43:40 +04:00
}
catch ( ClassFormatError )
{
}
}
return false ;
}
2011-12-14 13:04:57 +04:00
private void CompilePass1 ( )
2008-08-13 17:04:47 +04:00
{
2006-02-23 16:20:51 +03:00
Tracer . Info ( Tracer . Compiler , "Compiling class files (1)" ) ;
2011-12-14 13:04:57 +04:00
if ( CheckCompilingCoreAssembly ( ) )
{
EmitRemappedTypes ( ) ;
}
2008-11-18 08:32:15 +03:00
// if we're compiling the core class library, generate the "fake" generic types
// that represent the not-really existing types (i.e. the Java enums that represent .NET enums,
// the Method interface for delegates and the Annotation annotation for custom attributes)
if ( map ! = null & & CheckCompilingCoreAssembly ( ) )
{
FakeTypes . Create ( GetTypeWrapperFactory ( ) . ModuleBuilder , this ) ;
}
2008-12-23 10:11:29 +03:00
if ( options . sharedclassloader ! = null & & options . sharedclassloader [ 0 ] ! = this )
{
packages = options . sharedclassloader [ 0 ] . packages ;
}
else
{
packages = new Dictionary < string , string > ( ) ;
}
2011-12-14 13:04:57 +04:00
allwrappers = new List < TypeWrapper > ( ) ;
2008-08-13 17:04:47 +04:00
foreach ( string s in classesToCompile )
2006-02-23 16:20:51 +03:00
{
2008-08-13 17:04:47 +04:00
TypeWrapper wrapper = LoadClassByDottedNameFast ( s ) ;
2007-05-02 10:04:07 +04:00
if ( wrapper ! = null )
2006-02-23 16:20:51 +03:00
{
2008-08-13 17:04:47 +04:00
ClassLoaderWrapper loader = wrapper . GetClassLoader ( ) ;
if ( loader ! = this )
2006-02-23 16:20:51 +03:00
{
2012-01-26 10:43:40 +04:00
if ( ! ( loader is GenericClassLoader | | loader is CompilerClassLoader | | ( importedStubTypes . ContainsKey ( s ) & & importedStubTypes [ s ] = = wrapper ) | | IsStub ( s ) ) )
2007-01-31 14:26:41 +03:00
{
2010-07-16 12:50:40 +04:00
StaticCompiler . IssueMessage ( options , Message . SkippingReferencedClass , s , ( ( AssemblyClassLoader ) loader ) . GetAssembly ( wrapper ) . FullName ) ;
2006-09-12 13:57:36 +04:00
}
2007-05-02 10:04:07 +04:00
continue ;
2006-02-23 16:20:51 +03:00
}
2007-05-02 10:04:07 +04:00
int pos = wrapper . Name . LastIndexOf ( '.' ) ;
if ( pos ! = - 1 )
{
2008-08-13 17:04:47 +04:00
packages [ wrapper . Name . Substring ( 0 , pos ) ] = "" ;
2007-05-02 10:04:07 +04:00
}
2008-12-23 10:11:29 +03:00
if ( options . sharedclassloader ! = null & & options . sharedclassloader [ 0 ] ! = this )
{
options . sharedclassloader [ 0 ] . dynamicallyImportedTypes . Add ( wrapper ) ;
}
2007-05-02 10:04:07 +04:00
allwrappers . Add ( wrapper ) ;
2006-02-23 16:20:51 +03:00
}
}
2011-12-14 13:04:57 +04:00
}
2011-12-14 16:06:52 +04:00
private void CompilePass2 ( )
{
Tracer . Info ( Tracer . Compiler , "Compiling class files (2)" ) ;
foreach ( TypeWrapper tw in allwrappers )
{
DynamicTypeWrapper dtw = tw as DynamicTypeWrapper ;
if ( dtw ! = null )
{
dtw . CreateStep2 ( ) ;
}
}
}
private int CompilePass3 ( )
2011-12-14 13:04:57 +04:00
{
Tracer . Info ( Tracer . Compiler , "Compiling class files (3)" ) ;
if ( map ! = null & & CheckCompilingCoreAssembly ( ) )
{
FakeTypes . Finish ( this ) ;
}
2011-05-12 12:08:08 +04:00
foreach ( string proxy in options . proxies )
{
ProxyGenerator . Create ( this , proxy ) ;
}
2006-02-23 16:20:51 +03:00
if ( options . mainClass ! = null )
{
TypeWrapper wrapper = null ;
try
{
2008-08-13 17:04:47 +04:00
wrapper = LoadClassByDottedNameFast ( options . mainClass ) ;
2006-02-23 16:20:51 +03:00
}
catch ( RetargetableJavaException )
{
}
if ( wrapper = = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . MainClassNotFound ) ;
2006-02-23 16:20:51 +03:00
}
MethodWrapper mw = wrapper . GetMethodWrapper ( "main" , "([Ljava.lang.String;)V" , false ) ;
2012-03-25 13:10:28 +04:00
if ( mw = = null | | ! mw . IsStatic )
2006-02-23 16:20:51 +03:00
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . MainMethodNotFound ) ;
2006-02-23 16:20:51 +03:00
}
mw . Link ( ) ;
MethodInfo method = mw . GetMethod ( ) as MethodInfo ;
if ( method = = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . UnsupportedMainMethod ) ;
2006-02-23 16:20:51 +03:00
}
2008-11-14 11:42:07 +03:00
if ( ! ReflectUtil . IsFromAssembly ( method . DeclaringType , assemblyBuilder )
2006-02-23 16:20:51 +03:00
& & ( ! method . IsPublic | | ! method . DeclaringType . IsPublic ) )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ExternalMainNotAccessible ) ;
2006-02-23 16:20:51 +03:00
}
Type apartmentAttributeType = null ;
if ( options . apartment = = ApartmentState . STA )
{
2009-10-14 18:58:41 +04:00
apartmentAttributeType = JVM . Import ( typeof ( STAThreadAttribute ) ) ;
2006-02-23 16:20:51 +03:00
}
else if ( options . apartment = = ApartmentState . MTA )
{
2009-10-14 18:58:41 +04:00
apartmentAttributeType = JVM . Import ( typeof ( MTAThreadAttribute ) ) ;
2006-02-23 16:20:51 +03:00
}
2008-08-13 17:04:47 +04:00
SetMain ( method , options . target , options . props , options . noglobbing , apartmentAttributeType ) ;
2006-02-23 16:20:51 +03:00
}
if ( map ! = null )
{
2008-08-13 17:04:47 +04:00
LoadMappedExceptions ( map ) ;
2006-02-23 16:20:51 +03:00
Tracer . Info ( Tracer . Compiler , "Loading remapped types (2)" ) ;
2008-08-13 17:04:47 +04:00
FinishRemappedTypes ( ) ;
2006-02-23 16:20:51 +03:00
}
Tracer . Info ( Tracer . Compiler , "Compiling class files (2)" ) ;
2008-08-13 17:04:47 +04:00
AddResources ( options . resources , options . compressedResources ) ;
2006-12-05 10:52:25 +03:00
if ( options . externalResources ! = null )
{
2008-08-08 10:26:37 +04:00
foreach ( KeyValuePair < string , string > kv in options . externalResources )
2006-12-05 10:52:25 +03:00
{
2008-08-13 17:04:47 +04:00
assemblyBuilder . AddResourceFile ( JVM . MangleResourceName ( kv . Key ) , kv . Value ) ;
2006-12-05 10:52:25 +03:00
}
}
2006-02-23 16:20:51 +03:00
if ( options . fileversion ! = null )
{
2009-10-14 18:58:41 +04:00
CustomAttributeBuilder filever = new CustomAttributeBuilder ( JVM . Import ( typeof ( System . Reflection . AssemblyFileVersionAttribute ) ) . GetConstructor ( new Type [ ] { Types . String } ) , new object [ ] { options . fileversion } ) ;
2008-08-13 17:04:47 +04:00
assemblyBuilder . SetCustomAttribute ( filever ) ;
2006-02-23 16:20:51 +03:00
}
2007-07-25 20:28:20 +04:00
foreach ( object [ ] def in assemblyAnnotations )
{
2008-08-13 17:04:47 +04:00
Annotation annotation = Annotation . Load ( this , def ) ;
2007-07-25 20:28:20 +04:00
if ( annotation ! = null )
{
2008-08-13 17:04:47 +04:00
annotation . Apply ( this , assemblyBuilder , def ) ;
2007-07-25 20:28:20 +04:00
}
}
2007-10-21 11:15:40 +04:00
if ( options . classLoader ! = null )
{
TypeWrapper wrapper = null ;
try
{
2008-08-13 17:04:47 +04:00
wrapper = LoadClassByDottedNameFast ( options . classLoader ) ;
2007-10-21 11:15:40 +04:00
}
catch ( RetargetableJavaException )
{
}
if ( wrapper = = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ClassLoaderNotFound ) ;
2007-10-21 11:15:40 +04:00
}
2009-07-27 20:46:15 +04:00
if ( ! wrapper . IsPublic & & ! ReflectUtil . IsFromAssembly ( wrapper . TypeAsBaseType , assemblyBuilder ) )
2007-10-21 11:15:40 +04:00
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ClassLoaderNotAccessible ) ;
2007-10-21 11:15:40 +04:00
}
if ( wrapper . IsAbstract )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ClassLoaderIsAbstract ) ;
2007-10-21 11:15:40 +04:00
}
if ( ! wrapper . IsAssignableTo ( ClassLoaderWrapper . LoadClassCritical ( "java.lang.ClassLoader" ) ) )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ClassLoaderNotClassLoader ) ;
2007-10-21 11:15:40 +04:00
}
MethodWrapper mw = wrapper . GetMethodWrapper ( "<init>" , "(Lcli.System.Reflection.Assembly;)V" , false ) ;
2007-10-25 16:57:40 +04:00
if ( mw = = null )
2007-10-21 11:15:40 +04:00
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . ClassLoaderConstructorMissing ) ;
2007-10-21 11:15:40 +04:00
}
2009-10-14 18:58:41 +04:00
ConstructorInfo ci = JVM . LoadType ( typeof ( CustomAssemblyClassLoaderAttribute ) ) . GetConstructor ( BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic , null , new Type [ ] { Types . Type } , null ) ;
2008-08-13 17:04:47 +04:00
assemblyBuilder . SetCustomAttribute ( new CustomAttributeBuilder ( ci , new object [ ] { wrapper . TypeAsTBD } ) ) ;
2009-11-03 10:15:37 +03:00
// TODO it would be better to do this for all assemblies in a shared class loader group (because options.classloader is relevant only for the main assembly),
// but since it is probably common to specify the custom assembly class loader at the group level, it hopefully won't make much difference in practice.
MethodWrapper mwModuleInit = wrapper . GetMethodWrapper ( "InitializeModule" , "(Lcli.System.Reflection.Module;)V" , false ) ;
if ( mwModuleInit ! = null & & ! mwModuleInit . IsStatic )
{
MethodBuilder moduleInitializer = GetTypeWrapperFactory ( ) . ModuleBuilder . DefineGlobalMethod ( ".cctor" , MethodAttributes . Private | MethodAttributes . Static | MethodAttributes . SpecialName | MethodAttributes . RTSpecialName , null , Type . EmptyTypes ) ;
ILGenerator ilgen = moduleInitializer . GetILGenerator ( ) ;
ilgen . Emit ( OpCodes . Ldtoken , moduleInitializer ) ;
2010-05-16 11:47:08 +04:00
ilgen . Emit ( OpCodes . Call , JVM . Import ( typeof ( System . Reflection . MethodBase ) ) . GetMethod ( "GetMethodFromHandle" , new Type [ ] { JVM . Import ( typeof ( RuntimeMethodHandle ) ) } ) ) ;
ilgen . Emit ( OpCodes . Callvirt , JVM . Import ( typeof ( System . Reflection . MemberInfo ) ) . GetMethod ( "get_Module" ) ) ;
2009-11-03 10:15:37 +03:00
ilgen . Emit ( OpCodes . Call , StaticCompiler . GetRuntimeType ( "IKVM.Runtime.ByteCodeHelper" ) . GetMethod ( "InitializeModule" ) ) ;
ilgen . Emit ( OpCodes . Ret ) ;
}
2007-10-21 11:15:40 +04:00
}
2010-11-29 10:11:46 +03:00
if ( options . iconfile ! = null )
{
2012-03-25 13:10:28 +04:00
assemblyBuilder . __DefineIconResource ( IkvmcCompiler . ReadAllBytes ( options . iconfile ) ) ;
2010-11-29 10:11:46 +03:00
}
2012-03-19 16:42:05 +04:00
if ( options . manifestFile ! = null )
{
2012-03-25 13:10:28 +04:00
assemblyBuilder . __DefineManifestResource ( IkvmcCompiler . ReadAllBytes ( options . manifestFile ) ) ;
2012-03-19 16:42:05 +04:00
}
2008-08-13 17:04:47 +04:00
assemblyBuilder . DefineVersionInfoResource ( ) ;
2006-02-23 16:20:51 +03:00
return 0 ;
}
private static void ser_UnknownElement ( object sender , System . Xml . Serialization . XmlElementEventArgs e )
{
2012-03-25 13:10:28 +04:00
StaticCompiler . IssueMessage ( Message . UnknownElementInMapFile , e . Element . Name , e . LineNumber . ToString ( ) , e . LinePosition . ToString ( ) ) ;
2006-02-23 16:20:51 +03:00
}
private static void ser_UnknownAttribute ( object sender , System . Xml . Serialization . XmlAttributeEventArgs e )
{
2012-03-25 13:10:28 +04:00
StaticCompiler . IssueMessage ( Message . UnknownAttributeInMapFile , e . Attr . Name , e . LineNumber . ToString ( ) , e . LinePosition . ToString ( ) ) ;
2006-02-23 16:20:51 +03:00
}
2009-12-11 11:06:10 +03:00
private bool ValidateAndSetMap ( IKVM . Internal . MapXml . Root map )
{
bool valid = true ;
if ( map . assembly ! = null )
{
if ( map . assembly . Classes ! = null )
{
foreach ( IKVM . Internal . MapXml . Class c in map . assembly . Classes )
{
if ( c . Fields ! = null )
{
foreach ( IKVM . Internal . MapXml . Field f in c . Fields )
{
ValidateNameSig ( "field" , c . Name , f . Name , f . Sig , ref valid , true ) ;
}
}
if ( c . Methods ! = null )
{
foreach ( IKVM . Internal . MapXml . Method m in c . Methods )
{
ValidateNameSig ( "method" , c . Name , m . Name , m . Sig , ref valid , false ) ;
}
}
if ( c . Constructors ! = null )
{
foreach ( IKVM . Internal . MapXml . Constructor ctor in c . Constructors )
{
ValidateNameSig ( "constructor" , c . Name , "<init>" , ctor . Sig , ref valid , false ) ;
}
}
if ( c . Properties ! = null )
{
foreach ( IKVM . Internal . MapXml . Property prop in c . Properties )
{
ValidateNameSig ( "property" , c . Name , prop . Name , prop . Sig , ref valid , false ) ;
ValidatePropertyGetterSetter ( "getter" , c . Name , prop . Name , prop . getter , ref valid ) ;
ValidatePropertyGetterSetter ( "setter" , c . Name , prop . Name , prop . setter , ref valid ) ;
}
}
}
}
}
this . map = map ;
return valid ;
}
private static void ValidateNameSig ( string member , string clazz , string name , string sig , ref bool valid , bool field )
{
if ( ! IsValidName ( name ) )
{
valid = false ;
2012-03-25 13:10:28 +04:00
StaticCompiler . IssueMessage ( Message . InvalidMemberNameInMapFile , member , name , clazz ) ;
2009-12-11 11:06:10 +03:00
}
if ( ! IsValidSig ( sig , field ) )
{
valid = false ;
2012-03-25 13:10:28 +04:00
StaticCompiler . IssueMessage ( Message . InvalidMemberSignatureInMapFile , member , clazz , name , sig ) ;
2009-12-11 11:06:10 +03:00
}
}
private static void ValidatePropertyGetterSetter ( string getterOrSetter , string clazz , string property , IKVM . Internal . MapXml . Method method , ref bool valid )
{
if ( method ! = null )
{
if ( ! IsValidName ( method . Name ) )
{
valid = false ;
2012-03-25 13:10:28 +04:00
StaticCompiler . IssueMessage ( Message . InvalidPropertyNameInMapFile , getterOrSetter , clazz , property , method . Name ) ;
2009-12-11 11:06:10 +03:00
}
if ( ! ClassFile . IsValidMethodSig ( method . Sig ) )
{
valid = false ;
2012-03-25 13:10:28 +04:00
StaticCompiler . IssueMessage ( Message . InvalidPropertySignatureInMapFile , getterOrSetter , clazz , property , method . Sig ) ;
2009-12-11 11:06:10 +03:00
}
}
}
private static bool IsValidName ( string name )
{
return name ! = null & & name . Length ! = 0 ;
}
private static bool IsValidSig ( string sig , bool field )
{
2009-12-11 16:47:10 +03:00
return sig ! = null & & ( field ? ClassFile . IsValidFieldSig ( sig ) : ClassFile . IsValidMethodSig ( sig ) ) ;
2009-12-11 11:06:10 +03:00
}
2010-05-16 10:31:20 +04:00
internal Type GetTypeFromReferencedAssembly ( string name )
{
foreach ( AssemblyClassLoader acl in referencedAssemblies )
{
Type type = acl . MainAssembly . GetType ( name , false ) ;
if ( type ! = null )
{
return type ;
}
}
return null ;
}
2010-07-28 16:37:25 +04:00
internal override void IssueMessage ( Message msgId , params string [ ] values )
{
StaticCompiler . IssueMessage ( options , msgId , values ) ;
}
2011-11-11 19:35:13 +04:00
2011-11-14 10:17:13 +04:00
internal bool TryEnableUnmanagedExports ( )
2011-11-11 19:35:13 +04:00
{
2011-11-14 10:17:13 +04:00
// we only support -platform:x86 and -platform:x64
// (currently IKVM.Reflection doesn't support unmanaged exports for ARM)
if ( ( options . imageFileMachine = = ImageFileMachine . I386 & & ( options . pekind & PortableExecutableKinds . Required32Bit ) ! = 0 )
| | options . imageFileMachine = = ImageFileMachine . AMD64 )
{
// when you add unmanaged exports, the ILOnly flag MUST NOT be set or the DLL will fail to load
options . pekind & = ~ PortableExecutableKinds . ILOnly ;
return true ;
}
else
{
2011-11-15 09:41:19 +04:00
StaticCompiler . IssueMessage ( options , Message . DllExportRequiresSupportedPlatform ) ;
2011-11-14 10:17:13 +04:00
return false ;
}
2011-11-11 19:35:13 +04:00
}
2006-02-23 16:20:51 +03:00
}
2006-08-31 13:22:10 +04:00
2012-03-24 12:54:12 +04:00
struct ClassItem
{
internal byte [ ] data ;
internal string path ;
}
2010-08-05 17:43:00 +04:00
struct ResourceItem
{
internal ICSharpCode . SharpZipLib . Zip . ZipEntry zipEntry ;
internal byte [ ] data ;
internal string jar ;
}
2012-08-06 16:12:03 +04:00
sealed class CompilerOptions
2006-08-31 13:22:10 +04:00
{
internal string path ;
2010-05-07 16:05:52 +04:00
internal string keyfile ;
internal string keycontainer ;
internal bool delaysign ;
internal byte [ ] publicKey ;
internal StrongNameKeyPair keyPair ;
2010-04-14 18:43:21 +04:00
internal Version version ;
2006-08-31 13:22:10 +04:00
internal string fileversion ;
2010-11-29 10:11:46 +03:00
internal string iconfile ;
2012-03-19 16:42:05 +04:00
internal string manifestFile ;
2006-08-31 13:22:10 +04:00
internal bool targetIsModule ;
internal string assembly ;
internal string mainClass ;
internal ApartmentState apartment ;
internal PEFileKinds target ;
internal bool guessFileKind ;
2012-03-24 12:54:12 +04:00
internal Dictionary < string , ClassItem > classes ;
2009-11-04 08:18:37 +03:00
internal string [ ] unresolvedReferences ; // only used during command line parsing
2009-10-19 09:39:23 +04:00
internal Assembly [ ] references ;
2009-11-04 08:18:37 +03:00
internal string [ ] peerReferences ;
internal bool crossReferenceAllPeers = true ;
2010-08-05 17:43:00 +04:00
internal Dictionary < string , List < ResourceItem > > resources ;
2006-08-31 13:22:10 +04:00
internal string [ ] classesToExclude ;
internal string remapfile ;
2008-08-08 10:26:37 +04:00
internal Dictionary < string , string > props ;
2006-08-31 13:22:10 +04:00
internal bool noglobbing ;
internal CodeGenOptions codegenoptions ;
internal bool removeUnusedFields ;
internal bool compressedResources ;
internal string [ ] privatePackages ;
2009-10-28 14:25:20 +03:00
internal string [ ] publicPackages ;
2006-08-31 13:22:10 +04:00
internal string sourcepath ;
2008-08-08 10:26:37 +04:00
internal Dictionary < string , string > externalResources ;
2007-10-21 11:15:40 +04:00
internal string classLoader ;
2008-01-03 12:39:12 +03:00
internal PortableExecutableKinds pekind = PortableExecutableKinds . ILOnly ;
internal ImageFileMachine imageFileMachine = ImageFileMachine . I386 ;
2009-06-22 10:12:47 +04:00
internal long baseAddress ;
2012-03-21 15:33:10 +04:00
internal int fileAlignment ;
2012-03-21 16:38:22 +04:00
internal bool highentropyva ;
2008-12-23 10:11:29 +03:00
internal List < CompilerClassLoader > sharedclassloader ; // should *not* be deep copied in Copy(), because we want the list of all compilers that share a class loader
2010-07-16 12:50:40 +04:00
internal Dictionary < string , string > suppressWarnings = new Dictionary < string , string > ( ) ;
2011-06-28 10:02:11 +04:00
internal Dictionary < string , string > errorWarnings = new Dictionary < string , string > ( ) ; // treat specific warnings as errors
internal bool warnaserror ; // treat all warnings as errors
2010-07-16 12:56:13 +04:00
internal string writeSuppressWarningsFile ;
2011-05-12 12:08:08 +04:00
internal List < string > proxies = new List < string > ( ) ;
2008-08-13 17:04:47 +04:00
internal CompilerOptions Copy ( )
{
CompilerOptions copy = ( CompilerOptions ) MemberwiseClone ( ) ;
if ( classes ! = null )
{
2012-03-24 12:54:12 +04:00
copy . classes = new Dictionary < string , ClassItem > ( classes ) ;
2008-08-13 17:04:47 +04:00
}
if ( resources ! = null )
{
2010-08-05 17:43:00 +04:00
copy . resources = Copy ( resources ) ;
2008-08-13 17:04:47 +04:00
}
if ( props ! = null )
{
copy . props = new Dictionary < string , string > ( props ) ;
}
if ( externalResources ! = null )
{
copy . externalResources = new Dictionary < string , string > ( externalResources ) ;
}
2010-07-16 12:50:40 +04:00
copy . suppressWarnings = new Dictionary < string , string > ( suppressWarnings ) ;
copy . errorWarnings = new Dictionary < string , string > ( errorWarnings ) ;
2008-08-13 17:04:47 +04:00
return copy ;
}
2010-08-05 17:43:00 +04:00
internal static Dictionary < string , List < ResourceItem > > Copy ( Dictionary < string , List < ResourceItem > > resources )
{
Dictionary < string , List < ResourceItem > > copy = new Dictionary < string , List < ResourceItem > > ( ) ;
foreach ( KeyValuePair < string , List < ResourceItem > > kv in resources )
{
copy . Add ( kv . Key , new List < ResourceItem > ( kv . Value ) ) ;
}
return copy ;
}
2006-08-31 13:22:10 +04:00
}
enum Message
{
// These are the informational messages
MainMethodFound = 1 ,
OutputFileIs = 2 ,
AutoAddRef = 3 ,
MainMethodFromManifest = 4 ,
// This is were the warnings start
StartWarnings = 100 ,
ClassNotFound = 100 ,
ClassFormatError = 101 ,
DuplicateClassName = 102 ,
IllegalAccessError = 103 ,
VerificationError = 104 ,
NoClassDefFoundError = 105 ,
GenericUnableToCompileError = 106 ,
DuplicateResourceName = 107 ,
NotAClassFile = 108 ,
2007-01-31 14:26:41 +03:00
SkippingReferencedClass = 109 ,
2008-01-03 12:39:12 +03:00
NoJniRuntime = 110 ,
2008-12-23 09:07:10 +03:00
EmittedNoClassDefFoundError = 111 ,
EmittedIllegalAccessError = 112 ,
EmittedInstantiationError = 113 ,
EmittedIncompatibleClassChangeError = 114 ,
EmittedNoSuchFieldError = 115 ,
EmittedAbstractMethodError = 116 ,
EmittedNoSuchMethodError = 117 ,
EmittedLinkageError = 118 ,
2009-06-18 10:13:21 +04:00
EmittedVerificationError = 119 ,
EmittedClassFormatError = 120 ,
2010-05-07 09:48:22 +04:00
InvalidCustomAttribute = 121 ,
IgnoredCustomAttribute = 122 ,
2010-05-11 10:12:12 +04:00
AssumeAssemblyVersionMatch = 123 ,
2010-05-18 10:48:40 +04:00
InvalidDirectoryInLibOptionPath = 124 ,
InvalidDirectoryInLibEnvironmentPath = 125 ,
LegacySearchRule = 126 ,
AssemblyLocationIgnored = 127 ,
2011-02-17 15:43:18 +03:00
InterfaceMethodCantBeInternal = 128 ,
2011-11-11 19:35:13 +04:00
DllExportMustBeStaticMethod = 129 ,
2011-11-14 10:17:13 +04:00
DllExportRequiresSupportedPlatform = 130 ,
2011-11-15 09:51:38 +04:00
NonPrimaryAssemblyReference = 131 ,
DuplicateAssemblyReference = 132 ,
2013-01-07 16:19:56 +04:00
UnableToResolveType = 133 ,
2013-01-08 18:47:50 +04:00
StubsAreDeprecated = 134 ,
2010-05-18 10:48:40 +04:00
UnknownWarning = 999 ,
2011-05-12 12:08:08 +04:00
// This is where the errors start
StartErrors = 4000 ,
UnableToCreateProxy = 4001 ,
DuplicateProxy = 4002 ,
2011-07-11 11:32:40 +04:00
MapXmlUnableToResolveOpCode = 4003 ,
MapXmlError = 4004 ,
2012-03-23 20:45:41 +04:00
InputFileNotFound = 4005 ,
UnknownFileType = 4006 ,
2012-03-25 13:10:28 +04:00
UnknownElementInMapFile = 4007 ,
UnknownAttributeInMapFile = 4008 ,
InvalidMemberNameInMapFile = 4009 ,
InvalidMemberSignatureInMapFile = 4010 ,
InvalidPropertyNameInMapFile = 4011 ,
InvalidPropertySignatureInMapFile = 4012 ,
2012-03-23 20:45:41 +04:00
// Fatal errors
ResponseFileDepthExceeded = 5000 ,
ErrorReadingFile = 5001 ,
NoTargetsFound = 5002 ,
FileFormatLimitationExceeded = 5003 ,
CannotSpecifyBothKeyFileAndContainer = 5004 ,
DelaySignRequiresKey = 5005 ,
InvalidStrongNameKeyPair = 5006 ,
ReferenceNotFound = 5007 ,
OptionsMustPreceedChildLevels = 5008 ,
UnrecognizedTargetType = 5009 ,
UnrecognizedPlatform = 5010 ,
UnrecognizedApartment = 5011 ,
MissingFileSpecification = 5012 ,
PathTooLong = 5013 ,
PathNotFound = 5014 ,
InvalidPath = 5015 ,
InvalidOptionSyntax = 5016 ,
ExternalResourceNotFound = 5017 ,
ExternalResourceNameInvalid = 5018 ,
InvalidVersionFormat = 5019 ,
InvalidFileAlignment = 5020 ,
ErrorWritingFile = 5021 ,
UnrecognizedOption = 5022 ,
NoOutputFileSpecified = 5023 ,
SharedClassLoaderCannotBeUsedOnModuleTarget = 5024 ,
2012-03-25 13:10:28 +04:00
RuntimeNotFound = 5025 ,
MainClassRequiresExe = 5026 ,
ExeRequiresMainClass = 5027 ,
PropertiesRequireExe = 5028 ,
ModuleCannotHaveClassLoader = 5029 ,
ErrorParsingMapFile = 5030 ,
BootstrapClassesMissing = 5031 ,
StrongNameRequiresStrongNamedRefs = 5032 ,
MainClassNotFound = 5033 ,
MainMethodNotFound = 5034 ,
UnsupportedMainMethod = 5035 ,
ExternalMainNotAccessible = 5036 ,
ClassLoaderNotFound = 5037 ,
ClassLoaderNotAccessible = 5038 ,
ClassLoaderIsAbstract = 5039 ,
ClassLoaderNotClassLoader = 5040 ,
ClassLoaderConstructorMissing = 5041 ,
MapFileTypeNotFound = 5042 ,
MapFileClassNotFound = 5043 ,
MaximumErrorCountReached = 5044 ,
LinkageError = 5045 ,
RuntimeMismatch = 5046 ,
RuntimeMismatchStrongName = 5047 ,
CoreClassesMissing = 5048 ,
CriticalClassNotFound = 5049 ,
AssemblyContainsDuplicateClassNames = 5050 ,
CallerIDRequiresHasCallerIDAnnotation = 5051 ,
UnableToResolveInterface = 5052 ,
2013-01-08 11:07:07 +04:00
MissingBaseType = 5053 ,
2006-08-31 13:22:10 +04:00
}
2009-10-21 08:54:39 +04:00
static class StaticCompiler
2006-08-31 13:22:10 +04:00
{
2013-01-07 16:19:56 +04:00
internal static readonly Universe Universe = new Universe ( UniverseOptions . ResolveMissingMembers ) ;
2006-08-31 13:22:10 +04:00
internal static Assembly runtimeAssembly ;
2008-01-03 12:39:12 +03:00
internal static Assembly runtimeJniAssembly ;
2010-07-16 12:50:40 +04:00
internal static CompilerOptions toplevel ;
2011-06-28 10:17:40 +04:00
internal static int errorCount ;
2006-08-31 13:22:10 +04:00
2013-01-07 16:19:56 +04:00
static StaticCompiler ( )
{
Universe . ResolvedMissingMember + = ResolvedMissingMember ;
}
private static void ResolvedMissingMember ( Module requestingModule , MemberInfo member )
{
if ( requestingModule ! = null & & member is Type )
{
IssueMessage ( Message . UnableToResolveType , requestingModule . Name , ( ( Type ) member ) . FullName , member . Module . FullyQualifiedName ) ;
}
}
2009-10-21 08:54:39 +04:00
internal static Assembly Load ( string assemblyString )
{
2010-01-25 10:52:27 +03:00
return Universe . Load ( assemblyString ) ;
2009-10-21 08:54:39 +04:00
}
internal static Assembly LoadFile ( string path )
{
2010-05-12 19:15:25 +04:00
return Universe . LoadFile ( path ) ;
2009-10-21 08:54:39 +04:00
}
internal static Type GetRuntimeType ( string name )
{
Type type = runtimeAssembly . GetType ( name ) ;
if ( type ! = null )
{
return type ;
}
if ( runtimeJniAssembly ! = null )
{
return runtimeJniAssembly . GetType ( name , true ) ;
}
else
{
2010-05-27 12:27:37 +04:00
throw new TypeLoadException ( name ) ;
2009-10-21 08:54:39 +04:00
}
}
2010-09-20 19:08:45 +04:00
internal static Type GetTypeForMapXml ( ClassLoaderWrapper loader , string name )
2006-08-31 13:22:10 +04:00
{
2010-09-20 19:08:45 +04:00
Type type = GetType ( loader , name ) ;
if ( type = = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . MapFileTypeNotFound , name ) ;
2010-09-20 19:08:45 +04:00
}
return type ;
2006-08-31 13:22:10 +04:00
}
2010-10-21 14:58:57 +04:00
internal static TypeWrapper GetClassForMapXml ( ClassLoaderWrapper loader , string name )
{
TypeWrapper tw = loader . LoadClassByDottedNameFast ( name ) ;
if ( tw = = null )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . MapFileClassNotFound , name ) ;
2010-10-21 14:58:57 +04:00
}
return tw ;
}
2010-09-20 19:08:45 +04:00
internal static Type GetType ( ClassLoaderWrapper loader , string name )
2006-08-31 13:22:10 +04:00
{
2010-05-16 10:31:20 +04:00
CompilerClassLoader ccl = ( CompilerClassLoader ) loader ;
2010-09-20 19:08:45 +04:00
return ccl . GetTypeFromReferencedAssembly ( name ) ;
2006-08-31 13:22:10 +04:00
}
2010-07-16 12:50:40 +04:00
internal static void IssueMessage ( Message msgId , params string [ ] values )
2007-01-06 00:22:55 +03:00
{
2010-07-16 12:50:40 +04:00
IssueMessage ( toplevel , msgId , values ) ;
2007-01-06 00:22:55 +03:00
}
2010-07-16 12:50:40 +04:00
internal static void IssueMessage ( CompilerOptions options , Message msgId , params string [ ] values )
2006-08-31 13:22:10 +04:00
{
2013-01-07 14:54:55 +04:00
string key = ( ( int ) msgId ) . ToString ( ) ;
for ( int i = 0 ; ; i + + )
2006-08-31 13:22:10 +04:00
{
2013-01-07 14:54:55 +04:00
if ( options . suppressWarnings . ContainsKey ( key ) )
{
return ;
}
if ( i = = values . Length )
{
break ;
}
key + = ":" + values [ i ] ;
2006-08-31 13:22:10 +04:00
}
2010-07-16 12:50:40 +04:00
options . suppressWarnings . Add ( key , key ) ;
2010-07-16 12:56:13 +04:00
if ( options . writeSuppressWarningsFile ! = null )
{
File . AppendAllText ( options . writeSuppressWarningsFile , "-nowarn:" + key + Environment . NewLine ) ;
}
2006-08-31 13:22:10 +04:00
string msg ;
switch ( msgId )
{
case Message . MainMethodFound :
2012-03-23 20:45:41 +04:00
msg = "Found main method in class \"{0}\"" ;
2006-08-31 13:22:10 +04:00
break ;
case Message . OutputFileIs :
2012-03-23 20:45:41 +04:00
msg = "Output file is \"{0}\"" ;
2006-08-31 13:22:10 +04:00
break ;
case Message . AutoAddRef :
2012-03-23 20:45:41 +04:00
msg = "Automatically adding reference to \"{0}\"" ;
2006-08-31 13:22:10 +04:00
break ;
case Message . MainMethodFromManifest :
2012-03-23 20:45:41 +04:00
msg = "Using main class \"{0}\" based on jar manifest" ;
2006-08-31 13:22:10 +04:00
break ;
case Message . ClassNotFound :
2012-03-23 20:45:41 +04:00
msg = "Class \"{0}\" not found" ;
2006-08-31 13:22:10 +04:00
break ;
case Message . ClassFormatError :
2012-03-23 20:45:41 +04:00
msg = "Unable to compile class \"{0}\"" + Environment . NewLine +
2006-08-31 13:22:10 +04:00
" (class format error \"{1}\")" ;
break ;
case Message . DuplicateClassName :
2012-03-23 20:45:41 +04:00
msg = "Duplicate class name: \"{0}\"" ;
2006-08-31 13:22:10 +04:00
break ;
case Message . IllegalAccessError :
2012-03-23 20:45:41 +04:00
msg = "Unable to compile class \"{0}\"" + Environment . NewLine +
2006-08-31 13:22:10 +04:00
" (illegal access error \"{1}\")" ;
break ;
case Message . VerificationError :
2012-03-23 20:45:41 +04:00
msg = "Unable to compile class \"{0}\"" + Environment . NewLine +
2006-08-31 13:22:10 +04:00
" (verification error \"{1}\")" ;
break ;
case Message . NoClassDefFoundError :
2012-03-23 20:45:41 +04:00
msg = "Unable to compile class \"{0}\"" + Environment . NewLine +
2006-08-31 13:22:10 +04:00
" (missing class \"{1}\")" ;
break ;
case Message . GenericUnableToCompileError :
2012-03-23 20:45:41 +04:00
msg = "Unable to compile class \"{0}\"" + Environment . NewLine +
2006-08-31 13:22:10 +04:00
" (\"{1}\": \"{2}\")" ;
break ;
case Message . DuplicateResourceName :
2012-03-23 20:45:41 +04:00
msg = "Skipping resource (name clash): \"{0}\"" ;
2006-08-31 13:22:10 +04:00
break ;
case Message . NotAClassFile :
2012-03-23 20:45:41 +04:00
msg = "Not a class file \"{0}\", including it as resource" + Environment . NewLine +
2006-08-31 13:22:10 +04:00
" (class format error \"{1}\")" ;
break ;
2007-01-31 14:26:41 +03:00
case Message . SkippingReferencedClass :
2012-03-23 20:45:41 +04:00
msg = "Skipping class: \"{0}\"" + Environment . NewLine +
2007-01-31 14:26:41 +03:00
" (class is already available in referenced assembly \"{1}\")" ;
break ;
2008-01-03 12:39:12 +03:00
case Message . NoJniRuntime :
2012-03-23 20:45:41 +04:00
msg = "Unable to load runtime JNI assembly" ;
2008-01-03 12:39:12 +03:00
break ;
2008-12-23 09:07:10 +03:00
case Message . EmittedNoClassDefFoundError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.NoClassDefFoundError in \"{0}\"" + Environment . NewLine +
2008-12-23 09:07:10 +03:00
" (\"{1}\")" ;
break ;
case Message . EmittedIllegalAccessError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.IllegalAccessError in \"{0}\"" + Environment . NewLine +
2008-12-23 09:07:10 +03:00
" (\"{1}\")" ;
break ;
case Message . EmittedInstantiationError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.InstantiationError in \"{0}\"" + Environment . NewLine +
2008-12-23 09:07:10 +03:00
" (\"{1}\")" ;
break ;
case Message . EmittedIncompatibleClassChangeError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.IncompatibleClassChangeError in \"{0}\"" + Environment . NewLine +
2008-12-23 09:07:10 +03:00
" (\"{1}\")" ;
break ;
case Message . EmittedNoSuchFieldError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.NoSuchFieldError in \"{0}\"" + Environment . NewLine +
2008-12-23 09:07:10 +03:00
" (\"{1}\")" ;
break ;
case Message . EmittedAbstractMethodError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.AbstractMethodError in \"{0}\"" + Environment . NewLine +
2008-12-23 09:07:10 +03:00
" (\"{1}\")" ;
break ;
case Message . EmittedNoSuchMethodError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.NoSuchMethodError in \"{0}\"" + Environment . NewLine +
2008-12-23 09:07:10 +03:00
" (\"{1}\")" ;
break ;
case Message . EmittedLinkageError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.LinkageError in \"{0}\"" + Environment . NewLine +
2008-12-23 09:07:10 +03:00
" (\"{1}\")" ;
break ;
2009-06-18 10:13:21 +04:00
case Message . EmittedVerificationError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.VerificationError in \"{0}\"" + Environment . NewLine +
2009-06-18 10:13:21 +04:00
" (\"{1}\")" ;
break ;
case Message . EmittedClassFormatError :
2012-03-23 20:45:41 +04:00
msg = "Emitted java.lang.ClassFormatError in \"{0}\"" + Environment . NewLine +
2009-06-18 10:13:21 +04:00
" (\"{1}\")" ;
break ;
2010-05-07 09:48:22 +04:00
case Message . InvalidCustomAttribute :
2012-03-23 20:45:41 +04:00
msg = "Error emitting \"{0}\" custom attribute" + Environment . NewLine +
2010-05-07 09:48:22 +04:00
" (\"{1}\")" ;
break ;
case Message . IgnoredCustomAttribute :
2012-03-23 20:45:41 +04:00
msg = "Custom attribute \"{0}\" was ignored" + Environment . NewLine +
2010-05-07 09:48:22 +04:00
" (\"{1}\")" ;
break ;
2010-05-11 10:12:12 +04:00
case Message . AssumeAssemblyVersionMatch :
2012-03-23 20:45:41 +04:00
msg = "Assuming assembly reference \"{0}\" matches \"{1}\", you may need to supply runtime policy" ;
2010-05-11 10:12:12 +04:00
break ;
2010-05-18 10:48:40 +04:00
case Message . InvalidDirectoryInLibOptionPath :
2012-03-23 20:45:41 +04:00
msg = "Directory \"{0}\" specified in -lib option is not valid" ;
2010-05-18 10:48:40 +04:00
break ;
case Message . InvalidDirectoryInLibEnvironmentPath :
2012-03-23 20:45:41 +04:00
msg = "Directory \"{0}\" specified in LIB environment is not valid" ;
2010-05-18 10:48:40 +04:00
break ;
case Message . LegacySearchRule :
2012-03-23 20:45:41 +04:00
msg = "Found assembly \"{0}\" using legacy search rule, please append '.dll' to the reference" ;
2010-05-18 10:48:40 +04:00
break ;
case Message . AssemblyLocationIgnored :
2012-03-23 20:45:41 +04:00
msg = "Assembly \"{0}\" is ignored as previously loaded assembly \"{1}\" has the same identity \"{2}\"" ;
2010-05-18 10:48:40 +04:00
break ;
2011-02-17 15:43:18 +03:00
case Message . InterfaceMethodCantBeInternal :
2012-03-23 20:45:41 +04:00
msg = "Ignoring @ikvm.lang.Internal annotation on interface method" + Environment . NewLine +
2011-02-17 15:43:18 +03:00
" (\"{0}.{1}{2}\")" ;
break ;
2011-11-11 19:35:13 +04:00
case Message . DllExportMustBeStaticMethod :
2012-03-23 20:45:41 +04:00
msg = "Ignoring @ikvm.lang.DllExport annotation on non-static method" + Environment . NewLine +
2011-11-11 19:35:13 +04:00
" (\"{0}.{1}{2}\")" ;
break ;
2011-11-14 10:17:13 +04:00
case Message . DllExportRequiresSupportedPlatform :
2012-03-23 20:45:41 +04:00
msg = "Ignoring @ikvm.lang.DllExport annotation due to unsupported target platform" ;
2011-11-14 10:17:13 +04:00
break ;
2011-11-15 09:51:38 +04:00
case Message . NonPrimaryAssemblyReference :
2012-03-23 20:45:41 +04:00
msg = "Referenced assembly \"{0}\" is not the primary assembly of a shared class loader group, referencing primary assembly \"{1}\" instead" ;
2011-11-15 09:51:38 +04:00
break ;
case Message . DuplicateAssemblyReference :
2012-03-23 20:45:41 +04:00
msg = "Duplicate assembly reference \"{0}\"" ;
2011-11-15 09:51:38 +04:00
break ;
2013-01-07 16:19:56 +04:00
case Message . UnableToResolveType :
msg = "Reference in \"{0}\" to type \"{1}\" claims it is defined in \"{2}\", but it could not be found" ;
break ;
2013-01-08 18:47:50 +04:00
case Message . StubsAreDeprecated :
msg = "Compiling stubs is deprecated. Please add a reference to assembly \"{0}\" instead." ;
break ;
2011-05-12 12:08:08 +04:00
case Message . UnableToCreateProxy :
2012-03-23 20:45:41 +04:00
msg = "Unable to create proxy \"{0}\"" + Environment . NewLine +
2011-05-12 12:08:08 +04:00
" (\"{1}\")" ;
break ;
case Message . DuplicateProxy :
2012-03-23 20:45:41 +04:00
msg = "Duplicate proxy \"{0}\"" ;
2011-05-12 12:08:08 +04:00
break ;
2011-07-11 11:32:40 +04:00
case Message . MapXmlUnableToResolveOpCode :
2012-03-23 20:45:41 +04:00
msg = "Unable to resolve opcode in remap file: {0}" ;
2011-07-11 11:32:40 +04:00
break ;
case Message . MapXmlError :
2012-03-23 20:45:41 +04:00
msg = "Error in remap file: {0}" ;
break ;
case Message . InputFileNotFound :
msg = "Source file '{0}' not found" ;
break ;
case Message . UnknownFileType :
msg = "Unknown file type: {0}" ;
2011-07-11 11:32:40 +04:00
break ;
2012-03-25 13:10:28 +04:00
case Message . UnknownElementInMapFile :
msg = "Unknown element {0} in remap file, line {1}, column {2}" ;
break ;
case Message . UnknownAttributeInMapFile :
msg = "Unknown attribute {0} in remap file, line {1}, column {2}" ;
break ;
case Message . InvalidMemberNameInMapFile :
msg = "Invalid {0} name '{1}' in remap file in class {2}" ;
break ;
case Message . InvalidMemberSignatureInMapFile :
msg = "Invalid {0} signature '{3}' in remap file for {0} {1}.{2}" ;
break ;
case Message . InvalidPropertyNameInMapFile :
msg = "Invalid property {0} name '{3}' in remap file for property {1}.{2}" ;
break ;
case Message . InvalidPropertySignatureInMapFile :
msg = "Invalid property {0} signature '{3}' in remap file for property {1}.{2}" ;
break ;
2010-05-18 10:48:40 +04:00
case Message . UnknownWarning :
msg = "{0}" ;
break ;
2006-08-31 13:22:10 +04:00
default :
throw new InvalidProgramException ( ) ;
}
2011-05-12 12:08:08 +04:00
bool error = msgId > = Message . StartErrors
2011-11-27 15:29:56 +04:00
| | ( options . warnaserror & & msgId > = Message . StartWarnings )
2011-05-12 12:08:08 +04:00
| | options . errorWarnings . ContainsKey ( key )
| | options . errorWarnings . ContainsKey ( ( ( int ) msgId ) . ToString ( ) ) ;
2012-03-23 20:45:41 +04:00
Console . Error . Write ( "{0} IKVMC{1:D4}: " , error ? "error" : msgId < Message . StartWarnings ? "note" : "warning" , ( int ) msgId ) ;
2011-11-27 15:29:56 +04:00
if ( error & & Message . StartWarnings < = msgId & & msgId < Message . StartErrors )
2011-06-28 10:02:11 +04:00
{
Console . Error . Write ( "Warning as Error: " ) ;
}
2006-08-31 13:22:10 +04:00
Console . Error . WriteLine ( msg , values ) ;
2010-07-16 12:50:40 +04:00
if ( options ! = toplevel & & options . path ! = null )
{
Console . Error . WriteLine ( " (in {0})" , options . path ) ;
}
2011-05-12 12:08:08 +04:00
if ( error )
{
2011-06-28 10:17:40 +04:00
if ( + + errorCount = = 100 )
{
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . MaximumErrorCountReached ) ;
2011-06-28 10:17:40 +04:00
}
2011-05-12 12:08:08 +04:00
}
2006-08-31 13:22:10 +04:00
}
2007-02-01 10:13:02 +03:00
internal static void LinkageError ( string msg , TypeWrapper actualType , TypeWrapper expectedType , params object [ ] values )
{
object [ ] args = new object [ values . Length + 2 ] ;
values . CopyTo ( args , 2 ) ;
args [ 0 ] = AssemblyQualifiedName ( actualType ) ;
args [ 1 ] = AssemblyQualifiedName ( expectedType ) ;
2012-03-25 13:10:28 +04:00
string str = string . Format ( msg , args ) ;
2010-09-10 12:14:42 +04:00
if ( actualType is UnloadableTypeWrapper & & ( expectedType is CompiledTypeWrapper | | expectedType is DotNetTypeWrapper ) )
{
2012-03-25 13:10:28 +04:00
str + = string . Format ( "\n\t(Please add a reference to {0})" , expectedType . TypeAsBaseType . Assembly . Location ) ;
2010-09-10 12:14:42 +04:00
}
2012-03-25 13:10:28 +04:00
throw new FatalCompilerErrorException ( Message . LinkageError , str ) ;
2007-02-01 10:13:02 +03:00
}
private static string AssemblyQualifiedName ( TypeWrapper tw )
{
ClassLoaderWrapper loader = tw . GetClassLoader ( ) ;
AssemblyClassLoader acl = loader as AssemblyClassLoader ;
if ( acl ! = null )
{
2009-02-05 09:59:11 +03:00
return tw . Name + ", " + acl . GetAssembly ( tw ) . FullName ;
2007-02-01 10:13:02 +03:00
}
CompilerClassLoader ccl = loader as CompilerClassLoader ;
if ( ccl ! = null )
{
return tw . Name + ", " + ccl . GetTypeWrapperFactory ( ) . ModuleBuilder . Assembly . FullName ;
}
return tw . Name + " (unknown assembly)" ;
}
2006-08-31 13:22:10 +04:00
}
2006-02-23 16:20:51 +03:00
}