diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp new file mode 100644 index 0000000000..00d3a66979 --- /dev/null +++ b/classpath/java-io.cpp @@ -0,0 +1,261 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +#include "jni.h" + +#undef JNIEXPORT +#define JNIEXPORT __attribute__ ((visibility("default"))) + +#ifdef WIN32 +# include <io.h> +# define OPEN _open +# define CLOSE _close +# define READ _read +# define WRITE _write +# define STAT _stat +# define STRUCT_STAT struct _stat +# define MKDIR(path, mode) _mkdir(path) +# define CREAT _creat +# define OPEN_MASK O_BINARY +#else +# include <unistd.h> +# define OPEN open +# define CLOSE close +# define READ read +# define WRITE write +# define STAT stat +# define STRUCT_STAT struct stat +# define MKDIR mkdir +# define CREAT creat +# define OPEN_MASK 0 +#endif + +namespace { + +inline void +throwNew(JNIEnv* e, const char* class_, const char* message) +{ + jclass c = e->FindClass(class_); + if (c) { + e->ThrowNew(c, message); + e->DeleteLocalRef(c); + } +} + +inline bool +exists(const char* path) +{ + STRUCT_STAT s; + return STAT(path, &s) == 0; +} + +inline int +doOpen(JNIEnv* e, const char* path, int mask) +{ + int fd = OPEN(path, mask | OPEN_MASK, S_IRUSR | S_IWUSR); + if (fd == -1) { + throwNew(e, "java/lang/IOException", strerror(errno)); + } + return fd; +} + +inline void +doClose(JNIEnv* e, jint fd) +{ + int r = CLOSE(fd); + if (r == -1) { + throwNew(e, "java/lang/IOException", strerror(errno)); + } +} + +inline int +doRead(JNIEnv* e, jint fd, jbyte* data, jint length) +{ + int r = READ(fd, data, length); + if (r > 0) { + return r; + } else if (r == 0) { + return -1; + } else { + throwNew(e, "java/lang/IOException", strerror(errno)); + return 0; + } +} + +inline void +doWrite(JNIEnv* e, jint fd, const jbyte* data, jint length) +{ + int r = WRITE(fd, data, length); + if (r != length) { + throwNew(e, "java/lang/IOException", strerror(errno)); + } +} + +} // namespace + +extern "C" JNIEXPORT jstring JNICALL +Java_java_io_File_toAbsolutePath(JNIEnv* /*e*/, jclass, jstring path) +{ + // todo + return path; +} + +extern "C" JNIEXPORT jlong JNICALL +Java_java_io_File_length(JNIEnv* e, jclass, jstring path) +{ + const char* chars = e->GetStringUTFChars(path, 0); + if (chars) { + STRUCT_STAT s; + int r = STAT(chars, &s); + if (r == 0) { + return s.st_size; + } + e->ReleaseStringUTFChars(path, chars); + } + + return -1; +} + +extern "C" JNIEXPORT void JNICALL +Java_java_io_File_mkdir(JNIEnv* e, jclass, jstring path) +{ + const char* chars = e->GetStringUTFChars(path, 0); + if (chars) { + if (not exists(chars)) { + int r = ::MKDIR(chars, 0700); + if (r != 0) { + throwNew(e, "java/lang/IOException", strerror(errno)); + } + } + e->ReleaseStringUTFChars(path, chars); + } +} + +extern "C" JNIEXPORT void JNICALL +Java_java_io_File_createNewFile(JNIEnv* e, jclass, jstring path) +{ + const char* chars = e->GetStringUTFChars(path, 0); + if (chars) { + if (not exists(chars)) { + int fd = CREAT(chars, 0600); + if (fd == -1) { + throwNew(e, "java/lang/IOException", strerror(errno)); + } else { + doClose(e, fd); + } + } + e->ReleaseStringUTFChars(path, chars); + } +} + +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_exists(JNIEnv* e, jclass, jstring path) +{ + const char* chars = e->GetStringUTFChars(path, 0); + if (chars) { + bool v = exists(chars); + e->ReleaseStringUTFChars(path, chars); + return v; + } else { + return false; + } +} + +extern "C" JNIEXPORT jint JNICALL +Java_java_io_FileInputStream_open(JNIEnv* e, jclass, jstring path) +{ + const char* chars = e->GetStringUTFChars(path, 0); + if (chars) { + int fd = doOpen(e, chars, O_RDONLY); + e->ReleaseStringUTFChars(path, chars); + return fd; + } else { + return -1; + } +} + +extern "C" JNIEXPORT jint JNICALL +Java_java_io_FileInputStream_read__I(JNIEnv* e, jclass, jint fd) +{ + jbyte data; + int r = doRead(e, fd, &data, 1); + if (r <= 0) { + return -1; + } else { + return data; + } +} + +extern "C" JNIEXPORT jint JNICALL +Java_java_io_FileInputStream_read__I_3BII +(JNIEnv* e, jclass, jint fd, jbyteArray b, jint offset, jint length) +{ + jbyte* data = static_cast<jbyte*>(malloc(length)); + if (data == 0) { + throwNew(e, "java/lang/OutOfMemoryError", 0); + return 0; + } + + int r = doRead(e, fd, data, length); + + e->SetByteArrayRegion(b, offset, length, data); + + free(data); + + return r; +} + +extern "C" JNIEXPORT void JNICALL +Java_java_io_FileInputStream_close(JNIEnv* e, jclass, jint fd) +{ + doClose(e, fd); +} + +extern "C" JNIEXPORT jint JNICALL +Java_java_io_FileOutputStream_open(JNIEnv* e, jclass, jstring path) +{ + const char* chars = e->GetStringUTFChars(path, 0); + if (chars) { + int fd = doOpen(e, chars, O_WRONLY | O_CREAT); + e->ReleaseStringUTFChars(path, chars); + return fd; + } else { + return -1; + } +} + +extern "C" JNIEXPORT void JNICALL +Java_java_io_FileOutputStream_write__II(JNIEnv* e, jclass, jint fd, jint c) +{ + jbyte data = c; + doWrite(e, fd, &data, 1); +} + +extern "C" JNIEXPORT void JNICALL +Java_java_io_FileOutputStream_write__I_3BII +(JNIEnv* e, jclass, jint fd, jbyteArray b, jint offset, jint length) +{ + jbyte* data = static_cast<jbyte*>(malloc(length)); + if (data == 0) { + throwNew(e, "java/lang/OutOfMemoryError", 0); + return; + } + + e->GetByteArrayRegion(b, offset, length, data); + + if (not e->ExceptionCheck()) { + doWrite(e, fd, data, length); + } + + free(data); +} + +extern "C" JNIEXPORT void JNICALL +Java_java_io_FileOutputStream_close(JNIEnv* e, jclass, jint fd) +{ + doClose(e, fd); +} diff --git a/classpath/java/lang/System.cpp b/classpath/java-lang.cpp similarity index 75% rename from classpath/java/lang/System.cpp rename to classpath/java-lang.cpp index 7cb7402375..b8c961c4e4 100644 --- a/classpath/java/lang/System.cpp +++ b/classpath/java-lang.cpp @@ -9,14 +9,13 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring key) { jstring value = 0; - jboolean isCopy; - const char* chars = e->GetStringUTFChars(key, &isCopy); + const char* chars = e->GetStringUTFChars(key, 0); if (chars) { if (strcmp(chars, "line.separator") == 0) { value = e->NewStringUTF("\n"); } + e->ReleaseStringUTFChars(key, chars); } - e->ReleaseStringUTFChars(key, chars); return value; } diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java new file mode 100644 index 0000000000..1f6bbb51b0 --- /dev/null +++ b/classpath/java/io/File.java @@ -0,0 +1,61 @@ +package java.io; + +public class File { + private final String path; + + public File(String path) { + if (path == null) throw new NullPointerException(); + this.path = path; + } + + public File(String parent, String child) { + this(parent + "/" + child); + } + + public File(File parent, String child) { + this(parent.getPath() + "/" + child); + } + + public String getName() { + int index = path.lastIndexOf("/"); + if (index >= 0) { + return path.substring(index + 1); + } else { + return path; + } + } + + public String getPath() { + return path; + } + + private static native String toAbsolutePath(String path); + + public String getAbsolutePath() { + return toAbsolutePath(path); + } + + private static native long length(String path); + + public long length() { + return length(path); + } + + private static native boolean exists(String path); + + public boolean exists() { + return exists(path); + } + + private static native void mkdir(String path); + + public void mkdir() { + mkdir(path); + } + + private static native void createNewFile(String path); + + public void createNewFile() { + createNewFile(path); + } +} diff --git a/classpath/java/io/FileInputStream.cpp b/classpath/java/io/FileInputStream.cpp deleted file mode 100644 index 0da02c68f1..0000000000 --- a/classpath/java/io/FileInputStream.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include "jni.h" - -#undef JNIEXPORT -#define JNIEXPORT __attribute__ ((visibility("default"))) - -#ifdef WIN32 -# include <io.h> -# define CLOSE _close -# define READ _read -#else -# include <unistd.h> -# define CLOSE close -# define READ read -#endif - -namespace { - -int -doRead(JNIEnv* e, jint fd, jbyte* data, jint length) -{ - int r = READ(fd, data, length); - if (r > 0) { - return r; - } else if (r == 0) { - return -1; - } else { - e->ThrowNew(e->FindClass("java/lang/IOException"), strerror(errno)); - return 0; - } -} - -} // namespace - -extern "C" JNIEXPORT jint JNICALL -Java_java_io_FileInputStream_read__I(JNIEnv* e, jclass, jint fd) -{ - jbyte data; - int r = doRead(e, fd, &data, 1); - if (r <= 0) { - return -1; - } else { - return data; - } -} - -extern "C" JNIEXPORT jint JNICALL -Java_java_io_FileInputStream_read__I_3BII -(JNIEnv* e, jclass, jint fd, jbyteArray b, jint offset, jint length) -{ - jbyte* data = static_cast<jbyte*>(malloc(length)); - if (data == 0) { - e->ThrowNew(e->FindClass("java/lang/OutOfMemoryError"), 0); - return 0; - } - - int r = doRead(e, fd, data, length); - - e->SetByteArrayRegion(b, offset, length, data); - - free(data); - - return r; -} - -extern "C" JNIEXPORT void JNICALL -Java_java_io_FileInputStream_close(JNIEnv* e, jclass, jint fd) -{ - int r = CLOSE(fd); - if (r == -1) { - e->ThrowNew(e->FindClass("java/lang/IOException"), strerror(errno)); - } -} diff --git a/classpath/java/io/FileInputStream.java b/classpath/java/io/FileInputStream.java index d01f77325f..992d959ca7 100644 --- a/classpath/java/io/FileInputStream.java +++ b/classpath/java/io/FileInputStream.java @@ -7,6 +7,16 @@ public class FileInputStream extends InputStream { this.fd = fd.value; } + public FileInputStream(String path) throws IOException { + fd = open(path); + } + + public FileInputStream(File file) throws IOException { + this(file.getPath()); + } + + private static native int open(String path) throws IOException; + private static native int read(int fd) throws IOException; private static native int read(int fd, byte[] b, int offset, int length) @@ -19,6 +29,14 @@ public class FileInputStream extends InputStream { } public int read(byte[] b, int offset, int length) throws IOException { + if (b == null) { + throw new NullPointerException(); + } + + if (offset < 0 || offset + length > b.length) { + throw new ArrayIndexOutOfBoundsException(); + } + return read(fd, b, offset, length); } diff --git a/classpath/java/io/FileOutputStream.cpp b/classpath/java/io/FileOutputStream.cpp deleted file mode 100644 index 3fcc3d47a6..0000000000 --- a/classpath/java/io/FileOutputStream.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include "jni.h" - -#undef JNIEXPORT -#define JNIEXPORT __attribute__ ((visibility("default"))) - -#ifdef WIN32 -# include <io.h> -# define CLOSE _close -# define WRITE _write -#else -# include <unistd.h> -# define CLOSE close -# define WRITE write -#endif - -namespace { - -void -doWrite(JNIEnv* e, jint fd, const jbyte* data, jint length) -{ - int r = WRITE(fd, data, length); - if (r != length) { - e->ThrowNew(e->FindClass("java/lang/IOException"), strerror(errno)); - } -} - -} // namespace - -extern "C" JNIEXPORT void JNICALL -Java_java_io_FileOutputStream_write__II(JNIEnv* e, jclass, jint fd, jint c) -{ - jbyte data = c; - doWrite(e, fd, &data, 1); -} - -extern "C" JNIEXPORT void JNICALL -Java_java_io_FileOutputStream_write__I_3BII -(JNIEnv* e, jclass, jint fd, jbyteArray b, jint offset, jint length) -{ - jbyte* data = static_cast<jbyte*>(malloc(length)); - if (data == 0) { - e->ThrowNew(e->FindClass("java/lang/OutOfMemoryError"), 0); - return; - } - - e->GetByteArrayRegion(b, offset, length, data); - - if (not e->ExceptionCheck()) { - doWrite(e, fd, data, length); - } - - free(data); -} - -extern "C" JNIEXPORT void JNICALL -Java_java_io_FileOutputStream_close(JNIEnv* e, jclass, jint fd) -{ - int r = CLOSE(fd); - if (r == -1) { - e->ThrowNew(e->FindClass("java/lang/IOException"), strerror(errno)); - } -} diff --git a/classpath/java/io/FileOutputStream.java b/classpath/java/io/FileOutputStream.java index e6b99a3222..e2dda678da 100644 --- a/classpath/java/io/FileOutputStream.java +++ b/classpath/java/io/FileOutputStream.java @@ -7,6 +7,16 @@ public class FileOutputStream extends OutputStream { this.fd = fd.value; } + public FileOutputStream(String path) throws IOException { + fd = open(path); + } + + public FileOutputStream(File file) throws IOException { + this(file.getPath()); + } + + private static native int open(String path) throws IOException; + public static native void write(int fd, int c) throws IOException; public static native void write(int fd, byte[] b, int offset, int length) @@ -19,6 +29,14 @@ public class FileOutputStream extends OutputStream { } public void write(byte[] b, int offset, int length) throws IOException { + if (b == null) { + throw new NullPointerException(); + } + + if (offset < 0 || offset + length > b.length) { + throw new ArrayIndexOutOfBoundsException(); + } + write(fd, b, offset, length); } diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index bac9087698..482de19b1c 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -87,6 +87,42 @@ public final class String implements Comparable<String> { } } + public int indexOf(String s) { + if (s.length == 0) return 0; + + for (int i = 0; i < length - s.length; ++i) { + int j = 0; + for (; j < s.length; ++j) { + if (charAt(i + j) != s.charAt(j)) { + break; + } + } + if (j == s.length) { + return i; + } + } + + return -1; + } + + public int lastIndexOf(String s) { + if (s.length == 0) return length; + + for (int i = length - s.length; i >= 0; --i) { + int j = 0; + for (; j < s.length && i + j < length; ++j) { + if (charAt(i + j) != s.charAt(j)) { + break; + } + } + if (j == s.length) { + return i; + } + } + + return -1; + } + public String substring(int start) { return substring(start, length); } diff --git a/makefile b/makefile index ca9db33a67..c29bec3b08 100644 --- a/makefile +++ b/makefile @@ -16,7 +16,7 @@ src = src classpath = classpath test = test -input = $(cls)/Hello.class +input = $(cls)/Reflection.class cxx = g++ cc = gcc diff --git a/src/builtin.cpp b/src/builtin.cpp index 31b93b87af..12991e84a0 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -23,14 +23,8 @@ replace(char a, char b, char* c) for (; *c; ++c) if (*c == a) *c = b; } -} // namespace - -namespace vm { - -namespace builtin { - jstring -toString(Thread* t, jobject this_) +Object_toString(Thread* t, jobject this_) { object s = makeString (t, "%s@%p", @@ -41,31 +35,31 @@ toString(Thread* t, jobject this_) } jclass -getClass(Thread* t, jobject this_) +Object_getClass(Thread* t, jobject this_) { return pushReference(t, objectClass(t, *this_)); } void -wait(Thread* t, jobject this_, jlong milliseconds) +Object_wait(Thread* t, jobject this_, jlong milliseconds) { vm::wait(t, *this_, milliseconds); } void -notify(Thread* t, jobject this_) +Object_notify(Thread* t, jobject this_) { vm::notify(t, *this_); } void -notifyAll(Thread* t, jobject this_) +Object_notifyAll(Thread* t, jobject this_) { vm::notifyAll(t, *this_); } jclass -forName(Thread* t, jclass, jstring name) +Class_forName(Thread* t, jclass, jstring name) { if (LIKELY(name)) { object n = makeByteArray(t, stringLength(t, *name) + 1, false); @@ -95,7 +89,7 @@ forName(Thread* t, jclass, jstring name) } jboolean -isAssignableFrom(Thread* t, jobject this_, jclass that) +Class_isAssignableFrom(Thread* t, jobject this_, jclass that) { if (LIKELY(that)) { return vm::isAssignableFrom(t, *this_, *that); @@ -106,7 +100,7 @@ isAssignableFrom(Thread* t, jobject this_, jclass that) } jobject -get(Thread* t, jobject this_, jobject instancep) +Field_get(Thread* t, jobject this_, jobject instancep) { object field = *this_; @@ -169,7 +163,8 @@ get(Thread* t, jobject this_, jobject instancep) } jobject -invoke(Thread* t, jobject this_, jobject instancep, jobjectArray argumentsp) +Method_invoke(Thread* t, jobject this_, jobject instancep, + jobjectArray argumentsp) { object method = *this_; @@ -206,25 +201,9 @@ invoke(Thread* t, jobject this_, jobject instancep, jobjectArray argumentsp) return 0; } -jobject -currentThread(Thread* t, jclass) -{ - return pushReference(t, t->javaThread); -} - void -sleep(Thread* t, jclass, jlong milliseconds) -{ - if (milliseconds == 0) milliseconds = INT64_MAX; - - ENTER(t, Thread::IdleState); - - t->vm->system->sleep(milliseconds); -} - -void -arraycopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, - jint dstOffset, jint length) +System_arraycopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, + jint dstOffset, jint length) { if (LIKELY(src and dst)) { object s = *src; @@ -263,13 +242,13 @@ arraycopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, } jlong -currentTimeMillis(Thread* t, jclass) +System_currentTimeMillis(Thread* t, jclass) { return t->vm->system->now(); } void -loadLibrary(Thread* t, jobject, jstring name) +Runtime_loadLibrary(Thread* t, jobject, jstring name) { if (LIKELY(name)) { char n[stringLength(t, *name) + 1]; @@ -297,7 +276,7 @@ loadLibrary(Thread* t, jobject, jstring name) } void -gc(Thread* t, jobject) +Runtime_gc(Thread* t, jobject) { ENTER(t, Thread::ExclusiveState); @@ -305,13 +284,13 @@ gc(Thread* t, jobject) } void -exit(Thread* t, jobject, jint code) +Runtime_exit(Thread* t, jobject, jint code) { t->vm->system->exit(code); } jobject -trace(Thread* t, jclass, jint skipCount) +Throwable_trace(Thread* t, jclass, jint skipCount) { int frame = t->frame; while (skipCount-- and frame >= 0) { @@ -334,7 +313,7 @@ trace(Thread* t, jclass, jint skipCount) } jarray -resolveTrace(Thread* t, jclass, jobject trace) +Throwable_resolveTrace(Thread* t, jclass, jobject trace) { unsigned length = arrayLength(t, *trace); object array = makeObjectArray @@ -367,8 +346,23 @@ resolveTrace(Thread* t, jclass, jobject trace) return pushReference(t, array); } +jobject +Thread_currentThread(Thread* t, jclass) +{ + return pushReference(t, t->javaThread); +} + void -start(Thread* t, jobject this_) +Thread_sleep(Thread* t, jclass, jlong milliseconds) +{ + if (milliseconds == 0) milliseconds = INT64_MAX; + + ENTER(t, Thread::IdleState); + + t->vm->system->sleep(milliseconds); +} +void +Thread_start(Thread* t, jobject this_) { Thread* p = reinterpret_cast<Thread*>(threadPeer(t, *this_)); if (p) { @@ -413,56 +407,62 @@ start(Thread* t, jobject this_) } } +} // namespace + +namespace vm { + void -populate(Thread* t, object map) +populateBuiltinMap(Thread* t, object map) { struct { const char* key; void* value; } builtins[] = { { "Java_java_lang_Class_forName", - reinterpret_cast<void*>(forName) }, + reinterpret_cast<void*>(::Class_forName) }, { "Java_java_lang_Class_isAssignableFrom", - reinterpret_cast<void*>(isAssignableFrom) }, + reinterpret_cast<void*>(::Class_isAssignableFrom) }, { "Java_java_lang_System_arraycopy", - reinterpret_cast<void*>(arraycopy) }, + reinterpret_cast<void*>(::System_arraycopy) }, + { "Java_java_lang_System_currentTimeMillis", + reinterpret_cast<void*>(::System_currentTimeMillis) }, { "Java_java_lang_Runtime_loadLibrary", - reinterpret_cast<void*>(loadLibrary) }, + reinterpret_cast<void*>(::Runtime_loadLibrary) }, { "Java_java_lang_Runtime_gc", - reinterpret_cast<void*>(gc) }, + reinterpret_cast<void*>(::Runtime_gc) }, { "Java_java_lang_Runtiime_exit", - reinterpret_cast<void*>(exit) }, + reinterpret_cast<void*>(::Runtime_exit) }, { "Java_java_lang_Thread_doStart", - reinterpret_cast<void*>(start) }, + reinterpret_cast<void*>(::Thread_start) }, { "Java_java_lang_Thread_currentThread", - reinterpret_cast<void*>(currentThread) }, + reinterpret_cast<void*>(::Thread_currentThread) }, { "Java_java_lang_Thread_sleep", - reinterpret_cast<void*>(sleep) }, + reinterpret_cast<void*>(::Thread_sleep) }, { "Java_java_lang_Throwable_resolveTrace", - reinterpret_cast<void*>(resolveTrace) }, + reinterpret_cast<void*>(::Throwable_resolveTrace) }, { "Java_java_lang_Throwable_trace", - reinterpret_cast<void*>(trace) }, + reinterpret_cast<void*>(::Throwable_trace) }, { "Java_java_lang_Object_getClass", - reinterpret_cast<void*>(getClass) }, + reinterpret_cast<void*>(::Object_getClass) }, { "Java_java_lang_Object_notify", - reinterpret_cast<void*>(notify) }, + reinterpret_cast<void*>(::Object_notify) }, { "Java_java_lang_Object_notifyAll", - reinterpret_cast<void*>(notifyAll) }, + reinterpret_cast<void*>(::Object_notifyAll) }, { "Java_java_lang_Object_toString", - reinterpret_cast<void*>(toString) }, + reinterpret_cast<void*>(::Object_toString) }, { "Java_java_lang_Object_wait", - reinterpret_cast<void*>(wait) }, + reinterpret_cast<void*>(::Object_wait) }, { "Java_java_lang_reflect_Field_get", - reinterpret_cast<void*>(get) }, + reinterpret_cast<void*>(::Field_get) }, { "Java_java_lang_reflect_Method_invoke", - reinterpret_cast<void*>(invoke) }, + reinterpret_cast<void*>(::Method_invoke) }, { 0, 0 } }; @@ -476,6 +476,4 @@ populate(Thread* t, object map) } } -} // namespace builtin - } // namespace vm diff --git a/src/builtin.h b/src/builtin.h index 3c03ffba8c..ae2bb1dd9c 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -5,12 +5,8 @@ namespace vm { -namespace builtin { - void -populate(Thread* t, object map); - -} // namespace builtin +populateBuiltinMap(Thread* t, object map); } // namespace vm diff --git a/src/jnienv.cpp b/src/jnienv.cpp index c373b9b03f..8fee8bac87 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1,9 +1,9 @@ #include "jnienv.h" #include "machine.h" -namespace vm { +using namespace vm; -namespace jni { +namespace { jsize GetStringUTFLength(Thread* t, jstring s) @@ -41,16 +41,84 @@ NewStringUTF(Thread* t, const char* chars) } void -populate(JNIEnvVTable* table) +GetByteArrayRegion(Thread* t, jbyteArray array, jint offset, jint length, + jbyte* dst) +{ + ENTER(t, Thread::ActiveState); + + memcpy(dst, &byteArrayBody(t, *array, offset), length); +} + +void +SetByteArrayRegion(Thread* t, jbyteArray array, jint offset, jint length, + const jbyte* src) +{ + ENTER(t, Thread::ActiveState); + + memcpy(&byteArrayBody(t, *array, offset), src, length); +} + +jclass +FindClass(Thread* t, const char* name) +{ + ENTER(t, Thread::ActiveState); + + object n = makeByteArray(t, strlen(name) + 1, false); + memcpy(&byteArrayBody(t, n, 0), name, byteArrayLength(t, n)); + + return pushReference(t, resolveClass(t, n)); +} + +jint +ThrowNew(Thread* t, jclass c, const char* message) +{ + if (t->exception) { + return -1; + } + + ENTER(t, Thread::ActiveState); + + object m = 0; + PROTECT(t, m); + + if (message) { + m = makeString(t, "%s", message); + } + + object trace = makeTrace(t); + PROTECT(t, trace); + + t->exception = make(t, *c); + set(t, throwableMessageUnsafe(t, t->exception), m); + set(t, throwableTraceUnsafe(t, t->exception), trace); + + return 0; +} + +jboolean +ExceptionCheck(Thread* t) +{ + return t->exception != 0; +} + +} // namespace + +namespace vm { + +void +populateJNITable(JNIEnvVTable* table) { memset(table, 0, sizeof(JNIEnvVTable)); - table->GetStringUTFLength = GetStringUTFLength; - table->GetStringUTFChars = GetStringUTFChars; - table->ReleaseStringUTFChars = ReleaseStringUTFChars; - table->NewStringUTF = NewStringUTF; + table->GetStringUTFLength = ::GetStringUTFLength; + table->GetStringUTFChars = ::GetStringUTFChars; + table->ReleaseStringUTFChars = ::ReleaseStringUTFChars; + table->NewStringUTF = ::NewStringUTF; + table->GetByteArrayRegion = ::GetByteArrayRegion; + table->SetByteArrayRegion = ::SetByteArrayRegion; + table->FindClass = ::FindClass; + table->ThrowNew = ::ThrowNew; + table->ExceptionCheck = ::ExceptionCheck; } -} // namespace jni - } // namespace vm diff --git a/src/jnienv.h b/src/jnienv.h index c9454e1598..98b6b461fb 100644 --- a/src/jnienv.h +++ b/src/jnienv.h @@ -5,12 +5,8 @@ namespace vm { -namespace jni { - void -populate(JNIEnvVTable* table); - -} // namespace jni +populateJNITable(JNIEnvVTable* table); } // namespace vm diff --git a/src/machine.cpp b/src/machine.cpp index 0b73a80a57..99a2ccc040 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -468,7 +468,7 @@ makeJNIName(Thread* t, object method, bool decorate) for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1 and byteArrayBody(t, methodSpec, i) != ')'; ++i) { - index += mangle(byteArrayBody(t, className, i), + index += mangle(byteArrayBody(t, methodSpec, i), &byteArrayBody(t, name, index)); } } @@ -962,12 +962,12 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) if (flags & ACC_NATIVE) { object p = hashMapFindNode - (t, nativeMap, method, methodHash, methodEqual); + (t, nativeMap, methodName(t, method), byteArrayHash, byteArrayEqual); if (p) { set(t, tripleSecond(t, p), method); } else { - hashMapInsert(t, nativeMap, method, 0, methodHash); + hashMapInsert(t, nativeMap, methodName(t, method), 0, byteArrayHash); } } @@ -981,7 +981,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) PROTECT(t, method); object overloaded = hashMapFind - (t, nativeMap, method, methodHash, methodEqual); + (t, nativeMap, methodName(t, method), byteArrayHash, byteArrayEqual); object jniName = makeJNIName(t, method, overloaded); set(t, methodCode(t, method), jniName); @@ -1283,7 +1283,7 @@ Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder): tenuredWeakReferences(0), unsafe(false) { - jni::populate(&jniEnvVTable); + populateJNITable(&jniEnvVTable); if (not system->success(system->make(&stateLock)) or not system->success(system->make(&heapLock)) or @@ -1374,7 +1374,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): m->builtinMap = makeHashMap(this, NormalMap, 0, 0); m->monitorMap = makeHashMap(this, WeakMap, 0, 0); - builtin::populate(t, m->builtinMap); + populateBuiltinMap(t, m->builtinMap); t->javaThread = makeThread(t, 0, 0, reinterpret_cast<int64_t>(t)); } else { @@ -1585,6 +1585,28 @@ allocate2(Thread* t, unsigned sizeInBytes) } } +object +make(Thread* t, object class_) +{ + PROTECT(t, class_); + unsigned sizeInBytes = pad(classFixedSize(t, class_)); + object instance = allocate(t, sizeInBytes); + *static_cast<object*>(instance) = class_; + memset(static_cast<object*>(instance) + 1, 0, + sizeInBytes - sizeof(object)); + + if (UNLIKELY(classVmFlags(t, class_) & WeakReferenceFlag)) { + PROTECT(t, instance); + + ACQUIRE(t, t->vm->referenceLock); + + jreferenceNextUnsafe(t, instance) = t->vm->weakReferences; + t->vm->weakReferences = instance; + } + + return instance; +} + object makeByteArray(Thread* t, const char* format, ...) { diff --git a/src/machine.h b/src/machine.h index 3557243b87..7b2668d56e 100644 --- a/src/machine.h +++ b/src/machine.h @@ -6,8 +6,6 @@ #include "heap.h" #include "class-finder.h" -#define JNIEXPORT __attribute__ ((visibility("default"))) -#define JNIIMPORT __attribute__ ((visibility("hidden"))) #define JNICALL #define PROTECT(thread, name) \ @@ -22,7 +20,7 @@ namespace vm { const bool Verbose = false; -const bool DebugRun = false; +const bool DebugRun = true; const bool DebugStack = false; const bool DebugMonitors = false; @@ -1471,6 +1469,9 @@ makeUnsatisfiedLinkError(Thread* t, object message) return makeUnsatisfiedLinkError(t, message, trace, 0); } +object +make(Thread* t, object class_); + object makeByteArray(Thread* t, const char* format, ...); diff --git a/src/run.cpp b/src/run.cpp index 106fcdf5f4..4409382745 100644 --- a/src/run.cpp +++ b/src/run.cpp @@ -76,28 +76,6 @@ popFrame(Thread* t) } } -object -make(Thread* t, object class_) -{ - PROTECT(t, class_); - unsigned sizeInBytes = pad(classFixedSize(t, class_)); - object instance = allocate(t, sizeInBytes); - *static_cast<object*>(instance) = class_; - memset(static_cast<object*>(instance) + 1, 0, - sizeInBytes - sizeof(object)); - - if (UNLIKELY(classVmFlags(t, class_) & WeakReferenceFlag)) { - PROTECT(t, instance); - - ACQUIRE(t, t->vm->referenceLock); - - jreferenceNextUnsafe(t, instance) = t->vm->weakReferences; - t->vm->weakReferences = instance; - } - - return instance; -} - inline void setStatic(Thread* t, object field, object value) { diff --git a/test/test.sh b/test/test.sh index 2d1a228d64..ffdeca54fb 100644 --- a/test/test.sh +++ b/test/test.sh @@ -36,6 +36,8 @@ for test in ${tests}; do fi done +echo + if [ -n "${trouble}" ]; then - printf "\nsee ${log} for output\n" + printf "see ${log} for output\n" fi