mirror of
https://github.com/corda/corda.git
synced 2024-12-28 00:38:55 +00:00
Merge branch 'master' of dice:git/vm
Conflicts: src/run.cpp
This commit is contained in:
commit
f56fda9af6
@ -1,5 +1,8 @@
|
||||
package java.lang;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public final class Class <T> {
|
||||
private short flags;
|
||||
private byte vmFlags;
|
||||
@ -9,16 +12,57 @@ public final class Class <T> {
|
||||
private int[] objectMask;
|
||||
private byte[] name;
|
||||
private Class super_;
|
||||
private Object interfaceTable;
|
||||
private Object virtualTable;
|
||||
private Object fieldTable;
|
||||
private Object methodTable;
|
||||
private Object staticTable;
|
||||
private Object initializer;
|
||||
private Object[] interfaceTable;
|
||||
private Method[] virtualTable;
|
||||
private Field[] fieldTable;
|
||||
private Method[] methodTable;
|
||||
private Object[] staticTable;
|
||||
private Method initializer;
|
||||
|
||||
private Class() { }
|
||||
|
||||
public String getName() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
19
classpath/java/lang/NullPointerException.java
Normal file
19
classpath/java/lang/NullPointerException.java
Normal file
@ -0,0 +1,19 @@
|
||||
package java.lang;
|
||||
|
||||
public class NullPointerException extends RuntimeException {
|
||||
public NullPointerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public NullPointerException(String message) {
|
||||
this(message, null);
|
||||
}
|
||||
|
||||
public NullPointerException(Throwable cause) {
|
||||
this(null, cause);
|
||||
}
|
||||
|
||||
public NullPointerException() {
|
||||
this(null, null);
|
||||
}
|
||||
}
|
@ -101,7 +101,8 @@ public final class String implements Comparable<String> {
|
||||
return new String(data, offset + start, end - start, false);
|
||||
}
|
||||
} else {
|
||||
throw new IndexOutOfBoundsException();
|
||||
throw new IndexOutOfBoundsException
|
||||
(start + " not in (0, " + end + ") or " + end + " > " + length);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,4 +30,6 @@ public class Field<T> extends AccessibleObject {
|
||||
public String getName() {
|
||||
return new String(name, 0, name.length - 1, false);
|
||||
}
|
||||
|
||||
public native Object get(Object instance);
|
||||
}
|
||||
|
@ -32,4 +32,54 @@ public class Method<T> extends AccessibleObject implements Member {
|
||||
public String getName() {
|
||||
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 == ')') {
|
||||
break;
|
||||
} else if (c == 'L') {
|
||||
int start = i + 1;
|
||||
i = next(';', spec, start);
|
||||
String name = spec.substring(start, i);
|
||||
types[index++] = Class.forName(name);
|
||||
} else if (c == '[') {
|
||||
int start = i;
|
||||
while (spec.charAt(i) == '[') ++i;
|
||||
|
||||
if (spec.charAt(i) == 'L') {
|
||||
i = next(';', spec, i + 1);
|
||||
String name = spec.substring(start, i);
|
||||
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
|
||||
test = test
|
||||
|
||||
input = $(cls)/References.class
|
||||
input = $(cls)/Threads.class
|
||||
|
||||
cxx = g++
|
||||
cc = gcc
|
||||
|
195
src/builtin.cpp
195
src/builtin.cpp
@ -1,7 +1,30 @@
|
||||
#include "builtin.h"
|
||||
#include "machine.h"
|
||||
#include "constants.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 builtin {
|
||||
@ -41,6 +64,148 @@ notifyAll(Thread* t, jobject 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 instancep, jobjectArray argumentsp)
|
||||
{
|
||||
object method = *this_;
|
||||
|
||||
if (argumentsp) {
|
||||
object arguments = *argumentsp;
|
||||
|
||||
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 (instancep) {
|
||||
object instance = *instancep;
|
||||
|
||||
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
|
||||
currentThread(Thread* t)
|
||||
{
|
||||
@ -104,15 +269,14 @@ currentTimeMillis(Thread* t)
|
||||
}
|
||||
|
||||
void
|
||||
loadLibrary(Thread* t, jobject, jstring nameString)
|
||||
loadLibrary(Thread* t, jobject, jstring name)
|
||||
{
|
||||
if (LIKELY(nameString)) {
|
||||
object n = *nameString;
|
||||
char name[stringLength(t, n) + 1];
|
||||
stringChars(t, n, name);
|
||||
if (LIKELY(name)) {
|
||||
char n[stringLength(t, *name) + 1];
|
||||
stringChars(t, *name, n);
|
||||
|
||||
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
|
||||
return;
|
||||
}
|
||||
@ -120,11 +284,11 @@ loadLibrary(Thread* t, jobject, jstring nameString)
|
||||
|
||||
System::Library* lib;
|
||||
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;
|
||||
} else {
|
||||
object message = makeString(t, "library not found: %s", name);
|
||||
object message = makeString(t, "library not found: %s", n);
|
||||
t->exception = makeRuntimeException(t, message);
|
||||
}
|
||||
} else {
|
||||
@ -224,6 +388,10 @@ start(Thread* t, jobject this_)
|
||||
|
||||
vm::run(t, "java/lang/Thread", "run", "()V", t->javaThread);
|
||||
|
||||
if (t->exception) {
|
||||
printTrace(t, t->exception);
|
||||
}
|
||||
|
||||
t->exit();
|
||||
}
|
||||
|
||||
@ -252,6 +420,11 @@ populate(Thread* t, object map)
|
||||
const char* key;
|
||||
void* value;
|
||||
} builtins[] = {
|
||||
{ "Java_java_lang_Class_forName",
|
||||
reinterpret_cast<void*>(forName) },
|
||||
{ "Java_java_lang_Class_isAssignableFrom",
|
||||
reinterpret_cast<void*>(isAssignableFrom) },
|
||||
|
||||
{ "Java_java_lang_System_arraycopy",
|
||||
reinterpret_cast<void*>(arraycopy) },
|
||||
|
||||
@ -285,6 +458,12 @@ populate(Thread* t, object map)
|
||||
{ "Java_java_lang_Object_wait",
|
||||
reinterpret_cast<void*>(wait) },
|
||||
|
||||
{ "Java_java_lang_reflect_Field_get",
|
||||
reinterpret_cast<void*>(get) },
|
||||
|
||||
{ "Java_java_lang_reflect_Method_invoke",
|
||||
reinterpret_cast<void*>(invoke) },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -99,7 +99,7 @@ enum OpCode {
|
||||
i2s = 0x93,
|
||||
iadd = 0x60,
|
||||
iaload = 0x2e,
|
||||
iand = 0x73,
|
||||
iand = 0x7e,
|
||||
iastore = 0x4f,
|
||||
iconst_m1 = 0x02,
|
||||
iconst_0 = 0x03,
|
||||
@ -113,9 +113,9 @@ enum OpCode {
|
||||
if_acmpne = 0xa6,
|
||||
if_icmpeq = 0x9f,
|
||||
if_icmpne = 0xa0,
|
||||
if_icmpgt = 0xa1,
|
||||
if_icmplt = 0xa1,
|
||||
if_icmpge = 0xa2,
|
||||
if_icmplt = 0xa3,
|
||||
if_icmpgt = 0xa3,
|
||||
if_icmple = 0xa4,
|
||||
ifeq = 0x99,
|
||||
ifge = 0x9c,
|
||||
|
104
src/machine.cpp
104
src/machine.cpp
@ -1376,7 +1376,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
||||
|
||||
builtin::populate(t, m->builtinMap);
|
||||
|
||||
javaThread = makeThread(t, 0, 0, reinterpret_cast<int64_t>(t));
|
||||
t->javaThread = makeThread(t, 0, 0, reinterpret_cast<int64_t>(t));
|
||||
} else {
|
||||
threadPeer(this, javaThread) = reinterpret_cast<jlong>(this);
|
||||
parent->child = this;
|
||||
@ -1625,6 +1625,39 @@ stringChars(Thread* t, object string, char* chars)
|
||||
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;
|
||||
} else {
|
||||
return isAssignableFrom(t, class_, objectClass(t, o));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterFootprint(const char* s)
|
||||
{
|
||||
@ -2015,27 +2048,27 @@ resolveClass(Thread* t, object spec)
|
||||
|
||||
if (data) {
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "parsing %s\n", &byteArrayBody
|
||||
(t, spec, 0));
|
||||
fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0));
|
||||
}
|
||||
|
||||
// parse class file
|
||||
class_ = parseClass(t, data->start(), data->length());
|
||||
data->dispose();
|
||||
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "done parsing %s\n", &byteArrayBody
|
||||
(t, className(t, class_), 0));
|
||||
}
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "done parsing %s\n", &byteArrayBody(t, spec, 0));
|
||||
}
|
||||
|
||||
object bootstrapClass = hashMapFind
|
||||
(t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual);
|
||||
object bootstrapClass = hashMapFind
|
||||
(t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual);
|
||||
|
||||
if (bootstrapClass) {
|
||||
PROTECT(t, bootstrapClass);
|
||||
if (bootstrapClass) {
|
||||
PROTECT(t, bootstrapClass);
|
||||
|
||||
updateBootstrapClass(t, bootstrapClass, class_);
|
||||
class_ = bootstrapClass;
|
||||
updateBootstrapClass(t, bootstrapClass, class_);
|
||||
class_ = bootstrapClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2313,6 +2346,51 @@ collect(Thread* t, Heap::CollectionType type)
|
||||
killZombies(t, m->rootThread);
|
||||
}
|
||||
|
||||
void
|
||||
printTrace(Thread* t, object exception)
|
||||
{
|
||||
for (object e = exception; e; e = throwableCauseUnsafe(t, e)) {
|
||||
if (e != exception) {
|
||||
fprintf(stderr, "caused by: ");
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s", &byteArrayBody
|
||||
(t, className(t, objectClass(t, e)), 0));
|
||||
|
||||
if (throwableMessageUnsafe(t, e)) {
|
||||
object m = throwableMessageUnsafe(t, e);
|
||||
char message[stringLength(t, m) + 1];
|
||||
stringChars(t, m, message);
|
||||
fprintf(stderr, ": %s\n", message);
|
||||
} else {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
object trace = throwableTraceUnsafe(t, e);
|
||||
for (unsigned i = 0; i < arrayLength(t, trace); ++i) {
|
||||
object e = arrayBody(t, trace, i);
|
||||
const int8_t* class_ = &byteArrayBody
|
||||
(t, className(t, methodClass(t, traceElementMethod(t, e))), 0);
|
||||
const int8_t* method = &byteArrayBody
|
||||
(t, methodName(t, traceElementMethod(t, e)), 0);
|
||||
int line = lineNumber(t, traceElementMethod(t, e), traceElementIp(t, e));
|
||||
|
||||
fprintf(stderr, " at %s.%s ", class_, method);
|
||||
|
||||
switch (line) {
|
||||
case NativeLine:
|
||||
fprintf(stderr, "(native)\n");
|
||||
break;
|
||||
case UnknownLine:
|
||||
fprintf(stderr, "(unknown line)\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "(line %d)\n", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
noop()
|
||||
{ }
|
||||
|
@ -1377,6 +1377,12 @@ makeIllegalStateException(Thread* t, object message)
|
||||
return makeIllegalStateException(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIllegalArgumentException(Thread* t)
|
||||
{
|
||||
return makeIllegalArgumentException(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIllegalMonitorStateException(Thread* t)
|
||||
{
|
||||
@ -1427,6 +1433,14 @@ makeNullPointerException(Thread* t)
|
||||
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
|
||||
makeStackOverflowError(Thread* t)
|
||||
{
|
||||
@ -1466,6 +1480,12 @@ makeString(Thread* t, const char* format, ...);
|
||||
void
|
||||
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
|
||||
pushObject(Thread* t, object o)
|
||||
{
|
||||
@ -1622,9 +1642,13 @@ pokeLong(Thread* t, unsigned index, uint64_t value)
|
||||
inline object*
|
||||
pushReference(Thread* t, object o)
|
||||
{
|
||||
expect(t, t->sp + 1 < Thread::StackSizeInWords / 2);
|
||||
pushObject(t, o);
|
||||
return reinterpret_cast<object*>(t->stack + ((t->sp - 1) * 2) + 1);
|
||||
if (o) {
|
||||
expect(t, t->sp + 1 < Thread::StackSizeInWords / 2);
|
||||
pushObject(t, o);
|
||||
return reinterpret_cast<object*>(t->stack + ((t->sp - 1) * 2) + 1);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline int
|
||||
@ -2055,6 +2079,9 @@ vmNotifyAll(Thread* t, object o)
|
||||
notifyAll(t, o);
|
||||
}
|
||||
|
||||
void
|
||||
printTrace(Thread* t, object exception);
|
||||
|
||||
void
|
||||
exit(Thread* t);
|
||||
|
||||
|
344
src/run.cpp
344
src/run.cpp
@ -91,8 +91,7 @@ make(Thread* t, object class_)
|
||||
|
||||
ACQUIRE(t, t->vm->referenceLock);
|
||||
|
||||
// jreferenceNext(t, instance)
|
||||
cast<object>(instance, BytesPerWord) = t->vm->weakReferences;
|
||||
jreferenceNextUnsafe(t, instance) = t->vm->weakReferences;
|
||||
t->vm->weakReferences = instance;
|
||||
}
|
||||
|
||||
@ -106,33 +105,6 @@ setStatic(Thread* t, object field, object 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
|
||||
findInterfaceMethod(Thread* t, object method, object o)
|
||||
{
|
||||
@ -328,6 +300,16 @@ makeNativeMethodData(Thread* t, object method, void* function, bool builtin)
|
||||
case '[':
|
||||
argumentTableSize += BytesPerWord;
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -535,6 +517,8 @@ invokeNative(Thread* t, object method)
|
||||
object
|
||||
run(Thread* t)
|
||||
{
|
||||
const int base = t->frame;
|
||||
|
||||
unsigned instruction = nop;
|
||||
unsigned& ip = t->ip;
|
||||
unsigned& sp = t->sp;
|
||||
@ -659,8 +643,8 @@ run(Thread* t)
|
||||
|
||||
case areturn: {
|
||||
object result = popObject(t);
|
||||
popFrame(t);
|
||||
if (frame >= 0) {
|
||||
if (frame > base) {
|
||||
popFrame(t);
|
||||
pushObject(t, result);
|
||||
goto loop;
|
||||
} else {
|
||||
@ -1451,8 +1435,8 @@ run(Thread* t)
|
||||
|
||||
case ireturn: {
|
||||
int32_t result = popInt(t);
|
||||
popFrame(t);
|
||||
if (frame >= 0) {
|
||||
if (frame > base) {
|
||||
popFrame(t);
|
||||
pushInt(t, result);
|
||||
goto loop;
|
||||
} else {
|
||||
@ -1626,16 +1610,16 @@ run(Thread* t)
|
||||
|
||||
if (objectClass(t, v) == arrayBody(t, t->vm->types, Machine::IntType)) {
|
||||
pushInt(t, intValue(t, v));
|
||||
} else if (objectClass(t, v)
|
||||
== arrayBody(t, t->vm->types, Machine::StringType))
|
||||
{
|
||||
pushObject(t, v);
|
||||
} else if (objectClass(t, v)
|
||||
== arrayBody(t, t->vm->types, Machine::FloatType))
|
||||
{
|
||||
pushInt(t, floatValue(t, v));
|
||||
} else if (objectClass(t, v)
|
||||
== arrayBody(t, t->vm->types, Machine::StringType))
|
||||
{
|
||||
pushObject(t, v);
|
||||
} else {
|
||||
abort(t);
|
||||
pushObject(t, resolveClass(t, v));
|
||||
}
|
||||
} goto loop;
|
||||
|
||||
@ -1710,8 +1694,8 @@ run(Thread* t)
|
||||
|
||||
case lreturn: {
|
||||
int64_t result = popLong(t);
|
||||
popFrame(t);
|
||||
if (frame >= 0) {
|
||||
if (frame > base) {
|
||||
popFrame(t);
|
||||
pushLong(t, result);
|
||||
goto loop;
|
||||
} else {
|
||||
@ -1993,8 +1977,8 @@ run(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case return_: {
|
||||
popFrame(t);
|
||||
if (frame >= 0) {
|
||||
if (frame > base) {
|
||||
popFrame(t);
|
||||
goto loop;
|
||||
} else {
|
||||
return 0;
|
||||
@ -2148,7 +2132,7 @@ run(Thread* t)
|
||||
|
||||
pokeInt(t, t->frame + FrameIpOffset, t->ip);
|
||||
for (; frame >= 0; frame = frameNext(t, frame)) {
|
||||
if (methodFlags(t, frameMethod(t, frame)) & ACC_NATIVE) {
|
||||
if (frame < base) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2185,49 +2169,6 @@ run(Thread* t)
|
||||
}
|
||||
}
|
||||
|
||||
for (object e = exception; e; e = throwableCause(t, e)) {
|
||||
if (e == exception) {
|
||||
fprintf(stderr, "uncaught exception: ");
|
||||
} else {
|
||||
fprintf(stderr, "caused by: ");
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s", &byteArrayBody
|
||||
(t, className(t, objectClass(t, exception)), 0));
|
||||
|
||||
if (throwableMessage(t, exception)) {
|
||||
object m = throwableMessage(t, exception);
|
||||
char message[stringLength(t, m) + 1];
|
||||
stringChars(t, m, message);
|
||||
fprintf(stderr, ": %s\n", message);
|
||||
} else {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
object trace = throwableTrace(t, e);
|
||||
for (unsigned i = 0; i < arrayLength(t, trace); ++i) {
|
||||
object e = arrayBody(t, trace, i);
|
||||
const int8_t* class_ = &byteArrayBody
|
||||
(t, className(t, methodClass(t, traceElementMethod(t, e))), 0);
|
||||
const int8_t* method = &byteArrayBody
|
||||
(t, methodName(t, traceElementMethod(t, e)), 0);
|
||||
int line = lineNumber(t, traceElementMethod(t, e), traceElementIp(t, e));
|
||||
|
||||
fprintf(stderr, " at %s.%s ", class_, method);
|
||||
|
||||
switch (line) {
|
||||
case NativeLine:
|
||||
fprintf(stderr, "(native)\n");
|
||||
break;
|
||||
case UnknownLine:
|
||||
fprintf(stderr, "(unknown line)\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "(line %d)\n", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2249,32 +2190,14 @@ run(Thread* t, const char* className, int argc, const char** argv)
|
||||
run(t, className, "main", "([Ljava/lang/String;)V", 0, args);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vm {
|
||||
|
||||
object
|
||||
run(Thread* t, const char* className, const char* methodName,
|
||||
const char* methodSpec, object this_, ...)
|
||||
void
|
||||
pushArguments(Thread* t, object this_, const char* spec, va_list a)
|
||||
{
|
||||
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_) {
|
||||
pushObject(t, this_);
|
||||
}
|
||||
|
||||
va_list a;
|
||||
va_start(a, this_);
|
||||
|
||||
const char* s = methodSpec;
|
||||
const char* s = spec;
|
||||
++ s; // skip '('
|
||||
while (*s and *s != ')') {
|
||||
switch (*s) {
|
||||
@ -2311,6 +2234,172 @@ run(Thread* t, const char* className, const char* methodName,
|
||||
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);
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
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);
|
||||
|
||||
@ -2328,43 +2417,11 @@ run(Thread* t, const char* className, const char* methodName,
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 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);
|
||||
}
|
||||
}
|
||||
return invoke(t, method);
|
||||
}
|
||||
}
|
||||
|
||||
return ::run(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
@ -2379,7 +2436,10 @@ run(System* system, Heap* heap, ClassFinder* classFinder,
|
||||
::run(t, className, argc, argv);
|
||||
|
||||
int exitCode = 0;
|
||||
if (t->exception) exitCode = -1;
|
||||
if (t->exception) {
|
||||
exitCode = -1;
|
||||
printTrace(t, t->exception);
|
||||
}
|
||||
|
||||
exit(t);
|
||||
|
||||
|
@ -8,6 +8,12 @@
|
||||
|
||||
namespace vm {
|
||||
|
||||
object
|
||||
run(Thread* t, object method, object this_, ...);
|
||||
|
||||
object
|
||||
run2(Thread* t, object method, object this_, object arguments);
|
||||
|
||||
object
|
||||
run(Thread* t, const char* className, const char* methodName,
|
||||
const char* methodSpec, object this_, ...);
|
||||
|
@ -212,7 +212,7 @@ class MySystem: public System {
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
assert(s, context == 0);
|
||||
//assert(s, context == 0);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
pthread_cond_destroy(&condition);
|
||||
s->free(this);
|
||||
|
@ -139,9 +139,9 @@
|
||||
|
||||
(type throwable java/lang/Throwable
|
||||
(extends jobject)
|
||||
(object message)
|
||||
(object trace)
|
||||
(object cause))
|
||||
(noassert object message)
|
||||
(noassert object trace)
|
||||
(noassert object cause))
|
||||
|
||||
(type exception java/lang/Exception
|
||||
(extends throwable))
|
||||
@ -155,6 +155,9 @@
|
||||
(type illegalStateException java/lang/IllegalStateException
|
||||
(extends runtimeException))
|
||||
|
||||
(type illegalArgumentException java/lang/IllegalArgumentException
|
||||
(extends runtimeException))
|
||||
|
||||
(type illegalMonitorStateException java/lang/IllegalMonitorStateException
|
||||
(extends runtimeException))
|
||||
|
||||
@ -174,6 +177,9 @@
|
||||
(type classNotFoundException java/lang/ClassNotFoundException
|
||||
(extends runtimeException))
|
||||
|
||||
(type invocationTargetException java/lang/InvocationTargetException
|
||||
(extends exception))
|
||||
|
||||
(type error java/lang/Error
|
||||
(extends throwable))
|
||||
|
||||
@ -231,7 +237,7 @@
|
||||
|
||||
(type jreference java/lang/ref/Reference
|
||||
(extends jobject)
|
||||
(void* next)
|
||||
(noassert void* next)
|
||||
(void* target)
|
||||
(void* queue)
|
||||
(object jnext))
|
||||
@ -273,3 +279,30 @@
|
||||
(type doubleArray [D
|
||||
(extends jobject)
|
||||
(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…
Reference in New Issue
Block a user