2002-12-18 19:00:25 +03:00
|
|
|
/*
|
2005-01-05 15:11:50 +03:00
|
|
|
Copyright (C) 2002, 2003, 2004, 2005 Jeroen Frijters
|
2002-12-18 19:00:25 +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
|
|
|
|
|
|
|
|
*/
|
|
|
|
using System;
|
2004-09-05 13:37:58 +04:00
|
|
|
using System.Threading;
|
2004-03-16 20:10:09 +03:00
|
|
|
using System.Resources;
|
2002-12-18 19:00:25 +03:00
|
|
|
using System.Reflection.Emit;
|
|
|
|
using System.Reflection;
|
|
|
|
using System.IO;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Xml;
|
|
|
|
using System.Diagnostics;
|
2003-08-21 14:06:34 +04:00
|
|
|
using System.Text.RegularExpressions;
|
2005-02-02 18:11:26 +03:00
|
|
|
using System.Text;
|
2005-05-23 12:24:07 +04:00
|
|
|
using System.Security;
|
|
|
|
using System.Security.Permissions;
|
2004-09-09 15:17:55 +04:00
|
|
|
using IKVM.Attributes;
|
|
|
|
using IKVM.Runtime;
|
2002-12-18 19:00:25 +03:00
|
|
|
|
2004-10-19 17:43:55 +04:00
|
|
|
using ILGenerator = CountingILGenerator;
|
|
|
|
|
2004-09-15 17:35:44 +04:00
|
|
|
namespace IKVM.Runtime
|
|
|
|
{
|
2004-10-19 17:43:55 +04:00
|
|
|
public sealed class Startup
|
2004-09-15 17:35:44 +04:00
|
|
|
{
|
2004-10-19 17:43:55 +04:00
|
|
|
private Startup()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-02-16 14:20:43 +03:00
|
|
|
private static string[] Glob(string arg)
|
2004-09-15 17:35:44 +04:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
string dir = Path.GetDirectoryName(arg);
|
|
|
|
if(dir == "")
|
|
|
|
{
|
|
|
|
dir = null;
|
|
|
|
}
|
|
|
|
ArrayList list = new ArrayList();
|
|
|
|
foreach(FileSystemInfo fsi in new DirectoryInfo(dir == null ? Environment.CurrentDirectory : dir).GetFileSystemInfos(Path.GetFileName(arg)))
|
|
|
|
{
|
|
|
|
list.Add(dir != null ? Path.Combine(dir, fsi.Name) : fsi.Name);
|
|
|
|
}
|
|
|
|
if(list.Count == 0)
|
|
|
|
{
|
|
|
|
return new string[] { arg };
|
|
|
|
}
|
|
|
|
return (string[])list.ToArray(typeof(string));
|
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
|
|
|
return new string[] { arg };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static string[] Glob()
|
|
|
|
{
|
2005-02-16 14:20:43 +03:00
|
|
|
return Glob(1);
|
2004-09-15 17:35:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
public static string[] Glob(int skip)
|
|
|
|
{
|
|
|
|
if(IKVM.Internal.JVM.IsUnix)
|
|
|
|
{
|
|
|
|
string[] args = Environment.GetCommandLineArgs();
|
|
|
|
string[] vmargs = new string[args.Length - skip];
|
|
|
|
Array.Copy(args, skip, vmargs, 0, args.Length - skip);
|
|
|
|
return vmargs;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ArrayList list = new ArrayList();
|
|
|
|
string cmdline = Environment.CommandLine;
|
2005-02-02 18:11:26 +03:00
|
|
|
StringBuilder sb = new StringBuilder();
|
2004-09-15 17:35:44 +04:00
|
|
|
for(int i = 0; i < cmdline.Length;)
|
|
|
|
{
|
|
|
|
bool quoted = cmdline[i] == '"';
|
|
|
|
cont_arg:
|
|
|
|
while(i < cmdline.Length && cmdline[i] != ' ' && cmdline[i] != '"')
|
|
|
|
{
|
|
|
|
sb.Append(cmdline[i++]);
|
|
|
|
}
|
|
|
|
if(i < cmdline.Length && cmdline[i] == '"')
|
|
|
|
{
|
|
|
|
if(quoted && i > 1 && cmdline[i - 1] == '"')
|
|
|
|
{
|
|
|
|
sb.Append('"');
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
while(i < cmdline.Length && cmdline[i] != '"')
|
|
|
|
{
|
|
|
|
sb.Append(cmdline[i++]);
|
|
|
|
}
|
|
|
|
if(i < cmdline.Length && cmdline[i] == '"')
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if(i < cmdline.Length && cmdline[i] != ' ')
|
|
|
|
{
|
|
|
|
goto cont_arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while(i < cmdline.Length && cmdline[i] == ' ')
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if(skip > 0)
|
|
|
|
{
|
|
|
|
skip--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(quoted)
|
|
|
|
{
|
|
|
|
list.Add(sb.ToString());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
list.AddRange(Glob(sb.ToString()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sb.Length = 0;
|
|
|
|
}
|
|
|
|
return (string[])list.ToArray(typeof(string));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-19 17:43:55 +04:00
|
|
|
public static void SetProperties(System.Collections.Hashtable props)
|
2004-09-15 17:35:44 +04:00
|
|
|
{
|
2004-12-07 12:53:28 +03:00
|
|
|
IKVM.Internal.JVM.Library.setProperties(props);
|
2004-09-15 17:35:44 +04:00
|
|
|
}
|
2004-09-27 14:17:34 +04:00
|
|
|
|
|
|
|
public static void EnterMainThread()
|
|
|
|
{
|
|
|
|
if(Thread.CurrentThread.Name == null)
|
|
|
|
{
|
2005-02-16 14:20:43 +03:00
|
|
|
try
|
|
|
|
{
|
|
|
|
Thread.CurrentThread.Name = "main";
|
|
|
|
}
|
|
|
|
catch(InvalidOperationException)
|
|
|
|
{
|
|
|
|
}
|
2004-09-27 14:17:34 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void ExitMainThread()
|
|
|
|
{
|
|
|
|
// FXBUG when the main thread ends, it doesn't actually die, it stays around to manage the lifetime
|
|
|
|
// of the CLR, but in doing so it also keeps alive the thread local storage for this thread and we
|
|
|
|
// use the TLS as a hack to track when the thread dies (if the object stored in the TLS is finalized,
|
2005-02-16 14:20:43 +03:00
|
|
|
// we know the thread is dead). So to make that work for the main thread, we use jniDetach which
|
|
|
|
// explicitly cleans up our thread.
|
|
|
|
IKVM.Internal.JVM.Library.jniDetach();
|
2004-09-27 14:17:34 +04:00
|
|
|
}
|
2004-09-15 17:35:44 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
|
|
|
public sealed class Util
|
|
|
|
{
|
|
|
|
private Util()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public static object GetClassFromObject(object o)
|
|
|
|
{
|
|
|
|
Type t = o.GetType();
|
|
|
|
if(t.IsPrimitive || (ClassLoaderWrapper.IsRemappedType(t) && !t.IsSealed))
|
|
|
|
{
|
2004-12-21 17:59:29 +03:00
|
|
|
return DotNetTypeWrapper.GetWrapperFromDotNetType(t).ClassObject;
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
2004-12-21 17:59:29 +03:00
|
|
|
return ClassLoaderWrapper.GetWrapperFromType(t).ClassObject;
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
public static object GetClassFromTypeHandle(RuntimeTypeHandle handle)
|
|
|
|
{
|
|
|
|
Type t = Type.GetTypeFromHandle(handle);
|
|
|
|
if(t.IsPrimitive || ClassLoaderWrapper.IsRemappedType(t))
|
|
|
|
{
|
2004-12-21 17:59:29 +03:00
|
|
|
return DotNetTypeWrapper.GetWrapperFromDotNetType(t).ClassObject;
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
2004-12-21 17:59:29 +03:00
|
|
|
return ClassLoaderWrapper.GetWrapperFromType(t).ClassObject;
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
2004-11-16 14:11:53 +03:00
|
|
|
|
|
|
|
private static FieldWrapper GetFieldWrapperFromField(object field)
|
|
|
|
{
|
|
|
|
if(field == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException("field");
|
|
|
|
}
|
|
|
|
if(field.GetType().FullName != "java.lang.reflect.Field")
|
|
|
|
{
|
|
|
|
throw new ArgumentException("field");
|
|
|
|
}
|
2004-12-07 12:53:28 +03:00
|
|
|
return (FieldWrapper)IKVM.Internal.JVM.Library.getWrapperFromField(field);
|
2004-11-16 14:11:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
public static object GetFieldConstantValue(object field)
|
|
|
|
{
|
|
|
|
return GetFieldWrapperFromField(field).GetConstant();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool IsFieldDeprecated(object field)
|
|
|
|
{
|
|
|
|
FieldInfo fi = GetFieldWrapperFromField(field).GetField();
|
|
|
|
return fi != null && fi.IsDefined(typeof(ObsoleteAttribute), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool IsMethodDeprecated(object method)
|
|
|
|
{
|
|
|
|
if(method == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException("method");
|
|
|
|
}
|
|
|
|
if(method.GetType().FullName != "java.lang.reflect.Method")
|
|
|
|
{
|
|
|
|
throw new ArgumentException("method");
|
|
|
|
}
|
2004-12-07 12:53:28 +03:00
|
|
|
MethodWrapper mw = (MethodWrapper)IKVM.Internal.JVM.Library.getWrapperFromMethodOrConstructor(method);
|
2004-11-16 14:11:53 +03:00
|
|
|
MethodBase mb = mw.GetMethod();
|
|
|
|
return mb != null && mb.IsDefined(typeof(ObsoleteAttribute), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool IsConstructorDeprecated(object constructor)
|
|
|
|
{
|
|
|
|
if(constructor == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException("constructor");
|
|
|
|
}
|
|
|
|
if(constructor.GetType().FullName != "java.lang.reflect.Constructor")
|
|
|
|
{
|
|
|
|
throw new ArgumentException("constructor");
|
|
|
|
}
|
2004-12-07 12:53:28 +03:00
|
|
|
MethodWrapper mw = (MethodWrapper)IKVM.Internal.JVM.Library.getWrapperFromMethodOrConstructor(constructor);
|
2004-11-16 14:11:53 +03:00
|
|
|
MethodBase mb = mw.GetMethod();
|
|
|
|
return mb != null && mb.IsDefined(typeof(ObsoleteAttribute), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool IsClassDeprecated(object clazz)
|
|
|
|
{
|
|
|
|
if(clazz == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException("clazz");
|
|
|
|
}
|
|
|
|
if(clazz.GetType().FullName != "java.lang.Class")
|
|
|
|
{
|
|
|
|
throw new ArgumentException("clazz");
|
|
|
|
}
|
|
|
|
TypeWrapper wrapper = IKVM.NativeCode.java.lang.VMClass.getWrapperFromClass(clazz);
|
|
|
|
return wrapper.TypeAsTBD.IsDefined(typeof(ObsoleteAttribute), false);
|
|
|
|
}
|
2004-11-29 16:58:21 +03:00
|
|
|
|
|
|
|
[HideFromJava]
|
|
|
|
public static Exception MapException(Exception x)
|
|
|
|
{
|
|
|
|
return IKVM.Internal.JVM.Library.mapException(x);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
}
|
2004-09-15 17:35:44 +04:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
namespace IKVM.Internal
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
public class JVM
|
2004-03-26 13:19:21 +03:00
|
|
|
{
|
2005-05-23 12:24:07 +04:00
|
|
|
private static bool debug = System.Diagnostics.Debugger.IsAttached;
|
2004-10-19 17:43:55 +04:00
|
|
|
private static bool noJniStubs;
|
|
|
|
private static bool isStaticCompiler;
|
|
|
|
private static bool noStackTraceInfo;
|
2004-09-09 15:17:55 +04:00
|
|
|
private static bool compilationPhase1;
|
|
|
|
private static string sourcePath;
|
2005-02-23 15:56:15 +03:00
|
|
|
private static bool enableReflectionOnMethodsWithUnloadableTypeParameters;
|
2004-11-29 16:58:21 +03:00
|
|
|
private static ikvm.@internal.LibraryVMInterface lib;
|
|
|
|
|
2005-05-23 12:24:07 +04:00
|
|
|
internal static Version SafeGetAssemblyVersion(Assembly asm)
|
|
|
|
{
|
|
|
|
// Assembly.GetName().Version requires FileIOPermission,
|
|
|
|
// so we parse the FullName manually :-(
|
|
|
|
string name = asm.FullName;
|
|
|
|
int start = name.IndexOf(", Version=");
|
|
|
|
if(start >= 0)
|
|
|
|
{
|
|
|
|
start += 10;
|
|
|
|
int end = name.IndexOf(',', start);
|
|
|
|
if(end >= 0)
|
|
|
|
{
|
|
|
|
return new Version(name.Substring(start, end - start));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new Version();
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static string SafeGetEnvironmentVariable(string name)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
return Environment.GetEnvironmentVariable(name);
|
|
|
|
}
|
|
|
|
catch(SecurityException)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Assembly[] UnsafeGetAssemblies()
|
|
|
|
{
|
|
|
|
new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
|
|
|
|
return AppDomain.CurrentDomain.GetAssemblies();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Type UnsafeGetType(Assembly asm, string name)
|
|
|
|
{
|
|
|
|
new ReflectionPermission(ReflectionPermissionFlag.MemberAccess | ReflectionPermissionFlag.TypeInformation).Assert();
|
|
|
|
return asm.GetType(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static object UnsafeCreateInstance(Type type)
|
|
|
|
{
|
|
|
|
new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
|
|
|
|
return Activator.CreateInstance(type, true);
|
|
|
|
}
|
|
|
|
|
2004-11-29 16:58:21 +03:00
|
|
|
internal static ikvm.@internal.LibraryVMInterface Library
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if(lib == null)
|
|
|
|
{
|
2005-05-23 12:24:07 +04:00
|
|
|
foreach(Assembly asm in UnsafeGetAssemblies())
|
2004-12-21 17:59:29 +03:00
|
|
|
{
|
2005-05-23 12:24:07 +04:00
|
|
|
Type type = UnsafeGetType(asm, "java.lang.LibraryVMInterfaceImpl");
|
2004-12-21 17:59:29 +03:00
|
|
|
if(type != null)
|
|
|
|
{
|
2005-05-23 12:24:07 +04:00
|
|
|
lib = UnsafeCreateInstance(type) as ikvm.@internal.LibraryVMInterface;
|
2005-04-07 15:09:03 +04:00
|
|
|
if(lib == null)
|
|
|
|
{
|
|
|
|
// If the "as" fails, this is most likely due to an IKVM.GNU.Classpath.dll version
|
|
|
|
// that was linked against an incompatible version of IKVM.Runtime.dll.
|
|
|
|
JVM.CriticalFailure("Incompatible core library version", null);
|
|
|
|
}
|
2004-12-21 17:59:29 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(lib == null && !IsStaticCompiler)
|
|
|
|
{
|
|
|
|
JVM.CriticalFailure("Unable to find java.lang.LibraryVMInterfaceImpl", null);
|
|
|
|
}
|
2004-11-29 16:58:21 +03:00
|
|
|
}
|
|
|
|
return lib;
|
|
|
|
}
|
|
|
|
}
|
2004-03-26 13:19:21 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
public static bool Debug
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-09-05 13:37:58 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return debug;
|
2004-09-05 13:37:58 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
set
|
2004-09-05 13:37:58 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
debug = value;
|
2004-09-05 13:37:58 +04:00
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
public static string SourcePath
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-01-11 16:14:42 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return sourcePath;
|
2004-01-11 16:14:42 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
set
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
sourcePath = value;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-29 16:58:21 +03:00
|
|
|
internal static bool NoJniStubs
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return noJniStubs;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-29 16:58:21 +03:00
|
|
|
internal static bool NoStackTraceInfo
|
2004-10-19 17:43:55 +04:00
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return noStackTraceInfo;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-23 15:56:15 +03:00
|
|
|
public static bool EnableReflectionOnMethodsWithUnloadableTypeParameters
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return enableReflectionOnMethodsWithUnloadableTypeParameters;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
enableReflectionOnMethodsWithUnloadableTypeParameters = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static bool DisableDynamicBinding
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return isStaticCompiler;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-29 16:58:21 +03:00
|
|
|
internal static bool IsStaticCompiler
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-01-11 16:14:42 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return isStaticCompiler;
|
2004-01-11 16:14:42 +03:00
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
2004-11-29 16:58:21 +03:00
|
|
|
internal static bool IsStaticCompilerPhase1
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return compilationPhase1;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-11-29 16:58:21 +03:00
|
|
|
internal static bool CompileInnerClassesAsNestedTypes
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// NOTE at the moment, we always do this when compiling statically
|
|
|
|
// note that it makes no sense to turn this on when we're dynamically
|
|
|
|
// running Java code, it only makes sense to turn it off when statically
|
|
|
|
// compiling code that is never used as a library.
|
|
|
|
return IsStaticCompiler;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal static bool IsUnix
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return Environment.OSVersion.ToString().IndexOf("Unix") >= 0;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
|
|
|
|
internal static string MangleResourceName(string name)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// FXBUG there really shouldn't be any need to mangle the resource names,
|
|
|
|
// but in order for ILDASM/ILASM round tripping to work reliably, we have
|
|
|
|
// to make sure that we don't produce resource names that'll cause ILDASM
|
|
|
|
// to generate invalid filenames.
|
2005-02-02 18:11:26 +03:00
|
|
|
StringBuilder sb = new StringBuilder("ikvm__", name.Length + 6);
|
2004-09-09 15:17:55 +04:00
|
|
|
foreach(char c in name)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+.()$#@~=&{}[]0123456789`".IndexOf(c) != -1)
|
|
|
|
{
|
|
|
|
sb.Append(c);
|
|
|
|
}
|
|
|
|
else if(c == '/')
|
|
|
|
{
|
|
|
|
sb.Append('!');
|
|
|
|
}
|
|
|
|
else
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
sb.Append('%');
|
|
|
|
sb.Append(string.Format("{0:X4}", (int)c));
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
return sb.ToString();
|
|
|
|
}
|
2005-05-30 19:30:13 +04:00
|
|
|
#if !NO_STATIC_COMPILER
|
2004-09-09 15:17:55 +04:00
|
|
|
private class CompilerClassLoader : ClassLoaderWrapper
|
|
|
|
{
|
|
|
|
private Hashtable classes;
|
|
|
|
private Hashtable remapped = new Hashtable();
|
|
|
|
private string assemblyName;
|
|
|
|
private string assemblyFile;
|
|
|
|
private string assemblyDir;
|
|
|
|
private string keyfilename;
|
2005-01-07 12:34:19 +03:00
|
|
|
private string keycontainer;
|
2004-09-09 15:17:55 +04:00
|
|
|
private string version;
|
|
|
|
private bool targetIsModule;
|
|
|
|
private AssemblyBuilder assemblyBuilder;
|
2005-04-27 10:10:01 +04:00
|
|
|
private IKVM.Internal.MapXml.Attribute[] assemblyAttributes;
|
2004-09-09 15:17:55 +04:00
|
|
|
|
2005-01-07 12:34:19 +03:00
|
|
|
internal CompilerClassLoader(string path, string keyfilename, string keycontainer, string version, bool targetIsModule, string assemblyName, Hashtable classes)
|
2004-09-09 15:17:55 +04:00
|
|
|
: base(null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
this.classes = classes;
|
|
|
|
this.assemblyName = assemblyName;
|
|
|
|
FileInfo assemblyPath = new FileInfo(path);
|
|
|
|
this.assemblyFile = assemblyPath.Name;
|
|
|
|
this.assemblyDir = assemblyPath.DirectoryName;
|
|
|
|
this.targetIsModule = targetIsModule;
|
|
|
|
this.version = version;
|
|
|
|
this.keyfilename = keyfilename;
|
2005-01-07 12:34:19 +03:00
|
|
|
this.keycontainer = keycontainer;
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Info(Tracer.Compiler, "Instantiate CompilerClassLoader for {0}", assemblyName);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2005-05-30 19:30:13 +04:00
|
|
|
protected override TypeWrapper CreateDynamicTypeWrapper(ClassFile f, ClassLoaderWrapper loader, object protectionDomain)
|
|
|
|
{
|
|
|
|
return new AotTypeWrapper(f, loader);
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
protected override ModuleBuilder CreateModuleBuilder()
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
AssemblyName name = new AssemblyName();
|
|
|
|
name.Name = assemblyName;
|
|
|
|
if(keyfilename != null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
using(FileStream stream = File.Open(keyfilename, FileMode.Open))
|
|
|
|
{
|
|
|
|
name.KeyPair = new StrongNameKeyPair(stream);
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2005-01-07 12:34:19 +03:00
|
|
|
if(keycontainer != null)
|
|
|
|
{
|
|
|
|
name.KeyPair = new StrongNameKeyPair(keycontainer);
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
name.Version = new Version(version);
|
|
|
|
assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave, assemblyDir);
|
|
|
|
ModuleBuilder moduleBuilder;
|
|
|
|
moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName, assemblyFile, JVM.Debug);
|
|
|
|
CustomAttributeBuilder ikvmModuleAttr = new CustomAttributeBuilder(typeof(JavaModuleAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
|
|
|
|
moduleBuilder.SetCustomAttribute(ikvmModuleAttr);
|
2004-10-19 17:43:55 +04:00
|
|
|
CustomAttributeBuilder debugAttr = new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[] { typeof(bool), typeof(bool) }), new object[] { true, JVM.Debug });
|
|
|
|
assemblyBuilder.SetCustomAttribute(debugAttr);
|
2004-09-09 15:17:55 +04:00
|
|
|
return moduleBuilder;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override TypeWrapper GetTypeWrapperCompilerHook(string name)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
TypeWrapper type = base.GetTypeWrapperCompilerHook(name);
|
|
|
|
if(type == null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
type = (TypeWrapper)remapped[name];
|
|
|
|
if(type != null)
|
|
|
|
{
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
ClassFile f = (ClassFile)classes[name];
|
|
|
|
if(f != null)
|
|
|
|
{
|
|
|
|
// to enhance error reporting we special case loading of netexp
|
|
|
|
// classes, to handle the case where the ikvmstub type doesn't exist
|
|
|
|
// (this happens when the .NET mscorlib.jar is used on Mono, for example)
|
|
|
|
string netexp = f.IKVMAssemblyAttribute;
|
|
|
|
if(netexp != null)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Assembly.Load(netexp);
|
|
|
|
}
|
|
|
|
catch(Exception)
|
|
|
|
{
|
2005-04-27 10:10:01 +04:00
|
|
|
Console.Error.WriteLine("ikvmstub assembly not found: {0}", netexp);
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
// HACK create a new wrapper to see if the type is visible now
|
|
|
|
if(DotNetTypeWrapper.CreateDotNetTypeWrapper(name) == null)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2004-12-21 17:59:29 +03:00
|
|
|
type = DefineClass(f, null);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2004-10-19 17:43:55 +04:00
|
|
|
internal void SetMain(MethodInfo m, PEFileKinds target, Hashtable props, bool noglobbing, Type apartmentAttributeType)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
2004-09-27 14:17:34 +04:00
|
|
|
Type[] args = Type.EmptyTypes;
|
|
|
|
if(noglobbing)
|
|
|
|
{
|
|
|
|
args = new Type[] { typeof(string[]) };
|
|
|
|
}
|
2004-11-08 13:01:39 +03:00
|
|
|
MethodBuilder mainStub = this.ModuleBuilder.DefineGlobalMethod("main", MethodAttributes.Public | MethodAttributes.Static, typeof(int), args);
|
2004-09-27 14:17:34 +04:00
|
|
|
if(apartmentAttributeType != null)
|
2004-09-15 17:35:44 +04:00
|
|
|
{
|
2004-09-27 14:17:34 +04:00
|
|
|
mainStub.SetCustomAttribute(new CustomAttributeBuilder(apartmentAttributeType.GetConstructor(Type.EmptyTypes), new object[0]));
|
|
|
|
}
|
|
|
|
ILGenerator ilgen = mainStub.GetILGenerator();
|
2004-11-08 13:01:39 +03:00
|
|
|
LocalBuilder rc = ilgen.DeclareLocal(typeof(int));
|
2004-09-27 14:17:34 +04:00
|
|
|
if(props.Count > 0)
|
|
|
|
{
|
2004-10-19 17:43:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Newobj, typeof(Hashtable).GetConstructor(Type.EmptyTypes));
|
2004-09-27 14:17:34 +04:00
|
|
|
foreach(DictionaryEntry de in props)
|
2004-09-15 17:35:44 +04:00
|
|
|
{
|
2004-09-27 14:17:34 +04:00
|
|
|
ilgen.Emit(OpCodes.Dup);
|
|
|
|
ilgen.Emit(OpCodes.Ldstr, (string)de.Key);
|
|
|
|
ilgen.Emit(OpCodes.Ldstr, (string)de.Value);
|
2004-10-19 17:43:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Callvirt, typeof(Hashtable).GetMethod("Add"));
|
2004-09-15 17:35:44 +04:00
|
|
|
}
|
2004-09-27 14:17:34 +04:00
|
|
|
ilgen.Emit(OpCodes.Call, typeof(IKVM.Runtime.Startup).GetMethod("SetProperties"));
|
|
|
|
}
|
|
|
|
ilgen.BeginExceptionBlock();
|
|
|
|
ilgen.Emit(OpCodes.Call, typeof(IKVM.Runtime.Startup).GetMethod("EnterMainThread"));
|
|
|
|
if(noglobbing)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
2004-09-15 17:35:44 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-09-27 14:17:34 +04:00
|
|
|
ilgen.Emit(OpCodes.Call, typeof(IKVM.Runtime.Startup).GetMethod("Glob", Type.EmptyTypes));
|
2004-09-15 17:35:44 +04:00
|
|
|
}
|
2004-09-27 14:17:34 +04:00
|
|
|
ilgen.Emit(OpCodes.Call, m);
|
|
|
|
ilgen.BeginCatchBlock(typeof(Exception));
|
2004-11-29 16:58:21 +03:00
|
|
|
ilgen.Emit(OpCodes.Call, typeof(IKVM.Runtime.Util).GetMethod("MapException", new Type[] { typeof(Exception) }));
|
2004-09-27 14:17:34 +04:00
|
|
|
LocalBuilder exceptionLocal = ilgen.DeclareLocal(typeof(Exception));
|
|
|
|
ilgen.Emit(OpCodes.Stloc, exceptionLocal);
|
|
|
|
TypeWrapper threadTypeWrapper = ClassLoaderWrapper.LoadClassCritical("java.lang.Thread");
|
|
|
|
LocalBuilder threadLocal = ilgen.DeclareLocal(threadTypeWrapper.TypeAsLocalOrStackType);
|
2005-01-03 11:26:21 +03:00
|
|
|
threadTypeWrapper.GetMethodWrapper("currentThread", "()Ljava.lang.Thread;", false).EmitCall(ilgen);
|
2004-09-27 14:17:34 +04:00
|
|
|
ilgen.Emit(OpCodes.Stloc, threadLocal);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, threadLocal);
|
2005-01-03 11:26:21 +03:00
|
|
|
threadTypeWrapper.GetMethodWrapper("getThreadGroup", "()Ljava.lang.ThreadGroup;", false).EmitCallvirt(ilgen);
|
2004-09-27 14:17:34 +04:00
|
|
|
ilgen.Emit(OpCodes.Ldloc, threadLocal);
|
|
|
|
ilgen.Emit(OpCodes.Ldloc, exceptionLocal);
|
2005-01-03 11:26:21 +03:00
|
|
|
ClassLoaderWrapper.LoadClassCritical("java.lang.ThreadGroup").GetMethodWrapper("uncaughtException", "(Ljava.lang.Thread;Ljava.lang.Throwable;)V", false).EmitCall(ilgen);
|
2004-11-08 13:01:39 +03:00
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_1);
|
|
|
|
ilgen.Emit(OpCodes.Stloc, rc);
|
2004-09-27 14:17:34 +04:00
|
|
|
ilgen.BeginFinallyBlock();
|
|
|
|
ilgen.Emit(OpCodes.Call, typeof(IKVM.Runtime.Startup).GetMethod("ExitMainThread", Type.EmptyTypes));
|
|
|
|
ilgen.EndExceptionBlock();
|
2004-11-08 13:01:39 +03:00
|
|
|
ilgen.Emit(OpCodes.Ldloc, rc);
|
2004-09-27 14:17:34 +04:00
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
assemblyBuilder.SetEntryPoint(mainStub, target);
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void Save()
|
|
|
|
{
|
|
|
|
Tracer.Info(Tracer.Compiler, "CompilerClassLoader.Save...");
|
|
|
|
FinishAll();
|
|
|
|
|
2004-09-15 17:35:44 +04:00
|
|
|
ModuleBuilder.CreateGlobalFunctions();
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
if(targetIsModule)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Info(Tracer.Compiler, "CompilerClassLoader saving temp.$$$ in {0}", assemblyDir);
|
|
|
|
string manifestAssembly = "temp.$$$";
|
|
|
|
assemblyBuilder.Save(manifestAssembly);
|
|
|
|
File.Delete(assemblyDir + manifestAssembly);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Info(Tracer.Compiler, "CompilerClassLoader saving {0} in {1}", assemblyFile, assemblyDir);
|
|
|
|
assemblyBuilder.Save(assemblyFile);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2005-05-23 12:24:07 +04:00
|
|
|
internal void AddResources(Hashtable resources, bool compressedResources)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
|
|
|
Tracer.Info(Tracer.Compiler, "CompilerClassLoader adding resources...");
|
|
|
|
ModuleBuilder moduleBuilder = this.ModuleBuilder;
|
|
|
|
foreach(DictionaryEntry d in resources)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
byte[] buf = (byte[])d.Value;
|
|
|
|
if(buf.Length > 0)
|
|
|
|
{
|
|
|
|
IResourceWriter writer = moduleBuilder.DefineResource(JVM.MangleResourceName((string)d.Key), "");
|
2005-05-23 12:24:07 +04:00
|
|
|
writer.AddResource(compressedResources ? "lz" : "ikvm", buf);
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04: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;
|
2004-03-20 16:25:08 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
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;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
private class RemapperTypeWrapper : TypeWrapper
|
|
|
|
{
|
|
|
|
private TypeBuilder typeBuilder;
|
|
|
|
private TypeBuilder helperTypeBuilder;
|
|
|
|
private Type shadowType;
|
|
|
|
private IKVM.Internal.MapXml.Class classDef;
|
|
|
|
private TypeWrapper[] interfaceWrappers;
|
2004-08-17 13:05:21 +04:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override Assembly Assembly
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return typeBuilder.Assembly;
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override bool IsRemapped
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return true;
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
private static TypeWrapper GetBaseWrapper(IKVM.Internal.MapXml.Class c)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if((c.Modifiers & IKVM.Internal.MapXml.MapModifiers.Interface) != 0)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if(c.Name == "java.lang.Object")
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
2004-11-29 12:48:01 +03:00
|
|
|
return CoreClasses.java.lang.Object.Wrapper;
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal RemapperTypeWrapper(CompilerClassLoader classLoader, IKVM.Internal.MapXml.Class c, IKVM.Internal.MapXml.Root map)
|
2004-12-21 17:59:29 +03:00
|
|
|
: base((Modifiers)c.Modifiers, c.Name, GetBaseWrapper(c), classLoader, null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
classDef = c;
|
|
|
|
bool baseIsSealed = false;
|
|
|
|
shadowType = Type.GetType(c.Shadows, true);
|
|
|
|
classLoader.SetRemappedType(shadowType, this);
|
|
|
|
Type baseType = shadowType;
|
|
|
|
Type baseInterface = null;
|
|
|
|
if(baseType.IsInterface)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
baseInterface = baseType;
|
|
|
|
}
|
|
|
|
TypeAttributes attrs = TypeAttributes.Public;
|
|
|
|
if((c.Modifiers & IKVM.Internal.MapXml.MapModifiers.Interface) == 0)
|
|
|
|
{
|
|
|
|
attrs |= TypeAttributes.Class;
|
|
|
|
if(baseType.IsSealed)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
baseIsSealed = true;
|
|
|
|
// FXBUG .NET framework bug
|
|
|
|
// ideally we would make the type sealed and abstract,
|
|
|
|
// but Reflection.Emit incorrectly prohibits that
|
|
|
|
// (the ECMA spec explicitly mentions this is valid)
|
|
|
|
// attrs |= TypeAttributes.Abstract | TypeAttributes.Sealed;
|
|
|
|
attrs |= TypeAttributes.Abstract;
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04: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('/', '.');
|
|
|
|
typeBuilder = classLoader.ModuleBuilder.DefineType(name, attrs, baseIsSealed ? typeof(object) : baseType);
|
2005-05-23 12:24:07 +04:00
|
|
|
if(c.Attributes != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Attribute custattr in c.Attributes)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(typeBuilder, custattr);
|
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
if(baseInterface != null)
|
|
|
|
{
|
|
|
|
typeBuilder.AddInterfaceImplementation(baseInterface);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
if(!JVM.NoStackTraceInfo)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetSourceFile(typeBuilder, IKVM.Internal.MapXml.Root.filename);
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
if(baseIsSealed)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetModifiers(typeBuilder, (Modifiers)c.Modifiers);
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04: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
|
|
|
|
ConstructorInfo remappedClassAttribute = typeof(RemappedClassAttribute).GetConstructor(new Type[] { typeof(string), typeof(Type) });
|
|
|
|
classLoader.assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(remappedClassAttribute, new object[] { name, shadowType }));
|
|
|
|
|
|
|
|
ConstructorInfo remappedTypeAttribute = typeof(RemappedTypeAttribute).GetConstructor(new Type[] { typeof(Type) });
|
|
|
|
typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(remappedTypeAttribute, new object[] { shadowType }));
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
// HACK because of the above FXBUG that prevents us from making the type both abstract and sealed,
|
|
|
|
// we need to emit a private constructor (otherwise reflection will automatically generate a public
|
|
|
|
// default constructor, another lame feature)
|
|
|
|
if(baseIsSealed)
|
|
|
|
{
|
|
|
|
ConstructorBuilder cb = typeBuilder.DefineConstructor(MethodAttributes.Private, CallingConventions.Standard, Type.EmptyTypes);
|
|
|
|
ILGenerator ilgen = cb.GetILGenerator();
|
|
|
|
// lazyman's way to create a type-safe bogus constructor
|
|
|
|
ilgen.Emit(OpCodes.Ldnull);
|
|
|
|
ilgen.Emit(OpCodes.Throw);
|
|
|
|
}
|
|
|
|
|
2005-01-03 11:26:21 +03:00
|
|
|
ArrayList methods = new ArrayList();
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
if(c.Constructors != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Constructor m in c.Constructors)
|
|
|
|
{
|
2005-01-03 11:26:21 +03:00
|
|
|
methods.Add(new RemappedConstructorWrapper(this, m));
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(c.Methods != null)
|
|
|
|
{
|
|
|
|
// TODO we should also add methods from our super classes (e.g. Throwable should have Object's methods)
|
|
|
|
foreach(IKVM.Internal.MapXml.Method m in c.Methods)
|
|
|
|
{
|
2005-01-03 11:26:21 +03:00
|
|
|
methods.Add(new RemappedMethodWrapper(this, m, map));
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
}
|
2005-01-03 11:26:21 +03:00
|
|
|
|
|
|
|
SetMethods((MethodWrapper[])methods.ToArray(typeof(MethodWrapper)));
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
abstract class RemappedMethodBaseWrapper : MethodWrapper
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2005-01-03 11:26:21 +03:00
|
|
|
internal RemappedMethodBaseWrapper(RemapperTypeWrapper typeWrapper, string name, string sig, Modifiers modifiers)
|
|
|
|
: base(typeWrapper, name, sig, null, null, null, modifiers, MemberFlags.None)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
|
|
|
|
internal abstract MethodBase DoLink();
|
|
|
|
|
|
|
|
internal abstract void Finish();
|
|
|
|
|
|
|
|
internal static void AddDeclaredExceptions(MethodBase mb, IKVM.Internal.MapXml.Throws[] throws)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +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);
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
sealed class RemappedConstructorWrapper : RemappedMethodBaseWrapper
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
private IKVM.Internal.MapXml.Constructor m;
|
|
|
|
private MethodBuilder mbHelper;
|
2004-08-17 13:05:21 +04:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal RemappedConstructorWrapper(RemapperTypeWrapper typeWrapper, IKVM.Internal.MapXml.Constructor m)
|
2005-01-03 11:26:21 +03:00
|
|
|
: base(typeWrapper, "<init>", m.Sig, (Modifiers)m.Modifiers)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
|
|
|
this.m = m;
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override void EmitCall(ILGenerator ilgen)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Call, (ConstructorInfo)GetMethod());
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
|
|
|
|
internal override void EmitNewobj(ILGenerator ilgen)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(mbHelper != null)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Call, mbHelper);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Newobj, (ConstructorInfo)GetMethod());
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override MethodBase DoLink()
|
|
|
|
{
|
|
|
|
MethodAttributes attr = MapMethodAccessModifiers(m.Modifiers);
|
|
|
|
RemapperTypeWrapper typeWrapper = (RemapperTypeWrapper)DeclaringType;
|
|
|
|
Type[] paramTypes = typeWrapper.GetClassLoader().ArgTypeListFromSig(m.Sig);
|
2004-08-17 13:05:21 +04:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
ConstructorBuilder cbCore = null;
|
2004-08-17 13:05:21 +04:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
if(typeWrapper.shadowType.IsSealed)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
mbHelper = typeWrapper.typeBuilder.DefineMethod("newhelper", attr | MethodAttributes.Static, CallingConventions.Standard, typeWrapper.shadowType, paramTypes);
|
2005-05-23 12:24:07 +04:00
|
|
|
if(m.Attributes != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Attribute custattr in m.Attributes)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(mbHelper, custattr);
|
|
|
|
}
|
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
SetParameters(mbHelper, m.Params);
|
2004-09-09 15:17:55 +04:00
|
|
|
AttributeHelper.SetModifiers(mbHelper, (Modifiers)m.Modifiers);
|
|
|
|
AttributeHelper.SetNameSig(mbHelper, "<init>", m.Sig);
|
|
|
|
AddDeclaredExceptions(mbHelper, m.throws);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
cbCore = typeWrapper.typeBuilder.DefineConstructor(attr, CallingConventions.Standard, paramTypes);
|
2005-05-23 12:24:07 +04:00
|
|
|
if(m.Attributes != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Attribute custattr in m.Attributes)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(cbCore, custattr);
|
|
|
|
}
|
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
SetParameters(cbCore, m.Params);
|
2004-09-09 15:17:55 +04:00
|
|
|
AddDeclaredExceptions(cbCore, m.throws);
|
|
|
|
}
|
|
|
|
return cbCore;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override void Finish()
|
|
|
|
{
|
|
|
|
// TODO we should insert method tracing (if enabled)
|
|
|
|
|
|
|
|
Type[] paramTypes = this.GetParametersForDefineMethod();
|
|
|
|
|
|
|
|
ConstructorBuilder cbCore = GetMethod() as ConstructorBuilder;
|
|
|
|
|
|
|
|
if(cbCore != null)
|
|
|
|
{
|
|
|
|
ILGenerator ilgen = cbCore.GetILGenerator();
|
|
|
|
// TODO we need to support ghost (and other funky?) parameter types
|
|
|
|
if(m.body != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// TODO do we need return type conversion here?
|
|
|
|
m.body.Emit(ilgen);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
for(int i = 0; i < paramTypes.Length; i++)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)(i + 1));
|
|
|
|
}
|
|
|
|
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);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ret);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
ilgen.EmitLineNumberTable(cbCore);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
if(mbHelper != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ILGenerator ilgen = mbHelper.GetILGenerator();
|
|
|
|
if(m.redirect != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(m.redirect.Type != "static" || m.redirect.Class == null || m.redirect.Name == null || m.redirect.Sig == null)
|
|
|
|
{
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
Type[] redirParamTypes = ClassLoaderWrapper.GetBootstrapClassLoader().ArgTypeListFromSig(m.redirect.Sig);
|
|
|
|
for(int i = 0; i < redirParamTypes.Length; i++)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)i);
|
|
|
|
}
|
|
|
|
// HACK if the class name contains a comma, we assume it is a .NET type
|
|
|
|
if(m.redirect.Class.IndexOf(',') >= 0)
|
|
|
|
{
|
|
|
|
Type type = Type.GetType(m.redirect.Class, true);
|
|
|
|
MethodInfo mi = type.GetMethod(m.redirect.Name, redirParamTypes);
|
|
|
|
if(mi == null)
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
ilgen.Emit(OpCodes.Call, mi);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TypeWrapper tw = ClassLoaderWrapper.LoadClassCritical(m.redirect.Class);
|
2005-01-03 11:26:21 +03:00
|
|
|
MethodWrapper mw = tw.GetMethodWrapper(m.redirect.Name, m.redirect.Sig, false);
|
2004-09-09 15:17:55 +04:00
|
|
|
if(mw == null)
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
mw.Link();
|
|
|
|
mw.EmitCall(ilgen);
|
|
|
|
}
|
|
|
|
// TODO we may need a cast here (or a stack to return type conversion)
|
|
|
|
ilgen.Emit(OpCodes.Ret);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else if(m.alternateBody != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
m.alternateBody.Emit(ilgen);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else if(m.body != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// <body> doesn't make sense for helper constructors (which are actually factory methods)
|
|
|
|
throw new InvalidOperationException();
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ConstructorInfo baseCon = DeclaringType.TypeAsTBD.GetConstructor(paramTypes);
|
|
|
|
if(baseCon == null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// TODO better error handling
|
|
|
|
throw new InvalidOperationException("constructor not found: " + DeclaringType.Name + ".<init>" + m.Sig);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
for(int i = 0; i < paramTypes.Length; i++)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)i);
|
|
|
|
}
|
|
|
|
ilgen.Emit(OpCodes.Newobj, baseCon);
|
|
|
|
ilgen.Emit(OpCodes.Ret);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
ilgen.EmitLineNumberTable(mbHelper);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
sealed class RemappedMethodWrapper : RemappedMethodBaseWrapper
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
private IKVM.Internal.MapXml.Method m;
|
|
|
|
private IKVM.Internal.MapXml.Root map;
|
|
|
|
private MethodBuilder mbHelper;
|
|
|
|
private ArrayList overriders = new ArrayList();
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal RemappedMethodWrapper(RemapperTypeWrapper typeWrapper, IKVM.Internal.MapXml.Method m, IKVM.Internal.MapXml.Root map)
|
2005-01-03 11:26:21 +03:00
|
|
|
: base(typeWrapper, m.Name, m.Sig, (Modifiers)m.Modifiers)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
this.m = m;
|
|
|
|
this.map = map;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
|
|
|
|
internal override void EmitCall(ILGenerator ilgen)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Call, (MethodInfo)GetMethod());
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override void EmitCallvirt(ILGenerator ilgen)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(mbHelper != null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Call, mbHelper);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Callvirt, (MethodInfo)GetMethod());
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
internal override MethodBase DoLink()
|
|
|
|
{
|
|
|
|
RemapperTypeWrapper typeWrapper = (RemapperTypeWrapper)DeclaringType;
|
|
|
|
|
|
|
|
if(typeWrapper.IsInterface)
|
2004-07-10 11:19:42 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(m.@override == null)
|
2004-07-10 11:19:42 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
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(m.throws != null)
|
|
|
|
{
|
|
|
|
// TODO we need a place to stick the declared exceptions
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
// 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
|
|
|
|
ArrayList specialCases = null;
|
2005-04-27 10:10:01 +04:00
|
|
|
foreach(IKVM.Internal.MapXml.Class c in map.assembly.Classes)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
|
|
|
if(c.Methods != null)
|
2004-07-10 11:19:42 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
foreach(IKVM.Internal.MapXml.Method mm in c.Methods)
|
2004-07-10 11:19:42 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(mm.Name == m.Name && mm.Sig == m.Sig && mm.body != null)
|
2004-07-10 11:19:42 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(specialCases == null)
|
|
|
|
{
|
|
|
|
specialCases = new ArrayList();
|
|
|
|
}
|
|
|
|
specialCases.Add(c);
|
|
|
|
break;
|
2004-07-10 11:19:42 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
CustomAttributeBuilder cab = new CustomAttributeBuilder(typeof(RemappedInterfaceMethodAttribute).GetConstructor(new Type[] { typeof(string), typeof(string) }), new object[] { m.Name, m.@override.Name } );
|
|
|
|
typeWrapper.typeBuilder.SetCustomAttribute(cab);
|
|
|
|
MethodBuilder helper = null;
|
|
|
|
if(specialCases != null)
|
2004-07-10 11:19:42 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04: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)
|
|
|
|
{
|
|
|
|
// FXBUG we use a nested helper class, because Reflection.Emit won't allow us to add a static method to the interface
|
|
|
|
typeWrapper.helperTypeBuilder = typeWrapper.typeBuilder.DefineNestedType("__Helper", TypeAttributes.NestedPublic | TypeAttributes.Class);
|
2004-11-04 15:50:28 +03:00
|
|
|
AttributeHelper.HideFromJava(typeWrapper.helperTypeBuilder);
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2005-02-02 18:11:26 +03:00
|
|
|
helper = typeWrapper.helperTypeBuilder.DefineMethod(m.Name, MethodAttributes.Public | MethodAttributes.Static, typeWrapper.GetClassLoader().RetTypeWrapperFromSig(m.Sig).TypeAsSignatureType, argTypes);
|
2005-05-23 12:24:07 +04:00
|
|
|
if(m.Attributes != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Attribute custattr in m.Attributes)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(helper, custattr);
|
|
|
|
}
|
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
SetParameters(helper, m.Params);
|
2004-09-09 15:17:55 +04:00
|
|
|
ILGenerator ilgen = helper.GetILGenerator();
|
|
|
|
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);
|
|
|
|
Label label = ilgen.DefineLabel();
|
|
|
|
ilgen.Emit(OpCodes.Brfalse_S, label);
|
|
|
|
for(int i = 1; i < argTypes.Length; i++)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)i);
|
|
|
|
}
|
2005-01-03 11:26:21 +03:00
|
|
|
MethodWrapper mw = tw.GetMethodWrapper(m.Name, m.Sig, false);
|
2004-09-09 15:17:55 +04:00
|
|
|
mw.Link();
|
|
|
|
mw.EmitCallvirt(ilgen);
|
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
ilgen.MarkLabel(label);
|
|
|
|
ilgen.Emit(OpCodes.Pop);
|
|
|
|
}
|
|
|
|
for(int i = 0; i < argTypes.Length; i++)
|
2004-07-10 11:19:42 +04:00
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)i);
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Callvirt, interfaceMethod);
|
2004-07-10 11:19:42 +04:00
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
mbHelper = helper;
|
|
|
|
return interfaceMethod;
|
2004-07-10 11:19:42 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
MethodBuilder mbCore = null;
|
|
|
|
Type[] paramTypes = typeWrapper.GetClassLoader().ArgTypeListFromSig(m.Sig);
|
2005-02-02 18:11:26 +03:00
|
|
|
Type retType = typeWrapper.GetClassLoader().RetTypeWrapperFromSig(m.Sig).TypeAsSignatureType;
|
2004-09-09 15:17:55 +04:00
|
|
|
|
|
|
|
if(typeWrapper.shadowType.IsSealed && (m.Modifiers & IKVM.Internal.MapXml.MapModifiers.Static) == 0)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// 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)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2005-01-03 11:26:21 +03:00
|
|
|
RemappedMethodWrapper baseMethod = typeWrapper.BaseTypeWrapper.GetMethodWrapper(m.Name, m.Sig, true) as RemappedMethodWrapper;
|
2004-09-09 15:17:55 +04:00
|
|
|
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);
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
MethodInfo overrideMethod = null;
|
|
|
|
MethodAttributes attr = MapMethodAccessModifiers(m.Modifiers);
|
|
|
|
if((m.Modifiers & IKVM.Internal.MapXml.MapModifiers.Static) != 0)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
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;
|
|
|
|
if(typeWrapper.BaseTypeWrapper != null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2005-01-03 11:26:21 +03:00
|
|
|
RemappedMethodWrapper baseMethod = typeWrapper.BaseTypeWrapper.GetMethodWrapper(m.Name, m.Sig, true) as RemappedMethodWrapper;
|
2004-09-09 15:17:55 +04:00
|
|
|
if(baseMethod != null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
baseMethod.overriders.Add(typeWrapper);
|
|
|
|
if(baseMethod.m.@override != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
overrideMethod = typeWrapper.BaseTypeWrapper.TypeAsTBD.GetMethod(baseMethod.m.@override.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null);
|
|
|
|
if(overrideMethod == null)
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
mbCore = typeWrapper.typeBuilder.DefineMethod(m.Name, attr, CallingConventions.Standard, retType, paramTypes);
|
2005-05-23 12:24:07 +04:00
|
|
|
if(m.Attributes != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Attribute custattr in m.Attributes)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(mbCore, custattr);
|
|
|
|
}
|
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
SetParameters(mbCore, m.Params);
|
2004-09-09 15:17:55 +04:00
|
|
|
if(overrideMethod != null)
|
|
|
|
{
|
|
|
|
typeWrapper.typeBuilder.DefineMethodOverride(mbCore, overrideMethod);
|
|
|
|
}
|
|
|
|
AddDeclaredExceptions(mbCore, m.throws);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
if((m.Modifiers & IKVM.Internal.MapXml.MapModifiers.Static) == 0)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// instance methods must have an instancehelper method
|
|
|
|
MethodAttributes attr = MapMethodAccessModifiers(m.Modifiers) | MethodAttributes.Static;
|
|
|
|
// NOTE instancehelpers for protected methods are made public,
|
|
|
|
// because cli.System.Object derived types can call protected methods
|
|
|
|
if((m.Modifiers & IKVM.Internal.MapXml.MapModifiers.Protected) != 0)
|
|
|
|
{
|
|
|
|
attr &= ~MethodAttributes.MemberAccessMask;
|
|
|
|
attr |= MethodAttributes.Public;
|
|
|
|
// mark with specialname, so that tools (hopefully) won't show them
|
|
|
|
attr |= MethodAttributes.SpecialName;
|
|
|
|
}
|
|
|
|
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);
|
2005-05-23 12:24:07 +04:00
|
|
|
if(m.Attributes != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Attribute custattr in m.Attributes)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(mbHelper, custattr);
|
|
|
|
}
|
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
IKVM.Internal.MapXml.Param[] parameters;
|
|
|
|
if(m.Params == null)
|
2004-11-16 14:11:53 +03:00
|
|
|
{
|
2005-05-24 15:54:20 +04:00
|
|
|
parameters = new IKVM.Internal.MapXml.Param[1];
|
2004-11-16 14:11:53 +03:00
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
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";
|
|
|
|
SetParameters(mbHelper, parameters);
|
|
|
|
if(!typeWrapper.IsFinal)
|
2005-02-23 15:56:15 +03:00
|
|
|
{
|
2005-05-24 15:54:20 +04:00
|
|
|
AttributeHelper.SetEditorBrowsableNever(mbHelper);
|
2005-02-23 15:56:15 +03:00
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
AttributeHelper.SetModifiers(mbHelper, (Modifiers)m.Modifiers);
|
|
|
|
AttributeHelper.SetNameSig(mbHelper, m.Name, m.Sig);
|
|
|
|
AddDeclaredExceptions(mbHelper, m.throws);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
return mbCore;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override void Finish()
|
|
|
|
{
|
|
|
|
// TODO we should insert method tracing (if enabled)
|
|
|
|
Type[] paramTypes = this.GetParametersForDefineMethod();
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
MethodBuilder mbCore = GetMethod() as MethodBuilder;
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
// NOTE sealed types don't have instance methods (only instancehelpers)
|
|
|
|
if(mbCore != null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ILGenerator ilgen = mbCore.GetILGenerator();
|
|
|
|
MethodInfo baseMethod = null;
|
|
|
|
if(m.@override != null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
baseMethod = DeclaringType.TypeAsTBD.GetMethod(m.@override.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null);
|
|
|
|
if(baseMethod == null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
throw new InvalidOperationException();
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
((TypeBuilder)DeclaringType.TypeAsBaseType).DefineMethodOverride(mbCore, baseMethod);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
// TODO we need to support ghost (and other funky?) parameter types
|
|
|
|
if(m.body != null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// we manually walk the instruction list, because we need to special case the ret instructions
|
|
|
|
Hashtable context = new Hashtable();
|
|
|
|
foreach(IKVM.Internal.MapXml.Instruction instr in m.body.invoke)
|
|
|
|
{
|
|
|
|
if(instr is IKVM.Internal.MapXml.Ret)
|
|
|
|
{
|
2005-02-02 18:11:26 +03:00
|
|
|
this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null);
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
instr.Generate(context, ilgen);
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-10-19 17:43:55 +04:00
|
|
|
if(m.redirect != null && m.redirect.LineNumber != -1)
|
|
|
|
{
|
|
|
|
ilgen.SetLineNumber((ushort)m.redirect.LineNumber);
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
int thisOffset = 0;
|
|
|
|
if((m.Modifiers & IKVM.Internal.MapXml.MapModifiers.Static) == 0)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
thisOffset = 1;
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
for(int i = 0; i < paramTypes.Length; i++)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)(i + thisOffset));
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
2005-02-02 18:11:26 +03:00
|
|
|
this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null);
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ret);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
ilgen.EmitLineNumberTable(mbCore);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
// NOTE static methods don't have helpers
|
|
|
|
if(mbHelper != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ILGenerator ilgen = mbHelper.GetILGenerator();
|
|
|
|
// check "this" for null
|
|
|
|
if(m.@override != null && m.redirect == null && m.body == null && m.alternateBody == null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// we're going to be calling the overridden version, so we don't need the null check
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
EmitHelper.NullCheck(ilgen);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04: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)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// TODO we should have a way to supress this for overridden methods
|
2004-03-08 18:18:47 +03:00
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Isinst, DeclaringType.TypeAsBaseType);
|
2004-03-08 18:18:47 +03:00
|
|
|
ilgen.Emit(OpCodes.Dup);
|
|
|
|
Label skip = ilgen.DefineLabel();
|
|
|
|
ilgen.Emit(OpCodes.Brfalse_S, skip);
|
|
|
|
for(int i = 0; i < paramTypes.Length; i++)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)(i + 1));
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Callvirt, mbCore);
|
2005-02-02 18:11:26 +03:00
|
|
|
this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null);
|
2004-03-08 18:18:47 +03:00
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
ilgen.MarkLabel(skip);
|
|
|
|
ilgen.Emit(OpCodes.Pop);
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
foreach(RemapperTypeWrapper overrider in overriders)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2005-01-03 11:26:21 +03:00
|
|
|
RemappedMethodWrapper mw = (RemappedMethodWrapper)overrider.GetMethodWrapper(Name, Signature, false);
|
2004-09-09 15:17:55 +04:00
|
|
|
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
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
ilgen.Emit(OpCodes.Isinst, overrider.TypeAsTBD);
|
|
|
|
ilgen.Emit(OpCodes.Dup);
|
|
|
|
Label skip = ilgen.DefineLabel();
|
|
|
|
ilgen.Emit(OpCodes.Brfalse_S, skip);
|
|
|
|
for(int i = 0; i < paramTypes.Length; i++)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)(i + 1));
|
|
|
|
}
|
|
|
|
mw.Link();
|
|
|
|
mw.EmitCallvirt(ilgen);
|
2005-02-02 18:11:26 +03:00
|
|
|
this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null);
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
ilgen.MarkLabel(skip);
|
|
|
|
ilgen.Emit(OpCodes.Pop);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
if(m.body != null || m.alternateBody != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
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
|
|
|
|
Hashtable context = new Hashtable();
|
|
|
|
foreach(IKVM.Internal.MapXml.Instruction instr in body.invoke)
|
|
|
|
{
|
|
|
|
if(instr is IKVM.Internal.MapXml.Ret)
|
|
|
|
{
|
2005-02-02 18:11:26 +03:00
|
|
|
this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null);
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
instr.Generate(context, ilgen);
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-10-19 17:43:55 +04:00
|
|
|
if(m.redirect != null && m.redirect.LineNumber != -1)
|
|
|
|
{
|
|
|
|
ilgen.SetLineNumber((ushort)m.redirect.LineNumber);
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
Type shadowType = ((RemapperTypeWrapper)DeclaringType).shadowType;
|
|
|
|
for(int i = 0; i < paramTypes.Length + 1; i++)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)i);
|
|
|
|
}
|
|
|
|
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);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else
|
|
|
|
{
|
2005-01-03 11:26:21 +03:00
|
|
|
RemappedMethodWrapper baseMethod = DeclaringType.BaseTypeWrapper.GetMethodWrapper(Name, Signature, true) as RemappedMethodWrapper;
|
2004-09-09 15:17:55 +04:00
|
|
|
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);
|
|
|
|
}
|
2005-02-02 18:11:26 +03:00
|
|
|
this.ReturnType.EmitConvStackTypeToSignatureType(ilgen, null);
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
ilgen.EmitLineNumberTable(mbHelper);
|
2004-09-09 15:17:55 +04: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];
|
2005-02-02 18:11:26 +03:00
|
|
|
argTypes[0] = typeWrapper.TypeAsSignatureType;
|
2004-09-09 15:17:55 +04:00
|
|
|
this.GetParametersForDefineMethod().CopyTo(argTypes, 1);
|
|
|
|
MethodBuilder mb = typeWrapper.typeBuilder.DefineMethod("nonvirtualhelper/" + this.Name, MethodAttributes.Private | MethodAttributes.Static, this.ReturnTypeForDefineMethod, argTypes);
|
2005-05-23 12:24:07 +04:00
|
|
|
if(m.Attributes != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Attribute custattr in m.Attributes)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(mb, custattr);
|
|
|
|
}
|
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
SetParameters(mb, m.Params);
|
2004-10-19 17:43:55 +04:00
|
|
|
AttributeHelper.HideFromJava(mb);
|
2004-09-09 15:17:55 +04:00
|
|
|
ILGenerator ilgen = mb.GetILGenerator();
|
|
|
|
if(m.nonvirtualAlternateBody != null)
|
|
|
|
{
|
|
|
|
m.nonvirtualAlternateBody.Emit(ilgen);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Type shadowType = ((RemapperTypeWrapper)DeclaringType).shadowType;
|
|
|
|
MethodInfo baseMethod = shadowType.GetMethod(m.@override.Name, BindingFlags.Instance | BindingFlags.Public, null, paramTypes, null);
|
|
|
|
if(baseMethod == null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
throw new InvalidOperationException(DeclaringType.Name + "." + m.Name + m.Sig);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
for(int i = 0; i < paramTypes.Length; i++)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ldarg, (short)(i + 1));
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Call, baseMethod);
|
|
|
|
ilgen.Emit(OpCodes.Ret);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
private void EmitRedirect(Type baseType, ILGenerator ilgen)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
string redirName = m.redirect.Name;
|
|
|
|
string redirSig = m.redirect.Sig;
|
|
|
|
if(redirName == null)
|
|
|
|
{
|
|
|
|
redirName = m.Name;
|
|
|
|
}
|
|
|
|
if(redirSig == null)
|
|
|
|
{
|
|
|
|
redirSig = m.Sig;
|
|
|
|
}
|
|
|
|
ClassLoaderWrapper classLoader = ClassLoaderWrapper.GetBootstrapClassLoader();
|
|
|
|
// 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)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// TODO better error handling
|
|
|
|
Type type = m.redirect.Class == null ? baseType : Type.GetType(m.redirect.Class, true);
|
|
|
|
Type[] redirParamTypes = classLoader.ArgTypeListFromSig(redirSig);
|
|
|
|
MethodInfo mi = type.GetMethod(m.redirect.Name, redirParamTypes);
|
|
|
|
if(mi == null)
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
ilgen.Emit(OpCodes.Call, mi);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
TypeWrapper tw = ClassLoaderWrapper.LoadClassCritical(m.redirect.Class);
|
2005-01-03 11:26:21 +03:00
|
|
|
MethodWrapper mw = tw.GetMethodWrapper(redirName, redirSig, false);
|
2004-09-09 15:17:55 +04:00
|
|
|
if(mw == null)
|
|
|
|
{
|
2005-01-03 11:26:21 +03:00
|
|
|
throw new InvalidOperationException("Missing redirect method: " + tw.Name + "." + redirName + redirSig);
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
mw.Link();
|
|
|
|
mw.EmitCall(ilgen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-24 15:54:20 +04:00
|
|
|
private static void SetParameters(MethodBuilder mb, IKVM.Internal.MapXml.Param[] parameters)
|
|
|
|
{
|
|
|
|
if(parameters != null)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < parameters.Length; i++)
|
|
|
|
{
|
2005-05-26 12:05:47 +04:00
|
|
|
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++)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(pb, parameters[i].Attributes[j]);
|
|
|
|
}
|
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void SetParameters(ConstructorBuilder cb, IKVM.Internal.MapXml.Param[] parameters)
|
|
|
|
{
|
|
|
|
if(parameters != null)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < parameters.Length; i++)
|
|
|
|
{
|
2005-05-26 12:05:47 +04:00
|
|
|
ParameterBuilder pb = cb.DefineParameter(i + 1, ParameterAttributes.None, parameters[i].Name);
|
|
|
|
if(parameters[i].Attributes != null)
|
|
|
|
{
|
|
|
|
for(int j = 0; j < parameters[i].Attributes.Length; j++)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(pb, parameters[i].Attributes[j]);
|
|
|
|
}
|
|
|
|
}
|
2005-05-24 15:54:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal void Process2ndPass(IKVM.Internal.MapXml.Root map)
|
|
|
|
{
|
|
|
|
IKVM.Internal.MapXml.Class c = classDef;
|
|
|
|
TypeBuilder tb = typeBuilder;
|
|
|
|
bool baseIsSealed = shadowType.IsSealed;
|
|
|
|
|
|
|
|
if(c.Interfaces != null)
|
|
|
|
{
|
|
|
|
interfaceWrappers = new TypeWrapper[c.Interfaces.Length];
|
|
|
|
for(int i = 0; i < c.Interfaces.Length; i++)
|
|
|
|
{
|
|
|
|
TypeWrapper ifaceTypeWrapper = ClassLoaderWrapper.LoadClassCritical(c.Interfaces[i].Name);
|
|
|
|
interfaceWrappers[i] = ifaceTypeWrapper;
|
|
|
|
if(!baseIsSealed)
|
|
|
|
{
|
|
|
|
tb.AddInterfaceImplementation(ifaceTypeWrapper.TypeAsBaseType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AttributeHelper.SetImplementsAttribute(tb, interfaceWrappers);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
interfaceWrappers = TypeWrapper.EmptyArray;
|
|
|
|
}
|
|
|
|
|
2005-01-03 11:26:21 +03:00
|
|
|
ArrayList fields = new ArrayList();
|
|
|
|
|
2004-09-09 15:17:55 +04: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)
|
|
|
|
{
|
|
|
|
if(f.redirect != null)
|
|
|
|
{
|
|
|
|
TypeWrapper tw = ClassLoaderWrapper.LoadClassCritical(f.redirect.Class);
|
2005-01-03 11:26:21 +03:00
|
|
|
MethodWrapper method = tw.GetMethodWrapper(f.redirect.Name, f.redirect.Sig, false);
|
2004-09-09 15:17:55 +04:00
|
|
|
if(method == null || !method.IsStatic)
|
|
|
|
{
|
|
|
|
// TODO better error handling
|
|
|
|
throw new InvalidOperationException("remapping field: " + f.Name + f.Sig + " not found");
|
|
|
|
}
|
|
|
|
// TODO emit an static helper method that enables access to the field at runtime
|
|
|
|
method.Link();
|
2005-01-03 11:26:21 +03:00
|
|
|
fields.Add(new GetterFieldWrapper(this, GetClassLoader().FieldTypeWrapperFromSig(f.Sig), null, f.Name, f.Sig, (Modifiers)f.Modifiers, (MethodInfo)method.GetMethod()));
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
else if((f.Modifiers & IKVM.Internal.MapXml.MapModifiers.Static) != 0)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
FieldAttributes attr = MapFieldAccessModifiers(f.Modifiers) | FieldAttributes.Static;
|
|
|
|
if(f.Constant != null)
|
|
|
|
{
|
|
|
|
attr |= FieldAttributes.Literal;
|
|
|
|
}
|
|
|
|
else if((f.Modifiers & IKVM.Internal.MapXml.MapModifiers.Final) != 0)
|
|
|
|
{
|
|
|
|
attr |= FieldAttributes.InitOnly;
|
|
|
|
}
|
2005-02-02 18:11:26 +03:00
|
|
|
FieldBuilder fb = tb.DefineField(f.Name, GetClassLoader().FieldTypeWrapperFromSig(f.Sig).TypeAsSignatureType, attr);
|
2005-05-23 12:24:07 +04:00
|
|
|
if(f.Attributes != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Attribute custattr in f.Attributes)
|
|
|
|
{
|
|
|
|
AttributeHelper.SetCustomAttribute(fb, custattr);
|
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04: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);
|
2005-01-03 11:26:21 +03:00
|
|
|
fields.Add(new ConstantFieldWrapper(this, GetClassLoader().FieldTypeWrapperFromSig(f.Sig), f.Name, f.Sig, (Modifiers)f.Modifiers, fb, constant));
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-01-03 11:26:21 +03:00
|
|
|
fields.Add(FieldWrapper.Create(this, GetClassLoader().FieldTypeWrapperFromSig(f.Sig), fb, f.Name, f.Sig, (Modifiers)f.Modifiers));
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// TODO we should support adding arbitrary instance fields (the runtime will have to use
|
|
|
|
// a weak identity hashtable to store the extra information for subclasses that don't extend our stub)
|
|
|
|
throw new NotImplementedException(this.Name + "." + f.Name + f.Sig);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
2005-01-03 11:26:21 +03:00
|
|
|
SetFields((FieldWrapper[])fields.ToArray(typeof(FieldWrapper)));
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal void Process3rdPass()
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
foreach(RemappedMethodBaseWrapper m in GetMethods())
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
m.Link();
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
|
2004-10-19 17:43:55 +04:00
|
|
|
internal void Process4thPass(ICollection remappedTypes)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
|
|
|
foreach(RemappedMethodBaseWrapper m in GetMethods())
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
m.Finish();
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
|
|
|
|
if(classDef.Clinit != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ConstructorBuilder cb = typeBuilder.DefineTypeInitializer();
|
|
|
|
ILGenerator ilgen = cb.GetILGenerator();
|
|
|
|
// TODO emit code to make sure super class is initialized
|
|
|
|
classDef.Clinit.body.Emit(ilgen);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04: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)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
foreach(IKVM.Internal.MapXml.Interface iface in classDef.Interfaces)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
GetClassLoader().LoadClassByDottedName(iface.Name).Finish();
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
|
2004-10-19 17:43:55 +04:00
|
|
|
CreateShadowInstanceOf(remappedTypes);
|
|
|
|
CreateShadowCheckCast(remappedTypes);
|
|
|
|
|
2004-11-23 20:46:39 +03:00
|
|
|
if(!shadowType.IsInterface)
|
|
|
|
{
|
2005-05-31 13:47:14 +04:00
|
|
|
// For all inherited methods, we emit a method that hides the inherited method and
|
2004-11-23 20:46:39 +03:00
|
|
|
// annotate it with EditorBrowsableAttribute(EditorBrowsableState.Never) to make
|
|
|
|
// sure the inherited methods don't show up in Intellisense.
|
2005-05-23 12:24:07 +04:00
|
|
|
// TODO if the original method has a LinkDemand, we should copy that
|
2004-11-23 20:46:39 +03:00
|
|
|
Hashtable methods = new Hashtable();
|
2005-05-23 12:24:07 +04:00
|
|
|
foreach(MethodInfo mi in typeBuilder.BaseType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy))
|
2004-11-23 20:46:39 +03:00
|
|
|
{
|
2005-02-02 18:11:26 +03:00
|
|
|
string key = MakeMethodKey(mi);
|
|
|
|
if(!methods.ContainsKey(key))
|
2004-11-23 20:46:39 +03:00
|
|
|
{
|
2005-02-02 18:11:26 +03:00
|
|
|
ParameterInfo[] paramInfo = mi.GetParameters();
|
|
|
|
Type[] paramTypes = new Type[paramInfo.Length];
|
|
|
|
for(int i = 0; i < paramInfo.Length; i++)
|
|
|
|
{
|
|
|
|
paramTypes[i] = paramInfo[i].ParameterType;
|
|
|
|
}
|
2005-05-31 13:47:14 +04:00
|
|
|
MethodBuilder mb = typeBuilder.DefineMethod(mi.Name, mi.Attributes & (MethodAttributes.MemberAccessMask | MethodAttributes.SpecialName | MethodAttributes.Static), mi.ReturnType, paramTypes);
|
2005-02-02 18:11:26 +03:00
|
|
|
AttributeHelper.HideFromJava(mb);
|
|
|
|
AttributeHelper.SetEditorBrowsableNever(mb);
|
|
|
|
ILGenerator ilgen = mb.GetILGenerator();
|
|
|
|
for(int i = 0; i < paramTypes.Length; i++)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_S, (byte)i);
|
|
|
|
}
|
|
|
|
if(!mi.IsStatic)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_S, (byte)paramTypes.Length);
|
|
|
|
}
|
|
|
|
ilgen.Emit(OpCodes.Call, mi);
|
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
methods[key] = mb;
|
2004-11-23 20:46:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
2005-05-31 13:47:14 +04:00
|
|
|
PropertyBuilder pb = typeBuilder.DefineProperty(pi.Name, PropertyAttributes.None, pi.PropertyType, paramTypes);
|
2004-11-23 20:46:39 +03:00
|
|
|
if(pi.CanRead)
|
|
|
|
{
|
2005-02-02 18:11:26 +03:00
|
|
|
pb.SetGetMethod((MethodBuilder)methods[MakeMethodKey(pi.GetGetMethod())]);
|
2004-11-23 20:46:39 +03:00
|
|
|
}
|
|
|
|
if(pi.CanWrite)
|
|
|
|
{
|
2005-02-02 18:11:26 +03:00
|
|
|
pb.SetSetMethod((MethodBuilder)methods[MakeMethodKey(pi.GetSetMethod())]);
|
2004-11-23 20:46:39 +03:00
|
|
|
}
|
|
|
|
AttributeHelper.SetEditorBrowsableNever(pb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
typeBuilder.CreateType();
|
|
|
|
if(helperTypeBuilder != null)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
helperTypeBuilder.CreateType();
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
}
|
2005-02-02 18:11:26 +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();
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-10-19 17:43:55 +04:00
|
|
|
private void CreateShadowInstanceOf(ICollection remappedTypes)
|
|
|
|
{
|
|
|
|
// FXBUG .NET 1.1 doesn't allow static methods on interfaces
|
|
|
|
if(typeBuilder.IsInterface)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
MethodAttributes attr = MethodAttributes.SpecialName | MethodAttributes.Public | MethodAttributes.Static;
|
2004-11-23 20:46:39 +03:00
|
|
|
MethodBuilder mb = typeBuilder.DefineMethod("__<instanceof>", attr, typeof(bool), new Type[] { typeof(object) });
|
2004-10-19 17:43:55 +04:00
|
|
|
AttributeHelper.HideFromJava(mb);
|
2004-11-23 20:46:39 +03:00
|
|
|
AttributeHelper.SetEditorBrowsableNever(mb);
|
2004-10-19 17:43:55 +04:00
|
|
|
ILGenerator ilgen = mb.GetILGenerator();
|
|
|
|
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
ilgen.Emit(OpCodes.Isinst, shadowType);
|
|
|
|
Label retFalse = ilgen.DefineLabel();
|
|
|
|
ilgen.Emit(OpCodes.Brfalse_S, retFalse);
|
|
|
|
|
|
|
|
if(!shadowType.IsSealed)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
ilgen.Emit(OpCodes.Isinst, typeBuilder);
|
|
|
|
ilgen.Emit(OpCodes.Brtrue_S, retFalse);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(shadowType == typeof(object))
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
ilgen.Emit(OpCodes.Isinst, typeof(Array));
|
|
|
|
ilgen.Emit(OpCodes.Brtrue_S, retFalse);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach(RemapperTypeWrapper r in remappedTypes)
|
|
|
|
{
|
|
|
|
if(!r.shadowType.IsInterface && r.shadowType.IsSubclassOf(shadowType))
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
ilgen.Emit(OpCodes.Isinst, r.shadowType);
|
|
|
|
ilgen.Emit(OpCodes.Brtrue_S, retFalse);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_1);
|
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
|
|
|
|
ilgen.MarkLabel(retFalse);
|
|
|
|
ilgen.Emit(OpCodes.Ldc_I4_0);
|
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void CreateShadowCheckCast(ICollection remappedTypes)
|
|
|
|
{
|
|
|
|
// FXBUG .NET 1.1 doesn't allow static methods on interfaces
|
|
|
|
if(typeBuilder.IsInterface)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
MethodAttributes attr = MethodAttributes.SpecialName | MethodAttributes.Public | MethodAttributes.Static;
|
2004-11-23 20:46:39 +03:00
|
|
|
MethodBuilder mb = typeBuilder.DefineMethod("__<checkcast>", attr, shadowType, new Type[] { typeof(object) });
|
2004-10-19 17:43:55 +04:00
|
|
|
AttributeHelper.HideFromJava(mb);
|
2004-11-23 20:46:39 +03:00
|
|
|
AttributeHelper.SetEditorBrowsableNever(mb);
|
2004-10-19 17:43:55 +04:00
|
|
|
ILGenerator ilgen = mb.GetILGenerator();
|
|
|
|
|
|
|
|
Label fail = ilgen.DefineLabel();
|
|
|
|
bool hasfail = false;
|
|
|
|
|
|
|
|
if(!shadowType.IsSealed)
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
ilgen.Emit(OpCodes.Isinst, typeBuilder);
|
|
|
|
ilgen.Emit(OpCodes.Brtrue_S, fail);
|
|
|
|
hasfail = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(shadowType == typeof(object))
|
|
|
|
{
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
|
|
|
ilgen.Emit(OpCodes.Isinst, typeof(Array));
|
|
|
|
ilgen.Emit(OpCodes.Brtrue_S, fail);
|
|
|
|
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);
|
|
|
|
ilgen.Emit(OpCodes.Brtrue_S, fail);
|
|
|
|
hasfail = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ilgen.Emit(OpCodes.Ldarg_0);
|
2005-02-11 17:46:58 +03:00
|
|
|
EmitHelper.Castclass(ilgen, shadowType);
|
2004-10-19 17:43:55 +04:00
|
|
|
ilgen.Emit(OpCodes.Ret);
|
|
|
|
|
|
|
|
if(hasfail)
|
|
|
|
{
|
|
|
|
ilgen.MarkLabel(fail);
|
|
|
|
ilgen.ThrowException(typeof(InvalidCastException));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override MethodBase LinkMethod(MethodWrapper mw)
|
|
|
|
{
|
|
|
|
return ((RemappedMethodBaseWrapper)mw).DoLink();
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override TypeWrapper DeclaringTypeWrapper
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// at the moment we don't support nested remapped types
|
|
|
|
return null;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
|
|
|
|
internal override void Finish(bool forDebugSave)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override TypeWrapper[] InnerClasses
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return null;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override TypeWrapper[] Interfaces
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
|
|
|
{
|
|
|
|
return interfaceWrappers;
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override Type TypeAsTBD
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
|
|
|
{
|
|
|
|
return shadowType;
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override Type TypeAsBaseType
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
|
|
|
{
|
|
|
|
return typeBuilder;
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override TypeBuilder TypeAsBuilder
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
return typeBuilder;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal override bool IsMapUnsafeException
|
2004-07-10 11:19:42 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
get
|
|
|
|
{
|
|
|
|
// any remapped exceptions are automatically unsafe
|
|
|
|
return shadowType == typeof(Exception) || shadowType.IsSubclassOf(typeof(Exception));
|
|
|
|
}
|
2004-07-10 11:19:42 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal void EmitRemappedTypes(IKVM.Internal.MapXml.Root map)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Info(Tracer.Compiler, "Emit remapped types");
|
2004-08-17 13:05:21 +04:00
|
|
|
|
2005-04-27 10:10:01 +04:00
|
|
|
assemblyAttributes = map.assembly.Attributes;
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
// 1st pass, put all types in remapped to make them loadable
|
2005-04-15 11:54:31 +04:00
|
|
|
bool hasRemappedTypes = false;
|
2005-04-27 10:10:01 +04:00
|
|
|
foreach(IKVM.Internal.MapXml.Class c in map.assembly.Classes)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(c.Shadows != null)
|
|
|
|
{
|
|
|
|
remapped.Add(c.Name, new RemapperTypeWrapper(this, c, map));
|
2005-04-15 11:54:31 +04:00
|
|
|
hasRemappedTypes = true;
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
|
2005-04-15 11:54:31 +04:00
|
|
|
if(hasRemappedTypes)
|
|
|
|
{
|
2005-05-30 19:30:13 +04:00
|
|
|
AotTypeWrapper.SetupGhosts(map);
|
2005-04-15 11:54:31 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
// 2nd pass, resolve interfaces, publish methods/fields
|
2005-04-27 10:10:01 +04:00
|
|
|
foreach(IKVM.Internal.MapXml.Class c in map.assembly.Classes)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(c.Shadows != null)
|
|
|
|
{
|
|
|
|
RemapperTypeWrapper typeWrapper = (RemapperTypeWrapper)remapped[c.Name];
|
|
|
|
typeWrapper.Process2ndPass(map);
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal void FinishRemappedTypes()
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// 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)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
typeWrapper.Process3rdPass();
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
// 4th pass, implement methods/fields and bake the type
|
|
|
|
foreach(RemapperTypeWrapper typeWrapper in remapped.Values)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-10-19 17:43:55 +04:00
|
|
|
typeWrapper.Process4thPass(remapped.Values);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2005-04-27 10:10:01 +04:00
|
|
|
|
|
|
|
if(assemblyAttributes != null)
|
|
|
|
{
|
|
|
|
foreach(IKVM.Internal.MapXml.Attribute attr in assemblyAttributes)
|
|
|
|
{
|
2005-05-23 12:24:07 +04:00
|
|
|
AttributeHelper.SetCustomAttribute(((AssemblyBuilder)this.ModuleBuilder.Assembly), attr);
|
2005-04-27 10:10:01 +04:00
|
|
|
}
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
public class CompilerOptions
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
public string path;
|
|
|
|
public string keyfilename;
|
2005-01-07 12:34:19 +03:00
|
|
|
public string keycontainer;
|
2005-01-05 15:11:50 +03:00
|
|
|
public string version;
|
|
|
|
public bool targetIsModule;
|
|
|
|
public string assembly;
|
|
|
|
public string mainClass;
|
|
|
|
public ApartmentState apartment;
|
|
|
|
public PEFileKinds target;
|
|
|
|
public bool guessFileKind;
|
|
|
|
public byte[][] classes;
|
|
|
|
public string[] references;
|
|
|
|
public bool nojni;
|
|
|
|
public Hashtable resources;
|
|
|
|
public string[] classesToExclude;
|
|
|
|
public string remapfile;
|
|
|
|
public Hashtable props;
|
|
|
|
public bool noglobbing;
|
|
|
|
public bool nostacktraceinfo;
|
|
|
|
public bool removeUnusedFields;
|
2005-05-23 12:24:07 +04:00
|
|
|
public bool compressedResources;
|
2005-01-05 15:11:50 +03:00
|
|
|
}
|
|
|
|
|
2005-04-15 11:54:31 +04:00
|
|
|
private static bool IsSigned(Assembly asm)
|
|
|
|
{
|
|
|
|
return asm.GetName().GetPublicKey().Length != 0;
|
|
|
|
}
|
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
public static int Compile(CompilerOptions options)
|
|
|
|
{
|
|
|
|
Tracer.Info(Tracer.Compiler, "JVM.Compile path: {0}, assembly: {1}", options.path, options.assembly);
|
2004-09-09 15:17:55 +04:00
|
|
|
isStaticCompiler = true;
|
2005-01-05 15:11:50 +03:00
|
|
|
noJniStubs = options.nojni;
|
|
|
|
noStackTraceInfo = options.nostacktraceinfo;
|
2005-05-23 12:24:07 +04:00
|
|
|
Assembly runtimeAssembly = typeof(JVM).Assembly;
|
|
|
|
AssemblyName runtimeAssemblyName = runtimeAssembly.GetName();
|
|
|
|
bool allReferencesAreStrongNamed = IsSigned(runtimeAssembly);
|
2005-01-05 15:11:50 +03:00
|
|
|
foreach(string r in options.references)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
try
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Assembly reference = Assembly.LoadFrom(r);
|
|
|
|
if(reference == null)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: reference not found: {0}", r);
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2005-04-15 11:54:31 +04:00
|
|
|
allReferencesAreStrongNamed &= IsSigned(reference);
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Info(Tracer.Compiler, "Loaded reference assembly: {0}", reference.FullName);
|
2005-05-23 12:24:07 +04:00
|
|
|
// 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())
|
|
|
|
{
|
|
|
|
if(asmref.Name == runtimeAssemblyName.Name)
|
|
|
|
{
|
|
|
|
if(IsSigned(runtimeAssembly))
|
|
|
|
{
|
|
|
|
if(asmref.FullName != runtimeAssemblyName.FullName)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: referenced assembly {0} was compiled with an incompatible IKVM.Runtime version ({1})", r, asmref.Version);
|
|
|
|
Console.Error.WriteLine(" (current runtime is {0})", runtimeAssemblyName.FullName);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(asmref.GetPublicKey() != null && asmref.GetPublicKey().Length != 0)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: referenced assembly {0} was compiled with an incompatible (signed) IKVM.Runtime version", r);
|
|
|
|
Console.Error.WriteLine(" (current runtime is {0})", runtimeAssemblyName.FullName);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
catch(Exception x)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Console.Error.WriteLine("Error: invalid reference: {0} ({1})", r, x.Message);
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
Hashtable h = new Hashtable();
|
|
|
|
Tracer.Info(Tracer.Compiler, "Parsing class files");
|
2005-01-05 15:11:50 +03:00
|
|
|
for(int i = 0; i < options.classes.Length; i++)
|
2004-03-16 20:10:09 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ClassFile f;
|
|
|
|
try
|
2004-03-16 20:10:09 +03:00
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
f = new ClassFile(options.classes[i], 0, options.classes[i].Length, null, true);
|
2004-03-16 20:10:09 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
catch(UnsupportedClassVersionError x)
|
2004-04-23 18:21:43 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Console.Error.WriteLine("Error: unsupported class file version: {0}", x.Message);
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-04-23 18:21:43 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
catch(ClassFormatError x)
|
2004-04-23 18:21:43 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Console.Error.WriteLine("Error: invalid class file: {0}", x.Message);
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-04-23 18:21:43 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
string name = f.Name;
|
|
|
|
bool excluded = false;
|
2005-01-05 15:11:50 +03:00
|
|
|
for(int j = 0; j < options.classesToExclude.Length; j++)
|
2004-02-06 22:09:32 +03:00
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
if(Regex.IsMatch(name, options.classesToExclude[j]))
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
|
|
|
excluded = true;
|
|
|
|
break;
|
|
|
|
}
|
2004-02-06 22:09:32 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
if(h.ContainsKey(name))
|
2003-08-21 14:06:34 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Console.Error.WriteLine("Warning: duplicate class name: {0}", name);
|
2003-08-21 14:06:34 +04:00
|
|
|
excluded = true;
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
if(!excluded)
|
2003-12-20 01:19:18 +03:00
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.removeUnusedFields)
|
|
|
|
{
|
|
|
|
f.RemoveUnusedFields();
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
h[name] = f;
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.mainClass == null && (options.guessFileKind || options.target != PEFileKinds.Dll))
|
2003-12-20 01:19:18 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
foreach(ClassFile.Method m in f.Methods)
|
2003-12-20 01:19:18 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(m.IsPublic && m.IsStatic && m.Name == "main" && m.Signature == "([Ljava.lang.String;)V")
|
|
|
|
{
|
2005-02-23 15:56:15 +03:00
|
|
|
Console.Error.WriteLine("Note: found main method in class \"{0}\"", f.Name);
|
2005-01-05 15:11:50 +03:00
|
|
|
options.mainClass = f.Name;
|
2004-09-09 15:17:55 +04:00
|
|
|
break;
|
|
|
|
}
|
2003-12-20 01:19:18 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-08-21 14:06:34 +04:00
|
|
|
}
|
2003-02-20 17:18:38 +03:00
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.guessFileKind && options.mainClass == null)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
options.target = PEFileKinds.Dll;
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2003-12-20 01:19:18 +03:00
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.target == PEFileKinds.Dll && options.mainClass != null)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: main class cannot be specified for library or module");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2004-02-11 14:37:28 +03:00
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.target != PEFileKinds.Dll && options.mainClass == null)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: no main method found");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2003-12-20 01:19:18 +03:00
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.target == PEFileKinds.Dll && options.props.Count != 0)
|
2004-09-15 17:35:44 +04:00
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: properties cannot be specified for library or module");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-09-15 17:35:44 +04:00
|
|
|
}
|
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.path == null)
|
2004-01-11 16:14:42 +03:00
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.target == PEFileKinds.Dll)
|
2004-01-11 16:14:42 +03:00
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.targetIsModule)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
options.path = options.assembly + ".netmodule";
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
options.path = options.assembly + ".dll";
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2004-01-11 16:14:42 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
options.path = options.assembly + ".exe";
|
2004-01-11 16:14:42 +03:00
|
|
|
}
|
2005-02-23 15:56:15 +03:00
|
|
|
Console.Error.WriteLine("Note: output file is \"{0}\"", options.path);
|
2004-01-11 16:14:42 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.targetIsModule)
|
2004-01-11 16:14:42 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// TODO if we're overwriting a user specified assembly name, we need to emit a warning
|
2005-01-05 15:11:50 +03:00
|
|
|
options.assembly = new FileInfo(options.path).Name;
|
2004-01-11 16:14:42 +03:00
|
|
|
}
|
2003-12-20 01:19:18 +03:00
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.target == PEFileKinds.Dll && !options.path.ToLower().EndsWith(".dll") && !options.targetIsModule)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: library output file must end with .dll");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2003-12-20 01:19:18 +03:00
|
|
|
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.target != PEFileKinds.Dll && !options.path.ToLower().EndsWith(".exe"))
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: executable output file must end with .exe");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
2003-12-20 01:19:18 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
// make sure all inner classes have a reference to their outer class
|
|
|
|
// note that you cannot use the InnerClasses attribute in the inner class for this, because
|
|
|
|
// anonymous inner classes do not have a reference to their outer class
|
|
|
|
foreach(ClassFile classFile in h.Values)
|
2003-02-20 17:18:38 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
// don't handle inner classes for ikvmstub types
|
|
|
|
if(classFile.IKVMAssemblyAttribute == null)
|
2003-02-20 17:18:38 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
ClassFile.InnerClass[] innerClasses = classFile.InnerClasses;
|
|
|
|
if(innerClasses != null)
|
2003-02-20 17:18:38 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
for(int j = 0; j < innerClasses.Length; j++)
|
2003-02-20 17:18:38 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(innerClasses[j].outerClass != 0 && classFile.GetConstantPoolClass(innerClasses[j].outerClass) == classFile.Name)
|
2003-02-20 17:18:38 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
string inner = classFile.GetConstantPoolClass(innerClasses[j].innerClass);
|
|
|
|
ClassFile innerClass = (ClassFile)h[inner];
|
|
|
|
if(innerClass != null)
|
2003-05-30 16:08:59 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(innerClass.OuterClass != null)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: inner class {0} has multiple outer classes", inner);
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
innerClass.OuterClass = classFile;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Warning: inner class {0} missing", inner);
|
2003-05-30 16:08:59 +04:00
|
|
|
}
|
2003-02-20 17:18:38 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Info(Tracer.Compiler, "Constructing compiler");
|
2005-01-07 12:34:19 +03:00
|
|
|
CompilerClassLoader loader = new CompilerClassLoader(options.path, options.keyfilename, options.keycontainer, options.version, options.targetIsModule, options.assembly, h);
|
2004-09-09 15:17:55 +04:00
|
|
|
ClassLoaderWrapper.SetBootstrapClassLoader(loader);
|
|
|
|
compilationPhase1 = true;
|
|
|
|
IKVM.Internal.MapXml.Root map = null;
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.remapfile != null)
|
2002-12-29 19:27:00 +03:00
|
|
|
{
|
2005-01-05 15:11:50 +03:00
|
|
|
Tracer.Info(Tracer.Compiler, "Loading remapped types (1) from {0}", options.remapfile);
|
2004-09-09 15:17:55 +04:00
|
|
|
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(IKVM.Internal.MapXml.Root));
|
|
|
|
ser.UnknownElement += new System.Xml.Serialization.XmlElementEventHandler(ser_UnknownElement);
|
2004-10-19 17:43:55 +04:00
|
|
|
ser.UnknownAttribute += new System.Xml.Serialization.XmlAttributeEventHandler(ser_UnknownAttribute);
|
2005-01-05 15:11:50 +03:00
|
|
|
using(FileStream fs = File.Open(options.remapfile, FileMode.Open))
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-10-19 17:43:55 +04:00
|
|
|
XmlTextReader rdr = new XmlTextReader(fs);
|
|
|
|
IKVM.Internal.MapXml.Root.xmlReader = rdr;
|
|
|
|
IKVM.Internal.MapXml.Root.filename = new FileInfo(fs.Name).Name;
|
|
|
|
map = (IKVM.Internal.MapXml.Root)ser.Deserialize(rdr);
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
loader.EmitRemappedTypes(map);
|
2003-12-20 01:19:18 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
// Do a sanity check to make sure some of the bootstrap classes are available
|
|
|
|
if(loader.LoadClassByDottedNameFast("java.lang.Object") == null)
|
2002-12-29 19:27:00 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Assembly classpath = Assembly.LoadWithPartialName("IKVM.GNU.Classpath");
|
|
|
|
if(classpath == null)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Console.Error.WriteLine("Error: bootstrap classes missing and IKVM.GNU.Classpath.dll not found");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
2005-04-15 11:54:31 +04:00
|
|
|
allReferencesAreStrongNamed &= IsSigned(classpath);
|
2005-02-23 15:56:15 +03:00
|
|
|
Console.Error.WriteLine("Note: automatically adding reference to \"{0}\"", classpath.Location);
|
2004-09-09 15:17:55 +04:00
|
|
|
// we need to scan again for remapped types, now that we've loaded the core library
|
|
|
|
ClassLoaderWrapper.LoadRemappedTypes();
|
|
|
|
}
|
2004-11-23 20:46:39 +03:00
|
|
|
|
2005-04-15 11:54:31 +04:00
|
|
|
if((options.keycontainer != null || options.keyfilename != null) && !allReferencesAreStrongNamed)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: all referenced assemblies must be strong named, to be able to sign the output assembly");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-11-23 20:46:39 +03:00
|
|
|
ClassLoaderWrapper.PublishLibraryImplementationHelperType(typeof(gnu.classpath.RawData));
|
2004-11-29 16:58:21 +03:00
|
|
|
ClassLoaderWrapper.PublishLibraryImplementationHelperType(typeof(ikvm.@internal.LibraryVMInterface));
|
2004-11-23 20:46:39 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Info(Tracer.Compiler, "Compiling class files (1)");
|
|
|
|
ArrayList allwrappers = new ArrayList();
|
|
|
|
foreach(string s in h.Keys)
|
|
|
|
{
|
|
|
|
TypeWrapper wrapper = null;
|
|
|
|
try
|
2004-09-05 13:37:58 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
wrapper = loader.LoadClassByDottedNameFast(s);
|
|
|
|
if(wrapper == null)
|
|
|
|
{
|
|
|
|
// this should only happen for netexp types (because the other classes must exist, after all we just parsed them)
|
2005-02-23 15:56:15 +03:00
|
|
|
ClassFile c = h[s] as ClassFile;
|
|
|
|
if(c == null || c.IKVMAssemblyAttribute == null)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: loading class \"{0}\" failed for unknown reason", s);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
Console.Error.WriteLine("Warning: ikvmstub class \"{0}\" refers to non-existing type", s);
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
allwrappers.Add(wrapper);
|
|
|
|
}
|
2004-09-05 13:37:58 +04:00
|
|
|
}
|
2005-02-23 15:56:15 +03:00
|
|
|
catch(NoClassDefFoundError x)
|
2004-09-05 13:37:58 +04:00
|
|
|
{
|
2005-05-23 12:24:07 +04:00
|
|
|
Console.Error.WriteLine("Warning: unable to compile class \"{0}\"", s);
|
|
|
|
Console.Error.WriteLine(" (missing class \"{0}\")", x.Message);
|
2004-09-05 13:37:58 +04:00
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.mainClass != null)
|
2004-09-09 15:17:55 +04:00
|
|
|
{
|
2005-02-23 15:56:15 +03:00
|
|
|
TypeWrapper wrapper = null;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
wrapper = loader.LoadClassByDottedNameFast(options.mainClass);
|
|
|
|
}
|
|
|
|
catch(NoClassDefFoundError)
|
|
|
|
{
|
|
|
|
}
|
2004-12-08 14:07:21 +03:00
|
|
|
if(wrapper == null)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: main class not found");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-12-08 14:07:21 +03:00
|
|
|
}
|
2005-01-03 11:26:21 +03:00
|
|
|
MethodWrapper mw = wrapper.GetMethodWrapper("main", "([Ljava.lang.String;)V", false);
|
2004-12-08 14:07:21 +03:00
|
|
|
if(mw == null)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: main method not found");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-12-08 14:07:21 +03:00
|
|
|
}
|
|
|
|
mw.Link();
|
|
|
|
MethodInfo method = mw.GetMethod() as MethodInfo;
|
|
|
|
if(method == null)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: redirected main method not supported");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-12-08 14:07:21 +03:00
|
|
|
}
|
|
|
|
if(method.DeclaringType.Assembly != loader.ModuleBuilder.Assembly
|
|
|
|
&& (!method.IsPublic || !method.DeclaringType.IsPublic))
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Error: external main method must be public and in a public class");
|
2004-12-21 13:26:51 +03:00
|
|
|
return 1;
|
2004-12-08 14:07:21 +03:00
|
|
|
}
|
|
|
|
Type apartmentAttributeType = null;
|
2005-01-05 15:11:50 +03:00
|
|
|
if(options.apartment == ApartmentState.STA)
|
2004-12-08 14:07:21 +03:00
|
|
|
{
|
|
|
|
apartmentAttributeType = typeof(STAThreadAttribute);
|
|
|
|
}
|
2005-01-05 15:11:50 +03:00
|
|
|
else if(options.apartment == ApartmentState.MTA)
|
2004-12-08 14:07:21 +03:00
|
|
|
{
|
|
|
|
apartmentAttributeType = typeof(MTAThreadAttribute);
|
|
|
|
}
|
2005-01-05 15:11:50 +03:00
|
|
|
loader.SetMain(method, options.target, options.props, options.noglobbing, apartmentAttributeType);
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
compilationPhase1 = false;
|
|
|
|
if(map != null)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2005-05-30 19:30:13 +04:00
|
|
|
AotTypeWrapper.LoadMappedExceptions(map);
|
2004-09-09 15:17:55 +04:00
|
|
|
// mark all exceptions that are unsafe for mapping with a custom attribute,
|
|
|
|
// so that at runtime we can quickly assertain if an exception type can be
|
|
|
|
// caught without filtering
|
|
|
|
foreach(TypeWrapper tw in allwrappers)
|
2004-03-08 18:18:47 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
if(!tw.IsInterface && tw.IsMapUnsafeException)
|
|
|
|
{
|
|
|
|
tw.TypeAsBuilder.SetCustomAttribute(typeof(ExceptionIsUnsafeForMappingAttribute).GetConstructor(Type.EmptyTypes), new byte[0]);
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2005-05-30 19:30:13 +04:00
|
|
|
AotTypeWrapper.LoadMapXml(map);
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Info(Tracer.Compiler, "Loading remapped types (2)");
|
|
|
|
loader.FinishRemappedTypes();
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Info(Tracer.Compiler, "Compiling class files (2)");
|
2005-05-23 12:24:07 +04:00
|
|
|
loader.AddResources(options.resources, options.compressedResources);
|
2004-09-09 15:17:55 +04:00
|
|
|
loader.Save();
|
2004-12-21 13:26:51 +03:00
|
|
|
return 0;
|
2004-03-08 18:18:47 +03:00
|
|
|
}
|
2005-05-30 19:30:13 +04:00
|
|
|
#endif
|
2004-09-09 15:17:55 +04:00
|
|
|
public static void PrepareForSaveDebugImage()
|
|
|
|
{
|
|
|
|
ClassLoaderWrapper.PrepareForSaveDebugImage();
|
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
public static void SaveDebugImage(object mainClass)
|
|
|
|
{
|
|
|
|
ClassLoaderWrapper.SaveDebugImage(mainClass);
|
|
|
|
}
|
2002-12-27 12:01:16 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
public static void SetBootstrapClassLoader(object classLoader)
|
|
|
|
{
|
|
|
|
ClassLoaderWrapper.GetBootstrapClassLoader().SetJavaClassLoader(classLoader);
|
|
|
|
}
|
2003-12-24 14:51:41 +03:00
|
|
|
|
2004-09-09 15:17:55 +04:00
|
|
|
internal static void CriticalFailure(string message, Exception x)
|
2003-12-24 14:51:41 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
try
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Tracer.Error(Tracer.Runtime, "CRITICAL FAILURE: {0}", message);
|
2005-05-23 12:24:07 +04:00
|
|
|
// NOTE we use reflection to invoke MessageBox.Show, to make sure we run in environments where WinForms isn't available
|
|
|
|
Assembly winForms = IsUnix ? null : Assembly.Load("System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
|
2004-09-09 15:17:55 +04:00
|
|
|
Type messageBox = null;
|
|
|
|
if(winForms != null)
|
|
|
|
{
|
|
|
|
messageBox = winForms.GetType("System.Windows.Forms.MessageBox");
|
|
|
|
}
|
2005-05-23 12:24:07 +04:00
|
|
|
new ReflectionPermission(ReflectionPermissionFlag.MemberAccess | ReflectionPermissionFlag.TypeInformation).Assert();
|
2004-09-09 15:17:55 +04:00
|
|
|
message = String.Format("****** Critical Failure: {1} ******{0}" +
|
|
|
|
"{2}{0}" +
|
|
|
|
"{3}{0}" +
|
|
|
|
"{4}",
|
|
|
|
Environment.NewLine,
|
|
|
|
message,
|
|
|
|
x,
|
|
|
|
x != null ? new StackTrace(x, true).ToString() : "",
|
|
|
|
new StackTrace(true));
|
2005-05-23 12:24:07 +04:00
|
|
|
CodeAccessPermission.RevertAssert();
|
2004-09-09 15:17:55 +04:00
|
|
|
if(messageBox != null)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2005-05-23 12:24:07 +04:00
|
|
|
Version ver = SafeGetAssemblyVersion(typeof(JVM).Assembly);
|
|
|
|
messageBox.InvokeMember("Show", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, null, null, new object[] { message, "IKVM.NET " + ver + " Critical Failure" });
|
2004-09-09 15:17:55 +04:00
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine(message);
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
else
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
|
|
|
Console.Error.WriteLine(message);
|
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
catch(Exception ex)
|
2004-08-17 13:05:21 +04:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Console.Error.WriteLine(ex);
|
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
Environment.Exit(666);
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
}
|
2004-09-09 15:17:55 +04:00
|
|
|
|
|
|
|
private static void ser_UnknownElement(object sender, System.Xml.Serialization.XmlElementEventArgs e)
|
2003-12-24 14:51:41 +03:00
|
|
|
{
|
2004-09-09 15:17:55 +04:00
|
|
|
Console.Error.WriteLine("Unknown element {0} in XML mapping file, line {1}, column {2}", e.Element.Name, e.LineNumber, e.LinePosition);
|
|
|
|
Environment.Exit(1);
|
2003-12-24 14:51:41 +03:00
|
|
|
}
|
2004-10-19 17:43:55 +04:00
|
|
|
|
|
|
|
private static void ser_UnknownAttribute(object sender, System.Xml.Serialization.XmlAttributeEventArgs e)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Unknown attribute {0} in XML mapping file, line {1}, column {2}", e.Attr.Name, e.LineNumber, e.LinePosition);
|
|
|
|
Environment.Exit(1);
|
|
|
|
}
|
2003-12-24 14:51:41 +03:00
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|