more JNI work

This commit is contained in:
Joel Dice 2007-06-24 19:34:07 -06:00
parent f606f2d30a
commit 400b3633d7
13 changed files with 1291 additions and 115 deletions

5
classpath/Hello.java Normal file
View File

@ -0,0 +1,5 @@
public class Hello {
public static void main(String[] args) {
System.out.println("hello, world!");
}
}

View File

@ -0,0 +1,13 @@
#include "stdio.h"
#include "jni.h"
extern "C" JNIEXPORT void JNICALL
Java_java_lang_System_Output_println(JNIEnv* e, jobject, jstring s)
{
jboolean isCopy;
const char* chars = e->GetStringUTFChars(s, &isCopy);
if (chars) {
printf("%s", chars);
}
e->ReleaseStringUTFChars(s, chars);
}

View File

@ -0,0 +1,15 @@
package java.lang;
public abstract class System {
public static final Output out = new Output();
static {
loadLibrary("natives");
}
public static native void loadLibrary(String name);
public static class Output {
public native void println(String s);
}
}

View File

@ -2,7 +2,7 @@
bld = build
src = src
inp = input
classpath = classpath
cxx = g++
cc = gcc
@ -22,7 +22,7 @@ thread-lflags = -lpthread
cflags = $(warnings) -fPIC -fno-rtti -fno-exceptions -fvisibility=hidden \
-I$(src) -I$(bld) $(thread-cflags)
lflags = $(thread-lflags)
lflags = $(thread-lflags) -ldl
test-cflags = -DDEBUG_MEMORY
stress-cflags = -DDEBUG_MEMORY -DDEBUG_MEMORY_MAJOR
@ -32,6 +32,13 @@ stdcpp-sources = $(src)/stdc++.cpp
stdcpp-objects = $(call cpp-objects,$(stdcpp-sources),$(src))
stdcpp-cflags = $(fast) $(cflags)
jni-sources = $(classpath)/java/lang/System.cpp
jni-objects = $(call cpp-objects,$(jni-sources),$(classpath))
jni-cflags = -I/usr/lib/jvm/java-6-sun-1.6.0.00/include \
-I/usr/lib/jvm/java-6-sun-1.6.0.00/include/linux \
$(cflags)
jni-library = $(bld)/libnatives.so
generated-code = \
$(bld)/type-enums.cpp \
$(bld)/type-declarations.cpp \
@ -75,11 +82,10 @@ fast-objects = $(patsubst $(bld)/%,$(bld)/fast-%,$(interpreter-objects))
fast-executable = $(bld)/fast-vm
fast-cflags = $(fast) $(cflags)
input = $(bld)/classes/Test.class
input = $(bld)/classes/Hello.class
input-depends = \
$(bld)/classes/java/lang/Object.class \
$(bld)/classes/java/lang/Class.class \
$(bld)/classes/vm/VM.class
$(bld)/classes/java/lang/System.class \
$(jni-library)
gen-run-arg = $(shell echo $(1) | sed -e 's:$(bld)/classes/\(.*\)\.class:\1:')
args = -cp $(bld)/classes -hs 67108864 $(call gen-run-arg,$(input))
@ -142,10 +148,11 @@ $(generated-code): %.cpp: $(src)/types.def $(generator-executable)
$(bld)/type-generator.o: \
$(generator-headers)
$(bld)/classes/%.class: $(inp)/%.java
$(bld)/classes/%.class: $(classpath)/%.java
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(javac) -bootclasspath $(inp) -classpath $(inp) -d $(bld)/classes $(<)
$(javac) -bootclasspath $(classpath) -classpath $(classpath) \
-d $(bld)/classes $(<)
$(stdcpp-objects): $(bld)/%.o: $(src)/%.cpp
@echo "compiling $(@)"
@ -177,6 +184,15 @@ $(fast-objects): $(bld)/fast-%.o: $(src)/%.cpp $(interpreter-depends)
@mkdir -p $(dir $(@))
$(cxx) $(fast-cflags) -c $(<) -o $(@)
$(jni-objects): $(bld)/%.o: $(classpath)/%.cpp
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) $(jni-cflags) -c $(<) -o $(@)
$(jni-library): $(jni-objects)
@echo "linking $(@)"
$(cc) $(lflags) -shared $(^) -o $(@)
$(executable): $(interpreter-objects) $(stdcpp-objects)
@echo "linking $(@)"
$(cc) $(lflags) $(^) -o $(@)

