start work on reflection; bugfixes

This commit is contained in:
Joel Dice 2007-07-23 19:44:20 -06:00
parent 472ecb1713
commit 5f3bf175e0
12 changed files with 575 additions and 136 deletions

View File

@ -1,5 +1,8 @@
package java.lang; package java.lang;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
public final class Class <T> { public final class Class <T> {
private short flags; private short flags;
private byte vmFlags; private byte vmFlags;
@ -9,16 +12,57 @@ public final class Class <T> {
private int[] objectMask; private int[] objectMask;
private byte[] name; private byte[] name;
private Class super_; private Class super_;
private Object interfaceTable; private Object[] interfaceTable;
private Object virtualTable; private Method[] virtualTable;
private Object fieldTable; private Field[] fieldTable;
private Object methodTable; private Method[] methodTable;
private Object staticTable; private Object[] staticTable;
private Object initializer; private Method initializer;
private Class() { } private Class() { }
public String getName() { public String getName() {
return new String(name, 0, name.length - 1, false); return new String(name, 0, name.length - 1, false);
} }
public static native Class forName(String name);
public native boolean isAssignableFrom(Class c);
public Field getDeclaredField(String name) throws NoSuchFieldException {
for (int i = 0; i < fieldTable.length; ++i) {
if (fieldTable[i].getName().equals(name)) {
return fieldTable[i];
}
}
throw new NoSuchFieldException(name);
}
private static boolean match(Class[] a, Class[] b) {
if (a.length == b.length) {
for (int i = 0; i < a.length; ++i) {
if (! a[i].isAssignableFrom(b[i])) {
return false;
}
}
return true;
} else {
return false;
}
}
public Method getDeclaredMethod(String name, Class ... parameterTypes)
throws NoSuchMethodException
{
for (int i = 0; i < methodTable.length; ++i) {
if (methodTable[i].getName().equals(name)
&& match(parameterTypes, methodTable[i].getParameterTypes()))
{
return methodTable[i];
}
}
throw new NoSuchMethodException(name);
}
} }

View File

@ -30,4 +30,6 @@ public class Field<T> extends AccessibleObject {
public String getName() { public String getName() {
return new String(name, 0, name.length - 1, false); return new String(name, 0, name.length - 1, false);
} }
public native Object get(Object instance);
} }

View File

@ -32,4 +32,49 @@ public class Method<T> extends AccessibleObject implements Member {
public String getName() { public String getName() {
return new String(name, 0, name.length - 1, false); return new String(name, 0, name.length - 1, false);
} }
private static int next(char c, String s, int start) {
for (int i = start; i < s.length(); ++i) {
if (s.charAt(i) == c) return i;
}
throw new RuntimeException();
}
public Class[] getParameterTypes() {
int count = parameterCount;
if ((flags & Modifier.STATIC) == 0) {
-- count;
}
Class[] types = new Class[count];
int index = 0;
String spec = new String(this.spec, 1, this.spec.length - 1, false);
for (int i = 0; i < spec.length(); ++i) {
char c = spec.charAt(i);
if (c == 'L') {
String name = spec.substring(i + 1, next(';', spec, i + 1));
types[index++] = Class.forName(name);
} else if (c == '[') {
int start = i;
while (spec.charAt(i) == '[') ++i;
if (spec.charAt(i) == 'L') {
String name = spec.substring(start, next(';', spec, i + 1));
types[index++] = Class.forName(name);
} else {
String name = spec.substring(start, i + 1);
types[index++] = Class.forName(name);
}
} else {
String name = spec.substring(i, i + 1);
types[index++] = Class.forName(name);
}
}
return types;
}
public native Object invoke(Object instance, Object ... arguments);
} }

View File

@ -16,7 +16,7 @@ src = src
classpath = classpath classpath = classpath
test = test test = test
input = $(cls)/References.class input = $(cls)/Reflection.class
cxx = g++ cxx = g++
cc = gcc cc = gcc

View File

