This commit is contained in:
jfrijters 2003-01-02 13:46:16 +00:00
Родитель c2845d2179
Коммит e13321abc4
10 изменённых файлов: 282 добавлений и 66 удалений

Просмотреть файл

@ -32,6 +32,8 @@ using System.Diagnostics;
class ClassLoaderWrapper
{
private delegate object LoadClassDelegate(object classLoader, string className);
private static LoadClassDelegate loadClassDelegate;
private static bool arrayConstructionHack;
private static ArrayList ikvmAssemblies = new ArrayList();
private static Hashtable assemblyToClassLoaderWrapper = new Hashtable();
@ -42,7 +44,6 @@ class ClassLoaderWrapper
private static Hashtable typeToTypeWrapper = new Hashtable();
private static ClassLoaderWrapper bootstrapClassLoader;
private object javaClassLoader;
private MethodInfo loadClassMethod;
private Hashtable types = new Hashtable();
private Hashtable nativeMethods;
// HACK moduleBuilder is static, because multiple dynamic assemblies is broken (TypeResolve doesn't fire)
@ -117,13 +118,9 @@ class ClassLoaderWrapper
internal void SetJavaClassLoader(object javaClassLoader)
{
this.javaClassLoader = javaClassLoader;
if(javaClassLoader != null)
if(javaClassLoader != null && loadClassDelegate == null)
{
loadClassMethod = javaClassLoader.GetType().GetMethod("loadClass", BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Standard, new Type[] { typeof(string) }, null);
if(loadClassMethod == null)
{
throw new InvalidOperationException();
}
loadClassDelegate = (LoadClassDelegate)Delegate.CreateDelegate(typeof(LoadClassDelegate), GetType("java.lang.Class"), "__loadClassHelper");
}
}
@ -249,51 +246,29 @@ class ClassLoaderWrapper
throw JavaException.ClassNotFoundException(name);
}
}
// OPTIMIZE this should be optimized
try
// NOTE just like Java does (I think), we take the classloader lock before calling the loadClass method
lock(javaClassLoader)
{
object clazz;
// NOTE just like Java does (I think), we take the classloader lock before calling the loadClass method
lock(javaClassLoader)
Profiler.Enter("ClassLoader.loadClass");
try
{
Profiler.Enter("ClassLoader.loadClass");
try
{
clazz = loadClassMethod.Invoke(javaClassLoader, new object[] { name });
}
finally
{
Profiler.Leave("ClassLoader.loadClass");
}
type = (TypeWrapper)loadClassDelegate(javaClassLoader, name);
}
type = (TypeWrapper)clazz.GetType().GetField("wrapper", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(clazz);
if(type == null)
finally
{
Type t = (Type)clazz.GetType().GetField("type", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(clazz);
ClassLoaderWrapper loader = GetClassLoader(t);
type = (TypeWrapper)loader.types[name];
if(type == null)
{
// this shouldn't be possible
throw new InvalidOperationException(name + ", this = " + javaClassLoader);
}
Profiler.Leave("ClassLoader.loadClass");
}
// NOTE we're caching types loaded by parent classloaders as well!
// TODO not sure if this is correct
if(type.GetClassLoader() != this)
{
if(types[name] != type)
{
types.Add(name, type);
}
}
return type;
}
catch(TargetInvocationException x)
// NOTE we're caching types loaded by parent classloaders as well!
// TODO not sure if this is correct
if(type.GetClassLoader() != this)
{
ExceptionHelper.MapExceptionFast(x);
throw x.InnerException;
if(types[name] != type)
{
types.Add(name, type);
}
}
return type;
}
finally
{

Просмотреть файл

@ -39,7 +39,9 @@ public class ExceptionHelper
private class ExceptionInfoHelper
{
private static readonly Exception CAUSE_NOT_SET = new Exception();
private ArrayList stackTrace = new ArrayList();
private StackTrace tracePart1;
private StackTrace tracePart2;
private ArrayList stackTrace;
private Exception cause;
[StackTraceInfo(Hidden = true)]
@ -48,13 +50,8 @@ public class ExceptionHelper
Profiler.Enter("new ExceptionInfoHelper");
try
{
Append(new StackTrace(x, true));
bool chopFirst = stackTrace.Count != 0;
Append(new StackTrace(true));
if(chopFirst && stackTrace.Count > 0 && JVM.CleanStackTraces)
{
stackTrace.RemoveAt(0);
}
tracePart1 = new StackTrace(x, true);
tracePart2 = new StackTrace(true);
cause = x.InnerException;
if(cause == null)
{
@ -88,8 +85,9 @@ public class ExceptionHelper
internal void ResetStackTrace()
{
stackTrace.Clear();
Append(new StackTrace(true));
stackTrace = null;
tracePart1 = new StackTrace(true);
tracePart2 = null;
}
private static bool IsPrivateScope(MethodBase mb)
@ -238,11 +236,29 @@ public class ExceptionHelper
{
get
{
if(stackTrace == null)
{
stackTrace = new ArrayList();
Append(tracePart1);
if(tracePart2 != null)
{
bool chopFirst = stackTrace.Count != 0;
Append(tracePart2);
if(chopFirst && stackTrace.Count > 0 && JVM.CleanStackTraces)
{
stackTrace.RemoveAt(0);
}
}
tracePart1 = null;
tracePart2 = null;
}
return (StackTraceElement[])stackTrace.ToArray(typeof(StackTraceElement));
}
set
{
stackTrace = new ArrayList(value);
tracePart1 = null;
tracePart2 = null;
}
}
}
@ -492,7 +508,7 @@ public class ExceptionHelper
{
t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.ArrayIndexOutOfBoundsException"));
}
// HACK for String methods, we remap ArgumentOutOfRangeException to StringIndexOutOfBoundsException
// HACK for String methods, we remap ArgumentOutOfRangeException to StringIndexOutOfBoundsException
else if(type == typeof(ArgumentOutOfRangeException))
{
t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.StringIndexOutOfBoundsException"));
@ -559,9 +575,17 @@ public class ExceptionHelper
}
else if(type.FullName.StartsWith("System.") && type != typeof(TargetInvocationException))
{
// TODO this is just for debugging
Console.WriteLine("caught: {0}, handler: {1}", t.GetType().FullName, handler.FullName);
Console.WriteLine(t);
if(handler != typeof(Exception) && handler.FullName.StartsWith("System."))
{
// this is Java code explicitly handling a .NET exception (e.g. System.IO.IOException in java.io.FileDescriptor)
// so we don't need to print this
}
else
{
// TODO this is just for debugging
Console.WriteLine("caught: {0}, handler: {1}", t.GetType().FullName, handler.FullName);
Console.WriteLine(t);
}
}
if(!exceptions.ContainsKey(t))
{

Просмотреть файл

@ -25,7 +25,7 @@
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE"
DefineConstants = "DEBUG;TRACE;PROFILE"
DocumentationFile = ""
DebugSymbols = "true"
FileAlignment = "4096"

Просмотреть файл

@ -278,6 +278,30 @@ public class StringHelper
// TODO
return s.ToLower();
}
public static int indexOf(string s, char ch, int fromIndex)
{
// Java allow fromIndex to both below zero or above the length of the string, .NET doesn't
return s.IndexOf(ch, Math.Max(0, Math.Min(s.Length, fromIndex)));
}
public static int indexOf(string s, string o, int fromIndex)
{
// Java allow fromIndex to both below zero or above the length of the string, .NET doesn't
return s.IndexOf(o, Math.Max(0, Math.Min(s.Length, fromIndex)));
}
public static int lastIndexOf(string s, char ch, int fromIndex)
{
// Java allow fromIndex to both below zero or above the length of the string, .NET doesn't
return s.LastIndexOf(ch, Math.Max(0, Math.Min(s.Length - 1, fromIndex)));
}
public static int lastIndexOf(string s, string o, int fromIndex)
{
// Java allow fromIndex to both below zero or above the length of the string, .NET doesn't
return s.LastIndexOf(o, Math.Max(0, Math.Min(s.Length - 1, fromIndex)));
}
}
public class StringBufferHelper

Просмотреть файл

@ -717,7 +717,10 @@ class DynamicTypeWrapper : TypeWrapper
public override void Finish()
{
impl = impl.Finish();
lock(GetType())
{
impl = impl.Finish();
}
}
private abstract class DynamicImpl

Просмотреть файл

@ -451,7 +451,7 @@ namespace NativeCode.java
public static object execInternal(object obj, string[] cmd, string[] env, object dir)
{
// TODO
// TODO this was moved to the Java class ikvm.lang.DotNetProcess
throw new NotImplementedException();
}
@ -863,6 +863,11 @@ namespace NativeCode.java
return type;
}
public static object getWrapperFromType(Type t)
{
return ClassLoaderWrapper.GetWrapperFromType(t);
}
public static Type getType(object clazz)
{
if(getTypeMethod == null)
@ -1094,6 +1099,8 @@ namespace NativeCode.java
wrapper = ClassLoaderWrapper.GetWrapperFromType(type);
}
// we need to finish the type otherwise all methods will not be in the method map yet
// TODO since this can be called from Java code while finishing is in progress (finishing triggers
// class loading, which runs Java code which might call this method), we shouldn't finish here
wrapper.Finish();
return wrapper.GetMethods();
}
@ -1106,6 +1113,8 @@ namespace NativeCode.java
wrapper = ClassLoaderWrapper.GetWrapperFromType(type);
}
// we need to finish the type otherwise all fields will not be in the field map yet
// TODO since this can be called from Java code while finishing is in progress (finishing triggers
// class loading, which runs Java code which might call this method), we shouldn't finish here
wrapper.Finish();
return wrapper.GetFields();
}