1010
src/jni.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,8 @@ class System: public vm::System {
}
virtual void* tryAllocate(unsigned size) {
// todo: synchronize access
if (Verbose) {
fprintf(stderr, "try %d; count: %d; limit: %d\n",
size, count, limit);
@ -85,6 +87,8 @@ class System: public vm::System {
}
virtual void free(const void* p) {
// todo: synchronize access
if (p) {
const uintptr_t* up = static_cast<const uintptr_t*>(p) - 1;
if (count < *up) {
@ -110,14 +114,19 @@ class System: public vm::System {
return 0;
}
virtual uint64_t call(void* function, unsigned argumentCount,
uint32_t* argumentTable, uint8_t* argumentSizeTable,
unsigned returnSize)
virtual uint64_t call(void* ,//function,
unsigned ,//argumentCount,
uint32_t* ,//argumentTable,
uint8_t* ,//argumentSizeTable,
unsigned )//returnSize)
{
::abort();
}
virtual Status load(Library** lib, const char* name, Library* next) {
virtual Status load(vm::System::Library** lib,
const char* name,
vm::System::Library* next)
{
void* p = dlopen(name, RTLD_LAZY);
if (p) {
*lib = new (vm::System::allocate(sizeof(Library)))

View File

@ -44,8 +44,8 @@ class System {
virtual Status make(Monitor**) = 0;
virtual uint64_t call(void* function, unsigned argumentCount,
uint32_t* argumentTable, uint8_t* argumentSizeTable,
unsigned returnSize);
virtual Status load(Library**, const char* name, Library* next);
unsigned returnSize) = 0;
virtual Status load(Library**, const char* name, Library* next) = 0;
virtual void abort() = 0;
void* allocate(unsigned size) {

View File

@ -4,6 +4,7 @@
#include "class_finder.h"
#include "stream.h"
#include "constants.h"
#include "jni.h"
#include "vm.h"
#define PROTECT(thread, name) \
@ -30,7 +31,6 @@ object& arrayBodyUnsafe(Thread*, object, unsigned);
void set(Thread*, object&, object);
object makeString(Thread*, const char*, ...);
object makeByteArray(Thread*, const char*, ...);
unsigned objectSize(Thread* t, object o);
object&
objectClass(object o)
@ -152,10 +152,11 @@ class Thread {
unsigned ip;
unsigned sp;
unsigned heapIndex;
object stack[StackSizeInWords];
object heap[HeapSizeInWords];
Protector* protector;
Chain* chain;
object stack[StackSizeInWords];
object heap[HeapSizeInWords];
JNIEnv jniEnv;
};
#include "type-declarations.cpp"
@ -458,77 +459,6 @@ top(Thread* t)
return t->stack[t->sp - 1];
}
int32_t
builtinToString(Thread* t, int32_t this_)
{
object o = t->stack[this_ - 1];
object s = makeString(t, "%s@%p",
&byteArrayBody(t, className(t, objectClass(o)), 0),
o);
pushSafe(t, s);
return t->sp;
}
Thread::Thread(Machine* m):
vm(m),
next(0),
child(0),
state(NoState),
thread(0),
frame(0),
code(0),
exception(0),
ip(0),
sp(0),
heapIndex(0),
protector(0),
chain(0)
{
if (m->rootThread == 0) {
m->rootThread = this;
m->unsafe = true;
Thread* t = this;
#include "type-initializations.cpp"
object arrayClass = arrayBody(t, t->vm->types, Machine::ArrayType);
set(t, objectClass(t->vm->types), arrayClass);
object classClass = arrayBody(t, m->types, Machine::ClassType);
set(t, objectClass(classClass), classClass);
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
set(t, objectClass(intArrayClass), classClass);
m->unsafe = false;
m->bootstrapClassMap = makeHashMap(this, 0, 0);
#include "type-java-initializations.cpp"
m->classMap = makeHashMap(this, 0, 0);
m->builtinMap = makeHashMap(this, 0, 0);
struct {
const char* key;
void* value;
} builtins[] = {
{ "Java_java_lang_Object_toString",
reinterpret_cast<void*>(builtinToString) },
{ 0, 0 }
};
for (unsigned i = 0; builtins[i].key; ++i) {
object key = makeByteArray(t, builtins[i].key);
PROTECT(t, key);
object value = makePointer(t, builtins[i].value);
hashMapInsert(t, m->builtinMap, key, value, byteArrayHash);
}
}
}
void
Thread::dispose()
{
@ -864,6 +794,22 @@ make(Thread* t, object class_)
return instance;
}
unsigned
objectSize(Thread* t, object o)
{
object class_ = objectClass(o);
unsigned n = divide(classFixedSize(t, class_), BytesPerWord);
if (classArrayElementSize(t, class_)) {
n += divide(classArrayElementSize(t, class_)
* cast<uint32_t>(o, classFixedSize(t, class_) - 4),
BytesPerWord);
}
return n;
}
object
makeByteArray(Thread* t, const char* format, va_list a)
{
@ -915,6 +861,14 @@ makeTrace(Thread* t)
return trace;
}
object
makeRuntimeException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeClassCastException(t, message, trace, 0);
}
object
makeArrayIndexOutOfBoundsException(Thread* t, object message)
{
@ -1891,7 +1845,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
enter(t, Thread::ExclusiveState);
memcpy(bootstrapClass, class_, objectSize(t, class_));
memcpy(bootstrapClass, class_, objectSize(t, class_) * BytesPerWord);
enter(t, Thread::ActiveState);
}
@ -2013,12 +1967,12 @@ makeNativeMethodData(Thread* t, object method, void* function, bool builtin)
methodParameterCount(t, method),
false);
unsigned argumentTableSize = sizeof(void*) / 4;
unsigned argumentTableSize = BytesPerWord / 4;
unsigned index = 0;
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
nativeMethodDataParameterCodes(t, data, index++) = ObjectField;
argumentTableSize += 1;
argumentTableSize += BytesPerWord / 4;
}
const char* s = reinterpret_cast<const char*>
@ -2030,13 +1984,13 @@ makeNativeMethodData(Thread* t, object method, void* function, bool builtin)
switch (*s) {
case 'L':
argumentTableSize += 1;
argumentTableSize += BytesPerWord / 4;
while (*s and *s != ';') ++ s;
++ s;
break;
case '[':
argumentTableSize += 1;
argumentTableSize += BytesPerWord / 4;
while (*s == '[') ++ s;
break;
@ -2108,35 +2062,29 @@ invokeNative(Thread* t, object method)
uint8_t sizes[parameterCount + 1];
unsigned offset = 0;
switch (sizeof(uintptr_t)) {
case 4: {
sizes[0] = 4;
args[offset++] = reinterpret_cast<uintptr_t>(t);
} break;
case 8: {
sizes[0] = 8;
uint64_t v = reinterpret_cast<uint64_t>(t);
args[offset++] = static_cast<uint32_t>(v >> 32);
args[offset++] = static_cast<uint32_t>(v & 0xFFFFFFFF);
} break;
default:
abort(t);
}
sizes[0] = BytesPerWord;
JNIEnv* e = &(t->jniEnv);
memcpy(args + offset, &e, BytesPerWord);
offset += BytesPerWord / 4;
for (unsigned i = 0; i < parameterCount; ++i) {
unsigned code = nativeMethodDataParameterCodes(t, data, i);
if (code == ObjectField) {
sizes[i + 1] = 4;
args[offset++] = t->sp + i + 1;
sizes[i + 1] = BytesPerWord;
unsigned position = (t->sp - parameterCount) + i;
if (t->stack[position]) {
memcpy(args + offset, t->stack + position, BytesPerWord);
} else {
memset(args + offset, 0, BytesPerWord);
}
offset += BytesPerWord / 4;
} else {
sizes[i + 1] = primitiveSize(t, code);
uint64_t v = primitiveValue(t, code, t->stack[t->sp + i]);
if (sizes[i + 1] == 8) {
args[offset++] = static_cast<uint32_t>(v >> 32);
args[offset++] = static_cast<uint32_t>(v & 0xFFFFFFFF);
memcpy(args + offset, &v, 8);
offset += 2;
} else {
args[offset++] = v;
}
@ -2167,12 +2115,172 @@ invokeNative(Thread* t, object method)
if (UNLIKELY(t->exception) or returnCode == VoidField) {
return 0;
} else if (returnCode == ObjectField) {
return (rv == 0 ? 0 : t->stack[rv - 1]);
return (rv == 0 ? 0 :
*reinterpret_cast<object*>(static_cast<uintptr_t>(rv)));
} else {
return makePrimitive(t, returnCode, rv);
}
}
void
builtinLoadLibrary(JNIEnv* e, jstring nameString)
{
Thread* t = static_cast<Thread*>(e->reserved0);
if (LIKELY(nameString)) {
object n = *nameString;
char name[stringLength(t, n) + 1];
memcpy(name,
&byteArrayBody(t, stringBytes(t, n), stringOffset(t, n)),
stringLength(t, n));
name[stringLength(t, n)] = 0;
System::Library* lib;
if (LIKELY(t->vm->system->success
(t->vm->system->load(&lib, name, t->vm->libraries))))
{
t->vm->libraries = lib;
} else {
object message = makeString(t, "library not found: %s", name);
t->exception = makeRuntimeException(t, message);
}
} else {
t->exception = makeNullPointerException(t);
}
}
jstring
builtinToString(JNIEnv* e, jobject this_)
{
Thread* t = static_cast<Thread*>(e->reserved0);
object s = makeString
(t, "%s@%p",
&byteArrayBody(t, className(t, objectClass(*this_)), 0),
*this_);
pushSafe(t, s);
return t->stack + (t->sp - 1);
}
jsize
GetStringUTFLength(JNIEnv* e, jstring s)
{
Thread* t = static_cast<Thread*>(e->reserved0);
enter(t, Thread::ActiveState);
jsize length = 0;
if (LIKELY(s)) {
length = stringLength(t, *s);
} else {
t->exception = makeNullPointerException(t);
}
enter(t, Thread::IdleState);
return length;
}
const char*
GetStringUTFChars(JNIEnv* e, jstring s, jboolean* isCopy)
{
Thread* t = static_cast<Thread*>(e->reserved0);
enter(t, Thread::ActiveState);
char* chars = 0;
if (LIKELY(s)) {
chars = static_cast<char*>(t->vm->system->allocate(stringLength(t, *s)));
memcpy(chars,
&byteArrayBody(t, stringBytes(t, *s), stringOffset(t, *s)),
stringLength(t, *s));
chars[stringLength(t, *s)] = 0;
} else {
t->exception = makeNullPointerException(t);
}
enter(t, Thread::IdleState);
*isCopy = true;
return chars;
}
void
ReleaseStringUTFChars(JNIEnv* e, jstring, const char* chars)
{
Thread* t = static_cast<Thread*>(e->reserved0);
t->vm->system->free(chars);
}
Thread::Thread(Machine* m):
vm(m),
next(0),
child(0),
state(NoState),
thread(0),
frame(0),
code(0),
exception(0),
ip(0),
sp(0),
heapIndex(0),
protector(0),
chain(0)
{
memset(&jniEnv, 0, sizeof(JNIEnv));
jniEnv.reserved0 = this;
jniEnv.GetStringUTFLength = GetStringUTFLength;
jniEnv.GetStringUTFChars = GetStringUTFChars;
jniEnv.ReleaseStringUTFChars = ReleaseStringUTFChars;
if (m->rootThread == 0) {
m->rootThread = this;
m->unsafe = true;
Thread* t = this;
#include "type-initializations.cpp"
object arrayClass = arrayBody(t, t->vm->types, Machine::ArrayType);
set(t, objectClass(t->vm->types), arrayClass);
object classClass = arrayBody(t, m->types, Machine::ClassType);
set(t, objectClass(classClass), classClass);
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
set(t, objectClass(intArrayClass), classClass);
m->unsafe = false;
m->bootstrapClassMap = makeHashMap(this, 0, 0);
#include "type-java-initializations.cpp"
m->classMap = makeHashMap(this, 0, 0);
m->builtinMap = makeHashMap(this, 0, 0);
struct {
const char* key;
void* value;
} builtins[] = {
{ "Java_java_lang_Object_toString",
reinterpret_cast<void*>(builtinToString) },
{ "Java_java_lang_System_load",
reinterpret_cast<void*>(builtinLoadLibrary) },
{ 0, 0 }
};
for (unsigned i = 0; builtins[i].key; ++i) {
object key = makeByteArray(t, builtins[i].key);
PROTECT(t, key);
object value = makePointer(t, builtins[i].value);
hashMapInsert(t, m->builtinMap, key, value, byteArrayHash);
}
}
}
object
run(Thread* t)
{