ikvm-fork/ikvm/starter.cs

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

2002-12-18 19:00:25 +03:00
/*
2004-03-20 16:25:08 +03:00
Copyright (C) 2002, 2003, 2004 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;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
2004-09-15 17:35:44 +04:00
using System.Collections.Specialized;
2002-12-29 19:27:00 +03:00
using System.Text;
2004-09-09 15:17:55 +04:00
using IKVM.Internal;
2004-09-15 17:35:44 +04:00
using IKVM.Runtime;
2002-12-18 19:00:25 +03:00
using java.lang.reflect;
using java.net;
using java.util.jar;
using java.io;
public class Starter
{
private class Timer
{
private static Timer t;
private DateTime now = DateTime.Now;
internal Timer()
{
t = this;
}
~Timer()
{
Console.WriteLine(DateTime.Now - now);
}
}
2002-12-27 12:01:16 +03:00
public class PathClassLoader : URLClassLoader
{
private static URL[] GetClassPath(string classpath)
{
2003-02-15 20:06:47 +03:00
string[] s = classpath.Split(Path.PathSeparator);
2002-12-27 12:01:16 +03:00
URL[] urls = new URL[s.Length];
for(int i = 0; i < urls.Length; i++)
{
// TODO non-existing file/dir is treated as current directory, this obviously isn't correct
urls[i] = new java.io.File(s[i]).toURL();
}
return urls;
}
public PathClassLoader(string classpath, java.lang.ClassLoader parent)
: base(GetClassPath(classpath), parent)
{
}
protected override java.lang.Class loadClass(string name, bool resolve)
{
java.lang.Class c = findClass(name);
if(resolve)
{
resolveClass(c);
}
return c;
}
}
2003-12-20 01:19:18 +03:00
private class SaveAssemblyShutdownHook : java.lang.Thread
{
private java.lang.Class clazz;
internal SaveAssemblyShutdownHook(java.lang.Class clazz)
2004-09-27 14:17:34 +04:00
: base("SaveAssemblyShutdownHook")
2003-12-20 01:19:18 +03:00
{
this.clazz = clazz;
}
public override void run()
{
2004-08-17 13:05:21 +04:00
System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.AboveNormal;
2003-12-24 14:51:41 +03:00
Console.Error.WriteLine("Saving dynamic assembly...");
try
{
JVM.SaveDebugImage(clazz);
2004-04-23 18:21:43 +04:00
Console.Error.WriteLine("Saving done.");
2003-12-24 14:51:41 +03:00
}
catch(Exception x)
{
Console.Error.WriteLine(x);
2004-03-20 16:25:08 +03:00
Console.Error.WriteLine(new System.Diagnostics.StackTrace(x, true));
2003-12-24 14:51:41 +03:00
System.Diagnostics.Debug.Assert(false, x.ToString());
}
2003-12-20 01:19:18 +03:00
}
}
2004-04-02 12:13:01 +04:00
private class WaitShutdownHook : java.lang.Thread
{
2004-09-27 14:17:34 +04:00
internal WaitShutdownHook()
: base("WaitShutdownHook")
{
}
2004-04-02 12:13:01 +04:00
public override void run()
{
Console.Error.WriteLine("IKVM runtime terminated. Waiting for Ctrl+C...");
for(;;)
{
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
}
}
2002-12-18 19:00:25 +03:00
[STAThread] // NOTE this is here because otherwise SWT's RegisterDragDrop (a COM thing) doesn't work
2004-10-19 17:43:55 +04:00
[IKVM.Attributes.HideFromJava]
2002-12-18 19:00:25 +03:00
static int Main(string[] args)
{
2004-03-08 18:18:47 +03:00
Tracer.EnableTraceForDebug();
2004-10-19 17:43:55 +04:00
Hashtable props = new Hashtable();
2002-12-18 19:00:25 +03:00
bool jar = false;
bool saveAssembly = false;
2004-09-05 13:37:58 +04:00
bool saveAssemblyX = false;
2004-04-02 12:13:01 +04:00
bool waitOnExit = false;
2002-12-18 19:00:25 +03:00
string mainClass = null;
string[] vmargs = null;
2004-08-17 13:05:21 +04:00
string bootclasspath = null;
2002-12-18 19:00:25 +03:00
for(int i = 0; i < args.Length; i++)
{
if(args[i][0] == '-')
{
2003-03-17 17:02:46 +03:00
if(args[i] == "-help" || args[i] == "-?")
2002-12-18 19:00:25 +03:00
{
break;
}
2003-03-17 17:02:46 +03:00
else if(args[i] == "-Xsave")
2002-12-18 19:00:25 +03:00
{
saveAssembly = true;
2003-05-10 15:43:12 +04:00
JVM.PrepareForSaveDebugImage();
2002-12-18 19:00:25 +03:00
}
2004-09-05 13:37:58 +04:00
else if(args[i] == "-XXsave")
{
saveAssemblyX = true;
JVM.PrepareForSaveDebugImage();
}
2003-03-17 17:02:46 +03:00
else if(args[i] == "-Xtime")
2002-12-18 19:00:25 +03:00
{
new Timer();
}
2004-04-02 12:13:01 +04:00
else if(args[i] == "-Xwait")
{
waitOnExit = true;
}
2004-07-10 11:19:42 +04:00
else if(args[i] == "-Xbreak")
{
System.Diagnostics.Debugger.Break();
}
2002-12-18 19:00:25 +03:00
else if(args[i] == "-jar")
{
jar = true;
}
2003-07-21 16:12:40 +04:00
else if(args[i] == "-version")
{
Console.WriteLine("CLR version: {0}", Environment.Version);
foreach(Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
Console.WriteLine("{0}: {1}", asm.GetName().Name, asm.GetName().Version);
}
return 0;
}
2002-12-18 19:00:25 +03:00
else if(args[i].StartsWith("-D"))
{
string[] keyvalue = args[i].Substring(2).Split('=');
if(keyvalue.Length != 2)
{
keyvalue = new string[] { keyvalue[0], "" };
}
2004-09-05 13:37:58 +04:00
props[keyvalue[0]] = keyvalue[1];
2002-12-18 19:00:25 +03:00
}
2004-10-04 23:30:53 +04:00
else if(args[i] == "-ea" || args[i] == "-enableassertions")
{
props["ikvm.assert.default"] = "true";
}
else if(args[i] == "-da" || args[i] == "-disableassertions")
{
props["ikvm.assert.default"] = "false";
}
else if(args[i].StartsWith("-ea:") || args[i].StartsWith("-enableassertions:"))
{
props["ikvm.assert.enable"] = args[i].Substring(args[i].IndexOf(':') + 1);
}
else if(args[i].StartsWith("-da:") || args[i].StartsWith("-disableassertions:"))
{
props["ikvm.assert.disable"] = args[i].Substring(args[i].IndexOf(':') + 1);
}
2002-12-18 19:00:25 +03:00
else if(args[i] == "-cp" || args[i] == "-classpath")
{
2004-09-05 13:37:58 +04:00
props["java.class.path"] = args[++i];
2002-12-18 19:00:25 +03:00
}
2002-12-27 12:01:16 +03:00
else if(args[i].StartsWith("-Xbootclasspath:"))
{
2004-08-17 13:05:21 +04:00
bootclasspath = args[i].Substring(16);
2002-12-27 12:01:16 +03:00
}
2004-03-08 18:18:47 +03:00
else if(args[i].StartsWith("-Xtrace:"))
2003-03-17 17:02:46 +03:00
{
2004-03-08 18:18:47 +03:00
Tracer.SetTraceLevel(args[i].Substring(8));
}
else if(args[i].StartsWith("-Xmethodtrace:"))
{
Tracer.HandleMethodTrace(args[i].Substring(14));
2003-03-17 17:02:46 +03:00
}
2002-12-18 19:00:25 +03:00
else
{
Console.Error.WriteLine("{0}: illegal argument", args[i]);
break;
}
}
else
{
mainClass = args[i];
2004-09-15 17:35:44 +04:00
vmargs = Startup.Glob(i + 2);
2002-12-18 19:00:25 +03:00
break;
}
}
if(mainClass == null)
{
Console.Error.WriteLine("usage: ikvm [-options] <class> [args...]");
Console.Error.WriteLine(" (to execute a class)");
Console.Error.WriteLine(" or ikvm -jar [-options] <jarfile> [args...]");
Console.Error.WriteLine(" (to execute a jar file)");
Console.Error.WriteLine();
Console.Error.WriteLine("where options include:");
2004-09-15 17:35:44 +04:00
Console.Error.WriteLine(" -? -help Display this message");
2004-10-04 23:30:53 +04:00
Console.Error.WriteLine(" -version Display IKVM and runtime version");
2003-03-17 17:02:46 +03:00
Console.Error.WriteLine(" -cp -classpath <directories and zip/jar files separated by {0}>", Path.PathSeparator);
2004-09-15 17:35:44 +04:00
Console.Error.WriteLine(" Set search path for application classes and resources");
Console.Error.WriteLine(" -D<name>=<value> Set a system property");
2004-10-04 23:30:53 +04:00
Console.Error.WriteLine(" -ea[:<packagename>...|:<classname>]");
Console.Error.WriteLine(" -enableassertions[:<packagename>...|:<classname>]");
Console.Error.WriteLine(" Enable assertions.");
Console.Error.WriteLine(" -da[:<packagename>...|:<classname>]");
Console.Error.WriteLine(" -disableassertions[:<packagename>...|:<classname>]");
Console.Error.WriteLine(" Disable assertions");
2004-09-15 17:35:44 +04:00
Console.Error.WriteLine(" -Xsave Save the generated assembly (for debugging)");
Console.Error.WriteLine(" -Xtime Time the execution");
2003-03-17 17:02:46 +03:00
Console.Error.WriteLine(" -Xbootclasspath:<directories and zip/jar files separated by {0}>", Path.PathSeparator);
2004-09-15 17:35:44 +04:00
Console.Error.WriteLine(" Set search path for bootstrap classes and resources");
2004-03-08 18:18:47 +03:00
Console.Error.WriteLine(" -Xtrace:<string> Displays all tracepoints with the given name");
2004-10-04 23:30:53 +04:00
Console.Error.WriteLine(" -Xmethodtrace:<string>");
Console.Error.WriteLine(" Builds method trace into the specified output methods");
2004-04-02 12:13:01 +04:00
Console.Error.WriteLine(" -Xwait Keep process hanging around after exit");
2004-10-04 23:30:53 +04:00
Console.Error.WriteLine(" -Xbreak Trigger a user defined breakpoint at startup");
2002-12-18 19:00:25 +03:00
return 1;
}
try
{
2004-09-27 14:17:34 +04:00
if(jar)
{
props["java.class.path"] = mainClass;
}
2004-09-15 17:35:44 +04:00
Startup.SetProperties(props);
2004-09-27 14:17:34 +04:00
Startup.EnterMainThread();
2002-12-18 19:00:25 +03:00
if(jar)
{
JarFile jf = new JarFile(mainClass);
try
{
2004-11-04 15:50:28 +03:00
mainClass = jf.getManifest().getMainAttributes().getValue(Attributes.Name.MAIN_CLASS).Replace('/', '.');
2002-12-18 19:00:25 +03:00
}
finally
{
jf.close();
}
if(mainClass == null)
{
Console.Error.WriteLine("Manifest doesn't contain a Main-Class.");
return 1;
}
}
2004-08-17 13:05:21 +04:00
if(bootclasspath != null)
2002-12-27 12:01:16 +03:00
{
2004-08-17 13:05:21 +04:00
JVM.SetBootstrapClassLoader(new PathClassLoader(bootclasspath, null));
2002-12-27 12:01:16 +03:00
}
2004-08-17 13:05:21 +04:00
java.lang.Class clazz = java.lang.Class.forName(mainClass, true, java.lang.ClassLoader.getSystemClassLoader());
2003-12-20 01:19:18 +03:00
Method method = FindMainMethod(clazz);
if(method == null)
2003-08-29 14:14:08 +04:00
{
throw new java.lang.NoSuchMethodError("main");
}
2003-12-20 01:19:18 +03:00
else if(!Modifier.isPublic(method.getModifiers()))
{
Console.Error.WriteLine("Main method not public.");
}
else
2002-12-18 19:00:25 +03:00
{
2004-06-17 13:14:51 +04:00
// if clazz isn't public, we can still call main
method.setAccessible(true);
2004-03-16 20:10:09 +03:00
if(saveAssembly)
{
java.lang.Runtime.getRuntime().addShutdownHook(new SaveAssemblyShutdownHook(clazz));
}
2004-04-02 12:13:01 +04:00
if(waitOnExit)
{
java.lang.Runtime.getRuntime().addShutdownHook(new WaitShutdownHook());
}
2002-12-18 19:00:25 +03:00
try
{
method.invoke(null, new object[] { vmargs });
2003-12-20 01:19:18 +03:00
return 0;
2002-12-18 19:00:25 +03:00
}
2003-12-20 01:19:18 +03:00
catch(InvocationTargetException x)
2002-12-18 19:00:25 +03:00
{
2003-12-20 01:19:18 +03:00
throw x.getCause();
2002-12-18 19:00:25 +03:00
}
2004-09-05 13:37:58 +04:00
finally
{
if(saveAssemblyX)
{
JVM.SaveDebugImage(clazz);
}
}
2002-12-18 19:00:25 +03:00
}
}
catch(System.Exception x)
{
java.lang.Thread thread = java.lang.Thread.currentThread();
2004-11-29 16:58:21 +03:00
thread.getThreadGroup().uncaughtException(thread, IKVM.Runtime.Util.MapException(x));
2002-12-18 19:00:25 +03:00
}
2003-12-20 01:19:18 +03:00
finally
{
2004-09-27 14:17:34 +04:00
Startup.ExitMainThread();
2003-12-20 01:19:18 +03:00
}
return 1;
}
private static Method FindMainMethod(java.lang.Class clazz)
{
while(clazz != null)
{
foreach(Method m in clazz.getDeclaredMethods())
{
if(m.getName() == "main" && m.getReturnType() == java.lang.Void.TYPE)
{
java.lang.Class[] parameters = m.getParameterTypes();
if(parameters.Length == 1 && parameters[0] == java.lang.Class.forName("[Ljava.lang.String;"))
{
return m;
}
}
}
clazz = clazz.getSuperclass();
}
return null;
2002-12-18 19:00:25 +03:00
}
}