Просмотреть файл

@ -177,23 +177,26 @@
<redirect name="IndexOf" sig="(C)I" />
</method>
<method name="indexOf" sig="(II)I" modifiers="public">
<redirect name="IndexOf" sig="(CI)I" />
<redirect class="StringHelper" type="static" sig="(Ljava/lang/String;CI)I" />
</method>
<method name="indexOf" sig="(Ljava/lang/String;)I" modifiers="public">
<redirect name="IndexOf" />
</method>
<method name="indexOf" sig="(Ljava/lang/String;I)I" modifiers="public">
<redirect name="IndexOf" />
<redirect class="StringHelper" type="static" sig="(Ljava/lang/String;Ljava/lang/String;I)I" />
</method>
<method name="lastIndexOf" sig="(I)I" modifiers="public">
<redirect name="LastIndexOf" sig="(C)I" />
</method>
<method name="lastIndexOf" sig="(II)I" modifiers="public">
<redirect name="LastIndexOf" sig="(CI)I" />
<redirect class="StringHelper" type="static" sig="(Ljava/lang/String;CI)I" />
</method>
<method name="lastIndexOf" sig="(Ljava/lang/String;)I" modifiers="public">
<redirect name="LastIndexOf" />
</method>
<method name="lastIndexOf" sig="(Ljava/lang/String;I)I" modifiers="public">
<redirect class="StringHelper" type="static" sig="(Ljava/lang/String;Ljava/lang/String;I)I" />
</method>
<method name="toCharArray" sig="()[C" modifiers="public">
<redirect name="ToCharArray" />
</method>
@ -452,5 +455,15 @@
<ret />
</method>
</class>
<class name="java.lang.Runtime">
<method name="execInternal" sig="([Ljava/lang/String;[Ljava/lang/String;Ljava/io/File;)Ljava/lang/Process;">
<ldarg_0 />
<ldarg_1 />
<ldarg_2 />
<ldarg_3 />
<call class="ikvm.lang.DotNetProcess" name="execInternal" />
<ret />
</method>
</class>
</nativeMethods>
</root>
</root>

