diff --git a/classpath/avian/PersistentSet.java b/classpath/avian/PersistentSet.java index 5683327aee..917607ed90 100644 --- a/classpath/avian/PersistentSet.java +++ b/classpath/avian/PersistentSet.java @@ -252,7 +252,7 @@ public class PersistentSet implements Iterable { } ancestors.next = new Cell(n, ancestors.next); - sibling = ancestors.value.right; + sibling = ancestors.value.right = new Node(ancestors.value.right); } if (! (sibling.left.red || sibling.right.red)) { @@ -303,7 +303,7 @@ public class PersistentSet implements Iterable { } ancestors.next = new Cell(n, ancestors.next); - sibling = ancestors.value.left; + sibling = ancestors.value.left = new Node(ancestors.value.left); } if (! (sibling.right.red || sibling.left.red)) { diff --git a/classpath/avian/Utf8.java b/classpath/avian/Utf8.java index 84c4c28058..cb116043c0 100644 --- a/classpath/avian/Utf8.java +++ b/classpath/avian/Utf8.java @@ -50,9 +50,18 @@ public class Utf8 { while (i < offset+length) { int x = s8[i++]; if ((x & 0x080) == 0x0) { // 1 byte char - if (x == 0) ++i; // 2 byte null char + if (x == 0) { // 2 byte null char + if (i == offset + length) { + return null; + } + ++ i; + } cram(buf, j++, x); } else if ((x & 0x0e0) == 0x0c0) { // 2 byte char + if (i == offset + length) { + return null; + } + if (!isMultiByte) { buf = widen(buf, j, length-1); isMultiByte = true; @@ -60,6 +69,10 @@ public class Utf8 { int y = s8[i++]; cram(buf, j++, ((x & 0x1f) << 6) | (y & 0x3f)); } else if ((x & 0x0f0) == 0x0e0) { // 3 byte char + if (i + 1 >= offset + length) { + return null; + } + if (!isMultiByte) { buf = widen(buf, j, length-2); isMultiByte = true; @@ -74,8 +87,13 @@ public class Utf8 { public static char[] decode16(byte[] s8, int offset, int length) { Object decoded = decode(s8, offset, length); - if (decoded instanceof char[]) return (char[])decoded; - return (char[])widen(decoded, length, length); + if (decoded == null) { + return null; + } else if (decoded instanceof char[]) { + return (char[])decoded; + } else { + return (char[])widen(decoded, length, length); + } } private static void cram(Object data, int index, int val) { diff --git a/classpath/avian/resource/Handler.java b/classpath/avian/avianvmresource/Handler.java similarity index 98% rename from classpath/avian/resource/Handler.java rename to classpath/avian/avianvmresource/Handler.java index 51e8d1a838..ea776c7e92 100644 --- a/classpath/avian/resource/Handler.java +++ b/classpath/avian/avianvmresource/Handler.java @@ -8,7 +8,7 @@ There is NO WARRANTY for this software. See license.txt for details. */ -package avian.resource; +package avian.avianvmresource; import java.net.URL; import java.net.URLStreamHandler; diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 3cad9680a3..865f3c3fb4 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -402,7 +402,16 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, return; } +#ifdef __QNX__ + // fork(2) doesn't work in multithreaded QNX programs. See + // http://www.qnx.com/developers/docs/6.4.1/neutrino/getting_started/s1_procs.html + pid_t pid = vfork(); +#else + // We might be able to just use vfork on all UNIX-style systems, but + // the manual makes it sound dangerous due to the shared + // parent/child address space, so we use fork if we can. pid_t pid = fork(); +#endif switch(pid){ case -1: // error throwNewErrno(e, "java/io/IOException"); @@ -569,6 +578,8 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, } else if (strcmp(chars, "os.name") == 0) { #ifdef __APPLE__ r = e->NewStringUTF("Mac OS X"); +#elif defined __FreeBSD__ + r = e->NewStringUTF("FreeBSD"); #else r = e->NewStringUTF("Linux"); #endif diff --git a/classpath/java-net.cpp b/classpath/java-net.cpp index 1cfea1fbc2..76316bec00 100644 --- a/classpath/java-net.cpp +++ b/classpath/java-net.cpp @@ -16,6 +16,8 @@ # define ONLY_ON_WINDOWS(x) x #else # include +# include +# include # define ONLY_ON_WINDOWS(x) #endif diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 4120f276a8..d5e067e1e4 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -31,6 +31,9 @@ # include # include # include +# include +# include +# include # include # include #endif @@ -257,7 +260,7 @@ setTcpNoDelay(JNIEnv* e, int d, bool on) } void -doListen(JNIEnv* e, int s, sockaddr_in* address) +doBind(JNIEnv* e, int s, sockaddr_in* address) { int opt = 1; int r = ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, @@ -272,8 +275,12 @@ doListen(JNIEnv* e, int s, sockaddr_in* address) throwIOException(e); return; } +} - r = ::listen(s, 100); +void +doListen(JNIEnv* e, int s) +{ + int r = ::listen(s, 100); if (r != 0) { throwIOException(e); } @@ -333,6 +340,26 @@ doRead(int fd, void* buffer, size_t count) #endif } +int +doRecv(int fd, void* buffer, size_t count, int32_t* host, int32_t* port) +{ + sockaddr address; + socklen_t length = sizeof(address); + int r = recvfrom + (fd, static_cast(buffer), count, 0, &address, &length); + + if (r > 0) { + sockaddr_in a; memcpy(&a, &address, length); + *host = ntohl(a.sin_addr.s_addr); + *port = ntohs(a.sin_port); + } else { + *host = 0; + *port = 0; + } + + return r; +} + int doWrite(int fd, const void* buffer, size_t count) { @@ -344,9 +371,9 @@ doWrite(int fd, const void* buffer, size_t count) } int -makeSocket(JNIEnv* e) +makeSocket(JNIEnv* e, int type = SOCK_STREAM, int protocol = IPPROTO_TCP) { - int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + int s = ::socket(AF_INET, type, protocol); if (s < 0) { throwIOException(e); return s; @@ -378,7 +405,28 @@ Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv *e, init(e, &address, host, port); if (e->ExceptionCheck()) return 0; - ::doListen(e, s, &address); + ::doBind(e, s, &address); + if (e->ExceptionCheck()) return 0; + + ::doListen(e, s); + return s; +} + +extern "C" JNIEXPORT jint JNICALL +Java_java_nio_channels_DatagramChannel_bind(JNIEnv *e, + jclass, + jstring host, + jint port) +{ + int s = makeSocket(e, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0) return s; + if (e->ExceptionCheck()) return 0; + + sockaddr_in address; + init(e, &address, host, port); + if (e->ExceptionCheck()) return 0; + + ::doBind(e, s, &address); return s; } @@ -391,6 +439,16 @@ Java_java_nio_channels_SocketChannel_configureBlocking(JNIEnv *e, setBlocking(e, socket, blocking); } +extern "C" JNIEXPORT void JNICALL +Java_java_nio_channels_DatagramChannel_configureBlocking(JNIEnv* e, + jclass c, + jint socket, + jboolean blocking) +{ + return Java_java_nio_channels_SocketChannel_configureBlocking + (e, c, socket, blocking); +} + extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e, jclass, @@ -423,6 +481,24 @@ Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e, return s; } +extern "C" JNIEXPORT jint JNICALL +Java_java_nio_channels_DatagramChannel_connect(JNIEnv *e, + jclass, + jstring host, + jint port) +{ + int s = makeSocket(e, SOCK_DGRAM, IPPROTO_UDP); + if (e->ExceptionCheck()) return 0; + + sockaddr_in address; + init(e, &address, host, port); + if (e->ExceptionCheck()) return 0; + + ::doConnect(e, s, &address); + + return s; +} + extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e, jclass, @@ -475,6 +551,57 @@ Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e, return r; } +extern "C" JNIEXPORT jint JNICALL +Java_java_nio_channels_DatagramChannel_receive(JNIEnv* e, + jclass, + jint socket, + jbyteArray buffer, + jint offset, + jint length, + jboolean blocking, + jintArray address) +{ + int r; + int32_t host; + int32_t port; + if (blocking) { + uint8_t* buf = static_cast(allocate(e, length)); + if (buf) { + r = ::doRecv(socket, buf, length, &host, &port); + if (r > 0) { + e->SetByteArrayRegion + (buffer, offset, r, reinterpret_cast(buf)); + } + free(buf); + } else { + return 0; + } + } else { + jboolean isCopy; + uint8_t* buf = static_cast + (e->GetPrimitiveArrayCritical(buffer, &isCopy)); + + r = ::doRecv(socket, buf + offset, length, &host, &port); + + e->ReleasePrimitiveArrayCritical(buffer, buf, 0); + } + + if (r < 0) { + if (eagain()) { + return 0; + } else { + throwIOException(e); + } + } else if (r == 0) { + return -1; + } else { + jint jhost = host; e->SetIntArrayRegion(address, 0, 1, &jhost); + jint jport = port; e->SetIntArrayRegion(address, 1, 1, &jport); + } + + return r; +} + extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e, jclass, @@ -515,6 +642,18 @@ Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e, return r; } +extern "C" JNIEXPORT jint JNICALL +Java_java_nio_channels_DatagramChannel_write(JNIEnv* e, + jclass c, + jint socket, + jbyteArray buffer, + jint offset, + jint length, + jboolean blocking) +{ + return Java_java_nio_channels_SocketChannel_natWrite + (e, c, socket, buffer, offset, length, blocking); +} extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e, @@ -554,18 +693,29 @@ class Pipe { address.sin_family = AF_INET; address.sin_port = 0; address.sin_addr.s_addr = inet_addr("127.0.0.1"); //INADDR_LOOPBACK; + listener_ = makeSocket(e); + if (e->ExceptionCheck()) return; + setBlocking(e, listener_, false); - ::doListen(e, listener_, &address); + + ::doBind(e, listener_, &address); + if (e->ExceptionCheck()) return; + + ::doListen(e, listener_); + if (e->ExceptionCheck()) return; socklen_t length = sizeof(sockaddr_in); int r = getsockname(listener_, reinterpret_cast(&address), &length); if (r) { throwIOException(e); + return; } writer_ = makeSocket(e); + if (e->ExceptionCheck()) return; + setBlocking(e, writer_, true); connected_ = ::doConnect(e, writer_, &address); } @@ -663,6 +813,7 @@ Java_java_nio_channels_SocketSelector_natInit(JNIEnv* e, jclass) void *mem = malloc(sizeof(SelectorState)); if (mem) { SelectorState *s = new (mem) SelectorState(e); + if (e->ExceptionCheck()) return 0; if (s) { FD_ZERO(&(s->read)); diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 86e093495b..187549ebfd 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -72,12 +72,16 @@ public class File implements Serializable { } } - private static String normalize(String path) { - if ("\\".equals(FileSeparator)) { - return path.replace('/', '\\'); - } else { - return path; + private static String stripSeparators(String p) { + while (p.endsWith(FileSeparator)) { + p = p.substring(0, p.length() - 1); } + return p; + } + + private static String normalize(String path) { + return stripSeparators + ("\\".equals(FileSeparator) ? path.replace('/', '\\') : path); } public static native boolean rename(String old, String new_); @@ -150,7 +154,7 @@ public class File implements Serializable { public String getParent() { int index = path.lastIndexOf(FileSeparator); if (index >= 0) { - return path.substring(0, index); + return normalize(path.substring(0, index)); } else { return null; } @@ -239,11 +243,15 @@ public class File implements Serializable { public File[] listFiles(FilenameFilter filter) { String[] list = list(filter); - File[] result = new File[list.length]; - for (int i = 0; i < list.length; ++i) { - result[i] = new File(this, list[i]); + if (list != null) { + File[] result = new File[list.length]; + for (int i = 0; i < list.length; ++i) { + result[i] = new File(this, list[i]); + } + return result; + } else { + return null; } - return result; } public String[] list() { @@ -254,22 +262,26 @@ public class File implements Serializable { long handle = 0; try { handle = openDir(path); - Pair list = null; - int count = 0; - for (String s = readDir(handle); s != null; s = readDir(handle)) { - if (filter == null || filter.accept(this, s)) { - list = new Pair(s, list); - ++ count; + if (handle != 0) { + Pair list = null; + int count = 0; + for (String s = readDir(handle); s != null; s = readDir(handle)) { + if (filter == null || filter.accept(this, s)) { + list = new Pair(s, list); + ++ count; + } } - } - String[] result = new String[count]; - for (int i = count - 1; i >= 0; --i) { - result[i] = list.value; - list = list.next; - } + String[] result = new String[count]; + for (int i = count - 1; i >= 0; --i) { + result[i] = list.value; + list = list.next; + } - return result; + return result; + } else { + return null; + } } finally { if (handle != 0) { closeDir(handle); diff --git a/classpath/java/io/InputStreamReader.java b/classpath/java/io/InputStreamReader.java index 98f145cd92..9b35187d29 100644 --- a/classpath/java/io/InputStreamReader.java +++ b/classpath/java/io/InputStreamReader.java @@ -13,6 +13,8 @@ package java.io; import avian.Utf8; public class InputStreamReader extends Reader { + private static final int MultibytePadding = 4; + private final InputStream in; public InputStreamReader(InputStream in) { @@ -28,19 +30,60 @@ public class InputStreamReader extends Reader { throw new UnsupportedEncodingException(encoding); } } - public int read(char[] b, int offset, int length) throws IOException { - byte[] buffer = new byte[length]; - int c = in.read(buffer); + if (length == 0) { + return 0; + } - if (c <= 0) return c; + byte[] buffer = new byte[length + MultibytePadding]; + int bufferLength = length; + int bufferOffset = 0; + while (true) { + int c = in.read(buffer, bufferOffset, bufferLength); - char[] buffer16 = Utf8.decode16(buffer, 0, c); + if (c <= 0) { + if (bufferOffset > 0) { + // if we've reached the end of the stream while trying to + // read a multibyte character, we still need to return any + // competely-decoded characters, plus \ufffd to indicate an + // unknown character + c = 1; + while (bufferOffset > 0) { + char[] buffer16 = Utf8.decode16(buffer, 0, bufferOffset); - System.arraycopy(buffer16, 0, b, offset, buffer16.length); + if (buffer16 != null) { + System.arraycopy(buffer16, 0, b, offset, buffer16.length); + + c = buffer16.length + 1; + break; + } else { + -- bufferOffset; + } + } - return buffer16.length; + b[offset + c - 1] = '\ufffd'; + } + + return c; + } + + bufferOffset += c; + + char[] buffer16 = Utf8.decode16(buffer, 0, bufferOffset); + + if (buffer16 != null) { + bufferOffset = 0; + + System.arraycopy(buffer16, 0, b, offset, buffer16.length); + + return buffer16.length; + } else { + // the buffer ended in an incomplete multibyte character, so + // we try to read a another byte at a time until it's complete + bufferLength = 1; + } + } } public void close() throws IOException { diff --git a/classpath/java/lang/Deprecated.java b/classpath/java/lang/Deprecated.java new file mode 100644 index 0000000000..3bda3aa846 --- /dev/null +++ b/classpath/java/lang/Deprecated.java @@ -0,0 +1,17 @@ +/* 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.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Deprecated { } diff --git a/classpath/java/lang/Float.java b/classpath/java/lang/Float.java index 408de61220..f04e728bac 100644 --- a/classpath/java/lang/Float.java +++ b/classpath/java/lang/Float.java @@ -14,6 +14,10 @@ public final class Float extends Number { public static final Class TYPE = Class.forCanonicalName("F"); private static final int EXP_BIT_MASK = 0x7F800000; private static final int SIGNIF_BIT_MASK = 0x007FFFFF; + + public static final float NEGATIVE_INFINITY = -1.0f / 0.0f; + public static final float POSITIVE_INFINITY = 1.0f / 0.0f; + public static final float NaN = 0.0f / 0.0f; private final float value; diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 539a709169..936351c809 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -156,6 +156,10 @@ public class Thread implements Runnable { } public static void sleep(long milliseconds) throws InterruptedException { + if (milliseconds <= 0) { + milliseconds = 1; + } + Thread t = currentThread(); if (t.sleepLock == null) { t.sleepLock = new Object(); diff --git a/classpath/java/net/DatagramSocket.java b/classpath/java/net/DatagramSocket.java new file mode 100644 index 0000000000..2ba3f8d163 --- /dev/null +++ b/classpath/java/net/DatagramSocket.java @@ -0,0 +1,19 @@ +/* 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.net; + +import java.io.IOException; + +public abstract class DatagramSocket { + public abstract SocketAddress getRemoteSocketAddress(); + + public abstract void bind(SocketAddress address) throws SocketException; +} diff --git a/classpath/java/net/ProtocolFamily.java b/classpath/java/net/ProtocolFamily.java new file mode 100644 index 0000000000..d6a217f196 --- /dev/null +++ b/classpath/java/net/ProtocolFamily.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.net; + +public interface ProtocolFamily { } diff --git a/classpath/java/net/StandardProtocolFamily.java b/classpath/java/net/StandardProtocolFamily.java new file mode 100644 index 0000000000..43e8ce394d --- /dev/null +++ b/classpath/java/net/StandardProtocolFamily.java @@ -0,0 +1,15 @@ +/* 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.net; + +public enum StandardProtocolFamily implements ProtocolFamily { + INET; +} diff --git a/classpath/java/net/URL.java b/classpath/java/net/URL.java index f80e327997..c311ad8c15 100644 --- a/classpath/java/net/URL.java +++ b/classpath/java/net/URL.java @@ -83,8 +83,8 @@ public final class URL { { if ("http".equals(protocol) || "https".equals(protocol)) { return new avian.http.Handler(); - } else if ("resource".equals(protocol)) { - return new avian.resource.Handler(); + } else if ("avianvmresource".equals(protocol)) { + return new avian.avianvmresource.Handler(); } else if ("file".equals(protocol)) { return new avian.file.Handler(); } else if ("jar".equals(protocol)) { diff --git a/classpath/java/nio/ArrayByteBuffer.java b/classpath/java/nio/ArrayByteBuffer.java new file mode 100644 index 0000000000..336945c1bb --- /dev/null +++ b/classpath/java/nio/ArrayByteBuffer.java @@ -0,0 +1,92 @@ +/* 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. */ + +package java.nio; + +class ArrayByteBuffer extends ByteBuffer { + private final byte[] array; + private final int arrayOffset; + + ArrayByteBuffer(byte[] array, int offset, int length, boolean readOnly) { + super(readOnly); + + this.array = array; + this.arrayOffset = offset; + this.capacity = length; + this.limit = length; + this.position = 0; + } + + public ByteBuffer asReadOnlyBuffer() { + ByteBuffer b = new ArrayByteBuffer(array, arrayOffset, capacity, true); + b.position(position()); + b.limit(limit()); + return b; + } + + public boolean hasArray() { + return true; + } + + public byte[] array() { + return array; + } + + public ByteBuffer slice() { + return new ArrayByteBuffer + (array, arrayOffset + position, remaining(), true); + } + + public int arrayOffset() { + return arrayOffset; + } + + protected void doPut(int position, byte val) { + array[arrayOffset + position] = val; + } + + public ByteBuffer put(ByteBuffer src) { + int length = src.remaining(); + checkPut(position, length); + src.get(array, arrayOffset + position, length); + position += length; + return this; + } + + public ByteBuffer put(byte[] src, int offset, int length) { + checkPut(position, length); + + System.arraycopy(src, offset, array, arrayOffset + position, length); + position += length; + + return this; + } + + public ByteBuffer get(byte[] dst, int offset, int length) { + checkGet(position, length); + + System.arraycopy(array, arrayOffset + position, dst, offset, length); + position += length; + + return this; + } + + protected byte doGet(int position) { + return array[arrayOffset+position]; + } + + public String toString() { + return "(ArrayByteBuffer with array: " + array + + " arrayOffset: " + arrayOffset + + " position: " + position + + " limit: " + limit + + " capacity: " + capacity + ")"; + } +} diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java index e63217f6ea..3a6548d2b3 100644 --- a/classpath/java/nio/ByteBuffer.java +++ b/classpath/java/nio/ByteBuffer.java @@ -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 @@ -10,13 +10,22 @@ package java.nio; -public class ByteBuffer extends Buffer implements Comparable { - private final byte[] array; - private int arrayOffset; +public abstract class ByteBuffer + extends Buffer + implements Comparable +{ private final boolean readOnly; + protected ByteBuffer(boolean readOnly) { + this.readOnly = readOnly; + } + public static ByteBuffer allocate(int capacity) { - return new ByteBuffer(new byte[capacity], 0, capacity, false); + return new ArrayByteBuffer(new byte[capacity], 0, capacity, false); + } + + public static ByteBuffer allocateDirect(int capacity) { + return FixedArrayByteBuffer.make(capacity); } public static ByteBuffer wrap(byte[] array) { @@ -24,23 +33,53 @@ public class ByteBuffer extends Buffer implements Comparable { } public static ByteBuffer wrap(byte[] array, int offset, int length) { - return new ByteBuffer(array, offset, length, false); + return new ArrayByteBuffer(array, offset, length, false); } - private ByteBuffer(byte[] array, int offset, int length, boolean readOnly) { - this.array = array; - this.readOnly = readOnly; - arrayOffset = offset; - capacity = length; - limit = capacity; - position = 0; + public abstract ByteBuffer asReadOnlyBuffer(); + + public abstract ByteBuffer slice(); + + protected abstract void doPut(int offset, byte val); + + public abstract ByteBuffer put(byte[] arr, int offset, int len); + + protected abstract byte doGet(int offset); + + public abstract ByteBuffer get(byte[] dst, int offset, int length); + + public boolean hasArray() { + return false; } - public ByteBuffer asReadOnlyBuffer() { - ByteBuffer b = new ByteBuffer(array, arrayOffset, capacity, true); - b.position(position()); - b.limit(limit()); - return b; + public ByteBuffer compact() { + int remaining = remaining(); + + if (position != 0) { + ByteBuffer b = slice(); + position = 0; + put(b); + } + + position = remaining; + limit(capacity()); + + return this; + } + + public ByteBuffer put(ByteBuffer src) { + if (src.hasArray()) { + checkPut(position, src.remaining()); + + put(src.array(), src.arrayOffset() + src.position, src.remaining()); + src.position(src.position() + src.remaining()); + + return this; + } else { + byte[] buffer = new byte[src.remaining()]; + src.get(buffer); + return put(buffer); + } } public int compareTo(ByteBuffer o) { @@ -60,37 +99,22 @@ public class ByteBuffer extends Buffer implements Comparable { } public byte[] array() { - return array; - } - - public ByteBuffer slice() { - return new ByteBuffer(array, arrayOffset + position, remaining(), true); + throw new UnsupportedOperationException(); } public int arrayOffset() { - return arrayOffset; + throw new UnsupportedOperationException(); } - public ByteBuffer compact() { - if (position != 0) { - System.arraycopy(array, arrayOffset+position, array, arrayOffset, remaining()); - } - position=remaining(); - limit(capacity()); - + public ByteBuffer put(int offset, byte val) { + checkPut(offset, 1); + doPut(offset, val); return this; } public ByteBuffer put(byte val) { - checkPut(1); - array[arrayOffset+(position++)] = val; - return this; - } - - public ByteBuffer put(ByteBuffer src) { - checkPut(src.remaining()); - put(src.array, src.arrayOffset + src.position, src.remaining()); - src.position += src.remaining(); + put(position, val); + ++ position; return this; } @@ -98,125 +122,126 @@ public class ByteBuffer extends Buffer implements Comparable { return put(arr, 0, arr.length); } - public ByteBuffer put(byte[] arr, int offset, int len) { - checkPut(len); - System.arraycopy(arr, offset, array, arrayOffset+position, len); - position += len; + public ByteBuffer putLong(int position, long val) { + checkPut(position, 8); + + doPut(position , (byte) ((val >> 56) & 0xff)); + doPut(position + 1, (byte) ((val >> 48) & 0xff)); + doPut(position + 2, (byte) ((val >> 40) & 0xff)); + doPut(position + 3, (byte) ((val >> 32) & 0xff)); + doPut(position + 4, (byte) ((val >> 24) & 0xff)); + doPut(position + 5, (byte) ((val >> 16) & 0xff)); + doPut(position + 6, (byte) ((val >> 8) & 0xff)); + doPut(position + 7, (byte) ((val ) & 0xff)); + return this; } public ByteBuffer putInt(int position, int val) { checkPut(position, 4); - array[arrayOffset+position] = (byte)((val >> 24) & 0xff); - array[arrayOffset+position+1] = (byte)((val >> 16) & 0xff); - array[arrayOffset+position+2] = (byte)((val >> 8) & 0xff); - array[arrayOffset+position+3] = (byte)((val ) & 0xff); + + doPut(position , (byte) ((val >> 24) & 0xff)); + doPut(position + 1, (byte) ((val >> 16) & 0xff)); + doPut(position + 2, (byte) ((val >> 8) & 0xff)); + doPut(position + 3, (byte) ((val ) & 0xff)); + + return this; + } + + public ByteBuffer putShort(int position, short val) { + checkPut(position, 2); + + doPut(position , (byte) ((val >> 8) & 0xff)); + doPut(position + 1, (byte) ((val ) & 0xff)); + + return this; + } + + public ByteBuffer putLong(long val) { + putLong(position, val); + position += 8; return this; } public ByteBuffer putInt(int val) { - checkPut(4); putInt(position, val); position += 4; return this; } public ByteBuffer putShort(short val) { - checkPut(2); - put((byte)((val >> 8) & 0xff)); - put((byte)(val & 0xff)); - return this; - } - - public ByteBuffer putLong(long val) { - checkPut(8); - putInt((int)(val >> 32)); - putInt((int)val); + putShort(position, val); + position += 2; return this; } public byte get() { - checkGet(1); - return array[arrayOffset+(position++)]; + return get(position++); + } + + public byte get(int position) { + checkGet(position, 1); + return doGet(position); } public ByteBuffer get(byte[] dst) { return get(dst, 0, dst.length); } - public ByteBuffer get(byte[] dst, int offset, int length) { - checkGet(length); - System.arraycopy(array, arrayOffset + position, dst, offset, length); - position += length; - return this; - } + public long getLong(int position) { + checkGet(position, 8); - public byte get(int position) { - checkGet(position, 1); - return array[arrayOffset+position]; + return (((long) (doGet(position ) & 0xFF)) << 56) + | (((long) (doGet(position + 1) & 0xFF)) << 48) + | (((long) (doGet(position + 2) & 0xFF)) << 40) + | (((long) (doGet(position + 3) & 0xFF)) << 32) + | (((long) (doGet(position + 4) & 0xFF)) << 24) + | (((long) (doGet(position + 5) & 0xFF)) << 16) + | (((long) (doGet(position + 6) & 0xFF)) << 8) + | (((long) (doGet(position + 7) & 0xFF)) ); } public int getInt(int position) { checkGet(position, 4); - int p = arrayOffset + position; - return ((array[p] & 0xFF) << 24) - | ((array[p + 1] & 0xFF) << 16) - | ((array[p + 2] & 0xFF) << 8) - | ((array[p + 3] & 0xFF)); + return (((int) (doGet(position ) & 0xFF)) << 24) + | (((int) (doGet(position + 1) & 0xFF)) << 16) + | (((int) (doGet(position + 2) & 0xFF)) << 8) + | (((int) (doGet(position + 3) & 0xFF)) ); } public short getShort(int position) { checkGet(position, 2); - int p = arrayOffset + position; - return (short) (((array[p] & 0xFF) << 8) | ((array[p + 1] & 0xFF))); - } - - public int getInt() { - checkGet(4); - int i = get() << 24; - i |= (get() & 0xff) << 16; - i |= (get() & 0xff) << 8; - i |= (get() & 0xff); - return i; - } - - public short getShort() { - checkGet(2); - short s = (short)(get() << 8); - s |= get() & 0xff; - return s; + return (short) (( ((int) (doGet(position ) & 0xFF)) << 8) + | (((int) (doGet(position + 1) & 0xFF)) )); } public long getLong() { - checkGet(8); - long l = (long)getInt() << 32; - l |= (long)getInt() & 0xffffffffL; - return l; + long r = getLong(position); + position += 8; + return r; } - private void checkPut(int amount) { - if (readOnly) throw new ReadOnlyBufferException(); - if (amount > limit-position) throw new IndexOutOfBoundsException(); + public int getInt() { + int r = getInt(position); + position += 4; + return r; } - private void checkPut(int position, int amount) { + public short getShort() { + short r = getShort(position); + position += 2; + return r; + } + + protected void checkPut(int position, int amount) { if (readOnly) throw new ReadOnlyBufferException(); if (position < 0 || position+amount > limit) throw new IndexOutOfBoundsException(); } - private void checkGet(int amount) { + protected void checkGet(int position, int amount) { if (amount > limit-position) throw new IndexOutOfBoundsException(); } - - private void checkGet(int position, int amount) { - if (position < 0 || position+amount > limit) - throw new IndexOutOfBoundsException(); - } - - public String toString() { - return "(ByteBuffer with array: " + array + " arrayOffset: " + arrayOffset + " position: " + position + " remaining; " + remaining() + ")"; - } } diff --git a/classpath/java/nio/DirectByteBuffer.java b/classpath/java/nio/DirectByteBuffer.java new file mode 100644 index 0000000000..d33a0d5f6f --- /dev/null +++ b/classpath/java/nio/DirectByteBuffer.java @@ -0,0 +1,105 @@ +/* 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. */ + +package java.nio; + +import sun.misc.Unsafe; + +class DirectByteBuffer extends ByteBuffer { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final int baseOffset = unsafe.arrayBaseOffset(byte[].class); + + protected final long address; + + protected DirectByteBuffer(long address, int capacity, boolean readOnly) { + super(readOnly); + + this.address = address; + this.capacity = capacity; + this.limit = capacity; + this.position = 0; + } + + protected DirectByteBuffer(long address, int capacity) { + this(address, capacity, false); + } + + public ByteBuffer asReadOnlyBuffer() { + ByteBuffer b = new DirectByteBuffer(address, capacity, true); + b.position(position()); + b.limit(limit()); + return b; + } + + public ByteBuffer slice() { + return new DirectByteBuffer(address + position, remaining(), true); + } + + protected void doPut(int position, byte val) { + unsafe.putByte(address + position, val); + } + + public ByteBuffer put(ByteBuffer src) { + if (src instanceof DirectByteBuffer) { + checkPut(position, src.remaining()); + + DirectByteBuffer b = (DirectByteBuffer) src; + + unsafe.copyMemory + (b.address + b.position, address + position, b.remaining()); + + position += b.remaining(); + b.position += b.remaining(); + + return this; + } else { + return super.put(src); + } + } + + public ByteBuffer put(byte[] src, int offset, int length) { + if (offset < 0 || offset + length > src.length) { + throw new ArrayIndexOutOfBoundsException(); + } + + checkPut(position, length); + + unsafe.copyMemory + (src, baseOffset + offset, null, address + position, length); + + position += length; + + return this; + } + + public ByteBuffer get(byte[] dst, int offset, int length) { + if (offset < 0 || offset + length > dst.length) { + throw new ArrayIndexOutOfBoundsException(); + } + + checkGet(position, length); + + unsafe.copyMemory + (null, address + position, dst, baseOffset + offset, length); + + return this; + } + + protected byte doGet(int position) { + return unsafe.getByte(address + position); + } + + public String toString() { + return "(DirectByteBuffer with address: " + address + + " position: " + position + + " limit: " + limit + + " capacity: " + capacity + ")"; + } +} diff --git a/classpath/java/nio/FixedArrayByteBuffer.java b/classpath/java/nio/FixedArrayByteBuffer.java new file mode 100644 index 0000000000..c56ff421f0 --- /dev/null +++ b/classpath/java/nio/FixedArrayByteBuffer.java @@ -0,0 +1,58 @@ +/* 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. */ + +package java.nio; + +class FixedArrayByteBuffer extends DirectByteBuffer { + private final byte[] array; + private final int arrayOffset; + + private FixedArrayByteBuffer(long address, + byte[] array, + int offset, + int capacity, + boolean readOnly) + { + super(address, capacity, readOnly); + + this.array = array; + this.arrayOffset = offset; + } + + public static FixedArrayByteBuffer make(int capacity) { + long[] address = new long[1]; + byte[] array = allocateFixed(capacity, address); + return new FixedArrayByteBuffer(address[0], array, 0, capacity, false); + } + + private static native byte[] allocateFixed(int capacity, long[] address); + + public ByteBuffer asReadOnlyBuffer() { + ByteBuffer b = new FixedArrayByteBuffer + (address, array, arrayOffset, capacity, true); + b.position(position()); + b.limit(limit()); + return b; + } + + public ByteBuffer slice() { + return new FixedArrayByteBuffer + (address + position, array, arrayOffset + position, remaining(), true); + } + + public String toString() { + return "(FixedArrayByteBuffer with address: " + address + + " array: " + array + + " arrayOffset: " + arrayOffset + + " position: " + position + + " limit: " + limit + + " capacity: " + capacity + ")"; + } +} diff --git a/classpath/java/nio/channels/DatagramChannel.java b/classpath/java/nio/channels/DatagramChannel.java new file mode 100644 index 0000000000..ae30c75780 --- /dev/null +++ b/classpath/java/nio/channels/DatagramChannel.java @@ -0,0 +1,180 @@ +/* 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; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.net.SocketAddress; +import java.net.InetSocketAddress; +import java.net.ProtocolFamily; +import java.net.Socket; +import java.net.SocketException; +import java.net.DatagramSocket; +import java.net.StandardProtocolFamily; + +public class DatagramChannel extends SelectableChannel + implements ReadableByteChannel, WritableByteChannel +{ + public static final int InvalidSocket = -1; + + private int socket = InvalidSocket; + private boolean blocking = true; + + public SelectableChannel configureBlocking(boolean v) throws IOException { + blocking = v; + if (socket != InvalidSocket) { + configureBlocking(socket, v); + } + return this; + } + + int socketFD() { + return socket; + } + + void handleReadyOps(int ops) { + // ignore + } + + public static DatagramChannel open(ProtocolFamily family) + throws IOException + { + if (family.equals(StandardProtocolFamily.INET)) { + Socket.init(); + + return new DatagramChannel(); + } else { + throw new UnsupportedOperationException(); + } + } + + public static DatagramChannel open() + throws IOException + { + return open(StandardProtocolFamily.INET); + } + + public DatagramSocket socket() { + return new Handle(); + } + + public DatagramChannel bind(SocketAddress address) throws IOException { + InetSocketAddress inetAddress; + try { + inetAddress = (InetSocketAddress) address; + } catch (ClassCastException e) { + throw new UnsupportedAddressTypeException(); + } + + socket = bind(inetAddress.getHostName(), inetAddress.getPort()); + + return this; + } + + public DatagramChannel connect(SocketAddress address) throws IOException { + InetSocketAddress inetAddress; + try { + inetAddress = (InetSocketAddress) address; + } catch (ClassCastException e) { + throw new UnsupportedAddressTypeException(); + } + + socket = connect(inetAddress.getHostName(), inetAddress.getPort()); + + return this; + } + + public int write(ByteBuffer b) throws IOException { + if (b.remaining() == 0) return 0; + + byte[] array = b.array(); + if (array == null) throw new NullPointerException(); + + int c = write + (socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking); + + if (c > 0) { + b.position(b.position() + c); + } + + return c; + } + + public int read(ByteBuffer b) throws IOException { + int p = b.position(); + receive(b); + return b.position() - p; + } + + public SocketAddress receive(ByteBuffer b) throws IOException { + if (b.remaining() == 0) return null; + + byte[] array = b.array(); + if (array == null) throw new NullPointerException(); + + int[] address = new int[2]; + + int c = receive + (socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking, + address); + + if (c > 0) { + b.position(b.position() + c); + + return new InetSocketAddress(ipv4ToString(address[0]), address[1]); + } else { + return null; + } + } + + private static String ipv4ToString(int address) { + StringBuilder sb = new StringBuilder(); + + sb.append( address >> 24 ).append('.') + .append((address >> 16) & 0xFF).append('.') + .append((address >> 8) & 0xFF).append('.') + .append( address & 0xFF); + + return sb.toString(); + } + + public class Handle extends DatagramSocket { + public SocketAddress getRemoteSocketAddress() { + throw new UnsupportedOperationException(); + } + + public void bind(SocketAddress address) throws SocketException { + try { + DatagramChannel.this.bind(address); + } catch (SocketException e) { + throw e; + } catch (IOException e) { + SocketException se = new SocketException(); + se.initCause(e); + throw se; + } + } + } + + private static native void configureBlocking(int socket, boolean blocking) + throws IOException; + private static native int bind(String hostname, int port) + throws IOException; + private static native int connect(String hostname, int port) + throws IOException; + private static native int write(int socket, byte[] array, int offset, + int length, boolean blocking) + throws IOException; + private static native int receive(int socket, byte[] array, int offset, + int length, boolean blocking, + int[] address) + throws IOException; +} diff --git a/classpath/java/text/MessageFormat.java b/classpath/java/text/MessageFormat.java index ad64838a61..77d4845809 100644 --- a/classpath/java/text/MessageFormat.java +++ b/classpath/java/text/MessageFormat.java @@ -28,8 +28,14 @@ public class MessageFormat extends Format { public StringBuffer format(Object[] args, StringBuffer target, FieldPosition p) { - // todo - return target.append(pattern); + // todo: handle other format substitutions and escapes, and make + // this more efficient: + String result = pattern; + int length = args.length; + for (int i = 0; i < length; i++) { + result = result.replace("{" + i + "}", String.valueOf(args[i])); + } + return target.append(result); } public StringBuffer format(Object args, StringBuffer target, FieldPosition p) diff --git a/classpath/java/util/AbstractList.java b/classpath/java/util/AbstractList.java index fb9ccdccfd..87cbd6fb6e 100644 --- a/classpath/java/util/AbstractList.java +++ b/classpath/java/util/AbstractList.java @@ -15,6 +15,11 @@ public abstract class AbstractList extends AbstractCollection { protected int modCount; + public boolean add(T o) { + add(size(), o); + return true; + } + public Iterator iterator() { return listIterator(); } diff --git a/classpath/java/util/Arrays.java b/classpath/java/util/Arrays.java index c32cc1fe5f..1bf35c1114 100644 --- a/classpath/java/util/Arrays.java +++ b/classpath/java/util/Arrays.java @@ -17,6 +17,23 @@ public class Arrays { return asList(a).toString(); } + public static String toString(byte[] a) { + if (a == null) { + return "null"; + } else { + StringBuilder sb = new StringBuilder(); + sb.append("["); + for (int i = 0; i < a.length; ++i) { + sb.append(String.valueOf(a[i])); + if (i + 1 != a.length) { + sb.append(", "); + } + } + sb.append("]"); + return sb.toString(); + } + } + private static boolean equal(Object a, Object b) { return (a == null && b == null) || (a != null && a.equals(b)); } diff --git a/classpath/sun/misc/Unsafe.java b/classpath/sun/misc/Unsafe.java index b7613d2559..4f395718c9 100644 --- a/classpath/sun/misc/Unsafe.java +++ b/classpath/sun/misc/Unsafe.java @@ -47,4 +47,14 @@ public final class Unsafe { public native long getAddress(long address); public native void putAddress(long address, long x); + + public native int arrayBaseOffset(Class arrayClass); + + public native void copyMemory(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long count); + + public void copyMemory(long src, long dst, long count) { + copyMemory(null, src, null, dst, count); + } } diff --git a/makefile b/makefile index eeb2ce4ffe..8330ff31e0 100755 --- a/makefile +++ b/makefile @@ -5,6 +5,8 @@ version = 0.6 build-arch := $(shell uname -m \ | sed 's/^i.86$$/i386/' \ + | sed 's/^x86pc$$/i386/' \ + | sed 's/amd64/x86_64/' \ | sed 's/^arm.*$$/arm/' \ | sed 's/ppc/powerpc/') @@ -22,7 +24,6 @@ target-arch = $(arch) bootimage-platform = \ $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))) platform = $(bootimage-platform) -target-platform = $(platform) mode = fast process = compile @@ -85,6 +86,8 @@ ifeq ($(build-platform),darwin) library-path-variable = DYLD_LIBRARY_PATH endif +library-path = $(library-path-variable)=$(build) + ifneq ($(openjdk),) openjdk-arch = $(arch) ifeq ($(arch),x86_64) @@ -161,6 +164,8 @@ ifneq ($(platform),darwin) endif endif +target-format = elf + cxx = $(build-cxx) $(mflag) cc = $(build-cc) $(mflag) @@ -186,9 +191,10 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ target-cflags = -DTARGET_BYTES_PER_WORD=$(pointer-size) -common-cflags = $(warnings) -fno-rtti -fno-exceptions \ +common-cflags = $(warnings) -fno-rtti -fno-exceptions -I$(classpath-src) \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ + -DAVIAN_INFO="\"$(info)\"" \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" $(target-cflags) @@ -207,7 +213,7 @@ build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ 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 \ + -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_UNKNOWN \ -Wall -Wextra -Werror -Wunused-parameter -Winit-self -Wno-non-virtual-dtor cflags = $(build-cflags) @@ -218,6 +224,7 @@ build-lflags = -lz -lpthread -ldl lflags = $(common-lflags) -lpthread -ldl +soname-flag = -Wl,-soname -Wl,$(so-prefix)jvm$(so-suffix) version-script-flag = -Wl,--version-script=openjdk.ld build-system = posix @@ -284,8 +291,13 @@ ifeq ($(arch),arm) ifneq ($(arch),$(build-arch)) ifeq ($(platform),darwin) ios-bin = $(developer-dir)/Platforms/iPhoneOS.platform/Developer/usr/bin - cxx = $(ios-bin)/g++ - cc = $(ios-bin)/gcc + ifeq ($(use-clang),true) + cxx = clang -std=c++11 + cc = clang + else + cxx = $(ios-bin)/g++ + cc = $(ios-bin)/gcc + endif ar = $(ios-bin)/ar ranlib = $(ios-bin)/ranlib strip = $(ios-bin)/strip @@ -305,11 +317,45 @@ endif ifeq ($(build-platform),darwin) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) - cflags += -I/System/Library/Frameworks/JavaVM.framework/Headers/ + cflags += -I/System/Library/Frameworks/JavaVM.framework/Headers/ \ + -Wno-deprecated-declarations build-lflags += -framework CoreFoundation + soname-flag = +endif + +ifeq ($(platform),qnx) + cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) + lflags = $(common-lflags) -lsocket + ifeq ($(build-platform),qnx) + build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) + build-lflags = $(common-lflags) + else + ifeq ($(arch),i386) + prefix = i486-pc-nto-qnx6.5.0- + else + prefix = arm-unknown-nto-qnx6.5.0- + endif + endif + cxx = $(prefix)g++ + cc = $(prefix)gcc + ar = $(prefix)ar + ranlib = $(prefix)ranlib + strip = $(prefix)strip + rdynamic = -Wl,--export-dynamic +endif + +ifeq ($(platform),freebsd) +# There is no -ldl on FreeBSD + build-lflags = $(common-lflags) -lz -lpthread + lflags = $(common-lflags) -lpthread +# include/freebsd instead of include/linux + build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ + "-I$(JAVA_HOME)/include/freebsd" -I$(src) -pthread + cflags = $(build-cflags) endif ifeq ($(platform),darwin) + target-format = macho ifeq (${OSX_SDK_SYSROOT},) OSX_SDK_SYSROOT = 10.4u endif @@ -350,7 +396,8 @@ ifeq ($(platform),darwin) ifeq ($(arch),arm) ios-version := \ - $(shell if test -d $(sdk-dir)/iPhoneOS5.1.sdk; then echo 5.1; \ + $(shell if test -d $(sdk-dir)/iPhoneOS6.0.sdk; then echo 6.0; \ + elif 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; \ @@ -391,6 +438,8 @@ ifeq ($(platform),darwin) endif ifeq ($(platform),windows) + target-format = pe + inc = "$(win32)/include" lib = "$(win32)/lib" @@ -527,7 +576,8 @@ ifdef msvc cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \ - -Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I"$(build)" \ + -Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I$(classpath-src) \ + -I"$(build)" \ -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" \ -DTARGET_BYTES_PER_WORD=$(pointer-size) @@ -756,7 +806,7 @@ ifneq ($(classpath),avian) $(classpath-src)/avian/VMClass.java \ $(classpath-src)/avian/VMField.java \ $(classpath-src)/avian/VMMethod.java \ - $(classpath-src)/avian/resource/Handler.java + $(classpath-src)/avian/avianvmresource/Handler.java ifneq ($(openjdk),) classpath-sources := $(classpath-sources) \ @@ -777,9 +827,12 @@ vm-classes = \ test-support-sources = $(shell find $(test)/avian/ -name '*.java') test-sources = $(wildcard $(test)/*.java) +test-cpp-sources = $(wildcard $(test)/*.cpp) test-sources += $(test-support-sources) test-support-classes = $(call java-classes, $(test-support-sources),$(test),$(test-build)) test-classes = $(call java-classes,$(test-sources),$(test),$(test-build)) +test-cpp-objects = $(call cpp-objects,$(test-cpp-sources),$(test),$(test-build)) +test-library = $(build)/$(so-prefix)test$(so-suffix) test-dep = $(test-build).dep test-extra-sources = $(wildcard $(test)/extra/*.java) @@ -815,22 +868,22 @@ ifeq ($(target-arch),arm) cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM endif -ifeq ($(target-platform),linux) - cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_LINUX +ifeq ($(target-format),elf) + cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_ELF endif -ifeq ($(target-platform),windows) - cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_WINDOWS +ifeq ($(target-format),pe) + cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_PE endif -ifeq ($(target-platform),darwin) - cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_DARWIN +ifeq ($(target-format),macho) + cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_MACHO endif class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) -test-flags = -cp $(build)/test +test-flags = -Djava.library.path=$(build) -cp $(build)/test test-args = $(test-flags) $(input) @@ -904,7 +957,7 @@ $(classpath-dep): $(classpath-sources) $(test-build)/%.class: $(test)/%.java @echo $(<) -$(test-dep): $(test-sources) +$(test-dep): $(test-sources) $(test-library) @echo "compiling test classes" @mkdir -p $(test-build) files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \ @@ -939,6 +992,19 @@ endef $(vm-cpp-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) +$(test-cpp-objects): $(test-build)/%.o: $(test)/%.cpp $(vm-depends) + $(compile-object) + +$(test-library): $(test-cpp-objects) + @echo "linking $(@)" +ifdef msvc + $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ + -IMPLIB:$(test-build)/$(name).lib -MANIFESTFILE:$(@).manifest + $(mt) -manifest $(@).manifest -outputresource:"$(@);2" +else + $(ld) $(^) $(shared) $(lflags) -o $(@) +endif + $(build)/%.o: $(lzma)/C/%.c @echo "compiling $(@)" @mkdir -p $(dir $(@)) @@ -994,7 +1060,7 @@ $(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep) $(classpath-object): $(build)/classpath.jar $(converter) @echo "creating $(@)" $(converter) $(<) $(@) _binary_classpath_jar_start \ - _binary_classpath_jar_end $(platform) $(arch) + _binary_classpath_jar_end $(target-format) $(arch) $(build)/javahome.jar: @echo "creating $(@)" @@ -1005,7 +1071,7 @@ $(build)/javahome.jar: $(javahome-object): $(build)/javahome.jar $(converter) @echo "creating $(@)" $(converter) $(<) $(@) _binary_javahome_jar_start \ - _binary_javahome_jar_end $(platform) $(arch) + _binary_javahome_jar_end $(target-format) $(arch) define compile-generator-object @echo "compiling $(@)" @@ -1066,7 +1132,7 @@ $(bootimage-generator): $(bootimage-generator-objects) arch=$(build-arch) \ target-arch=$(arch) \ platform=$(bootimage-platform) \ - target-platform=$(platform) \ + target-format=$(target-format) \ openjdk=$(openjdk) \ openjdk-src=$(openjdk-src) \ bootimage-generator= \ @@ -1104,7 +1170,8 @@ ifdef msvc -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else - $(ld) $(^) $(version-script-flag) $(shared) $(lflags) $(bootimage-lflags) \ + $(ld) $(^) $(version-script-flag) $(soname-flag) \ + $(shared) $(lflags) $(bootimage-lflags) \ -o $(@) endif $(strip) $(strip-all) $(@) diff --git a/openjdk.pro b/openjdk.pro index 8207016de5..d0b8de812f 100644 --- a/openjdk.pro +++ b/openjdk.pro @@ -42,7 +42,7 @@ } -keep class avian.OpenJDK { - public static java.security.ProtectionDomain getProtectionDomain(); + ; } -keepclassmembers public class java.security.PrivilegedAction { @@ -208,7 +208,7 @@ -keep class sun.nio.cs.UTF_8 # loaded reflectively to handle embedded resources: --keep class avian.resource.Handler +-keep class avian.avianvmresource.Handler # refered to symbolically in MethodAccessorGenerator: -keep class sun.reflect.MethodAccessorImpl { @@ -244,3 +244,5 @@ -keep class sun.nio.fs.UnixException { UnixException(int); } + +-keep class sun.net.www.protocol.jar.Handler diff --git a/src/arm.S b/src/arm.S index dceb8d3b75..23e66cefdd 100644 --- a/src/arm.S +++ b/src/arm.S @@ -1,4 +1,4 @@ -/* arm.S: JNI gluecode for ARM/Linux +/* arm.S: JNI gluecode for ARM Copyright (c) 2008-2011, Avian Contributors Permission to use, copy, modify, and/or distribute this software @@ -9,6 +9,8 @@ There is NO WARRANTY for this software. See license.txt for details. */ +#include "types.h" + .text #define LOCAL(x) .L##x @@ -29,14 +31,18 @@ GLOBAL(vmNativeCall): r2 : memoryTable r3 : memoryCount [sp, #0] -> r6 : gprTable + [sp, #4] -> r7 : vfpTable + [sp, #8] -> r8 : returnType */ mov ip, sp // save stack frame - stmfd sp!, {r4-r6, lr} // save clobbered non-volatile regs + stmfd sp!, {r4-r8, lr} // save clobbered non-volatile regs // mv args into non-volatile regs mov r4, r0 mov r5, r1 ldr r6, [ip] + ldr r7, [ip, #4] + ldr r8, [ip, #8] // setup stack arguments if necessary sub sp, sp, r5 // allocate stack @@ -50,12 +56,38 @@ LOCAL(loop): // setup argument registers if necessary tst r6, r6 +#if (defined __APPLE__) && (defined __clang_major__) && (__clang_major__ >= 4) + ldmiane r6, {r0-r3} +#else ldmneia r6, {r0-r3} +#endif +#if defined(__ARM_PCS_VFP) + // and VFP registers + vldmia r7, {d0-d7} +#endif +#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) + mov lr, pc + bx r4 +#else blx r4 // call function +#endif add sp, sp, r5 // deallocate stack - ldmfd sp!, {r4-r6, pc} // restore non-volatile regs and return +#if defined(__ARM_PCS_VFP) + cmp r8,#FLOAT_TYPE + bne LOCAL(double) + fmrs r0,s0 + b LOCAL(exit) + +LOCAL(double): + cmp r8,#DOUBLE_TYPE + bne LOCAL(exit) + fmrrd r0,r1,d0 +#endif + +LOCAL(exit): + ldmfd sp!, {r4-r8, pc} // restore non-volatile regs and return .globl GLOBAL(vmJump) .align 2 @@ -85,7 +117,12 @@ GLOBAL(vmRun): mov r12, r0 ldr r0, [r2, #CHECKPOINT_THREAD] +#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) + mov lr, pc + bx r12 +#else blx r12 +#endif .globl GLOBAL(vmRun_returnAddress) .align 2 diff --git a/src/arm.cpp b/src/arm.cpp index 4f7c74b7d4..ae657e30d5 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -49,12 +49,6 @@ inline int XFER2(int cond, int P, int U, int W, int L, int Rn, int Rd, int S, in { return cond<<28 | P<<24 | U<<23 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | 1<<7 | S<<6 | H<<5 | 1<<4 | Rm; } inline int XFER2I(int cond, int P, int U, int W, int L, int Rn, int Rd, int offsetH, int S, int H, int offsetL) { return cond<<28 | P<<24 | U<<23 | 1<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offsetH<<8 | 1<<7 | S<<6 | H<<5 | 1<<4 | (offsetL&0xf); } -inline int BLOCKXFER(int cond, int P, int U, int S, int W, int L, int Rn, int rlist) -{ return cond<<28 | 4<<25 | P<<24 | U<<23 | S<<22 | W<<21 | L<<20 | Rn<<16 | rlist; } -inline int SWI(int cond, int imm) -{ return cond<<28 | 0x0f<<24 | (imm&0xffffff); } -inline int SWAP(int cond, int B, int Rn, int Rd, int Rm) -{ return cond<<28 | 1<<24 | B<<22 | Rn<<16 | Rd<<12 | 9<<4 | Rm; } inline int COOP(int cond, int opcode_1, int CRn, int CRd, int cp_num, int opcode_2, int CRm) { return cond<<28 | 0xe<<24 | opcode_1<<20 | CRn<<16 | CRd<<12 | cp_num<<8 | opcode_2<<5 | CRm; } inline int COXFER(int cond, int P, int U, int N, int W, int L, int Rn, int CRd, int cp_num, int offset) // offset is in words, not bytes @@ -71,41 +65,29 @@ inline int b(int offset) { return BRANCH(AL, 0, offset); } inline int bl(int offset) { return BRANCH(AL, 1, offset); } inline int bx(int Rm) { return BRANCHX(AL, 0, Rm); } inline int blx(int Rm) { return BRANCHX(AL, 1, Rm); } -inline int swi(int imm) { return SWI(AL, imm); } inline int and_(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x0, 0, Rn, Rd, shift, Sh, Rm); } inline int eor(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x1, 0, Rn, Rd, shift, Sh, Rm); } -inline int sub(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x2, 0, Rn, Rd, shift, Sh, Rm); } inline int rsb(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x3, 0, Rn, Rd, shift, Sh, Rm); } inline int add(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x4, 0, Rn, Rd, shift, Sh, Rm); } inline int adc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x5, 0, Rn, Rd, shift, Sh, Rm); } -inline int sbc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x6, 0, Rn, Rd, shift, Sh, Rm); } inline int rsc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x7, 0, Rn, Rd, shift, Sh, Rm); } -inline int tst(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x8, 1, Rn, 0, shift, Sh, Rm); } -inline int teq(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x9, 1, Rn, 0, shift, Sh, Rm); } inline int cmp(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xa, 1, Rn, 0, shift, Sh, Rm); } -inline int cmn(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xb, 1, Rn, 0, shift, Sh, Rm); } inline int orr(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xc, 0, Rn, Rd, shift, Sh, Rm); } inline int mov(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xd, 0, 0, Rd, shift, Sh, Rm); } -inline int bic(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xe, 0, Rn, Rd, shift, Sh, Rm); } inline int mvn(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xf, 0, 0, Rd, shift, Sh, Rm); } inline int andi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x0, 0, Rn, Rd, rot, imm); } -inline int eori(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x1, 0, Rn, Rd, rot, imm); } inline int subi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x2, 0, Rn, Rd, rot, imm); } inline int rsbi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x3, 0, Rn, Rd, rot, imm); } inline int addi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x4, 0, Rn, Rd, rot, imm); } inline int adci(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x5, 0, Rn, Rd, rot, imm); } inline int bici(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xe, 0, Rn, Rd, rot, imm); } inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0xa, 1, Rn, 0, rot, imm); } -inline int orri(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xc, 0, Rn, Rd, rot, imm); } inline int movi(int Rd, int imm, int rot=0) { return DATAI(AL, 0xd, 0, 0, Rd, rot, imm); } inline int orrsh(int Rd, int Rn, int Rm, int Rs, int Sh) { return DATAS(AL, 0xc, 0, Rn, Rd, Rs, Sh, Rm); } inline int movsh(int Rd, int Rm, int Rs, int Sh) { return DATAS(AL, 0xd, 0, 0, Rd, Rs, Sh, Rm); } inline int mul(int Rd, int Rm, int Rs) { return MULTIPLY(AL, 0, 0, Rd, 0, Rs, Rm); } inline int mla(int Rd, int Rm, int Rs, int Rn) { return MULTIPLY(AL, 1, 0, Rd, Rn, Rs, Rm); } inline int umull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, RdHi, RdLo, Rs, Rm); } -inline int umlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 5, 0, RdHi, RdLo, Rs, Rm); } -inline int smull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdHi, RdLo, Rs, Rm); } -inline int smlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 7, 0, RdHi, RdLo, Rs, Rm); } inline int ldr(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 1, Rn, Rd, 0, 0, Rm); } inline int ldri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 1, Rn, Rd, abs(imm)); } inline int ldrb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 1, Rn, Rd, 0, 0, Rm); } @@ -122,39 +104,19 @@ inline int ldrsh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, inline int ldrshi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 1, abs(imm)&0xf); } inline int ldrsb(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 0, Rm); } inline int ldrsbi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 0, abs(imm)&0xf); } -inline int pop(int Rd) { return XFERI(AL, 0, 1, 0, 0, 1, 13, Rd, 4); } -inline int ldmfd(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 1, 1, Rn, rlist); } -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); } inline int mcrr(int coproc, int opcode, int Rd, int Rn, int CRm) { return COREG2(AL, 0, Rn, Rd, coproc, opcode, CRm); } inline int mrc(int coproc, int opcode_1, int Rd, int CRn, int CRm, int opcode_2=0) { return COREG(AL, opcode_1, 1, CRn, Rd, coproc, opcode_2, CRm); } inline int mrrc(int coproc, int opcode, int Rd, int Rn, int CRm) { return COREG2(AL, 1, Rn, Rd, coproc, opcode, CRm); } -inline int ldc(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 0, W, 1, Rn, CRd, coproc, offset); } -inline int ldcl(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 1, W, 1, Rn, CRd, coproc, offset); } -inline int stc(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 0, W, 0, Rn, CRd, coproc, offset); } -inline int stcl(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 1, W, 0, Rn, CRd, coproc, offset); } // VFP FLOATING-POINT INSTRUCTIONS -inline int fmacs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); } -inline int fnmacs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); } -inline int fmscs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|1, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); } -inline int fnmscs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|1, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); } inline int fmuls(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); } -inline int fnmuls(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); } inline int fadds(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|3, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); } inline int fsubs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|3, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); } inline int fdivs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|8, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); } -inline int fmacd(int Dd, int Dn, int Dm) { return COOP(AL, 0, Dn, Dd, 11, 0, Dm); } -inline int fnmacd(int Dd, int Dn, int Dm) { return COOP(AL, 0, Dn, Dd, 11, 2, Dm); } -inline int fmscd(int Dd, int Dn, int Dm) { return COOP(AL, 1, Dn, Dd, 11, 0, Dm); } -inline int fnmscd(int Dd, int Dn, int Dm) { return COOP(AL, 1, Dn, Dd, 11, 2, Dm); } inline int fmuld(int Dd, int Dn, int Dm) { return COOP(AL, 2, Dn, Dd, 11, 0, Dm); } -inline int fnmuld(int Dd, int Dn, int Dm) { return COOP(AL, 2, Dn, Dd, 11, 2, Dm); } inline int faddd(int Dd, int Dn, int Dm) { return COOP(AL, 3, Dn, Dd, 11, 0, Dm); } inline int fsubd(int Dd, int Dn, int Dm) { return COOP(AL, 3, Dn, Dd, 11, 2, Dm); } inline int fdivd(int Dd, int Dn, int Dm) { return COOP(AL, 8, Dn, Dd, 11, 0, Dm); } @@ -163,15 +125,8 @@ inline int fabss(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0, Sd>>1, 10, inline int fnegs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 1, Sd>>1, 10, 2|(Sm&1), Sm>>1); } inline int fsqrts(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 1, Sd>>1, 10, 6|(Sm&1), Sm>>1); } inline int fcmps(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 4, Sd>>1, 10, 2|(Sm&1), Sm>>1); } -inline int fcmpes(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 4, Sd>>1, 10, 6|(Sm&1), Sm>>1); } -inline int fcmpzs(int Sd) { return COOP(AL, 0xb|(Sd&1)<<2, 5, Sd>>1, 10, 2, 0); } -inline int fcmpezs(int Sd) { return COOP(AL, 0xb|(Sd&1)<<2, 5, Sd>>1, 10, 6, 0); } inline int fcvtds(int Dd, int Sm) { return COOP(AL, 0xb, 7, Dd, 10, 6|(Sm&1), Sm>>1); } -inline int fuitos(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 8, Sd>>1, 10, 2|(Sm&1), Sm>>1); } inline int fsitos(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 8, Sd>>1, 10, 6|(Sm&1), Sm>>1); } -inline int ftouis(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 10, 2|(Sm&1), Sm>>1); } -inline int ftouizs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 10, 6|(Sm&1), Sm>>1); } -inline int ftosis(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 10, 2|(Sm&1), Sm>>1); } inline int ftosizs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 10, 6|(Sm&1), Sm>>1); } inline int fcpyd(int Dd, int Dm) { return COOP(AL, 0xb, 0, Dd, 11, 2, Dm); } inline int fabsd(int Dd, int Dm) { return COOP(AL, 0xb, 0, Dd, 11, 6, Dm); } @@ -179,24 +134,10 @@ inline int fnegd(int Dd, int Dm) { return COOP(AL, 0xb, 1, Dd, 11, 2, Dm); } inline int fsqrtd(int Dd, int Dm) { return COOP(AL, 0xb, 1, Dd, 11, 6, Dm); } // double-precision comparison instructions inline int fcmpd(int Dd, int Dm) { return COOP(AL, 0xb, 4, Dd, 11, 2, Dm); } -inline int fcmped(int Dd, int Dm) { return COOP(AL, 0xb, 4, Dd, 11, 6, Dm); } -inline int fcmpzd(int Dd) { return COOP(AL, 0xb, 5, Dd, 11, 2, 0); } -inline int fcmpezd(int Dd) { return COOP(AL, 0xb, 5, Dd, 11, 6, 0); } // double-precision conversion instructions inline int fcvtsd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 7, Sd>>1, 11, 6, Dm); } -inline int fuitod(int Dd, int Sm) { return COOP(AL, 0xb, 8, Dd, 11, 2|(Sm&1), Sm>>1); } inline int fsitod(int Dd, int Sm) { return COOP(AL, 0xb, 8, Dd, 11, 6|(Sm&1), Sm>>1); } -inline int ftouid(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 11, 2, Dm); } -inline int ftouizd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 11, 6, Dm); } -inline int ftosid(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 11, 2, Dm); } inline int ftosizd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 11, 6, Dm); } -// these are the multiple load/store analogs for VFP, useless for now -inline int fldms(int Rn, int Sd, int count) { return COXFER(AL, 0, 1, Sd&1, 0, 1, Rn, Sd>>1, 10, count); } -inline int fldmd(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 1, Rn, Dd, 11, count<<1); } -inline int fldmx(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 1, Rn, Dd, 11, count<<1|1); } -inline int fstms(int Rn, int Sd, int count) { return COXFER(AL, 0, 1, Sd&1, 0, 0, Rn, Sd>>1, 10, count); } -inline int fstmd(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 0, Rn, Dd, 11, count<<1); } -inline int fstmx(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 0, Rn, Dd, 11, count<<1|1); } // single load/store instructions for both precision types inline int flds(int Sd, int Rn, int offset=0) { return COXFER(AL, 1, 1, Sd&1, 0, 1, Rn, Sd>>1, 10, offset); }; inline int fldd(int Dd, int Rn, int offset=0) { return COXFER(AL, 1, 1, 0, 0, 1, Rn, Dd, 11, offset); }; @@ -205,32 +146,21 @@ inline int fstd(int Dd, int Rn, int offset=0) { return COXFER(AL, 1, 1, 0, 0, 0, // move between GPRs and FPRs inline int fmsr(int Sn, int Rd) { return mcr(10, 0, Rd, Sn>>1, 0, (Sn&1)<<2); } inline int fmrs(int Rd, int Sn) { return mrc(10, 0, Rd, Sn>>1, 0, (Sn&1)<<2); } -/* move to/from the low/high parts of double-precision registers, - seemingly redundant */ -inline int fmdlr(int Dn, int Rd) { return mcr(11, 0, Rd, Dn, 0); } -inline int fmrdl(int Rd, int Dn) { return mrc(11, 0, Rd, Dn, 0); } -inline int fmdhr(int Dn, int Rd) { return mcr(11, 1, Rd, Dn, 0); } -inline int fmrdh(int Rd, int Dn) { return mrc(11, 1, Rd, Dn, 0); } // move to/from VFP system registers -inline int fmxr(int reg, int Rd) { return mcr(10, 7, Rd, reg, 0); } inline int fmrx(int Rd, int reg) { return mrc(10, 7, Rd, reg, 0); } // these move around pairs of single-precision registers -inline int fmsrr(int Sm, int Rd, int Rn) { return mcrr(10, 1 | ((Sm&1)<<1), Rd, Rn, Sm>>1); } -inline int fmrrs(int Rd, int Rn, int Sm) { return mrrc(10, 1 | ((Sm&1)<<1), Rd, Rn, Sm>>1); } inline int fmdrr(int Dm, int Rd, int Rn) { return mcrr(11, 1, Rd, Rn, Dm); } inline int fmrrd(int Rd, int Rn, int Dm) { return mrrc(11, 1, Rd, Rn, Dm); } // FLAG SETTERS inline int SETCOND(int ins, int cond) { return ((ins&0x0fffffff) | (cond<<28)); } inline int SETS(int ins) { return ins | 1<<20; } // PSEUDO-INSTRUCTIONS -inline int nop() { return mov(0, 0); } inline int lsl(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, LSL); } inline int lsli(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSL, imm); } inline int lsr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, LSR); } inline int lsri(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSR, imm); } inline int asr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ASR); } inline int asri(int Rd, int Rm, int imm) { return mov(Rd, Rm, ASR, imm); } -inline int ror(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ROR); } inline int beq(int offset) { return SETCOND(b(offset), EQ); } inline int bne(int offset) { return SETCOND(b(offset), NE); } inline int bls(int offset) { return SETCOND(b(offset), LS); } @@ -245,35 +175,26 @@ inline int bpl(int offset) { return SETCOND(b(offset), PL); } inline int fmstat() { return fmrx(15, FPSCR); } // HARDWARE FLAGS bool vfpSupported() { - return true; // TODO + // TODO: Use at runtime detection +#if defined(__ARM_PCS_VFP) + // armhf + return true; +#else + // armel + // TODO: allow VFP use for -mfloat-abi=softfp armel builds. + // GCC -mfloat-abi=softfp flag allows use of VFP while remaining compatible + // with soft-float code. + return false; +#endif } } const uint64_t MASK_LO32 = 0xffffffff; const unsigned MASK_LO16 = 0xffff; const unsigned MASK_LO8 = 0xff; -inline unsigned lo32(int64_t i) { return (unsigned)(i&MASK_LO32); } -inline unsigned hi32(int64_t i) { return (unsigned)(i>>32); } -inline unsigned lo16(int64_t i) { return (unsigned)(i&MASK_LO16); } -inline unsigned hi16(int64_t i) { return lo16(i>>16); } inline unsigned lo8(int64_t i) { return (unsigned)(i&MASK_LO8); } -inline unsigned hi8(int64_t i) { return lo8(i>>8); } - -inline int ha16(int32_t i) { - return ((i >> 16) + ((i & 0x8000) ? 1 : 0)) & 0xffff; -} -inline int unha16(int32_t high, int32_t low) { - return ((high - ((low & 0x8000) ? 1 : 0)) << 16) | low; -} - -inline bool isInt8(target_intptr_t v) { return v == static_cast(v); } -inline bool isInt16(target_intptr_t v) { return v == static_cast(v); } -inline bool isInt24(target_intptr_t v) { return v == (v & 0xffffff); } -inline bool isInt32(target_intptr_t v) { return v == static_cast(v); } -inline int carry16(target_intptr_t v) { return static_cast(v) < 0 ? 1 : 0; } inline bool isOfWidth(int64_t i, int size) { return static_cast(i) >> size == 0; } -inline bool isOfWidth(int i, int size) { return static_cast(i) >> size == 0; } const int N_GPRS = 16; const int N_FPRS = 16; @@ -567,7 +488,7 @@ isBranch(TernaryOperation op) return op > FloatMin; } -bool +bool UNUSED isFloatBranch(TernaryOperation op) { return op > JumpIfNotEqual; @@ -634,72 +555,118 @@ write4(uint8_t* dst, uint32_t v) memcpy(dst, &v, 4); } +void +andC(Context* con, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst); + void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - int tmp1 = newTemp(con), tmp2 = newTemp(con); - emit(con, lsl(tmp1, b->high, a->low)); - emit(con, rsbi(tmp2, a->low, 32)); + int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con); + ResolvedPromise maskPromise(0x3F); + Assembler::Constant mask(&maskPromise); + Assembler::Register dst(tmp3); + andC(con, 4, &mask, a, &dst); + emit(con, lsl(tmp1, b->high, tmp3)); + emit(con, rsbi(tmp2, tmp3, 32)); emit(con, orrsh(tmp1, tmp1, b->low, tmp2, LSR)); - emit(con, SETS(subi(t->high, a->low, 32))); + emit(con, SETS(subi(t->high, tmp3, 32))); emit(con, SETCOND(mov(t->high, tmp1), MI)); emit(con, SETCOND(lsl(t->high, b->low, t->high), PL)); - emit(con, lsl(t->low, b->low, a->low)); - freeTemp(con, tmp1); freeTemp(con, tmp2); + emit(con, lsl(t->low, b->low, tmp3)); + freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3); } else { - emit(con, lsl(t->low, b->low, a->low)); + int tmp = newTemp(con); + ResolvedPromise maskPromise(0x1F); + Assembler::Constant mask(&maskPromise); + Assembler::Register dst(tmp); + andC(con, size, &mask, a, &dst); + emit(con, lsl(t->low, b->low, tmp)); + freeTemp(con, tmp); } } +void +moveRR(Context* con, unsigned srcSize, Assembler::Register* src, + unsigned dstSize, Assembler::Register* dst); + void shiftLeftC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == TargetBytesPerWord); - emit(con, lsli(t->low, b->low, getValue(a))); + if (getValue(a) & 0x1F) { + emit(con, lsli(t->low, b->low, getValue(a) & 0x1F)); + } else { + moveRR(con, size, b, size, t); + } } void shiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - int tmp1 = newTemp(con), tmp2 = newTemp(con); - emit(con, lsr(tmp1, b->low, a->low)); - emit(con, rsbi(tmp2, a->low, 32)); + int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con); + ResolvedPromise maskPromise(0x3F); + Assembler::Constant mask(&maskPromise); + Assembler::Register dst(tmp3); + andC(con, 4, &mask, a, &dst); + emit(con, lsr(tmp1, b->low, tmp3)); + emit(con, rsbi(tmp2, tmp3, 32)); emit(con, orrsh(tmp1, tmp1, b->high, tmp2, LSL)); - emit(con, SETS(subi(t->low, a->low, 32))); + emit(con, SETS(subi(t->low, tmp3, 32))); emit(con, SETCOND(mov(t->low, tmp1), MI)); emit(con, SETCOND(asr(t->low, b->high, t->low), PL)); - emit(con, asr(t->high, b->high, a->low)); - freeTemp(con, tmp1); freeTemp(con, tmp2); + emit(con, asr(t->high, b->high, tmp3)); + freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3); } else { - emit(con, asr(t->low, b->low, a->low)); + int tmp = newTemp(con); + ResolvedPromise maskPromise(0x1F); + Assembler::Constant mask(&maskPromise); + Assembler::Register dst(tmp); + andC(con, size, &mask, a, &dst); + emit(con, asr(t->low, b->low, tmp)); + freeTemp(con, tmp); } } void shiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == TargetBytesPerWord); - emit(con, asri(t->low, b->low, getValue(a))); + if (getValue(a) & 0x1F) { + emit(con, asri(t->low, b->low, getValue(a) & 0x1F)); + } else { + moveRR(con, size, b, size, t); + } } void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { - emit(con, lsr(t->low, b->low, a->low)); + int tmpShift = newTemp(con); + ResolvedPromise maskPromise(size == 8 ? 0x3F : 0x1F); + Assembler::Constant mask(&maskPromise); + Assembler::Register dst(tmpShift); + andC(con, 4, &mask, a, &dst); + emit(con, lsr(t->low, b->low, tmpShift)); if (size == 8) { int tmpHi = newTemp(con), tmpLo = newTemp(con); - emit(con, SETS(rsbi(tmpHi, a->low, 32))); + emit(con, SETS(rsbi(tmpHi, tmpShift, 32))); emit(con, lsl(tmpLo, b->high, tmpHi)); emit(con, orr(t->low, t->low, tmpLo)); - emit(con, addi(tmpHi, a->low, -32)); + emit(con, addi(tmpHi, tmpShift, -32)); emit(con, lsr(tmpLo, b->high, tmpHi)); emit(con, orr(t->low, t->low, tmpLo)); - emit(con, lsr(t->high, b->high, a->low)); + emit(con, lsr(t->high, b->high, tmpShift)); freeTemp(con, tmpHi); freeTemp(con, tmpLo); } + freeTemp(con, tmpShift); } void unsignedShiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == TargetBytesPerWord); - emit(con, lsri(t->low, b->low, getValue(a))); + if (getValue(a) & 0x1F) { + emit(con, lsri(t->low, b->low, getValue(a) & 0x1F)); + } else { + moveRR(con, size, b, size, t); + } } class ConstantPoolEntry: public Promise { @@ -909,10 +876,6 @@ jumpR(Context* con, unsigned size UNUSED, Assembler::Register* target) emit(con, bx(target->low)); } -void -moveRR(Context* con, unsigned srcSize, Assembler::Register* src, - unsigned dstSize, Assembler::Register* dst); - void swapRR(Context* con, unsigned aSize, Assembler::Register* a, unsigned bSize, Assembler::Register* b) @@ -1355,23 +1318,6 @@ moveRM(Context* con, unsigned srcSize, Assembler::Register* src, store(con, srcSize, src, dst->base, dst->offset, dst->index, dst->scale, true); } -void -moveAndUpdateRM(Context* con, unsigned srcSize UNUSED, Assembler::Register* src, - unsigned dstSize UNUSED, Assembler::Memory* dst) -{ - assert(con, srcSize == TargetBytesPerWord); - assert(con, dstSize == TargetBytesPerWord); - - if (dst->index == NoRegister) { - emit(con, stri(src->low, dst->base, dst->offset, dst->offset ? 1 : 0)); - } else { - assert(con, dst->offset == 0); - assert(con, dst->scale == 1); - - emit(con, str(src->low, dst->base, dst->index, 1)); - } -} - void load(Context* con, unsigned srcSize, int base, int offset, int index, unsigned scale, unsigned dstSize, Assembler::Register* dst, @@ -2354,7 +2300,7 @@ class MyArchitecture: public Assembler::Architecture { { *thunk = false; *aTypeMask = ~0; - *aRegisterMask = ~static_cast(0); + *aRegisterMask = GPR_MASK64; switch (op) { case Negate: @@ -2379,7 +2325,11 @@ class MyArchitecture: public Assembler::Architecture { break; case Float2Int: - if (vfpSupported() && bSize == 4) { + // todo: Java requires different semantics than SSE for + // converting floats to integers, we we need to either use + // thunks or produce inline machine code which handles edge + // cases properly. + if (false && vfpSupported() && bSize == 4) { *aTypeMask = (1 << RegisterOperand); *aRegisterMask = FPR_MASK64; } else { @@ -2407,7 +2357,7 @@ class MyArchitecture: public Assembler::Architecture { unsigned , uint8_t* bTypeMask, uint64_t* bRegisterMask) { *bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); - *bRegisterMask = ~static_cast(0); + *bRegisterMask = GPR_MASK64; switch (op) { case Negate: @@ -2538,7 +2488,7 @@ class MyArchitecture: public Assembler::Architecture { virtual void planDestination (TernaryOperation op, unsigned, uint8_t, uint64_t, - unsigned, uint8_t, const uint64_t, + unsigned, uint8_t, const uint64_t bRegisterMask, unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask) { if (isBranch(op)) { @@ -2546,7 +2496,7 @@ class MyArchitecture: public Assembler::Architecture { *cRegisterMask = 0; } else { *cTypeMask = (1 << RegisterOperand); - *cRegisterMask = ~static_cast(0); + *cRegisterMask = bRegisterMask; } } diff --git a/src/arm.h b/src/arm.h index 42fc44e8bf..15299ec762 100644 --- a/src/arm.h +++ b/src/arm.h @@ -44,7 +44,15 @@ THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) -#else // not __APPLE__ +#elif (defined __QNX__) +# include "arm/smpxchg.h" +# include "sys/mman.h" + +# define IP_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_PC]) +# define STACK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_SP]) +# define THREAD_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_IP]) +# define LINK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_LR]) +#else # define IP_REGISTER(context) (context->uc_mcontext.arm_pc) # define STACK_REGISTER(context) (context->uc_mcontext.arm_sp) # define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip) @@ -55,7 +63,8 @@ extern "C" uint64_t vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, - unsigned memoryCount, void* gprTable); + unsigned memoryCount, void* gprTable, void* vfpTable, + unsigned returnType); namespace vm { @@ -94,6 +103,8 @@ syncInstructionCache(const void* start, unsigned size) { #ifdef __APPLE__ sys_icache_invalidate(const_cast(start), size); +#elif (defined __QNX__) + msync(const_cast(start), size, MS_INVALIDATE_ICACHE); #else __clear_cache (const_cast(start), @@ -111,6 +122,8 @@ atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_) { #ifdef __APPLE__ return OSAtomicCompareAndSwap32(old, new_, reinterpret_cast(p)); +#elif (defined __QNX__) + return old == _smp_cmpxchg(p, old, new_); #else int r = __kernel_cmpxchg(static_cast(old), static_cast(new_), reinterpret_cast(p)); return (!r ? true : false); @@ -126,7 +139,7 @@ atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) inline uint64_t dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, unsigned argumentCount, unsigned argumentsSize UNUSED, - unsigned returnType UNUSED) + unsigned returnType) { #ifdef __APPLE__ const unsigned Alignment = 1; @@ -138,6 +151,11 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, uintptr_t gprTable[GprCount]; unsigned gprIndex = 0; + const unsigned VfpCount = 16; + uintptr_t vfpTable[VfpCount]; + unsigned vfpIndex = 0; + unsigned vfpBackfillIndex UNUSED = 0; + uintptr_t stack[(argumentCount * 8) / BytesPerWord]; // is > argumentSize to account for padding unsigned stackIndex = 0; @@ -145,6 +163,40 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, for (unsigned ati = 0; ati < argumentCount; ++ ati) { switch (argumentTypes[ati]) { case DOUBLE_TYPE: +#if defined(__ARM_PCS_VFP) + { + if (vfpIndex + Alignment <= VfpCount) { + if (vfpIndex % Alignment) { + vfpBackfillIndex = vfpIndex; + ++ vfpIndex; + } + + memcpy(vfpTable + vfpIndex, arguments + ai, 8); + vfpIndex += 8 / BytesPerWord; + } else { + vfpIndex = VfpCount; + if (stackIndex % Alignment) { + ++ stackIndex; + } + + memcpy(stack + stackIndex, arguments + ai, 8); + stackIndex += 8 / BytesPerWord; + } + ai += 8 / BytesPerWord; + } break; + + case FLOAT_TYPE: + if (vfpBackfillIndex) { + vfpTable[vfpBackfillIndex] = arguments[ai]; + vfpBackfillIndex = 0; + } else if (vfpIndex < VfpCount) { + vfpTable[vfpIndex++] = arguments[ai]; + } else { + stack[stackIndex++] = arguments[ai]; + } + ++ ai; + break; +#endif case INT64_TYPE: { if (gprIndex + Alignment <= GprCount) { // pass argument in register(s) if (Alignment == 1 @@ -188,11 +240,16 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, memset(gprTable + gprIndex, 0, (GprCount-gprIndex)*4); gprIndex = GprCount; } + if (vfpIndex < VfpCount) { + memset(vfpTable + vfpIndex, 0, (VfpCount-vfpIndex)*4); + vfpIndex = VfpCount; + } unsigned stackSize = stackIndex*BytesPerWord + ((stackIndex & 1) << 2); return vmNativeCall (function, stackSize, stack, stackIndex * BytesPerWord, - (gprIndex ? gprTable : 0)); + (gprIndex ? gprTable : 0), + (vfpIndex ? vfpTable : 0), returnType); } } // namespace vm diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index b4e0025b02..a2277c3488 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -198,7 +198,7 @@ public: const unsigned machine; ElfPlatform(PlatformInfo::Architecture arch): - Platform(PlatformInfo(PlatformInfo::Linux, arch)), + Platform(PlatformInfo(PlatformInfo::Elf, arch)), machine(getElfPlatform(arch)) {} class FileWriter { @@ -372,10 +372,9 @@ public: } }; -ElfPlatform elfx86Platform(PlatformInfo::x86); +ElfPlatform elfX86Platform(PlatformInfo::x86); ElfPlatform elfArmPlatform(PlatformInfo::Arm); ElfPlatform elfPowerPCPlatform(PlatformInfo::PowerPC); -ElfPlatform elfx86_64Platform(PlatformInfo::x86_64); - +ElfPlatform elfX86_64Platform(PlatformInfo::x86_64); } // namespace diff --git a/src/binaryToObject/mach-o.cpp b/src/binaryToObject/mach-o.cpp index dd89ddb304..96dd63aafd 100644 --- a/src/binaryToObject/mach-o.cpp +++ b/src/binaryToObject/mach-o.cpp @@ -286,7 +286,7 @@ public: } MachOPlatform(PlatformInfo::Architecture arch): - Platform(PlatformInfo(PlatformInfo::Darwin, arch)) {} + Platform(PlatformInfo(PlatformInfo::MachO, arch)) {} }; diff --git a/src/binaryToObject/main.cpp b/src/binaryToObject/main.cpp index 851a805bec..fe389f3d29 100644 --- a/src/binaryToObject/main.cpp +++ b/src/binaryToObject/main.cpp @@ -41,14 +41,14 @@ using namespace avian::tools; bool writeObject(uint8_t* data, size_t size, OutputStream* out, const char* startName, - const char* endName, const char* os, + const char* endName, const char* format, const char* architecture, unsigned alignment, bool writable, bool executable) { - Platform* platform = Platform::getPlatform(PlatformInfo(PlatformInfo::osFromString(os), PlatformInfo::archFromString(architecture))); + Platform* platform = Platform::getPlatform(PlatformInfo(PlatformInfo::formatFromString(format), PlatformInfo::archFromString(architecture))); if(!platform) { - fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture); + fprintf(stderr, "unsupported platform: %s/%s\n", format, architecture); return false; } diff --git a/src/binaryToObject/pe.cpp b/src/binaryToObject/pe.cpp index 69ca719bc1..8d5d5fc444 100644 --- a/src/binaryToObject/pe.cpp +++ b/src/binaryToObject/pe.cpp @@ -269,7 +269,7 @@ public: } WindowsPlatform(): - Platform(PlatformInfo(PlatformInfo::Windows, BytesPerWord == 4 ? PlatformInfo::x86 : PlatformInfo::x86_64)) {} + Platform(PlatformInfo(PlatformInfo::Pe, BytesPerWord == 4 ? PlatformInfo::x86 : PlatformInfo::x86_64)) {} }; WindowsPlatform<4> windows32Platform; diff --git a/src/binaryToObject/tools.cpp b/src/binaryToObject/tools.cpp index 3181474b94..9cc9059b93 100644 --- a/src/binaryToObject/tools.cpp +++ b/src/binaryToObject/tools.cpp @@ -85,15 +85,23 @@ void FileOutputStream::write(uint8_t byte) { 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; +PlatformInfo::Format PlatformInfo::formatFromString(const char* format) { + if (strcmp(format, "elf") == 0 + or strcmp(format, "linux") == 0 + or strcmp(format, "freebsd") == 0 + or strcmp(format, "qnx") == 0) + { + return Elf; + } else if (strcmp(format, "pe") == 0 + or strcmp(format, "windows") == 0) + { + return Pe; + } else if (strcmp(format, "macho") == 0 + or strcmp(format, "darwin") == 0) + { + return MachO; } else { - return UnknownOS; + return UnknownFormat; } } @@ -122,4 +130,5 @@ Platform* Platform::getPlatform(PlatformInfo info) { } // namespace tools -} // namespace avian \ No newline at end of file +} // namespace avian + diff --git a/src/binaryToObject/tools.h b/src/binaryToObject/tools.h index c95d22ae89..46bcd691e8 100644 --- a/src/binaryToObject/tools.h +++ b/src/binaryToObject/tools.h @@ -131,11 +131,11 @@ public: class PlatformInfo { public: - enum OperatingSystem { - Linux = AVIAN_PLATFORM_LINUX, - Windows = AVIAN_PLATFORM_WINDOWS, - Darwin = AVIAN_PLATFORM_DARWIN, - UnknownOS = AVIAN_PLATFORM_UNKNOWN + enum Format { + Elf = AVIAN_FORMAT_ELF, + Pe = AVIAN_FORMAT_PE, + MachO = AVIAN_FORMAT_MACHO, + UnknownFormat = AVIAN_FORMAT_UNKNOWN }; enum Architecture { @@ -146,18 +146,18 @@ public: UnknownArch = AVIAN_ARCH_UNKNOWN }; - const OperatingSystem os; + const Format format; const Architecture arch; - static OperatingSystem osFromString(const char* os); + static Format formatFromString(const char* format); static Architecture archFromString(const char* arch); - inline PlatformInfo(OperatingSystem os, Architecture arch): - os(os), + inline PlatformInfo(Format format, Architecture arch): + format(format), arch(arch) {} inline bool operator == (const PlatformInfo& other) { - return os == other.os && arch == other.arch; + return format == other.format && arch == other.arch; } inline bool isLittleEndian() { @@ -193,4 +193,5 @@ public: } // namespace avian -#endif \ No newline at end of file +#endif + diff --git a/src/bootimage.cpp b/src/bootimage.cpp index bfcbe2220e..492366f6c2 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -34,7 +34,7 @@ const unsigned TargetFixieSizeInBytes = 8 + (TargetBytesPerWord * 2); const unsigned TargetFixieSizeInWords = ceiling (TargetFixieSizeInBytes, TargetBytesPerWord); const unsigned TargetFixieAge = 0; -const unsigned TargetFixieHasMask = 1; +const unsigned TargetFixieFlags = 2; const unsigned TargetFixieSize = 4; const bool DebugNativeTarget = false; @@ -310,7 +310,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, if (endsWith(".class", name, nameSize) and (className == 0 or strncmp(name, className, nameSize - 6) == 0)) { - // fprintf(stderr, "%.*s\n", nameSize - 6, name); + // fprintf(stderr, "pass 1 %.*s\n", nameSize - 6, name); object c = resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "%.*s", nameSize - 6, name), true); @@ -412,8 +412,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, objectHash); } } - - // if (strcmp(name, "java/lang/System$Property.class") == 0) trap(); { object array = 0; PROTECT(t, array); @@ -441,11 +439,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, memberFields[memberIndex] = *f; - while (targetMemberOffset % f->targetSize) { - ++ targetMemberOffset; - } - - targetMemberOffset += f->targetSize; + targetMemberOffset = f->targetOffset + f->targetSize; ++ memberIndex; } @@ -458,7 +452,9 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, targetMemberOffset = TargetBytesPerWord; } - Field staticFields[count + 2]; + const unsigned StaticHeader = 3; + + Field staticFields[count + StaticHeader]; init(new (staticFields) Field, Type_object, 0, BytesPerWord, 0, TargetBytesPerWord); @@ -466,9 +462,12 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, init(new (staticFields + 1) Field, Type_intptr_t, BytesPerWord, BytesPerWord, TargetBytesPerWord, TargetBytesPerWord); - unsigned staticIndex = 2; - unsigned buildStaticOffset = BytesPerWord * 2; - unsigned targetStaticOffset = TargetBytesPerWord * 2; + init(new (staticFields + 2) Field, Type_object, BytesPerWord * 2, + BytesPerWord, TargetBytesPerWord * 2, TargetBytesPerWord); + + unsigned staticIndex = StaticHeader; + unsigned buildStaticOffset = BytesPerWord * StaticHeader; + unsigned targetStaticOffset = TargetBytesPerWord * StaticHeader; for (unsigned i = 0; i < vectorSize(t, fields); ++i) { object field = vectorBody(t, fields, i); @@ -539,9 +538,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, targetMemberOffset = pad(targetMemberOffset, TargetBytesPerWord); } } - - // if (strcmp(name, "avian/VMClass.class") == 0) trap(); - + if (hashMapFind(t, typeMaps, c, objectHash, objectEqual) == 0) { object array = makeByteArray (t, TypeMap::sizeInBytes @@ -600,7 +597,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, if (endsWith(".class", name, nameSize) and (className == 0 or strncmp(name, className, nameSize - 6) == 0)) { - // fprintf(stderr, "%.*s\n", nameSize - 6, name); + // fprintf(stderr, "pass 2 %.*s\n", nameSize - 6, name); object c = resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "%.*s", nameSize - 6, name), true); @@ -1175,13 +1172,13 @@ makeHeapImage(Thread* t, BootImage* image, target_uintptr_t* heap, memset(heap + position, 0, TargetFixieSizeInBytes); - uint8_t age = FixieTenureThreshold + 1; + uint16_t age = targetV2(FixieTenureThreshold + 1); memcpy(reinterpret_cast(heap + position) - + TargetFixieAge, &age, 1); + + TargetFixieAge, &age, 2); - uint8_t hasMask = true; + uint16_t flags = targetV2(1); memcpy(reinterpret_cast(heap + position) - + TargetFixieHasMask, &hasMask, 1); + + TargetFixieFlags, &flags, 2); uint32_t targetSize = targetV4(size); memcpy(reinterpret_cast(heap + position) @@ -1647,7 +1644,7 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp // fwrite(code, pad(image->codeSize, TargetBytesPerWord), 1, codeOutput); - Platform* platform = Platform::getPlatform(PlatformInfo((PlatformInfo::OperatingSystem)AVIAN_TARGET_PLATFORM, (PlatformInfo::Architecture)AVIAN_TARGET_ARCH)); + Platform* platform = Platform::getPlatform(PlatformInfo((PlatformInfo::Format)AVIAN_TARGET_FORMAT, (PlatformInfo::Architecture)AVIAN_TARGET_ARCH)); // if(!platform) { // fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture); diff --git a/src/builtin.cpp b/src/builtin.cpp index 9c3dca8508..845c0cebe1 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -155,7 +155,7 @@ Avian_java_lang_Runtime_exit } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength +Avian_avian_avianvmresource_Handler_00024ResourceInputStream_getContentLength (Thread* t, object, uintptr_t* arguments) { object path = reinterpret_cast(*arguments); @@ -179,7 +179,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_resource_Handler_00024ResourceInputStream_open +Avian_avian_avianvmresource_Handler_00024ResourceInputStream_open (Thread* t, object, uintptr_t* arguments) { object path = reinterpret_cast(*arguments); @@ -200,7 +200,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_resource_Handler_00024ResourceInputStream_available +Avian_avian_avianvmresource_Handler_00024ResourceInputStream_available (Thread*, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); @@ -211,7 +211,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_available } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_resource_Handler_00024ResourceInputStream_read__JI +Avian_avian_avianvmresource_Handler_00024ResourceInputStream_read__JI (Thread*, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); @@ -226,7 +226,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_read__JI } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_resource_Handler_00024ResourceInputStream_read__JI_3BII +Avian_avian_avianvmresource_Handler_00024ResourceInputStream_read__JI_3BII (Thread* t, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); @@ -251,7 +251,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_read__JI_3BII } extern "C" JNIEXPORT void JNICALL -Avian_avian_resource_Handler_00024ResourceInputStream_close +Avian_avian_avianvmresource_Handler_00024ResourceInputStream_close (Thread*, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); @@ -511,3 +511,55 @@ Avian_sun_misc_Unsafe_getAddress__J return *reinterpret_cast(p); } + +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 int64_t JNICALL +Avian_sun_misc_Unsafe_arrayBaseOffset +(Thread*, object, uintptr_t*) +{ + return ArrayBody; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_nio_FixedArrayByteBuffer_allocateFixed +(Thread* t, object, uintptr_t* arguments) +{ + int capacity = arguments[0]; + object address = reinterpret_cast(arguments[1]); + PROTECT(t, address); + + object array = allocate3 + (t, t->m->heap, Machine::FixedAllocation, ArrayBody + capacity, false); + + setObjectClass(t, array, type(t, Machine::ByteArrayType)); + byteArrayLength(t, array) = capacity; + + longArrayBody(t, address, 0) = reinterpret_cast(array) + ArrayBody; + + return reinterpret_cast(array); +} diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 5e68d2ed14..ddef6c36de 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -88,6 +88,12 @@ class MyClasspath : public Classpath { return AVIAN_CLASSPATH; } + virtual void + updatePackageMap(Thread*, object) + { + // ignore + } + virtual void dispose() { diff --git a/src/classpath-common.h b/src/classpath-common.h index d8105b9cd7..47d11343ac 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -278,7 +278,7 @@ makeStackTraceElement(Thread* t, object e) THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, class_)); replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast(&byteArrayBody(t, class_, 0))); - class_ = makeString(t, "%s", s); + class_ = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); object method = methodName(t, traceElementMethod(t, e)); PROTECT(t, method); diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index bbdb4a547e..bb505051d9 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -349,48 +349,66 @@ clearInterrupted(Thread*); class MyClasspath : public Classpath { public: - static const unsigned BufferSize = 1024; - MyClasspath(System* s, Allocator* allocator, const char* javaHome, const char* embedPrefix): allocator(allocator), ranNetOnLoad(0), ranManagementOnLoad(0) { class StringBuilder { public: - StringBuilder(System* s, char* pointer, unsigned remaining): - s(s), pointer(pointer), remaining(remaining) + StringBuilder(System* s, Allocator* allocator): + s(s), + allocator(allocator), + bufferSize(1024), + buffer(static_cast(allocator->allocate(bufferSize))), + offset(0) { } + void ensure(unsigned capacity) { + if (capacity > bufferSize) { + unsigned size = max(bufferSize * 2, capacity); + char* b = static_cast(allocator->allocate(size)); + + if (offset) { + memcpy(b, buffer, offset); + } + + allocator->free(buffer, bufferSize); + + buffer = b; + bufferSize = size; + } + } + void append(const char* append) { unsigned length = strlen(append); - expect(s, remaining > length); + ensure(offset + length + 1); - strncpy(pointer, append, remaining); + strncpy(buffer + offset, append, length + 1); - remaining -= length; - pointer += length; + offset += length; } void append(char c) { - assert(s, remaining > 1); + ensure(2); - pointer[0] = c; - pointer[1] = 0; + buffer[offset] = c; + buffer[offset + 1] = 0; - -- remaining; - ++ pointer; + ++ offset; } System* s; - char* pointer; - unsigned remaining; - } sb(s, buffer, BufferSize); + Allocator* allocator; + unsigned bufferSize; + char* buffer; + unsigned offset; + } sb(s, allocator); - this->javaHome = sb.pointer; + unsigned javaHomeOffset = sb.offset; sb.append(javaHome); sb.append('\0'); - this->classpath = sb.pointer; + unsigned classpathOffset = sb.offset; sb.append(AVIAN_CLASSPATH); sb.append(s->pathSeparator()); sb.append(javaHome); @@ -409,7 +427,7 @@ class MyClasspath : public Classpath { sb.append("/lib/resources.jar"); sb.append('\0'); - this->libraryPath = sb.pointer; + unsigned libraryPathOffset = sb.offset; sb.append(javaHome); #ifdef PLATFORM_WINDOWS sb.append("/bin"); @@ -417,21 +435,31 @@ class MyClasspath : public Classpath { sb.append("/lib"); #elif defined ARCH_x86_64 sb.append("/lib/amd64"); +#elif defined ARCH_arm + sb.append("/lib/arm"); #else // todo: handle other architectures sb.append("/lib/i386"); #endif sb.append('\0'); - - this->tzMappings = sb.pointer; + + unsigned tzMappingsOffset = sb.offset; sb.append(javaHome); sb.append("/lib/tzmappings"); - this->tzMappingsLength = sb.pointer - tzMappings; + this->tzMappingsLength = sb.offset - tzMappingsOffset; sb.append('\0'); - this->embedPrefix = sb.pointer; + unsigned embedPrefixOffset = sb.offset; sb.append(embedPrefix); - this->embedPrefixLength = sb.pointer - this->embedPrefix; + this->embedPrefixLength = sb.offset - embedPrefixOffset; + + this->javaHome = sb.buffer + javaHomeOffset; + this->classpath = sb.buffer + classpathOffset; + this->libraryPath = sb.buffer + libraryPathOffset; + this->tzMappings = sb.buffer + tzMappingsOffset; + this->embedPrefix = sb.buffer + embedPrefixOffset; + this->buffer = sb.buffer; + this->bufferSize = sb.bufferSize; } virtual object @@ -532,7 +560,7 @@ class MyClasspath : public Classpath { virtual void resolveNative(Thread* t, object method) { - if (strcmp(reinterpret_cast("sun/font/FontManager"), + if (strcmp(reinterpret_cast("sun/font/SunFontManager"), &byteArrayBody(t, className(t, methodClass(t, method)), 0)) == 0 and strcmp(reinterpret_cast("initIDs"), &byteArrayBody(t, methodName(t, method), 0)) == 0 @@ -621,6 +649,13 @@ class MyClasspath : public Classpath { t->m->processor->invoke (t, root(t, Machine::BootLoader), "java/lang/System", "initializeSystemClass", "()V", 0); + + t->m->processor->invoke + (t, root(t, Machine::BootLoader), "sun/misc/Launcher", + "getLauncher", "()Lsun/misc/Launcher;", 0); + + set(t, t->javaThread, ThreadContextClassLoader, + root(t, Machine::AppLoader)); } virtual const char* @@ -629,9 +664,51 @@ class MyClasspath : public Classpath { return classpath; } + virtual void + updatePackageMap(Thread* t, object class_) + { + PROTECT(t, class_); + + if (root(t, Machine::PackageMap) == 0) { + setRoot(t, Machine::PackageMap, makeHashMap(t, 0, 0)); + } + + object className = vm::className(t, class_); + if ('[' != byteArrayBody(t, className, 0)) { + THREAD_RUNTIME_ARRAY + (t, char, packageName, byteArrayLength(t, className)); + + char* s = reinterpret_cast(&byteArrayBody(t, className, 0)); + char* p = strrchr(s, '/'); + + if (p) { + int length = (p - s) + 1; + memcpy(RUNTIME_ARRAY_BODY(packageName), + &byteArrayBody(t, className, 0), + length); + RUNTIME_ARRAY_BODY(packageName)[length] = 0; + + object key = vm::makeByteArray(t, "%s", packageName); + + hashMapRemove + (t, root(t, Machine::PackageMap), key, byteArrayHash, + byteArrayEqual); + + object source = classSource(t, class_); + if (source == 0) { + source = vm::makeByteArray(t, "avian-dummy-package-source"); + } + + hashMapInsert + (t, root(t, Machine::PackageMap), key, source, byteArrayHash); + } + } + } + virtual void dispose() { + allocator->free(buffer, bufferSize); allocator->free(this, sizeof(*this)); } @@ -641,6 +718,8 @@ class MyClasspath : public Classpath { const char* libraryPath; const char* tzMappings; const char* embedPrefix; + char* buffer; + unsigned bufferSize; unsigned tzMappingsLength; unsigned embedPrefixLength; unsigned filePathField; @@ -655,7 +734,6 @@ class MyClasspath : public Classpath { unsigned zipEntryMethodField; bool ranNetOnLoad; bool ranManagementOnLoad; - char buffer[BufferSize]; JmmInterface jmmInterface; }; @@ -2283,11 +2361,28 @@ fieldForOffsetInClass(Thread* t, object c, unsigned offset) object fieldForOffset(Thread* t, object o, unsigned offset) { - object field = fieldForOffsetInClass(t, objectClass(t, o), offset); - if (field) { - return field; - } else { + object c = objectClass(t, o); + if (classVmFlags(t, c) & SingletonFlag) { + c = singletonObject(t, o, 0); + 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) + and fieldOffset(t, field) == offset) + { + return field; + } + } + } abort(t); + } else { + object field = fieldForOffsetInClass(t, c, offset); + if (field) { + return field; + } else { + abort(t); + } } } @@ -2311,10 +2406,13 @@ extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Class_getSuperclass (Thread* t, object, uintptr_t* arguments) { - object super = classSuper - (t, jclassVmClass(t, reinterpret_cast(arguments[0]))); - - return super ? reinterpret_cast(getJClass(t, super)) : 0; + object class_ = jclassVmClass(t, reinterpret_cast(arguments[0])); + if (classFlags(t, class_) & ACC_INTERFACE) { + return 0; + } else { + object super = classSuper(t, class_); + return super ? reinterpret_cast(getJClass(t, super)) : 0; + } } extern "C" JNIEXPORT void @@ -2394,13 +2492,6 @@ Avian_sun_misc_Unsafe_staticFieldOffset (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); } -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_arrayBaseOffset -(Thread*, object, uintptr_t*) -{ - return BytesPerWord * 2; -} - extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_arrayIndexScale (Thread* t, object, uintptr_t* arguments) @@ -2520,6 +2611,14 @@ Avian_sun_misc_Unsafe_getLong__Ljava_lang_Object_2J return cast(o, offset); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getDouble__Ljava_lang_Object_2J +(Thread* t, object method, uintptr_t* arguments) +{ + return Avian_sun_misc_Unsafe_getLong__Ljava_lang_Object_2J + (t, method, arguments); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getLongVolatile (Thread* t, object, uintptr_t* arguments) @@ -2782,32 +2881,6 @@ Avian_sun_misc_Unsafe_park 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) @@ -3002,6 +3075,8 @@ jvmInitProperties(Thread* t, uintptr_t* arguments) local::setProperty(t, method, *properties, "path.separator", ":"); # ifdef __APPLE__ local::setProperty(t, method, *properties, "os.name", "Mac OS X"); +# elif defined __FreeBSD__ + local::setProperty(t, method, *properties, "os.name", "FreeBSD"); # else // not __APPLE__ local::setProperty(t, method, *properties, "os.name", "Linux"); # endif // not __APPLE__ @@ -3019,6 +3094,14 @@ jvmInitProperties(Thread* t, uintptr_t* arguments) local::setProperty(t, method, *properties, "java.vm.vendor", "Avian Contributors"); + local::setProperty(t, method, *properties, "java.vm.name","Avian"); +#ifdef AVIAN_VERSION + local::setProperty(t, method, *properties, "java.vm.version",AVIAN_VERSION); +#endif +#ifdef AVIAN_INFO + local::setProperty(t, method, *properties, "java.vm.info",AVIAN_INFO); +#endif + local::setProperty (t, method, *properties, "java.home", static_cast(t->m->classpath)->javaHome); @@ -3128,7 +3211,7 @@ EXPORT(JVM_FreeMemory)() extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_MaxMemory)() { - return 0; + return local::globalMachine->heap->limit(); } extern "C" JNIEXPORT jint JNICALL @@ -3328,6 +3411,10 @@ jvmSleep(Thread* t, uintptr_t* arguments) { jlong milliseconds; memcpy(&milliseconds, arguments, sizeof(jlong)); + if (milliseconds <= 0) { + milliseconds = 1; + } + if (threadSleepLock(t, t->javaThread) == 0) { object lock = makeJobject(t); set(t, t->javaThread, ThreadSleepLock, lock); @@ -3516,10 +3603,37 @@ EXPORT(JVM_ClassDepth)(Thread*, jstring) { abort(); } extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_ClassLoaderDepth)(Thread*) { abort(); } -extern "C" JNIEXPORT jstring JNICALL -EXPORT(JVM_GetSystemPackage)(Thread*, jstring) +uint64_t +jvmGetSystemPackage(Thread* t, uintptr_t* arguments) { - return 0; + jstring s = reinterpret_cast(arguments[0]); + + ACQUIRE(t, t->m->classLock); + + THREAD_RUNTIME_ARRAY(t, char, chars, stringLength(t, *s) + 1); + stringChars(t, *s, RUNTIME_ARRAY_BODY(chars)); + + object key = makeByteArray(t, RUNTIME_ARRAY_BODY(chars)); + + object array = hashMapFind + (t, root(t, Machine::PackageMap), key, byteArrayHash, byteArrayEqual); + + if (array) { + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, byteArrayLength(t, array)))); + } else { + return 0; + } +} + +extern "C" JNIEXPORT jstring JNICALL +EXPORT(JVM_GetSystemPackage)(Thread* t, jstring s) +{ + uintptr_t arguments[] = { reinterpret_cast(s) }; + + return reinterpret_cast(run(t, jvmGetSystemPackage, arguments)); } uint64_t @@ -3787,7 +3901,7 @@ EXPORT(JVM_GetCallerClass)(Thread* t, int target) { ENTER(t, Thread::ActiveState); - object method = getCaller(t, target); + object method = getCaller(t, target, true); return method ? makeLocalReference (t, getJClass(t, methodClass(t, method))) : 0; @@ -4553,6 +4667,14 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments) unsigned returnCode = methodReturnCode(t, vmMethod); + THREAD_RESOURCE0(t, { + if (t->exception) { + object exception = t->exception; + t->exception = makeThrowable + (t, Machine::InvocationTargetExceptionType, 0, 0, exception); + } + }); + object result; if (args) { result = t->m->processor->invokeArray @@ -4591,6 +4713,14 @@ jvmNewInstanceFromConstructor(Thread* t, uintptr_t* arguments) (t, jclassVmClass(t, jconstructorClazz(t, *constructor))), jconstructorSlot(t, *constructor)); + THREAD_RESOURCE0(t, { + if (t->exception) { + object exception = t->exception; + t->exception = makeThrowable + (t, Machine::InvocationTargetExceptionType, 0, 0, exception); + } + }); + if (args) { t->m->processor->invokeArray(t, method, instance, *args); } else { @@ -4686,9 +4816,27 @@ extern "C" JNIEXPORT jfloat JNICALL EXPORT(JVM_ConstantPoolGetFloatAt)(Thread*, jobject, jobject, jint) { abort(); } +uint64_t +jvmConstantPoolGetDoubleAt(Thread* t, uintptr_t* arguments) +{ + jobject pool = reinterpret_cast(arguments[0]); + jint index = arguments[1]; + + double v; memcpy(&v, &singletonValue(t, *pool, index - 1), 8); + + return doubleToBits(v); +} + extern "C" JNIEXPORT jdouble JNICALL -EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread*, jobject, jobject, jint) -{ abort(); } +EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread* t, jobject, jobject pool, + jint index) +{ + uintptr_t arguments[] = { reinterpret_cast(pool), + static_cast(index) }; + + return bitsToDouble + (run(t, jvmConstantPoolGetDoubleAt, arguments)); +} extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_ConstantPoolGetStringAt)(Thread*, jobject, jobject, jint) diff --git a/src/common.h b/src/common.h index 1c45e2e855..adab2f587f 100644 --- a/src/common.h +++ b/src/common.h @@ -25,6 +25,8 @@ #ifdef _MSC_VER +#include "float.h" + // don't complain about using 'this' in member initializers: # pragma warning(disable:4355) @@ -37,6 +39,34 @@ typedef unsigned int uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; +#define strncasecmp _strnicmp + +#define FP_NAN 0 +#define FP_INFINITE 1 +#define FP_UNDEF 2 + +inline int fpclassify(double d) { + + switch(_fpclass(d)) { + case _FPCLASS_SNAN: + case _FPCLASS_QNAN: + return FP_NAN; + case _FPCLASS_PINF: + case _FPCLASS_NINF: + return FP_INFINITE; + } + return FP_UNDEF; +} + +#define INT32_MIN ((int32_t) _I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t) _I64_MIN) +#define INT64_MAX _I64_MAX + +inline int signbit(double d) { + return _copysign(1.0, d) < 0; +} + # define not ! # define or || # define and && diff --git a/src/compile-arm.S b/src/compile-arm.S index 427378c1f8..7db96279e9 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -75,7 +75,12 @@ LOCAL(vmInvoke_argumentTest): mov r8, r0 // load and call function address +#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) + mov lr, pc + bx r1 +#else blx r1 +#endif .globl GLOBAL(vmInvoke_returnAddress) .align 2 @@ -123,11 +128,18 @@ LOCAL(vmInvoke_continuationTest): ble LOCAL(vmInvoke_continuationLoop) ldr r7,[r5,#CONTINUATION_RETURN_ADDRESS_OFFSET] +#ifdef __APPLE__ + movw r11, :lower16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmInvoke_getAddress)+8)) + movt r11, :upper16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmInvoke_getAddress)+8)) +LOCAL(vmInvoke_getAddress): + add r11, pc, r11 +#else // not __APPLE__ ldr r10,LOCAL(vmInvoke_returnAddress_word) ldr r11,LOCAL(vmInvoke_getAddress_word) LOCAL(vmInvoke_getAddress): add r11,pc,r11 ldr r11,[r11,r10] +#endif // not __APPLE__ str r11,[sp,r7] ldr r7,[r5,#CONTINUATION_NEXT] @@ -210,23 +222,34 @@ LOCAL(vmJumpAndInvoke_argumentTest): mov sp,r2 // set return address to vmInvoke_returnAddress +#ifdef __APPLE__ + movw r11, :lower16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmJumpAndInvoke_getAddress)+8)) + movt r11, :upper16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmJumpAndInvoke_getAddress)+8)) +LOCAL(vmJumpAndInvoke_getAddress): + add r11, pc, r11 +#else // not __APPLE__ + ldr r10,LOCAL(vmInvoke_returnAddress_word) ldr r11,LOCAL(vmJumpAndInvoke_getAddress_word) LOCAL(vmJumpAndInvoke_getAddress): add r11,pc,r11 +#endif // not __APPLE__ ldr lr,[r11,r10] bx r1 +#ifndef __APPLE__ LOCAL(vmInvoke_returnAddress_word): .word GLOBAL(vmInvoke_returnAddress)(GOT) LOCAL(vmInvoke_getAddress_word): .word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmInvoke_getAddress)+8) LOCAL(vmJumpAndInvoke_getAddress_word): .word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmJumpAndInvoke_getAddress)+8) +#endif // not __APPLE__ #else // not AVIAN_CONTINUATIONS // vmJumpAndInvoke should only be called when continuations are - // enabled - bkpt + // enabled, so we force a crash if we reach here: + mov r1,#0 + ldr r1,[r1] #endif // not AVIAN_CONTINUATIONS diff --git a/src/compile.cpp b/src/compile.cpp index 166468dcec..86432bb131 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -202,6 +202,17 @@ class MyThread: public Thread { bool methodIsMostRecent; }; + class ReferenceFrame { + public: + ReferenceFrame(ReferenceFrame* next, Reference* reference): + next(next), + reference(reference) + { } + + ReferenceFrame* next; + Reference* reference; + }; + static void doTransition(MyThread* t, void* ip, void* stack, object continuation, MyThread::CallTrace* trace) { @@ -255,6 +266,7 @@ class MyThread: public Thread { transition(0), traceContext(0), stackLimit(0), + referenceFrame(0), methodLockIsClean(true) { arch->acquire(); @@ -280,6 +292,7 @@ class MyThread: public Thread { Context* transition; TraceContext* traceContext; uintptr_t stackLimit; + ReferenceFrame* referenceFrame; bool methodLockIsClean; }; @@ -1375,6 +1388,10 @@ class Frame { } ~Frame() { + dispose(); + } + + void dispose() { if (level > 1) { context->eventLog.append(PopContextEvent); } @@ -2574,13 +2591,25 @@ doubleToFloat(int64_t a) int64_t doubleToInt(int64_t a) { - return static_cast(bitsToDouble(a)); + double f = bitsToDouble(a); + switch (fpclassify(f)) { + case FP_NAN: return 0; + case FP_INFINITE: return signbit(f) ? INT32_MIN : INT32_MAX; + default: return f >= INT32_MAX ? INT32_MAX + : (f <= INT32_MIN ? INT32_MIN : static_cast(f)); + } } int64_t doubleToLong(int64_t a) { - return static_cast(bitsToDouble(a)); + double f = bitsToDouble(a); + switch (fpclassify(f)) { + case FP_NAN: return 0; + case FP_INFINITE: return signbit(f) ? INT64_MIN : INT64_MAX; + default: return f >= INT64_MAX ? INT64_MAX + : (f <= INT64_MIN ? INT64_MIN : static_cast(f)); + } } uint64_t @@ -2722,13 +2751,24 @@ floatToDouble(int32_t a) int64_t floatToInt(int32_t a) { - return static_cast(bitsToFloat(a)); + float f = bitsToFloat(a); + switch (fpclassify(f)) { + case FP_NAN: return 0; + case FP_INFINITE: return signbit(f) ? INT32_MIN : INT32_MAX; + default: return f >= INT32_MAX ? INT32_MAX + : (f <= INT32_MIN ? INT32_MIN : static_cast(f)); + } } int64_t floatToLong(int32_t a) { - return static_cast(bitsToFloat(a)); + float f = bitsToFloat(a); + switch (fpclassify(f)) { + case FP_NAN: return 0; + case FP_INFINITE: return signbit(f) ? INT64_MIN : INT64_MAX; + default: return static_cast(f); + } } uint64_t @@ -3708,21 +3748,10 @@ isReferenceTailCall(MyThread* t, object code, unsigned ip, object caller, (t, code, ip, caller, methodReferenceReturnCode(t, calleeReference)); } -void -compile(MyThread* t, Frame* initialFrame, unsigned ip, - int exceptionHandlerStart = -1); - -void -saveStateAndCompile(MyThread* t, Frame* initialFrame, unsigned ip) -{ - Compiler::State* state = initialFrame->c->saveState(); - compile(t, initialFrame, ip); - initialFrame->c->restoreState(state); -} - bool integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip, - unsigned size, Compiler::Operand* a, Compiler::Operand* b) + unsigned size, Compiler::Operand* a, Compiler::Operand* b, + unsigned* newIpp) { if (ip + 3 > codeLength(t, code)) { return false; @@ -3766,14 +3795,14 @@ integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip, return false; } - saveStateAndCompile(t, frame, newIp); + *newIpp = newIp; return true; } bool floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip, unsigned size, bool lessIfUnordered, Compiler::Operand* a, - Compiler::Operand* b) + Compiler::Operand* b, unsigned* newIpp) { if (ip + 3 > codeLength(t, code)) { return false; @@ -3833,7 +3862,7 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip, return false; } - saveStateAndCompile(t, frame, newIp); + *newIpp = newIp; return true; } @@ -4007,17 +4036,126 @@ targetFieldOffset(Context* context, object field) } } +class Stack { + public: + class MyResource: public Thread::Resource { + public: + MyResource(Stack* s): Resource(s->thread), s(s) { } + + virtual void release() { + s->zone.dispose(); + } + + Stack* s; + }; + + Stack(MyThread* t): + thread(t), + zone(t->m->system, t->m->heap, 0), + resource(this) + { } + + ~Stack() { + zone.dispose(); + } + + void pushValue(uintptr_t v) { + *static_cast(push(BytesPerWord)) = v; + } + + uintptr_t peekValue(unsigned offset) { + return *static_cast(peek((offset + 1) * BytesPerWord)); + } + + uintptr_t popValue() { + uintptr_t v = peekValue(0); + pop(BytesPerWord); + return v; + } + + void* push(unsigned size) { + return zone.allocate(size); + } + + void* peek(unsigned size) { + return zone.peek(size); + } + + void pop(unsigned size) { + zone.pop(size); + } + + MyThread* thread; + Zone zone; + MyResource resource; +}; + +class SwitchState { + public: + SwitchState(Compiler::State* state, + unsigned count, + unsigned defaultIp, + Compiler::Operand* key, + Promise* start, + int bottom, + int top): + state(state), + count(count), + defaultIp(defaultIp), + key(key), + start(start), + bottom(bottom), + top(top), + index(0) + { } + + Frame* frame() { + return reinterpret_cast + (reinterpret_cast(this) - pad(count * 4) - pad(sizeof(Frame))); + } + + uint32_t* ipTable() { + return reinterpret_cast + (reinterpret_cast(this) - pad(count * 4)); + } + + Compiler::State* state; + unsigned count; + unsigned defaultIp; + Compiler::Operand* key; + Promise* start; + int bottom; + int top; + unsigned index; +}; + void -compile(MyThread* t, Frame* initialFrame, unsigned ip, - int exceptionHandlerStart) +compile(MyThread* t, Frame* initialFrame, unsigned initialIp, + int exceptionHandlerStart = -1) { - THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap, - codeMaxStack(t, methodCode(t, initialFrame->context->method))); - Frame myFrame(initialFrame, RUNTIME_ARRAY_BODY(stackMap)); - Frame* frame = &myFrame; + enum { + Return, + Unbranch, + Unsubroutine, + Untable0, + Untable1, + Unswitch + }; + + Frame* frame = initialFrame; Compiler* c = frame->c; Context* context = frame->context; + unsigned stackSize = codeMaxStack(t, methodCode(t, context->method)); + Stack stack(t); + unsigned ip = initialIp; + unsigned newIp; + stack.pushValue(Return); + start: + uint8_t* stackMap = static_cast(stack.push(stackSize)); + frame = new (stack.push(sizeof(Frame))) Frame(frame, stackMap); + + loop: object code = methodCode(t, context->method); PROTECT(t, code); @@ -4025,7 +4163,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (context->visitTable[ip] ++) { // we've already visited this part of the code frame->visitLogicalIp(ip); - return; + goto next; } frame->startLogicalIp(ip); @@ -4282,7 +4420,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case areturn: { handleExit(t, frame); c->return_(TargetBytesPerWord, frame->popObject()); - } return; + } goto next; case arraylength: { frame->pushInt @@ -4327,7 +4465,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (ip == codeLength(t, code)) { c->trap(); } - } return; + } goto next; case bipush: frame->pushInt @@ -4391,7 +4529,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); - if (not floatBranch(t, frame, code, ip, 8, false, a, b)) { + if (floatBranch(t, frame, code, ip, 8, false, a, b, &newIp)) { + goto branch; + } else { frame->pushInt (c->call (c->constant @@ -4406,7 +4546,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); - if (not floatBranch(t, frame, code, ip, 8, true, a, b)) { + if (floatBranch(t, frame, code, ip, 8, true, a, b, &newIp)) { + goto branch; + } else { frame->pushInt (c->call (c->constant @@ -4504,7 +4646,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); - if (not floatBranch(t, frame, code, ip, 4, false, a, b)) { + if (floatBranch(t, frame, code, ip, 4, false, a, b, &newIp)) { + goto branch; + } else { frame->pushInt (c->call (c->constant @@ -4517,7 +4661,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); - if (not floatBranch(t, frame, code, ip, 4, true, a, b)) { + if (floatBranch(t, frame, code, ip, 4, true, a, b, &newIp)) { + goto branch; + } else { frame->pushInt (c->call (c->constant @@ -4851,7 +4997,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case if_acmpeq: case if_acmpne: { uint32_t offset = codeReadInt16(t, code, ip); - uint32_t newIp = (ip - 3) + offset; + newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); Compiler::Operand* a = frame->popObject(); @@ -4863,9 +5009,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } else { c->jumpIfNotEqual(TargetBytesPerWord, a, b, target); } - - saveStateAndCompile(t, frame, newIp); - } break; + } goto branch; case if_icmpeq: case if_icmpne: @@ -4874,7 +5018,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case if_icmplt: case if_icmple: { uint32_t offset = codeReadInt16(t, code, ip); - uint32_t newIp = (ip - 3) + offset; + newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); Compiler::Operand* a = frame->popInt(); @@ -4903,9 +5047,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, default: abort(t); } - - saveStateAndCompile(t, frame, newIp); - } break; + } goto branch; case ifeq: case ifne: @@ -4914,7 +5056,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case iflt: case ifle: { uint32_t offset = codeReadInt16(t, code, ip); - uint32_t newIp = (ip - 3) + offset; + newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); Compiler::Operand* target = frame->machineIp(newIp); @@ -4944,14 +5086,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, default: abort(t); } - - saveStateAndCompile(t, frame, newIp); - } break; + } goto branch; case ifnull: case ifnonnull: { uint32_t offset = codeReadInt16(t, code, ip); - uint32_t newIp = (ip - 3) + offset; + newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); Compiler::Operand* a = c->constant(0, Compiler::ObjectType); @@ -4963,9 +5103,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } else { c->jumpIfNotEqual(TargetBytesPerWord, a, b, target); } - - saveStateAndCompile(t, frame, newIp); - } break; + } goto branch; case iinc: { uint8_t index = codeBody(t, code, ip++); @@ -5028,21 +5166,18 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object argument; Thunk thunk; - TraceElement* trace; if (LIKELY(class_)) { argument = class_; thunk = instanceOf64Thunk; - trace = 0; } else { argument = makePair(t, context->method, reference); thunk = instanceOfFromReferenceThunk; - trace = frame->trace(0, 0); } frame->pushInt (c->call (c->constant(getThunk(t, thunk), Compiler::AddressType), - 0, trace, 4, Compiler::IntegerType, + 0, frame->trace(0, 0), 4, Compiler::IntegerType, 3, c->register_(t->arch->thread()), frame->append(argument), instance)); } break; @@ -5265,7 +5400,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case freturn: { handleExit(t, frame); c->return_(4, frame->popInt()); - } return; + } goto next; case ishl: { Compiler::Operand* a = frame->popInt(); @@ -5325,7 +5460,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case jsr: case jsr_w: { uint32_t thisIp; - uint32_t newIp; if (instruction == jsr) { uint32_t offset = codeReadInt16(t, code, ip); @@ -5343,10 +5477,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->jmp(frame->machineIp(newIp)); - saveStateAndCompile(t, frame, newIp); - - frame->endSubroutine(start); - } break; + stack.pushValue(start); + stack.pushValue(ip); + stack.pushValue(Unsubroutine); + ip = newIp; + } goto start; case l2d: { frame->pushLong(c->i2f(8, 8, frame->popLong())); @@ -5376,7 +5511,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); - if (not integerBranch(t, frame, code, ip, 8, a, b)) { + if (integerBranch(t, frame, code, ip, 8, a, b, &newIp)) { + goto branch; + } else { frame->pushInt (c->call (c->constant @@ -5534,14 +5671,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, (frame->addressPromise(c->machineIp(defaultIp))); Promise* start = 0; - THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, pairCount); + uint32_t* ipTable = static_cast + (stack.push(sizeof(uint32_t) * pairCount)); for (int32_t i = 0; i < pairCount; ++i) { unsigned index = ip + (i * 8); int32_t key = codeReadInt32(t, code, index); uint32_t newIp = base + codeReadInt32(t, code, index); assert(t, newIp < codeLength(t, code)); - RUNTIME_ARRAY_BODY(ipTable)[i] = newIp; + ipTable[i] = newIp; Promise* p = c->poolAppend(key); if (i == 0) { @@ -5565,19 +5703,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, TARGET_THREAD_CODEIMAGE), address) : address); - Compiler::State* state = c->saveState(); + new (stack.push(sizeof(SwitchState))) SwitchState + (c->saveState(), pairCount, defaultIp, 0, 0, 0, 0); - for (int32_t i = 0; i < pairCount; ++i) { - compile(t, frame, RUNTIME_ARRAY_BODY(ipTable)[i]); - - c->restoreState(state); - } + goto switchloop; } else { // a switch statement with no cases, apparently c->jmp(frame->machineIp(defaultIp)); + ip = defaultIp; } - - ip = defaultIp; } break; case lor: { @@ -5602,7 +5736,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case dreturn: { handleExit(t, frame); c->return_(8, frame->popLong()); - } return; + } goto next; case lshl: { Compiler::Operand* a = frame->popInt(); @@ -6029,7 +6163,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case ret: { unsigned index = codeBody(t, code, ip); frame->returnFromSubroutine(index); - } return; + } goto next; case return_: if (needsReturnBarrier(t, context->method)) { @@ -6038,7 +6172,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, handleExit(t, frame); c->return_(0, 0); - return; + goto next; case sipush: frame->pushInt @@ -6063,13 +6197,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, int32_t top = codeReadInt32(t, code, ip); Promise* start = 0; - THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, top - bottom + 1); + unsigned count = top - bottom + 1; + uint32_t* ipTable = static_cast + (stack.push(sizeof(uint32_t) * count)); for (int32_t i = 0; i < top - bottom + 1; ++i) { unsigned index = ip + (i * 4); uint32_t newIp = base + codeReadInt32(t, code, index); assert(t, newIp < codeLength(t, code)); - RUNTIME_ARRAY_BODY(ipTable)[i] = newIp; + ipTable[i] = newIp; Promise* p = c->poolAppendPromise (frame->addressPromise(c->machineIp(newIp))); @@ -6086,43 +6222,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->save(1, key); - saveStateAndCompile(t, frame, defaultIp); - - c->jumpIfGreater(4, c->constant(top, Compiler::IntegerType), key, - frame->machineIp(defaultIp)); - - c->save(1, key); - - saveStateAndCompile(t, frame, defaultIp); - - Compiler::Operand* normalizedKey - = (bottom - ? c->sub(4, c->constant(bottom, Compiler::IntegerType), key) : key); - - Compiler::Operand* entry = c->memory - (frame->absoluteAddressOperand(start), Compiler::AddressType, 0, - normalizedKey, TargetBytesPerWord); - - c->jmp - (c->load - (TargetBytesPerWord, TargetBytesPerWord, context->bootContext - ? c->add - (TargetBytesPerWord, c->memory - (c->register_(t->arch->thread()), Compiler::AddressType, - TARGET_THREAD_CODEIMAGE), entry) - : entry, - TargetBytesPerWord)); - - Compiler::State* state = c->saveState(); - - for (int32_t i = 0; i < top - bottom + 1; ++i) { - compile(t, frame, RUNTIME_ARRAY_BODY(ipTable)[i]); - - c->restoreState(state); - } + new (stack.push(sizeof(SwitchState))) SwitchState + (c->saveState(), count, defaultIp, key, start, bottom, top); + stack.pushValue(Untable0); ip = defaultIp; - } break; + } goto start; case wide: { switch (codeBody(t, code, ip++)) { @@ -6166,7 +6271,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned index = codeReadInt16(t, code, ip); c->jmp(loadLocal(context, 1, index)); frame->returnFromSubroutine(index); - } return; + } goto next; default: abort(t); } @@ -6175,6 +6280,113 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, default: abort(t); } } + + next: + frame->dispose(); + frame = 0; + stack.pop(sizeof(Frame)); + stack.pop(stackSize); + switch (stack.popValue()) { + case Return: + return; + + case Unbranch: + ip = stack.popValue(); + c->restoreState(reinterpret_cast(stack.popValue())); + frame = static_cast(stack.peek(sizeof(Frame))); + goto loop; + + case Untable0: { + SwitchState* s = static_cast + (stack.peek(sizeof(SwitchState))); + + frame = s->frame(); + + c->restoreState(s->state); + + c->jumpIfGreater(4, c->constant(s->top, Compiler::IntegerType), s->key, + frame->machineIp(s->defaultIp)); + + c->save(1, s->key); + ip = s->defaultIp; + stack.pushValue(Untable1); + } goto start; + + case Untable1: { + SwitchState* s = static_cast + (stack.peek(sizeof(SwitchState))); + + frame = s->frame(); + + c->restoreState(s->state); + + Compiler::Operand* normalizedKey + = (s->bottom + ? c->sub(4, c->constant(s->bottom, Compiler::IntegerType), s->key) + : s->key); + + Compiler::Operand* entry = c->memory + (frame->absoluteAddressOperand(s->start), Compiler::AddressType, 0, + normalizedKey, TargetBytesPerWord); + + c->jmp + (c->load + (TargetBytesPerWord, TargetBytesPerWord, context->bootContext + ? c->add + (TargetBytesPerWord, c->memory + (c->register_(t->arch->thread()), Compiler::AddressType, + TARGET_THREAD_CODEIMAGE), entry) + : entry, + TargetBytesPerWord)); + + s->state = c->saveState(); + } goto switchloop; + + case Unswitch: { + SwitchState* s = static_cast + (stack.peek(sizeof(SwitchState))); + + frame = s->frame(); + + c->restoreState + (static_cast(stack.peek(sizeof(SwitchState)))->state); + } goto switchloop; + + case Unsubroutine: { + ip = stack.popValue(); + unsigned start = stack.popValue(); + frame = reinterpret_cast(stack.peek(sizeof(Frame))); + frame->endSubroutine(start); + } goto loop; + + default: + abort(t); + } + + switchloop: { + SwitchState* s = static_cast + (stack.peek(sizeof(SwitchState))); + + if (s->index < s->count) { + ip = s->ipTable()[s->index++]; + stack.pushValue(Unswitch); + goto start; + } else { + ip = s->defaultIp; + unsigned count = s->count * 4; + stack.pop(sizeof(SwitchState)); + stack.pop(count); + frame = reinterpret_cast(stack.peek(sizeof(Frame))); + goto loop; + } + } + + branch: + stack.pushValue(reinterpret_cast(c->saveState())); + stack.pushValue(ip); + stack.pushValue(Unbranch); + ip = newIp; + goto start; } FILE* compileLog = 0; @@ -8778,6 +8990,32 @@ class MyProcessor: public Processor { } } + virtual bool + pushLocalFrame(Thread* vmt, unsigned) + { + MyThread* t = static_cast(vmt); + + t->referenceFrame = new + (t->m->heap->allocate(sizeof(MyThread::ReferenceFrame))) + MyThread::ReferenceFrame(t->referenceFrame, t->reference); + + return true; + } + + virtual void + popLocalFrame(Thread* vmt) + { + MyThread* t = static_cast(vmt); + + MyThread::ReferenceFrame* f = t->referenceFrame; + t->referenceFrame = f->next; + while (t->reference != f->reference) { + vm::dispose(t, t->reference); + } + + t->m->heap->free(f, sizeof(MyThread::ReferenceFrame)); + } + virtual object invokeArray(Thread* t, object method, object this_, object arguments) { diff --git a/src/environment.h b/src/environment.h index 045eb2642d..f24150cd0f 100644 --- a/src/environment.h +++ b/src/environment.h @@ -11,18 +11,18 @@ #ifndef AVIAN_ENVIRONMENT_H #define AVIAN_ENVIRONMENT_H -#ifndef AVIAN_TARGET_PLATFORM -#error build system should have defined AVIAN_TARGET_PLATFORM +#ifndef AVIAN_TARGET_FORMAT +#error build system should have defined AVIAN_TARGET_FORMAT #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_FORMAT_UNKNOWN 0 +#define AVIAN_FORMAT_ELF 1 +#define AVIAN_FORMAT_PE 2 +#define AVIAN_FORMAT_MACHO 3 #define AVIAN_ARCH_UNKNOWN 0 #define AVIAN_ARCH_X86 (1 << 8) @@ -30,4 +30,5 @@ #define AVIAN_ARCH_ARM (3 << 8) #define AVIAN_ARCH_POWERPC (4 << 8) -#endif \ No newline at end of file +#endif + diff --git a/src/finder.cpp b/src/finder.cpp index ba8aef75f4..bfe6214a9e 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -602,7 +602,7 @@ class BuiltinElement: public JarElement { } virtual const char* urlPrefix() { - return "resource:"; + return "avianvmresource:"; } virtual const char* sourceUrl() { diff --git a/src/heap.cpp b/src/heap.cpp index ed5d8777d4..2dc23e904e 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -463,12 +463,15 @@ class Segment { class Fixie { public: + static const unsigned HasMask = 1 << 0; + static const unsigned Marked = 1 << 1; + static const unsigned Dirty = 1 << 2; + static const unsigned Dead = 1 << 3; + Fixie(Context* c, unsigned size, bool hasMask, Fixie** handle, bool immortal): age(immortal ? FixieTenureThreshold + 1 : 0), - hasMask(hasMask), - marked(false), - dirty(false), + flags(hasMask ? HasMask : 0), size(size), next(0), handle(0) @@ -536,16 +539,54 @@ class Fixie { } unsigned totalSize() { - return totalSize(size, hasMask); + return totalSize(size, hasMask()); + } + + bool hasMask() { + return (flags & HasMask) != 0; + } + + bool marked() { + return (flags & Marked) != 0; + } + + void marked(bool v) { + if (v) { + flags |= Marked; + } else { + flags &= ~Marked; + } + } + + bool dirty() { + return (flags & Dirty) != 0; + } + + void dirty(bool v) { + if (v) { + flags |= Dirty; + } else { + flags &= ~Dirty; + } + } + + bool dead() { + return (flags & Dead) != 0; + } + + void dead(bool v) { + if (v) { + flags |= Dead; + } else { + flags &= ~Dead; + } } // be sure to update e.g. TargetFixieSizeInBytes in bootimage.cpp if // you add/remove/change fields in this class: - uint8_t age; - uint8_t hasMask; - uint8_t marked; - uint8_t dirty; + uint16_t age; + uint16_t flags; uint32_t size; Fixie* next; Fixie** handle; @@ -850,11 +891,11 @@ free(Context* c, Fixie** fixies, bool resetImmortal) fprintf(stderr, "reset immortal fixie %p\n", f); } *p = f->next; - memset(f->mask(), 0, Fixie::maskSize(f->size, f->hasMask)); + memset(f->mask(), 0, Fixie::maskSize(f->size, f->hasMask())); f->next = 0; f->handle = 0; - f->marked = false; - f->dirty = false; + f->marked(false); + f->dirty(false); } else { p = &(f->next); } @@ -868,6 +909,28 @@ free(Context* c, Fixie** fixies, bool resetImmortal) } } +void +kill(Fixie* fixies) +{ + for (Fixie* f = fixies; f; f = f->next) { + if (! f->immortal()) { + f->dead(true); + } + } +} + +void +killFixies(Context* c) +{ + assert(c, c->markedFixies == 0); + + if (c->mode == Heap::MajorCollection) { + kill(c->tenuredFixies); + kill(c->dirtyTenuredFixies); + } + kill(c->fixies); +} + void sweepFixies(Context* c) { @@ -898,14 +961,14 @@ sweepFixies(Context* c) if (f->age >= FixieTenureThreshold) { if (DebugFixies) { - fprintf(stderr, "tenure fixie %p (dirty: %d)\n", f, f->dirty); + fprintf(stderr, "tenure fixie %p (dirty: %d)\n", f, f->dirty()); } if (not f->immortal()) { c->tenuredFixieFootprint += f->totalSize(); } - if (f->dirty) { + if (f->dirty()) { f->add(c, &(c->dirtyTenuredFixies)); } else { f->add(c, &(c->tenuredFixies)); @@ -916,7 +979,7 @@ sweepFixies(Context* c) f->add(c, &(c->fixies)); } - f->marked = false; + f->marked(false); } c->tenuredFixieCeiling = max @@ -1006,14 +1069,15 @@ update3(Context* c, void* o, bool* needsVisit) { if (c->client->isFixed(o)) { Fixie* f = fixie(o); - if ((not f->marked) + if ((not f->marked()) and (c->mode == Heap::MajorCollection or f->age < FixieTenureThreshold)) { if (DebugFixies) { fprintf(stderr, "mark fixie %p\n", f); } - f->marked = true; + f->marked(true); + f->dead(false); f->move(c, &(c->markedFixies)); } *needsVisit = false; @@ -1044,13 +1108,13 @@ update2(Context* c, void* o, bool* needsVisit) void markDirty(Context* c, Fixie* f) { - if (not f->dirty) { + if (not f->dirty()) { #ifdef USE_ATOMIC_OPERATIONS ACQUIRE(c->lock); #endif - if (not f->dirty) { - f->dirty = true; + if (not f->dirty()) { + f->dirty(true); f->move(c, &(c->dirtyTenuredFixies)); } } @@ -1059,8 +1123,8 @@ markDirty(Context* c, Fixie* f) void markClean(Context* c, Fixie* f) { - if (f->dirty) { - f->dirty = false; + if (f->dirty()) { + f->dirty(false); if (f->immortal()) { f->remove(c); } else { @@ -1090,7 +1154,7 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result) { if (target and c->client->isFixed(target)) { Fixie* f = fixie(target); - assert(c, offset == 0 or f->hasMask); + assert(c, offset == 0 or f->hasMask()); if (static_cast(f->age + 1) >= FixieTenureThreshold) { if (DebugFixies) { @@ -1098,7 +1162,7 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result) f, offset, f->body() + offset, result); } - f->dirty = true; + f->dirty(true); markBit(f->mask(), offset); } } else if (seg->contains(p)) { @@ -1804,6 +1868,10 @@ class MyHeap: public Heap { c.immortalHeapEnd = start + sizeInWords; } + virtual unsigned limit() { + return c.limit; + } + virtual bool limitExceeded() { return c.count > c.limit; } @@ -1871,7 +1939,7 @@ class MyHeap: public Heap { if (c.client->isFixed(p)) { Fixie* f = fixie(p); - assert(&c, offset == 0 or f->hasMask); + assert(&c, offset == 0 or f->hasMask()); bool dirty = false; for (unsigned i = 0; i < count; ++i) { @@ -1946,11 +2014,22 @@ class MyHeap: public Heap { } } + virtual void postVisit() { + killFixies(&c); + } + virtual Status status(void* p) { p = mask(p); if (p == 0) { return Null; + } else if (c.client->isFixed(p)) { + Fixie* f = fixie(p); + return f->dead() + ? Unreachable + : (static_cast(f->age + 1) < FixieTenureThreshold + ? Reachable + : Tenured); } else if (c.nextGen1.contains(p)) { return Reachable; } else if (c.nextGen2.contains(p) diff --git a/src/heap.h b/src/heap.h index 875b4a5cbc..0ee4699914 100644 --- a/src/heap.h +++ b/src/heap.h @@ -59,6 +59,7 @@ class Heap: public Allocator { virtual void setClient(Client* client) = 0; virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0; + virtual unsigned limit() = 0; virtual bool limitExceeded() = 0; virtual void collect(CollectionType type, unsigned footprint) = 0; virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords, @@ -69,6 +70,7 @@ class Heap: public Allocator { virtual void mark(void* p, unsigned offset, unsigned count) = 0; virtual void pad(void* p) = 0; virtual void* follow(void* p) = 0; + virtual void postVisit() = 0; virtual Status status(void* p) = 0; virtual CollectionType collectionType() = 0; virtual void disposeFixies() = 0; diff --git a/src/interpret.cpp b/src/interpret.cpp index 9f28a2f769..543363a7d3 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -28,18 +28,31 @@ const unsigned FrameFootprint = 4; class Thread: public vm::Thread { public: + class ReferenceFrame { + public: + ReferenceFrame(ReferenceFrame* next, unsigned sp): + next(next), + sp(sp) + { } + + ReferenceFrame* next; + unsigned sp; + }; + Thread(Machine* m, object javaThread, vm::Thread* parent): vm::Thread(m, javaThread, parent), ip(0), sp(0), frame(-1), - code(0) + code(0), + referenceFrame(0) { } unsigned ip; unsigned sp; int frame; object code; + ReferenceFrame* referenceFrame; uintptr_t stack[0]; }; @@ -1065,11 +1078,27 @@ interpret3(Thread* t, const int base) } goto loop; case d2i: { - pushInt(t, static_cast(popDouble(t))); + double f = popDouble(t); + switch (fpclassify(f)) { + case FP_NAN: pushInt(t, 0); break; + case FP_INFINITE: pushInt(t, signbit(f) ? INT32_MIN : INT32_MAX); break; + default: pushInt + (t, f >= INT32_MAX ? INT32_MAX + : (f <= INT32_MIN ? INT32_MIN : static_cast(f))); + break; + } } goto loop; case d2l: { - pushLong(t, static_cast(popDouble(t))); + double f = popDouble(t); + switch (fpclassify(f)) { + case FP_NAN: pushLong(t, 0); break; + case FP_INFINITE: pushLong(t, signbit(f) ? INT64_MIN : INT64_MAX); break; + default: pushLong + (t, f >= INT64_MAX ? INT64_MAX + : (f <= INT64_MIN ? INT64_MIN : static_cast(f))); + break; + } } goto loop; case dadd: { @@ -1265,11 +1294,24 @@ interpret3(Thread* t, const int base) } goto loop; case f2i: { - pushInt(t, static_cast(popFloat(t))); + float f = popFloat(t); + switch (fpclassify(f)) { + case FP_NAN: pushInt(t, 0); break; + case FP_INFINITE: pushInt(t, signbit(f) ? INT32_MIN : INT32_MAX); break; + default: pushInt(t, f >= INT32_MAX ? INT32_MAX + : (f <= INT32_MIN ? INT32_MIN : static_cast(f))); + break; + } } goto loop; case f2l: { - pushLong(t, static_cast(popFloat(t))); + float f = popFloat(t); + switch (fpclassify(f)) { + case FP_NAN: pushLong(t, 0); break; + case FP_INFINITE: pushLong(t, signbit(f) ? INT64_MIN : INT64_MAX); + break; + default: pushLong(t, static_cast(f)); break; + } } goto loop; case fadd: { @@ -1888,14 +1930,14 @@ interpret3(Thread* t, const int base) int32_t b = popInt(t); int32_t a = popInt(t); - pushInt(t, a << b); + pushInt(t, a << (b & 0x1F)); } goto loop; case ishr: { int32_t b = popInt(t); int32_t a = popInt(t); - pushInt(t, a >> b); + pushInt(t, a >> (b & 0x1F)); } goto loop; case istore: @@ -1934,7 +1976,7 @@ interpret3(Thread* t, const int base) int32_t b = popInt(t); uint32_t a = popInt(t); - pushInt(t, a >> b); + pushInt(t, a >> (b & 0x1F)); } goto loop; case ixor: { @@ -2196,14 +2238,14 @@ interpret3(Thread* t, const int base) int32_t b = popInt(t); int64_t a = popLong(t); - pushLong(t, a << b); + pushLong(t, a << (b & 0x3F)); } goto loop; case lshr: { int32_t b = popInt(t); int64_t a = popLong(t); - pushLong(t, a >> b); + pushLong(t, a >> (b & 0x3F)); } goto loop; case lstore: @@ -2242,7 +2284,7 @@ interpret3(Thread* t, const int base) int64_t b = popInt(t); uint64_t a = popLong(t); - pushLong(t, a >> b); + pushLong(t, a >> (b & 0x3F)); } goto loop; case lxor: { @@ -2781,7 +2823,7 @@ pushArguments(Thread* t, object this_, const char* spec, break; case 'F': { - pushFloat(t, arguments[index++].d); + pushFloat(t, arguments[index++].f); } break; default: @@ -3010,6 +3052,34 @@ class MyProcessor: public Processor { } } + virtual bool + pushLocalFrame(vm::Thread* vmt, unsigned capacity) + { + Thread* t = static_cast(vmt); + + if (t->sp + capacity < stackSizeInWords(t) / 2) { + t->referenceFrame = new + (t->m->heap->allocate(sizeof(Thread::ReferenceFrame))) + Thread::ReferenceFrame(t->referenceFrame, t->sp); + + return true; + } else { + return false; + } + } + + virtual void + popLocalFrame(vm::Thread* vmt) + { + Thread* t = static_cast(vmt); + + Thread::ReferenceFrame* f = t->referenceFrame; + t->referenceFrame = f->next; + t->sp = f->sp; + + t->m->heap->free(f, sizeof(Thread::ReferenceFrame)); + } + virtual object invokeArray(vm::Thread* vmt, object method, object this_, object arguments) { @@ -3166,7 +3236,7 @@ class MyProcessor: public Processor { } virtual void dispose(vm::Thread* t) { - t->m->heap->free(t, sizeof(Thread)); + t->m->heap->free(t, sizeof(Thread) + t->m->stackSizeInBytes); } virtual void dispose() { diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 5846bea7b2..52da9559f7 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -45,19 +45,23 @@ DetachCurrentThread(Machine* m) { Thread* t = static_cast(m->localThread->get()); if (t) { - expect(t, t != m->rootThread); + // todo: detaching the root thread seems to cause stability + // problems which I haven't yet had a chance to investigate + // thoroughly. Meanwhile, we just ignore requests to detach it, + // which leaks a bit of memory but should be harmless otherwise. + if (m->rootThread != t) { + m->localThread->set(0); - m->localThread->set(0); + ACQUIRE_RAW(t, t->m->stateLock); - ACQUIRE_RAW(t, t->m->stateLock); + enter(t, Thread::ActiveState); - enter(t, Thread::ActiveState); + threadPeer(t, t->javaThread) = 0; - threadPeer(t, t->javaThread) = 0; + enter(t, Thread::ZombieState); - enter(t, Thread::ZombieState); - - t->state = Thread::JoinedState; + t->state = Thread::JoinedState; + } return 0; } else { @@ -237,9 +241,8 @@ newString(Thread* t, uintptr_t* arguments) const jchar* chars = reinterpret_cast(arguments[0]); jsize size = arguments[1]; - object a = 0; + object a = makeCharArray(t, size); if (size) { - a = makeCharArray(t, size); memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar)); } @@ -407,24 +410,6 @@ ExceptionCheck(Thread* t) return t->exception != 0; } -jobject JNICALL -NewDirectByteBuffer(Thread*, void*, jlong) -{ - return 0; -} - -void* JNICALL -GetDirectBufferAddress(Thread*, jobject) -{ - return 0; -} - -jlong JNICALL -GetDirectBufferCapacity(Thread*, jobject) -{ - return -1; -} - uint64_t getObjectClass(Thread* t, uintptr_t* arguments) { @@ -439,18 +424,20 @@ GetObjectClass(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; - return reinterpret_cast(run(t, getObjectClass, arguments)); + return reinterpret_cast(run(t, getObjectClass, arguments)); } uint64_t getSuperclass(Thread* t, uintptr_t* arguments) { - jclass c = reinterpret_cast(arguments[0]); - - object super = classSuper(t, jclassVmClass(t, *c)); - - return super ? reinterpret_cast - (makeLocalReference(t, getJClass(t, super))) : 0; + object class_ = jclassVmClass(t, *reinterpret_cast(arguments[0])); + if (classFlags(t, class_) & ACC_INTERFACE) { + return 0; + } else { + object super = classSuper(t, class_); + return super ? reinterpret_cast + (makeLocalReference(t, getJClass(t, super))) : 0; + } } jclass JNICALL @@ -3154,6 +3141,8 @@ GetPrimitiveArrayCritical(Thread* t, jarray array, jboolean* isCopy) *isCopy = true; } + expect(t, *array); + return reinterpret_cast(*array) + 2; } @@ -3276,6 +3265,66 @@ IsSameObject(Thread* t, jobject a, jobject b) } } +uint64_t +pushLocalFrame(Thread* t, uintptr_t* arguments) +{ + if (t->m->processor->pushLocalFrame(t, arguments[0])) { + return 1; + } else { + throw_(t, root(t, Machine::OutOfMemoryError)); + } +} + +jint JNICALL +PushLocalFrame(Thread* t, jint capacity) +{ + uintptr_t arguments[] = { static_cast(capacity) }; + + return run(t, pushLocalFrame, arguments) ? 0 : -1; +} + +uint64_t +popLocalFrame(Thread* t, uintptr_t* arguments) +{ + object result = *reinterpret_cast(arguments[0]); + PROTECT(t, result); + + t->m->processor->popLocalFrame(t); + + return reinterpret_cast(makeLocalReference(t, result)); +} + +jobject JNICALL +PopLocalFrame(Thread* t, jobject result) +{ + uintptr_t arguments[] = { reinterpret_cast(result) }; + + return reinterpret_cast(run(t, popLocalFrame, arguments)); +} + +jobject JNICALL +NewDirectByteBuffer(Thread* t, void* p, jlong capacity) +{ + jclass c = FindClass(t, "java/nio/DirectByteBuffer"); + return NewObject(t, c, GetMethodID(t, c, "", "(JI)V"), + reinterpret_cast(p), + static_cast(capacity)); +} + +void* JNICALL +GetDirectBufferAddress(Thread* t, jobject b) +{ + return reinterpret_cast + (GetLongField(t, b, GetFieldID(t, GetObjectClass(t, b), "address", "J"))); +} + +jlong JNICALL +GetDirectBufferCapacity(Thread* t, jobject b) +{ + return GetIntField + (t, b, GetFieldID(t, GetObjectClass(t, b), "capacity", "I")); +} + struct JavaVMOption { char* optionString; void* extraInfo; @@ -3556,6 +3605,8 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->MonitorExit = local::MonitorExit; envTable->GetJavaVM = local::GetJavaVM; envTable->IsSameObject = local::IsSameObject; + envTable->PushLocalFrame = local::PushLocalFrame; + envTable->PopLocalFrame = local::PopLocalFrame; } } // namespace vm @@ -3576,6 +3627,13 @@ JNI_GetDefaultJavaVMInitArgs(void*) return 0; } +extern "C" JNIEXPORT jint JNICALL +JNI_GetCreatedJavaVMs(Machine**, jsize, jsize*) +{ + // todo + return -1; +} + extern "C" JNIEXPORT jint JNICALL JNI_CreateJavaVM(Machine** m, Thread** t, void* args) { diff --git a/src/machine.cpp b/src/machine.cpp index 964bfd5452..828de31fc0 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -273,6 +273,8 @@ killZombies(Thread* t, Thread* o) unsigned footprint(Thread* t) { + expect(t, t->criticalLevel == 0); + unsigned n = t->heapOffset + t->heapIndex + t->backupHeapIndex; for (Thread* c = t->child; c; c = c->peer) { @@ -472,6 +474,25 @@ referenceTargetReachable(Thread* t, Heap::Visitor* v, object* p) } } +bool +isFinalizable(Thread* t, object o) +{ + return t->m->heap->status(o) == Heap::Unreachable + and (classVmFlags + (t, static_cast(t->m->heap->follow(objectClass(t, o)))) + & HasFinalizerFlag); +} + +void +clearTargetIfFinalizable(Thread* t, object r) +{ + if (isFinalizable + (t, static_cast(t->m->heap->follow(jreferenceTarget(t, r))))) + { + jreferenceTarget(t, r) = 0; + } +} + void postVisit(Thread* t, Heap::Visitor* v) { @@ -480,6 +501,30 @@ postVisit(Thread* t, Heap::Visitor* v) assert(t, m->finalizeQueue == 0); + m->heap->postVisit(); + + for (object p = m->weakReferences; p;) { + object r = static_cast(m->heap->follow(p)); + p = jreferenceVmNext(t, r); + clearTargetIfFinalizable(t, r); + } + + if (major) { + for (object p = m->tenuredWeakReferences; p;) { + object r = static_cast(m->heap->follow(p)); + p = jreferenceVmNext(t, r); + clearTargetIfFinalizable(t, r); + } + } + + for (Reference* r = m->jniReferences; r; r = r->next) { + if (r->weak and isFinalizable + (t, static_cast(t->m->heap->follow(r->target)))) + { + r->target = 0; + } + } + object firstNewTenuredFinalizer = 0; object lastNewTenuredFinalizer = 0; @@ -1128,7 +1173,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) unsigned count = s.read2(); if (count) { - unsigned staticOffset = BytesPerWord * 2; + unsigned staticOffset = BytesPerWord * 3; unsigned staticCount = 0; object fieldTable = makeArray(t, count); @@ -1242,7 +1287,10 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) uint8_t* body = reinterpret_cast (&singletonBody(t, staticTable, 0)); - for (unsigned i = 0, offset = 0; i < staticCount; ++i) { + memcpy(body, &class_, BytesPerWord); + singletonMarkObject(t, staticTable, 0); + + for (unsigned i = 0, offset = BytesPerWord; i < staticCount; ++i) { unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]); while (offset % size) { ++ offset; @@ -2248,6 +2296,11 @@ updateClassTables(Thread* t, object newClass, object oldClass) } } + object staticTable = classStaticTable(t, newClass); + if (staticTable) { + set(t, staticTable, SingletonBody, newClass); + } + if (classFlags(t, newClass) & ACC_INTERFACE) { object virtualTable = classVirtualTable(t, newClass); if (virtualTable) { @@ -3667,34 +3720,32 @@ stringUTFChars(Thread* t, object string, unsigned start, unsigned length, assert(t, static_cast (stringUTFLength(t, string, start, length)) == charsLength); - if (length) { - object data = stringData(t, string); - if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { - memcpy(chars, - &byteArrayBody(t, data, stringOffset(t, string) + start), - length); - chars[length] = 0; - } else { - int j = 0; - for (unsigned i = 0; i < length; ++i) { - uint16_t c = charArrayBody - (t, data, stringOffset(t, string) + start + i); - if(!c) { // null char - chars[j++] = 0; - } else if (c < 0x80) { // ASCII char - chars[j++] = static_cast(c); - } else if (c < 0x800) { // two-byte char - chars[j++] = static_cast(0x0c0 | (c >> 6)); - chars[j++] = static_cast(0x080 | (c & 0x03f)); - } else { // three-byte char - chars[j++] = static_cast(0x0e0 | ((c >> 12) & 0x0f)); - chars[j++] = static_cast(0x080 | ((c >> 6) & 0x03f)); - chars[j++] = static_cast(0x080 | (c & 0x03f)); - } + object data = stringData(t, string); + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { + memcpy(chars, + &byteArrayBody(t, data, stringOffset(t, string) + start), + length); + chars[length] = 0; + } else { + int j = 0; + for (unsigned i = 0; i < length; ++i) { + uint16_t c = charArrayBody + (t, data, stringOffset(t, string) + start + i); + if(!c) { // null char + chars[j++] = 0; + } else if (c < 0x80) { // ASCII char + chars[j++] = static_cast(c); + } else if (c < 0x800) { // two-byte char + chars[j++] = static_cast(0x0c0 | (c >> 6)); + chars[j++] = static_cast(0x080 | (c & 0x03f)); + } else { // three-byte char + chars[j++] = static_cast(0x0e0 | ((c >> 12) & 0x0f)); + chars[j++] = static_cast(0x080 | ((c >> 6) & 0x03f)); + chars[j++] = static_cast(0x080 | (c & 0x03f)); } - chars[j] = 0; - } - } + } + chars[j] = 0; + } } uint64_t @@ -3983,6 +4034,17 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size, return real; } +uint64_t +runParseClass(Thread* t, uintptr_t* arguments) +{ + object loader = reinterpret_cast(arguments[0]); + System::Region* region = reinterpret_cast(arguments[1]); + Machine::Type throwType = static_cast(arguments[2]); + + return reinterpret_cast + (parseClass(t, loader, region->start(), region->length(), throwType)); +} + object resolveSystemClass(Thread* t, object loader, object spec, bool throw_, Machine::Type throwType) @@ -4028,9 +4090,24 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_, { THREAD_RESOURCE(t, System::Region*, region, region->dispose()); + uintptr_t arguments[] = { reinterpret_cast(loader), + reinterpret_cast(region), + static_cast(throwType) }; + // parse class file - class_ = parseClass - (t, loader, region->start(), region->length(), throwType); + class_ = reinterpret_cast + (runRaw(t, runParseClass, arguments)); + + if (UNLIKELY(t->exception)) { + if (throw_) { + object e = t->exception; + t->exception = 0; + vm::throw_(t, e); + } else { + t->exception = 0; + return 0; + } + } } if (Verbose) { @@ -4068,6 +4145,8 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_, if (class_) { hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); + + t->m->classpath->updatePackageMap(t, class_); } else if (throw_) { throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0)); } @@ -4808,15 +4887,27 @@ parseUtf8(Thread* t, const char* data, unsigned length) } object -getCaller(Thread* t, unsigned target) +getCaller(Thread* t, unsigned target, bool skipMethodInvoke) { class Visitor: public Processor::StackVisitor { public: - Visitor(Thread* t, unsigned target): - t(t), method(0), count(0), target(target) + Visitor(Thread* t, unsigned target, bool skipMethodInvoke): + t(t), method(0), count(0), target(target), + skipMethodInvoke(skipMethodInvoke) { } virtual bool visit(Processor::StackWalker* walker) { + if (skipMethodInvoke + and methodClass + (t, walker->method()) == type(t, Machine::JmethodType) + and strcmp + (&byteArrayBody(t, methodName(t, walker->method()), 0), + reinterpret_cast("invoke")) + == 0) + { + return true; + } + if (count == target) { method = walker->method(); return false; @@ -4830,7 +4921,8 @@ getCaller(Thread* t, unsigned target) object method; unsigned count; unsigned target; - } v(t, target); + bool skipMethodInvoke; + } v(t, target, skipMethodInvoke); t->m->processor->walkStack(t, &v); diff --git a/src/machine.h b/src/machine.h index a9cba4024e..52233cab3c 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1206,6 +1206,7 @@ class Machine { BootLoader, AppLoader, BootstrapClassMap, + PackageMap, FindLoadedClassMethod, LoadClassMethod, MonitorMap, @@ -1550,6 +1551,9 @@ class Classpath { virtual const char* bootClasspath() = 0; + virtual void + updatePackageMap(Thread* t, object class_) = 0; + virtual void dispose() = 0; }; @@ -3801,7 +3805,7 @@ populateMultiArray(Thread* t, object array, int32_t* counts, unsigned index, unsigned dimensions); object -getCaller(Thread* t, unsigned target); +getCaller(Thread* t, unsigned target, bool skipMethodInvoke = false); object defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length); diff --git a/src/main.cpp b/src/main.cpp index 2518d60a13..fe2793c10d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -114,8 +114,8 @@ mainClass(const char* jar) unsigned length; while (readLine(region->start(), region->length(), &start, &length)) { const unsigned PrefixLength = 12; - if (strncmp("Main-Class: ", reinterpret_cast - (region->start() + start), PrefixLength) == 0) + if (strncasecmp("Main-Class: ", reinterpret_cast + (region->start() + start), PrefixLength) == 0) { result = static_cast(malloc(length + 1 - PrefixLength)); memcpy(result, region->start() + start + PrefixLength, @@ -172,9 +172,11 @@ main(int ac, const char** av) if (strcmp(av[i], "-cp") == 0 or strcmp(av[i], "-classpath") == 0) { + if (i + 1 == ac) usageAndExit(av[0]); classpath = av[++i]; } else if (strcmp(av[i], "-jar") == 0) { + if (i + 1 == ac) usageAndExit(av[0]); jar = av[++i]; } else if (strncmp(av[i], "-X", 2) == 0 or strncmp(av[i], "-D", 2) == 0) diff --git a/src/posix.cpp b/src/posix.cpp index ea3f133d37..1394a26886 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -14,7 +14,13 @@ #ifdef __APPLE__ # include "CoreFoundation/CoreFoundation.h" +# include "sys/ucontext.h" # undef assert +#else +# if defined __FreeBSD__ +# include "limits.h" +# endif +# include "ucontext.h" #endif #include "sys/mman.h" @@ -28,7 +34,6 @@ #include "unistd.h" #include "pthread.h" #include "signal.h" -#include "sys/ucontext.h" #include "stdint.h" #include "dirent.h" #include "sched.h" @@ -622,7 +627,7 @@ class MySystem: public System { } virtual void* tryAllocateExecutable(unsigned sizeInBytes) { -#if (! defined __APPLE__) && (defined __x86_64__) +#ifdef MAP_32BIT // map to the lower 32 bits of memory when possible so as to avoid // expensive relative jumps const unsigned Extra = MAP_32BIT; @@ -795,6 +800,13 @@ class MySystem: public System { } virtual FileType stat(const char* name, unsigned* length) { +#ifdef __FreeBSD__ + // Now the hack below causes the error "Dereferencing type-punned + // pointer will break strict aliasing rules", so another workaround + // is needed... + struct stat ss; + struct stat* s = &ss; +#else // Ugly Hack Alert: It seems that the Apple iOS Simulator's stat // implementation writes beyond the end of the struct stat we pass // it, which can clobber unrelated parts of the stack. Perhaps @@ -804,6 +816,7 @@ class MySystem: public System { // made up and seems to work. void* array[ceiling(sizeof(struct stat), sizeof(void*)) + 8]; struct stat* s = reinterpret_cast(array); +#endif int r = ::stat(name, s); if (r == 0) { diff --git a/src/powerpc.S b/src/powerpc.S index 290bef0559..ec685da04b 100644 --- a/src/powerpc.S +++ b/src/powerpc.S @@ -136,9 +136,18 @@ LOCAL(call): LOCAL(float): cmpwi r14,FLOAT_TYPE - beq LOCAL(copy) + bne LOCAL(double) + stfs f1,32(r19) + lwz r4,32(r19) + b LOCAL(exit) +LOCAL(double): cmpwi r14,DOUBLE_TYPE - beq LOCAL(copy) + bne LOCAL(int64) + stfd f1,32(r19) + lwz r3,32(r19) + lwz r4,36(r19) + b LOCAL(exit) +LOCAL(int64): cmpwi r14,INT64_TYPE beq LOCAL(exit) mr r4,r3 diff --git a/src/powerpc.cpp b/src/powerpc.cpp index a184c21f36..6a329a2f6e 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -672,6 +672,10 @@ write4(uint8_t* dst, uint32_t v) memcpy(dst, &v, 4); } +void +andC(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst); + void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if(size == 8) { @@ -683,25 +687,36 @@ void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler:: emit(con, addi(tmp->high, a->low, -32)); emit(con, slw(tmp->low, b->low, tmp->high)); emit(con, or_(t->high, t->high, tmp->low)); + emit(con, slw(t->low, b->low, a->low)); freeTemp(con, tmp->high); freeTemp(con, tmp->low); + } else { + emit(con, slw(t->low, b->low, a->low)); } - emit(con, slw(t->low, b->low, a->low)); } +void +moveRR(Context* c, unsigned srcSize, Assembler::Register* src, + unsigned dstSize, Assembler::Register* dst); + void shiftLeftC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { int sh = getValue(a); if (size == 8) { - if (sh < 32) { - emit(con, rlwinm(t->high,b->high,sh,0,31-sh)); - emit(con, rlwimi(t->high,b->low,sh,32-sh,31)); - emit(con, slwi(t->low, b->low, sh)); + sh &= 0x3F; + if (sh) { + if (sh < 32) { + emit(con, rlwinm(t->high,b->high,sh,0,31-sh)); + emit(con, rlwimi(t->high,b->low,sh,32-sh,31)); + emit(con, slwi(t->low, b->low, sh)); + } else { + emit(con, rlwinm(t->high,b->low,sh-32,0,63-sh)); + emit(con, li(t->low,0)); + } } else { - emit(con, rlwinm(t->high,b->low,sh-32,0,63-sh)); - emit(con, li(t->low,0)); + moveRR(con, size, b, size, t); } } else { - emit(con, slwi(t->low, b->low, sh)); + emit(con, slwi(t->low, b->low, sh & 0x1F)); } } @@ -728,16 +743,21 @@ void shiftRightC(Context* con, unsigned size, Assembler::Constant* a, Assembler: { int sh = getValue(a); if(size == 8) { - if (sh < 32) { - emit(con, rlwinm(t->low,b->low,32-sh,sh,31)); - emit(con, rlwimi(t->low,b->high,32-sh,0,sh-1)); - emit(con, srawi(t->high,b->high,sh)); + sh &= 0x3F; + if (sh) { + if (sh < 32) { + emit(con, rlwinm(t->low,b->low,32-sh,sh,31)); + emit(con, rlwimi(t->low,b->high,32-sh,0,sh-1)); + emit(con, srawi(t->high,b->high,sh)); + } else { + emit(con, srawi(t->high,b->high,31)); + emit(con, srawi(t->low,b->high,sh-32)); + } } else { - emit(con, srawi(t->high,b->high,31)); - emit(con, srawi(t->low,b->high,sh-32)); + moveRR(con, size, b, size, t); } } else { - emit(con, srawi(t->low, b->low, sh)); + emit(con, srawi(t->low, b->low, sh & 0x1F)); } } @@ -757,28 +777,32 @@ void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register* a, As } } -void -moveRR(Context* c, unsigned srcSize, Assembler::Register* src, - unsigned dstSize, Assembler::Register* dst); - void unsignedShiftRightC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { int sh = getValue(a); if (size == 8) { - if (sh == 32) { - Assembler::Register high(b->high); - moveRR(con, 4, &high, 4, t); - emit(con, li(t->high,0)); - } else if (sh < 32) { - emit(con, srwi(t->low, b->low, sh)); - emit(con, rlwimi(t->low,b->high,32-sh,0,sh-1)); - emit(con, rlwinm(t->high,b->high,32-sh,sh,31)); + if (sh & 0x3F) { + if (sh == 32) { + Assembler::Register high(b->high); + moveRR(con, 4, &high, 4, t); + emit(con, li(t->high,0)); + } else if (sh < 32) { + emit(con, srwi(t->low, b->low, sh)); + emit(con, rlwimi(t->low,b->high,32-sh,0,sh-1)); + emit(con, rlwinm(t->high,b->high,32-sh,sh,31)); + } else { + emit(con, rlwinm(t->low,b->high,64-sh,sh-32,31)); + emit(con, li(t->high,0)); + } } else { - emit(con, rlwinm(t->low,b->high,64-sh,sh-32,31)); - emit(con, li(t->high,0)); + moveRR(con, size, b, size, t); } } else { - emit(con, srwi(t->low, b->low, sh)); + if (sh & 0x1F) { + emit(con, srwi(t->low, b->low, sh & 0x1F)); + } else { + moveRR(con, size, b, size, t); + } } } diff --git a/src/powerpc.h b/src/powerpc.h index 8ddc9fc73c..6be4d34286 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -196,7 +196,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, } break; case DOUBLE_TYPE: { - if (fprIndex + (8 / BytesPerWord) <= FprCount) { + if (fprIndex + 1 <= FprCount) { memcpy(fprTable + fprIndex, arguments + ai, 8); ++ fprIndex; SKIP(gprIndex, 8 / BytesPerWord); diff --git a/src/processor.h b/src/processor.h index c4c6fd9ad2..6da91dddce 100644 --- a/src/processor.h +++ b/src/processor.h @@ -103,6 +103,12 @@ class Processor { virtual void disposeLocalReference(Thread* t, object* r) = 0; + virtual bool + pushLocalFrame(Thread* t, unsigned capacity) = 0; + + virtual void + popLocalFrame(Thread* t) = 0; + virtual object invokeArray(Thread* t, object method, object this_, object arguments) = 0; diff --git a/src/target-fields.h b/src/target-fields.h index 3481d4516e..a02aee0f6a 100644 --- a/src/target-fields.h +++ b/src/target-fields.h @@ -60,4 +60,5 @@ # error #endif -#endif \ No newline at end of file +#endif + diff --git a/src/tokenizer.h b/src/tokenizer.h index 23b7788232..5699227c74 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -32,13 +32,13 @@ class Tokenizer { { } bool hasMore() { - while (*s == delimiter and s != limit) ++s; - return *s != 0 and s != limit; + while (s != limit and *s == delimiter) ++s; + return s != limit and *s != 0; } Token next() { const char* p = s; - while (*s and *s != delimiter and s != limit) ++s; + while (s != limit and *s and *s != delimiter) ++s; return Token(p, s - p); } diff --git a/src/type-generator.cpp b/src/type-generator.cpp index f31b0f18c8..290aec459a 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -871,6 +871,13 @@ class MemberIterator { return true; } else { while (types) { + if (member) { + assert(member->type == Object::Scalar); + offset_ = ((offset_ + size_) + (BytesPerWord - 1)) + & ~(BytesPerWord - 1); + member = 0; + } + type = car(types); members = typeMembers(type); types = cdr(types); @@ -2207,5 +2214,7 @@ main(int ac, char** av) local::writeMaps(&out, declarations); } + out.write("\n"); + return 0; } diff --git a/src/windows.cpp b/src/windows.cpp index f6b4f1e550..532b66e161 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -876,7 +876,7 @@ class MySystem: public System { virtual void abort() { // trigger an EXCEPTION_ACCESS_VIOLATION, which we will catch and // generate a debug dump for - *static_cast(0) = 0; + *static_cast(0) = 0; } virtual void dispose() { @@ -929,7 +929,7 @@ dump(LPEXCEPTION_POINTERS e, const char* directory) char name[MAX_PATH]; _timeb tb; FTIME(&tb); - vm::snprintf(name, MAX_PATH, "%s\\crash-%"LLD".mdmp", directory, + vm::snprintf(name, MAX_PATH, "%s\\crash-%" LLD ".mdmp", directory, (static_cast(tb.time) * 1000) + static_cast(tb.millitm)); diff --git a/src/x86.S b/src/x86.S index 6c939ff7de..2a0096ec85 100644 --- a/src/x86.S +++ b/src/x86.S @@ -315,7 +315,7 @@ LOCAL(sse): movq 32(%rax),%xmm4 movq 40(%rax),%xmm5 movq 48(%rax),%xmm6 - movq 64(%rax),%xmm7 + movq 56(%rax),%xmm7 LOCAL(call): call *-48(%rbp) diff --git a/src/x86.cpp b/src/x86.cpp index 2a6d39d0aa..acdb8f1f71 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2164,7 +2164,9 @@ doShift(Context* c, UNUSED void (*shift) c->client->save(rcx); Assembler::Register cx(rcx); - moveCR(c, 4, a, 4, &cx); + ResolvedPromise promise(v & 0x3F); + Assembler::Constant masked(&promise); + moveCR(c, 4, &masked, 4, &cx); shift(c, aSize, &cx, bSize, b); } else { maybeRex(c, bSize, b); @@ -2183,9 +2185,16 @@ void shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, unsigned bSize, Assembler::Register* b) { - assert(c, a->low == rcx); - if (TargetBytesPerWord == 4 and bSize == 8) { + Assembler::Register cx(rcx); + if (a->low != rcx) { + c->client->save(rcx); + ResolvedPromise promise(0x3F); + Assembler::Constant mask(&promise); + moveRR(c, 4, a, 4, &cx); + andCR(c, 4, &mask, 4, &cx); + } + // shld opcode(c, 0x0f, 0xa5); modrm(c, 0xc0, b->high, b->low); @@ -2195,7 +2204,7 @@ shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, ResolvedPromise promise(32); Assembler::Constant constant(&promise); - compareCR(c, aSize, &constant, aSize, a); + compareCR(c, aSize, &constant, aSize, &cx); opcode(c, 0x7c); //jl c->code.append(2 + 2); @@ -2204,6 +2213,8 @@ shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, moveRR(c, 4, b, 4, &bh); // 2 bytes xorRR(c, 4, b, 4, b); // 2 bytes } else { + assert(c, a->low == rcx); + maybeRex(c, bSize, a, b); opcode(c, 0xd3, 0xe0 + regCode(b)); } @@ -2220,8 +2231,16 @@ void shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, unsigned bSize, Assembler::Register* b) { - assert(c, a->low == rcx); if (TargetBytesPerWord == 4 and bSize == 8) { + Assembler::Register cx(rcx); + if (a->low != rcx) { + c->client->save(rcx); + ResolvedPromise promise(0x3F); + Assembler::Constant mask(&promise); + moveRR(c, 4, a, 4, &cx); + andCR(c, 4, &mask, 4, &cx); + } + // shrd opcode(c, 0x0f, 0xad); modrm(c, 0xc0, b->low, b->high); @@ -2231,7 +2250,7 @@ shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, ResolvedPromise promise(32); Assembler::Constant constant(&promise); - compareCR(c, aSize, &constant, aSize, a); + compareCR(c, aSize, &constant, aSize, &cx); opcode(c, 0x7c); //jl c->code.append(2 + 3); @@ -2243,6 +2262,8 @@ shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, opcode(c, 0xc1, 0xf8 + b->high); c->code.append(31); } else { + assert(c, a->low == rcx); + maybeRex(c, bSize, a, b); opcode(c, 0xd3, 0xf8 + regCode(b)); } @@ -2259,9 +2280,16 @@ void unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, unsigned bSize, Assembler::Register* b) { - assert(c, a->low == rcx); - if (TargetBytesPerWord == 4 and bSize == 8) { + Assembler::Register cx(rcx); + if (a->low != rcx) { + c->client->save(rcx); + ResolvedPromise promise(0x3F); + Assembler::Constant mask(&promise); + moveRR(c, 4, a, 4, &cx); + andCR(c, 4, &mask, 4, &cx); + } + // shrd opcode(c, 0x0f, 0xad); modrm(c, 0xc0, b->low, b->high); @@ -2271,7 +2299,7 @@ unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, ResolvedPromise promise(32); Assembler::Constant constant(&promise); - compareCR(c, aSize, &constant, aSize, a); + compareCR(c, aSize, &constant, aSize, &cx); opcode(c, 0x7c); //jl c->code.append(2 + 2); @@ -2280,6 +2308,8 @@ unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, moveRR(c, 4, &bh, 4, b); // 2 bytes xorRR(c, 4, &bh, 4, &bh); // 2 bytes } else { + assert(c, a->low == rcx); + maybeRex(c, bSize, a, b); opcode(c, 0xd3, 0xe8 + regCode(b)); } @@ -2781,7 +2811,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned frameFootprint(unsigned footprint) { -#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS +#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE return max(footprint, StackAlignmentInWords); #else return max(footprint > argumentRegisterCount() ? @@ -2803,7 +2833,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned argumentRegisterCount() { -#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS +#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE if (TargetBytesPerWord == 8) return 4; else #else if (TargetBytesPerWord == 8) return 6; else @@ -2814,7 +2844,7 @@ class MyArchitecture: public Assembler::Architecture { virtual int argumentRegister(unsigned index) { assert(&c, TargetBytesPerWord == 8); switch (index) { -#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS +#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE case 0: return rcx; case 1: @@ -3064,7 +3094,11 @@ class MyArchitecture: public Assembler::Architecture { break; case Float2Int: - if (useSSE(&c) and bSize <= TargetBytesPerWord) { + // todo: Java requires different semantics than SSE for + // converting floats to integers, we we need to either use + // thunks or produce inline machine code which handles edge + // cases properly. + if (false and useSSE(&c) and bSize <= TargetBytesPerWord) { *aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); *aRegisterMask = (static_cast(FloatRegisterMask) << 32) | FloatRegisterMask; @@ -3228,7 +3262,7 @@ class MyArchitecture: public Assembler::Architecture { virtual void planSource (TernaryOperation op, unsigned aSize, uint8_t *aTypeMask, uint64_t *aRegisterMask, - unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, + unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask, unsigned, bool* thunk) { *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); @@ -3298,10 +3332,16 @@ class MyArchitecture: public Assembler::Architecture { case ShiftLeft: case ShiftRight: case UnsignedShiftRight: { - *aRegisterMask = (static_cast(GeneralRegisterMask) << 32) - | (static_cast(1) << rcx); - const uint32_t mask = GeneralRegisterMask & ~(1 << rcx); - *bRegisterMask = (static_cast(mask) << 32) | mask; + if (TargetBytesPerWord == 4 and bSize == 8) { + const uint32_t mask = GeneralRegisterMask & ~(1 << rcx); + *aRegisterMask = (static_cast(mask) << 32) | mask; + *bRegisterMask = (static_cast(mask) << 32) | mask; + } else { + *aRegisterMask = (static_cast(GeneralRegisterMask) << 32) + | (static_cast(1) << rcx); + const uint32_t mask = GeneralRegisterMask & ~(1 << rcx); + *bRegisterMask = (static_cast(mask) << 32) | mask; + } } break; case JumpIfFloatEqual: diff --git a/src/x86.h b/src/x86.h index 298cab6aaa..bda55bee7d 100644 --- a/src/x86.h +++ b/src/x86.h @@ -64,6 +64,18 @@ # define FRAME_REGISTER(context) \ THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) +# elif (defined __QNX__) +# define IP_REGISTER(context) (context->uc_mcontext.cpu.eip) +# define STACK_REGISTER(context) (context->uc_mcontext.cpu.esp) +# define THREAD_REGISTER(context) (context->uc_mcontext.cpu.ebx) +# define LINK_REGISTER(context) (context->uc_mcontext.cpu.ecx) +# define FRAME_REGISTER(context) (context->uc_mcontext.cpu.ebp) +# elif (defined __FreeBSD__) +# define IP_REGISTER(context) (context->uc_mcontext.mc_eip) +# define STACK_REGISTER(context) (context->uc_mcontext.mc_esp) +# define THREAD_REGISTER(context) (context->uc_mcontext.mc_ebx) +# define LINK_REGISTER(context) (context->uc_mcontext.mc_ecx) +# define FRAME_REGISTER(context) (context->uc_mcontext.mc_ebp) # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) @@ -111,6 +123,12 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*, # define FRAME_REGISTER(context) \ THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) +# elif (defined __FreeBSD__) +# define IP_REGISTER(context) (context->uc_mcontext.mc_rip) +# define STACK_REGISTER(context) (context->uc_mcontext.mc_rsp) +# define THREAD_REGISTER(context) (context->uc_mcontext.mc_rbx) +# define LINK_REGISTER(context) (context->uc_mcontext.mc_rcx) +# define FRAME_REGISTER(context) (context->uc_mcontext.mc_rbp) # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP]) diff --git a/src/zone.h b/src/zone.h index 9e35cdcad7..900ea5d3ab 100644 --- a/src/zone.h +++ b/src/zone.h @@ -20,10 +20,13 @@ class Zone: public Allocator { public: class Segment { public: - Segment(Segment* next, unsigned size): next(next), size(size) { } + Segment(Segment* next, unsigned size): + next(next), size(size), position(0) + { } Segment* next; uintptr_t size; + uintptr_t position; uint8_t data[0]; }; @@ -31,7 +34,6 @@ class Zone: public Allocator { s(s), allocator(allocator), segment(0), - position(0), minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 : minimumFootprint - sizeof(Segment)) { } @@ -55,7 +57,7 @@ class Zone: public Allocator { } bool tryEnsure(unsigned space) { - if (segment == 0 or position + space > segment->size) { + if (segment == 0 or segment->position + space > segment->size) { unsigned size = padToPage (max (space, max @@ -72,26 +74,24 @@ class Zone: public Allocator { } segment = new (p) Segment(segment, size - sizeof(Segment)); - position = 0; } return true; } void ensure(unsigned space) { - if (segment == 0 or position + space > segment->size) { + if (segment == 0 or segment->position + space > segment->size) { unsigned size = padToPage(space + sizeof(Segment)); segment = new (allocator->allocate(size)) Segment(segment, size - sizeof(Segment)); - position = 0; } } virtual void* tryAllocate(unsigned size) { size = pad(size); if (tryEnsure(size)) { - void* r = segment->data + position; - position += size; + void* r = segment->data + segment->position; + segment->position += size; return r; } else { return 0; @@ -99,17 +99,41 @@ class Zone: public Allocator { } virtual void* allocate(unsigned size) { + size = pad(size); void* p = tryAllocate(size); if (p) { return p; } else { ensure(size); - void* r = segment->data + position; - position += size; + void* r = segment->data + segment->position; + segment->position += size; return r; } } + void* peek(unsigned size) { + size = pad(size); + Segment* s = segment; + while (s->position < size) { + size -= s->position; + s = s->next; + } + return s->data + (s->position - size); + } + + void pop(unsigned size) { + size = pad(size); + Segment* s = segment; + while (s->position < size) { + size -= s->position; + Segment* next = s->next; + allocator->free(s, sizeof(Segment) + s->size); + s = next; + } + s->position -= size; + segment = s; + } + virtual void free(const void*, unsigned) { // not supported abort(s); @@ -119,7 +143,6 @@ class Zone: public Allocator { Allocator* allocator; void* context; Segment* segment; - unsigned position; unsigned minimumFootprint; }; diff --git a/test/Arrays.java b/test/Arrays.java index 27acd2e3ff..42e958068a 100644 --- a/test/Arrays.java +++ b/test/Arrays.java @@ -85,14 +85,14 @@ public class Arrays { a[0] = new Object(); expect(! java.util.Arrays.equals(a, b)); expect(! java.util.Arrays.equals(b, new Object[4])); - expect(! java.util.Arrays.equals(b, null)); - expect(! java.util.Arrays.equals(a, b)); - expect(java.util.Arrays.equals(null, null)); + expect(! java.util.Arrays.equals(a, null)); + expect(! java.util.Arrays.equals(null, b)); + expect(java.util.Arrays.equals((Object[])null, (Object[])null)); b[0] = a[0]; expect(java.util.Arrays.equals(a, b)); java.util.Arrays.hashCode(a); - java.util.Arrays.hashCode(null); + java.util.Arrays.hashCode((Object[])null); } } } diff --git a/test/Buffers.java b/test/Buffers.java new file mode 100644 index 0000000000..804d81eb93 --- /dev/null +++ b/test/Buffers.java @@ -0,0 +1,109 @@ +import java.nio.ByteBuffer; + +public class Buffers { + static { + System.loadLibrary("test"); + } + + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static void test(Factory factory1, Factory factory2) { + { final int size = 64; + ByteBuffer b1 = factory1.allocate(size); + try { + for (int i = 0; i < size; ++i) + b1.put(i, (byte) 42); + + for (int i = 0; i < size; ++i) + expect(b1.get(i) == 42); + + for (int i = 0; i < size / 2; ++i) + b1.putShort(i * 2, (short) -12345); + + for (int i = 0; i < size / 2; ++i) + expect(b1.getShort(i * 2) == -12345); + + for (int i = 0; i < size / 4; ++i) + b1.putInt(i * 4, 0x12345678); + + for (int i = 0; i < size / 4; ++i) + expect(b1.getInt(i * 4) == 0x12345678); + + for (int i = 0; i < size / 8; ++i) + b1.putLong(i * 8, 0x1234567890ABCDEFL); + + for (int i = 0; i < size / 8; ++i) + expect(b1.getLong(i * 8) == 0x1234567890ABCDEFL); + + ByteBuffer b2 = factory2.allocate(size); + try { + b2.put(b1); + + for (int i = 0; i < size / 8; ++i) + expect(b2.getLong(i * 8) == 0x1234567890ABCDEFL); + + } finally { + factory2.dispose(b2); + } + } finally { + factory1.dispose(b1); + } + } + } + + private static native ByteBuffer allocateNative(int capacity); + + private static native void freeNative(ByteBuffer b); + + public static void main(String[] args) { + Factory array = new Factory() { + public ByteBuffer allocate(int capacity) { + return ByteBuffer.allocate(capacity); + } + + public void dispose(ByteBuffer b) { + // ignore + } + }; + + Factory direct = new Factory() { + public ByteBuffer allocate(int capacity) { + return ByteBuffer.allocateDirect(capacity); + } + + public void dispose(ByteBuffer b) { + // ignore + } + }; + + Factory native_ = new Factory() { + public ByteBuffer allocate(int capacity) { + return allocateNative(capacity); + } + + public void dispose(ByteBuffer b) { + freeNative(b); + } + }; + + test(array, array); + test(array, direct); + test(array, native_); + + test(direct, array); + test(direct, direct); + test(direct, native_); + + test(native_, array); + test(native_, direct); + test(native_, native_); + } + + private interface Factory { + public ByteBuffer allocate(int capacity); + + public void dispose(ByteBuffer b); + } +} diff --git a/test/Datagrams.java b/test/Datagrams.java new file mode 100644 index 0000000000..3e017261da --- /dev/null +++ b/test/Datagrams.java @@ -0,0 +1,88 @@ +import java.net.SocketAddress; +import java.net.InetSocketAddress; +import java.net.ProtocolFamily; +import java.net.StandardProtocolFamily; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.channels.Selector; +import java.nio.channels.SelectionKey; + +public class Datagrams { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static boolean equal(byte[] a, int aOffset, byte[] b, int bOffset, + int length) + { + for (int i = 0; i < length; ++i) { + if (a[aOffset + i] != b[bOffset + i]) return false; + } + return true; + } + + public static void main(String[] args) throws Exception { + final String Hostname = "localhost"; + final int Port = 22043; + final SocketAddress Address = new InetSocketAddress(Hostname, Port); + final byte[] Message = "hello, world!".getBytes(); + + DatagramChannel out = DatagramChannel.open(); + try { + out.configureBlocking(false); + out.connect(Address); + + DatagramChannel in = DatagramChannel.open(); + try { + in.configureBlocking(false); + in.socket().bind(Address); + + Selector selector = Selector.open(); + try { + SelectionKey outKey = out.register + (selector, SelectionKey.OP_WRITE, null); + + SelectionKey inKey = in.register + (selector, SelectionKey.OP_READ, null); + + int state = 0; + ByteBuffer inBuffer = ByteBuffer.allocate(Message.length); + loop: while (true) { + selector.select(); + + switch (state) { + case 0: { + if (outKey.isWritable()) { + out.write(ByteBuffer.wrap(Message)); + state = 1; + } + } break; + + case 1: { + if (inKey.isReadable()) { + in.receive(inBuffer); + if (! inBuffer.hasRemaining()) { + expect(equal(inBuffer.array(), + inBuffer.arrayOffset(), + Message, + 0, + Message.length)); + break loop; + } + } + } break; + + default: throw new RuntimeException(); + } + } + } finally { + selector.close(); + } + } finally { + in.close(); + } + } finally { + out.close(); + } + } +} diff --git a/test/Files.java b/test/Files.java index 7a0170b678..e613bd4fc1 100644 --- a/test/Files.java +++ b/test/Files.java @@ -74,6 +74,12 @@ public class Files { f.delete(); } } + + expect(new File("foo/bar").getParent().equals("foo")); + expect(new File("foo/bar/").getParent().equals("foo")); + expect(new File("foo/bar//").getParent().equals("foo")); + + expect(new File("foo/nonexistent-directory").listFiles() == null); } } diff --git a/test/Floats.java b/test/Floats.java index 723b899a1a..b8b80cbd75 100644 --- a/test/Floats.java +++ b/test/Floats.java @@ -272,5 +272,62 @@ public class Floats { } } } + + { double v = Double.NaN; + expect(0 == (int) v); } + + { double v = Double.NEGATIVE_INFINITY; + expect(Integer.MIN_VALUE == (int) v); } + + { double v = Long.MIN_VALUE; + expect(Integer.MIN_VALUE == (int) v); } + + { double v = Double.POSITIVE_INFINITY; + expect(Integer.MAX_VALUE == (int) v); } + + { double v = Long.MAX_VALUE; + expect(Integer.MAX_VALUE == (int) v); } + + { float v = Float.NaN; + expect(0 == (int) v); } + + { float v = Float.NEGATIVE_INFINITY; + expect(Integer.MIN_VALUE == (int) v); } + + { float v = Integer.MIN_VALUE; + expect(Integer.MIN_VALUE == (int) v); } + + { float v = Float.POSITIVE_INFINITY; + expect(Integer.MAX_VALUE == (int) v); } + + { float v = Integer.MAX_VALUE; + expect(Integer.MAX_VALUE == (int) v); } + + { double v = Double.NaN; + expect(0 == (long) v); } + + { double v = Double.NEGATIVE_INFINITY; + expect(Long.MIN_VALUE == (long) v); } + + { double v = Long.MIN_VALUE; + expect(Long.MIN_VALUE == (long) v); } + + { double v = Double.POSITIVE_INFINITY; + expect(Long.MAX_VALUE == (long) v); } + + { double v = Long.MAX_VALUE; + expect(Long.MAX_VALUE == (long) v); } + + { float v = Float.NaN; + expect(0 == (long) v); } + + { float v = Float.NEGATIVE_INFINITY; + expect(Long.MIN_VALUE == (long) v); } + + { float v = Integer.MIN_VALUE; + expect(Integer.MIN_VALUE == (long) v); } + + { float v = Float.POSITIVE_INFINITY; + expect(Long.MAX_VALUE == (long) v); } } } diff --git a/test/Integers.java b/test/Integers.java index c88803b518..bbaa710351 100644 --- a/test/Integers.java +++ b/test/Integers.java @@ -20,7 +20,7 @@ public class Integers { return m; } - public static void main(String[] args) { + public static void main(String[] args) throws Exception { { int foo = 1028; foo -= 1023; expect(foo == 5); @@ -262,9 +262,57 @@ public class Integers { expect(bytesPerLine == 24); } - int y = -11760768; - expect((y + 0x8000) == (-11760768 + 0x8000)); + { int y = -11760768; + expect((y + 0x8000) == (-11760768 + 0x8000)); } expect(Math.min(796, 1069) == 796); + + { int b = 1; + expect((b << 32) == 1); } + + { int b = 0xFFFFFFFF; + expect((b >>> -1) == 1); } + + { int b = 0x10000000; + expect((b >> -31) == 0x8000000); } + + { int b = 1; int s = 32; + expect((b << s) == 1); } + + { int b = 0xFFFFFFFF; int s = -1; + expect((b >>> s) == 1); } + + { int b = 0x10000000; int s = -31; + expect((b >> s) == 0x8000000); } + + { int b = 0xBE; + expect((b & 0xFF) == 0xBE); } + + { int b = 0xBE; + expect((b >>> 0) == 0xBE); } + + { int b = 0xBE; + expect((b >> 0) == 0xBE); } + + { int b = 0xBE; + expect((b << 0) == 0xBE); } + + { int b = 0xBE; + expect(((b >>> 0) & 0xFF) == 0xBE); } + + { int b = 0xBE; int x = 0xFF; + expect((b & x) == 0xBE); } + + { int b = 0xBE; int x = 0; + expect((b >>> x) == 0xBE); } + + { int b = 0xBE; int x = 0; + expect((b >> x) == 0xBE); } + + { int b = 0xBE; int x = 0; + expect((b << x) == 0xBE); } + + { int b = 0xBE; int x = 0; int y = 0xFF; + expect(((b >>> x) & y) == 0xBE); } } } diff --git a/test/JNI.java b/test/JNI.java new file mode 100644 index 0000000000..b4e93c0f75 --- /dev/null +++ b/test/JNI.java @@ -0,0 +1,59 @@ +public class JNI { + static { + System.loadLibrary("test"); + } + + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static float echo(float f) { + return f; + } + + private static native float doEcho(float f); + + private static double echo(double f) { + return f; + } + + private static native double doEcho(double f); + + private static native double addDoubles + (double a1, double a2, double a3, double a4, double a5, double a6, + double a7, double a8, double a9, double a10, double a11, double a12, + double a13, double a14, double a15, double a16, double a17, double a18, + double a19, double a20); + + private static native float addFloats + (float a1, float a2, float a3, float a4, float a5, float a6, + float a7, float a8, float a9, float a10, float a11, float a12, + float a13, float a14, float a15, float a16, float a17, float a18, + float a19, float a20); + + private static native double addMix + (float a1, double a2, float a3, double a4, float a5, float a6, + float a7, float a8, float a9, float a10, float a11, float a12, + float a13, float a14, float a15, double a16, float a17, float a18, + float a19, float a20); + + public static void main(String[] args) { + expect(addDoubles + (1.0d, 2.0d, 3.0d, 4.0d, 5.0d, 6.0d, 7.0d, 8.0d, 9.0d, 10.0d, 11.0d, + 12.0d, 13.0d, 14.0d, 15.0d, 16.0d, 17.0d, 18.0d, 19.0d, 20.0d) + == 210.0d); + + expect(addFloats + (1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, + 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f) + == 210.0f); + + expect(addMix + (1.0f, 2.0d, 3.0f, 4.0d, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, + 12.0f, 13.0f, 14.0f, 15.0f, 16.0d, 17.0f, 18.0f, 19.0f, 20.0f) + == 210.0d); + + expect(doEcho(42.0f) == 42.0f); + expect(doEcho(42.0d) == 42.0d); + } +} diff --git a/test/Longs.java b/test/Longs.java index 0472536f60..4d9395f7b0 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -337,6 +337,58 @@ public class Longs { expect(z[0] == 337192406); expect(z[1] == -437261072); } + + { long b = 1; + expect((b << 64) == 1); } + + { long b = 0xFFFFFFFFFFFFFFFFL; + expect((b >>> -1) == 1); } + + { long b = 0x10000000000L; + expect((b >> -63) == 0x8000000000L); } + + { long b = 1; int s = 64; + expect((b << s) == 1); } + + { long b = 0xFFFFFFFFFFFFFFFFL; int s = -1; + expect((b >>> s) == 1); } + + { long b = 0x10000000000L; int s = -63; + expect((b >> s) == 0x8000000000L); } + + { long b = 0xBEL; + expect((b & 0xFF) == 0xBEL); } + + { long b = 0xBEL; + expect((b >>> 0) == 0xBEL); } + + { long b = 0xBEL; + expect((b >> 0) == 0xBEL); } + + { long b = 0xBEL; + expect((b << 0) == 0xBEL); } + + { long b = 0xBEL; + expect(((b >>> 0) & 0xFF) == 0xBEL); } + + { long b = 0xBEL; int x = 0xFF; + expect((b & x) == 0xBEL); } + + { long b = 0xBEL; int x = 0; + expect((b >>> x) == 0xBEL); } + + { long b = 0xBEL; int x = 0; + expect((b >> x) == 0xBEL); } + + { long b = 0xBEL; int x = 0; + expect((b << x) == 0xBEL); } + + { long b = 0xBEL; int x = 0; int y = 0xFF; + expect(((b >>> x) & y) == 0xBEL); } + + { long b = 0xFFFFFFFFFFFFFFFFL; int s = 20; + expect((b >>> -s) == 0xFFFFF); + } } } diff --git a/test/Strings.java b/test/Strings.java index d98c1f13f9..a49b37c9e1 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -21,7 +21,66 @@ public class Strings { return true; } - public static void main(String[] args) { + private static void testDecode(final boolean prematureEOS) throws Exception { + java.io.Reader r = new java.io.InputStreamReader + (new java.io.InputStream() { + int state = 0; + + public int read() { + throw new UnsupportedOperationException(); + } + + public int read(byte[] b, int offset, int length) { + if (length == 0) return 0; + + switch (state) { + case 0: + b[offset] = (byte) 0xc2; + state = 1; + return 1; + + case 1: + b[offset] = (byte) 0xae; + state = 2; + return 1; + + case 2: + b[offset] = (byte) 0xea; + state = 3; + return 1; + + case 3: + b[offset] = (byte) 0xba; + state = prematureEOS ? 5 : 4; + return 1; + + case 4: + b[offset] = (byte) 0xaf; + state = 5; + return 1; + + case 5: + return -1; + + default: + throw new RuntimeException(); + } + } + }, "UTF-8"); + + char[] buffer = new char[2]; + int offset = 0; + while (offset < buffer.length) { + int c = r.read(buffer, offset, buffer.length - offset); + if (c == -1) break; + offset += c; + } + + expect(new String(buffer, 0, offset).equals + (prematureEOS ? "\u00ae\ufffd" : "\u00ae\uaeaf")); + } + + public static void main(String[] args) throws Exception { expect(new String(new byte[] { 99, 111, 109, 46, 101, 99, 111, 118, 97, 116, 101, 46, 110, 97, 116, 46, 98, 117, 115, 46, 83, 121, 109, 98, 111, 108 }) @@ -77,5 +136,15 @@ public class Strings { expect(Character.forDigit(Character.digit('b', 16), 16) == 'b'); expect(Character.forDigit(Character.digit('f', 16), 16) == 'f'); expect(Character.forDigit(Character.digit('z', 36), 36) == 'z'); + + testDecode(false); + testDecode(true); + + expect + (java.text.MessageFormat.format + ("{0} enjoy {1} {2}. do {4}? {4} do?", + "I", "grape", "nuts", "foobar", + new Object() { public String toString() { return "you"; } }) + .equals("I enjoy grape nuts. do you? you do?")); } } diff --git a/test/jni.cpp b/test/jni.cpp new file mode 100644 index 0000000000..fe174edec9 --- /dev/null +++ b/test/jni.cpp @@ -0,0 +1,73 @@ +#include +#include "jni-util.h" + +extern "C" JNIEXPORT jdouble JNICALL +Java_JNI_addDoubles +(JNIEnv*, jclass, + jdouble a1, jdouble a2, jdouble a3, jdouble a4, jdouble a5, jdouble a6, + jdouble a7, jdouble a8, jdouble a9, jdouble a10, jdouble a11, jdouble a12, + jdouble a13, jdouble a14, jdouble a15, jdouble a16, jdouble a17, jdouble a18, + jdouble a19, jdouble a20) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + + a14 + a15 + a16 + a17 + a18 + a19 + a20; +} + +extern "C" JNIEXPORT jfloat JNICALL +Java_JNI_addFloats +(JNIEnv*, jclass, + jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6, + jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12, + jfloat a13, jfloat a14, jfloat a15, jfloat a16, jfloat a17, jfloat a18, + jfloat a19, jfloat a20) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + + a14 + a15 + a16 + a17 + a18 + a19 + a20; +} + +extern "C" JNIEXPORT jdouble JNICALL +Java_JNI_addMix +(JNIEnv*, jclass, + jfloat a1, jdouble a2, jfloat a3, jdouble a4, jfloat a5, jfloat a6, + jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12, + jfloat a13, jfloat a14, jfloat a15, jdouble a16, jfloat a17, jfloat a18, + jfloat a19, jfloat a20) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + + a14 + a15 + a16 + a17 + a18 + a19 + a20; +} + +extern "C" JNIEXPORT jfloat JNICALL +Java_JNI_doEcho__F(JNIEnv* e, jclass c, jfloat f) +{ + jvalue value; + value.f = f; + jvalue array[] = { value }; + return e->CallStaticFloatMethodA + (c, e->GetStaticMethodID(c, "echo", "(F)F"), array); +} + +extern "C" JNIEXPORT jdouble JNICALL +Java_JNI_doEcho__D(JNIEnv* e, jclass c, jdouble f) +{ + jvalue value; + value.d = f; + jvalue array[] = { value }; + return e->CallStaticDoubleMethodA + (c, e->GetStaticMethodID(c, "echo", "(D)D"), array); +} + +extern "C" JNIEXPORT jobject JNICALL +Java_Buffers_allocateNative(JNIEnv* e, jclass, jint capacity) +{ + void* p = allocate(e, capacity); + if (p == 0) return 0; + + return e->NewDirectByteBuffer(p, capacity); +} + +extern "C" JNIEXPORT void JNICALL +Java_Buffers_freeNative(JNIEnv* e, jclass, jobject b) +{ + free(e->GetDirectBufferAddress(b)); +}