diff --git a/.gitignore b/.gitignore index 8028923871..201518bb12 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ build .project .settings bin +/lib +/distrib diff --git a/classpath/avian/Addendum.java b/classpath/avian/Addendum.java index b363ecfc7c..b5c86d9008 100644 --- a/classpath/avian/Addendum.java +++ b/classpath/avian/Addendum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2010, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index 276be33fe9..48ac3bdd07 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2010, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/Classes.java b/classpath/avian/Classes.java index 1d2ad9370e..a445114022 100644 --- a/classpath/avian/Classes.java +++ b/classpath/avian/Classes.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Avian Contributors +/* Copyright (c) 2010-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 4ca98d86bd..a2d4948c8b 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2010, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/Machine.java b/classpath/avian/Machine.java index cbc62efae6..6115cf0c37 100644 --- a/classpath/avian/Machine.java +++ b/classpath/avian/Machine.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -10,8 +10,16 @@ package avian; +import sun.misc.Unsafe; + public abstract class Machine { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + public static native void dumpHeap(String outputFile); + public static Unsafe getUnsafe() { + return unsafe; + } + } diff --git a/classpath/avian/MethodAddendum.java b/classpath/avian/MethodAddendum.java index 597c169179..e2ae385b81 100644 --- a/classpath/avian/MethodAddendum.java +++ b/classpath/avian/MethodAddendum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2010, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/OpenJDK.java b/classpath/avian/OpenJDK.java index de9c6f1f40..95248b2398 100644 --- a/classpath/avian/OpenJDK.java +++ b/classpath/avian/OpenJDK.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Avian Contributors +/* Copyright (c) 2010-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/Stream.java b/classpath/avian/Stream.java index 14e6fc5773..a0762e6213 100644 --- a/classpath/avian/Stream.java +++ b/classpath/avian/Stream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index defb9d490a..5c228cd9c1 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/VMClass.java b/classpath/avian/VMClass.java index 5a3fdc662f..c3e87353b5 100644 --- a/classpath/avian/VMClass.java +++ b/classpath/avian/VMClass.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/VMField.java b/classpath/avian/VMField.java index 8df0d426c5..2e986321da 100644 --- a/classpath/avian/VMField.java +++ b/classpath/avian/VMField.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/http/Handler.java b/classpath/avian/http/Handler.java new file mode 100644 index 0000000000..70e7cea519 --- /dev/null +++ b/classpath/avian/http/Handler.java @@ -0,0 +1,26 @@ +/* Copyright (c) 2012, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package avian.http; + +import java.net.URL; +import java.net.URLStreamHandler; +import java.net.URLConnection; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +public class Handler extends URLStreamHandler { + protected URLConnection openConnection(URL url) { + throw new UnsupportedOperationException(); + } +} diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 9175c6e978..86020f57c8 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -32,10 +32,13 @@ # define STAT _wstat # define STRUCT_STAT struct _stat # define MKDIR(path, mode) _wmkdir(path) +# define CHMOD(path, mode) _wchmod(path, mode) # define UNLINK _wunlink # define RENAME _wrename # define OPEN_MASK O_BINARY +# define CHECK_X_OK R_OK + # ifdef _MSC_VER # define S_ISREG(x) ((x) & _S_IFREG) # define S_ISDIR(x) ((x) & _S_IFDIR) @@ -45,7 +48,6 @@ # define R_OK 4 # else # define OPEN _wopen -# define CREAT _wcreat # endif # define GET_CHARS GetStringChars @@ -67,11 +69,13 @@ typedef wchar_t char_t; # define STAT stat # define STRUCT_STAT struct stat # define MKDIR mkdir -# define CREAT creat +# define CHMOD chmod # define UNLINK unlink # define RENAME rename # define OPEN_MASK 0 +# define CHECK_X_OK X_OK + # define GET_CHARS GetStringUTFChars # define RELEASE_CHARS ReleaseStringUTFChars @@ -96,12 +100,6 @@ OPEN(string_t path, int mask, int mode) return -1; } } - -inline int -CREAT(string_t path, int mode) -{ - return OPEN(path, _O_CREAT, mode); -} #endif inline bool @@ -178,7 +176,8 @@ inline Mapping* map(JNIEnv* e, string_t path) { Mapping* result = 0; - HANDLE file = CreateFileW(path, FILE_READ_DATA, FILE_SHARE_READ, 0, + HANDLE file = CreateFileW(path, FILE_READ_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (file != INVALID_HANDLE_VALUE) { unsigned size = GetFileSize(file, 0); @@ -317,7 +316,19 @@ extern "C" JNIEXPORT jstring JNICALL Java_java_io_File_toAbsolutePath(JNIEnv* e UNUSED, jclass, jstring path) { #ifdef PLATFORM_WINDOWS - // todo + string_t chars = getChars(e, path); + if (chars) { + const unsigned BufferSize = MAX_PATH; + char_t buffer[BufferSize]; + DWORD success = GetFullPathNameW(chars, BufferSize, buffer, 0); + releaseChars(e, path, chars); + + if (success) { + return e->NewString + (reinterpret_cast(buffer), wcslen(buffer)); + } + } + return path; #else jstring result = path; @@ -388,21 +399,26 @@ Java_java_io_File_mkdir(JNIEnv* e, jclass, jstring path) } } -extern "C" JNIEXPORT void JNICALL +extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_createNewFile(JNIEnv* e, jclass, jstring path) { + bool result = false; string_t chars = getChars(e, path); if (chars) { if (not exists(chars)) { - int fd = CREAT(chars, 0600); + int fd = OPEN(chars, O_CREAT | O_WRONLY | O_EXCL, 0600); if (fd == -1) { - throwNewErrno(e, "java/io/IOException"); + if (errno != EEXIST) { + throwNewErrno(e, "java/io/IOException"); + } } else { + result = true; doClose(e, fd); } } releaseChars(e, path, chars); } + return result; } extern "C" JNIEXPORT void JNICALL @@ -442,6 +458,64 @@ Java_java_io_File_canWrite(JNIEnv* e, jclass, jstring path) return false; } +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_canExecute(JNIEnv* e, jclass, jstring path) +{ + string_t chars = getChars(e, path); + if (chars) { + int r = ACCESS(chars, CHECK_X_OK); + releaseChars(e, path, chars); + return (r == 0); + } + return false; +} + +#ifndef PLATFORM_WINDOWS +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_setExecutable(JNIEnv* e, jclass, jstring path, jboolean executable, jboolean ownerOnly) +{ + string_t chars = getChars(e, path); + if(chars) { + jboolean v; + int mask; + if(ownerOnly) { + mask = S_IXUSR; + } else { + mask = S_IXUSR | S_IXGRP | S_IXOTH; + } + + STRUCT_STAT s; + int r = STAT(chars, &s); + if(r == 0) { + int mode = s.st_mode; + if(executable) { + mode |= mask; + } else { + mode &= ~mask; + } + if(CHMOD(chars, mode) != 0) { + v = false; + } else { + v = true; + } + } else { + v = false; + } + releaseChars(e, path, chars); + return v; + } + return false; +} + +#else // ifndef PLATFORM_WINDOWS + +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_setExecutable(JNIEnv*, jclass, jstring, jboolean executable, jboolean) +{ + return executable; +} + +#endif extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_rename(JNIEnv* e, jclass, jstring old, jstring new_) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index bb087560fe..3cad9680a3 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -631,6 +631,36 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, return r; } +// System.getEnvironment() implementation +// TODO: For Win32, replace usage of deprecated _environ and add Unicode +// support (neither of which is likely to be of great importance). +#ifdef AVIAN_IOS +namespace { + const char* environ[] = { 0 }; +} +#elif defined __APPLE__ +# include +# define environ (*_NSGetEnviron()) +#else +extern char** environ; +#endif +extern "C" JNIEXPORT jobjectArray JNICALL +Java_java_lang_System_getEnvironment(JNIEnv* env, jclass) { + int length; + for (length = 0; environ[length] != 0; ++length) ; + + jobjectArray stringArray = + env->NewObjectArray(length, env->FindClass("java/lang/String"), + env->NewStringUTF("")); + + for (int i = 0; i < length; i++) { + jobject varString = env->NewStringUTF(environ[i]); + env->SetObjectArrayElement(stringArray, i, varString); + } + + return stringArray; +} + extern "C" JNIEXPORT jlong JNICALL Java_java_lang_System_currentTimeMillis(JNIEnv*, jclass) { diff --git a/classpath/java-net.cpp b/classpath/java-net.cpp index 20d853adc2..1cfea1fbc2 100644 --- a/classpath/java-net.cpp +++ b/classpath/java-net.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Avian Contributors +/* Copyright (c) 2010-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java-util-zip.cpp b/classpath/java-util-zip.cpp index f883e528bc..9ae2833332 100644 --- a/classpath/java-util-zip.cpp +++ b/classpath/java-util-zip.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java-util.cpp b/classpath/java-util.cpp index b880ff2d95..4c0a73161c 100644 --- a/classpath/java-util.cpp +++ b/classpath/java-util.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/BufferedInputStream.java b/classpath/java/io/BufferedInputStream.java index 67ac256a21..3f03a7c743 100644 --- a/classpath/java/io/BufferedInputStream.java +++ b/classpath/java/io/BufferedInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/BufferedReader.java b/classpath/java/io/BufferedReader.java index 2618dfdbd6..5b90b62012 100644 --- a/classpath/java/io/BufferedReader.java +++ b/classpath/java/io/BufferedReader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/ByteArrayOutputStream.java b/classpath/java/io/ByteArrayOutputStream.java index f0668da2da..0960dd3008 100644 --- a/classpath/java/io/ByteArrayOutputStream.java +++ b/classpath/java/io/ByteArrayOutputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 9342627bd5..86e093495b 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -35,6 +35,43 @@ public class File implements Serializable { this(parent.getPath() + FileSeparator + child); } + public static File createTempFile(String prefix, String suffix) + throws IOException + { + return createTempFile(prefix, suffix, null); + } + + public static File createTempFile(String prefix, String suffix, + File directory) + throws IOException + { + if(directory == null) { + directory = new File(System.getProperty("java.io.tmpdir")); + } + if(suffix == null) { + suffix = ".tmp"; + } + File ret; + long state = System.currentTimeMillis(); + + do { + ret = generateFile(directory, prefix, state, suffix); + state *= 7; + state += 3; + } while(ret == null); + ret.createNewFile(); + return ret; + } + + private static File generateFile(File directory, String prefix, long state, String suffix) { + File ret = new File(directory, prefix + state + suffix); + if(ret.exists()) { + return null; + } else { + return ret; + } + } + private static String normalize(String path) { if ("\\".equals(FileSeparator)) { return path.replace('/', '\\'); @@ -76,6 +113,22 @@ public class File implements Serializable { public boolean canWrite() { return canWrite(path); } + + private static native boolean canExecute(String path); + + public boolean canExecute() { + return canExecute(path); + } + + private static native boolean setExecutable(String path, boolean executable, boolean ownerOnly); + + public boolean setExecutable(boolean executable) { + return setExecutable(executable, true); + } + + public boolean setExecutable(boolean executable, boolean ownerOnly) { + return setExecutable(path, executable, ownerOnly); + } public String getName() { int index = path.lastIndexOf(FileSeparator); @@ -151,15 +204,10 @@ public class File implements Serializable { } } - private static native void createNewFile(String path) throws IOException; + private static native boolean createNewFile(String path) throws IOException; - public boolean createNewFile() { - try { - createNewFile(path); - return true; - } catch (IOException e) { - return false; - } + public boolean createNewFile() throws IOException { + return createNewFile(path); } public static native void delete(String path) throws IOException; diff --git a/classpath/java/io/FileInputStream.java b/classpath/java/io/FileInputStream.java index 9c614e2f7e..d3cd3cd08e 100644 --- a/classpath/java/io/FileInputStream.java +++ b/classpath/java/io/FileInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -16,6 +16,7 @@ public class FileInputStream extends InputStream { // } private int fd; + private int remaining; public FileInputStream(FileDescriptor fd) { this.fd = fd.value; @@ -23,12 +24,17 @@ public class FileInputStream extends InputStream { public FileInputStream(String path) throws IOException { fd = open(path); + remaining = (int) new File(path).length(); } public FileInputStream(File file) throws IOException { this(file.getPath()); } + public int available() throws IOException { + return remaining; + } + private static native int open(String path) throws IOException; private static native int read(int fd) throws IOException; @@ -39,7 +45,11 @@ public class FileInputStream extends InputStream { public static native void close(int fd) throws IOException; public int read() throws IOException { - return read(fd); + int c = read(fd); + if (c >= 0 && remaining > 0) { + -- remaining; + } + return c; } public int read(byte[] b, int offset, int length) throws IOException { @@ -51,7 +61,11 @@ public class FileInputStream extends InputStream { throw new ArrayIndexOutOfBoundsException(); } - return read(fd, b, offset, length); + int c = read(fd, b, offset, length); + if (c > 0 && remaining > 0) { + remaining -= c; + } + return c; } public void close() throws IOException { diff --git a/classpath/java/io/InputStream.java b/classpath/java/io/InputStream.java index 8e74c2db8d..ec29b52b7a 100644 --- a/classpath/java/io/InputStream.java +++ b/classpath/java/io/InputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/ObjectInputStream.java b/classpath/java/io/ObjectInputStream.java index 45bacc7380..b0f1ec0dd7 100644 --- a/classpath/java/io/ObjectInputStream.java +++ b/classpath/java/io/ObjectInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/ObjectOutputStream.java b/classpath/java/io/ObjectOutputStream.java index 7e45f9d2cc..3f310128bd 100644 --- a/classpath/java/io/ObjectOutputStream.java +++ b/classpath/java/io/ObjectOutputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/PrintStream.java b/classpath/java/io/PrintStream.java index a720fac6a0..7bd27d06b1 100644 --- a/classpath/java/io/PrintStream.java +++ b/classpath/java/io/PrintStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/RandomAccessFile.java b/classpath/java/io/RandomAccessFile.java index cc3c41e757..b6e88dd00e 100644 --- a/classpath/java/io/RandomAccessFile.java +++ b/classpath/java/io/RandomAccessFile.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/Reader.java b/classpath/java/io/Reader.java index a09c8a24e9..2edfd70803 100644 --- a/classpath/java/io/Reader.java +++ b/classpath/java/io/Reader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Character.java b/classpath/java/lang/Character.java index 88025280e8..3e7f1ed269 100644 --- a/classpath/java/lang/Character.java +++ b/classpath/java/lang/Character.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 22b645793a..eb183260d6 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index e245e4c9f1..9f2a853c46 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Enum.java b/classpath/java/lang/Enum.java index cf1d033cc3..8d0d4756b0 100644 --- a/classpath/java/lang/Enum.java +++ b/classpath/java/lang/Enum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Float.java b/classpath/java/lang/Float.java index d466cca2a3..408de61220 100644 --- a/classpath/java/lang/Float.java +++ b/classpath/java/lang/Float.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Package.java b/classpath/java/lang/Package.java index 5cd9b9547e..ed1e4e2985 100644 --- a/classpath/java/lang/Package.java +++ b/classpath/java/lang/Package.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/ReflectiveOperationException.java b/classpath/java/lang/ReflectiveOperationException.java new file mode 100644 index 0000000000..e3c8c0872f --- /dev/null +++ b/classpath/java/lang/ReflectiveOperationException.java @@ -0,0 +1,13 @@ +/* Copyright (c) 2012, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +public class ReflectiveOperationException extends Exception { } diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index 88c8ba71e3..a3c00bcbbf 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/RuntimePermission.java b/classpath/java/lang/RuntimePermission.java new file mode 100644 index 0000000000..a737444a6f --- /dev/null +++ b/classpath/java/lang/RuntimePermission.java @@ -0,0 +1,21 @@ +/* Copyright (c) 2012, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +import java.security.BasicPermission; + +public class RuntimePermission extends BasicPermission { + + public RuntimePermission(String name) { + super(name); + } + +} diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index 83ce12dfa3..24a893ad87 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/System.java b/classpath/java/lang/System.java index 9506fb3457..859121c56d 100644 --- a/classpath/java/lang/System.java +++ b/classpath/java/lang/System.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -17,12 +17,15 @@ import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileDescriptor; +import java.util.Map; +import java.util.Hashtable; import java.util.Properties; public abstract class System { private static final long NanoTimeBaseInMillis = currentTimeMillis(); private static Property properties; + private static Map environment; private static SecurityManager securityManager; // static { @@ -145,4 +148,37 @@ public abstract class System { this.next = next; } } + + public static String getenv(String name) throws NullPointerException, + SecurityException { + if (getSecurityManager() != null) { // is this allowed? + getSecurityManager(). + checkPermission(new RuntimePermission("getenv." + name)); + } + return getenv().get(name); + } + + public static Map getenv() throws SecurityException { + if (getSecurityManager() != null) { // is this allowed? + getSecurityManager().checkPermission(new RuntimePermission("getenv.*")); + } + + if (environment == null) { // build environment table + String[] vars = getEnvironment(); + environment = new Hashtable(vars.length); + for (String var : vars) { // parse name-value pairs + int equalsIndex = var.indexOf('='); + // null names and values are forbidden + if (equalsIndex != -1 && equalsIndex < var.length() - 1) { + environment.put(var.substring(0, equalsIndex), + var.substring(equalsIndex + 1)); + } + } + } + + return environment; + } + + /** Returns the native process environment. */ + private static native String[] getEnvironment(); } diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 4846287daf..539a709169 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -145,8 +145,8 @@ public class Thread implements Runnable { private static native boolean interrupt(long peer); - public boolean interrupted() { - return interrupted(peer); + public static boolean interrupted() { + return interrupted(currentThread().peer); } private static native boolean interrupted(long peer); diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 524cb7613a..8d76a6258f 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/reflect/InvocationHandler.java b/classpath/java/lang/reflect/InvocationHandler.java index 9541797ad3..584ae0c430 100644 --- a/classpath/java/lang/reflect/InvocationHandler.java +++ b/classpath/java/lang/reflect/InvocationHandler.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/reflect/Member.java b/classpath/java/lang/reflect/Member.java index e5e74042c6..09b00759c4 100644 --- a/classpath/java/lang/reflect/Member.java +++ b/classpath/java/lang/reflect/Member.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/reflect/Proxy.java b/classpath/java/lang/reflect/Proxy.java index 2801f96618..06805fc72c 100644 --- a/classpath/java/lang/reflect/Proxy.java +++ b/classpath/java/lang/reflect/Proxy.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2010, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/net/URL.java b/classpath/java/net/URL.java index eb46c61860..f80e327997 100644 --- a/classpath/java/net/URL.java +++ b/classpath/java/net/URL.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -81,7 +81,9 @@ public final class URL { private static URLStreamHandler findHandler(String protocol) throws MalformedURLException { - if ("resource".equals(protocol)) { + if ("http".equals(protocol) || "https".equals(protocol)) { + return new avian.http.Handler(); + } else if ("resource".equals(protocol)) { return new avian.resource.Handler(); } else if ("file".equals(protocol)) { return new avian.file.Handler(); diff --git a/classpath/java/net/URLConnection.java b/classpath/java/net/URLConnection.java index 0219fbe688..0ff8cacb4b 100644 --- a/classpath/java/net/URLConnection.java +++ b/classpath/java/net/URLConnection.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/net/URLStreamHandler.java b/classpath/java/net/URLStreamHandler.java index 5c72deada1..0e08bf45da 100644 --- a/classpath/java/net/URLStreamHandler.java +++ b/classpath/java/net/URLStreamHandler.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -38,9 +38,9 @@ public abstract class URLStreamHandler { host = s.substring(0, slash); } else { host = s.substring(0, colon); - port = Integer.parseInt(s.substring(colon + 1), slash); + port = Integer.parseInt(s.substring(colon + 1, slash)); } - s = s.substring(slash + 1); + s = s.substring(slash); } } diff --git a/classpath/java/nio/Buffer.java b/classpath/java/nio/Buffer.java index c93c11f347..00e34c6932 100644 --- a/classpath/java/nio/Buffer.java +++ b/classpath/java/nio/Buffer.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java index 2dee03f7d9..e63217f6ea 100644 --- a/classpath/java/nio/ByteBuffer.java +++ b/classpath/java/nio/ByteBuffer.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/Channels.java b/classpath/java/nio/channels/Channels.java index 849a16dffc..2e786e70b2 100644 --- a/classpath/java/nio/channels/Channels.java +++ b/classpath/java/nio/channels/Channels.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Avian Contributors +/* Copyright (c) 2010-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/ClosedSelectorException.java b/classpath/java/nio/channels/ClosedSelectorException.java new file mode 100644 index 0000000000..046fc37f4f --- /dev/null +++ b/classpath/java/nio/channels/ClosedSelectorException.java @@ -0,0 +1,13 @@ +/* Copyright (c) 2012, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.nio.channels; + +public class ClosedSelectorException extends IllegalStateException { } diff --git a/classpath/java/nio/channels/SelectableChannel.java b/classpath/java/nio/channels/SelectableChannel.java index 734bce9fc8..0475f6adfe 100644 --- a/classpath/java/nio/channels/SelectableChannel.java +++ b/classpath/java/nio/channels/SelectableChannel.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/ServerSocketChannel.java b/classpath/java/nio/channels/ServerSocketChannel.java index 53e6eec36d..1b27e0f049 100644 --- a/classpath/java/nio/channels/ServerSocketChannel.java +++ b/classpath/java/nio/channels/ServerSocketChannel.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/SocketChannel.java b/classpath/java/nio/channels/SocketChannel.java index 65c9768d88..36fdf06c2e 100644 --- a/classpath/java/nio/channels/SocketChannel.java +++ b/classpath/java/nio/channels/SocketChannel.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/SocketSelector.java b/classpath/java/nio/channels/SocketSelector.java index 2482d0f180..82bcd6da41 100644 --- a/classpath/java/nio/channels/SocketSelector.java +++ b/classpath/java/nio/channels/SocketSelector.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -15,7 +15,7 @@ import java.util.Iterator; import java.net.Socket; class SocketSelector extends Selector { - protected long state; + protected volatile long state; protected final Object lock = new Object(); protected boolean woken = false; @@ -31,7 +31,7 @@ class SocketSelector extends Selector { public Selector wakeup() { synchronized (lock) { - if (! woken) { + if (isOpen() && (! woken)) { woken = true; natWakeup(state); @@ -66,6 +66,10 @@ class SocketSelector extends Selector { } public int doSelect(long interval) throws IOException { + if (! isOpen()) { + throw new ClosedSelectorException(); + } + selectedKeys.clear(); if (clearWoken()) interval = -1; @@ -106,8 +110,13 @@ class SocketSelector extends Selector { return selectedKeys.size(); } - public void close() { - natClose(state); + public synchronized void close() { + synchronized (lock) { + if (isOpen()) { + natClose(state); + state = 0; + } + } } private static native long natInit(); diff --git a/classpath/java/security/CodeSource.java b/classpath/java/security/CodeSource.java index 296f38c128..8ae784177a 100644 --- a/classpath/java/security/CodeSource.java +++ b/classpath/java/security/CodeSource.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/security/ProtectionDomain.java b/classpath/java/security/ProtectionDomain.java index 25673c8ee3..f17bf6810e 100644 --- a/classpath/java/security/ProtectionDomain.java +++ b/classpath/java/security/ProtectionDomain.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/AbstractCollection.java b/classpath/java/util/AbstractCollection.java index 54cd7288df..f7e06bad32 100644 --- a/classpath/java/util/AbstractCollection.java +++ b/classpath/java/util/AbstractCollection.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/ArrayList.java b/classpath/java/util/ArrayList.java index 698f3f79df..d7a61d61ed 100644 --- a/classpath/java/util/ArrayList.java +++ b/classpath/java/util/ArrayList.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index 40c133f753..acb94cb40d 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/Locale.java b/classpath/java/util/Locale.java index 373506bdec..66e685378b 100644 --- a/classpath/java/util/Locale.java +++ b/classpath/java/util/Locale.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index 10b5c90687..9b1798491f 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/Random.java b/classpath/java/util/Random.java index 856f30424a..ac39a4417e 100644 --- a/classpath/java/util/Random.java +++ b/classpath/java/util/Random.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -13,7 +13,9 @@ package java.util; public class Random { private static final long Mask = 0x5DEECE66DL; - private static long nextSeed = 0; + private static final long InitialSeed = 123456789987654321L; + + private static long nextSeed = InitialSeed; private long seed; @@ -22,7 +24,13 @@ public class Random { } public Random() { - setSeed((nextSeed++) ^ System.currentTimeMillis()); + synchronized (Random.class) { + setSeed(nextSeed ^ System.currentTimeMillis()); + nextSeed *= 123456789987654321L; + if (nextSeed == 0) { + nextSeed = InitialSeed; + } + } } public void setSeed(long seed) { diff --git a/classpath/java/util/TreeSet.java b/classpath/java/util/TreeSet.java index 01e76496a2..0faac7ad12 100644 --- a/classpath/java/util/TreeSet.java +++ b/classpath/java/util/TreeSet.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/Vector.java b/classpath/java/util/Vector.java index e95c8df414..0e1dadd7fe 100644 --- a/classpath/java/util/Vector.java +++ b/classpath/java/util/Vector.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/regex/Matcher.java b/classpath/java/util/regex/Matcher.java index 99f9d9daad..dd21a062af 100644 --- a/classpath/java/util/regex/Matcher.java +++ b/classpath/java/util/regex/Matcher.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/zip/Deflater.java b/classpath/java/util/zip/Deflater.java index 8368bb0817..9b6b832039 100644 --- a/classpath/java/util/zip/Deflater.java +++ b/classpath/java/util/zip/Deflater.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/zip/DeflaterOutputStream.java b/classpath/java/util/zip/DeflaterOutputStream.java index 3ee3fcdbb8..c77fbd1a52 100644 --- a/classpath/java/util/zip/DeflaterOutputStream.java +++ b/classpath/java/util/zip/DeflaterOutputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/zip/Inflater.java b/classpath/java/util/zip/Inflater.java index 9f44415194..a4c00e6934 100644 --- a/classpath/java/util/zip/Inflater.java +++ b/classpath/java/util/zip/Inflater.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/zip/ZipEntry.java b/classpath/java/util/zip/ZipEntry.java index 9f18369c52..31359a8507 100644 --- a/classpath/java/util/zip/ZipEntry.java +++ b/classpath/java/util/zip/ZipEntry.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -14,4 +14,8 @@ public abstract class ZipEntry { public abstract String getName(); public abstract int getCompressedSize(); public abstract int getSize(); + + public boolean isDirectory() { + return getName().endsWith("/"); + } } diff --git a/classpath/java/util/zip/ZipFile.java b/classpath/java/util/zip/ZipFile.java index 94d8b99b08..f3d0428e82 100644 --- a/classpath/java/util/zip/ZipFile.java +++ b/classpath/java/util/zip/ZipFile.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -86,7 +86,7 @@ public class ZipFile { } public InputStream getInputStream(ZipEntry entry) throws IOException { - int pointer = ((MyEntry) entry).pointer(); + final int pointer = ((MyEntry) entry).pointer(); int method = compressionMethod(window, pointer); int size = compressedSize(window, pointer); InputStream in = new MyInputStream(file, fileData(window, pointer), size); @@ -99,7 +99,35 @@ public class ZipFile { return in; case Deflated: - return new InflaterInputStream(in, new Inflater(true)); + return new InflaterInputStream(in, new Inflater(true)) { + int remaining = uncompressedSize(window, pointer); + + public int read() throws IOException { + int c = super.read(); + if (c >= 0) { + -- remaining; + } + return c; + } + + public int read(byte[] buffer) throws IOException { + return read(buffer, 0, buffer.length); + } + + public int read(byte[] buffer, int offset, int length) + throws IOException + { + int c = super.read(buffer, offset, length); + if (c > 0) { + remaining -= c; + } + return c; + } + + public int available() { + return remaining; + } + }; default: throw new IOException(); diff --git a/classpath/sun/misc/Unsafe.java b/classpath/sun/misc/Unsafe.java new file mode 100644 index 0000000000..b7613d2559 --- /dev/null +++ b/classpath/sun/misc/Unsafe.java @@ -0,0 +1,50 @@ +package sun.misc; + +public final class Unsafe { + private void Unsafe() { } + + private static final Unsafe Instance = new Unsafe(); + + public static Unsafe getUnsafe() { + return Instance; + } + + public native long allocateMemory(long bytes); + + public native void setMemory + (Object base, long offset, long count, byte value); + + public native void freeMemory(long address); + + public native byte getByte(long address); + + public native void putByte(long address, byte x); + + public native short getShort(long address); + + public native void putShort(long address, short x); + + public native char getChar(long address); + + public native void putChar(long address, char x); + + public native int getInt(long address); + + public native void putInt(long address, int x); + + public native long getLong(long address); + + public native void putLong(long address, long x); + + public native float getFloat(long address); + + public native void putFloat(long address, float x); + + public native double getDouble(long address); + + public native void putDouble(long address, double x); + + public native long getAddress(long address); + + public native void putAddress(long address, long x); +} diff --git a/license.txt b/license.txt index 4ed92c217a..22265643ee 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright (c) 2008-2011, Avian Contributors +Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/makefile b/makefile index 218216f537..86bc33e9b1 100755 --- a/makefile +++ b/makefile @@ -18,9 +18,11 @@ build-platform := \ | sed 's/^cygwin.*$$/cygwin/') arch = $(build-arch) +target-arch = $(arch) bootimage-platform = \ $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))) platform = $(bootimage-platform) +target-platform = $(platform) mode = fast process = compile @@ -51,6 +53,8 @@ test-build = $(build)/test src = src classpath-src = classpath test = test +win32 ?= $(root)/win32 +win64 ?= $(root)/win64 classpath = avian @@ -111,8 +115,13 @@ ifneq ($(openjdk),) else options := $(options)-openjdk test-executable = $(shell pwd)/$(executable-dynamic) - library-path = \ - $(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch) + ifeq ($(build-platform),darwin) + library-path = \ + $(library-path-variable)=$(build):$(openjdk)/jre/lib + else + library-path = \ + $(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch) + endif javahome = "$$($(native-path) "$(openjdk)/jre")" endif @@ -183,8 +192,10 @@ endif build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread -converter-cflags = -D__STDC_CONSTANT_MACROS -Isrc/binaryToObject \ - -fno-rtti -fno-exceptions +converter-cflags = -D__STDC_CONSTANT_MACROS -Isrc/binaryToObject -Isrc/ \ + -fno-rtti -fno-exceptions \ + -DAVIAN_TARGET_ARCH=AVIAN_ARCH_UNKNOWN \ + -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_UNKNOWN cflags = $(build-cflags) @@ -212,6 +223,9 @@ openjdk-extra-cflags = -fvisibility=hidden bootimage-cflags = -DTARGET_BYTES_PER_WORD=$(pointer-size) +developer-dir := $(shell if test -d /Developer; then echo /Developer; \ + else echo /Applications/Xcode.app/Contents/Developer; fi) + ifeq ($(build-arch),powerpc) ifneq ($(arch),$(build-arch)) bootimage-cflags += -DTARGET_OPPOSITE_ENDIAN @@ -221,6 +235,7 @@ endif ifeq ($(arch),i386) pointer-size = 4 endif + ifeq ($(arch),powerpc) asm = powerpc pointer-size = 4 @@ -231,7 +246,6 @@ ifeq ($(arch),powerpc) ifneq ($(platform),darwin) ifneq ($(arch),$(build-arch)) - converter-cflags += -DOPPOSITE_ENDIAN cxx = powerpc-linux-gnu-g++ cc = powerpc-linux-gnu-gcc ar = powerpc-linux-gnu-ar @@ -240,9 +254,11 @@ ifeq ($(arch),powerpc) endif endif endif + ifeq ($(arch),arm) asm = arm pointer-size = 4 + ifeq ($(build-platform),darwin) ios = true else @@ -252,7 +268,7 @@ ifeq ($(arch),arm) ifneq ($(arch),$(build-arch)) ifeq ($(platform),darwin) - ios-bin = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin + ios-bin = $(developer-dir)/Platforms/iPhoneOS.platform/Developer/usr/bin cxx = $(ios-bin)/g++ cc = $(ios-bin)/gcc ar = $(ios-bin)/ar @@ -272,10 +288,6 @@ ifeq ($(ios),true) cflags += -DAVIAN_IOS endif -ifeq ($(platform),linux) - bootimage-cflags += -DTARGET_PLATFORM_LINUX -endif - ifeq ($(build-platform),darwin) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) cflags += -I/System/Library/Frameworks/JavaVM.framework/Headers/ @@ -283,8 +295,6 @@ ifeq ($(build-platform),darwin) endif ifeq ($(platform),darwin) - bootimage-cflags += -DTARGET_PLATFORM_DARWIN - ifeq (${OSX_SDK_SYSROOT},) OSX_SDK_SYSROOT = 10.4u endif @@ -303,9 +313,11 @@ ifeq ($(platform),darwin) endif version-script-flag = - lflags = $(common-lflags) -ldl -framework CoreFoundation + lflags = $(common-lflags) -ldl -framework CoreFoundation \ + -Wl,-compatibility_version,1.0.0 ifneq ($(arch),arm) - lflags += -framework CoreServices + lflags += -framework CoreServices -framework SystemConfiguration \ + -framework Security endif ifeq ($(bootimage),true) bootimage-lflags = -Wl,-segprot,__RWX,rwx,rwx @@ -315,12 +327,22 @@ ifeq ($(platform),darwin) so-suffix = .dylib shared = -dynamiclib + sdk-dir = $(developer-dir)/Platforms/iPhoneOS.platform/Developer/SDKs + ifeq ($(arch),arm) - ifeq ($(build-arch),powerpc) - converter-cflags += -DOPPOSITE_ENDIAN + ios-version := \ + $(shell if test -d $(sdk-dir)/iPhoneOS5.1.sdk; then echo 5.1; \ + elif test -d $(sdk-dir)/iPhoneOS5.0.sdk; then echo 5.0; \ + elif test -d $(sdk-dir)/iPhoneOS4.3.sdk; then echo 4.3; \ + elif test -d $(sdk-dir)/iPhoneOS4.2.sdk; then echo 4.2; \ + else echo; fi) + + ifeq ($(ios-version),) + x := $(error "couldn't find SDK for iOS version") endif - flags = -arch armv6 -isysroot \ - /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/ + + flags = -arch armv7 -isysroot \ + $(sdk-dir)/iPhoneOS$(ios-version).sdk/ openjdk-extra-cflags += $(flags) cflags += $(flags) asmflags += $(flags) @@ -328,9 +350,6 @@ ifeq ($(platform),darwin) endif ifeq ($(arch),powerpc) - ifneq (,$(filter i386 x86_64 arm,$(build-arch))) - converter-cflags += -DOPPOSITE_ENDIAN - endif openjdk-extra-cflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} cflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} asmflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} @@ -338,9 +357,6 @@ ifeq ($(platform),darwin) endif ifeq ($(arch),i386) - ifeq ($(build-arch),powerpc) - converter-cflags += -DOPPOSITE_ENDIAN - endif openjdk-extra-cflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} cflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} asmflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} @@ -348,9 +364,6 @@ ifeq ($(platform),darwin) endif ifeq ($(arch),x86_64) - ifeq ($(build-arch),powerpc) - converter-cflags += -DOPPOSITE_ENDIAN - endif openjdk-extra-cflags += -arch x86_64 cflags += -arch x86_64 asmflags += -arch x86_64 @@ -359,10 +372,8 @@ ifeq ($(platform),darwin) endif ifeq ($(platform),windows) - bootimage-cflags += -DTARGET_PLATFORM_WINDOWS - - inc = "$(root)/win32/include" - lib = "$(root)/win32/lib" + inc = "$(win32)/include" + lib = "$(win32)/lib" embed-prefix = c:/avian-embedded @@ -372,9 +383,8 @@ ifeq ($(platform),windows) so-suffix = .dll exe-suffix = .exe - lflags = -L$(lib) $(common-lflags) -lws2_32 -mwindows -mconsole - cflags = -I$(inc) $(common-cflags) -DWINVER=0x0500 -DTARGET_PLATFORM_WINDOWS - + lflags = -L$(lib) $(common-lflags) -lws2_32 -liphlpapi -mwindows -mconsole + cflags = -I$(inc) $(common-cflags) -DWINVER=0x0500 ifeq (,$(filter mingw32 cygwin,$(build-platform))) openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive @@ -411,13 +421,16 @@ ifeq ($(platform),windows) ar = x86_64-w64-mingw32-ar ranlib = x86_64-w64-mingw32-ranlib strip = x86_64-w64-mingw32-strip - inc = "$(root)/win64/include" - lib = "$(root)/win64/lib" + inc = "$(win64)/include" + lib = "$(win64)/lib" + else + shared += -Wl,--add-stdcall-alias endif endif ifeq ($(mode),debug) optimization-cflags = -O0 -g3 + converter-cflags += -O0 -g3 strip = : endif ifeq ($(mode),debug-fast) @@ -459,6 +472,7 @@ ifneq ($(platform),darwin) ifeq ($(arch),i386) # this is necessary to support __sync_bool_compare_and_swap: cflags += -march=i586 + lflags += -march=i586 endif endif @@ -469,7 +483,7 @@ build-ld := $(build-cc) ifdef msvc windows-java-home := $(shell cygpath -m "$(JAVA_HOME)") - zlib := $(shell cygpath -m "$(root)/win32/msvc") + zlib := $(shell cygpath -m "$(win32)/msvc") cxx = "$(msvc)/BIN/cl.exe" cc = $(cxx) ld = "$(msvc)/BIN/link.exe" @@ -478,7 +492,8 @@ ifdef msvc -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \ -Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I"$(build)" \ - -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" + -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" \ + -DTARGET_BYTES_PER_WORD=$(pointer-size) shared = -dll lflags = -nologo -LIBPATH:"$(zlib)/lib" -DEFAULTLIB:ws2_32 \ -DEFAULTLIB:zlib -MANIFEST -debug @@ -569,10 +584,7 @@ bootimage-generator-objects = \ $(call cpp-objects,$(bootimage-generator-sources),$(src),$(build)) bootimage-generator = $(build)/bootimage-generator -bootimage-bin = $(build)/bootimage.bin bootimage-object = $(build)/bootimage-bin.o - -codeimage-bin = $(build)/codeimage.bin codeimage-object = $(build)/codeimage-bin.o ifeq ($(bootimage),true) @@ -608,14 +620,23 @@ generator-objects = \ $(call generator-cpp-objects,$(generator-sources),$(src),$(build)) generator = $(build)/generator -converter-objects = \ - $(build)/binaryToObject-main.o \ - $(build)/binaryToObject-elf64.o \ - $(build)/binaryToObject-elf32.o \ - $(build)/binaryToObject-mach-o64.o \ - $(build)/binaryToObject-mach-o32.o \ - $(build)/binaryToObject-pe.o -converter = $(build)/binaryToObject +converter-depends = \ + $(src)/binaryToObject/tools.h \ + $(src)/binaryToObject/endianness.h + + +converter-sources = \ + $(src)/binaryToObject/tools.cpp \ + $(src)/binaryToObject/elf.cpp \ + $(src)/binaryToObject/mach-o.cpp \ + $(src)/binaryToObject/pe.cpp + +converter-tool-sources = \ + $(src)/binaryToObject/main.cpp + +converter-objects = $(call cpp-objects,$(converter-sources),$(src),$(build)) +converter-tool-objects = $(call cpp-objects,$(converter-tool-sources),$(src),$(build)) +converter = $(build)/binaryToObject/binaryToObject static-library = $(build)/lib$(name).a executable = $(build)/$(name)${exe-suffix} @@ -685,6 +706,34 @@ ifeq ($(tails),true) extra.Tails endif +ifeq ($(target-arch),i386) + cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_X86 +endif + +ifeq ($(target-arch),x86_64) + cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_X86_64 +endif + +ifeq ($(target-arch),powerpc) + cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_POWERPC +endif + +ifeq ($(target-arch),arm) + cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM +endif + +ifeq ($(target-platform),linux) + cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_LINUX +endif + +ifeq ($(target-platform),windows) + cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_WINDOWS +endif + +ifeq ($(target-platform),darwin) + cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_DARWIN +endif + class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) @@ -820,26 +869,12 @@ $(boot-object): $(boot-source) $(boot-javahome-object): $(src)/boot-javahome.cpp $(compile-object) -$(build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp - $(build-cxx) $(converter-cflags) -c $(^) -o $(@) +$(converter-objects) $(converter-tool-objects): $(build)/binaryToObject/%.o: $(src)/binaryToObject/%.cpp $(converter-depends) + @mkdir -p $(dir $(@)) + $(build-cxx) $(converter-cflags) -c $(<) -o $(@) -$(build)/binaryToObject-elf64.o: $(src)/binaryToObject/elf.cpp - $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=64 -c $(^) -o $(@) - -$(build)/binaryToObject-elf32.o: $(src)/binaryToObject/elf.cpp - $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=32 -c $(^) -o $(@) - -$(build)/binaryToObject-mach-o64.o: $(src)/binaryToObject/mach-o.cpp - $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=64 -c $(^) -o $(@) - -$(build)/binaryToObject-mach-o32.o: $(src)/binaryToObject/mach-o.cpp - $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=32 -c $(^) -o $(@) - -$(build)/binaryToObject-pe.o: $(src)/binaryToObject/pe.cpp - $(build-cxx) $(converter-cflags) -c $(^) -o $(@) - -$(converter): $(converter-objects) - $(build-cc) $(^) -o $(@) +$(converter): $(converter-objects) $(converter-tool-objects) + $(build-cc) $(^) -g -o $(@) $(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep) @echo "creating $(@)" @@ -880,20 +915,10 @@ $(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) \ $(ar) cru $(@) $(^) $(ranlib) $(@) -$(bootimage-bin): $(bootimage-generator) - $(<) $(classpath-build) $(@) $(codeimage-bin) - -$(bootimage-object): $(bootimage-bin) $(converter) - @echo "creating $(@)" - $(converter) $(<) $(@) _binary_bootimage_bin_start \ - _binary_bootimage_bin_end $(platform) $(arch) $(pointer-size) \ - writable - -$(codeimage-object): $(bootimage-bin) $(converter) - @echo "creating $(@)" - $(converter) $(codeimage-bin) $(@) _binary_codeimage_bin_start \ - _binary_codeimage_bin_end $(platform) $(arch) $(pointer-size) \ - executable +$(bootimage-object) $(codeimage-object): $(bootimage-generator) + $(<) -cp $(classpath-build) -bootimage $(bootimage-object) -codeimage $(codeimage-object) \ + -bootimage-symbols _binary_bootimage_bin_start:_binary_bootimage_bin_end \ + -codeimage-symbols _binary_codeimage_bin_start:_binary_codeimage_bin_end executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \ @@ -916,10 +941,13 @@ else endif $(strip) $(strip-all) $(@) -$(bootimage-generator): +$(bootimage-generator): $(bootimage-generator-objects) + echo arch=$(arch) platform=$(platform) $(MAKE) mode=$(mode) \ arch=$(build-arch) \ + target-arch=$(arch) \ platform=$(bootimage-platform) \ + target-platform=$(platform) \ openjdk=$(openjdk) \ openjdk-src=$(openjdk-src) \ bootimage-generator= \ @@ -930,7 +958,7 @@ $(bootimage-generator): $(build-bootimage-generator): \ $(vm-objects) $(classpath-object) $(classpath-objects) \ - $(heapwalk-objects) $(bootimage-generator-objects) + $(heapwalk-objects) $(bootimage-generator-objects) $(converter-objects) @echo "linking $(@)" ifeq ($(platform),windows) ifdef msvc @@ -983,6 +1011,18 @@ $(openjdk-objects): $(build)/openjdk/%-openjdk.o: $(openjdk-src)/%.c \ @echo "compiling $(@)" @mkdir -p $(dir $(@)) sed 's/^static jclass ia_class;//' < $(<) > $(build)/openjdk/$(notdir $(<)) +ifeq ($(ios),true) + sed \ + -e 's/^#ifndef __APPLE__/#if 1/' \ + -e 's/^#ifdef __APPLE__/#if 0/' \ + < "$(openjdk-src)/solaris/native/java/lang/ProcessEnvironment_md.c" \ + > $(build)/openjdk/ProcessEnvironment_md.c + sed \ + -e 's/^#ifndef __APPLE__/#if 1/' \ + -e 's/^#ifdef __APPLE__/#if 0/' \ + < "$(openjdk-src)/solaris/native/java/lang/UNIXProcess_md.c" \ + > $(build)/openjdk/UNIXProcess_md.c +endif $(cc) -fPIC $(openjdk-extra-cflags) $(openjdk-cflags) \ $(optimization-cflags) -w -c $(build)/openjdk/$(notdir $(<)) \ $(call output,$(@)) @@ -1013,6 +1053,42 @@ ifeq ($(platform),windows) < "$(openjdk-src)/windows/native/java/net/NetworkInterface.h" \ > $(build)/openjdk/NetworkInterface.h echo 'static int getAddrsFromAdapter(IP_ADAPTER_ADDRESSES *ptr, netaddr **netaddrPP);' >> $(build)/openjdk/NetworkInterface.h +endif +ifeq ($(platform),darwin) + mkdir -p $(build)/openjdk/netinet + for file in \ + /usr/include/netinet/ip.h \ + /usr/include/netinet/in_systm.h \ + /usr/include/netinet/ip_icmp.h \ + /usr/include/netinet/in_var.h \ + /usr/include/netinet/icmp6.h \ + /usr/include/netinet/ip_var.h; do \ + if [ ! -f "$(build)/openjdk/netinet/$$(basename $${file})" ]; then \ + ln "$${file}" "$(build)/openjdk/netinet/$$(basename $${file})"; \ + fi; \ + done + mkdir -p $(build)/openjdk/netinet6 + for file in \ + /usr/include/netinet6/in6_var.h; do \ + if [ ! -f "$(build)/openjdk/netinet6/$$(basename $${file})" ]; then \ + ln "$${file}" "$(build)/openjdk/netinet6/$$(basename $${file})"; \ + fi; \ + done + mkdir -p $(build)/openjdk/net + for file in \ + /usr/include/net/if_arp.h; do \ + if [ ! -f "$(build)/openjdk/net/$$(basename $${file})" ]; then \ + ln "$${file}" "$(build)/openjdk/net/$$(basename $${file})"; \ + fi; \ + done + mkdir -p $(build)/openjdk/sys + for file in \ + /usr/include/sys/kern_event.h \ + /usr/include/sys/sys_domain.h; do \ + if [ ! -f "$(build)/openjdk/sys/$$(basename $${file})" ]; then \ + ln "$${file}" "$(build)/openjdk/sys/$$(basename $${file})"; \ + fi; \ + done endif @touch $(@) @@ -1024,6 +1100,7 @@ $(openjdk-jar-dep): $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jsse.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jce.jar")" && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/charsets.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/ext/sunjce_provider.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/resources.jar")") @touch $(@) diff --git a/openjdk-src.mk b/openjdk-src.mk index 28166a9542..027b6a79b5 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -45,7 +45,6 @@ openjdk-sources = \ $(openjdk-src)/share/native/java/util/zip/CRC32.c \ $(openjdk-src)/share/native/java/util/zip/Deflater.c \ $(openjdk-src)/share/native/java/util/zip/Inflater.c \ - $(openjdk-src)/share/native/java/util/zip/ZipEntry.c \ $(openjdk-src)/share/native/java/util/zip/ZipFile.c \ $(openjdk-src)/share/native/java/util/zip/zip_util.c \ $(openjdk-src)/share/native/sun/management/VMManagementImpl.c \ @@ -76,6 +75,7 @@ openjdk-headers-classes = \ java.lang.Double \ java.lang.Float \ java.lang.Integer \ + java.lang.Long \ java.lang.Object \ java.lang.Package \ java.lang.Runtime \ @@ -124,7 +124,7 @@ openjdk-headers-classes = \ sun.net.spi.DefaultProxySelector \ sun.nio.ch.FileKey \ sun.nio.ch.FileChannelImpl \ - sun.nio.ch.FileDispatcher \ + sun.nio.ch.FileDispatcherImpl \ sun.nio.ch.DatagramChannelImpl \ sun.nio.ch.DatagramDispatcher \ sun.nio.ch.IOStatus \ @@ -173,6 +173,7 @@ endif ifeq ($(platform),windows) openjdk-sources += \ + $(openjdk-src)/windows/native/common/jni_util_md.c \ $(openjdk-src)/windows/native/java/io/canonicalize_md.c \ $(openjdk-src)/windows/native/java/io/Console_md.c \ $(openjdk-src)/windows/native/java/io/FileDescriptor_md.c \ @@ -193,7 +194,6 @@ ifeq ($(platform),windows) $(openjdk-src)/windows/native/java/net/Inet6AddressImpl.c \ $(openjdk-src)/windows/native/java/net/NetworkInterface.c \ $(openjdk-src)/windows/native/java/net/NetworkInterface_winXP.c \ - $(openjdk-src)/windows/native/java/net/NetworkInterface_win9x.c \ $(openjdk-src)/windows/native/java/net/SocketInputStream.c \ $(openjdk-src)/windows/native/java/net/SocketOutputStream.c \ $(openjdk-src)/windows/native/java/util/WindowsPreferences.c \ @@ -203,7 +203,7 @@ ifeq ($(platform),windows) $(openjdk-src)/windows/native/sun/nio/ch/DatagramChannelImpl.c \ $(openjdk-src)/windows/native/sun/nio/ch/DatagramDispatcher.c \ $(openjdk-src)/windows/native/sun/nio/ch/FileChannelImpl.c \ - $(openjdk-src)/windows/native/sun/nio/ch/FileDispatcher.c \ + $(openjdk-src)/windows/native/sun/nio/ch/FileDispatcherImpl.c \ $(openjdk-src)/windows/native/sun/nio/ch/FileKey.c \ $(openjdk-src)/windows/native/sun/nio/ch/IOUtil.c \ $(openjdk-src)/windows/native/sun/nio/ch/Net.c \ @@ -211,6 +211,7 @@ ifeq ($(platform),windows) $(openjdk-src)/windows/native/sun/nio/ch/SocketChannelImpl.c \ $(openjdk-src)/windows/native/sun/nio/ch/SocketDispatcher.c \ $(openjdk-src)/windows/native/sun/nio/ch/WindowsSelectorImpl.c \ + $(openjdk-src)/windows/native/sun/nio/fs/WindowsNativeDispatcher.c \ $(openjdk-src)/windows/native/sun/security/provider/WinCAPISeedGenerator.c openjdk-headers-classes += \ @@ -218,6 +219,7 @@ ifeq ($(platform),windows) java.lang.ProcessImpl \ sun.io.Win32ErrorMode \ sun.nio.ch.WindowsSelectorImpl \ + sun.nio.fs.WindowsNativeDispatcher \ openjdk-cflags += \ "-I$(openjdk-src)/windows/javavm/export" \ @@ -228,6 +230,9 @@ ifeq ($(platform),windows) "-I$(openjdk-src)/windows/native/sun/nio/ch" \ "-I$(openjdk-src)/windows/javavm/include" \ "-I$(root)/win32/include" \ + -DLOCALE_SNAME=0x0000005c \ + -DLOCALE_SISO3166CTRYNAME2=0x00000068 \ + -DLOCALE_SISO639LANGNAME2=0x00000067 \ -D_JNI_IMPLEMENTATION_ \ -D_JAVASOFT_WIN32_TYPEDEF_MD_H_ \ -Ds6_words=_s6_words \ @@ -235,6 +240,7 @@ ifeq ($(platform),windows) else openjdk-sources += \ $(openjdk-src)/solaris/native/common/jdk_util_md.c \ + $(openjdk-src)/solaris/native/common/jni_util_md.c \ $(openjdk-src)/solaris/native/java/io/canonicalize_md.c \ $(openjdk-src)/solaris/native/java/io/Console_md.c \ $(openjdk-src)/solaris/native/java/io/FileDescriptor_md.c \ @@ -265,30 +271,26 @@ else $(openjdk-src)/solaris/native/sun/nio/ch/DatagramChannelImpl.c \ $(openjdk-src)/solaris/native/sun/nio/ch/DatagramDispatcher.c \ $(openjdk-src)/solaris/native/sun/nio/ch/FileChannelImpl.c \ - $(openjdk-src)/solaris/native/sun/nio/ch/FileDispatcher.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/FileDispatcherImpl.c \ $(openjdk-src)/solaris/native/sun/nio/ch/FileKey.c \ $(openjdk-src)/solaris/native/sun/nio/ch/IOUtil.c \ $(openjdk-src)/solaris/native/sun/nio/ch/Net.c \ $(openjdk-src)/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c \ $(openjdk-src)/solaris/native/sun/nio/ch/SocketChannelImpl.c \ $(openjdk-src)/solaris/native/sun/nio/ch/SocketDispatcher.c \ - $(openjdk-src)/solaris/native/sun/nio/ch/EPollArrayWrapper.c \ $(openjdk-src)/solaris/native/sun/nio/ch/PollArrayWrapper.c \ $(openjdk-src)/solaris/native/sun/nio/ch/InheritedChannel.c \ $(openjdk-src)/solaris/native/sun/nio/ch/NativeThread.c \ - - ifeq ($(platform),linux) - openjdk-sources += \ - $(openjdk-src)/solaris/native/java/net/linux_close.c - endif + $(openjdk-src)/solaris/native/sun/nio/fs/UnixNativeDispatcher.c \ openjdk-headers-classes += \ java.net.PlainDatagramSocketImpl \ java.io.UnixFileSystem \ sun.nio.ch.InheritedChannel \ - sun.nio.ch.EPollArrayWrapper \ + sun.nio.fs.UnixNativeDispatcher \ - openjdk-cflags += "-I$(openjdk-src)/solaris/javavm/export" \ + openjdk-cflags += \ + "-I$(openjdk-src)/solaris/javavm/export" \ "-I$(openjdk-src)/solaris/native/common" \ "-I$(openjdk-src)/solaris/native/java/io" \ "-I$(openjdk-src)/solaris/native/java/lang" \ @@ -297,10 +299,45 @@ else "-I$(openjdk-src)/solaris/native/sun/management" \ "-I$(openjdk-src)/solaris/native/sun/nio/ch" \ "-I$(openjdk-src)/solaris/javavm/include" \ - "-I$(openjdk-src)/solaris/hpi/include" + "-I$(openjdk-src)/solaris/hpi/include" \ + "-I$(openjdk-src)/solaris/native/common/deps" + + ifeq ($(platform),linux) + openjdk-sources += \ + $(openjdk-src)/solaris/native/java/net/linux_close.c \ + $(openjdk-src)/solaris/native/common/deps/syscalls_fp.c \ + $(openjdk-src)/solaris/native/common/deps/gconf2/gconf_fp.c \ + $(openjdk-src)/solaris/native/common/deps/glib2/gio_fp.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/EPollArrayWrapper.c + + openjdk-headers-classes += \ + sun.nio.ch.EPollArrayWrapper + + openjdk-cflags += \ + "-I$(openjdk-src)/solaris/native/common/deps/glib2" \ + "-I$(openjdk-src)/solaris/native/common/deps/gconf2" \ + $(shell pkg-config --cflags glib-2.0) \ + $(shell pkg-config --cflags gconf-2.0) + endif + + ifeq ($(platform),darwin) + openjdk-sources += \ + $(openjdk-src)/solaris/native/java/net/bsd_close.c + + ifeq ($(ios),true) + openjdk-local-sources += \ + $(src)/openjdk/my_java_props_macosx.c + else + openjdk-sources += \ + $(openjdk-src)/solaris/native/java/lang/java_props_macosx.c + endif + + openjdk-cflags += \ + -DMACOSX + endif endif -openjdk-local-sources = \ +openjdk-local-sources += \ $(src)/openjdk/my_net_util.c \ $(src)/openjdk/my_management.c diff --git a/openjdk.pro b/openjdk.pro index dd9e07a910..953b5e205b 100644 --- a/openjdk.pro +++ b/openjdk.pro @@ -11,6 +11,7 @@ -keep class java.lang.System { private static void initializeSystemClass(); + public static void setProperties(java.util.Properties); } -keep class java.lang.ClassLoader { @@ -33,6 +34,11 @@ -keep class java.util.Properties { public java.lang.Object setProperty(java.lang.String, java.lang.String); + public java.lang.String getProperty(java.lang.String); + } + +-keep class java.util.Hashtable { + public java.lang.Object remove(java.lang.Object); } -keep class avian.OpenJDK { diff --git a/readme.txt b/readme.txt index a81b6b2693..6c08030677 100644 --- a/readme.txt +++ b/readme.txt @@ -54,7 +54,7 @@ Avian can currently target the following platforms: Linux (i386, x86_64, ARM, and 32-bit PowerPC) Windows (i386 and x86_64) Mac OS X (i386, x86_64 and 32-bit PowerPC) - + Apple iOS (i386 and ARM) Building -------- @@ -78,6 +78,7 @@ certain flags described below, all of which are optional. arch={i386,x86_64,powerpc,arm} \ process={compile,interpret} \ mode={debug,debug-fast,fast,small} \ + ios={true,false} \ bootimage={true,false} \ heapdump={true,false} \ tails={true,false} \ @@ -93,13 +94,20 @@ certain flags described below, all of which are optional. default: output of $(uname -m), normalized in some cases (e.g. i686 -> i386) + * process - choice between pure interpreter or JIT compiler + default: compile + * mode - which set of compilation flags to use to determine optimization level, debug symbols, and whether to enable assertions default: fast - * process - choice between pure interpreter or JIT compiler - default: compile + * ios - if true, cross-compile for iOS on OS X. Note that + non-jailbroken iOS devices do not allow JIT compilation, so only + process=interpret or bootimage=true builds will run on such + devices. See git://oss.readytalk.com/hello-ios.git for an example + of an Xcode project for iOS which uses Avian. + default: false * bootimage - if true, create a boot image containing the pre-parsed class library and ahead-of-time compiled methods. This option is @@ -220,11 +228,11 @@ features beyond that subset, you may want to tell Avian to use OpenJDK's class library instead. To do so, specify the directory where OpenJDK is installed, e.g.: - $ make openjdk=/usr/lib/jvm/java-6-openjdk + $ make openjdk=/usr/lib/jvm/java-7-openjdk This will build Avian as a conventional JVM (e.g. libjvm.so) which loads its boot class library and native libraries (e.g. libjava.so) -from /usr/lib/jvm/java-6-openjdk/jre at runtime. To run an +from /usr/lib/jvm/java-7-openjdk/jre at runtime. To run an application in this configuration, you'll need to make sure the VM is in your library search path. For example: @@ -235,8 +243,8 @@ in your library search path. For example: Alternatively, you can enable a stand-alone build using OpenJDK by specifying the location of the OpenJDK source code, e.g.: - $ make openjdk=$(pwd)/../jdk6/build/linux-amd64/j2sdk-image \ - openjdk-src=$(pwd)/../jdk6/jdk/src + $ make openjdk=$(pwd)/../jdk7/build/linux-amd64/j2sdk-image \ + openjdk-src=$(pwd)/../jdk7/jdk/src You must ensure that the path specified for openjdk-src does not have any spaces in it; make gets confused when dependency paths include @@ -260,7 +268,9 @@ an LZMA-enabled version: You can reduce the size futher for embedded builds by using ProGuard and the supplied openjdk.pro configuration file (see "Embedding with -ProGuard and a Boot Image" below). Also see app.mk in +ProGuard and a Boot Image" below). Note that you'll still need to use +vm.pro in that case -- openjdk.pro just adds additional constraints +specific to the OpenJDK port. Also see app.mk in git://oss.readytalk.com/avian-swt-examples.git for an example of using Avian, OpenJDK, ProGuard, and UPX in concert. @@ -269,49 +279,42 @@ it on various OSes: Debian-based Linux: # conventional build: - apt-get install openjdk-6-jdk - make openjdk=/usr/lib/jvm/java-6-openjdk test + apt-get install openjdk-7-jdk + make openjdk=/usr/lib/jvm/java-7-openjdk test # stand-alone build: - apt-get install openjdk-6-jdk - apt-get source openjdk-6-jdk - apt-get build-dep openjdk-6-jdk - (cd openjdk-6-6b18-1.8.3 && ./debian/rules patch) - make openjdk=/usr/lib/jvm/java-6-openjdk \ - openjdk-src=$(pwd)/openjdk-6-6b18-1.8.3/build/openjdk/jdk/src \ + apt-get install openjdk-7-jdk + apt-get source openjdk-7-jdk + apt-get build-dep openjdk-7-jdk + (cd openjdk-7-7~b147-2.0 && dpkg-buildpackage) + make openjdk=/usr/lib/jvm/java-7-openjdk \ + openjdk-src=$(pwd)/openjdk-7-7~b147-2.0/build/openjdk/jdk/src \ test Mac OS X: - # Prerequisite: install MacPorts (http://www.macports.org/) - sudo port selfupdate + # Prerequisite: build OpenJDK 7 according to + # https://wikis.oracle.com/display/OpenJDK/Mac+OS+X+Port # conventional build: - sudo port install openjdk6 - make openjdk=/opt/local/share/java/openjdk6 test + make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image test # stand-alone build: - sudo port fetch openjdk6 - sudo port patch openjdk6 - make openjdk=/opt/local/share/java/openjdk6 \ - openjdk-src=/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_java_openjdk6/work/jdk/src \ - test + make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image \ + openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test Windows (Cygwin): + # Prerequisite: build OpenJDK 7 according to + # http://weblogs.java.net/blog/simonis/archive/2011/10/28/yaojowbi-yet-another-openjdk-windows-build-instruction + # conventional build: - # Prerequisite: download and install the latest Windows OpenJDK - # build from http://www.openscg.com/se/openjdk/ - make openjdk=/cygdrive/c/OpenSCG/openjdk-6.21 test + make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image test # stand-alone build: - # Prerequisite: install OpenSCG build as above, plus the - # corresponding source bundle from - # http://download.java.net/openjdk/jdk6/promoted/, e.g.: - wget http://download.java.net/openjdk/jdk6/promoted/b21/openjdk-6-src-b21-20_jan_2011.tar.gz - mkdir openjdk - (cd openjdk && tar xzf ../openjdk-6-src-b21-20_jan_2011.tar.gz) - make openjdk=/cygdrive/c/OpenSCG/openjdk-6.21 \ - openjdk-src=$(pwd)/openjdk/jdk/src \ - test + make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image \ + openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test + +Currently, only OpenJDK 7 is supported. Later versions might work, +but have not yet been tested. Installing @@ -356,7 +359,7 @@ EOF Step 3: Make an object file out of the jar. - $ ../build/${platform}-${arch}/binaryToObject boot.jar boot-jar.o \ + $ ../build/${platform}-${arch}/binaryToObject/binaryToObject boot.jar boot-jar.o \ _binary_boot_jar_start _binary_boot_jar_end ${platform} ${arch} Step 4: Write a driver which starts the VM and runs the desired main @@ -364,7 +367,7 @@ method. Note the bootJar function, which will be called by the VM to get a handle to the embedded jar. We tell the VM about this jar by setting the boot classpath to "[bootJar]". - $ cat >main.cpp <embedded-jar-main.cpp <main.cpp <bootimage-main.cpp <allocate(size); +} + #endif//ALLOCATOR_H diff --git a/src/arm.S b/src/arm.S index 281e69f724..dceb8d3b75 100644 --- a/src/arm.S +++ b/src/arm.S @@ -20,6 +20,7 @@ #endif .globl GLOBAL(vmNativeCall) +.align 2 GLOBAL(vmNativeCall): /* arguments: @@ -57,6 +58,7 @@ LOCAL(loop): ldmfd sp!, {r4-r6, pc} // restore non-volatile regs and return .globl GLOBAL(vmJump) +.align 2 GLOBAL(vmJump): mov lr, r0 ldr r0, [sp] @@ -69,6 +71,7 @@ GLOBAL(vmJump): #define CHECKPOINT_STACK 24 .globl GLOBAL(vmRun) +.align 2 GLOBAL(vmRun): // r0: function // r1: arguments @@ -85,6 +88,7 @@ GLOBAL(vmRun): blx r12 .globl GLOBAL(vmRun_returnAddress) +.align 2 GLOBAL(vmRun_returnAddress): add sp, sp, #12 ldmfd sp!, {r4-r11, lr} diff --git a/src/arm.cpp b/src/arm.cpp index 07c8df1cea..14baab01e2 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -127,6 +127,8 @@ inline int ldmfd(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 1, 1, Rn, rl inline int stmfd(int Rn, int rlist) { return BLOCKXFER(AL, 1, 0, 0, 1, 0, Rn, rlist); } inline int swp(int Rd, int Rm, int Rn) { return SWAP(AL, 0, Rn, Rd, Rm); } inline int swpb(int Rd, int Rm, int Rn) { return SWAP(AL, 1, Rn, Rd, Rm); } +// breakpoint instruction, this really has its own instruction format +inline int bkpt(int16_t immed) { return 0xe1200070 | (((unsigned)immed & 0xffff) >> 4 << 8) | (immed & 0xf); } // COPROCESSOR INSTRUCTIONS inline int cdp(int coproc, int opcode_1, int CRd, int CRn, int CRm, int opcode_2) { return COOP(AL, opcode_1, CRn, CRd, coproc, opcode_2, CRm); } inline int mcr(int coproc, int opcode_1, int Rd, int CRn, int CRm, int opcode_2=0) { return COREG(AL, opcode_1, 0, CRn, Rd, coproc, opcode_2, CRm); } @@ -236,7 +238,6 @@ inline int fmstat() { return fmrx(15, FPSCR); } bool vfpSupported() { return true; // TODO } - } const uint64_t MASK_LO32 = 0xffffffff; @@ -341,7 +342,7 @@ class Context { public: Context(System* s, Allocator* a, Zone* zone): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), - firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(this, 0)), + firstBlock(new(zone) MyBlock(this, 0)), lastBlock(firstBlock), poolOffsetHead(0), poolOffsetTail(0), constantPool(0), constantPoolCount(0) { } @@ -459,8 +460,7 @@ class Offset: public Promise { Promise* offset(Context* c, bool forTrace = false) { - return new (c->zone->allocate(sizeof(Offset))) - Offset(c, c->lastBlock, c->code.length(), forTrace); + return new(c->zone) Offset(c, c->lastBlock, c->code.length(), forTrace); } bool @@ -527,8 +527,7 @@ class OffsetTask: public Task { void appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset) { - c->tasks = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask - (c->tasks, promise, instructionOffset); + c->tasks = new(c->zone) OffsetTask(c->tasks, promise, instructionOffset); } inline unsigned @@ -769,17 +768,14 @@ appendConstantPoolEntry(Context* c, Promise* constant, Promise* callOffset) if (constant->resolved()) { // make a copy, since the original might be allocated on the // stack, and we need our copy to live until assembly is complete - constant = new (c->zone->allocate(sizeof(ResolvedPromise))) - ResolvedPromise(constant->value()); + constant = new(c->zone) ResolvedPromise(constant->value()); } - c->constantPool = new (c->zone->allocate(sizeof(ConstantPoolEntry))) - ConstantPoolEntry(c, constant, c->constantPool, callOffset); + c->constantPool = new(c->zone) ConstantPoolEntry(c, constant, c->constantPool, callOffset); ++ c->constantPoolCount; - PoolOffset* o = new (c->zone->allocate(sizeof(PoolOffset))) PoolOffset - (c->lastBlock, c->constantPool, c->code.length() - c->lastBlock->offset); + PoolOffset* o = new(c->zone) PoolOffset(c->lastBlock, c->constantPool, c->code.length() - c->lastBlock->offset); if (DebugPool) { fprintf(stderr, "add pool offset %p %d to block %p\n", @@ -798,8 +794,7 @@ void appendPoolEvent(Context* c, MyBlock* b, unsigned offset, PoolOffset* head, PoolOffset* tail) { - PoolEvent* e = new (c->zone->allocate(sizeof(PoolEvent))) PoolEvent - (head, tail, offset); + PoolEvent* e = new(c->zone) PoolEvent(head, tail, offset); if (b->poolEventTail) { b->poolEventTail->next = e; @@ -1839,8 +1834,7 @@ branchCM(Context* con, TernaryOperation op, unsigned size, ShiftMaskPromise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) { - return new (c->zone->allocate(sizeof(ShiftMaskPromise))) - ShiftMaskPromise(base, shift, mask); + return new(c->zone) ShiftMaskPromise(base, shift, mask); } void @@ -1934,6 +1928,12 @@ return_(Context* c) emit(c, bx(LinkRegister)); } +void +trap(Context* c) +{ + emit(c, bkpt()); +} + void memoryBarrier(Context*) {} @@ -1947,7 +1947,7 @@ argumentFootprint(unsigned footprint) void nextFrame(ArchitectureContext* c, uint32_t* start, unsigned size UNUSED, - unsigned footprint, void* link, void*, + unsigned footprint, void* link, bool, unsigned targetParameterFootprint UNUSED, void** ip, void** stack) { assert(c, *ip >= start); @@ -2021,6 +2021,7 @@ populateTables(ArchitectureContext* c) zo[LoadBarrier] = memoryBarrier; zo[StoreStoreBarrier] = memoryBarrier; zo[StoreLoadBarrier] = memoryBarrier; + zo[Trap] = trap; uo[index(c, LongCall, C)] = CAST1(longCallC); @@ -2252,12 +2253,12 @@ class MyArchitecture: public Assembler::Architecture { } virtual void nextFrame(void* start, unsigned size, unsigned footprint, - void* link, void* stackLimit, + void* link, bool mostRecent, unsigned targetParameterFootprint, void** ip, void** stack) { ::nextFrame(&c, static_cast(start), size, footprint, link, - stackLimit, targetParameterFootprint, ip, stack); + mostRecent, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { @@ -2508,9 +2509,7 @@ class MyAssembler: public Assembler { { Register stack(StackRegister); Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); - Constant handlerConstant - (new (c.zone->allocate(sizeof(ResolvedPromise))) - ResolvedPromise(handler)); + Constant handlerConstant(new(c.zone) ResolvedPromise(handler)); branchRM(&c, JumpIfGreaterOrEqual, TargetBytesPerWord, &stack, &stackLimit, &handlerConstant); } @@ -2815,8 +2814,7 @@ class MyAssembler: public Assembler { MyBlock* b = c.lastBlock; b->size = c.code.length() - b->offset; if (startNew) { - c.lastBlock = new (c.zone->allocate(sizeof(MyBlock))) - MyBlock(&c, c.code.length()); + c.lastBlock = new (c.zone) MyBlock(&c, c.code.length()); } else { c.lastBlock = 0; } @@ -2887,8 +2885,7 @@ Assembler* makeAssembler(System* system, Allocator* allocator, Zone* zone, Assembler::Architecture* architecture) { - return new (zone->allocate(sizeof(MyAssembler))) - MyAssembler(system, allocator, zone, + return new(zone) MyAssembler(system, allocator, zone, static_cast(architecture)); } diff --git a/src/assembler.h b/src/assembler.h index 1566df6cd7..d2ba2caf5d 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -32,10 +32,11 @@ enum Operation { Return, LoadBarrier, StoreStoreBarrier, - StoreLoadBarrier + StoreLoadBarrier, + Trap }; -const unsigned OperationCount = StoreLoadBarrier + 1; +const unsigned OperationCount = Trap + 1; enum UnaryOperation { Call, @@ -367,7 +368,7 @@ class Assembler { virtual unsigned alignFrameSize(unsigned sizeInWords) = 0; virtual void nextFrame(void* start, unsigned size, unsigned footprint, - void* link, void* stackLimit, + void* link, bool mostRecent, unsigned targetParameterFootprint, void** ip, void** stack) = 0; virtual void* frameIp(void* stack) = 0; diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index bdfdce51c3..caf7c9c545 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2011, Avian Contributors +/* Copyright (c) 2009-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -8,12 +8,15 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#include "stdint.h" -#include "stdio.h" -#include "string.h" +#include +#include +#include +#include #include "endianness.h" +#include "tools.h" + #define EI_NIDENT 16 #define EI_MAG0 0 @@ -62,344 +65,316 @@ #define STV_DEFAULT 0 -#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#define ELF32_ST_INFO(bind, type) ELF64_ST_INFO((bind), (type)) - -#if (BITS_PER_WORD == 64) -# define FileHeader Elf64_Ehdr -# define SectionHeader Elf64_Shdr -# define Symbol Elf64_Sym -# define Class ELFCLASS64 -# define SYMBOL_INFO ELF64_ST_INFO -#elif (BITS_PER_WORD == 32) -# define FileHeader Elf32_Ehdr -# define SectionHeader Elf32_Shdr -# define Symbol Elf32_Sym -# define Class ELFCLASS32 -# define SYMBOL_INFO ELF32_ST_INFO -#else -# error -#endif +#define SYMBOL_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) #define OSABI ELFOSABI_SYSV namespace { -typedef uint16_t Elf64_Half; -typedef uint32_t Elf64_Word; -typedef uint64_t Elf64_Addr; -typedef uint64_t Elf64_Xword; -typedef uint16_t Elf64_Section; -typedef uint64_t Elf64_Off; +using namespace avian::tools; -struct Elf64_Ehdr { - unsigned char e_ident[EI_NIDENT]; - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; - Elf64_Off e_phoff; - Elf64_Off e_shoff; - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; +template +struct ElfTypes { + typedef uint16_t Half; + typedef uint32_t Word; + typedef AddrTy Addr; + typedef uint64_t Xword; + typedef uint16_t Section; + typedef AddrTy Off; + typedef AddrTy XFlags; + static const unsigned BytesPerWord = sizeof(AddrTy); }; -struct Elf64_Shdr { - Elf64_Word sh_name; - Elf64_Word sh_type; - Elf64_Xword sh_flags; - Elf64_Addr sh_addr; - Elf64_Off sh_offset; - Elf64_Xword sh_size; - Elf64_Word sh_link; - Elf64_Word sh_info; - Elf64_Xword sh_addralign; - Elf64_Xword sh_entsize; -}; +template +struct Symbol_Ty; -struct Elf64_Sym { - Elf64_Word st_name; +template<> +struct Symbol_Ty { + typedef ElfTypes Elf; + + Elf::Word st_name; unsigned char st_info; unsigned char st_other; - Elf64_Section st_shndx; - Elf64_Addr st_value; - Elf64_Xword st_size; + Elf::Section st_shndx; + Elf::Addr st_value; + Elf::Xword st_size; }; -typedef uint16_t Elf32_Half; -typedef uint32_t Elf32_Word; -typedef uint32_t Elf32_Addr; -typedef uint64_t Elf32_Xword; -typedef uint16_t Elf32_Section; -typedef uint32_t Elf32_Off; +template<> +struct Symbol_Ty { + typedef ElfTypes Elf; -struct Elf32_Ehdr { - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -}; - -struct Elf32_Shdr { - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -}; - -struct Elf32_Sym { - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; + Elf::Word st_name; + Elf::Addr st_value; + Elf::Word st_size; unsigned char st_info; unsigned char st_other; - Elf32_Section st_shndx; + Elf::Section st_shndx; }; -void -writeObject(const uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* sectionName, unsigned sectionFlags, - unsigned alignment, int machine, int encoding) -{ - const unsigned sectionCount = 5; - const unsigned symbolCount = 2; +using avian::endian::Endianness; - const unsigned sectionNameLength = strlen(sectionName) + 1; - const unsigned startNameLength = strlen(startName) + 1; - const unsigned endNameLength = strlen(endName) + 1; +#define V1 Endianness::v1 +#define V2 Endianness::v2 +#define V3 Endianness::v3 +#define V4 Endianness::v4 +#define VANY Endianness::vAny - const char* const sectionStringTableName = ".shstrtab"; - const char* const stringTableName = ".strtab"; - const char* const symbolTableName = ".symtab"; - const unsigned sectionStringTableNameLength - = strlen(sectionStringTableName) + 1; - const unsigned stringTableNameLength = strlen(stringTableName) + 1; - const unsigned symbolTableNameLength = strlen(symbolTableName) + 1; - - const unsigned nullStringOffset = 0; - - const unsigned sectionStringTableNameOffset = nullStringOffset + 1; - const unsigned stringTableNameOffset - = sectionStringTableNameOffset + sectionStringTableNameLength; - const unsigned symbolTableNameOffset - = stringTableNameOffset + stringTableNameLength; - const unsigned sectionNameOffset - = symbolTableNameOffset + symbolTableNameLength; - const unsigned sectionStringTableLength - = sectionNameOffset + sectionNameLength; - - const unsigned startNameOffset = nullStringOffset + 1; - const unsigned endNameOffset = startNameOffset + startNameLength; - const unsigned stringTableLength = endNameOffset + endNameLength; - - const unsigned bodySectionNumber = 1; - const unsigned sectionStringTableSectionNumber = 2; - const unsigned stringTableSectionNumber = 3; - - FileHeader fileHeader; - memset(&fileHeader, 0, sizeof(FileHeader)); - fileHeader.e_ident[EI_MAG0] = V1(ELFMAG0); - fileHeader.e_ident[EI_MAG1] = V1(ELFMAG1); - fileHeader.e_ident[EI_MAG2] = V1(ELFMAG2); - fileHeader.e_ident[EI_MAG3] = V1(ELFMAG3); - fileHeader.e_ident[EI_CLASS] = V1(Class); - fileHeader.e_ident[EI_DATA] = V1(encoding); - fileHeader.e_ident[EI_VERSION] = V1(EV_CURRENT); - fileHeader.e_ident[EI_OSABI] = V1(OSABI); - fileHeader.e_ident[EI_ABIVERSION] = V1(0); - fileHeader.e_type = V2(ET_REL); - fileHeader.e_machine = V2(machine); - fileHeader.e_version = V4(EV_CURRENT); - fileHeader.e_entry = VW(0); - fileHeader.e_phoff = VW(0); - fileHeader.e_shoff = VW(sizeof(FileHeader)); - fileHeader.e_flags = V4(machine == EM_ARM ? 0x04000000 : 0); - fileHeader.e_ehsize = V2(sizeof(FileHeader)); - fileHeader.e_phentsize = V2(0); - fileHeader.e_phnum = V2(0); - fileHeader.e_shentsize = V2(sizeof(SectionHeader)); - fileHeader.e_shnum = V2(sectionCount); - fileHeader.e_shstrndx = V2(sectionStringTableSectionNumber); - - SectionHeader nullSection; - memset(&nullSection, 0, sizeof(SectionHeader)); - - SectionHeader bodySection; - bodySection.sh_name = V4(sectionNameOffset); - bodySection.sh_type = V4(SHT_PROGBITS); - bodySection.sh_flags = VW(sectionFlags); - bodySection.sh_addr = VW(0); - unsigned bodySectionOffset - = sizeof(FileHeader) + (sizeof(SectionHeader) * sectionCount); - bodySection.sh_offset = VW(bodySectionOffset); - unsigned bodySectionSize = size; - bodySection.sh_size = VW(bodySectionSize); - bodySection.sh_link = V4(0); - bodySection.sh_info = V4(0); - bodySection.sh_addralign = VW(alignment); - bodySection.sh_entsize = VW(0); - - SectionHeader sectionStringTableSection; - sectionStringTableSection.sh_name = V4(sectionStringTableNameOffset); - sectionStringTableSection.sh_type = V4(SHT_STRTAB); - sectionStringTableSection.sh_flags = VW(0); - sectionStringTableSection.sh_addr = VW(0); - unsigned sectionStringTableSectionOffset - = bodySectionOffset + bodySectionSize; - sectionStringTableSection.sh_offset = VW(sectionStringTableSectionOffset); - unsigned sectionStringTableSectionSize = sectionStringTableLength; - sectionStringTableSection.sh_size = VW(sectionStringTableSectionSize); - sectionStringTableSection.sh_link = V4(0); - sectionStringTableSection.sh_info = V4(0); - sectionStringTableSection.sh_addralign = VW(1); - sectionStringTableSection.sh_entsize = VW(0); - - SectionHeader stringTableSection; - stringTableSection.sh_name = V4(stringTableNameOffset); - stringTableSection.sh_type = V4(SHT_STRTAB); - stringTableSection.sh_flags = VW(0); - stringTableSection.sh_addr = VW(0); - unsigned stringTableSectionOffset - = sectionStringTableSectionOffset + sectionStringTableSectionSize; - stringTableSection.sh_offset = VW(stringTableSectionOffset); - unsigned stringTableSectionSize = stringTableLength; - stringTableSection.sh_size = VW(stringTableSectionSize); - stringTableSection.sh_link = V4(0); - stringTableSection.sh_info = V4(0); - stringTableSection.sh_addralign = VW(1); - stringTableSection.sh_entsize = VW(0); - - SectionHeader symbolTableSection; - symbolTableSection.sh_name = V4(symbolTableNameOffset); - symbolTableSection.sh_type = V4(SHT_SYMTAB); - symbolTableSection.sh_flags = VW(0); - symbolTableSection.sh_addr = VW(0); - unsigned symbolTableSectionOffset - = stringTableSectionOffset + stringTableSectionSize; - symbolTableSection.sh_offset = VW(symbolTableSectionOffset); - unsigned symbolTableSectionSize = sizeof(Symbol) * symbolCount; - symbolTableSection.sh_size = VW(symbolTableSectionSize); - symbolTableSection.sh_link = V4(stringTableSectionNumber); - symbolTableSection.sh_info = V4(0); - symbolTableSection.sh_addralign = VW(BITS_PER_WORD / 8); - symbolTableSection.sh_entsize = VW(sizeof(Symbol)); - - Symbol startSymbol; - startSymbol.st_name = V4(startNameOffset); - startSymbol.st_value = VW(0); - startSymbol.st_size = VW(0); - startSymbol.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE)); - startSymbol.st_other = V1(STV_DEFAULT); - startSymbol.st_shndx = V2(bodySectionNumber); - - Symbol endSymbol; - endSymbol.st_name = V4(endNameOffset); - endSymbol.st_value = VW(size); - endSymbol.st_size = VW(0); - endSymbol.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE)); - endSymbol.st_other = V1(STV_DEFAULT); - endSymbol.st_shndx = V2(bodySectionNumber); - - fwrite(&fileHeader, 1, sizeof(fileHeader), out); - fwrite(&nullSection, 1, sizeof(nullSection), out); - fwrite(&bodySection, 1, sizeof(bodySection), out); - fwrite(§ionStringTableSection, 1, sizeof(sectionStringTableSection), - out); - fwrite(&stringTableSection, 1, sizeof(stringTableSection), out); - fwrite(&symbolTableSection, 1, sizeof(symbolTableSection), out); - - fwrite(data, 1, size, out); - - fputc(0, out); - fwrite(sectionStringTableName, 1, sectionStringTableNameLength, out); - fwrite(stringTableName, 1, stringTableNameLength, out); - fwrite(symbolTableName, 1, symbolTableNameLength, out); - fwrite(sectionName, 1, sectionNameLength, out); - - fputc(0, out); - fwrite(startName, 1, startNameLength, out); - fwrite(endName, 1, endNameLength, out); - - fwrite(&startSymbol, 1, sizeof(startSymbol), out); - fwrite(&endSymbol, 1, sizeof(endSymbol), out); +unsigned getElfPlatform(PlatformInfo::Architecture arch) { + switch(arch) { + case PlatformInfo::x86_64: + return EM_X86_64; + case PlatformInfo::x86: + return EM_386; + case PlatformInfo::Arm: + return EM_ARM; + case PlatformInfo::PowerPC: + return EM_PPC; + } + return ~0; } +const char* getSectionName(unsigned accessFlags, unsigned& sectionFlags) { + sectionFlags = SHF_ALLOC; + if (accessFlags & Platform::Writable) { + if (accessFlags & Platform::Executable) { + sectionFlags |= SHF_WRITE | SHF_EXECINSTR; + return ".rwx"; + } else { + sectionFlags |= SHF_WRITE; + return ".data"; + } + } else if (accessFlags & Platform::Executable) { + sectionFlags |= SHF_EXECINSTR; + return ".text"; + } else { + return ".rodata"; + } +} + +template +class ElfPlatform : public Platform { +public: + + typedef ElfTypes Elf; + static const unsigned Class = Elf::BytesPerWord / 4; + + struct FileHeader { + unsigned char e_ident[EI_NIDENT]; + typename Elf::Half e_type; + typename Elf::Half e_machine; + typename Elf::Word e_version; + typename Elf::Addr e_entry; + typename Elf::Off e_phoff; + typename Elf::Off e_shoff; + typename Elf::Word e_flags; + typename Elf::Half e_ehsize; + typename Elf::Half e_phentsize; + typename Elf::Half e_phnum; + typename Elf::Half e_shentsize; + typename Elf::Half e_shnum; + typename Elf::Half e_shstrndx; + }; + + struct SectionHeader { + typename Elf::Word sh_name; + typename Elf::Word sh_type; + typename Elf::XFlags sh_flags; + typename Elf::Addr sh_addr; + typename Elf::Off sh_offset; + typename Elf::Off sh_size; + typename Elf::Word sh_link; + typename Elf::Word sh_info; + typename Elf::Addr sh_addralign; + typename Elf::Off sh_entsize; + }; + + typedef Symbol_Ty Symbol; + + static const unsigned Encoding = TargetLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; + + const unsigned machine; + + ElfPlatform(PlatformInfo::Architecture arch): + Platform(PlatformInfo(PlatformInfo::Linux, arch)), + machine(getElfPlatform(arch)) {} + + class FileWriter { + public: + unsigned sectionCount; + unsigned sectionStringTableSectionNumber; + + AddrTy dataOffset; + + FileHeader header; + StringTable strings; + + FileWriter(unsigned machine): + sectionCount(0), + dataOffset(sizeof(FileHeader)) + { + memset(&header, 0, sizeof(FileHeader)); + header.e_ident[EI_MAG0] = V1(ELFMAG0); + header.e_ident[EI_MAG1] = V1(ELFMAG1); + header.e_ident[EI_MAG2] = V1(ELFMAG2); + header.e_ident[EI_MAG3] = V1(ELFMAG3); + header.e_ident[EI_CLASS] = V1(Class); + header.e_ident[EI_DATA] = V1(Encoding); + header.e_ident[EI_VERSION] = V1(EV_CURRENT); + header.e_ident[EI_OSABI] = V1(OSABI); + header.e_ident[EI_ABIVERSION] = V1(0); + header.e_type = V2(ET_REL); + header.e_machine = V2(machine); + header.e_version = V4(EV_CURRENT); + header.e_entry = VANY(static_cast(0)); + header.e_phoff = VANY(static_cast(0)); + header.e_shoff = VANY(static_cast(sizeof(FileHeader))); + header.e_flags = V4(machine == EM_ARM ? 0x04000000 : 0); + header.e_ehsize = V2(sizeof(FileHeader)); + header.e_phentsize = V2(0); + header.e_phnum = V2(0); + header.e_shentsize = V2(sizeof(SectionHeader)); + } + + void writeHeader(OutputStream* out) { + header.e_shnum = V2(sectionCount); + header.e_shstrndx = V2(sectionStringTableSectionNumber); + out->writeChunk(&header, sizeof(FileHeader)); + } + }; + + class SectionWriter { + public: + FileWriter& file; + String name; + SectionHeader header; + const size_t* dataSize; + const uint8_t* const* data; + + SectionWriter(FileWriter& file): + file(file), + name(""), + data(0), + dataSize(0) + { + memset(&header, 0, sizeof(SectionHeader)); + file.sectionCount++; + file.dataOffset += sizeof(SectionHeader); + size_t nameOffset = file.strings.add(name); + header.sh_name = V4(nameOffset); + } + + SectionWriter( + FileWriter& file, + const char* chname, + unsigned type, + AddrTy flags, + unsigned alignment, + AddrTy addr, + const uint8_t* const* data, + size_t* dataSize, + size_t entsize = 0, + unsigned link = 0): + + file(file), + name(chname), + data(data), + dataSize(dataSize) + { + if(strcmp(chname, ".shstrtab") == 0) { + file.sectionStringTableSectionNumber = file.sectionCount; + } + file.sectionCount++; + file.dataOffset += sizeof(SectionHeader); + size_t nameOffset = file.strings.add(name); + + header.sh_name = V4(nameOffset); + header.sh_type = V4(type); + header.sh_flags = VANY(flags); + header.sh_addr = VANY(addr); + // header.sh_offset = VANY(static_cast(bodySectionOffset)); + // header.sh_size = VANY(static_cast(*dataSize)); + header.sh_link = V4(link); + header.sh_info = V4(0); + header.sh_addralign = VANY(static_cast(alignment)); + header.sh_entsize = VANY(static_cast(entsize)); + } + + void writeHeader(OutputStream* out) { + if(dataSize) { + header.sh_offset = VANY(file.dataOffset); + header.sh_size = VANY(static_cast(*dataSize)); + file.dataOffset += *dataSize; + } + + out->writeChunk(&header, sizeof(SectionHeader)); + } + + void writeData(OutputStream* out) { + if(data) { + out->writeChunk(*data, *dataSize); + } + } + + + }; + + virtual bool writeObject(OutputStream* out, Slice symbols, Slice data, unsigned accessFlags, unsigned alignment) { + + unsigned sectionFlags; + const char* sectionName = getSectionName(accessFlags, sectionFlags); + + StringTable symbolStringTable; + Buffer symbolTable; + + FileWriter file(machine); + + const int bodySectionNumber = 1; + const int stringTableSectionNumber = 3; + + SectionWriter sections[] = { + SectionWriter(file), // null section + SectionWriter(file, sectionName, SHT_PROGBITS, sectionFlags, alignment, 0, &data.items, &data.count), // body section + SectionWriter(file, ".shstrtab", SHT_STRTAB, 0, 1, 0, &file.strings.data, &file.strings.length), + SectionWriter(file, ".strtab", SHT_STRTAB, 0, 1, 0, &symbolStringTable.data, &symbolStringTable.length), + SectionWriter(file, ".symtab", SHT_SYMTAB, 0, 8, 0, &symbolTable.data, &symbolTable.length, sizeof(Symbol), stringTableSectionNumber) + }; + + // for some reason, string tables require a null first element... + symbolStringTable.add(""); + + for(SymbolInfo* sym = symbols.begin(); sym != symbols.end(); sym++) { + size_t nameOffset = symbolStringTable.add(sym->name); + + Symbol symbolStruct; + symbolStruct.st_name = V4(nameOffset); + symbolStruct.st_value = VANY(static_cast(sym->addr)); + symbolStruct.st_size = VANY(static_cast(0)); + symbolStruct.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE)); + symbolStruct.st_other = V1(STV_DEFAULT); + symbolStruct.st_shndx = V2(bodySectionNumber); + symbolTable.write(&symbolStruct, sizeof(Symbol)); + } + + file.writeHeader(out); + + for(int i = 0; i < file.sectionCount; i++) { + sections[i].writeHeader(out); + } + + for(int i = 0; i < file.sectionCount; i++) { + sections[i].writeData(out); + } + + return true; + } +}; + +ElfPlatform elfx86Platform(PlatformInfo::x86); +ElfPlatform elfArmPlatform(PlatformInfo::Arm); +ElfPlatform elfPowerPCPlatform(PlatformInfo::PowerPC); +ElfPlatform elfx86_64Platform(PlatformInfo::x86_64); + + } // namespace - -#define MACRO_MAKE_NAME(a, b, c) a##b##c -#define MAKE_NAME(a, b, c) MACRO_MAKE_NAME(a, b, c) - -namespace binaryToObject { - -bool -MAKE_NAME(writeElf, BITS_PER_WORD, Object) - (uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* architecture, unsigned alignment, - bool writable, bool executable) -{ - int machine; - int encoding; - if (strcmp(architecture, "x86_64") == 0) { - machine = EM_X86_64; - encoding = ELFDATA2LSB; - } else if (strcmp(architecture, "i386") == 0) { - machine = EM_386; - encoding = ELFDATA2LSB; - } else if (strcmp(architecture, "arm") == 0) { - machine = EM_ARM; - encoding = ELFDATA2LSB; - } else if (strcmp(architecture, "powerpc") == 0) { - machine = EM_PPC; - encoding = ELFDATA2MSB; - } else { - fprintf(stderr, "unsupported architecture: %s\n", architecture); - return false; - } - - const char* sectionName; - unsigned sectionFlags = SHF_ALLOC; - if (writable) { - if (executable) { - sectionName = ".rwx"; - sectionFlags |= SHF_WRITE | SHF_EXECINSTR; - } else { - sectionName = ".data"; - sectionFlags |= SHF_WRITE; - } - } else if (executable) { - sectionName = ".text"; - sectionFlags |= SHF_EXECINSTR; - } else { - sectionName = ".rodata"; - } - - writeObject(data, size, out, startName, endName, sectionName, sectionFlags, - alignment, machine, encoding); - - return true; -} - -} // namespace binaryToObject diff --git a/src/binaryToObject/endianness.h b/src/binaryToObject/endianness.h index 46cfcd8b46..d1501a3926 100644 --- a/src/binaryToObject/endianness.h +++ b/src/binaryToObject/endianness.h @@ -1,38 +1,81 @@ -#ifndef ENDIANNESS_H -#define ENDIANNESS_H +/* Copyright (c) 2008-2012, Avian Contributors -#define V1(v) (v) + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. -#ifdef OPPOSITE_ENDIAN -# define V2(v) \ - ((((v) >> 8) & 0xFF) | \ - (((v) << 8))) -# define V4(v) \ - ((((v) >> 24) & 0x000000FF) | \ - (((v) >> 8) & 0x0000FF00) | \ - (((v) << 8) & 0x00FF0000) | \ - (((v) << 24))) -# define V8(v) \ - (((static_cast(v) >> 56) & UINT64_C(0x00000000000000FF)) | \ - ((static_cast(v) >> 40) & UINT64_C(0x000000000000FF00)) | \ - ((static_cast(v) >> 24) & UINT64_C(0x0000000000FF0000)) | \ - ((static_cast(v) >> 8) & UINT64_C(0x00000000FF000000)) | \ - ((static_cast(v) << 8) & UINT64_C(0x000000FF00000000)) | \ - ((static_cast(v) << 24) & UINT64_C(0x0000FF0000000000)) | \ - ((static_cast(v) << 40) & UINT64_C(0x00FF000000000000)) | \ - ((static_cast(v) << 56))) -#else -# define V2(v) (v) -# define V4(v) (v) -# define V8(v) (v) -#endif + There is NO WARRANTY for this software. See license.txt for + details. */ -#if (BITS_PER_WORD == 64) -# define VW(v) V8(v) -#elif (BITS_PER_WORD == 32) -# define VW(v) V4(v) -#else -# error -#endif +#ifndef AVIAN_ENDIANNESS_H +#define AVIAN_ENDIANNESS_H -#endif//ENDIANNESS_H +namespace avian { + +namespace endian { + +static union { + uint32_t i; + char c[4]; +} _DetectEndianness = {1}; + +const bool LittleEndian = _DetectEndianness.c[0] == 1; + +template +class Endianness { +public: + static inline uint8_t v1(uint8_t v) { + return v; + } + + static inline uint16_t v2(uint16_t v) { + if(LittleEndian == TargetLittleEndian) { + return v; + } else { + return ((v >> 8) & 0xFF) | (v << 8); + } + } + + static inline uint32_t v4(uint32_t v) { + if(LittleEndian == TargetLittleEndian) { + return v; + } else { + return + ((v >> 24) & 0x000000FF) | + ((v >> 8) & 0x0000FF00) | + ((v << 8) & 0x00FF0000) | + ((v << 24)); + } + } + + static inline uint32_t vAny(uint32_t v) { + return v4(v); + } + + static inline uint64_t v8(uint64_t v) { + if(LittleEndian == TargetLittleEndian) { + return v; + } else { + return + ((static_cast(v) >> 56) & (static_cast(0xff) << 0)) | + ((static_cast(v) >> 40) & (static_cast(0xff) << 8)) | + ((static_cast(v) >> 24) & (static_cast(0xff) << 16)) | + ((static_cast(v) >> 8) & (static_cast(0xff) << 24)) | + ((static_cast(v) << 8) & (static_cast(0xff) << 32)) | + ((static_cast(v) << 24) & (static_cast(0xff) << 40)) | + ((static_cast(v) << 40) & (static_cast(0xff) << 48)) | + ((static_cast(v) << 56)); + } + } + + static inline uint64_t vAny(uint64_t v) { + return v8(v); + } +}; + +} // namespace endian + +} // namespace avian + +#endif // AVIAN_ENDIANNESS_H diff --git a/src/binaryToObject/mach-o.cpp b/src/binaryToObject/mach-o.cpp index fefde4a467..50d7e56d78 100644 --- a/src/binaryToObject/mach-o.cpp +++ b/src/binaryToObject/mach-o.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -8,19 +8,19 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#include "stdint.h" -#include "stdio.h" -#include "string.h" +#include +#include +#include #include "endianness.h" +#include "tools.h" + #define MH_MAGIC_64 0xfeedfacf #define MH_MAGIC 0xfeedface #define MH_OBJECT 1 -#define LC_SEGMENT_64 0x19 -#define LC_SEGMENT 1 #define LC_SYMTAB 2 #define S_REGULAR 0 @@ -38,144 +38,23 @@ #define CPU_SUBTYPE_I386_ALL 3 #define CPU_SUBTYPE_X86_64_ALL CPU_SUBTYPE_I386_ALL #define CPU_SUBTYPE_POWERPC_ALL 0 -#define CPU_SUBTYPE_ARM_V6 6 - -#if (BITS_PER_WORD == 64) -# define Magic MH_MAGIC_64 -# define Segment LC_SEGMENT_64 -# define FileHeader mach_header_64 -# define SegmentCommand segment_command_64 -# define Section section_64 -# define NList struct nlist_64 -#elif (BITS_PER_WORD == 32) -# define Magic MH_MAGIC -# define Segment LC_SEGMENT -# define FileHeader mach_header -# define SegmentCommand segment_command -# define Section section -# define NList struct nlist -#else -# error -#endif +#define CPU_SUBTYPE_ARM_V7 9 namespace { +using namespace avian::tools; + typedef int cpu_type_t; typedef int cpu_subtype_t; typedef int vm_prot_t; -struct mach_header_64 { - uint32_t magic; - cpu_type_t cputype; - cpu_subtype_t cpusubtype; - uint32_t filetype; - uint32_t ncmds; - uint32_t sizeofcmds; - uint32_t flags; - uint32_t reserved; -}; +using avian::endian::Endianness; -struct segment_command_64 { - uint32_t cmd; - uint32_t cmdsize; - char segname[16]; - uint64_t vmaddr; - uint64_t vmsize; - uint64_t fileoff; - uint64_t filesize; - vm_prot_t maxprot; - vm_prot_t initprot; - uint32_t nsects; - uint32_t flags; -}; - -struct section_64 { - char sectname[16]; - char segname[16]; - uint64_t addr; - uint64_t size; - uint32_t offset; - uint32_t align; - uint32_t reloff; - uint32_t nreloc; - uint32_t flags; - uint32_t reserved1; - uint32_t reserved2; - uint32_t reserved3; -}; - -struct nlist_64 { - union { - uint32_t n_strx; - } n_un; - uint8_t n_type; - uint8_t n_sect; - uint16_t n_desc; - uint64_t n_value; -}; - -struct mach_header { - uint32_t magic; - cpu_type_t cputype; - cpu_subtype_t cpusubtype; - uint32_t filetype; - uint32_t ncmds; - uint32_t sizeofcmds; - uint32_t flags; -}; - -struct segment_command { - uint32_t cmd; - uint32_t cmdsize; - char segname[16]; - uint32_t vmaddr; - uint32_t vmsize; - uint32_t fileoff; - uint32_t filesize; - vm_prot_t maxprot; - vm_prot_t initprot; - uint32_t nsects; - uint32_t flags; -}; - -struct section { - char sectname[16]; - char segname[16]; - uint32_t addr; - uint32_t size; - uint32_t offset; - uint32_t align; - uint32_t reloff; - uint32_t nreloc; - uint32_t flags; - uint32_t reserved1; - uint32_t reserved2; -}; - -struct symtab_command { - uint32_t cmd; - uint32_t cmdsize; - uint32_t symoff; - uint32_t nsyms; - uint32_t stroff; - uint32_t strsize; -}; - -struct nlist { - union { - int32_t n_strx; - } n_un; - uint8_t n_type; - uint8_t n_sect; - int16_t n_desc; - uint32_t n_value; -}; - -inline unsigned -pad(unsigned n) -{ - return (n + ((BITS_PER_WORD / 8) - 1)) & ~((BITS_PER_WORD / 8) - 1); -} +#define V1 Endianness::v1 +#define V2 Endianness::v2 +#define V3 Endianness::v3 +#define V4 Endianness::v4 +#define VANY Endianness::vAny inline unsigned log(unsigned n) @@ -185,177 +64,233 @@ log(unsigned n) return r; } -void -writeObject(const uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* segmentName, const char* sectionName, - unsigned alignment, cpu_type_t cpuType, cpu_subtype_t cpuSubType) -{ - unsigned startNameLength = strlen(startName) + 1; - unsigned endNameLength = strlen(endName) + 1; +template +class MachOPlatform : public Platform { +public: - FileHeader header = { - V4(Magic), // magic - V4(cpuType), - V4(cpuSubType), - V4(MH_OBJECT), // filetype, - V4(2), // ncmds - V4(sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command)), // sizeofcmds - V4(0) // flags + struct FileHeader { + uint32_t magic; + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + + union { + uint32_t flags; + AddrTy flagsAndMaybeReserved; + }; }; - SegmentCommand segment = { - V4(Segment), // cmd - V4(sizeof(SegmentCommand) + sizeof(Section)), // cmdsize - "", // segname - VW(0), // vmaddr - VW(pad(size)), // vmsize - VW(sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command)), // fileoff - VW(pad(size)), // filesize - V4(7), // maxprot - V4(7), // initprot - V4(1), // nsects - V4(0) // flags + + struct SegmentCommand { + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + AddrTy vmaddr; + AddrTy vmsize; + AddrTy fileoff; + AddrTy filesize; + vm_prot_t maxprot; + vm_prot_t initprot; + uint32_t nsects; + uint32_t flags; }; - strncpy(segment.segname, segmentName, sizeof(segment.segname)); - - Section sect = { - "", // sectname - "", // segname - VW(0), // addr - VW(pad(size)), // size - V4(sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command)), // offset - V4(log(alignment)), // align - V4(0), // reloff - V4(0), // nreloc - V4(S_REGULAR), // flags - V4(0), // reserved1 - V4(0), // reserved2 + struct Section { + char sectname[16]; + char segname[16]; + AddrTy addr; + AddrTy size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + uint32_t reserved1; + AddrTy reserved2AndMaybe3; }; - strncpy(sect.segname, segmentName, sizeof(sect.segname)); - strncpy(sect.sectname, sectionName, sizeof(sect.sectname)); - - symtab_command symbolTable = { - V4(LC_SYMTAB), // cmd - V4(sizeof(symtab_command)), // cmdsize - V4(sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command) - + pad(size)), // symoff - V4(2), // nsyms - V4(sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command) - + pad(size) - + (sizeof(NList) * 2)), // stroff - V4(1 + startNameLength + endNameLength), // strsize + struct NList { + union { + uint32_t n_strx; + } n_un; + uint8_t n_type; + uint8_t n_sect; + uint16_t n_desc; + AddrTy n_value; }; - NList symbolList[] = { - { - V4(1), // n_un - V1(N_SECT | N_EXT), // n_type - V1(1), // n_sect - V2(0), // n_desc - VW(0) // n_value - }, - { - V4(1 + startNameLength), // n_un - V1(N_SECT | N_EXT), // n_type - V1(1), // n_sect - V2(0), // n_desc - VW(size) // n_value + struct SymtabCommand { + uint32_t cmd; + uint32_t cmdsize; + uint32_t symoff; + uint32_t nsyms; + uint32_t stroff; + uint32_t strsize; + }; + + static const unsigned BytesPerWord = sizeof(AddrTy); + static const unsigned Segment = BytesPerWord == 8 ? 0x19 : 1; + static const unsigned Magic = BytesPerWord == 8 ? 0xfeedfacf : 0xfeedface; + + static inline unsigned + pad(unsigned n) + { + return (n + (BytesPerWord - 1)) & ~(BytesPerWord - 1); + } + + virtual bool writeObject(OutputStream* out, Slice symbols, Slice data, unsigned accessFlags, unsigned alignment) { + cpu_type_t cpuType; + cpu_subtype_t cpuSubType; + switch(info.arch) { + case PlatformInfo::x86_64: + cpuType = CPU_TYPE_X86_64; + cpuSubType = CPU_SUBTYPE_X86_64_ALL; + break; + case PlatformInfo::x86: + cpuType = CPU_TYPE_I386; + cpuSubType = CPU_SUBTYPE_I386_ALL; + break; + case PlatformInfo::PowerPC: + cpuType = CPU_TYPE_POWERPC; + cpuSubType = CPU_SUBTYPE_POWERPC_ALL; + break; + case PlatformInfo::Arm: + cpuType = CPU_TYPE_ARM; + cpuSubType = CPU_SUBTYPE_ARM_V7; + break; + default: + // should never happen (see MachOPlatform declarations at bottom) + fprintf(stderr, "unsupported architecture: %d\n", info.arch); + return false; } - }; - fwrite(&header, 1, sizeof(header), out); - fwrite(&segment, 1, sizeof(segment), out); - fwrite(§, 1, sizeof(sect), out); - fwrite(&symbolTable, 1, sizeof(symbolTable), out); + const char* segmentName; + const char* sectionName; + if (accessFlags & Writable) { + if (accessFlags & Executable) { + segmentName = "__RWX"; + sectionName = "__rwx"; + } else { + segmentName = "__DATA"; + sectionName = "__data"; + } + } else { + segmentName = "__TEXT"; + sectionName = "__text"; + } - fwrite(data, 1, size, out); - for (unsigned i = 0; i < pad(size) - size; ++i) fputc(0, out); + FileHeader header = { + V4(Magic), // magic + V4(cpuType), + V4(cpuSubType), + V4(MH_OBJECT), // filetype, + V4(2), // ncmds + V4(sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(SymtabCommand)), // sizeofcmds + V4(0) // flags + }; - fwrite(&symbolList, 1, sizeof(symbolList), out); + AddrTy finalSize = pad(data.count); - fputc(0, out); - fwrite(startName, 1, startNameLength, out); - fwrite(endName, 1, endNameLength, out); -} + SegmentCommand segment = { + V4(Segment), // cmd + V4(sizeof(SegmentCommand) + sizeof(Section)), // cmdsize + "", // segname + VANY(static_cast(0)), // vmaddr + VANY(static_cast(finalSize)), // vmsize + VANY(static_cast(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(SymtabCommand))), // fileoff + VANY(static_cast(finalSize)), // filesize + V4(7), // maxprot + V4(7), // initprot + V4(1), // nsects + V4(0) // flags + }; + + strncpy(segment.segname, segmentName, sizeof(segment.segname)); + + Section sect = { + "", // sectname + "", // segname + VANY(static_cast(0)), // addr + VANY(static_cast(finalSize)), // size + V4(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(SymtabCommand)), // offset + V4(log(alignment)), // align + V4(0), // reloff + V4(0), // nreloc + V4(S_REGULAR), // flags + V4(0), // reserved1 + V4(0), // reserved2 + }; + + strncpy(sect.segname, segmentName, sizeof(sect.segname)); + strncpy(sect.sectname, sectionName, sizeof(sect.sectname)); + + StringTable strings; + strings.add(""); + Buffer symbolList; + + for(SymbolInfo* sym = symbols.begin(); sym != symbols.end(); sym++) { + unsigned offset = strings.length; + strings.write("_", 1); + strings.add(sym->name); + NList symbol = { + V4(offset), // n_un + V1(N_SECT | N_EXT), // n_type + V1(1), // n_sect + V2(0), // n_desc + VANY(static_cast(sym->addr)) // n_value + }; + symbolList.write(&symbol, sizeof(NList)); + } + + SymtabCommand symbolTable = { + V4(LC_SYMTAB), // cmd + V4(sizeof(SymtabCommand)), // cmdsize + V4(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(SymtabCommand) + + finalSize), // symoff + V4(symbols.count), // nsyms + V4(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(SymtabCommand) + + finalSize + + (sizeof(NList) * symbols.count)), // stroff + V4(strings.length), // strsize + }; + + out->writeChunk(&header, sizeof(header)); + out->writeChunk(&segment, sizeof(segment)); + out->writeChunk(§, sizeof(sect)); + out->writeChunk(&symbolTable, sizeof(symbolTable)); + + out->writeChunk(data.items, data.count); + out->writeRepeat(0, finalSize - data.count); + + out->writeChunk(symbolList.data, symbolList.length); + + out->writeChunk(strings.data, strings.length); + } + + MachOPlatform(PlatformInfo::Architecture arch): + Platform(PlatformInfo(PlatformInfo::Darwin, arch)) {} + +}; + +MachOPlatform darwinx86Platform(PlatformInfo::x86); +MachOPlatform darwinArmPlatform(PlatformInfo::Arm); +MachOPlatform darwinPowerPCPlatform(PlatformInfo::PowerPC); +MachOPlatform darwinx86_64Platform(PlatformInfo::x86_64); } // namespace - -#define MACRO_MAKE_NAME(a, b, c) a##b##c -#define MAKE_NAME(a, b, c) MACRO_MAKE_NAME(a, b, c) - -namespace binaryToObject { - -bool -MAKE_NAME(writeMachO, BITS_PER_WORD, Object) - (uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* architecture, unsigned alignment, - bool writable, bool executable) -{ - cpu_type_t cpuType; - cpu_subtype_t cpuSubType; - if (strcmp(architecture, "x86_64") == 0) { - cpuType = CPU_TYPE_X86_64; - cpuSubType = CPU_SUBTYPE_X86_64_ALL; - } else if (strcmp(architecture, "i386") == 0) { - cpuType = CPU_TYPE_I386; - cpuSubType = CPU_SUBTYPE_I386_ALL; - } else if (strcmp(architecture, "powerpc") == 0) { - cpuType = CPU_TYPE_POWERPC; - cpuSubType = CPU_SUBTYPE_POWERPC_ALL; - } else if (strcmp(architecture, "arm") == 0) { - cpuType = CPU_TYPE_ARM; - cpuSubType = CPU_SUBTYPE_ARM_V6; - } else { - fprintf(stderr, "unsupported architecture: %s\n", architecture); - return false; - } - - const char* segmentName; - const char* sectionName; - if (writable) { - if (executable) { - segmentName = "__RWX"; - sectionName = "__rwx"; - } else { - segmentName = "__DATA"; - sectionName = "__data"; - } - } else { - segmentName = "__TEXT"; - sectionName = "__text"; - } - - unsigned startNameLength = strlen(startName); - char myStartName[startNameLength + 2]; - myStartName[0] = '_'; - memcpy(myStartName + 1, startName, startNameLength + 1); - - unsigned endNameLength = strlen(endName); - char myEndName[endNameLength + 2]; - myEndName[0] = '_'; - memcpy(myEndName + 1, endName, endNameLength + 1); - - writeObject(data, size, out, myStartName, myEndName, segmentName, - sectionName, alignment, cpuType, cpuSubType); - - return true; -} - -} // namespace binaryToObject diff --git a/src/binaryToObject/main.cpp b/src/binaryToObject/main.cpp index ffc6f1e017..d8f801a5e3 100644 --- a/src/binaryToObject/main.cpp +++ b/src/binaryToObject/main.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -8,111 +8,59 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#include "stdint.h" -#include "stdio.h" -#include "stdlib.h" -#include "string.h" +#include +#include +#include +#include -#include "sys/stat.h" +#include #ifdef WIN32 #include #else -#include "sys/mman.h" +#include +#include #endif -#include "fcntl.h" -#include "unistd.h" +#include -namespace binaryToObject { +#include "tools.h" -bool -writeElf64Object(uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* architecture, unsigned alignment, bool writable, - bool executable); +extern "C" +void __cxa_pure_virtual() { + abort(); +} -bool -writeElf32Object(uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* architecture, unsigned alignment, bool writable, - bool executable); +void* operator new(size_t size) { + return malloc(size); +} -bool -writeMachO64Object(uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* architecture, unsigned alignment, bool writable, - bool executable); - -bool -writeMachO32Object(uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* architecture, unsigned alignment, bool writable, - bool executable); - -bool -writePEObject(uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* architecture, - unsigned alignment, bool writable, bool executable); - -} // namespace binaryToObject +void operator delete(void* mem) { abort(); } namespace { +using namespace avian::tools; + bool -writeObject(uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* platform, +writeObject(uint8_t* data, size_t size, OutputStream* out, const char* startName, + const char* endName, const char* os, const char* architecture, unsigned alignment, bool writable, bool executable) { - using namespace binaryToObject; + Platform* platform = Platform::getPlatform(PlatformInfo(PlatformInfo::osFromString(os), PlatformInfo::archFromString(architecture))); - bool found = false; - bool success = false; - if (strcmp("linux", platform) == 0) { - if (strcmp("x86_64", architecture) == 0) { - found = true; - success = writeElf64Object - (data, size, out, startName, endName, architecture, alignment, - writable, executable); - } else if (strcmp("i386", architecture) == 0 - or strcmp("arm", architecture) == 0 - or strcmp("powerpc", architecture) == 0) - { - found = true; - success = writeElf32Object - (data, size, out, startName, endName, architecture, alignment, - writable, executable); - } - } else if (strcmp("darwin", platform) == 0) { - if (strcmp("x86_64", architecture) == 0) { - found = true; - success = writeMachO64Object - (data, size, out, startName, endName, architecture, alignment, - writable, executable); - } else if (strcmp("i386", architecture) == 0 - or strcmp("powerpc", architecture) == 0 - or strcmp("arm", architecture) == 0) - { - found = true; - success = writeMachO32Object - (data, size, out, startName, endName, architecture, alignment, - writable, executable); - } - } else if (strcmp("windows", platform) == 0 - and ((strcmp("x86_64", architecture) == 0 - or strcmp("i386", architecture) == 0))) - { - found = true; - success = writePEObject - (data, size, out, startName, endName, architecture, alignment, writable, - executable); - } - - if (not found) { - fprintf(stderr, "unsupported platform: %s/%s\n", platform, architecture); + if(!platform) { + fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture); return false; } - return success; + SymbolInfo symbols[] = { + SymbolInfo(0, startName), + SymbolInfo(size, endName) + }; + + unsigned accessFlags = (writable ? Platform::Writable : 0) | (executable ? Platform::Executable : 0); + + return platform->writeObject(out, Slice(symbols, 2), Slice(data, size), accessFlags, alignment); + } void @@ -191,13 +139,11 @@ main(int argc, const char** argv) bool success = false; if (data) { - FILE* out = fopen(argv[2], "wb"); - if (out) { + FileOutputStream out(argv[2]); + if (out.isValid()) { success = writeObject - (data, size, out, argv[3], argv[4], argv[5], argv[6], alignment, + (data, size, &out, argv[3], argv[4], argv[5], argv[6], alignment, writable, executable); - - fclose(out); } else { fprintf(stderr, "unable to open %s\n", argv[2]); } diff --git a/src/binaryToObject/pe.cpp b/src/binaryToObject/pe.cpp index 45cc9556a9..32f13cc4fa 100644 --- a/src/binaryToObject/pe.cpp +++ b/src/binaryToObject/pe.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -8,16 +8,21 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#include "stdint.h" -#include "stdio.h" -#include "string.h" +#include +#include +#include +#include + +#include "tools.h" + +namespace { #define IMAGE_SIZEOF_SHORT_NAME 8 #define IMAGE_FILE_RELOCS_STRIPPED 1 #define IMAGE_FILE_LINE_NUMS_STRIPPED 4 #define IMAGE_FILE_MACHINE_AMD64 0x8664 -#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_32BIT_MACHINE 256 #define IMAGE_SCN_ALIGN_1BYTES 0x100000 @@ -29,8 +34,6 @@ #define IMAGE_SCN_MEM_WRITE 0x80000000 #define IMAGE_SCN_CNT_CODE 32 -namespace { - struct IMAGE_FILE_HEADER { uint16_t Machine; uint16_t NumberOfSections; @@ -77,155 +80,199 @@ pad(unsigned n) return (n + (4 - 1)) & ~(4 - 1); } -void -writeObject(const uint8_t* data, unsigned size, FILE* out, - const char* startName, const char* endName, - const char* sectionName, int machine, int machineMask, - int sectionMask) -{ - const unsigned sectionCount = 1; - const unsigned symbolCount = 2; +using namespace avian::tools; - const unsigned sectionNumber = 1; +template +class WindowsPlatform : public Platform { +public: - const unsigned startNameLength = strlen(startName) + 1; - const unsigned endNameLength = strlen(endName) + 1; - const unsigned startNameOffset = 4; - const unsigned endNameOffset = startNameOffset + startNameLength; + class FileWriter { + public: + unsigned sectionCount; + unsigned symbolCount; + unsigned dataStart; + unsigned dataOffset; - IMAGE_FILE_HEADER fileHeader = { - machine, // Machine - sectionCount, // NumberOfSections - 0, // TimeDateStamp - sizeof(IMAGE_FILE_HEADER) - + sizeof(IMAGE_SECTION_HEADER) - + pad(size), // PointerToSymbolTable - symbolCount, // NumberOfSymbols - 0, // SizeOfOptionalHeader - IMAGE_FILE_RELOCS_STRIPPED - | IMAGE_FILE_LINE_NUMS_STRIPPED - | machineMask // Characteristics + IMAGE_FILE_HEADER header; + + StringTable strings; + Buffer symbols; + + FileWriter(unsigned machine, unsigned machineMask, unsigned symbolCount): + sectionCount(0), + symbolCount(symbolCount), + dataStart(sizeof(IMAGE_FILE_HEADER)), + dataOffset(0) + { + header.Machine = machine; + // header.NumberOfSections = sectionCount; + header.TimeDateStamp = 0; + // header.PointerToSymbolTable = sizeof(IMAGE_FILE_HEADER) + // + sizeof(IMAGE_SECTION_HEADER) + // + pad(size); + // header.NumberOfSymbols = symbolCount; + header.SizeOfOptionalHeader = 0; + header.Characteristics = IMAGE_FILE_RELOCS_STRIPPED + | IMAGE_FILE_LINE_NUMS_STRIPPED + | machineMask; + } + + void writeHeader(OutputStream* out) { + header.NumberOfSections = sectionCount; + header.PointerToSymbolTable = dataStart + dataOffset; + dataOffset = pad(dataOffset + symbolCount * sizeof(IMAGE_SYMBOL)); + header.NumberOfSymbols = symbolCount; + out->writeChunk(&header, sizeof(IMAGE_FILE_HEADER)); + } + + void addSymbol(String name, unsigned addr, unsigned sectionNumber, unsigned type, unsigned storageClass) { + unsigned nameOffset = strings.add(name); + IMAGE_SYMBOL symbol = { + { 0 }, // Name + addr, // Value + sectionNumber, // SectionNumber + type, // Type + storageClass, // StorageClass + 0, // NumberOfAuxSymbols + }; + symbol.N.Name.Long = nameOffset+4; + symbols.write(&symbol, sizeof(IMAGE_SYMBOL)); + } + + void writeData(OutputStream* out) { + out->writeChunk(symbols.data, symbols.length); + uint32_t size = strings.length + 4; + out->writeChunk(&size, 4); + out->writeChunk(strings.data, strings.length); + } }; - IMAGE_SECTION_HEADER sectionHeader = { - "", // Name - 0, // PhysicalAddress - 0, // VirtualAddress - pad(size), // SizeOfRawData - sizeof(IMAGE_FILE_HEADER) - + sizeof(IMAGE_SECTION_HEADER), // PointerToRawData - 0, // PointerToRelocations - 0, // PointerToLinenumbers - 0, // NumberOfRelocations - 0, // NumberOfLinenumbers - sectionMask // Characteristics + class SectionWriter { + public: + FileWriter& file; + IMAGE_SECTION_HEADER header; + size_t dataSize; + size_t finalSize; + const uint8_t* data; + unsigned dataOffset; + + SectionWriter( + FileWriter& file, + const char* name, + unsigned sectionMask, + const uint8_t* data, + size_t dataSize): + + file(file), + data(data), + dataSize(dataSize), + finalSize(pad(dataSize)) + { + file.sectionCount++; + file.dataStart += sizeof(IMAGE_SECTION_HEADER); + strcpy(reinterpret_cast(header.Name), name); + header.Misc.VirtualSize = 0; + header.SizeOfRawData = finalSize; + // header.PointerToRawData = file.dataOffset; + dataOffset = file.dataOffset; + file.dataOffset += finalSize; + header.PointerToRelocations = 0; + header.PointerToLinenumbers = 0; + header.NumberOfRelocations = 0; + header.NumberOfLinenumbers = 0; + header.Characteristics = sectionMask; + } + + void writeHeader(OutputStream* out) { + header.PointerToRawData = dataOffset + file.dataStart; + out->writeChunk(&header, sizeof(IMAGE_SECTION_HEADER)); + } + + void writeData(OutputStream* out) { + out->writeChunk(data, dataSize); + out->writeRepeat(0, finalSize - dataSize); + } + + }; - strncpy(reinterpret_cast(sectionHeader.Name), sectionName, - sizeof(sectionHeader.Name)); + virtual bool writeObject(OutputStream* out, Slice symbols, Slice data, unsigned accessFlags, unsigned alignment) { - IMAGE_SYMBOL startSymbol = { - { 0 }, // Name - 0, // Value - sectionNumber, // SectionNumber - 0, // Type - 2, // StorageClass - 0, // NumberOfAuxSymbols - }; - startSymbol.N.Name.Long = startNameOffset; + int machine; + int machineMask; - IMAGE_SYMBOL endSymbol = { - { 0 }, // Name - size, // Value - sectionNumber, // SectionNumber - 0, // Type - 2, // StorageClass - 0, // NumberOfAuxSymbols - }; - endSymbol.N.Name.Long = endNameOffset; + if (BytesPerWord == 8) { + machine = IMAGE_FILE_MACHINE_AMD64; + machineMask = 0; + } else { // if (BytesPerWord == 8) + machine = IMAGE_FILE_MACHINE_I386; + machineMask = IMAGE_FILE_32BIT_MACHINE; + } - fwrite(&fileHeader, 1, sizeof(fileHeader), out); - fwrite(§ionHeader, 1, sizeof(sectionHeader), out); + int sectionMask; + switch (alignment) { + case 0: + case 1: + sectionMask = IMAGE_SCN_ALIGN_1BYTES; + break; + case 2: + sectionMask = IMAGE_SCN_ALIGN_2BYTES; + break; + case 4: + sectionMask = IMAGE_SCN_ALIGN_4BYTES; + break; + case 8: + sectionMask = IMAGE_SCN_ALIGN_8BYTES; + break; + default: + fprintf(stderr, "unsupported alignment: %d\n", alignment); + return false; + } - fwrite(data, 1, size, out); - for (unsigned i = 0; i < pad(size) - size; ++i) fputc(0, out); + sectionMask |= IMAGE_SCN_MEM_READ; - fwrite(&startSymbol, 1, sizeof(startSymbol), out); - fwrite(&endSymbol, 1, sizeof(endSymbol), out); + const char* sectionName; + if (accessFlags & Platform::Writable) { + if (accessFlags & Platform::Executable) { + sectionName = ".rwx"; + sectionMask |= IMAGE_SCN_MEM_WRITE + | IMAGE_SCN_MEM_EXECUTE + | IMAGE_SCN_CNT_CODE; + } else { + sectionName = ".data"; + sectionMask |= IMAGE_SCN_MEM_WRITE; + } + } else { + sectionName = ".text"; + sectionMask |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; + } - uint32_t symbolTableSize = endNameOffset + endNameLength; - fwrite(&symbolTableSize, 1, 4, out); + FileWriter file(machine, machineMask, symbols.count); - fwrite(startName, 1, startNameLength, out); - fwrite(endName, 1, endNameLength, out); -} + SectionWriter section(file, sectionName, sectionMask, data.items, data.count); + + file.writeHeader(out); + + for(SymbolInfo* sym = symbols.begin(); sym != symbols.end(); sym++) { + file.addSymbol(sym->name, sym->addr, 1, 0, 2); + } + + section.writeHeader(out); + + section.writeData(out); + + file.writeData(out); + + return true; + + } + + WindowsPlatform(): + Platform(PlatformInfo(PlatformInfo::Windows, BytesPerWord == 4 ? PlatformInfo::x86 : PlatformInfo::x86_64)) {} +}; + +WindowsPlatform<4> windows32Platform; +WindowsPlatform<8> windows64Platform; } // namespace - -namespace binaryToObject { - -bool -writePEObject -(uint8_t* data, unsigned size, FILE* out, const char* startName, - const char* endName, const char* architecture, unsigned alignment, - bool writable, bool executable) -{ - int machine; - int machineMask; - if (strcmp(architecture, "x86_64") == 0) { - machine = IMAGE_FILE_MACHINE_AMD64; - machineMask = 0; - } else if (strcmp(architecture, "i386") == 0) { - machine = IMAGE_FILE_MACHINE_I386; - machineMask = IMAGE_FILE_32BIT_MACHINE; - } else { - fprintf(stderr, "unsupported architecture: %s\n", architecture); - return false; - } - - int sectionMask; - switch (alignment) { - case 0: - case 1: - sectionMask = IMAGE_SCN_ALIGN_1BYTES; - break; - case 2: - sectionMask = IMAGE_SCN_ALIGN_2BYTES; - break; - case 4: - sectionMask = IMAGE_SCN_ALIGN_4BYTES; - break; - case 8: - sectionMask = IMAGE_SCN_ALIGN_8BYTES; - break; - default: - fprintf(stderr, "unsupported alignment: %d\n", alignment); - return false; - } - - sectionMask |= IMAGE_SCN_MEM_READ; - - const char* sectionName; - if (writable) { - if (executable) { - sectionName = ".rwx"; - sectionMask |= IMAGE_SCN_MEM_WRITE - | IMAGE_SCN_MEM_EXECUTE - | IMAGE_SCN_CNT_CODE; - } else { - sectionName = ".data"; - sectionMask |= IMAGE_SCN_MEM_WRITE; - } - } else { - sectionName = ".text"; - sectionMask |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; - } - - writeObject(data, size, out, startName, endName, sectionName, machine, - machineMask, sectionMask); - - return true; -} - -} // namespace binaryToObject diff --git a/src/binaryToObject/tools.cpp b/src/binaryToObject/tools.cpp new file mode 100644 index 0000000000..3181474b94 --- /dev/null +++ b/src/binaryToObject/tools.cpp @@ -0,0 +1,125 @@ +/* Copyright (c) 2009-2012, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#include +#include +#include +#include + +#include "tools.h" + +namespace avian { + +namespace tools { + +String::String(const char* text): + text(text), + length(strlen(text)) {} + +Buffer::Buffer(): + capacity(100), + length(0), + data((uint8_t*)malloc(capacity)) {} + +Buffer::~Buffer() { + free(data); +} + +void Buffer::ensure(size_t more) { + if(length + more > capacity) { + capacity = capacity * 2 + more; + data = (uint8_t*)realloc(data, capacity); + } +} + +void Buffer::write(const void* d, size_t size) { + ensure(size); + memcpy(data + length, d, size); + length += size; +} + +unsigned StringTable::add(String str) { + unsigned offset = Buffer::length; + Buffer::write(str.text, str.length + 1); + return offset; +} + +void OutputStream::write(uint8_t byte) { + writeChunk(&byte, 1); +} + +void OutputStream::writeRepeat(uint8_t byte, size_t size) { + for(size_t i = 0; i < size; i++) { + write(byte); + } +} + +FileOutputStream::FileOutputStream(const char* name): + file(fopen(name, "wb")) {} + +FileOutputStream::~FileOutputStream() { + if(file) { + fclose(file); + } +} + +bool FileOutputStream::isValid() { + return file; +} + +void FileOutputStream::writeChunk(const void* data, size_t size) { + fwrite(data, size, 1, file); +} + +void FileOutputStream::write(uint8_t byte) { + fputc(byte, file); +} + + +Platform* Platform::first = 0; + +PlatformInfo::OperatingSystem PlatformInfo::osFromString(const char* os) { + if(strcmp(os, "linux") == 0) { + return Linux; + } else if(strcmp(os, "windows") == 0) { + return Windows; + } else if(strcmp(os, "darwin") == 0) { + return Darwin; + } else { + return UnknownOS; + } +} + +PlatformInfo::Architecture PlatformInfo::archFromString(const char* arch) { + if(strcmp(arch, "i386") == 0) { + return x86; + } else if(strcmp(arch, "x86_64") == 0) { + return x86_64; + } else if(strcmp(arch, "powerpc") == 0) { + return PowerPC; + } else if(strcmp(arch, "arm") == 0) { + return Arm; + } else { + return UnknownArch; + } +} + +Platform* Platform::getPlatform(PlatformInfo info) { + for(Platform* p = first; p; p = p->next) { + if(p->info == info) { + return p; + } + } + return 0; +} + +} // namespace tools + +} // namespace avian \ No newline at end of file diff --git a/src/binaryToObject/tools.h b/src/binaryToObject/tools.h new file mode 100644 index 0000000000..c95d22ae89 --- /dev/null +++ b/src/binaryToObject/tools.h @@ -0,0 +1,196 @@ +/* Copyright (c) 2009-2012, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#ifndef AVIAN_TOOLS_H_ +#define AVIAN_TOOLS_H_ + +#include +#include "environment.h" + +namespace avian { + +namespace tools { + +class OutputStream { +public: + virtual void writeChunk(const void* data, size_t size) = 0; + virtual void write(uint8_t byte); + virtual void writeRepeat(uint8_t byte, size_t size); +}; + +class FileOutputStream : public OutputStream { +private: + FILE* file; +public: + FileOutputStream(const char* name); + ~FileOutputStream(); + + bool isValid(); + + virtual void writeChunk(const void* data, size_t size); + virtual void write(uint8_t byte); +}; + +class String { +public: + const char* text; + size_t length; + + String(const char* text); + + inline String(const char* text, size_t length): + text(text), + length(length) {} +}; + +class SymbolInfo { +public: + unsigned addr; + String name; + + inline SymbolInfo(uint64_t addr, const String& name): + addr(addr), + name(name) {} + + inline SymbolInfo(): + name("") {} +}; + +class Buffer { +public: + size_t capacity; + size_t length; + uint8_t* data; + + Buffer(); + ~Buffer(); + + void ensure(size_t more); + void write(const void* d, size_t size); +}; + +class StringTable : public Buffer { +public: + unsigned add(String str); +}; + +template +class Slice { +public: + T* items; + size_t count; + + inline Slice(T* items, size_t count): + items(items), + count(count) {} + + inline Slice(const Slice& copy): + items(copy.items), + count(copy.count) {} + + inline T* begin() { + return items; + } + + inline T* end() { + return items + count; + } +}; + +template +class DynamicArray : public Slice { +public: + size_t capacity; + + DynamicArray(): + Slice((T*)malloc(10 * sizeof(T)), 0), + capacity(10) {} + ~DynamicArray() { + free(Slice::items); + } + + void ensure(size_t more) { + if(Slice::count + more > capacity) { + capacity = capacity * 2 + more; + Slice::items = (T*)realloc(Slice::items, capacity * sizeof(T)); + } +} + + void add(const T& item) { + ensure(1); + Slice::items[Slice::count++] = item; + } +}; + +class PlatformInfo { +public: + enum OperatingSystem { + Linux = AVIAN_PLATFORM_LINUX, + Windows = AVIAN_PLATFORM_WINDOWS, + Darwin = AVIAN_PLATFORM_DARWIN, + UnknownOS = AVIAN_PLATFORM_UNKNOWN + }; + + enum Architecture { + x86 = AVIAN_ARCH_X86, + x86_64 = AVIAN_ARCH_X86_64, + PowerPC = AVIAN_ARCH_POWERPC, + Arm = AVIAN_ARCH_ARM, + UnknownArch = AVIAN_ARCH_UNKNOWN + }; + + const OperatingSystem os; + const Architecture arch; + + static OperatingSystem osFromString(const char* os); + static Architecture archFromString(const char* arch); + + inline PlatformInfo(OperatingSystem os, Architecture arch): + os(os), + arch(arch) {} + + inline bool operator == (const PlatformInfo& other) { + return os == other.os && arch == other.arch; + } + + inline bool isLittleEndian() { + return arch != PowerPC; + } +}; + +class Platform { +private: + Platform* next; + static Platform* first; +public: + PlatformInfo info; + + inline Platform(PlatformInfo info): + next(first), + info(info) + { + first = this; + } + + enum AccessFlags { + Writable = 1 << 0, + Executable = 1 << 1 + }; + + virtual bool writeObject(OutputStream* out, Slice symbols, Slice data, unsigned accessFlags, unsigned alignment) = 0; + + static Platform* getPlatform(PlatformInfo info); +}; + +} // namespace tools + +} // namespace avian + +#endif \ No newline at end of file diff --git a/src/boot-javahome.cpp b/src/boot-javahome.cpp index 4ef2efd896..bb965cdc3a 100644 --- a/src/boot-javahome.cpp +++ b/src/boot-javahome.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Avian Contributors +/* Copyright (c) 2010-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/boot.cpp b/src/boot.cpp index c78667f5af..4f3d8edbb0 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 28f45dd382..17a27f198d 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -16,16 +16,18 @@ #include "stream.h" #include "assembler.h" #include "target.h" +#include "binaryToObject/tools.h" // since we aren't linking against libstdc++, we must implement this // ourselves: extern "C" void __cxa_pure_virtual(void) { abort(); } using namespace vm; +using namespace avian::tools; namespace { -const unsigned HeapCapacity = 256 * 1024 * 1024; +const unsigned HeapCapacity = 512 * 1024 * 1024; const unsigned TargetFixieSizeInBytes = 8 + (TargetBytesPerWord * 2); const unsigned TargetFixieSizeInWords = ceiling @@ -435,6 +437,10 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, memberFields[memberIndex] = *f; + while (targetMemberOffset % f->targetSize) { + ++ targetMemberOffset; + } + targetMemberOffset += f->targetSize; ++ memberIndex; @@ -498,10 +504,8 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, } if (fieldFlags(t, field) & ACC_STATIC) { - unsigned excess = (targetStaticOffset % targetSize) - % TargetBytesPerWord; - if (excess) { - targetStaticOffset += TargetBytesPerWord - excess; + while (targetStaticOffset % targetSize) { + ++ targetStaticOffset; } buildStaticOffset = fieldOffset(t, field); @@ -680,10 +684,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, } for (; methods; methods = pairSecond(t, methods)) { - intptr_t address = codeCompiled(t, methodCode(t, pairFirst(t, methods))); - reinterpret_cast(address)[-1] - = targetVW(reinterpret_cast(address)[-1]); - codeCompiled(t, methodCode(t, pairFirst(t, methods))) -= reinterpret_cast(code); } @@ -1281,12 +1281,48 @@ targetThunk(BootImage::Thunk t) } void -writeBootImage2(Thread* t, FILE* bootimageOutput, FILE* codeOutput, +writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutput, BootImage* image, uint8_t* code, const char* className, - const char* methodName, const char* methodSpec) + const char* methodName, const char* methodSpec, + const char* bootimageStart, const char* bootimageEnd, + const char* codeimageStart, const char* codeimageEnd) { + setRoot(t, Machine::OutOfMemoryError, + make(t, type(t, Machine::OutOfMemoryErrorType))); + Zone zone(t->m->system, t->m->heap, 64 * 1024); + class MyCompilationHandler : public Processor::CompilationHandler { + public: + + String heapDup(const char* name) { + String ret(name); + char* n = (char*)heap->allocate(ret.length + 1); + memcpy(n, ret.text, ret.length + 1); + ret.text = n; + return ret; + } + + virtual void compiled(const void* code, unsigned size UNUSED, unsigned frameSize UNUSED, const char* name) { + uint64_t offset = reinterpret_cast(code) - codeOffset; + symbols.add(SymbolInfo(offset, heapDup(name))); + // printf("%ld %ld %s.%s%s\n", offset, offset + size, class_, name, spec); + } + + virtual void dispose() {} + + DynamicArray symbols; + uint64_t codeOffset; + Heap* heap; + + MyCompilationHandler(uint64_t codeOffset, Heap* heap): + codeOffset(codeOffset), + heap(heap) {} + + } compilationHandler(reinterpret_cast(code), t->m->heap); + + t->m->processor->addCompilationHandler(&compilationHandler); + object classPoolMap; object typeMaps; object constants; @@ -1573,6 +1609,8 @@ writeBootImage2(Thread* t, FILE* bootimageOutput, FILE* codeOutput, image->bootClassCount, image->stringCount, image->callCount, image->heapSize, image->codeSize); + Buffer bootimageData; + if (true) { { BootImage targetImage; @@ -1589,19 +1627,15 @@ writeBootImage2(Thread* t, FILE* bootimageOutput, FILE* codeOutput, #include "bootimage-fields.cpp" #undef THUNK_FIELD - fwrite(&targetImage, sizeof(BootImage), 1, bootimageOutput); + bootimageData.write(&targetImage, sizeof(BootImage)); } - fwrite(bootClassTable, image->bootClassCount * sizeof(unsigned), 1, - bootimageOutput); - fwrite(appClassTable, image->appClassCount * sizeof(unsigned), 1, - bootimageOutput); - fwrite(stringTable, image->stringCount * sizeof(unsigned), 1, - bootimageOutput); - fwrite(callTable, image->callCount * sizeof(unsigned) * 2, 1, - bootimageOutput); + bootimageData.write(bootClassTable, image->bootClassCount * sizeof(unsigned)); + bootimageData.write(appClassTable, image->appClassCount * sizeof(unsigned)); + bootimageData.write(stringTable, image->stringCount * sizeof(unsigned)); + bootimageData.write(callTable, image->callCount * sizeof(unsigned) * 2); - unsigned offset = sizeof(BootImage) + unsigned offset = sizeof(BootImage) + (image->bootClassCount * sizeof(unsigned)) + (image->appClassCount * sizeof(unsigned)) + (image->stringCount * sizeof(unsigned)) @@ -1609,52 +1643,313 @@ writeBootImage2(Thread* t, FILE* bootimageOutput, FILE* codeOutput, while (offset % TargetBytesPerWord) { uint8_t c = 0; - fwrite(&c, 1, 1, bootimageOutput); + bootimageData.write(&c, 1); ++ offset; } - fwrite(heapMap, pad(heapMapSize(image->heapSize), TargetBytesPerWord), 1, - bootimageOutput); + bootimageData.write(heapMap, pad(heapMapSize(image->heapSize), TargetBytesPerWord)); - fwrite(heap, pad(image->heapSize, TargetBytesPerWord), 1, bootimageOutput); + bootimageData.write(heap, pad(image->heapSize, TargetBytesPerWord)); - fwrite(code, pad(image->codeSize, TargetBytesPerWord), 1, codeOutput); + // fwrite(code, pad(image->codeSize, TargetBytesPerWord), 1, codeOutput); + + Platform* platform = Platform::getPlatform(PlatformInfo((PlatformInfo::OperatingSystem)AVIAN_TARGET_PLATFORM, (PlatformInfo::Architecture)AVIAN_TARGET_ARCH)); + + // if(!platform) { + // fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture); + // return false; + // } + + SymbolInfo bootimageSymbols[] = { + SymbolInfo(0, bootimageStart), + SymbolInfo(bootimageData.length, bootimageEnd) + }; + + platform->writeObject(bootimageOutput, Slice(bootimageSymbols, 2), Slice(bootimageData.data, bootimageData.length), Platform::Writable, TargetBytesPerWord); + + compilationHandler.symbols.add(SymbolInfo(0, codeimageStart)); + compilationHandler.symbols.add(SymbolInfo(image->codeSize, codeimageEnd)); + + platform->writeObject(codeOutput, Slice(compilationHandler.symbols), Slice(code, image->codeSize), Platform::Executable, TargetBytesPerWord); + + for(SymbolInfo* sym = compilationHandler.symbols.begin(); sym != compilationHandler.symbols.end() - 2; sym++) { + t->m->heap->free(const_cast((const void*)sym->name.text), sym->name.length + 1); + } } } uint64_t writeBootImage(Thread* t, uintptr_t* arguments) { - FILE* bootimageOutput = reinterpret_cast(arguments[0]); - FILE* codeOutput = reinterpret_cast(arguments[1]); + OutputStream* bootimageOutput = reinterpret_cast(arguments[0]); + OutputStream* codeOutput = reinterpret_cast(arguments[1]); BootImage* image = reinterpret_cast(arguments[2]); uint8_t* code = reinterpret_cast(arguments[3]); const char* className = reinterpret_cast(arguments[4]); const char* methodName = reinterpret_cast(arguments[5]); const char* methodSpec = reinterpret_cast(arguments[6]); + const char* bootimageStart = reinterpret_cast(arguments[7]); + const char* bootimageEnd = reinterpret_cast(arguments[8]); + const char* codeimageStart = reinterpret_cast(arguments[9]); + const char* codeimageEnd = reinterpret_cast(arguments[10]); + writeBootImage2 (t, bootimageOutput, codeOutput, image, code, className, methodName, - methodSpec); + methodSpec, bootimageStart, bootimageEnd, codeimageStart, codeimageEnd); return 1; } +class Arg; + +class ArgParser { +public: + Arg* first; + Arg** last; + + ArgParser(): + first(0), + last(&first) {} + + bool parse(int ac, const char** av); + void printUsage(const char* exe); +}; + +class Arg { +public: + Arg* next; + bool required; + const char* name; + const char* desc; + + const char* value; + + Arg(ArgParser& parser, bool required, const char* name, const char* desc): + next(0), + required(required), + name(name), + desc(desc), + value(0) + { + *parser.last = this; + parser.last = &next; + } +}; + +bool ArgParser::parse(int ac, const char** av) { + Arg* state = 0; + + for(int i = 1; i < ac; i++) { + if(state) { + if(state->value) { + fprintf(stderr, "duplicate parameter %s: '%s' and '%s'\n", state->name, state->value, av[i]); + return false; + } + state->value = av[i]; + state = 0; + } else { + if(av[i][0] != '-') { + fprintf(stderr, "expected -parameter\n"); + return false; + } + for(Arg* arg = first; arg; arg = arg->next) { + if(strcmp(arg->name, &av[i][1]) == 0) { + state = arg; + } + } + if(!state) { + fprintf(stderr, "unrecognized parameter %s\n", av[i]); + return false; + } + } + } + + if(state) { + fprintf(stderr, "expected argument after -%s\n", state->name); + return false; + } + + for(Arg* arg = first; arg; arg = arg->next) { + if(arg->required && !arg->value) { + fprintf(stderr, "expected value for %s\n", arg->name); + return false; + } + } + + return true; +} + +void ArgParser::printUsage(const char* exe) { + fprintf(stderr, "usage:\n%s \\\n", exe); + for(Arg* arg = first; arg; arg = arg->next) { + const char* lineEnd = arg->next ? " \\" : ""; + if(arg->required) { + fprintf(stderr, " -%s\t%s%s\n", arg->name, arg->desc, lineEnd); + } else { + fprintf(stderr, " [-%s\t%s]%s\n", arg->name, arg->desc, lineEnd); + } + } +} + +class Arguments { +public: + + const char* classpath; + + const char* bootimage; + const char* codeimage; + + char* entryClass; + char* entryMethod; + char* entrySpec; + + char* bootimageStart; + char* bootimageEnd; + + char* codeimageStart; + char* codeimageEnd; + + bool maybeSplit(const char* src, char*& destA, char*& destB) { + if(src) { + const char* split = strchr(src, ':'); + if(!split) { + return false; + } + + destA = strndup(src, split - src); + destB = strdup(split + 1); + } + return true; + } + + Arguments(int ac, const char** av): + entryClass(0), + entryMethod(0), + entrySpec(0), + bootimageStart(0), + bootimageEnd(0), + codeimageStart(0), + codeimageEnd(0) + { + ArgParser parser; + Arg classpath(parser, true, "cp", ""); + Arg bootimage(parser, true, "bootimage", ""); + Arg codeimage(parser, true, "codeimage", ""); + Arg entry(parser, false, "entry", "[.[]]"); + Arg bootimageSymbols(parser, false, "bootimage-symbols", ":"); + Arg codeimageSymbols(parser, false, "codeimage-symbols", ":"); + + if(!parser.parse(ac, av)) { + parser.printUsage(av[0]); + exit(1); + } + + this->classpath = classpath.value; + this->bootimage = bootimage.value; + this->codeimage = codeimage.value; + + if(entry.value) { + if(const char* entryClassEnd = strchr(entry.value, '.')) { + entryClass = strndup(entry.value, entryClassEnd - entry.value); + if(const char* entryMethodEnd = strchr(entryClassEnd, '(')) { + entryMethod = strndup(entryClassEnd + 1, entryMethodEnd - entryClassEnd - 1); + entrySpec = strdup(entryMethodEnd); + } else { + entryMethod = strdup(entryClassEnd + 1); + } + } else { + entryClass = strdup(entry.value); + } + } + + if(!maybeSplit(bootimageSymbols.value, bootimageStart, bootimageEnd) || + !maybeSplit(codeimageSymbols.value, codeimageStart, codeimageEnd)) + { + fprintf(stderr, "wrong format for symbols\n"); + parser.printUsage(av[0]); + exit(1); + } + + if(!bootimageStart) { + bootimageStart = strdup("_binary_bootimage_bin_start"); + } + + if(!bootimageEnd) { + bootimageEnd = strdup("_binary_bootimage_bin_end"); + } + + if(!codeimageStart) { + codeimageStart = strdup("_binary_codeimage_bin_start"); + } + + if(!codeimageEnd) { + codeimageEnd = strdup("_binary_codeimage_bin_end"); + } + + } + + ~Arguments() { + if(entryClass) { + free(entryClass); + } + if(entryMethod) { + free(entryMethod); + } + if(entrySpec) { + free(entrySpec); + } + if(bootimageStart) { + free(bootimageStart); + } + if(bootimageEnd) { + free(bootimageEnd); + } + if(codeimageStart) { + free(codeimageStart); + } + if(codeimageEnd) { + free(codeimageEnd); + } + } + + void dump() { + printf( + "classpath = %s\n" + "bootimage = %s\n" + "codeimage = %s\n" + "entryClass = %s\n" + "entryMethod = %s\n" + "entrySpec = %s\n" + "bootimageStart = %s\n" + "bootimageEnd = %s\n" + "codeimageStart = %s\n" + "codeimageEnd = %s\n", + classpath, + bootimage, + codeimage, + entryClass, + entryMethod, + entrySpec, + bootimageStart, + bootimageEnd, + codeimageStart, + codeimageEnd); + } +}; + } // namespace int main(int ac, const char** av) { - if (ac < 4 or ac > 7) { - fprintf(stderr, "usage: %s " - " [ [ []]]\n", av[0]); - return -1; - } + Arguments args(ac, av); + // args.dump(); System* s = makeSystem(0); Heap* h = makeHeap(s, HeapCapacity * 2); Classpath* c = makeClasspath(s, h, AVIAN_JAVA_HOME, AVIAN_EMBED_PREFIX); - Finder* f = makeFinder(s, h, av[1], 0); + Finder* f = makeFinder(s, h, args.classpath, 0); Processor* p = makeProcessor(s, h, false); // todo: currently, the compiler cannot compile code with jumps or @@ -1662,44 +1957,51 @@ main(int ac, const char** av) // in a branch instruction for the target architecture (~32MB on // PowerPC and ARM). When that limitation is removed, we'll be able // to specify a capacity as large as we like here: +#if (defined ARCH_x86_64) || (defined ARCH_x86_32) + const unsigned CodeCapacity = 128 * 1024 * 1024; +#else const unsigned CodeCapacity = 30 * 1024 * 1024; +#endif uint8_t* code = static_cast(h->allocate(CodeCapacity)); BootImage image; p->initialize(&image, code, CodeCapacity); Machine* m = new (h->allocate(sizeof(Machine))) Machine - (s, h, f, 0, p, c, 0, 0, 0, 0); + (s, h, f, 0, p, c, 0, 0, 0, 0, 128 * 1024); Thread* t = p->makeThread(m, 0, 0); enter(t, Thread::ActiveState); enter(t, Thread::IdleState); - FILE* bootimageOutput = vm::fopen(av[2], "wb"); - if (bootimageOutput == 0) { - fprintf(stderr, "unable to open %s\n", av[2]); + FileOutputStream bootimageOutput(args.bootimage); + if (!bootimageOutput.isValid()) { + fprintf(stderr, "unable to open %s\n", args.bootimage); return -1; } - FILE* codeOutput = vm::fopen(av[3], "wb"); - if (codeOutput == 0) { - fprintf(stderr, "unable to open %s\n", av[3]); + FileOutputStream codeOutput(args.codeimage); + if (!codeOutput.isValid()) { + fprintf(stderr, "unable to open %s\n", args.codeimage); return -1; } - uintptr_t arguments[] = { reinterpret_cast(bootimageOutput), - reinterpret_cast(codeOutput), - reinterpret_cast(&image), - reinterpret_cast(code), - reinterpret_cast(ac > 4 ? av[4] : 0), - reinterpret_cast(ac > 5 ? av[5] : 0), - reinterpret_cast(ac > 6 ? av[6] : 0) }; + uintptr_t arguments[] = { + reinterpret_cast(&bootimageOutput), + reinterpret_cast(&codeOutput), + reinterpret_cast(&image), + reinterpret_cast(code), + reinterpret_cast(args.entryClass), + reinterpret_cast(args.entryMethod), + reinterpret_cast(args.entrySpec), + reinterpret_cast(args.bootimageStart), + reinterpret_cast(args.bootimageEnd), + reinterpret_cast(args.codeimageStart), + reinterpret_cast(args.codeimageEnd) + }; run(t, writeBootImage, arguments); - fclose(codeOutput); - fclose(bootimageOutput); - if (t->exception) { printTrace(t, t->exception); return -1; diff --git a/src/bootimage.h b/src/bootimage.h index a7e178524a..16f11ab379 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/builtin.cpp b/src/builtin.cpp index eed2508564..9c3dca8508 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -327,3 +327,187 @@ Avian_avian_Singleton_getLong (t, reinterpret_cast(arguments[0]), arguments[1]), 8); return v; } + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_allocateMemory +(Thread* t, object, uintptr_t* arguments) +{ + int64_t size; memcpy(&size, arguments + 1, 8); + void* p = malloc(size); + if (p) { + return reinterpret_cast(p); + } else { + throwNew(t, Machine::OutOfMemoryErrorType); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_freeMemory +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + if (p) { + free(reinterpret_cast(p)); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_setMemory +(Thread* t, object, uintptr_t* arguments) +{ + object base = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int64_t count; memcpy(&count, arguments + 4, 8); + int8_t value = arguments[6]; + + PROTECT(t, base); + + ACQUIRE(t, t->m->referenceLock); + + if (base) { + memset(&cast(base, offset), value, count); + } else { + memset(reinterpret_cast(offset), value, count); + } +} + +// NB: The following primitive get/put methods are only used by the +// interpreter. The JIT/AOT compiler implements them as intrinsics, +// so these versions will be ignored. + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putByte__JB +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int8_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putShort__JS +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int16_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putChar__JC +(Thread* t, object method, uintptr_t* arguments) +{ + Avian_sun_misc_Unsafe_putShort__JS(t, method, arguments); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putInt__JI +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int32_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putFloat__JF +(Thread* t, object method, uintptr_t* arguments) +{ + Avian_sun_misc_Unsafe_putInt__JI(t, method, arguments); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putLong__JJ +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int64_t v; memcpy(&v, arguments + 3, 8); + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putDouble__JD +(Thread* t, object method, uintptr_t* arguments) +{ + Avian_sun_misc_Unsafe_putLong__JJ(t, method, arguments); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putAddress__JJ +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int64_t v; memcpy(&v, arguments + 3, 8); + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getByte__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getShort__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getChar__J +(Thread* t, object method, uintptr_t* arguments) +{ + return Avian_sun_misc_Unsafe_getShort__J(t, method, arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getInt__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getFloat__J +(Thread* t, object method, uintptr_t* arguments) +{ + return Avian_sun_misc_Unsafe_getInt__J(t, method, arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getLong__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getDouble__J +(Thread* t, object method, uintptr_t* arguments) +{ + return Avian_sun_misc_Unsafe_getLong__J(t, method, arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getAddress__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 39cde4ff83..5e68d2ed14 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2011, Avian Contributors +/* Copyright (c) 2010-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -54,6 +54,12 @@ class MyClasspath : public Classpath { root(t, Machine::BootLoader), 0, 0, group, 0); } + virtual void + clearInterrupted(Thread*) + { + // ignore + } + virtual void runThread(Thread* t) { diff --git a/src/classpath-common.h b/src/classpath-common.h index 99e042162c..d8105b9cd7 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2011, Avian Contributors +/* Copyright (c) 2010-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -120,6 +120,16 @@ void runOnLoadIfFound(Thread* t, System::Library* library) { void* p = library->resolve("JNI_OnLoad"); + +#ifdef PLATFORM_WINDOWS + if (p == 0) { + p = library->resolve("_JNI_OnLoad@8"); + if (p == 0) { + p = library->resolve("JNI_OnLoad@8"); + } + } +#endif + if (p) { jint (JNICALL * JNI_OnLoad)(Machine*, void*); memcpy(&JNI_OnLoad, &p, sizeof(void*)); diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 2b12362a6c..fe9dbfdbfb 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2011, Avian Contributors +/* Copyright (c) 2010-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -42,7 +42,6 @@ # define S_IWUSR _S_IWRITE # else # define OPEN _open -# define CREAT _creat # endif # define O_RDONLY _O_RDONLY @@ -82,6 +81,8 @@ typedef int socklen_t; #endif // not PLATFORM_WINDOWS +#define JVM_EEXIST -100 + using namespace vm; namespace { @@ -97,12 +98,6 @@ OPEN(string_t path, int mask, int mode) return -1; } } - -inline int -CREAT(string_t path, int mode) -{ - return OPEN(path, _O_CREAT, mode); -} #endif namespace local { @@ -349,6 +344,9 @@ makeClassNameString(Thread* t, object name) void interceptFileOperations(Thread*); +void +clearInterrupted(Thread*); + class MyClasspath : public Classpath { public: static const unsigned BufferSize = 1024; @@ -415,6 +413,8 @@ class MyClasspath : public Classpath { sb.append(javaHome); #ifdef PLATFORM_WINDOWS sb.append("/bin"); +#elif defined __APPLE__ + sb.append("/lib"); #elif defined ARCH_x86_64 sb.append("/lib/amd64"); #else @@ -440,9 +440,14 @@ class MyClasspath : public Classpath { PROTECT(t, class_); object name = makeClassNameString(t, getClassName(t, class_)); + PROTECT(t, name); - return vm::makeJclass - (t, 0, 0, name, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, class_); + object c = allocate(t, FixedSizeOfJclass, true); + setObjectClass(t, c, type(t, Machine::JclassType)); + set(t, c, JclassName, name); + set(t, c, JclassVmClass, class_); + + return c; } virtual object @@ -504,6 +509,12 @@ class MyClasspath : public Classpath { return thread; } + virtual void + clearInterrupted(Thread* t) + { + local::clearInterrupted(t); + } + virtual void runThread(Thread* t) { @@ -551,31 +562,61 @@ class MyClasspath : public Classpath { expect(t, loadLibrary(t, libraryPath, "java", true, true)); #endif // not AVIAN_OPENJDK_SRC - object constructor = resolveMethod + { object class_ = resolveClass + (t, root(t, Machine::BootLoader), "java/util/Properties", true, + Machine::NoClassDefFoundErrorType); + + PROTECT(t, class_); + + object instance = makeNew(t, class_); + + PROTECT(t, instance); + + object constructor = resolveMethod(t, class_, "", "()V"); + + t->m->processor->invoke(t, constructor, instance); + + t->m->processor->invoke + (t, root(t, Machine::BootLoader), "java/lang/System", + "setProperties", "(Ljava/util/Properties;)V", 0, instance); + } + + { object constructor = resolveMethod (t, type(t, Machine::ClassLoaderType), "", "(Ljava/lang/ClassLoader;)V"); - PROTECT(t, constructor); + PROTECT(t, constructor); - t->m->processor->invoke(t, constructor, root(t, Machine::BootLoader), 0); + t->m->processor->invoke(t, constructor, root(t, Machine::BootLoader), 0); - t->m->processor->invoke - (t, constructor, root(t, Machine::AppLoader), - root(t, Machine::BootLoader)); + t->m->processor->invoke + (t, constructor, root(t, Machine::AppLoader), + root(t, Machine::BootLoader)); + } - object scl = resolveField - (t, type(t, Machine::ClassLoaderType), "scl", "Ljava/lang/ClassLoader;"); + { object assertionLock = resolveField + (t, type(t, Machine::ClassLoaderType), "assertionLock", + "Ljava/lang/Object;"); - PROTECT(t, scl); + set(t, root(t, Machine::BootLoader), fieldOffset(t, assertionLock), + root(t, Machine::BootLoader)); + } - object sclSet = resolveField - (t, type(t, Machine::ClassLoaderType), "sclSet", "Z"); + { object scl = resolveField + (t, type(t, Machine::ClassLoaderType), "scl", + "Ljava/lang/ClassLoader;"); - set(t, classStaticTable(t, type(t, Machine::ClassLoaderType)), - fieldOffset(t, scl), root(t, Machine::AppLoader)); + PROTECT(t, scl); - cast(classStaticTable(t, type(t, Machine::ClassLoaderType)), - fieldOffset(t, sclSet)) = true; + object sclSet = resolveField + (t, type(t, Machine::ClassLoaderType), "sclSet", "Z"); + + set(t, classStaticTable(t, type(t, Machine::ClassLoaderType)), + fieldOffset(t, scl), root(t, Machine::AppLoader)); + + cast(classStaticTable(t, type(t, Machine::ClassLoaderType)), + fieldOffset(t, sclSet)) = true; + } t->m->processor->invoke (t, root(t, Machine::BootLoader), "java/lang/System", @@ -1318,15 +1359,17 @@ getZipFileEntry(Thread* t, object method, uintptr_t* arguments) ZipFile* file = reinterpret_cast(peer); if (file->region) { - THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 2); - stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + THREAD_RUNTIME_ARRAY(t, char, p, byteArrayLength(t, path) + 2); + memcpy(RUNTIME_ARRAY_BODY(p), &byteArrayBody(t, path, 0), + byteArrayLength(t, path)); + RUNTIME_ARRAY_BODY(p)[byteArrayLength(t, path)] = 0; replace('\\', '/', RUNTIME_ARRAY_BODY(p)); if (addSlash) { - RUNTIME_ARRAY_BODY(p)[stringLength(t, path)] = '/'; - RUNTIME_ARRAY_BODY(p)[stringLength(t, path) + 1] = 0; + RUNTIME_ARRAY_BODY(p)[byteArrayLength(t, path)] = '/'; + RUNTIME_ARRAY_BODY(p)[byteArrayLength(t, path) + 1] = 0; } - return reinterpret_cast(find(file, p, stringLength(t, path))); + return reinterpret_cast(find(file, p, byteArrayLength(t, path))); } else { int64_t entry = longValue (t, t->m->processor->invoke @@ -1340,6 +1383,43 @@ getZipFileEntry(Thread* t, object method, uintptr_t* arguments) } } +int64_t JNICALL +getZipFileEntryBytes(Thread* t, object method, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + int type = arguments[2]; + + ZipFile::Entry* entry = reinterpret_cast(peer); + if (entry->start) { + switch (type) { + case 0: { // name + unsigned nameLength = fileNameLength(entry->start); + object array = makeByteArray(t, nameLength + 1); + memcpy(&byteArrayBody(t, array, 0), fileName(entry->start), nameLength); + byteArrayBody(t, array, nameLength) = 0; + return reinterpret_cast(array); + } break; + + case 1: { // extra + return 0; + } break; + + case 2: { // comment + return 0; + } break; + + default: abort(t); + } + return compressedSize(entry->start); + } else { + return reinterpret_cast + (t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + 0, entry->entry, type)); + } +} + int64_t JNICALL getNextZipFileEntry(Thread* t, object method, uintptr_t* arguments) { @@ -1467,6 +1547,8 @@ freeZipFileEntry(Thread* t, object method, uintptr_t* arguments) (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, file->file, entry->entry); } + + t->m->heap->free(entry, sizeof(ZipFile::Entry)); } int64_t JNICALL @@ -1674,7 +1756,7 @@ loadLibrary(Thread* t, object, uintptr_t* arguments) loadLibrary (t, static_cast(t->m->classpath)->libraryPath, - RUNTIME_ARRAY_BODY(n), not absolute, false); + RUNTIME_ARRAY_BODY(n), not absolute, true); } // only safe to call during bootstrap when there's only one thread @@ -1703,6 +1785,15 @@ intercept(Thread* t, object c, const char* name, const char* spec, object runtimeData = getMethodRuntimeData(t, m); set(t, runtimeData, MethodRuntimeDataNative, native); + } else { + // If we can't find the method, just ignore it, since ProGuard may + // have stripped it out as unused. Otherwise, the code below can + // be uncommented for debugging purposes. + + // fprintf(stderr, "unable to find %s%s in %s\n", + // name, spec, &byteArrayBody(t, className(t, c), 0)); + + // abort(t); } } @@ -1770,60 +1861,6 @@ interceptFileOperations(Thread* t) } } - { object zipEntryClass = resolveClass - (t, root(t, Machine::BootLoader), "java/util/zip/ZipEntry", false); - - if (zipEntryClass) { - PROTECT(t, zipEntryClass); - - object zipEntryNameField = findFieldInClass2 - (t, zipEntryClass, "name", "Ljava/lang/String;"); - - if (zipEntryNameField) { - cp->zipEntryNameField = fieldOffset(t, zipEntryNameField); - - object zipEntryTimeField = findFieldInClass2 - (t, zipEntryClass, "time", "J"); - - if (zipEntryTimeField) { - cp->zipEntryTimeField = fieldOffset(t, zipEntryTimeField); - - object zipEntryCrcField = findFieldInClass2 - (t, zipEntryClass, "crc", "J"); - - if (zipEntryCrcField) { - cp->zipEntryCrcField = fieldOffset(t, zipEntryCrcField); - - object zipEntrySizeField = findFieldInClass2 - (t, zipEntryClass, "size", "J"); - - if (zipEntrySizeField) { - cp->zipEntrySizeField = fieldOffset(t, zipEntrySizeField); - - object zipEntryCsizeField = findFieldInClass2 - (t, zipEntryClass, "csize", "J"); - - if (zipEntryCsizeField) { - cp->zipEntryCsizeField = fieldOffset(t, zipEntryCsizeField); - - object zipEntryMethodField = findFieldInClass2 - (t, zipEntryClass, "method", "I"); - - if (zipEntryMethodField) { - cp->zipEntryMethodField = fieldOffset - (t, zipEntryMethodField); - - intercept(t, zipEntryClass, "initFields", "(J)V", - voidPointer(initializeZipEntryFields)); - } - } - } - } - } - } - } - } - { object zipFileClass = resolveClass (t, root(t, Machine::BootLoader), "java/util/zip/ZipFile", false); @@ -1836,19 +1873,22 @@ interceptFileOperations(Thread* t) if (zipFileJzfileField) { cp->zipFileJzfileField = fieldOffset(t, zipFileJzfileField); - intercept(t, zipFileClass, "open", "(Ljava/lang/String;IJ)J", + intercept(t, zipFileClass, "open", "(Ljava/lang/String;IJZ)J", voidPointer(openZipFile)); intercept(t, zipFileClass, "getTotal", "(J)I", voidPointer(getZipFileEntryCount)); - intercept(t, zipFileClass, "getEntry", "(JLjava/lang/String;Z)J", + intercept(t, zipFileClass, "getEntry", "(J[BZ)J", voidPointer(getZipFileEntry)); + intercept(t, zipFileClass, "getEntryBytes", "(JI)[B", + voidPointer(getZipFileEntryBytes)); + intercept(t, zipFileClass, "getNextEntry", "(JI)J", voidPointer(getNextZipFileEntry)); - intercept(t, zipFileClass, "getMethod", "(J)I", + intercept(t, zipFileClass, "getEntryMethod", "(J)I", voidPointer(getZipFileEntryMethod)); intercept(t, zipFileClass, "freeEntry", "(JJ)V", @@ -1857,10 +1897,10 @@ interceptFileOperations(Thread* t) intercept(t, zipFileClass, "read", "(JJJ[BII)I", voidPointer(readZipFileEntry)); - intercept(t, zipFileClass, "getCSize", "(J)J", + intercept(t, zipFileClass, "getEntryCSize", "(J)J", voidPointer(getZipFileEntryCompressedSize)); - intercept(t, zipFileClass, "getSize", "(J)J", + intercept(t, zipFileClass, "getEntrySize", "(J)J", voidPointer(getZipFileEntryUncompressedSize)); intercept(t, zipFileClass, "getZipMessage", "(J)Ljava/lang/String;", @@ -2181,6 +2221,14 @@ interruptLock(Thread* t, object thread) return threadInterruptLock(t, thread); } +void +clearInterrupted(Thread* t) +{ + monitorAcquire(t, local::interruptLock(t, t->javaThread)); + threadInterrupted(t, t->javaThread) = false; + monitorRelease(t, local::interruptLock(t, t->javaThread)); +} + bool pipeAvailable(int fd, int* available) { @@ -2207,19 +2255,40 @@ pipeAvailable(int fd, int* available) } object -fieldForOffset(Thread* t, object o, unsigned offset) +fieldForOffsetInClass(Thread* t, object c, unsigned offset) { - object table = classFieldTable(t, objectClass(t, o)); - for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { - object field = objectArrayBody(t, table, i); - if ((fieldFlags(t, field) & ACC_STATIC) == 0 - and fieldOffset(t, field) == offset) - { + object super = classSuper(t, c); + if (super) { + object field = fieldForOffsetInClass(t, super, offset); + if (field) { return field; } } - - abort(t); + + object table = classFieldTable(t, c); + if (table) { + for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { + object field = objectArrayBody(t, table, i); + if ((fieldFlags(t, field) & ACC_STATIC) == 0 + and fieldOffset(t, field) == offset) + { + return field; + } + } + } + + return 0; +} + +object +fieldForOffset(Thread* t, object o, unsigned offset) +{ + object field = fieldForOffsetInClass(t, objectClass(t, o), offset); + if (field) { + return field; + } else { + abort(t); + } } } // namespace local @@ -2255,6 +2324,24 @@ Avian_sun_misc_Unsafe_registerNatives // ignore } +extern "C" JNIEXPORT void +Avian_sun_misc_Perf_registerNatives +(Thread*, object, uintptr_t*) +{ + // ignore +} + +extern "C" JNIEXPORT int64_t +Avian_sun_misc_Perf_createLong +(Thread* t, object, uintptr_t*) +{ + return reinterpret_cast + (t->m->processor->invoke + (t, resolveMethod + (t, root(t, Machine::BootLoader), "java/nio/ByteBuffer", "allocate", + "(I)Ljava/nio/ByteBuffer;"), 0, 8)); +} + extern "C" JNIEXPORT int64_t Avian_sun_misc_Unsafe_addressSize (Thread*, object, uintptr_t*) @@ -2504,13 +2591,20 @@ Avian_sun_misc_Unsafe_putFloat__Ljava_lang_Object_2JF } extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_getBoolean +Avian_sun_misc_Unsafe_getByte (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); - return cast(o, offset); + return cast(o, offset); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getBoolean +(Thread* t, object method, uintptr_t* arguments) +{ + return Avian_sun_misc_Unsafe_getByte(t, method, arguments); } extern "C" JNIEXPORT void JNICALL @@ -2560,6 +2654,13 @@ Avian_sun_misc_Unsafe_putObjectVolatile storeLoadMemoryBarrier(); } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putOrderedObject +(Thread* t, object method, uintptr_t* arguments) +{ + Avian_sun_misc_Unsafe_putObjectVolatile(t, method, arguments); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_compareAndSwapInt (Thread*, object, uintptr_t* arguments) @@ -2615,115 +2716,6 @@ Avian_sun_misc_Unsafe_compareAndSwapLong #endif } -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_allocateMemory -(Thread* t, object, uintptr_t* arguments) -{ - void* p = malloc(arguments[1]); - if (p) { - return reinterpret_cast(p); - } else { - throwNew(t, Machine::OutOfMemoryErrorType); - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_freeMemory -(Thread*, object, uintptr_t* arguments) -{ - void* p = reinterpret_cast(arguments[1]); - if (p) { - free(p); - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_setMemory -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int64_t count; memcpy(&count, arguments + 3, 8); - int8_t v = arguments[5]; - - memset(reinterpret_cast(p), v, count); -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_putByte__JB -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int8_t v = arguments[3]; - - *reinterpret_cast(p) = v; -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_putShort__JS -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int16_t v = arguments[3]; - - *reinterpret_cast(p) = v; -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_putLong__JJ -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int64_t v; memcpy(&v, arguments + 3, 8); - - *reinterpret_cast(p) = v; -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_putInt__JI -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int32_t v = arguments[3]; - - *reinterpret_cast(p) = v; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_getByte__J -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - - return *reinterpret_cast(p); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_getInt__J -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - - return *reinterpret_cast(p); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_getLong__J -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - - return *reinterpret_cast(p); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_getFloat__J -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - - return *reinterpret_cast(p); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_pageSize (Thread*, object, uintptr_t*) @@ -2764,12 +2756,15 @@ Avian_sun_misc_Unsafe_park if (time <= 0) { return; } - } else { - time /= 1000 * 1000; + } else if (time) { + // if not absolute, interpret time as nanoseconds, but make sure + // it doesn't become zero when we convert to milliseconds, since + // zero is interpreted as infinity below + time = (time / (1000 * 1000)) + 1; } monitorAcquire(t, local::interruptLock(t, t->javaThread)); - while (time > 0 + while (time >= 0 and (not (threadUnparked(t, t->javaThread) or monitorWait (t, local::interruptLock(t, t->javaThread), time)))) @@ -2777,11 +2772,55 @@ Avian_sun_misc_Unsafe_park int64_t now = t->m->system->now(); time -= now - then; then = now; + + if (time == 0) { + break; + } } threadUnparked(t, t->javaThread) = false; monitorRelease(t, local::interruptLock(t, t->javaThread)); } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_copyMemory +(Thread* t, object, uintptr_t* arguments) +{ + object srcBase = reinterpret_cast(arguments[1]); + int64_t srcOffset; memcpy(&srcOffset, arguments + 2, 8); + object dstBase = reinterpret_cast(arguments[4]); + int64_t dstOffset; memcpy(&dstOffset, arguments + 5, 8); + int64_t count; memcpy(&count, arguments + 7, 8); + + PROTECT(t, srcBase); + PROTECT(t, dstBase); + + ACQUIRE(t, t->m->referenceLock); + + void* src = srcBase + ? &cast(srcBase, srcOffset) + : reinterpret_cast(srcOffset); + + void* dst = dstBase + ? &cast(dstBase, dstOffset) + : reinterpret_cast(dstOffset); + + memcpy(dst, src, count); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_monitorEnter +(Thread* t, object, uintptr_t* arguments) +{ + acquire(t, reinterpret_cast(arguments[1])); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_monitorExit +(Thread* t, object, uintptr_t* arguments) +{ + release(t, reinterpret_cast(arguments[1])); +} + namespace { namespace local { @@ -2956,22 +2995,22 @@ jvmInitProperties(Thread* t, uintptr_t* arguments) GetCurrentDirectory(MAX_PATH, buffer); local::setProperty(t, method, *properties, "user.dir", buffer); -#else +#else // not PLATFORM_WINDOWS local::setProperty(t, method, *properties, "line.separator", "\n"); local::setProperty(t, method, *properties, "file.separator", "/"); local::setProperty(t, method, *properties, "path.separator", ":"); # ifdef __APPLE__ local::setProperty(t, method, *properties, "os.name", "Mac OS X"); -# else +# else // not __APPLE__ local::setProperty(t, method, *properties, "os.name", "Linux"); -# endif +# endif // not __APPLE__ local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); local::setProperty(t, method, *properties, "user.home", getenv("HOME")); char buffer[PATH_MAX]; local::setProperty(t, method, *properties, "user.dir", getcwd(buffer, PATH_MAX)); -#endif +#endif // not PLATFORM_WINDOWS local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", "avian"); @@ -2987,6 +3026,11 @@ jvmInitProperties(Thread* t, uintptr_t* arguments) (t, method, *properties, "sun.boot.library.path", static_cast(t->m->classpath)->libraryPath); + local::setProperty + (t, method, *properties, "sun.boot.class.path", + static_cast + (systemClassLoaderFinder(t, root(t, Machine::BootLoader)))->path()); + local::setProperty(t, method, *properties, "file.encoding", "ASCII"); #ifdef ARCH_x86_32 local::setProperty(t, method, *properties, "os.arch", "x86"); @@ -3153,7 +3197,7 @@ jvmFillInStackTrace(Thread* t, uintptr_t* arguments) { jobject throwable = reinterpret_cast(arguments[0]); - object trace = getTrace(t, 1); + object trace = getTrace(t, 2); set(t, *throwable, ThrowableTrace, trace); return 1; @@ -3231,12 +3275,20 @@ EXPORT(JVM_DisableCompiler)(Thread*, jclass) // ignore } +uint64_t +jvmStartThread(Thread* t, uintptr_t* arguments) +{ + jobject thread = reinterpret_cast(arguments[0]); + + return startThread(t, *thread) != 0; +} + extern "C" JNIEXPORT void JNICALL EXPORT(JVM_StartThread)(Thread* t, jobject thread) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(thread) }; - startThread(t, *thread); + run(t, jvmStartThread, arguments); } extern "C" JNIEXPORT void JNICALL @@ -3315,9 +3367,8 @@ jvmInterrupt(Thread* t, uintptr_t* arguments) Thread* p = reinterpret_cast(threadPeer(t, *thread)); if (p) { interrupt(t, p); - } else { - threadInterrupted(t, *thread) = true; } + threadInterrupted(t, *thread) = true; monitorRelease(t, local::interruptLock(t, *thread)); return 1; @@ -3355,8 +3406,21 @@ EXPORT(JVM_IsInterrupted)(Thread* t, jobject thread, jboolean clear) return run(t, jvmIsInterrupted, arguments); } +uint64_t +jvmHoldsLock(Thread* t, uintptr_t* arguments) +{ + object m = objectMonitor(t, *reinterpret_cast(arguments[0]), false); + + return m and monitorOwner(t, m) == t; +} + extern "C" JNIEXPORT jboolean JNICALL -EXPORT(JVM_HoldsLock)(Thread*, jclass, jobject) { abort(); } +EXPORT(JVM_HoldsLock)(Thread* t, jclass, jobject o) +{ + uintptr_t arguments[] = { reinterpret_cast(o) }; + + return run(t, jvmHoldsLock, arguments); +} extern "C" JNIEXPORT void JNICALL EXPORT(JVM_DumpAllStacks)(Thread*, jclass) { abort(); } @@ -3826,10 +3890,9 @@ EXPORT(JVM_FindClassFromClassLoader)(Thread* t, const char* name, } extern "C" JNIEXPORT jclass JNICALL -EXPORT(JVM_FindClassFromBootLoader)(Thread* t, const char* name, - jboolean throwError) +JVM_FindClassFromBootLoader(Thread* t, const char* name) { - return EXPORT(JVM_FindClassFromClassLoader)(t, name, false, 0, throwError); + return EXPORT(JVM_FindClassFromClassLoader)(t, name, false, 0, false); } extern "C" JNIEXPORT jclass JNICALL @@ -4257,9 +4320,9 @@ jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments) } object method = makeJmethod - (t, true, *c, i, name, returnType, parameterTypes, exceptionTypes, + (t, true, 0, *c, i, name, returnType, parameterTypes, exceptionTypes, methodFlags(t, vmMethod), signature, 0, annotationTable, 0, - annotationDefault, 0, 0, 0, 0, 0); + annotationDefault, 0, 0, 0); assert(t, ai < objectArrayLength(t, array)); @@ -4346,8 +4409,8 @@ jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments) } object field = makeJfield - (t, true, *c, i, name, type, fieldFlags - (t, vmField), signature, 0, annotationTable, 0, 0, 0, 0, 0, 0); + (t, true, 0, *c, i, name, type, fieldFlags + (t, vmField), signature, 0, annotationTable, 0, 0, 0, 0); assert(t, ai < objectArrayLength(t, array)); @@ -4437,8 +4500,8 @@ jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments) } object method = makeJconstructor - (t, true, *c, i, parameterTypes, exceptionTypes, methodFlags - (t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0, 0); + (t, true, 0, *c, i, parameterTypes, exceptionTypes, methodFlags + (t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0); assert(t, ai < objectArrayLength(t, array)); @@ -4872,7 +4935,12 @@ EXPORT(JVM_NativePath)(char* path) extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_Open)(const char* path, jint flags, jint mode) { - return OPEN(path, flags, mode); + int r = OPEN(path, flags, mode); + if (r == -1) { + return errno == EEXIST ? JVM_EEXIST : -1; + } else { + return r; + } } extern "C" JNIEXPORT jint JNICALL @@ -5205,9 +5273,11 @@ jboolean JNICALL GetBoolAttribute(Thread* t, jmmBoolAttribute attribute) { const unsigned JMM_THREAD_CPU_TIME = 24; + const unsigned JMM_THREAD_ALLOCATED_MEMORY = 25; switch (attribute) { case JMM_THREAD_CPU_TIME: + case JMM_THREAD_ALLOCATED_MEMORY: return false; default: @@ -5290,13 +5360,19 @@ extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetThreadStateNames)(JNIEnv*, jint, jintArray) { abort(); } extern "C" JNIEXPORT void JNICALL -EXPORT(JVM_GetVersionInfo)(JNIEnv*, local::jvm_version_info*, size_t) -{ abort(); } +EXPORT(JVM_GetVersionInfo)(JNIEnv*, local::jvm_version_info* info, size_t size) +{ + memset(info, 0, size); + info->jvm_version = 0x01070000; +} extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_CX8Field)(JNIEnv*, jobject*, jfieldID*, jlong, jlong) { abort(); } +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_SetNativeThreadName)(JNIEnv*, jobject, jstring) { abort(); } + } // namespace local } // namespace @@ -5316,7 +5392,17 @@ jio_vfprintf(FILE* stream, const char* format, va_list a) #ifdef PLATFORM_WINDOWS extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_GetThreadInterruptEvent)() -{ abort(); } +{ + // hack: We don't want to expose thread interruption implementation + // details, so we give the class library a fake event to play with. + // This means that threads won't be interruptable when blocked in + // Process.waitFor. + static HANDLE fake = 0; + if (fake == 0) { + fake = CreateEvent(0, true, false, 0); + } + return fake; +} namespace { HMODULE jvmHandle = 0; } diff --git a/src/common.h b/src/common.h index 7c60041449..009b90226e 100644 --- a/src/common.h +++ b/src/common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -56,10 +56,12 @@ typedef unsigned __int64 uint64_t; # ifdef _M_IX86 typedef int32_t intptr_t; typedef uint32_t uintptr_t; +# define UINT64_C(x) x##LL # define ARCH_x86_32 # elif defined _M_X64 typedef int64_t intptr_t; typedef uint64_t uintptr_t; +# define UINT64_C(x) x##L # define ARCH_x86_64 # else # error "unsupported architecture" diff --git a/src/compile-arm.S b/src/compile-arm.S index a3f15f7c14..8ce5cc3684 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2011, Avian Contributors +/* Copyright (c) 2010-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -38,6 +38,7 @@ #define CONTINUATION_BODY 32 .globl GLOBAL(vmInvoke) +.align 2 GLOBAL(vmInvoke): /* arguments @@ -84,6 +85,7 @@ LOCAL(vmInvoke_argumentTest): blx r1 .globl GLOBAL(vmInvoke_returnAddress) +.align 2 GLOBAL(vmInvoke_returnAddress): // restore stack pointer ldr sp, [r8, #THREAD_SCRATCH] @@ -97,6 +99,7 @@ GLOBAL(vmInvoke_returnAddress): str r5, [r8, #THREAD_STACK] .globl GLOBAL(vmInvoke_safeStack) +.align 2 GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS @@ -174,6 +177,7 @@ LOCAL(vmInvoke_return): bx lr .globl GLOBAL(vmJumpAndInvoke) +.align 2 GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // r0: thread diff --git a/src/compile.cpp b/src/compile.cpp index 25fa2c5ab5..5e54cd8616 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -176,8 +176,8 @@ class MyThread: public Thread { Context(t, ip, stack, continuation, trace), t(t), link(0), - javaStackLimit(0), - next(t->traceContext) + next(t->traceContext), + methodIsMostRecent(false) { t->traceContext = this; } @@ -186,8 +186,8 @@ class MyThread: public Thread { Context(t, t->ip, t->stack, t->continuation, t->trace), t(t), link(link), - javaStackLimit(0), - next(t->traceContext) + next(t->traceContext), + methodIsMostRecent(false) { t->traceContext = this; } @@ -198,8 +198,8 @@ class MyThread: public Thread { MyThread* t; void* link; - void* javaStackLimit; TraceContext* next; + bool methodIsMostRecent; }; static void doTransition(MyThread* t, void* ip, void* stack, @@ -353,18 +353,18 @@ root(Thread* t, Root root); void setRoot(Thread* t, Root root, object value); -unsigned -compiledSize(intptr_t address) -{ - return reinterpret_cast(address)[-1]; -} - intptr_t methodCompiled(Thread* t, object method) { return codeCompiled(t, methodCode(t, method)); } +unsigned +methodCompiledSize(Thread* t, object method) +{ + return codeCompiledSize(t, methodCode(t, method)); +} + intptr_t compareIpToMethodBounds(Thread* t, intptr_t ip, object method) { @@ -374,13 +374,13 @@ compareIpToMethodBounds(Thread* t, intptr_t ip, object method) fprintf(stderr, "find %p in (%p,%p)\n", reinterpret_cast(ip), reinterpret_cast(start), - reinterpret_cast(start + compiledSize(start))); + reinterpret_cast(start + methodCompiledSize(t, method))); } if (ip < start) { return -1; } else if (ip < start + static_cast - (compiledSize(start) + TargetBytesPerWord)) + (methodCompiledSize(t, method))) { return 0; } else { @@ -427,19 +427,20 @@ alignedFrameSize(MyThread* t, object method) } void -nextFrame(MyThread* t, void** ip, void** sp, object method, object target) +nextFrame(MyThread* t, void** ip, void** sp, object method, object target, + bool mostRecent) { object code = methodCode(t, method); intptr_t start = codeCompiled(t, code); void* link; - void* javaStackLimit; + bool methodIsMostRecent; if (t->traceContext) { link = t->traceContext->link; - javaStackLimit = t->traceContext->javaStackLimit; + methodIsMostRecent = mostRecent and t->traceContext->methodIsMostRecent; } else { link = 0; - javaStackLimit = 0; + methodIsMostRecent = false; } // fprintf(stderr, "nextFrame %s.%s%s target %s.%s%s ip %p sp %p\n", @@ -458,8 +459,8 @@ nextFrame(MyThread* t, void** ip, void** sp, object method, object target) // *ip, *sp); t->arch->nextFrame - (reinterpret_cast(start), compiledSize(start), - alignedFrameSize(t, method), link, javaStackLimit, + (reinterpret_cast(start), codeCompiledSize(t, code), + alignedFrameSize(t, method), link, methodIsMostRecent, target ? methodParameterFootprint(t, target) : -1, ip, sp); // fprintf(stderr, "next frame ip %p sp %p\n", *ip, *sp); @@ -514,6 +515,7 @@ class MyStackWalker: public Processor::StackWalker { state(Start), method_(0), target(0), + count_(0), protector(this) { if (t->traceContext) { @@ -538,6 +540,7 @@ class MyStackWalker: public Processor::StackWalker { method_(w->method_), target(w->target), continuation(w->continuation), + count_(0), protector(this) { } @@ -609,13 +612,15 @@ class MyStackWalker: public Processor::StackWalker { } void next() { + expect(t, count_ <= stackSizeInWords(t)); + switch (state) { case Continuation: continuation = continuationNext(t, continuation); break; case Method: - nextFrame(t, &ip_, &stack, method_, target); + nextFrame(t, &ip_, &stack, method_, target, count_ == 0); break; case NativeMethod: @@ -625,6 +630,8 @@ class MyStackWalker: public Processor::StackWalker { abort(t); } + ++ count_; + state = Next; } @@ -671,6 +678,7 @@ class MyStackWalker: public Processor::StackWalker { object method_; object target; object continuation; + unsigned count_; MyProtector protector; }; @@ -1381,8 +1389,7 @@ class Frame { Compiler::Operand* append(object o) { BootContext* bc = context->bootContext; if (bc) { - Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) - ListenPromise(t->m->system, bc->zone); + Promise* p = new (bc->zone) ListenPromise(t->m->system, bc->zone); PROTECT(t, o); object pointer = makePointer(t, p); @@ -1400,9 +1407,7 @@ class Frame { } } - context->objectPool = new - (context->zone.allocate(sizeof(PoolElement))) - PoolElement(t, o, context->objectPool); + context->objectPool = new(&context->zone) PoolElement(t, o, context->objectPool); ++ context->objectPoolCount; @@ -1607,8 +1612,7 @@ class Frame { Promise* addressPromise(Promise* p) { BootContext* bc = context->bootContext; if (bc) { - bc->addresses = new (bc->zone->allocate(sizeof(DelayedPromise))) - DelayedPromise(t->m->system, bc->zone, p, bc->addresses); + bc->addresses = new(bc->zone) DelayedPromise(t->m->system, bc->zone, p, bc->addresses); return bc->addresses; } else { return p; @@ -1625,7 +1629,7 @@ class Frame { (TargetBytesPerWord, c->memory (c->register_(t->arch->thread()), Compiler::AddressType, TargetThreadCodeImage), c->promiseConstant - (new (context->zone.allocate(sizeof(OffsetPromise))) + (new(&context->zone) OffsetPromise (p, - reinterpret_cast(codeAllocator(t)->base)), Compiler::AddressType)) @@ -2065,6 +2069,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, } object target = t->trace->targetMethod; + bool mostRecent = true; *targetIp = 0; while (*targetIp == 0) { @@ -2075,7 +2080,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, if (handler) { *targetIp = handler; - nextFrame(t, &ip, &stack, method, target); + nextFrame(t, &ip, &stack, method, target, mostRecent); void** sp = static_cast(stackForFrame(t, stack, method)) + t->arch->frameReturnAddressSize(); @@ -2089,7 +2094,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, t->exception = 0; } else { - nextFrame(t, &ip, &stack, method, target); + nextFrame(t, &ip, &stack, method, target, mostRecent); if (t->exception) { releaseLock(t, method, stack); @@ -2137,6 +2142,8 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, *targetContinuation = continuationNext(t, c); } } + + mostRecent = false; } } @@ -2160,6 +2167,8 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) object last = 0; PROTECT(t, last); + bool mostRecent = true; + *targetIp = 0; while (*targetIp == 0) { object method = methodForIp(t, ip); @@ -2177,7 +2186,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) } void* nextIp = ip; - nextFrame(t, &nextIp, &stack, method, target); + nextFrame(t, &nextIp, &stack, method, target, mostRecent); void** bottom = static_cast(stack) + t->arch->frameReturnAddressSize(); @@ -2215,6 +2224,8 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); } + + mostRecent = false; } expect(t, last); @@ -2357,6 +2368,31 @@ findInterfaceMethodFromInstanceAndReference return findInterfaceMethodFromInstance(t, method, instance); } +void +checkMethod(Thread* t, object method, bool shouldBeStatic) +{ + if (((methodFlags(t, method) & ACC_STATIC) == 0) == shouldBeStatic) { + throwNew(t, Machine::IncompatibleClassChangeErrorType, + "expected %s.%s%s to be %s", + &byteArrayBody(t, className(t, methodClass(t, method)), 0), + &byteArrayBody(t, methodName(t, method), 0), + &byteArrayBody(t, methodSpec(t, method), 0), + shouldBeStatic ? "static" : "non-static"); + } +} + +void +checkField(Thread* t, object field, bool shouldBeStatic) +{ + if (((fieldFlags(t, field) & ACC_STATIC) == 0) == shouldBeStatic) { + throwNew(t, Machine::IncompatibleClassChangeErrorType, + "expected %s.%s to be %s", + &byteArrayBody(t, className(t, fieldClass(t, field)), 0), + &byteArrayBody(t, fieldName(t, field), 0), + shouldBeStatic ? "static" : "non-static"); + } +} + int64_t findSpecialMethodFromReference(MyThread* t, object pair) { @@ -2369,7 +2405,7 @@ findSpecialMethodFromReference(MyThread* t, object pair) target = findVirtualMethod(t, target, classSuper(t, class_)); } - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + checkMethod(t, target, false); return prepareMethodForCall(t, target); } @@ -2379,7 +2415,7 @@ findStaticMethodFromReference(MyThread* t, object pair) { object target = resolveMethod(t, pair); - assert(t, methodFlags(t, target) & ACC_STATIC); + checkMethod(t, target, true); return prepareMethodForCall(t, target); } @@ -2393,7 +2429,7 @@ findVirtualMethodFromReference(MyThread* t, object pair, object instance) target = findVirtualMethod(t, target, objectClass(t, instance)); - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + checkMethod(t, target, false); return prepareMethodForCall(t, target); } @@ -3402,8 +3438,7 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall) and (not (TailCalls and tailCall and (methodFlags(t, target) & ACC_NATIVE)))) { - Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) - ListenPromise(t->m->system, bc->zone); + Promise* p = new(bc->zone) ListenPromise(t->m->system, bc->zone); PROTECT(t, target); object pointer = makePointer(t, p); @@ -3809,6 +3844,13 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip, return true; } +Compiler::Operand* +popLongAddress(Frame* frame) +{ + return TargetBytesPerWord == 8 ? frame->popLong() : frame->c->load + (8, 8, frame->popLong(), TargetBytesPerWord); +} + bool intrinsic(MyThread* t, Frame* frame, object target) { @@ -3837,6 +3879,127 @@ intrinsic(MyThread* t, Frame* frame, object target) return true; } } + } else if (UNLIKELY(MATCH(className, "sun/misc/Unsafe"))) { + Compiler* c = frame->c; + if (MATCH(methodName(t, target), "getByte") + and MATCH(methodSpec(t, target), "(J)B")) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushInt + (c->load + (1, 1, c->memory(address, Compiler::IntegerType, 0, 0, 1), + TargetBytesPerWord)); + return true; + } else if (MATCH(methodName(t, target), "putByte") + and MATCH(methodSpec(t, target), "(JB)V")) + { + Compiler::Operand* value = frame->popInt(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (TargetBytesPerWord, value, 1, c->memory + (address, Compiler::IntegerType, 0, 0, 1)); + return true; + } else if ((MATCH(methodName(t, target), "getShort") + and MATCH(methodSpec(t, target), "(J)S")) + or (MATCH(methodName(t, target), "getChar") + and MATCH(methodSpec(t, target), "(J)C"))) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushInt + (c->load + (2, 2, c->memory(address, Compiler::IntegerType, 0, 0, 1), + TargetBytesPerWord)); + return true; + } else if ((MATCH(methodName(t, target), "putShort") + and MATCH(methodSpec(t, target), "(JS)V")) + or (MATCH(methodName(t, target), "putChar") + and MATCH(methodSpec(t, target), "(JC)V"))) + { + Compiler::Operand* value = frame->popInt(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (TargetBytesPerWord, value, 2, c->memory + (address, Compiler::IntegerType, 0, 0, 1)); + return true; + } else if ((MATCH(methodName(t, target), "getInt") + and MATCH(methodSpec(t, target), "(J)I")) + or (MATCH(methodName(t, target), "getFloat") + and MATCH(methodSpec(t, target), "(J)F"))) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushInt + (c->load + (4, 4, c->memory + (address, MATCH(methodName(t, target), "getInt") + ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1), + TargetBytesPerWord)); + return true; + } else if ((MATCH(methodName(t, target), "putInt") + and MATCH(methodSpec(t, target), "(JI)V")) + or (MATCH(methodName(t, target), "putFloat") + and MATCH(methodSpec(t, target), "(JF)V"))) + { + Compiler::Operand* value = frame->popInt(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (TargetBytesPerWord, value, 4, c->memory + (address, MATCH(methodName(t, target), "putInt") + ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1)); + return true; + } else if ((MATCH(methodName(t, target), "getLong") + and MATCH(methodSpec(t, target), "(J)J")) + or (MATCH(methodName(t, target), "getDouble") + and MATCH(methodSpec(t, target), "(J)D"))) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushLong + (c->load + (8, 8, c->memory + (address, MATCH(methodName(t, target), "getLong") + ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1), + 8)); + return true; + } else if ((MATCH(methodName(t, target), "putLong") + and MATCH(methodSpec(t, target), "(JJ)V")) + or (MATCH(methodName(t, target), "putDouble") + and MATCH(methodSpec(t, target), "(JD)V"))) + { + Compiler::Operand* value = frame->popLong(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (8, value, 8, c->memory + (address, MATCH(methodName(t, target), "putLong") + ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1)); + return true; + } else if (MATCH(methodName(t, target), "getAddress") + and MATCH(methodSpec(t, target), "(J)J")) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushLong + (c->load + (TargetBytesPerWord, TargetBytesPerWord, + c->memory(address, Compiler::AddressType, 0, 0, 1), 8)); + return true; + } else if (MATCH(methodName(t, target), "putAddress") + and MATCH(methodSpec(t, target), "(JJ)V")) + { + Compiler::Operand* value = frame->popLong(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (8, value, TargetBytesPerWord, c->memory + (address, Compiler::AddressType, 0, 0, 1)); + return true; + } } return false; } @@ -4167,6 +4330,10 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), target); + + if (ip == codeLength(t, code)) { + c->trap(); + } } return; case bipush: @@ -4441,7 +4608,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* table; if (instruction == getstatic) { - assert(t, fieldFlags(t, field) & ACC_STATIC); + checkField(t, field, true); PROTECT(t, field); @@ -4461,7 +4628,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, table = frame->append(classStaticTable(t, fieldClass(t, field))); } else { - assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + checkField(t, field, false); table = frame->popObject(); @@ -4906,7 +5073,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, int returnCode; bool tailCall; if (LIKELY(target)) { - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + checkMethod(t, target, false); argument = target; thunk = findInterfaceMethodFromInstanceThunk; @@ -4965,7 +5132,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, target = findVirtualMethod(t, target, classSuper(t, class_)); } - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + checkMethod(t, target, false); bool tailCall = isTailCall(t, code, ip, context->method, target); @@ -4995,7 +5162,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object target = resolveMethod(t, context->method, index - 1, false); if (LIKELY(target)) { - assert(t, methodFlags(t, target) & ACC_STATIC); + checkMethod(t, target, true); if (not intrinsic(t, frame, target)) { bool tailCall = isTailCall(t, code, ip, context->method, target); @@ -5021,44 +5188,46 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object target = resolveMethod(t, context->method, index - 1, false); if (LIKELY(target)) { - assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + checkMethod(t, target, false); + + if (not intrinsic(t, frame, target)) { + bool tailCall = isTailCall(t, code, ip, context->method, target); - bool tailCall = isTailCall(t, code, ip, context->method, target); + if (LIKELY(methodVirtual(t, target))) { + unsigned parameterFootprint = methodParameterFootprint(t, target); - if (LIKELY(methodVirtual(t, target))) { - unsigned parameterFootprint = methodParameterFootprint(t, target); + unsigned offset = TargetClassVtable + + (methodOffset(t, target) * TargetBytesPerWord); - unsigned offset = TargetClassVtable - + (methodOffset(t, target) * TargetBytesPerWord); + Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); - Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); + unsigned rSize = resultSize(t, methodReturnCode(t, target)); - unsigned rSize = resultSize(t, methodReturnCode(t, target)); + Compiler::Operand* result = c->stackCall + (c->memory + (c->and_ + (TargetBytesPerWord, c->constant + (TargetPointerMask, Compiler::IntegerType), + c->memory(instance, Compiler::ObjectType, 0, 0, 1)), + Compiler::ObjectType, offset, 0, 1), + tailCall ? Compiler::TailJump : 0, + frame->trace(0, 0), + rSize, + operandTypeForFieldCode(t, methodReturnCode(t, target)), + parameterFootprint); - Compiler::Operand* result = c->stackCall - (c->memory - (c->and_ - (TargetBytesPerWord, c->constant - (TargetPointerMask, Compiler::IntegerType), - c->memory(instance, Compiler::ObjectType, 0, 0, 1)), - Compiler::ObjectType, offset, 0, 1), - tailCall ? Compiler::TailJump : 0, - frame->trace(0, 0), - rSize, - operandTypeForFieldCode(t, methodReturnCode(t, target)), - parameterFootprint); + frame->pop(parameterFootprint); - frame->pop(parameterFootprint); + if (rSize) { + pushReturnValue(t, frame, methodReturnCode(t, target), result); + } + } else { + // OpenJDK generates invokevirtual calls to private methods + // (e.g. readObject and writeObject for serialization), so + // we must handle such cases here. - if (rSize) { - pushReturnValue(t, frame, methodReturnCode(t, target), result); + compileDirectInvoke(t, frame, target, tailCall); } - } else { - // OpenJDK generates invokevirtual calls to private methods - // (e.g. readObject and writeObject for serialization), so - // we must handle such cases here. - - compileDirectInvoke(t, frame, target, tailCall); } } else { PROTECT(t, reference); @@ -5633,7 +5802,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object staticTable = 0; if (instruction == putstatic) { - assert(t, fieldFlags(t, field) & ACC_STATIC); + checkField(t, field, true); if (fieldClass(t, field) != methodClass(t, context->method) and classNeedsInit(t, fieldClass(t, field))) @@ -5653,7 +5822,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, staticTable = classStaticTable(t, fieldClass(t, field)); } else { - assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + checkField(t, field, false); if (inTryBlock(t, code, ip - 3)) { c->saveLocals(); @@ -6019,29 +6188,15 @@ FILE* compileLog = 0; void logCompile(MyThread* t, const void* code, unsigned size, const char* class_, - const char* name, const char* spec) -{ - static bool open = false; - if (not open) { - open = true; - const char* path = findProperty(t, "avian.jit.log"); - if (path) { - compileLog = vm::fopen(path, "wb"); - } else if (DebugCompile) { - compileLog = stderr; - } - } - - if (compileLog) { - fprintf(compileLog, "%p %p %s.%s%s\n", - code, static_cast(code) + size, - class_, name, spec); - } -} + const char* name, const char* spec); int resolveIpForwards(Context* context, int start, int end) { + if (start < 0) { + start = 0; + } + while (start < end and context->visitTable[start] == 0) { ++ start; } @@ -6056,6 +6211,13 @@ resolveIpForwards(Context* context, int start, int end) int resolveIpBackwards(Context* context, int start, int end) { + Thread* t = context->thread; + if (start >= static_cast + (codeLength(t, methodCode(t, context->method)))) + { + start = codeLength(t, methodCode(t, context->method)) - 1; + } + while (start >= end and context->visitTable[start] == 0) { -- start; } @@ -6075,8 +6237,10 @@ truncateIntArray(Thread* t, object array, unsigned length) PROTECT(t, array); object newArray = makeIntArray(t, length); - memcpy(&intArrayBody(t, newArray, 0), &intArrayBody(t, array, 0), - length * 4); + if (length) { + memcpy(&intArrayBody(t, newArray, 0), &intArrayBody(t, array, 0), + length * 4); + } return newArray; } @@ -6089,8 +6253,10 @@ truncateArray(Thread* t, object array, unsigned length) PROTECT(t, array); object newArray = makeArray(t, length); - memcpy(&arrayBody(t, newArray, 0), &arrayBody(t, array, 0), - length * BytesPerWord); + if (length) { + memcpy(&arrayBody(t, newArray, 0), &arrayBody(t, array, 0), + length * BytesPerWord); + } return newArray; } @@ -6103,9 +6269,11 @@ truncateLineNumberTable(Thread* t, object table, unsigned length) PROTECT(t, table); object newTable = makeLineNumberTable(t, length); - memcpy(&lineNumberTableBody(t, newTable, 0), - &lineNumberTableBody(t, table, 0), - length * sizeof(uint64_t)); + if (length) { + memcpy(&lineNumberTableBody(t, newTable, 0), + &lineNumberTableBody(t, table, 0), + length * sizeof(uint64_t)); + } return newTable; } @@ -6139,11 +6307,16 @@ translateExceptionHandlerTable(MyThread* t, Context* context, intptr_t start) exceptionHandlerEnd(oldHandler)); if (LIKELY(handlerStart >= 0)) { + assert(t, handlerStart < static_cast + (codeLength(t, methodCode(t, context->method)))); + int handlerEnd = resolveIpBackwards (context, exceptionHandlerEnd(oldHandler), exceptionHandlerStart(oldHandler)); assert(t, handlerEnd >= 0); + assert(t, handlerEnd < static_cast + (codeLength(t, methodCode(t, context->method)))); intArrayBody(t, newIndex, ni * 3) = c->machineIp(handlerStart)->value() - start; @@ -6489,7 +6662,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, } if (path == 0) { - path = new (context->zone.allocate(sizeof(SubroutinePath))) + path = new(&context->zone) SubroutinePath(call, subroutinePath, makeRootTable(t, &(context->zone), context->method)); } @@ -6871,15 +7044,14 @@ finish(MyThread* t, FixedAllocator* allocator, Context* context) // we must acquire the class lock here at the latest unsigned codeSize = c->resolve - (allocator->base + allocator->offset + TargetBytesPerWord); + (allocator->base + allocator->offset); unsigned total = pad(codeSize, TargetBytesPerWord) - + pad(c->poolSize(), TargetBytesPerWord) + TargetBytesPerWord; + + pad(c->poolSize(), TargetBytesPerWord); target_uintptr_t* code = static_cast (allocator->allocate(total, TargetBytesPerWord)); - code[0] = codeSize; - uint8_t* start = reinterpret_cast(code + 1); + uint8_t* start = reinterpret_cast(code); context->executableAllocator = allocator; context->executableStart = code; @@ -6915,8 +7087,7 @@ finish(MyThread* t, FixedAllocator* allocator, Context* context) p != bc->addressSentinal; p = p->next) { - p->basis = new (bc->zone->allocate(sizeof(ResolvedPromise))) - ResolvedPromise(p->basis->value()); + p->basis = new(bc->zone) ResolvedPromise(p->basis->value()); } } @@ -6932,7 +7103,7 @@ finish(MyThread* t, FixedAllocator* allocator, Context* context) code = makeCode (t, 0, newExceptionHandlerTable, newLineNumberTable, - reinterpret_cast(start), codeMaxStack(t, code), + reinterpret_cast(start), codeSize, codeMaxStack(t, code), codeMaxLocals(t, code), 0); set(t, context->method, MethodCode, code); @@ -7636,6 +7807,7 @@ visitStack(MyThread* t, Heap::Visitor* v) MyThread::CallTrace* trace = t->trace; object targetMethod = (trace ? trace->targetMethod : 0); object target = targetMethod; + bool mostRecent = true; while (stack) { if (targetMethod) { @@ -7648,7 +7820,7 @@ visitStack(MyThread* t, Heap::Visitor* v) PROTECT(t, method); void* nextIp = ip; - nextFrame(t, &nextIp, &stack, method, target); + nextFrame(t, &nextIp, &stack, method, target, mostRecent); visitStackAndLocals(t, v, stack, method, ip); @@ -7669,6 +7841,8 @@ visitStack(MyThread* t, Heap::Visitor* v) } else { break; } + + mostRecent = false; } } @@ -8037,10 +8211,17 @@ class ArgumentList { break; case 'J': - case 'D': addLong(va_arg(arguments, uint64_t)); break; + case 'D': + addLong(doubleToBits(va_arg(arguments, double))); + break; + + case 'F': + addInt(floatToBits(va_arg(arguments, double))); + break; + default: addInt(va_arg(arguments, uint32_t)); break; @@ -8150,7 +8331,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments) uintptr_t stackLimit = t->stackLimit; uintptr_t stackPosition = reinterpret_cast(&t); if (stackLimit == 0) { - t->stackLimit = stackPosition - StackSizeInBytes; + t->stackLimit = stackPosition - t->m->stackSizeInBytes; } else if (stackPosition < stackLimit) { throwNew(t, Machine::StackOverflowErrorType); } @@ -8295,6 +8476,24 @@ processor(MyThread* t); void compileThunks(MyThread* t, FixedAllocator* allocator); +class CompilationHandlerList { +public: + CompilationHandlerList(CompilationHandlerList* next, Processor::CompilationHandler* handler): + next(next), + handler(handler) {} + + void dispose(Allocator* allocator) { + if(this) { + next->dispose(allocator); + handler->dispose(); + allocator->free(this, sizeof(*this)); + } + } + + CompilationHandlerList* next; + Processor::CompilationHandler* handler; +}; + class MyProcessor: public Processor { public: class Thunk { @@ -8338,7 +8537,8 @@ class MyProcessor: public Processor { FixedSizeOfArithmeticException), codeAllocator(s, 0, 0), callTableSize(0), - useNativeFeatures(useNativeFeatures) + useNativeFeatures(useNativeFeatures), + compilationHandlers(0) { thunkTable[compileMethodIndex] = voidPointer(local::compileMethod); thunkTable[compileVirtualMethodIndex] = voidPointer(compileVirtualMethod); @@ -8525,7 +8725,7 @@ class MyProcessor: public Processor { } Reference* r = new (t->m->heap->allocate(sizeof(Reference))) - Reference(o, &(t->reference)); + Reference(o, &(t->reference), false); acquire(t, r); @@ -8644,6 +8844,7 @@ class MyProcessor: public Processor { t->arch->release(); t->m->heap->free(t, sizeof(*t)); + } virtual void dispose() { @@ -8651,6 +8852,8 @@ class MyProcessor: public Processor { s->freeExecutable(codeAllocator.base, codeAllocator.capacity); } + compilationHandlers->dispose(allocator); + s->handleSegFault(0); allocator->free(this, sizeof(*this)); @@ -8674,7 +8877,7 @@ class MyProcessor: public Processor { // we caught the thread in Java code - use the register values c.ip = ip; c.stack = stack; - c.javaStackLimit = stack; + c.methodIsMostRecent = true; } else if (target->transition) { // we caught the thread in native code while in the middle // of updating the context fields (MyThread::stack, etc.) @@ -8747,6 +8950,10 @@ class MyProcessor: public Processor { codeAllocator.capacity = capacity; } + virtual void addCompilationHandler(CompilationHandler* handler) { + compilationHandlers = new(allocator->allocate(sizeof(CompilationHandlerList))) CompilationHandlerList(compilationHandlers, handler); + } + virtual void compileMethod(Thread* vmt, Zone* zone, object* constants, object* calls, DelayedPromise** addresses, object method, OffsetResolver* resolver) @@ -8902,8 +9109,56 @@ class MyProcessor: public Processor { unsigned callTableSize; bool useNativeFeatures; void* thunkTable[dummyIndex + 1]; + CompilationHandlerList* compilationHandlers; }; +const char* +stringOrNull(const char* str) { + if(str) { + return str; + } else { + return "(null)"; + } +} + +size_t +stringOrNullSize(const char* str) { + return strlen(stringOrNull(str)); +} + +void +logCompile(MyThread* t, const void* code, unsigned size, const char* class_, + const char* name, const char* spec) +{ + static bool open = false; + if (not open) { + open = true; + const char* path = findProperty(t, "avian.jit.log"); + if (path) { + compileLog = vm::fopen(path, "wb"); + } else if (DebugCompile) { + compileLog = stderr; + } + } + + if (compileLog) { + fprintf(compileLog, "%p %p %s.%s%s\n", + code, static_cast(code) + size, + class_, name, spec); + } + + size_t nameLength = stringOrNullSize(class_) + stringOrNullSize(name) + stringOrNullSize(spec) + 2; + + THREAD_RUNTIME_ARRAY(t, char, completeName, nameLength); + + sprintf(RUNTIME_ARRAY_BODY(completeName), "%s.%s%s", stringOrNull(class_), stringOrNull(name), stringOrNull(spec)); + + MyProcessor* p = static_cast(t->m->processor); + for(CompilationHandlerList* h = p->compilationHandlers; h; h = h->next) { + h->handler->compiled(code, 0, 0, RUNTIME_ARRAY_BODY(completeName)); + } +} + void* compileMethod2(MyThread* t, void* ip) { @@ -9303,8 +9558,7 @@ fixupMethods(Thread* t, object map, BootImage* image UNUSED, uint8_t* code) logCompile (static_cast(t), reinterpret_cast(methodCompiled(t, method)), - reinterpret_cast - (methodCompiled(t, method))[-1], + methodCompiledSize(t, method), reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, method)), 0)), reinterpret_cast @@ -9495,8 +9749,7 @@ compileCall(MyThread* t, Context* c, ThunkIndex index, bool call = true) (call ? Call : Jump, TargetBytesPerWord, RegisterOperand, &scratch); } else { Assembler::Constant proc - (new (c->zone.allocate(sizeof(ResolvedPromise))) - ResolvedPromise(reinterpret_cast(t->thunkTable[index]))); + (new(&c->zone) ResolvedPromise(reinterpret_cast(t->thunkTable[index]))); a->apply (call ? LongCall : LongJump, TargetBytesPerWord, ConstantOperand, &proc); @@ -9771,7 +10024,15 @@ compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) a->setDestination(start); a->write(); - logCompile(t, start, *size, 0, "virtualThunk", 0); + const char* const virtualThunkBaseName = "virtualThunk"; + const size_t virtualThunkBaseNameLength = strlen(virtualThunkBaseName); + const size_t maxIntStringLength = 10; + + THREAD_RUNTIME_ARRAY(t, char, virtualThunkName, virtualThunkBaseNameLength + maxIntStringLength); + + sprintf(RUNTIME_ARRAY_BODY(virtualThunkName), "%s%d", virtualThunkBaseName, index); + + logCompile(t, start, *size, 0, virtualThunkName, 0); return reinterpret_cast(start); } diff --git a/src/compiler.cpp b/src/compiler.cpp index 737f723da4..56a2709e42 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -576,7 +576,7 @@ count(Cell* c) Cell* cons(Context* c, void* value, Cell* next) { - return new (c->zone->allocate(sizeof(Cell))) Cell(next, value); + return new (c->zone) Cell(next, value); } Cell* @@ -648,7 +648,7 @@ Link* link(Context* c, Event* predecessor, Link* nextPredecessor, Event* successor, Link* nextSuccessor, ForkState* forkState) { - return new (c->zone->allocate(sizeof(Link))) Link + return new(c->zone) Link (predecessor, nextPredecessor, successor, nextSuccessor, forkState); } @@ -1602,15 +1602,13 @@ constantSite(Context* c, Promise* value); ShiftMaskPromise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) { - return new (c->zone->allocate(sizeof(ShiftMaskPromise))) - ShiftMaskPromise(base, shift, mask); + return new(c->zone) ShiftMaskPromise(base, shift, mask); } CombinedPromise* combinedPromise(Context* c, Promise* low, Promise* high) { - return new (c->zone->allocate(sizeof(CombinedPromise))) - CombinedPromise(low, high); + return new(c->zone) CombinedPromise(low, high); } class ConstantSite: public Site { @@ -1686,14 +1684,13 @@ class ConstantSite: public Site { ConstantSite* constantSite(Context* c, Promise* value) { - return new (c->zone->allocate(sizeof(ConstantSite))) ConstantSite(value); + return new(c->zone) ConstantSite(value); } ResolvedPromise* resolved(Context* c, int64_t value) { - return new (c->zone->allocate(sizeof(ResolvedPromise))) - ResolvedPromise(value); + return new(c->zone) ResolvedPromise(value); } ConstantSite* @@ -1776,7 +1773,7 @@ class AddressSite: public Site { AddressSite* addressSite(Context* c, Promise* address) { - return new (c->zone->allocate(sizeof(AddressSite))) AddressSite(address); + return new(c->zone) AddressSite(address); } RegisterSite* @@ -1978,15 +1975,13 @@ registerSite(Context* c, int number) assert(c, (1 << number) & (c->arch->generalRegisterMask() | c->arch->floatRegisterMask())); - return new (c->zone->allocate(sizeof(RegisterSite))) - RegisterSite(1 << number, number); + return new(c->zone) RegisterSite(1 << number, number); } RegisterSite* freeRegisterSite(Context* c, uint32_t mask) { - return new (c->zone->allocate(sizeof(RegisterSite))) - RegisterSite(mask, NoRegister); + return new(c->zone) RegisterSite(mask, NoRegister); } MemorySite* @@ -2219,8 +2214,7 @@ class MemorySite: public Site { MemorySite* memorySite(Context* c, int base, int offset, int index, unsigned scale) { - return new (c->zone->allocate(sizeof(MemorySite))) - MemorySite(base, offset, index, scale); + return new(c->zone) MemorySite(base, offset, index, scale); } MemorySite* @@ -2341,8 +2335,7 @@ read(Context* c, const SiteMask& mask, Value* successor = 0) { assert(c, (mask.typeMask != 1 << MemoryOperand) or mask.frameIndex >= 0); - return new (c->zone->allocate(sizeof(SingleRead))) - SingleRead(mask, successor); + return new(c->zone) SingleRead(mask, successor); } bool @@ -2762,7 +2755,7 @@ class MultiRead: public Read { MultiRead* multiRead(Context* c) { - return new (c->zone->allocate(sizeof(MultiRead))) MultiRead; + return new(c->zone) MultiRead; } class StubRead: public Read { @@ -2811,7 +2804,7 @@ class StubRead: public Read { StubRead* stubRead(Context* c) { - return new (c->zone->allocate(sizeof(StubRead))) StubRead; + return new(c->zone) StubRead; } Site* @@ -3121,15 +3114,13 @@ clean(Context* c, Event* e, Stack* stack, Local* locals, Read* reads, CodePromise* codePromise(Context* c, Event* e) { - return e->promises = new (c->zone->allocate(sizeof(CodePromise))) - CodePromise(c, e->promises); + return e->promises = new(c->zone) CodePromise(c, e->promises); } CodePromise* codePromise(Context* c, Promise* offset) { - return new (c->zone->allocate(sizeof(CodePromise))) - CodePromise(c, offset); + return new (c->zone) CodePromise(c, offset); } void @@ -3467,7 +3458,7 @@ appendCall(Context* c, Value* address, unsigned flags, Stack* argumentStack, unsigned argumentCount, unsigned stackArgumentFootprint) { - append(c, new (c->zone->allocate(sizeof(CallEvent))) + append(c, new(c->zone) CallEvent(c, address, flags, traceHandler, result, resultSize, argumentStack, argumentCount, stackArgumentFootprint)); @@ -3515,8 +3506,7 @@ class ReturnEvent: public Event { void appendReturn(Context* c, unsigned size, Value* value) { - append(c, new (c->zone->allocate(sizeof(ReturnEvent))) - ReturnEvent(c, size, value)); + append(c, new(c->zone) ReturnEvent(c, size, value)); } void @@ -3714,7 +3704,7 @@ pickSiteOrMove(Context* c, Value* src, Value* dst, Site* nextWord, Value* value(Context* c, ValueType type, Site* site = 0, Site* target = 0) { - return new (c->zone->allocate(sizeof(Value))) Value(site, target, type); + return new(c->zone) Value(site, target, type); } void @@ -3914,7 +3904,7 @@ appendMove(Context* c, BinaryOperation type, unsigned srcSize, assert(c, not thunk); - append(c, new (c->zone->allocate(sizeof(MoveEvent))) + append(c, new(c->zone) MoveEvent (c, type, srcSize, srcSelectSize, src, dstSize, dst, SiteMask(srcTypeMask, srcRegisterMask, AnyFrameIndex), @@ -4173,7 +4163,7 @@ snapshot(Context* c, Value* value, Snapshot* next) value, value->buddy, buffer); } - return new (c->zone->allocate(sizeof(Snapshot))) Snapshot(c, value, next); + return new(c->zone) Snapshot(c, value, next); } Snapshot* @@ -4189,8 +4179,7 @@ makeSnapshots(Context* c, Value* value, Snapshot* next) Stack* stack(Context* c, Value* value, Stack* next) { - return new (c->zone->allocate(sizeof(Stack))) - Stack(next ? next->index + 1 : 0, value, next); + return new(c->zone) Stack(next ? next->index + 1 : 0, value, next); } Value* @@ -4450,7 +4439,7 @@ appendCombine(Context* c, TernaryOperation type, resultSize, argumentStack, stackSize, 0); } else { append - (c, new (c->zone->allocate(sizeof(CombineEvent))) + (c, new(c->zone) CombineEvent (c, type, firstSize, first, @@ -4568,7 +4557,7 @@ appendTranslate(Context* c, BinaryOperation type, unsigned firstSize, 0, 0, result, resultSize, argumentStack, ceiling(firstSize, TargetBytesPerWord), 0); } else { - append(c, new (c->zone->allocate(sizeof(TranslateEvent))) + append(c, new(c->zone) TranslateEvent (c, type, firstSize, first, resultSize, result, SiteMask(firstTypeMask, firstRegisterMask, AnyFrameIndex), @@ -4576,14 +4565,14 @@ appendTranslate(Context* c, BinaryOperation type, unsigned firstSize, } } -class BarrierEvent: public Event { +class OperationEvent: public Event { public: - BarrierEvent(Context* c, Operation op): + OperationEvent(Context* c, Operation op): Event(c), op(op) { } virtual const char* name() { - return "BarrierEvent"; + return "OperationEvent"; } virtual void compile(Context* c) { @@ -4594,9 +4583,10 @@ class BarrierEvent: public Event { }; void -appendBarrier(Context* c, Operation op) +appendOperation(Context* c, Operation op) { - append(c, new (c->zone->allocate(sizeof(BarrierEvent))) BarrierEvent(c, op)); + append + (c, new(c->zone) OperationEvent(c, op)); } class MemoryEvent: public Event { @@ -4676,7 +4666,7 @@ void appendMemory(Context* c, Value* base, int displacement, Value* index, unsigned scale, Value* result) { - append(c, new (c->zone->allocate(sizeof(MemoryEvent))) + append(c, new(c->zone) MemoryEvent(c, base, displacement, index, scale, result)); } @@ -4907,7 +4897,7 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first, result, address); } else { append - (c, new (c->zone->allocate(sizeof(BranchEvent))) + (c, new(c->zone) BranchEvent (c, type, size, first, second, address, SiteMask(firstTypeMask, firstRegisterMask, AnyFrameIndex), @@ -4971,8 +4961,7 @@ void appendJump(Context* c, UnaryOperation type, Value* address, bool exit = false, bool cleanLocals = false) { - append(c, new (c->zone->allocate(sizeof(JumpEvent))) - JumpEvent(c, type, address, exit, cleanLocals)); + append(c, new(c->zone) JumpEvent(c, type, address, exit, cleanLocals)); } class BoundsCheckEvent: public Event { @@ -5050,8 +5039,7 @@ void appendBoundsCheck(Context* c, Value* object, unsigned lengthOffset, Value* index, intptr_t handler) { - append(c, new (c->zone->allocate(sizeof(BoundsCheckEvent))) - BoundsCheckEvent(c, object, lengthOffset, index, handler)); + append(c, new(c->zone) BoundsCheckEvent(c, object, lengthOffset, index, handler)); } class FrameSiteEvent: public Event { @@ -5077,8 +5065,7 @@ class FrameSiteEvent: public Event { void appendFrameSite(Context* c, Value* value, int index) { - append(c, new (c->zone->allocate(sizeof(FrameSiteEvent))) - FrameSiteEvent(c, value, index)); + append(c, new(c->zone) FrameSiteEvent(c, value, index)); } unsigned @@ -5156,8 +5143,7 @@ class BuddyEvent: public Event { void appendBuddy(Context* c, Value* original, Value* buddy) { - append(c, new (c->zone->allocate(sizeof(BuddyEvent))) - BuddyEvent(c, original, buddy)); + append(c, new(c->zone) BuddyEvent(c, original, buddy)); } class SaveLocalsEvent: public Event { @@ -5182,8 +5168,7 @@ class SaveLocalsEvent: public Event { void appendSaveLocals(Context* c) { - append(c, new (c->zone->allocate(sizeof(SaveLocalsEvent))) - SaveLocalsEvent(c)); + append(c, new(c->zone) SaveLocalsEvent(c)); } class DummyEvent: public Event { @@ -5209,7 +5194,7 @@ appendDummy(Context* c) c->stack = i->stack; c->locals = i->locals; - append(c, new (c->zone->allocate(sizeof(DummyEvent))) DummyEvent(c)); + append(c, new(c->zone) DummyEvent(c)); c->stack = stack; c->locals = locals; @@ -5745,7 +5730,7 @@ class Block { Block* block(Context* c, Event* head) { - return new (c->zone->allocate(sizeof(Block))) Block(head); + return new(c->zone) Block(head); } void @@ -6056,8 +6041,7 @@ class MyCompiler: public Compiler { } virtual Subroutine* startSubroutine() { - return c.subroutine = new (c.zone->allocate(sizeof(MySubroutine))) - MySubroutine; + return c.subroutine = new(c.zone) MySubroutine; } virtual void returnFromSubroutine(Subroutine* subroutine, Operand* address) { @@ -6198,7 +6182,7 @@ class MyCompiler: public Compiler { } virtual Promise* machineIp(unsigned logicalIp) { - return new (c.zone->allocate(sizeof(IpPromise))) IpPromise(&c, logicalIp); + return new(c.zone) IpPromise(&c, logicalIp); } virtual Promise* poolAppend(intptr_t value) { @@ -6206,12 +6190,9 @@ class MyCompiler: public Compiler { } virtual Promise* poolAppendPromise(Promise* value) { - Promise* p = new (c.zone->allocate(sizeof(PoolPromise))) - PoolPromise(&c, c.constantCount); + Promise* p = new(c.zone) PoolPromise(&c, c.constantCount); - ConstantPoolNode* constant - = new (c.zone->allocate(sizeof(ConstantPoolNode))) - ConstantPoolNode(value); + ConstantPoolNode* constant = new (c.zone) ConstantPoolNode(value); if (c.firstConstant) { c.lastConstant->next = constant; @@ -6902,16 +6883,20 @@ class MyCompiler: public Compiler { return result; } + virtual void trap() { + appendOperation(&c, Trap); + } + virtual void loadBarrier() { - appendBarrier(&c, LoadBarrier); + appendOperation(&c, LoadBarrier); } virtual void storeStoreBarrier() { - appendBarrier(&c, StoreStoreBarrier); + appendOperation(&c, StoreStoreBarrier); } virtual void storeLoadBarrier() { - appendBarrier(&c, StoreLoadBarrier); + appendOperation(&c, StoreLoadBarrier); } virtual void compile(uintptr_t stackOverflowHandler, @@ -6992,8 +6977,7 @@ Compiler* makeCompiler(System* system, Assembler* assembler, Zone* zone, Compiler::Client* client) { - return new (zone->allocate(sizeof(local::MyCompiler))) - local::MyCompiler(system, assembler, zone, client); + return new(zone) local::MyCompiler(system, assembler, zone, client); } } // namespace vm diff --git a/src/compiler.h b/src/compiler.h index 85deed9473..e66c69a67c 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -184,6 +184,8 @@ class Compiler { virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) = 0; virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) = 0; + virtual void trap() = 0; + virtual void loadBarrier() = 0; virtual void storeStoreBarrier() = 0; virtual void storeLoadBarrier() = 0; diff --git a/src/environment.h b/src/environment.h new file mode 100644 index 0000000000..045eb2642d --- /dev/null +++ b/src/environment.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2008-2012, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#ifndef AVIAN_ENVIRONMENT_H +#define AVIAN_ENVIRONMENT_H + +#ifndef AVIAN_TARGET_PLATFORM +#error build system should have defined AVIAN_TARGET_PLATFORM +#endif + +#ifndef AVIAN_TARGET_ARCH +#error build system should have defined AVIAN_TARGET_ARCH +#endif + +#define AVIAN_PLATFORM_UNKNOWN 0 +#define AVIAN_PLATFORM_LINUX 1 +#define AVIAN_PLATFORM_WINDOWS 2 +#define AVIAN_PLATFORM_DARWIN 3 + +#define AVIAN_ARCH_UNKNOWN 0 +#define AVIAN_ARCH_X86 (1 << 8) +#define AVIAN_ARCH_X86_64 (2 << 8) +#define AVIAN_ARCH_ARM (3 << 8) +#define AVIAN_ARCH_POWERPC (4 << 8) + +#endif \ No newline at end of file diff --git a/src/finder.cpp b/src/finder.cpp index f53738e9f4..1a08e65008 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -448,6 +448,7 @@ class JarElement: public Element { unsigned jarLength): s(s), allocator(allocator), + originalName(0), name(0), urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0), sourceUrl_(name ? append(allocator, "file:", name) : 0), @@ -517,12 +518,14 @@ class JarElement: public Element { } virtual void dispose(unsigned size) { - if (originalName != name) { - allocator->free(originalName, strlen(originalName) + 1); + if (name) { + if (originalName != name) { + allocator->free(originalName, strlen(originalName) + 1); + } + allocator->free(name, strlen(name) + 1); + allocator->free(urlPrefix_, strlen(urlPrefix_) + 1); + allocator->free(sourceUrl_, strlen(sourceUrl_) + 1); } - allocator->free(name, strlen(name) + 1); - allocator->free(urlPrefix_, strlen(urlPrefix_) + 1); - allocator->free(sourceUrl_, strlen(sourceUrl_) + 1); if (index) { index->dispose(); } @@ -906,7 +909,9 @@ class MyFinder: public Finder { e = e->next; t->dispose(); } - allocator->free(pathString, strlen(pathString) + 1); + if (pathString) { + allocator->free(pathString, strlen(pathString) + 1); + } allocator->free(this, sizeof(*this)); } diff --git a/src/finder.h b/src/finder.h index 55aa9e85ee..f4582417fa 100644 --- a/src/finder.h +++ b/src/finder.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -173,7 +173,7 @@ class Finder { virtual void dispose() = 0; }; -Finder* +JNIEXPORT Finder* makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary); Finder* diff --git a/src/heap.h b/src/heap.h index 838d88786c..875b4a5cbc 100644 --- a/src/heap.h +++ b/src/heap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/interpret.cpp b/src/interpret.cpp index 6e04cd4942..6a66c1778b 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -40,7 +40,7 @@ class Thread: public vm::Thread { unsigned sp; int frame; object code; - uintptr_t stack[StackSizeInWords]; + uintptr_t stack[0]; }; inline void @@ -50,7 +50,7 @@ pushObject(Thread* t, object o) fprintf(stderr, "push object %p at %d\n", o, t->sp); } - assert(t, t->sp + 1 < StackSizeInWords / 2); + assert(t, t->sp + 1 < stackSizeInWords(t) / 2); t->stack[(t->sp * 2) ] = ObjectTag; t->stack[(t->sp * 2) + 1] = reinterpret_cast(o); ++ t->sp; @@ -63,7 +63,7 @@ pushInt(Thread* t, uint32_t v) fprintf(stderr, "push int %d at %d\n", v, t->sp); } - assert(t, t->sp + 1 < StackSizeInWords / 2); + assert(t, t->sp + 1 < stackSizeInWords(t) / 2); t->stack[(t->sp * 2) ] = IntTag; t->stack[(t->sp * 2) + 1] = v; ++ t->sp; @@ -156,7 +156,7 @@ peekObject(Thread* t, unsigned index) index); } - assert(t, index < StackSizeInWords / 2); + assert(t, index < stackSizeInWords(t) / 2); assert(t, t->stack[index * 2] == ObjectTag); return *reinterpret_cast(t->stack + (index * 2) + 1); } @@ -170,7 +170,7 @@ peekInt(Thread* t, unsigned index) index); } - assert(t, index < StackSizeInWords / 2); + assert(t, index < stackSizeInWords(t) / 2); assert(t, t->stack[index * 2] == IntTag); return t->stack[(index * 2) + 1]; } @@ -226,7 +226,7 @@ inline object* pushReference(Thread* t, object o) { if (o) { - expect(t, t->sp + 1 < StackSizeInWords / 2); + expect(t, t->sp + 1 < stackSizeInWords(t) / 2); pushObject(t, o); return reinterpret_cast(t->stack + ((t->sp - 1) * 2) + 1); } else { @@ -405,7 +405,7 @@ checkStack(Thread* t, object method) + codeMaxLocals(t, methodCode(t, method)) + FrameFootprint + codeMaxStack(t, methodCode(t, method)) - > StackSizeInWords / 2)) + > stackSizeInWords(t) / 2)) { throwNew(t, Machine::StackOverflowErrorType); } @@ -758,6 +758,8 @@ interpret3(Thread* t, const int base) object& exception = t->exception; uintptr_t* stack = t->stack; + code = methodCode(t, frameMethod(t, frame)); + if (UNLIKELY(exception)) { goto throw_; } @@ -2877,7 +2879,7 @@ class MyProcessor: public Processor { virtual vm::Thread* makeThread(Machine* m, object javaThread, vm::Thread* parent) { - Thread* t = new (m->heap->allocate(sizeof(Thread))) + Thread* t = new (m->heap->allocate(sizeof(Thread) + m->stackSizeInBytes)) Thread(m, javaThread, parent); t->init(); return t; @@ -2994,7 +2996,7 @@ class MyProcessor: public Processor { assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 - > StackSizeInWords / 2)) + > stackSizeInWords(t) / 2)) { throwNew(t, Machine::StackOverflowErrorType); } @@ -3018,7 +3020,7 @@ class MyProcessor: public Processor { assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 - > StackSizeInWords / 2)) + > stackSizeInWords(t) / 2)) { throwNew(t, Machine::StackOverflowErrorType); } @@ -3041,7 +3043,7 @@ class MyProcessor: public Processor { or t->state == Thread::ExclusiveState); if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false) - > StackSizeInWords / 2)) + > stackSizeInWords(t) / 2)) { throwNew(t, Machine::StackOverflowErrorType); } @@ -3065,6 +3067,10 @@ class MyProcessor: public Processor { abort(s); } + virtual void addCompilationHandler(CompilationHandler* handler) { + abort(s); + } + virtual void compileMethod(vm::Thread*, Zone*, object*, object*, DelayedPromise**, object, OffsetResolver*) { diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 34f82efc65..ffc0937789 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2157,7 +2157,7 @@ SetStaticDoubleField(Thread* t, jobject c, jfieldID field, jdouble v) } jobject JNICALL -NewGlobalRef(Thread* t, jobject o) +newGlobalRef(Thread* t, jobject o, bool weak) { ENTER(t, Thread::ActiveState); @@ -2165,7 +2165,7 @@ NewGlobalRef(Thread* t, jobject o) if (o) { for (Reference* r = t->m->jniReferences; r; r = r->next) { - if (r->target == *o) { + if (r->target == *o and r->weak == weak) { acquire(t, r); return &(r->target); @@ -2173,7 +2173,7 @@ NewGlobalRef(Thread* t, jobject o) } Reference* r = new (t->m->heap->allocate(sizeof(Reference))) - Reference(*o, &(t->m->jniReferences)); + Reference(*o, &(t->m->jniReferences), weak); acquire(t, r); @@ -2183,6 +2183,12 @@ NewGlobalRef(Thread* t, jobject o) } } +jobject JNICALL +NewGlobalRef(Thread* t, jobject o) +{ + return newGlobalRef(t, o, false); +} + void JNICALL DeleteGlobalRef(Thread* t, jobject r) { @@ -2195,6 +2201,18 @@ DeleteGlobalRef(Thread* t, jobject r) } } +jobject JNICALL +NewWeakGlobalRef(Thread* t, jobject o) +{ + return newGlobalRef(t, o, true); +} + +void JNICALL +DeleteWeakGlobalRef(Thread* t, jobject r) +{ + DeleteGlobalRef(t, r); +} + jint JNICALL EnsureLocalCapacity(Thread*, jint) { @@ -3166,8 +3184,9 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->SetStaticFloatField = local::SetStaticFloatField; envTable->SetStaticDoubleField = local::SetStaticDoubleField; envTable->NewGlobalRef = local::NewGlobalRef; - envTable->NewWeakGlobalRef = local::NewGlobalRef; + envTable->NewWeakGlobalRef = local::NewWeakGlobalRef; envTable->DeleteGlobalRef = local::DeleteGlobalRef; + envTable->DeleteWeakGlobalRef = local::DeleteWeakGlobalRef; envTable->EnsureLocalCapacity = local::EnsureLocalCapacity; envTable->ExceptionOccurred = local::ExceptionOccurred; envTable->ExceptionDescribe = local::ExceptionDescribe; @@ -3250,6 +3269,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) local::JavaVMInitArgs* a = static_cast(args); unsigned heapLimit = 0; + unsigned stackLimit = 0; const char* bootLibrary = 0; const char* classpath = 0; const char* javaHome = AVIAN_JAVA_HOME; @@ -3266,6 +3286,8 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) const char* p = a->options[i].optionString + 2; if (strncmp(p, "mx", 2) == 0) { heapLimit = local::parseSize(p + 2); + } else if (strncmp(p, "ss", 2) == 0) { + stackLimit = local::parseSize(p + 2); } else if (strncmp(p, BOOTCLASSPATH_PREPEND_OPTION ":", sizeof(BOOTCLASSPATH_PREPEND_OPTION)) == 0) { @@ -3308,6 +3330,8 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) } if (heapLimit == 0) heapLimit = 128 * 1024 * 1024; + + if (stackLimit == 0) stackLimit = 128 * 1024; if (classpath == 0) classpath = "."; @@ -3358,9 +3382,9 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) *(argumentPointer++) = a->options[i].optionString; } - *m = new (h->allocate(sizeof(Machine))) - Machine - (s, h, bf, af, p, c, properties, propertyCount, arguments, a->nOptions); + *m = new (h->allocate(sizeof(Machine))) Machine + (s, h, bf, af, p, c, properties, propertyCount, arguments, a->nOptions, + stackLimit); *t = p->makeThread(*m, 0, 0); diff --git a/src/machine.cpp b/src/machine.cpp index fbf8ca2511..4df244d536 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -45,18 +45,10 @@ void join(Thread* t, Thread* o) { if (t != o) { - // todo: There's potentially a leak here on systems where we must - // call join on a thread in order to clean up all resources - // associated with it. If a thread has already been zombified by - // the time we get here, acquireSystem will return false, which - // means we can't safely join it because the System::Thread may - // already have been disposed. In that case, the thread has - // already exited (or will soon), but the OS will never free all - // its resources because it doesn't know we're completely done - // with it. - if (acquireSystem(t, o)) { + assert(t, o->state != Thread::JoinedState); + assert(t, (o->flags & Thread::SystemFlag) == 0); + if (o->flags & Thread::JoinFlag) { o->systemThread->join(); - releaseSystem(t, o); } o->state = Thread::JoinedState; } @@ -229,6 +221,9 @@ turnOffTheLights(Thread* t) visitAll(t, t->m->rootThread, disposeNoRemove); System* s = m->system; + + expect(s, m->threadCount == 0); + Heap* h = m->heap; Processor* p = m->processor; Classpath* c = m->classpath; @@ -254,15 +249,17 @@ killZombies(Thread* t, Thread* o) killZombies(t, child); } - switch (o->state) { - case Thread::ZombieState: - join(t, o); - // fall through - - case Thread::JoinedState: - dispose(t, o, true); - - default: break; + if ((o->flags & Thread::SystemFlag) == 0) { + switch (o->state) { + case Thread::ZombieState: + join(t, o); + // fall through + + case Thread::JoinedState: + dispose(t, o, true); + + default: break; + } } } @@ -587,6 +584,16 @@ postVisit(Thread* t, Heap::Visitor* v) = m->tenuredWeakReferences; m->tenuredWeakReferences = firstNewTenuredWeakReference; } + + for (Reference* r = m->jniReferences; r; r = r->next) { + if (r->weak) { + if (m->heap->status(r->target) == Heap::Unreachable) { + r->target = 0; + } else { + v->visit(&(r->target)); + } + } + } } void @@ -872,9 +879,10 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i) parsePoolEntry(t, s, index, pool, ci); parsePoolEntry(t, s, index, pool, nti); - + object class_ = referenceName(t, singletonObject(t, pool, ci)); object nameAndType = singletonObject(t, pool, nti); + object value = makeReference (t, class_, pairFirst(t, nameAndType), pairSecond(t, nameAndType)); set(t, pool, SingletonBody + (i * BytesPerWord), value); @@ -1156,9 +1164,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) unsigned size = fieldSize(t, code); if (flags & ACC_STATIC) { - unsigned excess = (staticOffset % size) % BytesPerWord; - if (excess) { - staticOffset += BytesPerWord - excess; + while (staticOffset % size) { + ++ staticOffset; } fieldOffset(t, field) = staticOffset; @@ -1197,9 +1204,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) for (unsigned i = 0, offset = 0; i < staticCount; ++i) { unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]); - unsigned excess = offset % size; - if (excess) { - offset += BytesPerWord - excess; + while (offset % size) { + ++ offset; } unsigned value = intArrayBody(t, staticValueTable, i); @@ -1302,7 +1308,7 @@ parseCode(Thread* t, Stream& s, object pool) unsigned maxLocals = s.read2(); unsigned length = s.read4(); - object code = makeCode(t, pool, 0, 0, 0, maxStack, maxLocals, length); + object code = makeCode(t, pool, 0, 0, 0, 0, maxStack, maxLocals, length); s.read(&codeBody(t, code, 0), length); PROTECT(t, code); @@ -2226,7 +2232,7 @@ boot(Thread* t) m->processor->boot(t, 0, 0); - { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1); + { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 0, 1); codeBody(t, bootCode, 0) = impdep1; object bootMethod = makeMethod (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); @@ -2410,6 +2416,38 @@ isInitializing(Thread* t, object c) return false; } +object +findInTable(Thread* t, object table, object name, object spec, + object& (*getName)(Thread*, object), + object& (*getSpec)(Thread*, object)) +{ + if (table) { + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object o = arrayBody(t, table, i); + if (vm::strcmp(&byteArrayBody(t, getName(t, o), 0), + &byteArrayBody(t, name, 0)) == 0 and + vm::strcmp(&byteArrayBody(t, getSpec(t, o), 0), + &byteArrayBody(t, spec, 0)) == 0) + { + return o; + } + } + +// fprintf(stderr, "%s %s not in\n", +// &byteArrayBody(t, name, 0), +// &byteArrayBody(t, spec, 0)); + +// for (unsigned i = 0; i < arrayLength(t, table); ++i) { +// object o = arrayBody(t, table, i); +// fprintf(stderr, "\t%s %s\n", +// &byteArrayBody(t, getName(t, o), 0), +// &byteArrayBody(t, getSpec(t, o), 0)); +// } + } + + return 0; +} + } // namespace namespace vm { @@ -2417,7 +2455,8 @@ namespace vm { Machine::Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder, Processor* processor, Classpath* classpath, const char** properties, unsigned propertyCount, - const char** arguments, unsigned argumentCount): + const char** arguments, unsigned argumentCount, + unsigned stackSizeInBytes): vtable(&javaVMVTable), system(system), heapClient(new (heap->allocate(sizeof(HeapClient))) @@ -2435,10 +2474,12 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, propertyCount(propertyCount), arguments(arguments), argumentCount(argumentCount), + threadCount(0), activeCount(0), liveCount(0), daemonCount(0), fixedFootprint(0), + stackSizeInBytes(stackSizeInBytes), localThread(0), stateLock(0), heapLock(0), @@ -2619,23 +2660,7 @@ Thread::exit() } else { threadPeer(this, javaThread) = 0; - System::Monitor* myLock = lock; - System::Thread* mySystemThread = systemThread; - - { ACQUIRE_RAW(this, m->stateLock); - - while (flags & SystemFlag) { - m->stateLock->wait(systemThread, 0); - } - - atomicOr(&flags, Thread::DisposeFlag); - - enter(this, Thread::ZombieState); - } - - myLock->dispose(); - - mySystemThread->dispose(); + enter(this, Thread::ZombieState); } } } @@ -2643,15 +2668,15 @@ Thread::exit() void Thread::dispose() { - if ((flags & Thread::DisposeFlag) == 0) { - if (lock) { - lock->dispose(); - } - - if (systemThread) { - systemThread->dispose(); - } + if (lock) { + lock->dispose(); } + + if (systemThread) { + systemThread->dispose(); + } + + -- m->threadCount; m->heap->free(defaultHeap, ThreadHeapSizeInBytes); @@ -2864,6 +2889,7 @@ enter(Thread* t, Thread::State s) INCREMENT(&(t->m->activeCount), 1); if (t->state == Thread::NoState) { ++ t->m->liveCount; + ++ t->m->threadCount; } t->state = s; } break; @@ -3064,17 +3090,32 @@ popResources(Thread* t) } object -makeByteArray(Thread* t, const char* format, va_list a) +makeByteArrayV(Thread* t, const char* format, va_list a, int size) +{ + THREAD_RUNTIME_ARRAY(t, char, buffer, size); + + int r = vm::vsnprintf(RUNTIME_ARRAY_BODY(buffer), size - 1, format, a); + if (r >= 0 and r < size - 1) { + object s = makeByteArray(t, strlen(RUNTIME_ARRAY_BODY(buffer)) + 1); + memcpy(&byteArrayBody(t, s, 0), RUNTIME_ARRAY_BODY(buffer), + byteArrayLength(t, s)); + return s; + } else { + return 0; + } +} + +object +makeByteArray(Thread* t, const char* format, ...) { int size = 256; while (true) { - THREAD_RUNTIME_ARRAY(t, char, buffer, size); - - int r = vm::vsnprintf(RUNTIME_ARRAY_BODY(buffer), size - 1, format, a); - if (r >= 0 and r < size - 1) { - object s = makeByteArray(t, strlen(RUNTIME_ARRAY_BODY(buffer)) + 1); - memcpy(&byteArrayBody(t, s, 0), RUNTIME_ARRAY_BODY(buffer), - byteArrayLength(t, s)); + va_list a; + va_start(a, format); + object s = makeByteArrayV(t, format, a, size); + va_end(a); + + if (s) { return s; } else { size *= 2; @@ -3082,26 +3123,22 @@ makeByteArray(Thread* t, const char* format, va_list a) } } -object -makeByteArray(Thread* t, const char* format, ...) -{ - va_list a; - va_start(a, format); - object s = makeByteArray(t, format, a); - va_end(a); - - return s; -} - object makeString(Thread* t, const char* format, ...) { - va_list a; - va_start(a, format); - object s = makeByteArray(t, format, a); - va_end(a); + int size = 256; + while (true) { + va_list a; + va_start(a, format); + object s = makeByteArrayV(t, format, a, size); + va_end(a); - return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1); + if (s) { + return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1); + } else { + size *= 2; + } + } } int @@ -3245,7 +3282,9 @@ isAssignableFrom(Thread* t, object a, object b) return isAssignableFrom (t, classStaticTable(t, a), classStaticTable(t, b)); } - } else { + } else if ((classVmFlags(t, a) & PrimitiveFlag) + == (classVmFlags(t, b) & PrimitiveFlag)) + { for (; b; b = classSuper(t, b)) { if (b == a) { return true; @@ -3877,35 +3916,17 @@ makeObjectArray(Thread* t, object elementClass, unsigned count) } object -findInTable(Thread* t, object table, object name, object spec, - object& (*getName)(Thread*, object), - object& (*getSpec)(Thread*, object)) +findFieldInClass(Thread* t, object class_, object name, object spec) { - if (table) { - for (unsigned i = 0; i < arrayLength(t, table); ++i) { - object o = arrayBody(t, table, i); - if (vm::strcmp(&byteArrayBody(t, getName(t, o), 0), - &byteArrayBody(t, name, 0)) == 0 and - vm::strcmp(&byteArrayBody(t, getSpec(t, o), 0), - &byteArrayBody(t, spec, 0)) == 0) - { - return o; - } - } + return findInTable + (t, classFieldTable(t, class_), name, spec, fieldName, fieldSpec); +} -// fprintf(stderr, "%s %s not in\n", -// &byteArrayBody(t, name, 0), -// &byteArrayBody(t, spec, 0)); - -// for (unsigned i = 0; i < arrayLength(t, table); ++i) { -// object o = arrayBody(t, table, i); -// fprintf(stderr, "\t%s %s\n", -// &byteArrayBody(t, getName(t, o), 0), -// &byteArrayBody(t, getSpec(t, o), 0)); -// } - } - - return 0; +object +findMethodInClass(Thread* t, object class_, object name, object spec) +{ + return findInTable + (t, classMethodTable(t, class_), name, spec, methodName, methodSpec); } object @@ -4145,7 +4166,9 @@ visitRoots(Machine* m, Heap::Visitor* v) } for (Reference* r = m->jniReferences; r; r = r->next) { - v->visit(&(r->target)); + if (not r->weak) { + v->visit(&(r->target)); + } } } @@ -4419,7 +4442,7 @@ noop() } // namespace vm // for debugging -void +JNIEXPORT void vmPrintTrace(Thread* t) { class Visitor: public Processor::StackVisitor { @@ -4461,7 +4484,7 @@ vmPrintTrace(Thread* t) } // also for debugging -void* +JNIEXPORT void* vmAddressFromLine(Thread* t, object m, unsigned line) { object code = methodCode(t, m); diff --git a/src/machine.h b/src/machine.h index b11ca98667..05bc01b1e6 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -112,14 +112,15 @@ const unsigned ThreadBackupHeapSizeInBytes = 2 * 1024; const unsigned ThreadBackupHeapSizeInWords = ThreadBackupHeapSizeInBytes / BytesPerWord; -const unsigned StackSizeInBytes = 128 * 1024; -const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord; - const unsigned ThreadHeapPoolSize = 64; const unsigned FixedFootprintThresholdInBytes = ThreadHeapPoolSize * ThreadHeapSizeInBytes; +// number of zombie threads which may accumulate before we force a GC +// to clean them up: +const unsigned ZombieCollectionThreshold = 16; + enum FieldCode { VoidField, ByteField, @@ -1211,11 +1212,12 @@ noop(); class Reference { public: - Reference(object target, Reference** handle): + Reference(object target, Reference** handle, bool weak): target(target), next(*handle), handle(handle), - count(0) + count(0), + weak(weak) { if (next) { next->handle = &next; @@ -1227,6 +1229,7 @@ class Reference { Reference* next; Reference** handle; unsigned count; + bool weak; }; class Classpath; @@ -1275,7 +1278,7 @@ class Machine { Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder, Processor* processor, Classpath* classpath, const char** properties, unsigned propertyCount, const char** arguments, - unsigned argumentCount); + unsigned argumentCount, unsigned stackSizeInBytes); ~Machine() { dispose(); @@ -1299,10 +1302,12 @@ class Machine { unsigned propertyCount; const char** arguments; unsigned argumentCount; + unsigned threadCount; unsigned activeCount; unsigned liveCount; unsigned daemonCount; unsigned fixedFootprint; + unsigned stackSizeInBytes; System::Local* localThread; System::Monitor* stateLock; System::Monitor* heapLock; @@ -1387,7 +1392,7 @@ class Thread { static const unsigned StressFlag = 1 << 4; static const unsigned ActiveFlag = 1 << 5; static const unsigned SystemFlag = 1 << 6; - static const unsigned DisposeFlag = 1 << 7; + static const unsigned JoinFlag = 1 << 7; class Protector { public: @@ -1572,6 +1577,9 @@ class Classpath { virtual object makeThread(Thread* t, Thread* parent) = 0; + virtual void + clearInterrupted(Thread* t) = 0; + virtual void runThread(Thread* t) = 0; @@ -1632,6 +1640,12 @@ objectClass(Thread*, object o) return mask(cast(o, 0)); } +inline unsigned +stackSizeInWords(Thread* t) +{ + return t->m->stackSizeInBytes / BytesPerWord; +} + void enter(Thread* t, Thread::State state); @@ -1983,6 +1997,7 @@ runThread(Thread* t, uintptr_t*) inline bool startThread(Thread* t, Thread* p) { + p->flags |= Thread::JoinFlag; return t->m->system->success(t->m->system->start(&(p->runnable))); } @@ -1994,6 +2009,7 @@ addThread(Thread* t, Thread* p) assert(t, p->state == Thread::NoState); p->state = Thread::IdleState; + ++ t->m->threadCount; ++ t->m->liveCount; p->peer = p->parent->child; @@ -2012,6 +2028,7 @@ removeThread(Thread* t, Thread* p) assert(t, p->state == Thread::IdleState); -- t->m->liveCount; + -- t->m->threadCount; t->m->stateLock->notifyAll(t->systemThread); @@ -2020,11 +2037,24 @@ removeThread(Thread* t, Thread* p) if (p->javaThread) { threadPeer(t, p->javaThread) = 0; } + + p->dispose(); } inline Thread* startThread(Thread* t, object javaThread) { + { PROTECT(t, javaThread); + + stress(t); + + ACQUIRE_RAW(t, t->m->stateLock); + + if (t->m->threadCount > t->m->liveCount + ZombieCollectionThreshold) { + collect(t, Heap::MinorCollection); + } + } + Thread* p = t->m->processor->makeThread(t->m, javaThread, t); addThread(t, p); @@ -2143,6 +2173,8 @@ hashTaken(Thread*, object o) inline unsigned baseSize(Thread* t, object o, object class_) { + assert(t, classFixedSize(t, class_) >= BytesPerWord); + return ceiling(classFixedSize(t, class_), BytesPerWord) + ceiling(classArrayElementSize(t, class_) * cast(o, classFixedSize(t, class_) - BytesPerWord), @@ -2191,7 +2223,7 @@ make(Thread* t, object class_) } object -makeByteArray(Thread* t, const char* format, va_list a); +makeByteArrayV(Thread* t, const char* format, va_list a, int size); object makeByteArray(Thread* t, const char* format, ...); @@ -2566,16 +2598,7 @@ makeObjectArray(Thread* t, unsigned count) } object -findInTable(Thread* t, object table, object name, object spec, - object& (*getName)(Thread*, object), - object& (*getSpec)(Thread*, object)); - -inline object -findFieldInClass(Thread* t, object class_, object name, object spec) -{ - return findInTable - (t, classFieldTable(t, class_), name, spec, fieldName, fieldSpec); -} +findFieldInClass(Thread* t, object class_, object name, object spec); inline object findFieldInClass2(Thread* t, object class_, const char* name, const char* spec) @@ -2587,12 +2610,8 @@ findFieldInClass2(Thread* t, object class_, const char* name, const char* spec) return findFieldInClass(t, class_, n, s); } -inline object -findMethodInClass(Thread* t, object class_, object name, object spec) -{ - return findInTable - (t, classMethodTable(t, class_), name, spec, methodName, methodSpec); -} +object +findMethodInClass(Thread* t, object class_, object name, object spec); inline object makeThrowable @@ -2617,25 +2636,37 @@ makeThrowable } inline object -makeThrowable(Thread* t, Machine::Type type, const char* format, va_list a) +makeThrowableV(Thread* t, Machine::Type type, const char* format, va_list a, + int size) { - object s = makeByteArray(t, format, a); + object s = makeByteArrayV(t, format, a, size); - object message = t->m->classpath->makeString - (t, s, 0, byteArrayLength(t, s) - 1); + if (s) { + object message = t->m->classpath->makeString + (t, s, 0, byteArrayLength(t, s) - 1); - return makeThrowable(t, type, message); + return makeThrowable(t, type, message); + } else { + return 0; + } } inline object makeThrowable(Thread* t, Machine::Type type, const char* format, ...) { - va_list a; - va_start(a, format); - object r = makeThrowable(t, type, format, a); - va_end(a); + int size = 256; + while (true) { + va_list a; + va_start(a, format); + object r = makeThrowableV(t, type, format, a, size); + va_end(a); - return r; + if (r) { + return r; + } else { + size *= 2; + } + } } void @@ -2671,12 +2702,19 @@ throwNew inline void NO_RETURN throwNew(Thread* t, Machine::Type type, const char* format, ...) { - va_list a; - va_start(a, format); - object r = makeThrowable(t, type, format, a); - va_end(a); + int size = 256; + while (true) { + va_list a; + va_start(a, format); + object r = makeThrowableV(t, type, format, a, size); + va_end(a); - throw_(t, r); + if (r) { + throw_(t, r); + } else { + size *= 2; + } + } } object @@ -2764,19 +2802,12 @@ parameterFootprint(Thread* t, const char* s, bool static_); void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)); -inline bool -zombified(Thread* t) -{ - return t->state == Thread::ZombieState - or t->state == Thread::JoinedState; -} - inline bool acquireSystem(Thread* t, Thread* target) { ACQUIRE_RAW(t, t->m->stateLock); - if (not zombified(target)) { + if (t->state != Thread::JoinedState) { atomicOr(&(target->flags), Thread::SystemFlag); return true; } else { @@ -2789,7 +2820,7 @@ releaseSystem(Thread* t, Thread* target) { ACQUIRE_RAW(t, t->m->stateLock); - assert(t, not zombified(target)); + assert(t, t->state != Thread::JoinedState); atomicAnd(&(target->flags), ~Thread::SystemFlag); } @@ -3187,6 +3218,7 @@ wait(Thread* t, object o, int64_t milliseconds) if (interrupted) { if (t->m->alive or (t->flags & Thread::DaemonFlag) == 0) { + t->m->classpath->clearInterrupted(t); throwNew(t, Machine::InterruptedExceptionType); } else { throw_(t, root(t, Machine::Shutdown)); @@ -3870,10 +3902,10 @@ errorLog(Thread* t) } // namespace vm -void +JNIEXPORT void vmPrintTrace(vm::Thread* t); -void* +JNIEXPORT void* vmAddressFromLine(vm::Thread* t, vm::object m, unsigned line); #endif//MACHINE_H diff --git a/src/main.cpp b/src/main.cpp index a84630b68c..2518d60a13 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -143,6 +143,7 @@ usageAndExit(const char* name) (stderr, "usage: %s\n" "\t[{-cp|-classpath} ]\n" "\t[-Xmx]\n" + "\t[-Xss]\n" "\t[-Xbootclasspath/p:]\n" "\t[-Xbootclasspath:]\n" "\t[-Xbootclasspath/a:]\n" diff --git a/src/openjdk/jni_md.h b/src/openjdk/jni_md.h index bf5614c995..86858429d3 100644 --- a/src/openjdk/jni_md.h +++ b/src/openjdk/jni_md.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Avian Contributors +/* Copyright (c) 2010-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/openjdk/my_java_props_macosx.c b/src/openjdk/my_java_props_macosx.c new file mode 100644 index 0000000000..8a1850010f --- /dev/null +++ b/src/openjdk/my_java_props_macosx.c @@ -0,0 +1,28 @@ +#include "java_props_macosx.h" + +PreferredToolkit +getPreferredToolkit() +{ + return unset; +} + +void +setOSNameAndVersion(java_props_t* props) +{ + props->os_name = strdup("iOS"); + props->os_version = strdup("Unknown"); +} + +void +setProxyProperties(java_props_t* props) +{ + // ignore +} + +char* +setupMacOSXLocale(int cat) +{ + return 0; +} + +char* environ[0]; diff --git a/src/posix.cpp b/src/posix.cpp index 074c6b379c..3d0f525013 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -122,8 +122,7 @@ pathOfExecutable(System* s, const char** retBuf, unsigned* size) const bool Verbose = false; -const unsigned Waiting = 1 << 0; -const unsigned Notified = 1 << 1; +const unsigned Notified = 1 << 0; class MySystem: public System { public: @@ -256,7 +255,14 @@ class MySystem: public System { } void append(Thread* t) { +#ifndef NDEBUG + for (Thread* x = first; x; x = x->next) { + expect(s, t != x); + } +#endif + if (last) { + expect(s, t != last); last->next = t; last = t; } else { @@ -271,6 +277,7 @@ class MySystem: public System { if (current == first) { first = t->next; } else { + expect(s, previous != t->next); previous->next = t->next; } @@ -286,6 +293,12 @@ class MySystem: public System { current = current->next; } } + +#ifndef NDEBUG + for (Thread* x = first; x; x = x->next) { + expect(s, t != x); + } +#endif } virtual void wait(System::Thread* context, int64_t time) { @@ -308,13 +321,13 @@ class MySystem: public System { { ACQUIRE(t->mutex); + expect(s, (t->flags & Notified) == 0); + interrupted = t->r->interrupted(); if (interrupted and clearInterrupted) { t->r->setInterrupted(false); } - t->flags |= Waiting; - append(t); depth = this->depth; @@ -343,14 +356,22 @@ class MySystem: public System { } notified = ((t->flags & Notified) != 0); - - t->flags = 0; } pthread_mutex_lock(&mutex); + { ACQUIRE(t->mutex); + t->flags = 0; + } + if (not notified) { remove(t); + } else { +#ifndef NDEBUG + for (Thread* x = first; x; x = x->next) { + expect(s, t != x); + } +#endif } t->next = 0; @@ -380,6 +401,7 @@ class MySystem: public System { Thread* t = first; first = first->next; if (t == last) { + expect(s, first == 0); last = 0; } diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 7e315b1f35..a184c21f36 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2011, Avian Contributors +/* Copyright (c) 2009-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -130,6 +130,7 @@ inline int cmpw(int ra, int rb) { return cmp(0, ra, rb); } inline int cmplw(int ra, int rb) { return cmpl(0, ra, rb); } inline int cmpwi(int ra, int i) { return cmpi(0, ra, i); } inline int cmplwi(int ra, int i) { return cmpli(0, ra, i); } +inline int trap() { return 0x7fe00008; } // todo: macro-ify } const int64_t MASK_LO32 = 0x0ffffffff; @@ -232,7 +233,7 @@ class Context { public: Context(System* s, Allocator* a, Zone* zone): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), - firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(this, 0)), + firstBlock(new(zone) MyBlock(this, 0)), lastBlock(firstBlock), jumpOffsetHead(0), jumpOffsetTail(0), constantPool(0), constantPoolCount(0) { } @@ -348,8 +349,7 @@ class Offset: public Promise { Promise* offset(Context* c) { - return new (c->zone->allocate(sizeof(Offset))) - Offset(c, c->lastBlock, c->code.length()); + return new(c->zone) Offset(c, c->lastBlock, c->code.length()); } bool @@ -467,14 +467,13 @@ void appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, bool conditional) { - OffsetTask* task = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask - (c->tasks, promise, instructionOffset, conditional); + OffsetTask* task = new(c->zone) OffsetTask(c->tasks, promise, instructionOffset, conditional); c->tasks = task; if (conditional) { - JumpOffset* offset = new (c->zone->allocate(sizeof(JumpOffset))) JumpOffset - (c->lastBlock, task, c->code.length() - c->lastBlock->offset); + JumpOffset* offset = + new(c->zone) JumpOffset(c->lastBlock, task, c->code.length() - c->lastBlock->offset); if (c->lastBlock->jumpOffsetTail) { c->lastBlock->jumpOffsetTail->next = offset; @@ -489,7 +488,7 @@ void appendJumpEvent(Context* c, MyBlock* b, unsigned offset, JumpOffset* head, JumpOffset* tail) { - JumpEvent* e = new (c->zone->allocate(sizeof(JumpEvent))) JumpEvent + JumpEvent* e = new(c->zone) JumpEvent (head, tail, offset); if (b->jumpEventTail) { @@ -857,8 +856,7 @@ void appendImmediateTask(Context* c, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset, bool address) { - c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask - (c->tasks, promise, offset, size, promiseOffset, address); + c->tasks = new(c->zone) ImmediateTask(c->tasks, promise, offset, size, promiseOffset, address); } class ConstantPoolEntry: public Promise { @@ -889,8 +887,7 @@ class ConstantPoolEntry: public Promise { ConstantPoolEntry* appendConstantPoolEntry(Context* c, Promise* constant) { - return new (c->zone->allocate(sizeof(ConstantPoolEntry))) - ConstantPoolEntry(c, constant); + return new (c->zone) ConstantPoolEntry(c, constant); } void @@ -1784,8 +1781,7 @@ branchCM(Context* c, TernaryOperation op, unsigned size, ShiftMaskPromise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) { - return new (c->zone->allocate(sizeof(ShiftMaskPromise))) - ShiftMaskPromise(base, shift, mask); + return new (c->zone) ShiftMaskPromise(base, shift, mask); } void @@ -1907,6 +1903,12 @@ return_(Context* c) emit(c, blr()); } +void +trap(Context* c) +{ + emit(c, trap()); +} + void memoryBarrier(Context* c) { @@ -1923,7 +1925,7 @@ argumentFootprint(unsigned footprint) void nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size, - unsigned footprint, void* link, void*, + unsigned footprint, void* link, bool, unsigned targetParameterFootprint, void** ip, void** stack) { assert(c, *ip >= start); @@ -1988,6 +1990,7 @@ populateTables(ArchitectureContext* c) zo[LoadBarrier] = memoryBarrier; zo[StoreStoreBarrier] = memoryBarrier; zo[StoreLoadBarrier] = memoryBarrier; + zo[Trap] = trap; uo[index(c, LongCall, C)] = CAST1(longCallC); @@ -2215,12 +2218,12 @@ class MyArchitecture: public Assembler::Architecture { } virtual void nextFrame(void* start, unsigned size, unsigned footprint, - void* link, void* stackLimit, + void* link, bool mostRecent, unsigned targetParameterFootprint, void** ip, void** stack) { ::nextFrame(&c, static_cast(start), size, footprint, link, - stackLimit, targetParameterFootprint, ip, stack); + mostRecent, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { @@ -2454,8 +2457,7 @@ class MyAssembler: public Assembler { Register stack(StackRegister); Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); Constant handlerConstant - (new (c.zone->allocate(sizeof(ResolvedPromise))) - ResolvedPromise(handler)); + (new(c.zone) ResolvedPromise(handler)); branchRM(&c, JumpIfGreaterOrEqual, TargetBytesPerWord, &stack, &stackLimit, &handlerConstant); } @@ -2775,8 +2777,7 @@ class MyAssembler: public Assembler { MyBlock* b = c.lastBlock; b->size = c.code.length() - b->offset; if (startNew) { - c.lastBlock = new (c.zone->allocate(sizeof(MyBlock))) - MyBlock(&c, c.code.length()); + c.lastBlock = new(c.zone) MyBlock(&c, c.code.length()); } else { c.lastBlock = 0; } @@ -2847,9 +2848,9 @@ Assembler* makeAssembler(System* system, Allocator* allocator, Zone* zone, Assembler::Architecture* architecture) { - return new (zone->allocate(sizeof(MyAssembler))) - MyAssembler(system, allocator, zone, - static_cast(architecture)); + return + new(zone) MyAssembler(system, allocator, zone, + static_cast(architecture)); } } // namespace vm diff --git a/src/powerpc.h b/src/powerpc.h index 9b877719d0..8ddc9fc73c 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/process.h b/src/process.h index 45de6d975c..04fcf57c7d 100644 --- a/src/process.h +++ b/src/process.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/processor.h b/src/processor.h index 71defc268e..4af110401f 100644 --- a/src/processor.h +++ b/src/processor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2010, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -41,6 +41,13 @@ class Processor { virtual unsigned count() = 0; }; + class CompilationHandler { + public: + virtual void compiled(const void* code, unsigned size, unsigned frameSize, const char* name) = 0; + + virtual void dispose() = 0; + }; + virtual Thread* makeThread(Machine* m, object javaThread, Thread* parent) = 0; @@ -120,6 +127,9 @@ class Processor { virtual void initialize(BootImage* image, uint8_t* code, unsigned capacity) = 0; + virtual void + addCompilationHandler(CompilationHandler* handler) = 0; + virtual void compileMethod(Thread* t, Zone* zone, object* constants, object* calls, DelayedPromise** addresses, object method, diff --git a/src/system.h b/src/system.h index 0ec1b29eb5..c36aefacd9 100644 --- a/src/system.h +++ b/src/system.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -199,7 +199,7 @@ assert(System* s, bool v) #endif // not NDEBUG -System* +JNIEXPORT System* makeSystem(const char* crashDumpDirectory); } // namespace vm diff --git a/src/types.def b/src/types.def index c95ed03a0a..31d96404a8 100644 --- a/src/types.def +++ b/src/types.def @@ -77,6 +77,7 @@ (object exceptionHandlerTable) (object lineNumberTable) (intptr_t compiled) + (uint32_t compiledSize) (uint16_t maxStack) (uint16_t maxLocals) (array uint8_t body)) @@ -219,6 +220,8 @@ (type negativeArraySizeException java/lang/NegativeArraySizeException) +(type reflectiveOperationException java/lang/ReflectiveOperationException) + (type classCastException java/lang/ClassCastException) (type classNotFoundException java/lang/ClassNotFoundException) diff --git a/src/util.cpp b/src/util.cpp index 562255b95a..915913e6e1 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -58,8 +58,7 @@ class TreeContext { TreeContext::Path* path(TreeContext* c, object node, TreeContext::Path* next) { - return new (c->zone->allocate(sizeof(TreeContext::Path))) - TreeContext::Path(node, next); + return new(c->zone) TreeContext::Path(node, next); } inline object diff --git a/src/windows.cpp b/src/windows.cpp index 42a79d3024..f6b4f1e550 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -215,6 +215,12 @@ class MySystem: public System { } void append(Thread* t) { +#ifndef NDEBUG + for (Thread* x = first; x; x = x->next) { + expect(s, t != x); + } +#endif + if (last) { last->next = t; last = t; @@ -245,6 +251,12 @@ class MySystem: public System { current = current->next; } } + +#ifndef NDEBUG + for (Thread* x = first; x; x = x->next) { + expect(s, t != x); + } +#endif } virtual void wait(System::Thread* context, int64_t time) { @@ -270,6 +282,8 @@ class MySystem: public System { { ACQUIRE(s, t->mutex); + expect(s, (t->flags & Notified) == 0); + interrupted = t->r->interrupted(); if (interrupted and clearInterrupted) { t->r->setInterrupted(false); @@ -306,15 +320,23 @@ class MySystem: public System { } notified = ((t->flags & Notified) != 0); - - t->flags = 0; } r = WaitForSingleObject(mutex, INFINITE); assert(s, r == WAIT_OBJECT_0); + { ACQUIRE(s, t->mutex); + t->flags = 0; + } + if (not notified) { remove(t); + } else { +#ifndef NDEBUG + for (Thread* x = first; x; x = x->next) { + expect(s, t != x); + } +#endif } t->next = 0; @@ -346,6 +368,7 @@ class MySystem: public System { Thread* t = first; first = first->next; if (t == last) { + expect(s, first == 0); last = 0; } diff --git a/src/x86.cpp b/src/x86.cpp index 28c6dc2bc7..095a567c63 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -8,6 +8,7 @@ There is NO WARRANTY for this software. See license.txt for details. */ +#include "environment.h" #include "assembler.h" #include "target.h" #include "vector.h" @@ -156,7 +157,7 @@ class Context { public: Context(System* s, Allocator* a, Zone* zone, ArchitectureContext* ac): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), - firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), + firstBlock(new(zone) MyBlock(0)), lastBlock(firstBlock), ac(ac) { } @@ -206,8 +207,7 @@ expect(Context* c, bool v) ResolvedPromise* resolved(Context* c, int64_t value) { - return new (c->zone->allocate(sizeof(ResolvedPromise))) - ResolvedPromise(value); + return new(c->zone) ResolvedPromise(value); } class CodePromise: public Promise { @@ -233,7 +233,7 @@ class CodePromise: public Promise { CodePromise* codePromise(Context* c, unsigned offset) { - return new (c->zone->allocate(sizeof(CodePromise))) CodePromise(c, offset); + return new (c->zone) CodePromise(c, offset); } class Offset: public Promise { @@ -267,8 +267,7 @@ class Offset: public Promise { Promise* offset(Context* c) { - return new (c->zone->allocate(sizeof(Offset))) - Offset(c, c->lastBlock, c->code.length(), c->lastBlock->lastPadding); + return new(c->zone) Offset(c, c->lastBlock, c->code.length(), c->lastBlock->lastPadding); } class Task { @@ -345,8 +344,8 @@ void appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, unsigned instructionSize) { - OffsetTask* task = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask - (c->tasks, promise, instructionOffset, instructionSize); + OffsetTask* task = + new(c->zone) OffsetTask(c->tasks, promise, instructionOffset, instructionSize); c->tasks = task; } @@ -417,7 +416,7 @@ void appendImmediateTask(Context* c, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset = 0) { - c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask + c->tasks = new(c->zone) ImmediateTask (c->tasks, promise, offset, size, promiseOffset); } @@ -644,6 +643,12 @@ return_(Context* c) opcode(c, 0xc3); } +void +trap(Context* c) +{ + opcode(c, 0xcc); +} + void ignore(Context*) { } @@ -832,7 +837,7 @@ callM(Context* c, unsigned size UNUSED, Assembler::Memory* a) void alignedCallC(Context* c, unsigned size, Assembler::Constant* a) { - new (c->zone->allocate(sizeof(AlignmentPadding))) AlignmentPadding(c, 1, 4); + new(c->zone) AlignmentPadding(c, 1, 4); callC(c, size, a); } @@ -842,8 +847,7 @@ alignedLongCallC(Context* c, unsigned size, Assembler::Constant* a) assert(c, size == TargetBytesPerWord); if (TargetBytesPerWord == 8) { - new (c->zone->allocate(sizeof(AlignmentPadding))) - AlignmentPadding(c, 2, 8); + new (c->zone) AlignmentPadding(c, 2, 8); longCallC(c, size, a); } else { alignedCallC(c, size, a); @@ -853,7 +857,7 @@ alignedLongCallC(Context* c, unsigned size, Assembler::Constant* a) void alignedJumpC(Context* c, unsigned size, Assembler::Constant* a) { - new (c->zone->allocate(sizeof(AlignmentPadding))) AlignmentPadding(c, 1, 4); + new (c->zone) AlignmentPadding(c, 1, 4); jumpC(c, size, a); } @@ -863,8 +867,7 @@ alignedLongJumpC(Context* c, unsigned size, Assembler::Constant* a) assert(c, size == TargetBytesPerWord); if (TargetBytesPerWord == 8) { - new (c->zone->allocate(sizeof(AlignmentPadding))) - AlignmentPadding(c, 2, 8); + new (c->zone) AlignmentPadding(c, 2, 8); longJumpC(c, size, a); } else { alignedJumpC(c, size, a); @@ -1289,8 +1292,7 @@ moveAR(Context* c, unsigned aSize, Assembler::Address* a, ShiftMaskPromise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) { - return new (c->zone->allocate(sizeof(ShiftMaskPromise))) - ShiftMaskPromise(base, shift, mask); + return new(c->zone) ShiftMaskPromise(base, shift, mask); } void @@ -1478,7 +1480,8 @@ subtractBorrowCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, opcode(c, 0x83, 0xd8 + regCode(b)); c->code.append(v); } else { - abort(c); + opcode(c, 0x81, 0xd8 + regCode(b)); + c->code.append4(v); } } @@ -2161,8 +2164,8 @@ divideRR(Context* c, unsigned aSize, Assembler::Register* a, assert(c, a->low != rdx); c->client->save(rdx); - - maybeRex(c, aSize, a, b); + + maybeRex(c, aSize, a, b); opcode(c, 0x99); // cdq maybeRex(c, aSize, b, a); opcode(c, 0xf7, 0xf8 + regCode(a)); @@ -2178,8 +2181,8 @@ remainderRR(Context* c, unsigned aSize, Assembler::Register* a, assert(c, a->low != rdx); c->client->save(rdx); - - maybeRex(c, aSize, a, b); + + maybeRex(c, aSize, a, b); opcode(c, 0x99); // cdq maybeRex(c, aSize, b, a); opcode(c, 0xf7, 0xf8 + regCode(a)); @@ -2550,7 +2553,7 @@ read4(uint8_t* p) void nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, - unsigned footprint, void*, void* stackLimit, + unsigned footprint, void*, bool mostRecent, unsigned targetParameterFootprint, void** ip, void** stack) { assert(c, *ip >= start); @@ -2568,6 +2571,7 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, } if (instruction <= start) { + assert(c, mostRecent); *ip = static_cast(*stack)[0]; return; } @@ -2577,6 +2581,8 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, start += (TargetBytesPerWord == 4 ? 3 : 4); if (instruction <= start or *instruction == 0x5d) { + assert(c, mostRecent); + *ip = static_cast(*stack)[1]; *stack = static_cast(*stack) + 1; return; @@ -2588,8 +2594,7 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, return; } - unsigned offset = footprint + FrameHeaderSize - - (stackLimit == *stack ? 1 : 0); + unsigned offset = footprint + FrameHeaderSize - (mostRecent ? 1 : 0); if (TailCalls) { if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { @@ -2640,6 +2645,7 @@ populateTables(ArchitectureContext* c) zo[LoadBarrier] = ignore; zo[StoreStoreBarrier] = ignore; zo[StoreLoadBarrier] = storeLoadBarrier; + zo[Trap] = trap; uo[index(c, Call, C)] = CAST1(callC); uo[index(c, Call, R)] = CAST1(callR); @@ -2677,6 +2683,7 @@ populateTables(ArchitectureContext* c) bo[index(c, MoveZ, R, R)] = CAST2(moveZRR); bo[index(c, MoveZ, M, R)] = CAST2(moveZMR); + bo[index(c, MoveZ, C, R)] = CAST2(moveCR); bo[index(c, Add, R, R)] = CAST2(addRR); bo[index(c, Add, C, R)] = CAST2(addCR); @@ -2814,7 +2821,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned frameFootprint(unsigned footprint) { -#ifdef TARGET_PLATFORM_WINDOWS +#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS return max(footprint, StackAlignmentInWords); #else return max(footprint > argumentRegisterCount() ? @@ -2836,7 +2843,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned argumentRegisterCount() { -#ifdef TARGET_PLATFORM_WINDOWS +#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS if (TargetBytesPerWord == 8) return 4; else #else if (TargetBytesPerWord == 8) return 6; else @@ -2847,7 +2854,7 @@ class MyArchitecture: public Assembler::Architecture { virtual int argumentRegister(unsigned index) { assert(&c, TargetBytesPerWord == 8); switch (index) { -#ifdef TARGET_PLATFORM_WINDOWS +#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS case 0: return rcx; case 1: @@ -2963,12 +2970,12 @@ class MyArchitecture: public Assembler::Architecture { } virtual void nextFrame(void* start, unsigned size, unsigned footprint, - void* link, void* stackLimit, + void* link, bool mostRecent, unsigned targetParameterFootprint, void** ip, void** stack) { local::nextFrame(&c, static_cast(start), size, footprint, - link, stackLimit, targetParameterFootprint, ip, stack); + link, mostRecent, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { @@ -3695,8 +3702,7 @@ class MyAssembler: public Assembler { MyBlock* b = c.lastBlock; b->size = c.code.length() - b->offset; if (startNew) { - c.lastBlock = new (c.zone->allocate(sizeof(MyBlock))) - MyBlock(c.code.length()); + c.lastBlock = new(c.zone) MyBlock(c.code.length()); } else { c.lastBlock = 0; } @@ -3740,9 +3746,9 @@ Assembler* makeAssembler(System* system, Allocator* allocator, Zone* zone, Assembler::Architecture* architecture) { - return new (zone->allocate(sizeof(local::MyAssembler))) - local::MyAssembler(system, allocator, zone, - static_cast(architecture)); + return + new(zone) local::MyAssembler(system, allocator, zone, + static_cast(architecture)); } } // namespace vm diff --git a/src/x86.h b/src/x86.h index 72cc891ac1..298cab6aaa 100644 --- a/src/x86.h +++ b/src/x86.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Avian Contributors +/* Copyright (c) 2008-2012, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/zlib-custom.h b/src/zlib-custom.h index cf1119e1fe..ab00841eec 100644 --- a/src/zlib-custom.h +++ b/src/zlib-custom.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2009, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/test/Files.java b/test/Files.java index 6bf01dadaa..7a0170b678 100644 --- a/test/Files.java +++ b/test/Files.java @@ -1,4 +1,6 @@ import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; public class Files { private static void expect(boolean v) { @@ -20,10 +22,58 @@ public class Files { } } + + private static void setExecutableTestWithPermissions(boolean executable) + throws Exception + { + File file = File.createTempFile("avian.", null); + file.setExecutable(executable); + if (executable) { + expect(file.canExecute()); + } else { + // Commented out because this will fail on Windows - both on Avian and on OpenJDK + // The implementation for Windows considers canExecute() to be the same as canRead() + // expect(!file.canExecute()); + } + } - public static void main(String[] args) { + public static void main(String[] args) throws Exception { isAbsoluteTest(true); isAbsoluteTest(false); + setExecutableTestWithPermissions(true); + setExecutableTestWithPermissions(false); + + { File f = new File("test.txt"); + f.createNewFile(); + expect(! f.createNewFile()); + f.delete(); + } + + { File f = new File("test.txt"); + FileOutputStream out = new FileOutputStream(f); + try { + byte[] message = "hello, world!\n".getBytes(); + out.write(message); + out.close(); + + FileInputStream in = new FileInputStream(f); + try { + expect(in.available() == message.length); + + for (int i = 0; i < message.length; ++i) { + in.read(); + expect(in.available() == message.length - i - 1); + } + + expect(in.read() == -1); + expect(in.available() == 0); + } finally { + in.close(); + } + } finally { + f.delete(); + } + } } } diff --git a/test/Longs.java b/test/Longs.java index 434ee908c9..0472536f60 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -234,6 +234,54 @@ public class Longs { expect((a ^ 25214903884L) == (2L ^ 25214903884L)); } + { long b = 2; + expect((-281474976710656L) >> b == -281474976710656L >> 2); + expect((-281474976710656L) >>> b == -281474976710656L >>> 2); + expect((-281474976710656L) << b == -281474976710656L << 2); + expect((-281474976710656L) + b == -281474976710656L + 2L); + expect((-281474976710656L) - b == -281474976710656L - 2L); + expect((-281474976710656L) * b == -281474976710656L * 2L); + expect((-281474976710656L) / b == -281474976710656L / 2L); + expect((-281474976710656L) % b == -281474976710656L % 2L); + expect(((-281474976710656L) & b) == (-281474976710656L & 2L)); + expect(((-281474976710656L) | b) == (-281474976710656L | 2L)); + expect(((-281474976710656L) ^ b) == (-281474976710656L ^ 2L)); + + b = 2; + expect(281474976710656L >> b == 281474976710656L >> 2); + expect(281474976710656L >>> b == 281474976710656L >>> 2); + expect(281474976710656L << b == 281474976710656L << 2); + expect(281474976710656L + b == 281474976710656L + 2L); + expect(281474976710656L - b == 281474976710656L - 2L); + expect(281474976710656L * b == 281474976710656L * 2L); + expect(281474976710656L / b == 281474976710656L / 2L); + expect(281474976710656L % b == 281474976710656L % 2L); + expect((281474976710656L & b) == (281474976710656L & 2L)); + expect((281474976710656L | b) == (281474976710656L | 2L)); + expect((281474976710656L ^ b) == (281474976710656L ^ 2L)); + } + + { long a = 2L; + expect(a + (-281474976710656L) == 2L + (-281474976710656L)); + expect(a - (-281474976710656L) == 2L - (-281474976710656L)); + expect(a * (-281474976710656L) == 2L * (-281474976710656L)); + expect(a / (-281474976710656L) == 2L / (-281474976710656L)); + expect(a % (-281474976710656L) == 2L % (-281474976710656L)); + expect((a & (-281474976710656L)) == (2L & (-281474976710656L))); + expect((a | (-281474976710656L)) == (2L | (-281474976710656L))); + expect((a ^ (-281474976710656L)) == (2L ^ (-281474976710656L))); + + a = 2L; + expect(a + 281474976710656L == 2L + 281474976710656L); + expect(a - 281474976710656L == 2L - 281474976710656L); + expect(a * 281474976710656L == 2L * 281474976710656L); + expect(a / 281474976710656L == 2L / 281474976710656L); + expect(a % 281474976710656L == 2L % 281474976710656L); + expect((a & 281474976710656L) == (2L & 281474976710656L)); + expect((a | 281474976710656L) == (2L | 281474976710656L)); + expect((a ^ 281474976710656L) == (2L ^ 281474976710656L)); + } + { long x = 231; expect((x >> 32) == 0); expect((x >>> 32) == 0); diff --git a/test/Misc.java b/test/Misc.java index 7ff2f25378..450f23d2b0 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -235,5 +235,7 @@ public class Misc { System.out.println(75.62); System.out.println(75.62d); System.out.println(new char[] { 'h', 'i' }); + + expect(! (((Object) new int[0]) instanceof Object[])); } } diff --git a/test/UnsafeTest.java b/test/UnsafeTest.java new file mode 100644 index 0000000000..5167526c3b --- /dev/null +++ b/test/UnsafeTest.java @@ -0,0 +1,65 @@ +import sun.misc.Unsafe; + +public class UnsafeTest { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + public static void main(String[] args) { + Unsafe u = avian.Machine.getUnsafe(); + + final long size = 64; + long memory = u.allocateMemory(size); + try { + for (int i = 0; i < size; ++i) + u.putByte(memory + i, (byte) 42); + + for (int i = 0; i < size; ++i) + expect(u.getByte(memory + i) == 42); + + for (int i = 0; i < size / 2; ++i) + u.putShort(memory + (i * 2), (short) -12345); + + for (int i = 0; i < size / 2; ++i) + expect(u.getShort(memory + (i * 2)) == -12345); + + for (int i = 0; i < size / 2; ++i) + u.putChar(memory + (i * 2), (char) 23456); + + for (int i = 0; i < size / 2; ++i) + expect(u.getChar(memory + (i * 2)) == 23456); + + for (int i = 0; i < size / 4; ++i) + u.putInt(memory + (i * 4), 0x12345678); + + for (int i = 0; i < size / 4; ++i) + expect(u.getInt(memory + (i * 4)) == 0x12345678); + + for (int i = 0; i < size / 4; ++i) + u.putFloat(memory + (i * 4), 1.2345678F); + + for (int i = 0; i < size / 4; ++i) + expect(u.getFloat(memory + (i * 4)) == 1.2345678F); + + for (int i = 0; i < size / 8; ++i) + u.putLong(memory + (i * 8), 0x1234567890ABCDEFL); + + for (int i = 0; i < size / 8; ++i) + expect(u.getLong(memory + (i * 8)) == 0x1234567890ABCDEFL); + + for (int i = 0; i < size / 8; ++i) + u.putDouble(memory + (i * 8), 1.23456789012345D); + + for (int i = 0; i < size / 8; ++i) + expect(u.getDouble(memory + (i * 8)) == 1.23456789012345D); + + for (int i = 0; i < size / 8; ++i) + u.putAddress(memory + (i * 8), 0x12345678); + + for (int i = 0; i < size / 8; ++i) + expect(u.getAddress(memory + (i * 8)) == 0x12345678); + } finally { + u.freeMemory(memory); + } + } +} diff --git a/test/UrlTest.java b/test/UrlTest.java index 35281b367a..244d1ec45a 100644 --- a/test/UrlTest.java +++ b/test/UrlTest.java @@ -3,7 +3,7 @@ import java.net.URL; public class UrlTest { private static String query="var1=val1&var2=val2"; - private static String path="testpath"; + private static String path="/testpath"; private static String domain="file://www.readytalk.com"; private static String file=path + "?" + query; private static URL url; @@ -15,7 +15,6 @@ public class UrlTest { private static void setupURL() throws MalformedURLException { StringBuilder builder = new StringBuilder(); builder.append(domain); - builder.append("/"); builder.append(file); url = new URL(builder.toString()); } diff --git a/update-copyright.sh b/update-copyright.sh new file mode 100644 index 0000000000..994addef38 --- /dev/null +++ b/update-copyright.sh @@ -0,0 +1,12 @@ +for x in $(find -name *.S -or -name *.cpp -or -name *.h -or -name *.java | sort); do + year_of_last_change=$(git log -1 --format=format:"%ai" $x | cut -c 1-4) + copyright_years=$(grep "^/\* Copyright (c) .*, Avian Contributors$" $x | sed "s-^/\* Copyright (c) \(.*\), Avian Contributors\$-\1-") + if [ "$copyright_years" != "" ]; then + first_copyright_year=$(echo "$copyright_years" | sed "s/\(.*\)-.*/\1/") + last_copyright_year=$(echo "$copyright_years" | sed "s/.*-\(.*\)/\1/") + if [ "$last_copyright_year" != "$year_of_last_change" ]; then + echo "$first_copyright_year-$year_of_last_change $x" + sed -i "s:^/\* Copyright (c) .*, Avian Contributors\$:/* Copyright (c) $first_copyright_year-$year_of_last_change, Avian Contributors:" $x + fi + fi +done diff --git a/vm.pro b/vm.pro index 495bc4c3ab..4cdb1654ee 100644 --- a/vm.pro +++ b/vm.pro @@ -66,6 +66,7 @@ -keep public class java.lang.UnsatisfiedLinkError -keep public class java.lang.ExceptionInInitializerError -keep public class java.lang.OutOfMemoryError +-keep public class java.lang.IncompatibleClassChangeError -keep public class java.lang.reflect.InvocationTargetException -keep public class java.io.IOException -keep public class java.io.FileNotFoundException