Просмотреть файл

@ -54,11 +54,27 @@ namespace MapXml
{
string sig = Sig;
Type[] argTypes = ClassLoaderWrapper.GetBootstrapClassLoader().ArgTypeListFromSig(sig);
// TODO use our own reflection, because the type might not have been finished
method = Type.GetType(Class, true).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, argTypes, null);
}
else
{
method = Type.GetType(Class, true).GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
if(Type.GetType(Class, true).Assembly is AssemblyBuilder)
{
MethodWrapper[] methods = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(Class).GetMethods();
for(int i = 0; i < methods.Length; i++)
{
if(methods[i].Name == name)
{
method = methods[i].GetMethod();
break;
}
}
}
else
{
method = Type.GetType(Class, true).GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
}
}
if(method == null)
{
@ -253,6 +269,30 @@ namespace MapXml
}
}
[XmlType("ldarg_1")]
public sealed class LdArg_1 : Simple
{
public LdArg_1() : base(OpCodes.Ldarg_1)
{
}
}
[XmlType("ldarg_2")]
public sealed class LdArg_2 : Simple
{
public LdArg_2() : base(OpCodes.Ldarg_2)
{
}
}
[XmlType("ldarg_3")]
public sealed class LdArg_3 : Simple
{
public LdArg_3() : base(OpCodes.Ldarg_3)
{
}
}
[XmlType("ret")]
public sealed class Ret : Simple
{
@ -276,6 +316,9 @@ namespace MapXml
[XmlElement(typeof(StLoc))]
[XmlElement(typeof(LdLoc))]
[XmlElement(typeof(LdArg_0))]
[XmlElement(typeof(LdArg_1))]
[XmlElement(typeof(LdArg_2))]
[XmlElement(typeof(LdArg_3))]
[XmlElement(typeof(Ret))]
public Instruction[] invoke;

Просмотреть файл

@ -1,3 +1,4 @@
C:\ikvm\classpath\ikvm\lang\DotNetProcess.java
C:\ikvm\classpath\gnu\classpath\Configuration.java
C:\ikvm\classpath\gnu\java\net\protocol\ikvmres\Handler.java
C:\ikvm\classpath\java\io\FileDescriptor.java

Просмотреть файл

@ -0,0 +1,124 @@
/*
Copyright (C) 2002 Jeroen Frijters
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
*/
package ikvm.lang;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.File;
import system.text.StringBuilder;
import system.diagnostics.ProcessStartInfo;
public class DotNetProcess extends Process
{
private system.diagnostics.Process proc;
private DotNetProcess(system.diagnostics.Process proc)
{
this.proc = proc;
}
public OutputStream getOutputStream()
{
return new java.io.FileOutputStream(new java.io.FileDescriptor(proc.get_StandardInput().get_BaseStream()));
}
public InputStream getInputStream()
{
return new java.io.FileInputStream(new java.io.FileDescriptor(proc.get_StandardOutput().get_BaseStream()));
}
public InputStream getErrorStream()
{
return new java.io.FileInputStream(new java.io.FileDescriptor(proc.get_StandardError().get_BaseStream()));
}
public int waitFor() throws InterruptedException
{
proc.WaitForExit();
return proc.get_ExitCode();
}
public int exitValue()
{
if(proc.get_HasExited())
{
return proc.get_ExitCode();
}
throw new IllegalThreadStateException();
}
public void destroy()
{
try
{
if(false) throw new system.InvalidOperationException();
proc.Kill();
}
catch(system.InvalidOperationException x)
{
}
}
public static Process execInternal(Runtime runtime, String[] cmd, String[] env, File dir)
{
StringBuilder sb = new StringBuilder();
for(int i = 1; i < cmd.length; i++)
{
if(i > 1)
{
sb.Append(' ');
}
// HACK if the arg contains a space, we surround it with quotes
// this isn't nearly good enough, but for now it'll have to do
if(cmd[i].indexOf(' ') >= 0)
{
sb.Append('"').Append(cmd[i]).Append('"');
}
else
{
sb.Append(cmd[i]);
}
}
ProcessStartInfo si = new ProcessStartInfo(cmd[0], sb.ToString());
si.set_UseShellExecute(false);
si.set_RedirectStandardError(true);
si.set_RedirectStandardOutput(true);
si.set_RedirectStandardInput(true);
si.set_CreateNoWindow(true);
if(dir != null)
{
si.set_WorkingDirectory(dir.toString());
}
if(env != null)
{
for(int i = 0; i < env.length; i++)
{
int pos = env[i].indexOf('=');
si.get_EnvironmentVariables().Add(env[i].substring(0, pos), env[i].substring(pos + 1));
}
}
// TODO map the exceptions
return new DotNetProcess(system.diagnostics.Process.Start(si));
}
}