@ -1,7 +1,30 @@
#include "builtin.h" #include "builtin.h"
#include "machine.h" #include "machine.h"
#include "constants.h"
#include "run.h" #include "run.h"
using namespace vm;
namespace {
object
doInvoke(Thread* t, object this_, object instance, object arguments)
{
object v = pushReference(t, run2(t, this_, instance, arguments));
if (t->exception) {
t->exception = makeInvocationTargetException(t, t->exception);
}
return v;
}
inline void
replace(char a, char b, char* c)
{
for (; *c; ++c) if (*c == a) *c = b;
}
} // namespace
namespace vm { namespace vm {
namespace builtin { namespace builtin {
@ -41,6 +64,142 @@ notifyAll(Thread* t, jobject this_)
vm::notifyAll(t, *this_); vm::notifyAll(t, *this_);
} }
jclass
forName(Thread* t, jstring name)
{
if (LIKELY(name)) {
object n = makeByteArray(t, stringLength(t, *name) + 1, false);
char* s = reinterpret_cast<char*>(&byteArrayBody(t, n, 0));
stringChars(t, *name, s);
replace('.', '/', s);
object c = resolveClass(t, n);
if (t->exception) {
return 0;
}
object clinit = classInitializer(t, c);
if (clinit) {
PROTECT(t, c);
set(t, classInitializer(t, c), 0);
run(t, clinit, 0);
}
return pushReference(t, c);
} else {
t->exception = makeNullPointerException(t);
return 0;
}
}
jboolean
isAssignableFrom(Thread* t, jobject this_, jclass that)
{
if (LIKELY(that)) {
return vm::isAssignableFrom(t, *this_, *that);
} else {
t->exception = makeNullPointerException(t);
return 0;
}
}
jobject
get(Thread* t, jobject this_, jobject instancep)
{
object field = *this_;
if (fieldFlags(t, field) & ACC_STATIC) {
return pushReference
(t, arrayBody(t, classStaticTable(t, fieldClass(t, field)),
fieldOffset(t, field)));
} else if (instancep) {
object instance = *instancep;
if (instanceOf(t, fieldClass(t, this_), instance)) {
switch (fieldCode(t, field)) {
case ByteField:
return pushReference
(t, makeByte(t, cast<int8_t>(instance, fieldOffset(t, field))));
case BooleanField:
return pushReference
(t, makeBoolean(t, cast<uint8_t>(instance, fieldOffset(t, field))));
case CharField:
return pushReference
(t, makeChar(t, cast<uint16_t>(instance, fieldOffset(t, field))));
case ShortField:
return pushReference
(t, makeShort(t, cast<int16_t>(instance, fieldOffset(t, field))));
case FloatField:
return pushReference
(t, makeFloat(t, cast<uint32_t>(instance, fieldOffset(t, field))));
case IntField:
return pushReference
(t, makeInt(t, cast<int32_t>(instance, fieldOffset(t, field))));
case DoubleField:
return pushReference
(t, makeDouble(t, cast<uint64_t>(instance, fieldOffset(t, field))));
case LongField:
return pushReference
(t, makeLong(t, cast<int64_t>(instance, fieldOffset(t, field))));
case ObjectField:
return pushReference
(t, cast<object>(instance, fieldOffset(t, field)));
default:
abort(t);
}
} else {
t->exception = makeIllegalArgumentException(t);
return 0;
}
} else {
t->exception = makeNullPointerException(t);
return 0;
}
}
jobject
invoke(Thread* t, jobject this_, jobject instance, jobjectArray arguments)
{
object method = *this_;
if (arguments) {
if (methodFlags(t, method) & ACC_STATIC) {
if (objectArrayLength(t, arguments) == methodParameterCount(t, method)) {
return pushReference(t, doInvoke(t, method, 0, *arguments));
} else {
t->exception = makeArrayIndexOutOfBoundsException(t, 0);
}
} else if (instance) {
if (instanceOf(t, methodClass(t, method), instance)) {
if (objectArrayLength(t, arguments)
== static_cast<unsigned>(methodParameterCount(t, method) - 1))
{
return pushReference(t, doInvoke(t, method, *instance, *arguments));
} else {
t->exception = makeArrayIndexOutOfBoundsException(t, 0);
}
}
} else {
t->exception = makeNullPointerException(t);
}
} else {
t->exception = makeNullPointerException(t);
}
return 0;
}
jobject jobject
currentThread(Thread* t) currentThread(Thread* t)
{ {
@ -104,15 +263,14 @@ currentTimeMillis(Thread* t)
} }
void void
loadLibrary(Thread* t, jobject, jstring nameString) loadLibrary(Thread* t, jobject, jstring name)
{ {
if (LIKELY(nameString)) { if (LIKELY(name)) {
object n = *nameString; char n[stringLength(t, *name) + 1];
char name[stringLength(t, n) + 1]; stringChars(t, *name, n);
stringChars(t, n, name);
for (System::Library* lib = t->vm->libraries; lib; lib = lib->next()) { for (System::Library* lib = t->vm->libraries; lib; lib = lib->next()) {
if (::strcmp(lib->name(), name) == 0) { if (::strcmp(lib->name(), n) == 0) {
// already loaded // already loaded
return; return;
} }
@ -120,11 +278,11 @@ loadLibrary(Thread* t, jobject, jstring nameString)
System::Library* lib; System::Library* lib;
if (LIKELY(t->vm->system->success if (LIKELY(t->vm->system->success
(t->vm->system->load(&lib, name, t->vm->libraries)))) (t->vm->system->load(&lib, n, t->vm->libraries))))
{ {
t->vm->libraries = lib; t->vm->libraries = lib;
} else { } else {
object message = makeString(t, "library not found: %s", name); object message = makeString(t, "library not found: %s", n);
t->exception = makeRuntimeException(t, message); t->exception = makeRuntimeException(t, message);
} }
} else { } else {
@ -211,8 +369,7 @@ start(Thread* t, jobject this_)
object message = makeString(t, "thread already started"); object message = makeString(t, "thread already started");
t->exception = makeIllegalStateException(t, message); t->exception = makeIllegalStateException(t, message);
} else { } else {
p = new (t->vm->system->allocate(sizeof(Thread))) p = new (t->vm->system->allocate(sizeof(Thread))) Thread(t->vm, *this_, t);
Thread(t->vm, t->vm->system, *this_, t);
enter(p, Thread::ActiveState); enter(p, Thread::ActiveState);
@ -253,6 +410,15 @@ populate(Thread* t, object map)
const char* key; const char* key;
void* value; void* value;
} builtins[] = { } builtins[] = {
{ "Java_java_lang_Class_forName",
reinterpret_cast<void*>(forName) },
{ "Java_java_lang_Field_get",
reinterpret_cast<void*>(get) },
{ "Java_java_lang_Method_invoke",
reinterpret_cast<void*>(invoke) },
{ "Java_java_lang_System_arraycopy", { "Java_java_lang_System_arraycopy",
reinterpret_cast<void*>(arraycopy) }, reinterpret_cast<void*>(arraycopy) },

View File

@ -1,12 +1,8 @@
#include "sys/mman.h" #include "sys/mman.h"
#include "sys/types.h" #include "sys/types.h"
#include "sys/stat.h" #include "sys/stat.h"
#include "fcntl.h" #include "fcntl.h"
#include "system.h" #include "system.h"
#include "class-finder.h" #include "class-finder.h"

View File

@ -1305,17 +1305,11 @@ Machine::dispose()
if (libraries) { if (libraries) {
libraries->dispose(); libraries->dispose();
} }
if (rootThread) {
rootThread->dispose();
}
} }
Thread::Thread(Machine* m, Allocator* allocator, object javaThread, Thread::Thread(Machine* m, object javaThread, Thread* parent):
Thread* parent):
vtable(&(m->jniEnvVTable)), vtable(&(m->jniEnvVTable)),
vm(m), vm(m),
allocator(allocator),
parent(parent), parent(parent),
peer((parent ? parent->child : 0)), peer((parent ? parent->child : 0)),
child(0), child(0),
@ -1423,9 +1417,7 @@ Thread::dispose()
heap = 0; heap = 0;
#endif // VM_STRESS #endif // VM_STRESS
if (allocator) { vm->system->free(this);
allocator->free(this);
}
} }
void void
@ -1633,6 +1625,39 @@ stringChars(Thread* t, object string, char* chars)
chars[stringLength(t, string)] = 0; chars[stringLength(t, string)] = 0;
} }
bool
isAssignableFrom(Thread* t, object a, object b)
{
if (classFlags(t, a) & ACC_INTERFACE) {
for (; b; b = classSuper(t, b)) {
object itable = classInterfaceTable(t, b);
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable, i) == a) {
return true;
}
}
}
} else {
for (; b; b = classSuper(t, b)) {
if (b == a) {
return true;
}
}
}
return false;
}
bool
instanceOf(Thread* t, object class_, object o)
{
if (o == 0) {
return false;
}
return isAssignableFrom(t, class_, objectClass(t, o));
}
unsigned unsigned
parameterFootprint(const char* s) parameterFootprint(const char* s)
{ {

View File

@ -22,7 +22,7 @@
namespace vm { namespace vm {
const bool Verbose = false; const bool Verbose = false;
const bool DebugRun = false; const bool DebugRun = true;
const bool DebugStack = false; const bool DebugStack = false;
const bool DebugMonitors = false; const bool DebugMonitors = false;
@ -1158,18 +1158,13 @@ class Thread {
static const unsigned HeapSizeInWords = HeapSizeInBytes / BytesPerWord; static const unsigned HeapSizeInWords = HeapSizeInBytes / BytesPerWord;
static const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord; static const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord;
Thread(Machine* m, Allocator* allocator, object javaThread, Thread* parent); Thread(Machine* m, object javaThread, Thread* parent);
~Thread() {
exit();
}
void exit(); void exit();
void dispose(); void dispose();
JNIEnvVTable* vtable; JNIEnvVTable* vtable;
Machine* vm; Machine* vm;
Allocator* allocator;
Thread* parent; Thread* parent;
Thread* peer; Thread* peer;
Thread* child; Thread* child;
@ -1382,6 +1377,12 @@ makeIllegalStateException(Thread* t, object message)
return makeIllegalStateException(t, message, trace, 0); return makeIllegalStateException(t, message, trace, 0);
} }
inline object
makeIllegalArgumentException(Thread* t)
{
return makeIllegalArgumentException(t, 0, makeTrace(t), 0);
}
inline object inline object
makeIllegalMonitorStateException(Thread* t) makeIllegalMonitorStateException(Thread* t)
{ {
@ -1432,6 +1433,14 @@ makeNullPointerException(Thread* t)
return makeNullPointerException(t, 0, makeTrace(t), 0); return makeNullPointerException(t, 0, makeTrace(t), 0);
} }
inline object
makeInvocationTargetException(Thread* t, object targetException)
{
PROTECT(t, targetException);
object trace = makeTrace(t);
return makeRuntimeException(t, 0, trace, targetException);
}
inline object inline object
makeStackOverflowError(Thread* t) makeStackOverflowError(Thread* t)
{ {
@ -1471,6 +1480,12 @@ makeString(Thread* t, const char* format, ...);
void void
stringChars(Thread* t, object string, char* chars); stringChars(Thread* t, object string, char* chars);
bool
isAssignableFrom(Thread* t, object a, object b);
bool
instanceOf(Thread* t, object class_, object o);
inline void inline void
pushObject(Thread* t, object o) pushObject(Thread* t, object o)
{ {
@ -1627,9 +1642,13 @@ pokeLong(Thread* t, unsigned index, uint64_t value)
inline object* inline object*
pushReference(Thread* t, object o) pushReference(Thread* t, object o)
{ {
if (o) {
expect(t, t->sp + 1 < Thread::StackSizeInWords / 2); expect(t, t->sp + 1 < Thread::StackSizeInWords / 2);
pushObject(t, o); pushObject(t, o);
return reinterpret_cast<object*>(t->stack + ((t->sp - 1) * 2) + 1); return reinterpret_cast<object*>(t->stack + ((t->sp - 1) * 2) + 1);
} else {
return 0;
}
} }
inline int inline int

View File

@ -106,33 +106,6 @@ setStatic(Thread* t, object field, object value)
fieldOffset(t, field)), value); fieldOffset(t, field)), value);
} }
bool
instanceOf(Thread* t, object class_, object o)
{
if (o == 0) {
return false;
}
if (classFlags(t, class_) & ACC_INTERFACE) {
for (object oc = objectClass(t, o); oc; oc = classSuper(t, oc)) {
object itable = classInterfaceTable(t, oc);
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable, i) == class_) {
return true;
}
}
}
} else {
for (object oc = objectClass(t, o); oc; oc = classSuper(t, oc)) {
if (oc == class_) {
return true;
}
}
}
return false;
}
object object
findInterfaceMethod(Thread* t, object method, object o) findInterfaceMethod(Thread* t, object method, object o)
{ {
@ -535,6 +508,8 @@ invokeNative(Thread* t, object method)
object object
run(Thread* t) run(Thread* t)
{ {
const int base = t->frame;
unsigned instruction = nop; unsigned instruction = nop;
unsigned& ip = t->ip; unsigned& ip = t->ip;
unsigned& sp = t->sp; unsigned& sp = t->sp;
@ -659,8 +634,8 @@ run(Thread* t)
case areturn: { case areturn: {
object result = popObject(t); object result = popObject(t);
if (frame > base) {
popFrame(t); popFrame(t);
if (frame >= 0) {
pushObject(t, result); pushObject(t, result);
goto loop; goto loop;
} else { } else {
@ -1451,8 +1426,8 @@ run(Thread* t)
case ireturn: { case ireturn: {
int32_t result = popInt(t); int32_t result = popInt(t);
if (frame > base) {
popFrame(t); popFrame(t);
if (frame >= 0) {
pushInt(t, result); pushInt(t, result);
goto loop; goto loop;
} else { } else {
@ -1710,8 +1685,8 @@ run(Thread* t)
case lreturn: { case lreturn: {
int64_t result = popLong(t); int64_t result = popLong(t);
if (frame > base) {
popFrame(t); popFrame(t);
if (frame >= 0) {
pushLong(t, result); pushLong(t, result);
goto loop; goto loop;
} else { } else {
@ -1993,8 +1968,8 @@ run(Thread* t)
} goto loop; } goto loop;
case return_: { case return_: {
if (frame > base) {
popFrame(t); popFrame(t);
if (frame >= 0) {
goto loop; goto loop;
} else { } else {
return 0; return 0;
@ -2249,32 +2224,14 @@ run(Thread* t, const char* className, int argc, const char** argv)
run(t, className, "main", "([Ljava/lang/String;)V", 0, args); run(t, className, "main", "([Ljava/lang/String;)V", 0, args);
} }
} // namespace void
pushArguments(Thread* t, object this_, const char* spec, va_list a)
namespace vm {
object
run(Thread* t, const char* className, const char* methodName,
const char* methodSpec, object this_, ...)
{ {
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
if (UNLIKELY(t->sp + parameterFootprint(methodSpec) + 1
> Thread::StackSizeInWords / 2))
{
t->exception = makeStackOverflowError(t);
return 0;
}
if (this_) { if (this_) {
pushObject(t, this_); pushObject(t, this_);
} }
va_list a; const char* s = spec;
va_start(a, this_);
const char* s = methodSpec;
++ s; // skip '(' ++ s; // skip '('
while (*s and *s != ')') { while (*s and *s != ')') {
switch (*s) { switch (*s) {
@ -2311,22 +2268,59 @@ run(Thread* t, const char* className, const char* methodName,
break; break;
} }
} }
}
va_end(a); void
pushArguments(Thread* t, object this_, const char* spec, object a)
{
if (this_) {
pushObject(t, this_);
}
object class_ = resolveClass(t, makeByteArray(t, "%s", className)); unsigned index = 0;
if (LIKELY(t->exception == 0)) { const char* s = spec;
PROTECT(t, class_); ++ s; // skip '('
while (*s and *s != ')') {
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
pushObject(t, objectArrayBody(t, a, index++));
break;
object name = makeByteArray(t, methodName); case '[':
PROTECT(t, name); while (*s == '[') ++ s;
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
break;
object spec = makeByteArray(t, methodSpec); default:
object reference = makeReference(t, class_, name, spec); ++ s;
break;
}
pushObject(t, objectArrayBody(t, a, index++));
break;
object method = findMethodInClass(t, class_, reference); case 'J':
if (LIKELY(t->exception == 0)) { case 'D':
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); ++ s;
pushLong(t, cast<int64_t>(objectArrayBody(t, a, index++), BytesPerWord));
break;
default:
++ s;
pushInt(t, cast<int32_t>(objectArrayBody(t, a, index++), BytesPerWord));
break;
}
}
}
object
invoke(Thread* t, object method)
{
object result = 0;
if (methodFlags(t, method) & ACC_NATIVE) { if (methodFlags(t, method) & ACC_NATIVE) {
unsigned returnCode = invokeNative(t, method); unsigned returnCode = invokeNative(t, method);
@ -2359,12 +2353,108 @@ run(Thread* t, const char* className, const char* methodName,
checkStack(t, method); checkStack(t, method);
if (LIKELY(t->exception == 0)) { if (LIKELY(t->exception == 0)) {
pushFrame(t, method); pushFrame(t, method);
} result = ::run(t);
} popFrame(t);
} }
} }
return ::run(t); return result;
}
} // namespace
namespace vm {
object
run(Thread* t, object method, object this_, ...)
{
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
> Thread::StackSizeInWords / 2))
{
t->exception = makeStackOverflowError(t);
return 0;
}
va_list a;
va_start(a, this_);
const char* spec = reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, method), 0));
pushArguments(t, this_, spec, a);
va_end(a);
return invoke(t, method);
}
object
run2(Thread* t, object method, object this_, object arguments)
{
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1
> Thread::StackSizeInWords / 2))
{
t->exception = makeStackOverflowError(t);
return 0;
}
const char* spec = reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, method), 0));
pushArguments(t, this_, spec, arguments);
return invoke(t, method);
}
object
run(Thread* t, const char* className, const char* methodName,
const char* methodSpec, object this_, ...)
{
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
if (UNLIKELY(t->sp + parameterFootprint(methodSpec) + 1
> Thread::StackSizeInWords / 2))
{
t->exception = makeStackOverflowError(t);
return 0;
}
va_list a;
va_start(a, this_);
pushArguments(t, this_, methodSpec, a);
va_end(a);
object class_ = resolveClass(t, makeByteArray(t, "%s", className));
if (LIKELY(t->exception == 0)) {
PROTECT(t, class_);
object name = makeByteArray(t, methodName);
PROTECT(t, name);
object spec = makeByteArray(t, methodSpec);
object reference = makeReference(t, class_, name, spec);
object method = findMethodInClass(t, class_, reference);
if (LIKELY(t->exception == 0)) {
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
return invoke(t, method);
}
}
return 0;
} }
int int
@ -2372,16 +2462,16 @@ run(System* system, Heap* heap, ClassFinder* classFinder,
const char* className, int argc, const char** argv) const char* className, int argc, const char** argv)
{ {
Machine m(system, heap, classFinder); Machine m(system, heap, classFinder);
Thread t(&m, 0, 0, 0); Thread* t = new (system->allocate(sizeof(Thread))) Thread(&m, 0, 0);
enter(&t, Thread::ActiveState); enter(t, Thread::ActiveState);
::run(&t, className, argc, argv); ::run(t, className, argc, argv);
int exitCode = 0; int exitCode = 0;
if (t.exception) exitCode = -1; if (t->exception) exitCode = -1;
exit(&t); exit(t);
return exitCode; return exitCode;
} }

View File

@ -8,6 +8,12 @@
namespace vm { namespace vm {
object
run(Thread* t, object method, object this_, ...);
object
run2(Thread* t, object method, object this_, object arguments);
object object
run(Thread* t, const char* className, const char* methodName, run(Thread* t, const char* className, const char* methodName,
const char* methodSpec, object this_, ...); const char* methodSpec, object this_, ...);

View File

@ -155,6 +155,9 @@
(type illegalStateException java/lang/IllegalStateException (type illegalStateException java/lang/IllegalStateException
(extends runtimeException)) (extends runtimeException))
(type illegalArgumentException java/lang/IllegalArgumentException
(extends runtimeException))
(type illegalMonitorStateException java/lang/IllegalMonitorStateException (type illegalMonitorStateException java/lang/IllegalMonitorStateException
(extends runtimeException)) (extends runtimeException))
@ -174,6 +177,9 @@
(type classNotFoundException java/lang/ClassNotFoundException (type classNotFoundException java/lang/ClassNotFoundException
(extends runtimeException)) (extends runtimeException))
(type invocationTargetException java/lang/InvocationTargetException
(extends exception))
(type error java/lang/Error (type error java/lang/Error
(extends throwable)) (extends throwable))
@ -273,3 +279,30 @@
(type doubleArray [D (type doubleArray [D
(extends jobject) (extends jobject)
(array uint64_t body)) (array uint64_t body))
(type jbyte B
(extends jobject))
(type jboolean Z
(extends jobject))
(type jshort S
(extends jobject))
(type jchar C
(extends jobject))
(type jint I
(extends jobject))
(type jlong L
(extends jobject))
(type jfloat F
(extends jobject))
(type jdouble D
(extends jobject))
(type jvoid V
(extends jobject))

13
test/Reflection.java Normal file
View File

@ -0,0 +1,13 @@
import java.lang.reflect.Method;
import java.lang.reflect.Field;
public class Reflection {
public static void main(String[] args) throws Exception {
Class system = Class.forName("java.lang.System");
Field out = system.getDeclaredField("out");
Class output = Class.forName("java.lang.System$Output");
Method println = output.getDeclaredMethod("println", String.class);
println.invoke(out.get(null), "Hello, World!");
}
}