зеркало из https://github.com/mono/ikvm-fork.git
no message
This commit is contained in:
Родитель
c2845d2179
Коммит
e13321abc4
|
@ -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));
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче