mirror of
https://github.com/corda/corda.git
synced 2025-02-26 11:20:44 +00:00
start work on reflection; bugfixes
This commit is contained in:
parent
472ecb1713
commit
5f3bf175e0
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
2
makefile
2
makefile
@ -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
|
||||||
|
186
src/builtin.cpp
186
src/builtin.cpp
@ -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) },
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
expect(t, t->sp + 1 < Thread::StackSizeInWords / 2);
|
if (o) {
|
||||||
pushObject(t, o);
|
expect(t, t->sp + 1 < Thread::StackSizeInWords / 2);
|
||||||
return reinterpret_cast<object*>(t->stack + ((t->sp - 1) * 2) + 1);
|
pushObject(t, o);
|
||||||
|
return reinterpret_cast<object*>(t->stack + ((t->sp - 1) * 2) + 1);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int
|
inline int
|
||||||
|
280
src/run.cpp
280
src/run.cpp
@ -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);
|
||||||
popFrame(t);
|
if (frame > base) {
|
||||||
if (frame >= 0) {
|
popFrame(t);
|
||||||
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);
|
||||||
popFrame(t);
|
if (frame > base) {
|
||||||
if (frame >= 0) {
|
popFrame(t);
|
||||||
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);
|
||||||
popFrame(t);
|
if (frame > base) {
|
||||||
if (frame >= 0) {
|
popFrame(t);
|
||||||
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_: {
|
||||||
popFrame(t);
|
if (frame > base) {
|
||||||
if (frame >= 0) {
|
popFrame(t);
|
||||||
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,6 +2268,171 @@ run(Thread* t, const char* className, const char* methodName,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pushArguments(Thread* t, object this_, const char* spec, object a)
|
||||||
|
{
|
||||||
|
if (this_) {
|
||||||
|
pushObject(t, this_);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned index = 0;
|
||||||
|
const char* s = spec;
|
||||||
|
++ s; // skip '('
|
||||||
|
while (*s and *s != ')') {
|
||||||
|
switch (*s) {
|
||||||
|
case 'L':
|
||||||
|
while (*s and *s != ';') ++ s;
|
||||||
|
++ s;
|
||||||
|
pushObject(t, objectArrayBody(t, a, index++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
while (*s == '[') ++ s;
|
||||||
|
switch (*s) {
|
||||||
|
case 'L':
|
||||||
|
while (*s and *s != ';') ++ s;
|
||||||
|
++ s;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
++ s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pushObject(t, objectArrayBody(t, a, index++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'J':
|
||||||
|
case 'D':
|
||||||
|
++ 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) {
|
||||||
|
unsigned returnCode = invokeNative(t, method);
|
||||||
|
|
||||||
|
if (LIKELY(t->exception == 0)) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case ByteField:
|
||||||
|
case BooleanField:
|
||||||
|
case CharField:
|
||||||
|
case ShortField:
|
||||||
|
case FloatField:
|
||||||
|
case IntField:
|
||||||
|
return makeInt(t, popInt(t));
|
||||||
|
|
||||||
|
case LongField:
|
||||||
|
case DoubleField:
|
||||||
|
return makeLong(t, popLong(t));
|
||||||
|
|
||||||
|
case ObjectField:
|
||||||
|
return popObject(t);
|
||||||
|
|
||||||
|
case VoidField:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort(t);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
checkStack(t, method);
|
||||||
|
if (LIKELY(t->exception == 0)) {
|
||||||
|
pushFrame(t, method);
|
||||||
|
result = ::run(t);
|
||||||
|
popFrame(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);
|
va_end(a);
|
||||||
|
|
||||||
@ -2328,43 +2450,11 @@ run(Thread* t, const char* className, const char* methodName,
|
|||||||
if (LIKELY(t->exception == 0)) {
|
if (LIKELY(t->exception == 0)) {
|
||||||
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
|
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
|
||||||
|
|
||||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
return invoke(t, method);
|
||||||
unsigned returnCode = invokeNative(t, method);
|
|
||||||
|
|
||||||
if (LIKELY(t->exception == 0)) {
|
|
||||||
switch (returnCode) {
|
|
||||||
case ByteField:
|
|
||||||
case BooleanField:
|
|
||||||
case CharField:
|
|
||||||
case ShortField:
|
|
||||||
case FloatField:
|
|
||||||
case IntField:
|
|
||||||
return makeInt(t, popInt(t));
|
|
||||||
|
|
||||||
case LongField:
|
|
||||||
case DoubleField:
|
|
||||||
return makeLong(t, popLong(t));
|
|
||||||
|
|
||||||
case ObjectField:
|
|
||||||
return popObject(t);
|
|
||||||
|
|
||||||
case VoidField:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
|
||||||
abort(t);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
checkStack(t, method);
|
|
||||||
if (LIKELY(t->exception == 0)) {
|
|
||||||
pushFrame(t, method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ::run(t);
|
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;
|
||||||
}
|
}
|
||||||
|
@ -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_, ...);
|
||||||
|
@ -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
13
test/Reflection.java
Normal 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!");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user