This commit is contained in:
jfrijters 2003-01-17 14:34:33 +00:00
Родитель ca68c87f68
Коммит 5dcfa2b55a
16 изменённых файлов: 606 добавлений и 828 удалений

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

@ -96,17 +96,6 @@ Object* JNI::UnwrapGlobalRef(jobject o)
return 0;
}
/*
void* CreateDebugWrapper(String* name, void* pfunc)
{
char* pstub = new char[6];
pstub[0] = 0x90;
pstub[1] = 0xe8;
*((void**)&pstub[2]) = pfunc;
return pstub;
}
*/
IntPtr JNI::GetJniFuncPtr(String* method, String* sig, String* clazz)
{
System::Text::StringBuilder* mangledSig = new System::Text::StringBuilder();

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

@ -113,13 +113,30 @@ public:
public __gc class VM
{
public:
static MethodBase* GetMethod(Object* clazz, String* name, String* sig, bool isStatic)
static IntPtr GetMethodCookie(Object* clazz, String* name, String* sig, bool isStatic)
{
return JniHelper::GetMethod(clazz, name, sig, isStatic);
return JniHelper::GetMethodCookie(clazz, name, sig, isStatic);
}
static FieldInfo* GetField(Object* clazz, String* name, String* sig, bool isStatic)
static String* GetMethodArgList(IntPtr cookie)
{
return JniHelper::GetField(clazz, name, sig, isStatic);
return JniHelper::GetMethodArgList(cookie);
}
[StackTraceInfo(Hidden = true)]
static Object* InvokeMethod(IntPtr cookie, Object* obj, Object* args[], bool nonVirtual)
{
return JniHelper::InvokeMethod(cookie, obj, args, nonVirtual);
}
static IntPtr GetFieldCookie(Object* clazz, String* name, String* sig, bool isStatic)
{
return JniHelper::GetFieldCookie(clazz, name, sig, isStatic);
}
static Object* GetFieldValue(IntPtr cookie, Object* obj)
{
return JniHelper::GetFieldValue(cookie, obj);
}
static void SetFieldValue(IntPtr cookie, Object* obj, Object* value)
{
JniHelper::SetFieldValue(cookie, obj, value);
}
static Object* FindClass(String* javaName)
{

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

@ -249,72 +249,26 @@ jobject JNIEnv::AllocObject(jclass cls)
jmethodID JNIEnv::FindMethodID(jclass cls, const char* name, const char* sig, bool isstatic)
{
MethodBase* m = VM::GetMethod(UnwrapRef(cls), StringFromUTF8(name), StringFromUTF8(sig), isstatic);
if(!m)
jmethodID mid = (jmethodID)(void*)VM::GetMethodCookie(UnwrapRef(cls), StringFromUTF8(name), StringFromUTF8(sig), isstatic);
if(!mid)
{
//Console::WriteLine("Method not found: {0}{1} (static = {2})", StringFromUTF8(name), StringFromUTF8(sig), __box(isstatic));
// TODO set the exception message
ThrowNew(FindClass("java/lang/NoSuchMethodError"), "");
return 0;
}
// TODO jmethodID must be cached and delete'd!!! As it stands, we have a huge leak...
// also, don't forget to Free the GCHandle...
jmethodID mid = new _jmethodID;
mid->method = (void*)(IntPtr)GCHandle::Alloc(m);
int argc = 0;
for(int i = 1; sig[i] != ')'; i++)
{
switch(sig[i])
{
case 'I':
case 'Z':
case 'S':
case 'C':
case 'B':
mid->args[argc++] = 'I';
break;
case 'L':
while(sig[i] != ';') i++;
mid->args[argc++] = 'L';
break;
case '[':
while(sig[i] == '[') i++;
if(sig[i] == 'L') while(sig[i] != ';') i++;
mid->args[argc++] = 'L';
break;
case 'D':
mid->args[argc++] = 'D';
break;
case 'F':
mid->args[argc++] = 'F';
break;
case 'J':
mid->args[argc++] = 'J';
break;
}
if(argc == 256)
{
// it isn't valid for a Java method to have more than 256 arguments,
// so this cannot happen for valid classes
throw new NotSupportedException();
}
}
mid->args[argc] = 0;
return mid;
}
jfieldID JNIEnv::FindFieldID(jclass cls, const char* name, const char* sig, bool isstatic)
{
FieldInfo* f = VM::GetField(UnwrapRef(cls), StringFromUTF8(name), StringFromUTF8(sig), isstatic);
if(!f)
jfieldID fid = (jfieldID)(void*)VM::GetFieldCookie(UnwrapRef(cls), StringFromUTF8(name), StringFromUTF8(sig), isstatic);
if(!fid)
{
// TODO what is the proper handling of this
assert(false);
throw new NotImplementedException("field not found");
// TODO set the exception message
ThrowNew(FindClass("java/lang/NoSuchFieldError"), "");
return 0;
}
// TODO jfieldID must be cached and delete'd!!! As it stands, we have a huge leak...
// also, don't forget to Free the GCHandle...
jfieldID fid = new _jfieldID;
fid->field = (void*)(IntPtr)GCHandle::Alloc(f);
return fid;
}
@ -323,11 +277,70 @@ jmethodID JNIEnv::GetStaticMethodID(jclass cls, const char *name, const char *si
return FindMethodID(cls, name, sig, true);
}
static int GetMethodArgs(jmethodID methodID, char* sig)
{
int count = 0;
String* s = VM::GetMethodArgList(methodID);
for(int i = 0; i < s->Length; i++)
{
*sig++ = (char)s->get_Chars(i);
count++;
}
*sig = 0;
return count;
}
Object* JNIEnv::InvokeHelper(jobject object, jmethodID methodID, jvalue* args)
{
assert(!pLocalRefs->PendingException);
assert(methodID);
char sig[257];
int argc = GetMethodArgs(methodID, sig);
Object* argarray __gc[] = new Object*[argc];
for(int i = 0; i < argc; i++)
{
switch(sig[i])
{
case 'Z':
argarray[i] = __box(args[i].z != JNI_FALSE);
break;
case 'B':
argarray[i] = __box((char)args[i].b);
break;
case 'C':
argarray[i] = __box((__wchar_t)args[i].c);
break;
case 'S':
argarray[i] = __box((short)args[i].s);
break;
case 'I':
argarray[i] = __box((int)args[i].i);
break;
case 'J':
argarray[i] = __box((__int64)args[i].j);
break;
case 'F':
argarray[i] = __box((float)args[i].f);
break;
case 'D':
argarray[i] = __box((double)args[i].d);
break;
case 'L':
argarray[i] = UnwrapRef(args[i].l);
break;
}
}
try
{
return VM::InvokeMethod(methodID, UnwrapRef(object), argarray, false);
}
catch(Exception* x)
{
pLocalRefs->PendingException = x;
return 0;
}
/*
MethodBase* m = __try_cast<MethodBase*>(GCHandle::op_Explicit((IntPtr)methodID->method).Target);
ParameterInfo* p __gc[] = m->GetParameters();
Object* argarray __gc[] = new Object*[p->Length];
@ -410,6 +423,7 @@ Object* JNIEnv::InvokeHelper(jobject object, jmethodID methodID, jvalue* args)
pLocalRefs->PendingException = x->InnerException;
return 0;
}
*/
}
void JNICALL JNIEnv::CallStaticVoidMethodA(jclass cls, jmethodID methodID, jvalue* args)
@ -420,12 +434,17 @@ void JNICALL JNIEnv::CallStaticVoidMethodA(jclass cls, jmethodID methodID, jvalu
void JNICALL JNIEnv::CallStaticVoidMethodV(jclass clazz, jmethodID methodID, va_list args)
{
int argc = strlen(methodID->args);
char arglist[257];
int argc = GetMethodArgs(methodID, arglist);
jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));
for(int i = 0; i < argc; i++)
{
switch(methodID->args[i])
switch(arglist[i])
{
case 'Z':
case 'B':
case 'S':
case 'C':
case 'I':
argarray[i].i = va_arg(args, int);
break;
@ -457,12 +476,17 @@ void JNIEnv::CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...)
#define STATIC_METHOD_IMPL(Type,type) \
type JNICALL JNIEnv::CallStatic##Type##MethodV(jclass clazz, jmethodID methodID, va_list args)\
{\
int argc = strlen(methodID->args);\
char sig[257];\
int argc = GetMethodArgs(methodID, sig);\
jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));\
for(int i = 0; i < argc; i++)\
{\
switch(methodID->args[i])\
switch(sig[i])\
{\
case 'Z':\
case 'B':\
case 'S':\
case 'C':\
case 'I':\
argarray[i].i = va_arg(args, int);\
break;\
@ -543,13 +567,11 @@ jfieldID JNICALL JNIEnv::GetStaticFieldID(jclass cls, const char *name, const ch
#define GET_SET_FIELD(Type,type,cpptype) \
void JNICALL JNIEnv::Set##Type##Field(jobject obj, jfieldID fieldID, type val)\
{\
FieldInfo* pField = __try_cast<FieldInfo*>(GCHandle::op_Explicit((IntPtr)fieldID->field).Target);\
pField->SetValue(UnwrapRef(obj), __box((cpptype)val));\
VM::SetFieldValue((IntPtr)fieldID, UnwrapRef(obj), __box((cpptype)val));\
}\
type JNICALL JNIEnv::Get##Type##Field(jobject obj, jfieldID fieldID)\
{\
FieldInfo* pField = __try_cast<FieldInfo*>(GCHandle::op_Explicit((IntPtr)fieldID->field).Target);\
return __unbox<cpptype>(pField->GetValue(UnwrapRef(obj)));\
return __unbox<cpptype>(VM::GetFieldValue((IntPtr)fieldID, UnwrapRef(obj)));\
}
GET_SET_FIELD(Boolean,jboolean,bool)
@ -563,14 +585,12 @@ GET_SET_FIELD(Double,jdouble,double)
void JNICALL JNIEnv::SetObjectField(jobject obj, jfieldID fieldID, jobject val)
{
FieldInfo* pField = __try_cast<FieldInfo*>(GCHandle::op_Explicit((IntPtr)fieldID->field).Target);
pField->SetValue(UnwrapRef(obj), UnwrapRef(val));
VM::SetFieldValue((IntPtr)fieldID, UnwrapRef(obj), UnwrapRef(val));
}
jobject JNICALL JNIEnv::GetObjectField(jobject obj, jfieldID fieldID)
{
FieldInfo* pField = __try_cast<FieldInfo*>(GCHandle::op_Explicit((IntPtr)fieldID->field).Target);
return (jobject)(void*)pLocalRefs->MakeLocalRef(pField->GetValue(UnwrapRef(obj)));
return (jobject)(void*)pLocalRefs->MakeLocalRef(VM::GetFieldValue((IntPtr)fieldID, UnwrapRef(obj)));
}
#pragma unmanaged
@ -603,12 +623,17 @@ type JNIEnv::Call##Type##Method(jobject obj, jmethodID methodID, ...) \
}\
type JNICALL JNIEnv::Call##Type##MethodV(jobject obj, jmethodID methodID, va_list args)\
{\
int argc = strlen(methodID->args);\
char sig[257];\
int argc = GetMethodArgs(methodID, sig);\
jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));\
for(int i = 0; i < argc; i++)\
{\
switch(methodID->args[i])\
switch(sig[i])\
{\
case 'Z':\
case 'B':\
case 'S':\
case 'C':\
case 'I':\
argarray[i].i = va_arg(args, int);\
break;\
@ -674,12 +699,17 @@ void JNIEnv::CallVoidMethod(jobject obj, jmethodID methodID, ...)
void JNICALL JNIEnv::CallVoidMethodV(jobject obj, jmethodID methodID, va_list args)
{
int argc = strlen(methodID->args);
char sig[257];
int argc = GetMethodArgs(methodID, sig);
jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));
for(int i = 0; i < argc; i++)
{
switch(methodID->args[i])
switch(sig[i])
{
case 'Z':
case 'B':
case 'S':
case 'C':
case 'I':
argarray[i].i = va_arg(args, int);
break;
@ -857,12 +887,17 @@ jobject JNICALL JNIEnv::NewObject(jclass clazz, jmethodID methodID, ...)
jobject JNICALL JNIEnv::NewObjectV(jclass clazz, jmethodID methodID, va_list args)
{
int argc = strlen(methodID->args);
char sig[257];
int argc = GetMethodArgs(methodID, sig);
jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));
for(int i = 0; i < argc; i++)
{
switch(methodID->args[i])
switch(sig[i])
{
case 'Z':
case 'B':
case 'S':
case 'C':
case 'I':
argarray[i].i = va_arg(args, int);
break;

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

@ -94,13 +94,10 @@ typedef struct _jfieldID* jfieldID;
struct _jmethodID
{
void* method;
char args[257]; // 'I', 'J', 'L', 'D' or 'F', and terminated by '\0'
};
struct _jfieldID
{
void* field;
};
/*

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

@ -78,18 +78,13 @@ public class ByteCodeHelper
TypeWrapper wrapper = classLoader.LoadClassBySlashedName(clazz);
wrapper.Finish();
// TODO who checks that the arg types are loadable?
// TODO instead of getting the constructor from the type, we should use the (future) reflection support in MethodWrapper
//MethodWrapper mw = wrapper.GetMethodWrapper(new MethodDescriptor(classLoader, name, sig), false);
// TODO handle error, check access, etc.
ConstructorInfo constructor = wrapper.Type.GetConstructor(classLoader.ArgTypeListFromSig(sig));
try
// TODO check accessibility
MethodWrapper mw = wrapper.GetMethodWrapper(new MethodDescriptor(classLoader, name, sig), false);
if(mw == null)
{
return constructor.Invoke(args);
}
catch(TargetInvocationException x)
{
ExceptionHelper.MapExceptionFast(x);
throw x.InnerException;
// TODO throw the appropriate exception
throw new NotImplementedException("constructor missing");
}
return mw.Invoke(null, args, false);
}
}

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

@ -127,7 +127,7 @@ class ClassLoaderWrapper
internal void LoadRemappedTypes()
{
nativeMethods = new Hashtable();
// TODO interfaces have java/lang/Object as the base type (do they really?)
// NOTE interfaces have *not* java/lang/Object as the base type (even though they do in the class file)
types["java.lang.Cloneable"] = new RemappedTypeWrapper(this, ModifiersAttribute.GetModifiers(typeof(java.lang.Cloneable)), "java/lang/Cloneable", typeof(java.lang.Cloneable), new TypeWrapper[0], null);
typeToTypeWrapper.Add(typeof(java.lang.Cloneable), types["java.lang.Cloneable"]);
types["java.io.Serializable"] = new RemappedTypeWrapper(this, ModifiersAttribute.GetModifiers(typeof(java.io.Serializable)), "java/io/Serializable", typeof(java.io.Serializable), new TypeWrapper[0], null);
@ -360,7 +360,7 @@ class ClassLoaderWrapper
// TODO copy accessibility from element type
wrapper = new RemappedTypeWrapper(this, modifiers, name, array, interfaces, GetBootstrapClassLoader().LoadClassByDottedName("java.lang.Object"));
MethodInfo clone = typeof(Array).GetMethod("Clone");
MethodWrapper mw = new MethodWrapper(wrapper, mdClone, clone, Modifiers.Public);
MethodWrapper mw = new MethodWrapper(wrapper, mdClone, clone, null, Modifiers.Public);
mw.EmitCall = CodeEmitter.Create(OpCodes.Callvirt, clone);
mw.EmitCallvirt = CodeEmitter.Create(OpCodes.Callvirt, clone);
wrapper.AddMethod(mw);

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

@ -212,7 +212,7 @@ public class ExceptionHelper
for(int i = stackTrace.Count - 1; i >= 0; i--)
{
StackTraceElement ste = (StackTraceElement)stackTrace[i];
if(ste.getClassName() == "System.Reflection.RuntimeMethodInfo")
if(ste.getClassName() == "System.Reflection.MethodBase")
{
// skip method invocation by reflection, if it is at the top of the stack
chop++;
@ -242,12 +242,13 @@ public class ExceptionHelper
Append(tracePart1);
if(tracePart2 != null)
{
bool chopFirst = stackTrace.Count != 0;
// don't have a clue why this was here, but it doesn't work for jni.class
//bool chopFirst = stackTrace.Count != 0;
Append(tracePart2);
if(chopFirst && stackTrace.Count > 0 && JVM.CleanStackTraces)
{
stackTrace.RemoveAt(0);
}
//if(chopFirst && stackTrace.Count > 0 && JVM.CleanStackTraces)
//{
// stackTrace.RemoveAt(0);
//}
}
tracePart1 = null;
tracePart2 = null;

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

@ -22,58 +22,91 @@
*/
using System;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
public sealed class JniHelper
{
public static System.Reflection.MethodBase GetMethod(object clazz, string name, string sig, bool isStatic)
public static IntPtr GetMethodCookie(object clazz, string name, string sig, bool isStatic)
{
// TODO this is totally broken, because JNI needs to support redirection
TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromType(NativeCode.java.lang.Class.getType(clazz));
wrapper.Finish();
MethodDescriptor md = new MethodDescriptor(wrapper.GetClassLoader(), name, sig);
BindingFlags bindings = BindingFlags.Public | BindingFlags.NonPublic;
if(isStatic)
MethodWrapper mw = wrapper.GetMethodWrapper(new MethodDescriptor(wrapper.GetClassLoader(), name, sig), true);
if(mw != null)
{
bindings |= BindingFlags.Static;
}
else
{
bindings |= BindingFlags.Instance;
}
if(name == "<init>")
{
return wrapper.Type.GetConstructor(bindings, null, md.ArgTypes, null);
}
Type type = wrapper.Type;
while(type != null)
{
MethodInfo m = type.GetMethod(name, bindings, null, CallingConventions.Standard, md.ArgTypes, null);
if(m != null)
if(mw.IsStatic == isStatic)
{
return m;
return mw.Cookie;
}
type = type.BaseType;
}
return null;
return (IntPtr)0;
}
public static System.Reflection.FieldInfo GetField(object clazz, string name, string sig, bool isStatic)
// this method returns a simplified method argument descriptor.
// some examples:
// "()V" -> ""
// "(ILjava/lang/String;)I" -> "IL"
// "([Ljava/lang/String;)V" -> "L"
public static string GetMethodArgList(IntPtr cookie)
{
StringBuilder sb = new StringBuilder();
string s = MethodWrapper.FromCookie(cookie).Descriptor.Signature;
for(int i = 1;; i++)
{
switch(s[i])
{
case '[':
while(s[i] == '[') i++;
if(s[i] == 'L')
{
while(s[i] != ';') i++;
}
sb.Append('L');
break;
case 'L':
while(s[i] != ';') i++;
sb.Append('L');
break;
case ')':
return sb.ToString();
default:
sb.Append(s[i]);
break;
}
}
}
[StackTraceInfo(Hidden = true)]
public static object InvokeMethod(IntPtr cookie, object obj, object[] args, bool nonVirtual)
{
return MethodWrapper.FromCookie(cookie).Invoke(obj, args, nonVirtual);
}
public static IntPtr GetFieldCookie(object clazz, string name, string sig, bool isStatic)
{
// TODO this is totally broken, because JNI needs to support redirection
TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromType(NativeCode.java.lang.Class.getType(clazz));
wrapper.Finish();
MethodDescriptor md = new MethodDescriptor(wrapper.GetClassLoader(), name, sig);
BindingFlags bindings = BindingFlags.Public | BindingFlags.NonPublic;
if(isStatic)
// TODO GetFieldWrapper should take sig (what about searching the base classes?)
FieldWrapper fw = wrapper.GetFieldWrapper(name);
if(fw != null)
{
bindings |= BindingFlags.Static;
if(fw.IsStatic == isStatic)
{
return fw.Cookie;
}
}
else
{
bindings |= BindingFlags.Instance;
}
return wrapper.Type.GetField(name, bindings);
return (IntPtr)0;
}
public static void SetFieldValue(IntPtr cookie, object obj, object val)
{
FieldWrapper.FromCookie(cookie).SetValue(obj, val);
}
public static object GetFieldValue(IntPtr cookie, object obj)
{
return FieldWrapper.FromCookie(cookie).GetValue(obj);
}
public static object FindClass(string javaName)

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

@ -164,8 +164,7 @@ public class StringHelper
public static bool startsWith(string s, string prefix, int toffset)
{
// TODO
throw new NotImplementedException();
return s.Substring(toffset).StartsWith(prefix);
}
public static void getChars(string s, int srcBegin, int srcEnd, char[] dst, int dstBegin)

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

@ -1781,6 +1781,7 @@ class DynamicTypeWrapper : TypeWrapper
if(retTypeWrapper.IsUnloadable)
{
CustomAttributeBuilder attrib = new CustomAttributeBuilder(typeof(UnloadableTypeAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { retTypeWrapper.Name });
// TODO DefineParameter(0, ...) throws an exception, even though this looks like the way to do it...
((MethodBuilder)method).DefineParameter(0, ParameterAttributes.None, null).SetCustomAttribute(attrib);
}
for(int i = 0; i < argTypeWrappers.Length; i++)
@ -2029,7 +2030,7 @@ class RemappedTypeWrapper : TypeWrapper
invokevirtual = CodeEmitter.Create(OpCodes.Callvirt, (MethodInfo)overrideMethod);
}
}
MethodWrapper mw = new MethodWrapper(this, md, overrideMethod, modifiers);
MethodWrapper mw = new MethodWrapper(this, md, overrideMethod, redirect, modifiers);
mw.EmitNewobj = newopc;
mw.EmitCall = invokespecial;
mw.EmitCallvirt = invokevirtual;
@ -2143,7 +2144,7 @@ class RemappedTypeWrapper : TypeWrapper
newopc = constructor.newobj;
invokespecial = constructor.invokespecial;
}
MethodWrapper mw = new MethodWrapper(this, md, null, modifiers);
MethodWrapper mw = new MethodWrapper(this, md, null, null, modifiers);
mw.EmitNewobj = newopc;
mw.EmitCall = invokespecial;
if(retcast != null)
@ -2551,7 +2552,7 @@ class NetExpTypeWrapper : TypeWrapper
if(md.Name == "<init>" && type.IsSubclassOf(typeof(MulticastDelegate)))
{
// TODO set method flags
MethodWrapper method = new MethodWrapper(this, md, null, Modifiers.Public);
MethodWrapper method = new MethodWrapper(this, md, null, null, Modifiers.Public);
// TODO what class loader should we use?
TypeWrapper iface = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName(classFile.Name + "$Method");
iface.Finish();
@ -2812,7 +2813,7 @@ class CompiledTypeWrapper : TypeWrapper
{
return null;
}
MethodWrapper method = new MethodWrapper(this, md, mb, ModifiersAttribute.GetModifiers(mb));
MethodWrapper method = new MethodWrapper(this, md, mb, null, ModifiersAttribute.GetModifiers(mb));
if(mb is ConstructorInfo)
{
method.EmitCall = CodeEmitter.Create(OpCodes.Call, (ConstructorInfo)mb);
@ -3116,9 +3117,11 @@ public abstract class CodeEmitter
sealed class MethodWrapper
{
private IntPtr cookie;
private TypeWrapper declaringType;
private MethodDescriptor md;
private MethodBase originalMethod;
private MethodBase redirMethod;
private Modifiers modifiers;
private bool isRemappedVirtual;
private bool isRemappedOverride;
@ -3126,13 +3129,14 @@ sealed class MethodWrapper
internal CodeEmitter EmitCallvirt;
internal CodeEmitter EmitNewobj;
// TODO creation of MethodWrappers should be cleaned up (and every instance should support Invoke())
internal static MethodWrapper Create(TypeWrapper declaringType, MethodDescriptor md, MethodBase originalMethod, MethodBase method, Modifiers modifiers)
{
if(method == null)
{
throw new InvalidOperationException();
}
MethodWrapper wrapper = new MethodWrapper(declaringType, md, originalMethod, modifiers);
MethodWrapper wrapper = new MethodWrapper(declaringType, md, originalMethod, method, modifiers);
if(method is ConstructorInfo)
{
wrapper.EmitCall = CodeEmitter.Create(OpCodes.Call, (ConstructorInfo)method);
@ -3162,8 +3166,13 @@ sealed class MethodWrapper
return wrapper;
}
internal MethodWrapper(TypeWrapper declaringType, MethodDescriptor md, MethodBase originalMethod, Modifiers modifiers)
internal MethodWrapper(TypeWrapper declaringType, MethodDescriptor md, MethodBase originalMethod, MethodBase method, Modifiers modifiers)
{
if(method != originalMethod)
{
redirMethod = method;
Debug.Assert(!(method is MethodBuilder));
}
this.declaringType = declaringType;
this.md = md;
// NOTE originalMethod may be null
@ -3171,6 +3180,23 @@ sealed class MethodWrapper
this.modifiers = modifiers;
}
internal IntPtr Cookie
{
get
{
if(cookie == (IntPtr)0)
{
cookie = (IntPtr)System.Runtime.InteropServices.GCHandle.Alloc(this);
}
return cookie;
}
}
internal static MethodWrapper FromCookie(IntPtr cookie)
{
return (MethodWrapper)((System.Runtime.InteropServices.GCHandle)cookie).Target;
}
internal TypeWrapper DeclaringType
{
get
@ -3342,6 +3368,85 @@ sealed class MethodWrapper
return (modifiers & Modifiers.Abstract) != 0;
}
}
internal object Invoke(object obj, object[] args, bool nonVirtual)
{
// TODO instead of looking up the method using reflection, we should use the method object passed into the
// constructor
if(IsStatic)
{
MethodInfo method = this.originalMethod != null && !(this.originalMethod is MethodBuilder) ? (MethodInfo)this.originalMethod : declaringType.Type.GetMethod(md.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, md.ArgTypes, null);
try
{
return method.Invoke(null, args);
}
catch(TargetInvocationException x)
{
throw ExceptionHelper.MapExceptionFast(x.InnerException);
}
}
else
{
// calling <init> without an instance means that we're constructing a new instance
// NOTE this means that we cannot detect a NullPointerException when calling <init>
if(md.Name == "<init>")
{
if(obj == null)
{
ConstructorInfo constructor = this.originalMethod != null && !(this.originalMethod is ConstructorBuilder) ? (ConstructorInfo)this.originalMethod : declaringType.Type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Standard, md.ArgTypes, null);
try
{
return constructor.Invoke(args);
}
catch(TargetInvocationException x)
{
throw ExceptionHelper.MapExceptionFast(x.InnerException);
}
}
else
{
throw new NotImplementedException("invoking constructor on existing instance");
}
}
if(nonVirtual)
{
throw new NotImplementedException("non-virtual reflective method invocation non implemented");
}
MethodInfo method = (MethodInfo)this.originalMethod;
if(redirMethod != null)
{
method = (MethodInfo)redirMethod;
if(method.IsStatic)
{
// we've been redirected to a static method, so we have to copy the this into the args
object[] oldargs = args;
args = new object[args.Length + 1];
args[0] = obj;
oldargs.CopyTo(args, 1);
obj = null;
}
}
else
{
if(method is MethodBuilder || method == null)
{
method = declaringType.Type.GetMethod(md.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, md.ArgTypes, null);
}
if(method == null)
{
throw new NotImplementedException("method not found: " + this.declaringType.Name + "." + md.Name + md.Signature);
}
}
try
{
return method.Invoke(obj, args);
}
catch(TargetInvocationException x)
{
throw ExceptionHelper.MapExceptionFast(x.InnerException);
}
}
}
}
class CastEmitter : CodeEmitter
@ -3395,6 +3500,7 @@ sealed class FieldWrapper
private string name;
private string sig;
private Modifiers modifiers;
private IntPtr cookie;
internal CodeEmitter EmitGet;
internal CodeEmitter EmitSet;
@ -3410,6 +3516,23 @@ sealed class FieldWrapper
this.modifiers = modifiers;
}
internal IntPtr Cookie
{
get
{
if(cookie == (IntPtr)0)
{
cookie = (IntPtr)System.Runtime.InteropServices.GCHandle.Alloc(this);
}
return cookie;
}
}
internal static FieldWrapper FromCookie(IntPtr cookie)
{
return (FieldWrapper)((System.Runtime.InteropServices.GCHandle)cookie).Target;
}
internal TypeWrapper DeclaringType
{
get
@ -3609,4 +3732,34 @@ sealed class FieldWrapper
}
return field;
}
internal void SetValue(object obj, object val)
{
// TODO this is a broken implementation (for one thing, it needs to support redirection)
BindingFlags bindings = BindingFlags.Public | BindingFlags.NonPublic;
if(IsStatic)
{
bindings |= BindingFlags.Static;
}
else
{
bindings |= BindingFlags.Instance;
}
DeclaringType.Type.GetField(name, bindings).SetValue(obj, val);
}
internal object GetValue(object obj)
{
// TODO this is a broken implementation (for one thing, it needs to support redirection)
BindingFlags bindings = BindingFlags.Public | BindingFlags.NonPublic;
if(IsStatic)
{
bindings |= BindingFlags.Static;
}
else
{
bindings |= BindingFlags.Instance;
}
return DeclaringType.Type.GetField(name, bindings).GetValue(obj);
}
}

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

@ -172,6 +172,59 @@ namespace NativeCode.java
}
}
internal class JavaWrapper
{
private static Type java_lang_Integer = ClassLoaderWrapper.GetType("java.lang.Integer");
private static Type java_lang_Short = ClassLoaderWrapper.GetType("java.lang.Short");
private static Type java_lang_Boolean = ClassLoaderWrapper.GetType("java.lang.Boolean");
private static Type java_lang_Long = ClassLoaderWrapper.GetType("java.lang.Long");
internal static object Box(object o)
{
if(o is int)
{
return Activator.CreateInstance(java_lang_Integer, new object[] { o });
}
else if(o is bool)
{
return Activator.CreateInstance(java_lang_Boolean, new object[] { o });
}
else if(o is long)
{
return Activator.CreateInstance(java_lang_Long, new object[] { o });
}
else
{
throw new NotImplementedException(o.GetType().FullName);
}
}
internal static object Unbox(object o)
{
Type type = o.GetType();
if(type == java_lang_Integer)
{
return java_lang_Integer.GetMethod("intValue").Invoke(o, new object[0]);
}
else if(type == java_lang_Boolean)
{
return java_lang_Boolean.GetMethod("booleanValue").Invoke(o, new object[0]);
}
else if(type == java_lang_Short)
{
return java_lang_Short.GetMethod("shortValue").Invoke(o, new object[0]);
}
else if(type == java_lang_Long)
{
return java_lang_Long.GetMethod("longValue").Invoke(o, new object[0]);
}
else
{
throw new NotImplementedException(o.GetType().FullName);
}
}
}
public class Method
{
public static String GetName(object methodCookie)
@ -211,98 +264,25 @@ namespace NativeCode.java
return new object[0];
}
[StackTraceInfo(Hidden = true)]
public static object Invoke(object methodCookie, object o, object[] args)
{
// TODO this is a very lame implementation, no where near correct
MethodWrapper wrapper = (MethodWrapper)methodCookie;
wrapper.DeclaringType.Finish();
TypeWrapper[] argWrappers = wrapper.GetParameters();
Type[] argTypes = new Type[argWrappers.Length];
for(int i = 0; i < argTypes.Length; i++)
MethodWrapper mw = (MethodWrapper)methodCookie;
mw.DeclaringType.Finish();
TypeWrapper[] argWrappers = mw.GetParameters();
for(int i = 0; i < argWrappers.Length; i++)
{
argWrappers[i].Finish();
argTypes[i] = argWrappers[i].Type;
if(argTypes[i].IsPrimitive)
if(argWrappers[i].IsPrimitive)
{
if(argTypes[i] == typeof(int))
{
args[i] = ClassLoaderWrapper.GetType("java.lang.Integer").GetMethod("intValue").Invoke(args[i], new object[0]);
}
else if(argTypes[i] == typeof(bool))
{
args[i] = ClassLoaderWrapper.GetType("java.lang.Boolean").GetMethod("booleanValue").Invoke(args[i], new object[0]);
}
else if(argTypes[i] == typeof(short))
{
args[i] = ClassLoaderWrapper.GetType("java.lang.Short").GetMethod("shortValue").Invoke(args[i], new object[0]);
}
else
{
throw new NotImplementedException("argtype: " + argTypes[i].FullName);
}
args[i] = JavaWrapper.Unbox(args[i]);
}
}
try
object retval = mw.Invoke(o, args, false);
if(mw.ReturnType.IsPrimitive && mw.ReturnType != PrimitiveTypeWrapper.VOID)
{
if(wrapper.Name == "<init>")
{
if(o == null)
{
return wrapper.DeclaringType.Type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, argTypes, null).Invoke(args);
}
else
{
throw new NotImplementedException("invoking constructor on existing instance");
}
}
else
{
MethodInfo mi;
if(wrapper.GetMethod() is NetSystem.Reflection.Emit.MethodBuilder || wrapper.GetMethod() == null)
{
mi = wrapper.DeclaringType.Type.GetMethod(wrapper.Name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, argTypes, null);
}
else
{
mi = (MethodInfo)wrapper.GetMethod();
}
if(mi == null)
{
throw new InvalidOperationException("Method not found: " + wrapper.DeclaringType.Name + "." + wrapper.Name + wrapper.Descriptor.Signature);
}
object retval = mi.Invoke(o, args);
if(wrapper.ReturnType.Type.IsValueType)
{
if(wrapper.ReturnType.Type == typeof(int))
{
retval = Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.Integer"), new object[] { (int)retval });
}
else if(wrapper.ReturnType.Type == typeof(bool))
{
retval = Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.Boolean"), new object[] { (bool)retval });
}
else if(wrapper.ReturnType.Type == typeof(void))
{
// nothing to do
}
else
{
throw new NotImplementedException("rettype: " + wrapper.ReturnType.Type.FullName);
}
}
return retval;
}
retval = JavaWrapper.Box(retval);
}
catch(TargetInvocationException x)
{
throw JavaException.InvocationTargetException(ExceptionHelper.MapException(x.InnerException, typeof(Exception)));
}
}
// TODO remove this, it isn't used anymore
public static Exception mapException(Exception x)
{
return ExceptionHelper.MapException(x, typeof(Exception));
return retval;
}
}
@ -366,20 +346,21 @@ namespace NativeCode.java
{
MethodInfo m = properties.GetType().GetMethod("setProperty");
// TODO set all these properties to something useful
m.Invoke(properties, new string[] { "java.version", "1.1" });
m.Invoke(properties, new string[] { "java.version", "1.3" });
m.Invoke(properties, new string[] { "java.vendor", "Jeroen Frijters" });
m.Invoke(properties, new string[] { "java.vendor.url", "http://jeroen.nu/" });
m.Invoke(properties, new string[] { "java.home", "" });
m.Invoke(properties, new string[] { "java.vm.specification.version", "" });
m.Invoke(properties, new string[] { "java.vm.specification.vendor", "" });
m.Invoke(properties, new string[] { "java.vm.specification.name", "" });
m.Invoke(properties, new string[] { "java.vm.version", "" });
m.Invoke(properties, new string[] { "java.vm.vendor", "" });
m.Invoke(properties, new string[] { "java.vm.name", "" });
m.Invoke(properties, new string[] { "java.specification.version", "" });
m.Invoke(properties, new string[] { "java.specification.vendor", "" });
m.Invoke(properties, new string[] { "java.specification.name", "" });
m.Invoke(properties, new string[] { "java.class.version", "" });
m.Invoke(properties, new string[] { "java.vendor.url", "http://ikvm.net/" });
// HACK using the Assembly.Location property isn't correct
m.Invoke(properties, new string[] { "java.home", new FileInfo(typeof(Runtime).Assembly.Location).DirectoryName });
m.Invoke(properties, new string[] { "java.vm.specification.version", "1.0" });
m.Invoke(properties, new string[] { "java.vm.specification.vendor", "Sun Microsystems Inc." });
m.Invoke(properties, new string[] { "java.vm.specification.name", "Java Virtual Machine Specification" });
m.Invoke(properties, new string[] { "java.vm.version", typeof(Runtime).Assembly.GetName().Version.ToString() });
m.Invoke(properties, new string[] { "java.vm.vendor", "Jeroen Frijters" });
m.Invoke(properties, new string[] { "java.vm.name", "IKVM.NET" });
m.Invoke(properties, new string[] { "java.specification.version", "1.3" });
m.Invoke(properties, new string[] { "java.specification.vendor", "Sun Microsystems Inc." });
m.Invoke(properties, new string[] { "java.specification.name", "Java Platform API Specification" });
m.Invoke(properties, new string[] { "java.class.version", "48.0" });
string classpath = Environment.GetEnvironmentVariable("CLASSPATH");
if(classpath == null)
{
@ -390,15 +371,20 @@ namespace NativeCode.java
m.Invoke(properties, new string[] { "java.io.tmpdir", Path.GetTempPath() });
m.Invoke(properties, new string[] { "java.compiler", "" });
m.Invoke(properties, new string[] { "java.ext.dirs", "" });
m.Invoke(properties, new string[] { "os.name", "Windows" });
m.Invoke(properties, new string[] { "os.arch", "" });
m.Invoke(properties, new string[] { "os.version", Environment.OSVersion.ToString() });
// NOTE os.name *must* contain "Windows" when running on Windows, because Classpath tests on that
string osname = Environment.OSVersion.ToString();
string osver = Environment.OSVersion.Version.ToString();
// HACK if the osname contains the version, we remove it
osname = osname.Replace(osver, "").Trim();
m.Invoke(properties, new string[] { "os.name", osname });
m.Invoke(properties, new string[] { "os.arch", Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") });
m.Invoke(properties, new string[] { "os.version", osver });
m.Invoke(properties, new string[] { "file.separator", Path.DirectorySeparatorChar.ToString() });
m.Invoke(properties, new string[] { "file.encoding", "8859_1" });
m.Invoke(properties, new string[] { "path.separator", Path.PathSeparator.ToString() });
m.Invoke(properties, new string[] { "line.separator", Environment.NewLine });
m.Invoke(properties, new string[] { "user.name", Environment.UserName });
m.Invoke(properties, new string[] { "user.home", "" });
m.Invoke(properties, new string[] { "user.home", Environment.GetEnvironmentVariable("USERPROFILE") });
m.Invoke(properties, new string[] { "user.dir", Environment.CurrentDirectory });
m.Invoke(properties, new string[] { "awt.toolkit", "ikvm.awt.NetToolkit, awt, Version=1.0, Culture=neutral, PublicKeyToken=null" });
}
@ -416,6 +402,7 @@ namespace NativeCode.java
public static int nativeLoad(object obj, string filename)
{
// TODO native libraries somehow need to be scoped by class loader
return JVM.JniProvider.LoadNativeLibrary(filename);
}
@ -656,39 +643,6 @@ namespace NativeCode.java
}
}
/* not used anymore
public class System
{
public static bool isWordsBigEndian()
{
return !BitConverter.IsLittleEndian;
}
private static long timebase = ((TimeZone.CurrentTimeZone.ToUniversalTime(DateTime.Now) - new DateTime(1970, 1, 1)).Ticks / 10000L) - Environment.TickCount;
public static long currentTimeMillis()
{
// NOTE this wraps after 24.9 days, but it is much faster than calling DateTime.Now every time
return timebase + Environment.TickCount;
}
public static void setErr0(object printStream)
{
ClassLoaderWrapper.GetType("java.lang.System").GetField("err", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, printStream);
}
public static void setIn0(object inputStream)
{
ClassLoaderWrapper.GetType("java.lang.System").GetField("in", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, inputStream);
}
public static void setOut0(object printStream)
{
ClassLoaderWrapper.GetType("java.lang.System").GetField("out", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, printStream);
}
}
*/
public class VMSystem
{
public static void arraycopy(object src, int srcStart, object dest, int destStart, int len)

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

@ -481,7 +481,7 @@ class Compiler
throw new NotImplementedException("branch into try block not implemented: " + clazz.Name + "." + m.Method.Name + m.Method.Signature + " (index = " + exceptionIndex + ", pc = " + instr.PC + ")");
}
// every instruction has an associated label, for now
// TODO for now, every instruction has an associated label, optimize this
if(true)
{
object label = labels[instr.PC];
@ -991,166 +991,147 @@ class Compiler
thisType = null;
}
MethodWrapper method = (thisType != null) ? GetMethod(cpi, thisType, instr.NormalizedOpCode) : null;
CodeEmitter emit = null;
if(instr.NormalizedOpCode == NormalizedByteCode.__invokespecial)
{
if(cpi.Name == "<init>")
emit = method.EmitCall;
}
else
{
emit = method.EmitCallvirt;
}
if(instr.NormalizedOpCode == NormalizedByteCode.__invokespecial && cpi.Name == "<init>")
{
if(VerifierTypeWrapper.IsNew(type))
{
if(VerifierTypeWrapper.IsNew(type))
if(!thisType.IsUnloadable && (thisType.IsAbstract || thisType.IsInterface))
{
if(!thisType.IsUnloadable && (thisType.IsAbstract || thisType.IsInterface))
// the CLR gets confused when we do a newobj on an abstract class,
// so we set method to null, to basically just comment out the constructor
// call (the InstantiationError was already emitted at the "new" bytecode)
method = null;
}
// we have to construct a list of all the unitialized references to the object
// we're about to create on the stack, so that we can reconstruct the stack after
// the "newobj" instruction
int trivcount = 0;
bool nontrivial = false;
bool[] stackfix = new bool[ma.GetStackHeight(i) - (argcount + 1)];
bool[] localsfix = new bool[m.MaxLocals];
for(int j = 0; j < stackfix.Length; j++)
{
if(ma.GetRawStackTypeWrapper(i, argcount + 1 + j) == type)
{
// the CLR gets confused when we do a newobj on an abstract class,
// so we set method to null, to basically just comment out the constructor
// call (the InstantiationError was already emitted at the "new" bytecode)
method = null;
stackfix[j] = true;
if(trivcount == j)
{
trivcount++;
}
else
{
// if there is other stuff on the stack between the new object
// references, we need to do more work to construct the proper stack
// layout after the newobj instruction
nontrivial = true;
}
}
// we have to construct a list of all the unitialized references to the object
// we're about to create on the stack, so that we can reconstruct the stack after
// the "newobj" instruction
int trivcount = 0;
bool nontrivial = false;
bool[] stackfix = new bool[ma.GetStackHeight(i) - (argcount + 1)];
bool[] localsfix = new bool[m.MaxLocals];
}
for(int j = 0; j < localsfix.Length; j++)
{
if(ma.GetLocalTypeWrapper(i, j) == type)
{
localsfix[j] = true;
nontrivial = true;
}
}
if(method != null)
{
method.EmitNewobj.Emit(ilGenerator);
}
else
{
for(int j = 0; j < argcount; j++)
{
ilGenerator.Emit(OpCodes.Pop);
}
ilGenerator.Emit(OpCodes.Ldnull);
}
if(java_lang_Throwable == null)
{
java_lang_Throwable = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName("java/lang/Throwable");
}
if(thisType.IsSubTypeOf(java_lang_Throwable))
{
// HACK if the next instruction isn't an athrow, we need to
// call fillInStackTrace, because the object might be used
// to print out a stack trace without ever being thrown
if(code[i + 1].NormalizedOpCode != NormalizedByteCode.__athrow)
{
ilGenerator.Emit(OpCodes.Dup);
ilGenerator.Emit(OpCodes.Call, fillInStackTraceMethod);
ilGenerator.Emit(OpCodes.Pop);
}
}
if(nontrivial)
{
// this could be done a little more efficiently, but since in practice this
// code never runs (for code compiled from Java source) it doesn't
// really matter
LocalBuilder newobj = ilGenerator.DeclareLocal(thisType.Type);
ilGenerator.Emit(OpCodes.Stloc, newobj);
LocalBuilder[] tempstack = new LocalBuilder[stackfix.Length];
for(int j = 0; j < stackfix.Length; j++)
{
if(ma.GetRawStackTypeWrapper(i, argcount + 1 + j) == type)
if(!stackfix[j])
{
stackfix[j] = true;
if(trivcount == j)
TypeWrapper stacktype = ma.GetRawStackTypeWrapper(i, argcount + 1 + j);
// it could be another new object reference (not from current invokespecial <init>
// instruction)
if(stacktype == VerifierTypeWrapper.Null)
{
trivcount++;
// TODO handle null stack entries
throw new NotImplementedException();
}
else
else if(!VerifierTypeWrapper.IsNew(stacktype))
{
// if there is other stuff on the stack between the new object
// references, we need to do more work to construct the proper stack
// layout after the newobj instruction
nontrivial = true;
LocalBuilder lb = ilGenerator.DeclareLocal(stacktype.TypeOrUnloadableAsObject);
ilGenerator.Emit(OpCodes.Stloc, lb);
tempstack[j] = lb;
}
}
}
for(int j = stackfix.Length - 1; j >= 0; j--)
{
if(stackfix[j])
{
ilGenerator.Emit(OpCodes.Ldloc, newobj);
}
else if(tempstack[j] != null)
{
ilGenerator.Emit(OpCodes.Ldloc, tempstack[j]);
}
}
for(int j = 0; j < localsfix.Length; j++)
{
if(ma.GetLocalTypeWrapper(i, j) == type)
if(localsfix[j])
{
localsfix[j] = true;
nontrivial = true;
}
}
if(method != null)
{
method.EmitNewobj.Emit(ilGenerator);
}
else
{
for(int j = 0; j < argcount; j++)
{
ilGenerator.Emit(OpCodes.Pop);
}
ilGenerator.Emit(OpCodes.Ldnull);
}
if(java_lang_Throwable == null)
{
java_lang_Throwable = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName("java/lang/Throwable");
}
if(thisType.IsSubTypeOf(java_lang_Throwable))
{
// HACK if the next instruction isn't an athrow, we need to
// call fillInStackTrace, because the object might be used
// to print out a stack trace without ever being thrown
if(code[i + 1].NormalizedOpCode != NormalizedByteCode.__athrow)
{
ilGenerator.Emit(OpCodes.Dup);
ilGenerator.Emit(OpCodes.Call, fillInStackTraceMethod);
ilGenerator.Emit(OpCodes.Pop);
}
}
if(nontrivial)
{
// this could be done a little more efficiently, but since in practice this
// code never runs (for code compiled from Java source) it doesn't
// really matter
LocalBuilder newobj = ilGenerator.DeclareLocal(thisType.Type);
ilGenerator.Emit(OpCodes.Stloc, newobj);
LocalBuilder[] tempstack = new LocalBuilder[stackfix.Length];
for(int j = 0; j < stackfix.Length; j++)
{
if(!stackfix[j])
{
TypeWrapper stacktype = ma.GetRawStackTypeWrapper(i, argcount + 1 + j);
// it could be another new object reference (not from current invokespecial <init>
// instruction)
if(stacktype == VerifierTypeWrapper.Null)
{
// TODO handle null stack entries
throw new NotImplementedException();
}
else if(!VerifierTypeWrapper.IsNew(stacktype))
{
LocalBuilder lb = ilGenerator.DeclareLocal(stacktype.TypeOrUnloadableAsObject);
ilGenerator.Emit(OpCodes.Stloc, lb);
tempstack[j] = lb;
}
}
}
for(int j = stackfix.Length - 1; j >= 0; j--)
{
if(stackfix[j])
{
ilGenerator.Emit(OpCodes.Ldloc, newobj);
}
else if(tempstack[j] != null)
{
ilGenerator.Emit(OpCodes.Ldloc, tempstack[j]);
}
}
for(int j = 0; j < localsfix.Length; j++)
{
if(localsfix[j])
{
ilGenerator.Emit(OpCodes.Ldloc, newobj);
ilGenerator.Emit(OpCodes.Stloc, GetLocal(typeof(object), j));
}
}
}
else
{
if(trivcount == 0)
{
ilGenerator.Emit(OpCodes.Pop);
}
else
{
for(int j = 1; j < trivcount; j++)
{
ilGenerator.Emit(OpCodes.Dup);
}
ilGenerator.Emit(OpCodes.Ldloc, newobj);
ilGenerator.Emit(OpCodes.Stloc, GetLocal(typeof(object), j));
}
}
}
else
{
if(method != null)
if(trivcount == 0)
{
method.EmitCall.Emit(ilGenerator);
ilGenerator.Emit(OpCodes.Pop);
}
else
{
// if we're a constructor and the call to the base class constructor
// wasn't accessible, we need make sure that there is no code path that
// returns from the constructor, otherwise the method will be not verifiable
// TODO this isn't anywhere near a proper solution, but for the time being it works
// some things to consider:
// - only pull this full when calls to the base class constructor fail
// - when control flow is complex, this trivial solution will not work
ilGenerator.Emit(OpCodes.Ldnull);
ilGenerator.Emit(OpCodes.Throw);
return;
// for(int j = 0; j < argcount + 1; j++)
// {
// ilGenerator.Emit(OpCodes.Pop);
// }
// EmitPlaceholder(cpi.Signature.Substring(cpi.Signature.LastIndexOf(')') + 1));
for(int j = 1; j < trivcount; j++)
{
ilGenerator.Emit(OpCodes.Dup);
}
}
}
}
@ -1162,19 +1143,29 @@ class Compiler
}
else
{
for(int j = 0; j < argcount + 1; j++)
{
ilGenerator.Emit(OpCodes.Pop);
}
EmitPlaceholder(cpi.GetRetType(classLoader));
// if we're a constructor and the call to the base class constructor
// wasn't accessible, we need make sure that there is no code path that
// returns from the constructor, otherwise the method will be not verifiable
// TODO this isn't anywhere near a proper solution, but for the time being it works
// some things to consider:
// - only pull this full when calls to the base class constructor fail
// - when control flow is complex, this trivial solution will not work
ilGenerator.Emit(OpCodes.Ldnull);
ilGenerator.Emit(OpCodes.Throw);
return;
// for(int j = 0; j < argcount + 1; j++)
// {
// ilGenerator.Emit(OpCodes.Pop);
// }
// EmitPlaceholder(cpi.Signature.Substring(cpi.Signature.LastIndexOf(')') + 1));
}
}
}
else
{
if(method != null)
if(emit != null)
{
method.EmitCallvirt.Emit(ilGenerator);
emit.Emit(ilGenerator);
}
else
{
@ -2244,7 +2235,7 @@ class Compiler
// we cannot use EmitError, because that will yield an invalid constructor (that doesn't call the superclass constructor)
if(IsUnloadable(cpi))
{
MethodWrapper dummy = new MethodWrapper(null, null, null, Modifiers.Synthetic);
MethodWrapper dummy = new MethodWrapper(null, null, null, null, Modifiers.Synthetic);
if(invoke == NormalizedByteCode.__invokespecial)
{
dummy.EmitNewobj = new DynamicNewEmitter(classLoader, clazz, cpi);

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

@ -1599,7 +1599,8 @@ class MethodAnalyzer
}
case NormalizedByteCode.__monitorenter:
case NormalizedByteCode.__monitorexit:
// TODO is this allowed to be an uninitialized object?
// TODO these bytecodes are allowed on an uninitialized object, but
// we don't support that at the moment...
s.PopObjectType();
break;
case NormalizedByteCode.__return:

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

@ -1,316 +0,0 @@
/*
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.awt;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.image.*;
import java.awt.peer.*;
import java.net.*;
import java.util.*;
import java.awt.List;
public class NetToolkit extends Toolkit
{
private static EventQueue eventQueue = new EventQueue();
// NOTE "native" is just an easy way to say I haven't implemented it yet
protected java.awt.peer.ButtonPeer createButton(Button target) throws HeadlessException
{
return new NetButtonPeer();
}
protected java.awt.peer.TextFieldPeer createTextField(TextField target) throws HeadlessException
{
return new NetTextFieldPeer();
}
protected native java.awt.peer.LabelPeer createLabel(Label target) throws HeadlessException;
protected native java.awt.peer.ListPeer createList(List target) throws HeadlessException;
protected native java.awt.peer.CheckboxPeer createCheckbox(Checkbox target)
throws HeadlessException;
protected native java.awt.peer.ScrollbarPeer createScrollbar(Scrollbar target)
throws HeadlessException;
protected native java.awt.peer.ScrollPanePeer createScrollPane(ScrollPane target)
throws HeadlessException;
protected java.awt.peer.TextAreaPeer createTextArea(TextArea target) throws HeadlessException
{
return new NetTextAreaPeer();
}
protected native java.awt.peer.ChoicePeer createChoice(Choice target)
throws HeadlessException;
protected java.awt.peer.FramePeer createFrame(Frame target) throws HeadlessException
{
return new NetFramePeer();
}
protected native java.awt.peer.CanvasPeer createCanvas(Canvas target);
protected java.awt.peer.PanelPeer createPanel(Panel target)
{
return new NetPanelPeer();
}
protected native java.awt.peer.WindowPeer createWindow(Window target)
throws HeadlessException;
protected native java.awt.peer.DialogPeer createDialog(Dialog target)
throws HeadlessException;
protected native java.awt.peer.MenuBarPeer createMenuBar(MenuBar target)
throws HeadlessException;
protected native java.awt.peer.MenuPeer createMenu(Menu target)
throws HeadlessException;
protected native java.awt.peer.PopupMenuPeer createPopupMenu(PopupMenu target)
throws HeadlessException;
protected native java.awt.peer.MenuItemPeer createMenuItem(MenuItem target)
throws HeadlessException;
protected native java.awt.peer.FileDialogPeer createFileDialog(FileDialog target)
throws HeadlessException;
protected native java.awt.peer.CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target)
throws HeadlessException;
protected native java.awt.peer.FontPeer getFontPeer(String name, int style);
public native Dimension getScreenSize() throws HeadlessException;
public native int getScreenResolution() throws HeadlessException;
public native ColorModel getColorModel()
throws HeadlessException;
public native String[] getFontList();
public native FontMetrics getFontMetrics(Font font);
public native void sync();
public native Image getImage(String filename);
public native Image getImage(URL url);
public native Image createImage(String filename);
public native Image createImage(URL url);
public native boolean prepareImage(Image image,
int width,
int height,
ImageObserver observer);
public native int checkImage(Image image,
int width,
int height,
ImageObserver observer);
public native Image createImage(ImageProducer producer);
public native Image createImage(byte[] imagedata,
int imageoffset,
int imagelength);
public native PrintJob getPrintJob(Frame frame,
String jobtitle,
Properties props);
public native void beep();
public native Clipboard getSystemClipboard()
throws HeadlessException;
protected EventQueue getSystemEventQueueImpl()
{
return eventQueue;
}
// public native java.awt.dnd.peer.DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge)
// throws InvalidDnDOperationException;
// public native Map mapInputMethodHighlight(InputMethodHighlight highlight)
// throws HeadlessException;
}
class NetComponentPeer implements ComponentPeer
{
public native int checkImage(Image img, int width, int height, ImageObserver ob);
public native Image createImage(ImageProducer prod);
public native Image createImage(int width, int height);
public native void disable();
public native void dispose();
public native void enable();
public native ColorModel getColorModel();
public native FontMetrics getFontMetrics(Font f);
public native Graphics getGraphics();
public native Point getLocationOnScreen();
public native Dimension getMinimumSize();
public Dimension getPreferredSize()
{
System.out.println("NOTE: NetComponentPeer.getPreferredSize not implemented");
return new Dimension(0, 0);
}
public Toolkit getToolkit()
{
return Toolkit.getDefaultToolkit();
}
public native void handleEvent(AWTEvent e);
public native void hide();
public native boolean isFocusTraversable();
public native Dimension minimumSize();
public Dimension preferredSize()
{
System.out.println("NOTE: NetComponentPeer.preferredSize not implemented");
return new Dimension(0, 0);
}
public native void paint(Graphics graphics);
public native boolean prepareImage(Image img, int width, int height, ImageObserver ob);
public native void print(Graphics graphics);
public native void repaint(long tm, int x, int y, int width, int height);
public native void requestFocus();
public native void reshape(int x, int y, int width, int height);
public native void setBackground(Color color);
public native void setBounds(int x, int y, int width, int height);
public native void setCursor(Cursor cursor);
public void setEnabled(boolean enabled)
{
System.out.println("NOTE: NetComponentPeer.setEnabled not implemented");
}
public native void setFont(Font font);
public native void setForeground(Color color);
public void setVisible(boolean visible)
{
System.out.println("NOTE: NetComponentPeer.setVisible not implemented");
}
public native void show();
public native GraphicsConfiguration getGraphicsConfiguration();
public void setEventMask (long mask)
{
System.out.println("NOTE: NetComponentPeer.setEventMask not implemented");
}
}
class NetButtonPeer extends NetComponentPeer implements ButtonPeer
{
public native void setLabel(String label);
}
class NetTextComponentPeer extends NetComponentPeer implements TextComponentPeer
{
public native int getSelectionEnd();
public native int getSelectionStart();
public String getText()
{
System.out.println("NOTE: NetTextComponentPeer.getText not implemented");
return "";
}
public void setText(String text)
{
System.out.println("NOTE: NetTextComponentPeer.setText not implemented");
}
public native void select(int start_pos, int end_pos);
public native void setEditable(boolean editable);
public native int getCaretPosition();
public native void setCaretPosition(int pos);
}
class NetTextFieldPeer extends NetTextComponentPeer implements TextFieldPeer
{
public native Dimension minimumSize(int len);
public native Dimension preferredSize(int len);
public native Dimension getMinimumSize(int len);
public Dimension getPreferredSize(int len)
{
System.out.println("NOTE: NetTextFieldPeer.getPreferredSize not implemented");
return new Dimension(0, 0);
}
public native void setEchoChar(char echo_char);
public native void setEchoCharacter(char echo_char);
}
class NetTextAreaPeer extends NetTextComponentPeer implements TextAreaPeer
{
public void insert(String text, int pos)
{
System.out.println("NOTE: NetTextAreaPeer.insert not implemented");
}
public native void insertText(String text, int pos);
public native Dimension minimumSize(int rows, int cols);
public native Dimension getMinimumSize(int rows, int cols);
public native Dimension preferredSize(int rows, int cols);
public Dimension getPreferredSize(int rows, int cols)
{
System.out.println("NOTE: NetTextAreaPeer.getPreferredSize not implemented");
return new Dimension(0, 0);
}
public native void replaceRange(String text, int start_pos, int end_pos);
public native void replaceText(String text, int start_pos, int end_pos);
}
class NetContainerPeer extends NetComponentPeer implements ContainerPeer
{
public native Insets insets();
public Insets getInsets()
{
System.out.println("NOTE: NetContainerPeer.getInsets not implemented");
return new Insets(0, 0, 0, 0);
}
public void beginValidate()
{
System.out.println("NOTE: NetContainerPeer.beginValidate not implemented");
}
public void endValidate()
{
System.out.println("NOTE: NetContainerPeer.endValidate not implemented");
}
}
class NetPanelPeer extends NetContainerPeer implements PanelPeer
{
}
class NetWindowPeer extends NetContainerPeer implements WindowPeer
{
public native void toBack();
public void toFront()
{
System.out.println("NOTE: NetWindowPeer.toFront not implemented");
}
}
class NetFramePeer extends NetWindowPeer implements FramePeer
{
NetFramePeer()
{
}
public native void setIconImage(Image image);
public native void setMenuBar(MenuBar mb);
public native void setResizable(boolean resizable);
public native void setTitle(String title);
}

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

@ -248,35 +248,18 @@ public final class Constructor
throws InstantiationException, IllegalAccessException,
InvocationTargetException
{
return Method.Invoke(methodCookie, null, args);
/*
if(Modifier.isAbstract(clazz.getModifiers()))
{
throw new InstantiationException();
}
// TODO check args and accessibility
try
{
if(false) throw new MemberAccessException();
if(false) throw new ArgumentException();
if(false) throw new TargetParameterCountException();
if(false) throw new TargetInvocationException(null);
// TODO wrappers need to be unwrapped (e.g. java.lang.Integer -> boxed System.Int32)
return ci.Invoke(args);
return Method.Invoke(methodCookie, null, args);
}
catch(MemberAccessException x1)
catch(Throwable x)
{
throw new IllegalAccessException(x1.get_Message());
throw new InvocationTargetException(x);
}
catch(ArgumentException x2)
{
throw new IllegalArgumentException();
}
catch(TargetParameterCountException x3)
{
throw new IllegalArgumentException();
}
catch(TargetInvocationException x4)
{
InstantiationException ie = new InstantiationException();
ie.initCause(Method.mapException(x4.get_InnerException()));
throw ie;
}
*/
}
}

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

@ -307,70 +307,16 @@ public final class Method extends AccessibleObject implements Member
public Object invoke(Object o, Object[] args)
throws IllegalAccessException, InvocationTargetException
{
// TODO
return Invoke(methodCookie, o, args);
/*
// TODO check args and accessibility
try
{
if(false) throw new MemberAccessException();
if(false) throw new ArgumentException();
if(false) throw new TargetParameterCountException();
if(false) throw new TargetInvocationException(null);
ParameterInfo[] params = method.GetParameters();
for(int i = 0; i < params.length; i++)
{
Type type = params[i].get_ParameterType();
if(type.get_IsPrimitive())
{
if(type == BoxHelper.INT)
{
args[i] = BoxHelper.boxInteger(((Integer)args[i]).intValue());
}
else if(type == BoxHelper.BOOLEAN)
{
args[i] = BoxHelper.boxBoolean(((java.lang.Boolean)args[i]).booleanValue());
}
else
{
throw new InternalError("method invoke arg boxing not implemented for " + type.get_FullName());
}
}
}
// TODO wrappers need to be unwrapped (e.g. java.lang.Integer -> boxed System.Int32)
Object retval = method.Invoke(o, args);
Type rettype = method.get_ReturnType();
if(rettype.get_IsPrimitive())
{
if(rettype == BoxHelper.INT)
{
retval = new Integer(BoxHelper.unboxInteger(retval));
}
else
{
throw new InternalError("method invoke retval unboxing not implemented for " + rettype.get_FullName());
}
}
return retval;
return Invoke(methodCookie, o, args);
}
catch(MemberAccessException x1)
catch(Throwable x)
{
throw new IllegalAccessException(x1.get_Message());
throw new InvocationTargetException(x);
}
catch(ArgumentException x2)
{
throw new IllegalArgumentException();
}
catch(TargetParameterCountException x3)
{
throw new IllegalArgumentException();
}
catch(TargetInvocationException x4)
{
throw new InvocationTargetException(mapException(x4.get_InnerException()));
}
*/
}
static native Object Invoke(Object methodCookie, Object o, Object[] args);
static native Throwable mapException(Throwable x);
static native Object Invoke(Object methodCookie, Object o, Object[] args);
}