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 class ClassLoaderWrapper
{ {
private delegate object LoadClassDelegate(object classLoader, string className);
private static LoadClassDelegate loadClassDelegate;
private static bool arrayConstructionHack; private static bool arrayConstructionHack;
private static ArrayList ikvmAssemblies = new ArrayList(); private static ArrayList ikvmAssemblies = new ArrayList();
private static Hashtable assemblyToClassLoaderWrapper = new Hashtable(); private static Hashtable assemblyToClassLoaderWrapper = new Hashtable();
@ -42,7 +44,6 @@ class ClassLoaderWrapper
private static Hashtable typeToTypeWrapper = new Hashtable(); private static Hashtable typeToTypeWrapper = new Hashtable();
private static ClassLoaderWrapper bootstrapClassLoader; private static ClassLoaderWrapper bootstrapClassLoader;
private object javaClassLoader; private object javaClassLoader;
private MethodInfo loadClassMethod;
private Hashtable types = new Hashtable(); private Hashtable types = new Hashtable();
private Hashtable nativeMethods; private Hashtable nativeMethods;
// HACK moduleBuilder is static, because multiple dynamic assemblies is broken (TypeResolve doesn't fire) // 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) internal void SetJavaClassLoader(object javaClassLoader)
{ {
this.javaClassLoader = 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); loadClassDelegate = (LoadClassDelegate)Delegate.CreateDelegate(typeof(LoadClassDelegate), GetType("java.lang.Class"), "__loadClassHelper");
if(loadClassMethod == null)
{
throw new InvalidOperationException();
}
} }
} }
@ -249,51 +246,29 @@ class ClassLoaderWrapper
throw JavaException.ClassNotFoundException(name); throw JavaException.ClassNotFoundException(name);
} }
} }
// OPTIMIZE this should be optimized // NOTE just like Java does (I think), we take the classloader lock before calling the loadClass method
try lock(javaClassLoader)
{ {
object clazz; Profiler.Enter("ClassLoader.loadClass");
// NOTE just like Java does (I think), we take the classloader lock before calling the loadClass method try
lock(javaClassLoader)
{ {
Profiler.Enter("ClassLoader.loadClass"); type = (TypeWrapper)loadClassDelegate(javaClassLoader, name);
try
{
clazz = loadClassMethod.Invoke(javaClassLoader, new object[] { name });
}
finally
{
Profiler.Leave("ClassLoader.loadClass");
}
} }
type = (TypeWrapper)clazz.GetType().GetField("wrapper", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(clazz); finally
if(type == null)
{ {
Type t = (Type)clazz.GetType().GetField("type", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(clazz); Profiler.Leave("ClassLoader.loadClass");
ClassLoaderWrapper loader = GetClassLoader(t);
type = (TypeWrapper)loader.types[name];
if(type == null)
{
// this shouldn't be possible
throw new InvalidOperationException(name + ", this = " + javaClassLoader);
}
} }
// 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); if(types[name] != type)
throw x.InnerException; {
types.Add(name, type);
}
} }
return type;
} }
finally finally
{ {

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

@ -39,7 +39,9 @@ public class ExceptionHelper
private class ExceptionInfoHelper private class ExceptionInfoHelper
{ {
private static readonly Exception CAUSE_NOT_SET = new Exception(); 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; private Exception cause;
[StackTraceInfo(Hidden = true)] [StackTraceInfo(Hidden = true)]
@ -48,13 +50,8 @@ public class ExceptionHelper
Profiler.Enter("new ExceptionInfoHelper"); Profiler.Enter("new ExceptionInfoHelper");
try try
{ {
Append(new StackTrace(x, true)); tracePart1 = new StackTrace(x, true);
bool chopFirst = stackTrace.Count != 0; tracePart2 = new StackTrace(true);
Append(new StackTrace(true));
if(chopFirst && stackTrace.Count > 0 && JVM.CleanStackTraces)
{
stackTrace.RemoveAt(0);
}
cause = x.InnerException; cause = x.InnerException;
if(cause == null) if(cause == null)
{ {
@ -88,8 +85,9 @@ public class ExceptionHelper
internal void ResetStackTrace() internal void ResetStackTrace()
{ {
stackTrace.Clear(); stackTrace = null;
Append(new StackTrace(true)); tracePart1 = new StackTrace(true);
tracePart2 = null;
} }
private static bool IsPrivateScope(MethodBase mb) private static bool IsPrivateScope(MethodBase mb)
@ -238,11 +236,29 @@ public class ExceptionHelper
{ {
get 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)); return (StackTraceElement[])stackTrace.ToArray(typeof(StackTraceElement));
} }
set set
{ {
stackTrace = new ArrayList(value); stackTrace = new ArrayList(value);
tracePart1 = null;
tracePart2 = null;
} }
} }
} }
@ -492,7 +508,7 @@ public class ExceptionHelper
{ {
t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.ArrayIndexOutOfBoundsException")); 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)) else if(type == typeof(ArgumentOutOfRangeException))
{ {
t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.StringIndexOutOfBoundsException")); 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)) else if(type.FullName.StartsWith("System.") && type != typeof(TargetInvocationException))
{ {
// TODO this is just for debugging if(handler != typeof(Exception) && handler.FullName.StartsWith("System."))
Console.WriteLine("caught: {0}, handler: {1}", t.GetType().FullName, handler.FullName); {
Console.WriteLine(t); // 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)) if(!exceptions.ContainsKey(t))
{ {

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

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

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

@ -278,6 +278,30 @@ public class StringHelper
// TODO // TODO
return s.ToLower(); 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 public class StringBufferHelper

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

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

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

@ -451,7 +451,7 @@ namespace NativeCode.java
public static object execInternal(object obj, string[] cmd, string[] env, object dir) 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(); throw new NotImplementedException();
} }
@ -863,6 +863,11 @@ namespace NativeCode.java
return type; return type;
} }
public static object getWrapperFromType(Type t)
{
return ClassLoaderWrapper.GetWrapperFromType(t);
}
public static Type getType(object clazz) public static Type getType(object clazz)
{ {
if(getTypeMethod == null) if(getTypeMethod == null)
@ -1094,6 +1099,8 @@ namespace NativeCode.java
wrapper = ClassLoaderWrapper.GetWrapperFromType(type); wrapper = ClassLoaderWrapper.GetWrapperFromType(type);
} }
// we need to finish the type otherwise all methods will not be in the method map yet // 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(); wrapper.Finish();
return wrapper.GetMethods(); return wrapper.GetMethods();
} }
@ -1106,6 +1113,8 @@ namespace NativeCode.java
wrapper = ClassLoaderWrapper.GetWrapperFromType(type); wrapper = ClassLoaderWrapper.GetWrapperFromType(type);
} }
// we need to finish the type otherwise all fields will not be in the field map yet // 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(); wrapper.Finish();
return wrapper.GetFields(); return wrapper.GetFields();
} }

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

@ -177,23 +177,26 @@
<redirect name="IndexOf" sig="(C)I" /> <redirect name="IndexOf" sig="(C)I" />
</method> </method>
<method name="indexOf" sig="(II)I" modifiers="public"> <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>
<method name="indexOf" sig="(Ljava/lang/String;)I" modifiers="public"> <method name="indexOf" sig="(Ljava/lang/String;)I" modifiers="public">
<redirect name="IndexOf" /> <redirect name="IndexOf" />
</method> </method>
<method name="indexOf" sig="(Ljava/lang/String;I)I" modifiers="public"> <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>
<method name="lastIndexOf" sig="(I)I" modifiers="public"> <method name="lastIndexOf" sig="(I)I" modifiers="public">
<redirect name="LastIndexOf" sig="(C)I" /> <redirect name="LastIndexOf" sig="(C)I" />
</method> </method>
<method name="lastIndexOf" sig="(II)I" modifiers="public"> <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>
<method name="lastIndexOf" sig="(Ljava/lang/String;)I" modifiers="public"> <method name="lastIndexOf" sig="(Ljava/lang/String;)I" modifiers="public">
<redirect name="LastIndexOf" /> <redirect name="LastIndexOf" />
</method> </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"> <method name="toCharArray" sig="()[C" modifiers="public">
<redirect name="ToCharArray" /> <redirect name="ToCharArray" />
</method> </method>
@ -452,5 +455,15 @@
<ret /> <ret />
</method> </method>
</class> </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> </nativeMethods>
</root> </root>

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

@ -54,11 +54,27 @@ namespace MapXml
{ {
string sig = Sig; string sig = Sig;
Type[] argTypes = ClassLoaderWrapper.GetBootstrapClassLoader().ArgTypeListFromSig(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); method = Type.GetType(Class, true).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, argTypes, null);
} }
else 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) 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")] [XmlType("ret")]
public sealed class Ret : Simple public sealed class Ret : Simple
{ {
@ -276,6 +316,9 @@ namespace MapXml
[XmlElement(typeof(StLoc))] [XmlElement(typeof(StLoc))]
[XmlElement(typeof(LdLoc))] [XmlElement(typeof(LdLoc))]
[XmlElement(typeof(LdArg_0))] [XmlElement(typeof(LdArg_0))]
[XmlElement(typeof(LdArg_1))]
[XmlElement(typeof(LdArg_2))]
[XmlElement(typeof(LdArg_3))]
[XmlElement(typeof(Ret))] [XmlElement(typeof(Ret))]
public Instruction[] invoke; 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\classpath\Configuration.java
C:\ikvm\classpath\gnu\java\net\protocol\ikvmres\Handler.java C:\ikvm\classpath\gnu\java\net\protocol\ikvmres\Handler.java
C:\ikvm\classpath\java\io\FileDescriptor.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));
}
}