From c602f4673b9b6f1ccf855d8c30c3f6f89938a825 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 3 Jul 2012 11:24:05 -0600 Subject: [PATCH 01/95] implement java.nio.channels.DatagramChannel --- classpath/java-nio.cpp | 102 +++++++++++++- classpath/java/net/ProtocolFamily.java | 13 ++ .../java/net/StandardProtocolFamily.java | 15 +++ .../java/nio/channels/DatagramChannel.java | 127 ++++++++++++++++++ test/Datagrams.java | 88 ++++++++++++ 5 files changed, 339 insertions(+), 6 deletions(-) create mode 100644 classpath/java/net/ProtocolFamily.java create mode 100644 classpath/java/net/StandardProtocolFamily.java create mode 100644 classpath/java/nio/channels/DatagramChannel.java create mode 100644 test/Datagrams.java diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 4120f276a8..5d597a0cff 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -257,7 +257,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 +272,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); } @@ -344,9 +348,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 +382,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 +416,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 +458,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 +528,19 @@ Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e, return r; } +extern "C" JNIEXPORT jint JNICALL +Java_java_nio_channels_DatagramChannel_read(JNIEnv* e, + jclass c, + jint socket, + jbyteArray buffer, + jint offset, + jint length, + jboolean blocking) +{ + return Java_java_nio_channels_SocketChannel_natRead + (e, c, socket, buffer, offset, length, blocking); +} + extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e, jclass, @@ -515,6 +581,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 +632,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 +752,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/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/nio/channels/DatagramChannel.java b/classpath/java/nio/channels/DatagramChannel.java new file mode 100644 index 0000000000..e2fb72c72f --- /dev/null +++ b/classpath/java/nio/channels/DatagramChannel.java @@ -0,0 +1,127 @@ +/* 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.StandardProtocolFamily; + +public class DatagramChannel extends SelectableChannel + implements ReadableByteChannel, WritableByteChannel +{ + public static final int InvalidSocket = -1; + + private int socket = InvalidSocket; + private boolean blocking = true; + + public DatagramChannel 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 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 { + if (b.remaining() == 0) return 0; + + byte[] array = b.array(); + if (array == null) throw new NullPointerException(); + + int c = read + (socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking); + + if (c > 0) { + b.position(b.position() + c); + } + + return c; + } + + 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 read(int socket, byte[] array, int offset, + int length, boolean blocking) + throws IOException; +} diff --git a/test/Datagrams.java b/test/Datagrams.java new file mode 100644 index 0000000000..78b1104c33 --- /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(StandardProtocolFamily.INET); + try { + out.configureBlocking(false); + out.connect(Address); + + DatagramChannel in = DatagramChannel.open(StandardProtocolFamily.INET); + try { + in.configureBlocking(false); + in.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.read(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(); + } + } +} From 9974d9164835aaa4590d6d085f07f538e7fe84cd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 10 Jul 2012 14:09:14 -0600 Subject: [PATCH 02/95] implement DatagramChannel.receive and fix Datagrams to be Java 6 compatible --- classpath/java-nio.cpp | 76 ++++++++++++++++--- classpath/java/net/DatagramSocket.java | 19 +++++ .../java/nio/channels/DatagramChannel.java | 67 ++++++++++++++-- test/Datagrams.java | 8 +- 4 files changed, 150 insertions(+), 20 deletions(-) create mode 100644 classpath/java/net/DatagramSocket.java diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 5d597a0cff..1464121def 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -337,6 +337,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) { @@ -529,16 +549,54 @@ Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e, } extern "C" JNIEXPORT jint JNICALL -Java_java_nio_channels_DatagramChannel_read(JNIEnv* e, - jclass c, - jint socket, - jbyteArray buffer, - jint offset, - jint length, - jboolean blocking) +Java_java_nio_channels_DatagramChannel_receive(JNIEnv* e, + jclass, + jint socket, + jbyteArray buffer, + jint offset, + jint length, + jboolean blocking, + jintArray address) { - return Java_java_nio_channels_SocketChannel_natRead - (e, c, socket, buffer, offset, length, blocking); + 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 { + e->SetIntArrayRegion(address, 0, 1, &host); + e->SetIntArrayRegion(address, 1, 1, &port); + } + + return r; } extern "C" JNIEXPORT jint JNICALL 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/nio/channels/DatagramChannel.java b/classpath/java/nio/channels/DatagramChannel.java index e2fb72c72f..ae30c75780 100644 --- a/classpath/java/nio/channels/DatagramChannel.java +++ b/classpath/java/nio/channels/DatagramChannel.java @@ -16,6 +16,8 @@ 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 @@ -26,7 +28,7 @@ public class DatagramChannel extends SelectableChannel private int socket = InvalidSocket; private boolean blocking = true; - public DatagramChannel configureBlocking(boolean v) throws IOException { + public SelectableChannel configureBlocking(boolean v) throws IOException { blocking = v; if (socket != InvalidSocket) { configureBlocking(socket, v); @@ -54,6 +56,16 @@ public class DatagramChannel extends SelectableChannel } } + 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 { @@ -97,19 +109,59 @@ public class DatagramChannel extends SelectableChannel } public int read(ByteBuffer b) throws IOException { - if (b.remaining() == 0) return 0; + 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 c = read - (socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking); + 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(); } - return c; + 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) @@ -121,7 +173,8 @@ public class DatagramChannel extends SelectableChannel private static native int write(int socket, byte[] array, int offset, int length, boolean blocking) throws IOException; - private static native int read(int socket, byte[] array, int offset, - int length, boolean blocking) + private static native int receive(int socket, byte[] array, int offset, + int length, boolean blocking, + int[] address) throws IOException; } diff --git a/test/Datagrams.java b/test/Datagrams.java index 78b1104c33..3e017261da 100644 --- a/test/Datagrams.java +++ b/test/Datagrams.java @@ -27,15 +27,15 @@ public class Datagrams { final SocketAddress Address = new InetSocketAddress(Hostname, Port); final byte[] Message = "hello, world!".getBytes(); - DatagramChannel out = DatagramChannel.open(StandardProtocolFamily.INET); + DatagramChannel out = DatagramChannel.open(); try { out.configureBlocking(false); out.connect(Address); - DatagramChannel in = DatagramChannel.open(StandardProtocolFamily.INET); + DatagramChannel in = DatagramChannel.open(); try { in.configureBlocking(false); - in.bind(Address); + in.socket().bind(Address); Selector selector = Selector.open(); try { @@ -60,7 +60,7 @@ public class Datagrams { case 1: { if (inKey.isReadable()) { - in.read(inBuffer); + in.receive(inBuffer); if (! inBuffer.hasRemaining()) { expect(equal(inBuffer.array(), inBuffer.arrayOffset(), From 4237a19b68a32570b5a95bce2fab686efdcac850 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 17 Jul 2012 18:21:17 -0600 Subject: [PATCH 03/95] add support for QNX on x86_32 All but one test is passing. The failure is due to the fact that QNX doesn't (in general) support calling fork(2) from a multithreaded process. Thus, we'll need to use spawn instead of fork/exec on QNX, which I'll attempt in a later commit. http://www.qnx.com/developers/docs/6.4.1/neutrino/getting_started/s1_procs.html --- classpath/java-net.cpp | 2 ++ classpath/java-nio.cpp | 1 + makefile | 25 ++++++++++++++++++++++--- src/posix.cpp | 2 +- src/x86.h | 6 ++++++ 5 files changed, 32 insertions(+), 4 deletions(-) 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 1464121def..17b249c502 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -31,6 +31,7 @@ # include # include # include +# include # include # include #endif diff --git a/makefile b/makefile index eeb2ce4ffe..7a6800760e 100755 --- a/makefile +++ b/makefile @@ -5,6 +5,7 @@ version = 0.6 build-arch := $(shell uname -m \ | sed 's/^i.86$$/i386/' \ + | sed 's/^x86pc$$/i386/' \ | sed 's/^arm.*$$/arm/' \ | sed 's/ppc/powerpc/') @@ -309,6 +310,24 @@ ifeq ($(build-platform),darwin) build-lflags += -framework CoreFoundation endif +ifeq ($(platform),qnx) + target-platform = linux + 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 + prefix = i486-pc-nto-qnx6.5.0- + endif + cxx = $(prefix)g++ + cc = $(prefix)gcc + ar = $(prefix)ar + ranlib = $(prefix)ranlib + strip = $(prefix)strip + rdynamic = -Wl,--export-dynamic +endif + ifeq ($(platform),darwin) ifeq (${OSX_SDK_SYSROOT},) OSX_SDK_SYSROOT = 10.4u @@ -994,7 +1013,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-platform) $(arch) $(build)/javahome.jar: @echo "creating $(@)" @@ -1005,7 +1024,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-platform) $(arch) define compile-generator-object @echo "compiling $(@)" @@ -1066,7 +1085,7 @@ $(bootimage-generator): $(bootimage-generator-objects) arch=$(build-arch) \ target-arch=$(arch) \ platform=$(bootimage-platform) \ - target-platform=$(platform) \ + target-platform=$(target-platform) \ openjdk=$(openjdk) \ openjdk-src=$(openjdk-src) \ bootimage-generator= \ diff --git a/src/posix.cpp b/src/posix.cpp index ea3f133d37..4e45579137 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -28,7 +28,7 @@ #include "unistd.h" #include "pthread.h" #include "signal.h" -#include "sys/ucontext.h" +#include "ucontext.h" #include "stdint.h" #include "dirent.h" #include "sched.h" diff --git a/src/x86.h b/src/x86.h index 298cab6aaa..4d978b2a0c 100644 --- a/src/x86.h +++ b/src/x86.h @@ -64,6 +64,12 @@ # 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) # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) From cace9d4531952ee591ea9041ce4d0aee72a9dc7d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 17 Jul 2012 19:26:37 -0600 Subject: [PATCH 04/95] use vfork instead of fork on QNX On QNX, fork cannot be used in multithreaded programs, but vfork can, so that's what we'll use. http://www.qnx.com/developers/docs/6.4.1/neutrino/getting_started/s1_procs.html --- classpath/java-lang.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 3cad9680a3..82376799c1 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"); From 4bafdf628663f79d4433db9f748d4a8885446d0e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 17 Jul 2012 19:38:39 -0600 Subject: [PATCH 05/95] add QNX ARM support This is untested so far, since I haven't figured out how to install the ARM port of QNX on QEMU. --- makefile | 6 +++++- src/arm.h | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 7a6800760e..7e1ed6de37 100755 --- a/makefile +++ b/makefile @@ -318,7 +318,11 @@ ifeq ($(platform),qnx) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) build-lflags = $(common-lflags) else - prefix = i486-pc-nto-qnx6.5.0- + 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 diff --git a/src/arm.h b/src/arm.h index 42fc44e8bf..9008ac489e 100644 --- a/src/arm.h +++ b/src/arm.h @@ -44,7 +44,12 @@ 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__) +# 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) From b4ecec30340784a8313eea936f3e84fe35de37a4 Mon Sep 17 00:00:00 2001 From: Mike Keesey Date: Mon, 23 Jul 2012 18:55:11 -0600 Subject: [PATCH 06/95] Implementing add(T element) in AbstractList, which just calls add(size(), element) and returns true per the spec. --- classpath/java/util/AbstractList.java | 5 +++++ 1 file changed, 5 insertions(+) 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(); } From de086d1046fd6d958b92440b981fab877a1c6941 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 24 Jul 2012 11:38:43 -0600 Subject: [PATCH 07/95] fix typo in Arrays test --- test/Arrays.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Arrays.java b/test/Arrays.java index 27acd2e3ff..e00bbf5688 100644 --- a/test/Arrays.java +++ b/test/Arrays.java @@ -85,8 +85,8 @@ 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(a, null)); + expect(! java.util.Arrays.equals(null, b)); expect(java.util.Arrays.equals(null, null)); b[0] = a[0]; expect(java.util.Arrays.equals(a, b)); From 03c3182497b875365bc6d1bb7f8109628123e655 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Jul 2012 00:12:30 -0600 Subject: [PATCH 08/95] fix OS X regression due to QNX header differences --- src/posix.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/posix.cpp b/src/posix.cpp index 4e45579137..6b2184011b 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -14,7 +14,10 @@ #ifdef __APPLE__ # include "CoreFoundation/CoreFoundation.h" +# include "sys/ucontext.h" # undef assert +#else +# include "ucontext.h" #endif #include "sys/mman.h" @@ -28,7 +31,6 @@ #include "unistd.h" #include "pthread.h" #include "signal.h" -#include "ucontext.h" #include "stdint.h" #include "dirent.h" #include "sched.h" From c17710d2b096f15297204b39d67ffa431b70ab1d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 24 Jul 2012 16:50:24 -0600 Subject: [PATCH 09/95] fix int32_t*/jint* type incompatibility in java-nio.cpp --- classpath/java-nio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 17b249c502..a9a7088078 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -593,8 +593,8 @@ Java_java_nio_channels_DatagramChannel_receive(JNIEnv* e, } else if (r == 0) { return -1; } else { - e->SetIntArrayRegion(address, 0, 1, &host); - e->SetIntArrayRegion(address, 1, 1, &port); + jint jhost = host; e->SetIntArrayRegion(address, 0, 1, &jhost); + jint jport = port; e->SetIntArrayRegion(address, 1, 1, &jport); } return r; From 836fc211068b76be1f8ff3068ccc1d7f1a528177 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 31 Jul 2012 09:27:18 -0600 Subject: [PATCH 10/95] fix bugs in File.getParent and listFiles getParent should return the same value regardless of whether it ends in a file separator, and listFiles should return null for non-directories. --- classpath/java/io/File.java | 50 +++++++++++++++++++++++-------------- test/Files.java | 6 +++++ 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 86e093495b..d8bfd474b4 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -148,9 +148,13 @@ public class File implements Serializable { } public String getParent() { - int index = path.lastIndexOf(FileSeparator); + String p = path; + while (p.endsWith(FileSeparator)) { + p = p.substring(0, p.length() - 1); + } + int index = p.lastIndexOf(FileSeparator); if (index >= 0) { - return path.substring(0, index); + return p.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/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); } } From a97c5728bb6265933024f1a4a1e7e3d8db992358 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 31 Jul 2012 16:36:01 +0000 Subject: [PATCH 11/95] add support for the ARM hardware floating point ABI This ABI's calling convention passes arguments and returns results using VFP registers, so we need to tweak vmNativeCall to match it. Thanks to Damjan Jovanovic for pointing this out and providing an initial patch. --- src/arm.S | 27 +++++++++++++++++++++++++-- src/arm.h | 46 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/arm.S b/src/arm.S index dceb8d3b75..d7b0c6ce6d 100644 --- a/src/arm.S +++ b/src/arm.S @@ -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 @@ -51,11 +57,28 @@ LOCAL(loop): // setup argument registers if necessary tst r6, r6 ldmneia r6, {r0-r3} +#if defined(__VFP_FP__) && (! defined(__SOFTFP__)) + // and VFP registers + vldmia r7, {d0-d8} +#endif blx r4 // call function add sp, sp, r5 // deallocate stack - ldmfd sp!, {r4-r6, pc} // restore non-volatile regs and return +#if defined(__VFP_FP__) && (! defined(__SOFTFP__)) + 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 diff --git a/src/arm.h b/src/arm.h index 9008ac489e..da06b97865 100644 --- a/src/arm.h +++ b/src/arm.h @@ -60,7 +60,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 { @@ -131,7 +132,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; @@ -143,6 +144,10 @@ 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; + uintptr_t stack[(argumentCount * 8) / BytesPerWord]; // is > argumentSize to account for padding unsigned stackIndex = 0; @@ -150,6 +155,36 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, for (unsigned ati = 0; ati < argumentCount; ++ ati) { switch (argumentTypes[ati]) { case DOUBLE_TYPE: +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + { + if (vfpIndex + Alignment <= VfpCount) { + if (vfpIndex % Alignment) { + ++ 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 (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 @@ -193,11 +228,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 From b023f5a2aaa2ffe5ce02f2e87bc462982c28ba7e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 31 Jul 2012 20:02:03 +0000 Subject: [PATCH 12/95] fix allocate/free size mismatch in interpret.cpp This was causing a crash every time the VM was run when build using mode=debug and process=interpret. --- src/interpret.cpp | 2 +- src/posix.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/interpret.cpp b/src/interpret.cpp index 9f28a2f769..c3617122a5 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -3166,7 +3166,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/posix.cpp b/src/posix.cpp index 6b2184011b..6ea15ab118 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -904,6 +904,7 @@ class MySystem: public System { } virtual void abort() { + *static_cast(0) = 0; ::abort(); } From 2ec1eee6f5047fb653dc97777ea3b7b9f2225ecd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 31 Jul 2012 20:07:34 +0000 Subject: [PATCH 13/95] revert debug code accidentally included in last commit --- src/posix.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/posix.cpp b/src/posix.cpp index 6ea15ab118..6b2184011b 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -904,7 +904,6 @@ class MySystem: public System { } virtual void abort() { - *static_cast(0) = 0; ::abort(); } From 67ec092e9ab35b7f742f432fabfb6add40c8293e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Aug 2012 16:02:55 +0000 Subject: [PATCH 14/95] add JNI test to test suite --- makefile | 30 ++++++++++++++++++++++++------ test/JNI.java | 33 +++++++++++++++++++++++++++++++++ test/jni.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 test/JNI.java create mode 100644 test/jni.cpp diff --git a/makefile b/makefile index 7e1ed6de37..fa197dc8c6 100755 --- a/makefile +++ b/makefile @@ -86,6 +86,8 @@ ifeq ($(build-platform),darwin) library-path-variable = DYLD_LIBRARY_PATH endif +library-path = $(library-path-variable)=$(test-build) + ifneq ($(openjdk),) openjdk-arch = $(arch) ifeq ($(arch),x86_64) @@ -123,10 +125,10 @@ ifneq ($(openjdk),) test-executable = $(shell pwd)/$(executable-dynamic) ifeq ($(build-platform),darwin) library-path = \ - $(library-path-variable)=$(build):$(openjdk)/jre/lib + $(library-path-variable)=$(test-build):$(build):$(openjdk)/jre/lib else library-path = \ - $(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch) + $(library-path-variable)=$(test-build):$(build):$(openjdk)/jre/lib/$(openjdk-arch) endif javahome = "$$($(native-path) "$(openjdk)/jre")" endif @@ -148,8 +150,8 @@ ifeq ($(use-clang),true) build-cxx = clang -std=c++11 build-cc = clang else - build-cxx = g++ - build-cc = gcc + build-cxx = g++-4.7 + build-cc = gcc-4.7 endif mflag = @@ -187,7 +189,7 @@ 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)\" \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ @@ -800,9 +802,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 = $(test-build)/libtest.so test-dep = $(test-build).dep test-extra-sources = $(wildcard $(test)/extra/*.java) @@ -927,7 +932,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))"; \ @@ -962,6 +967,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 $(@)) diff --git a/test/JNI.java b/test/JNI.java new file mode 100644 index 0000000000..edd52364b5 --- /dev/null +++ b/test/JNI.java @@ -0,0 +1,33 @@ +public class JNI { + static { + System.loadLibrary("test"); + } + + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + 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); + + 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); + } +} diff --git a/test/jni.cpp b/test/jni.cpp new file mode 100644 index 0000000000..a4bfbf8093 --- /dev/null +++ b/test/jni.cpp @@ -0,0 +1,26 @@ +#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; +} From 2cb5a749916f486aaf926f16eb82ba8b4484962e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Aug 2012 16:48:26 +0000 Subject: [PATCH 15/95] fix mixed marshalling of mixed float/double argument lists on armhf When we skip a single-precision register to ensure a double-precision load is aligned, we need to remember that in case we see another single-precision argument later on, which we must backfill into that register we skipped according to the ABI. --- src/arm.h | 7 ++++++- test/JNI.java | 11 +++++++++++ test/jni.cpp | 12 ++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/arm.h b/src/arm.h index da06b97865..05c3e30cab 100644 --- a/src/arm.h +++ b/src/arm.h @@ -147,6 +147,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, const unsigned VfpCount = 16; uintptr_t vfpTable[VfpCount]; unsigned vfpIndex = 0; + unsigned vfpBackfillIndex = 0; uintptr_t stack[(argumentCount * 8) / BytesPerWord]; // is > argumentSize to account for padding unsigned stackIndex = 0; @@ -159,6 +160,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, { if (vfpIndex + Alignment <= VfpCount) { if (vfpIndex % Alignment) { + vfpBackfillIndex = vfpIndex; ++ vfpIndex; } @@ -177,7 +179,10 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, } break; case FLOAT_TYPE: - if (vfpIndex < VfpCount) { + if (vfpBackfillIndex) { + vfpTable[vfpBackfillIndex] = arguments[ai]; + vfpBackfillIndex = 0; + } else if (vfpIndex < VfpCount) { vfpTable[vfpIndex++] = arguments[ai]; } else { stack[stackIndex++] = arguments[ai]; diff --git a/test/JNI.java b/test/JNI.java index edd52364b5..dc24da9b8f 100644 --- a/test/JNI.java +++ b/test/JNI.java @@ -19,6 +19,12 @@ public class JNI { 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, @@ -29,5 +35,10 @@ public class JNI { (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); } } diff --git a/test/jni.cpp b/test/jni.cpp index a4bfbf8093..8dd009325a 100644 --- a/test/jni.cpp +++ b/test/jni.cpp @@ -24,3 +24,15 @@ Java_JNI_addFloats 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; +} From 2be438b2bb7ebe9ef6ba2b83b9771f2bad9208ff Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Aug 2012 11:20:41 -0600 Subject: [PATCH 16/95] fix bad offset for SSE argument marshalling in x86.S --- src/x86.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 4ffe2d58bf5ef58523fddf001afcbcb10615a787 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Aug 2012 19:59:34 +0000 Subject: [PATCH 17/95] load arguments into the first 8 VFP registers, not the first 9 --- src/arm.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arm.S b/src/arm.S index d7b0c6ce6d..e67dcc0681 100644 --- a/src/arm.S +++ b/src/arm.S @@ -59,7 +59,7 @@ LOCAL(loop): ldmneia r6, {r0-r3} #if defined(__VFP_FP__) && (! defined(__SOFTFP__)) // and VFP registers - vldmia r7, {d0-d8} + vldmia r7, {d0-d7} #endif blx r4 // call function From 5270db52c7b2d92417160f6234a544d4c5a9c0fb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Jul 2012 05:26:25 -0600 Subject: [PATCH 18/95] fix unused variable warning for non-hardfloat ARM systems --- src/arm.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/arm.h b/src/arm.h index 05c3e30cab..07035f33df 100644 --- a/src/arm.h +++ b/src/arm.h @@ -45,6 +45,8 @@ # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) #elif (defined __QNX__) +# include "arm/smpxchg.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]) @@ -117,6 +119,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); @@ -147,7 +151,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, const unsigned VfpCount = 16; uintptr_t vfpTable[VfpCount]; unsigned vfpIndex = 0; - unsigned vfpBackfillIndex = 0; + unsigned vfpBackfillIndex UNUSED = 0; uintptr_t stack[(argumentCount * 8) / BytesPerWord]; // is > argumentSize to account for padding unsigned stackIndex = 0; From 7467ebde13d5f10363d063119d112a496ee4b485 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Jul 2012 05:27:15 -0600 Subject: [PATCH 19/95] Revert "fix unused variable warning for non-hardfloat ARM systems" This reverts commit 5270db52c7b2d92417160f6234a544d4c5a9c0fb. --- src/arm.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/arm.h b/src/arm.h index 07035f33df..05c3e30cab 100644 --- a/src/arm.h +++ b/src/arm.h @@ -45,8 +45,6 @@ # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) #elif (defined __QNX__) -# include "arm/smpxchg.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]) @@ -119,8 +117,6 @@ 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); @@ -151,7 +147,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, const unsigned VfpCount = 16; uintptr_t vfpTable[VfpCount]; unsigned vfpIndex = 0; - unsigned vfpBackfillIndex UNUSED = 0; + unsigned vfpBackfillIndex = 0; uintptr_t stack[(argumentCount * 8) / BytesPerWord]; // is > argumentSize to account for padding unsigned stackIndex = 0; From 56da23b964e6233fc2833d587c5e555f15b1e6fc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 19 Jul 2012 05:28:03 -0600 Subject: [PATCH 20/95] fix unused variable warning for non-hardfloat ARM systems --- src/arm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arm.h b/src/arm.h index 05c3e30cab..8be28f5bb2 100644 --- a/src/arm.h +++ b/src/arm.h @@ -147,7 +147,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, const unsigned VfpCount = 16; uintptr_t vfpTable[VfpCount]; unsigned vfpIndex = 0; - unsigned vfpBackfillIndex = 0; + unsigned vfpBackfillIndex UNUSED = 0; uintptr_t stack[(argumentCount * 8) / BytesPerWord]; // is > argumentSize to account for padding unsigned stackIndex = 0; From 57e318bbeca2e27c4d775906a0d0fcd776164db1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 2 Aug 2012 10:40:49 -0600 Subject: [PATCH 21/95] revert accidentally-committed build-cc/build-cxx change --- makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index fa197dc8c6..6120005fba 100755 --- a/makefile +++ b/makefile @@ -150,8 +150,8 @@ ifeq ($(use-clang),true) build-cxx = clang -std=c++11 build-cc = clang else - build-cxx = g++-4.7 - build-cc = gcc-4.7 + build-cxx = g++ + build-cc = gcc endif mflag = From c1aa0b46b59531d4a2bf842146b361ee6b264bdc Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Thu, 2 Aug 2012 10:36:16 -0600 Subject: [PATCH 22/95] add support for FreeBSD --- classpath/java-lang.cpp | 2 ++ classpath/java-nio.cpp | 2 ++ makefile | 14 ++++++++++++++ src/binaryToObject/elf.cpp | 17 +++++++++++------ src/binaryToObject/tools.cpp | 5 ++++- src/binaryToObject/tools.h | 4 +++- src/classpath-openjdk.cpp | 2 ++ src/environment.h | 4 +++- src/posix.cpp | 11 +++++++++++ src/target-fields.h | 3 ++- src/x86.h | 6 ++++++ 11 files changed, 60 insertions(+), 10 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 82376799c1..865f3c3fb4 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -578,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-nio.cpp b/classpath/java-nio.cpp index a9a7088078..d5e067e1e4 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -31,6 +31,8 @@ # include # include # include +# include +# include # include # include # include diff --git a/makefile b/makefile index 6120005fba..2a91344f2e 100755 --- a/makefile +++ b/makefile @@ -334,6 +334,16 @@ ifeq ($(platform),qnx) 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) ifeq (${OSX_SDK_SYSROOT},) OSX_SDK_SYSROOT = 10.4u @@ -855,6 +865,10 @@ ifeq ($(target-platform),darwin) cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_DARWIN endif +ifeq ($(target-platform),freebsd) + cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_FREEBSD +endif + class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index b4e0025b02..f50e4b6eba 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -197,8 +197,8 @@ public: const unsigned machine; - ElfPlatform(PlatformInfo::Architecture arch): - Platform(PlatformInfo(PlatformInfo::Linux, arch)), + ElfPlatform(PlatformInfo::OperatingSystem os, PlatformInfo::Architecture arch): + Platform(PlatformInfo(os, arch)), machine(getElfPlatform(arch)) {} class FileWriter { @@ -372,10 +372,15 @@ public: } }; -ElfPlatform elfx86Platform(PlatformInfo::x86); -ElfPlatform elfArmPlatform(PlatformInfo::Arm); -ElfPlatform elfPowerPCPlatform(PlatformInfo::PowerPC); -ElfPlatform elfx86_64Platform(PlatformInfo::x86_64); +ElfPlatform elfLinuxX86Platform(PlatformInfo::Linux, PlatformInfo::x86); +ElfPlatform elfLinuxArmPlatform(PlatformInfo::Linux, PlatformInfo::Arm); +ElfPlatform elfLinuxPowerPCPlatform(PlatformInfo::Linux, PlatformInfo::PowerPC); +ElfPlatform elfLinuxX86_64Platform(PlatformInfo::Linux, PlatformInfo::x86_64); + +ElfPlatform elfFreeBSDx86Platform(PlatformInfo::FreeBSD, PlatformInfo::x86); +ElfPlatform elfFreeBSDArmPlatform(PlatformInfo::FreeBSD, PlatformInfo::Arm); +ElfPlatform elfFreeBSDPowerPCPlatform(PlatformInfo::FreeBSD, PlatformInfo::PowerPC); +ElfPlatform elfFreeBSDx86_64Platform(PlatformInfo::FreeBSD, PlatformInfo::x86_64); } // namespace diff --git a/src/binaryToObject/tools.cpp b/src/binaryToObject/tools.cpp index 3181474b94..89961a74c5 100644 --- a/src/binaryToObject/tools.cpp +++ b/src/binaryToObject/tools.cpp @@ -92,6 +92,8 @@ PlatformInfo::OperatingSystem PlatformInfo::osFromString(const char* os) { return Windows; } else if(strcmp(os, "darwin") == 0) { return Darwin; + } else if(strcmp(os, "freebsd") == 0) { + return FreeBSD; } else { return UnknownOS; } @@ -122,4 +124,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..dde9140678 100644 --- a/src/binaryToObject/tools.h +++ b/src/binaryToObject/tools.h @@ -135,6 +135,7 @@ public: Linux = AVIAN_PLATFORM_LINUX, Windows = AVIAN_PLATFORM_WINDOWS, Darwin = AVIAN_PLATFORM_DARWIN, + FreeBSD = AVIAN_PLATFORM_FREEBSD, UnknownOS = AVIAN_PLATFORM_UNKNOWN }; @@ -193,4 +194,5 @@ public: } // namespace avian -#endif \ No newline at end of file +#endif + diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index bbdb4a547e..febbf3b947 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3002,6 +3002,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__ diff --git a/src/environment.h b/src/environment.h index 045eb2642d..2d66407109 100644 --- a/src/environment.h +++ b/src/environment.h @@ -23,6 +23,7 @@ #define AVIAN_PLATFORM_LINUX 1 #define AVIAN_PLATFORM_WINDOWS 2 #define AVIAN_PLATFORM_DARWIN 3 +#define AVIAN_PLATFORM_FREEBSD 4 #define AVIAN_ARCH_UNKNOWN 0 #define AVIAN_ARCH_X86 (1 << 8) @@ -30,4 +31,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/posix.cpp b/src/posix.cpp index 6b2184011b..afa4c0ca38 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -17,6 +17,9 @@ # include "sys/ucontext.h" # undef assert #else +# if defined __FreeBSD__ +# include "limits.h" +# endif # include "ucontext.h" #endif @@ -797,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 @@ -806,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/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/x86.h b/src/x86.h index 4d978b2a0c..42cf083d77 100644 --- a/src/x86.h +++ b/src/x86.h @@ -70,6 +70,12 @@ # 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]) From 3a1343fb062adeca3940f79b433359950bbcaad9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 2 Aug 2012 10:49:32 -0600 Subject: [PATCH 23/95] add support for FreeBSD on x86_64 --- makefile | 1 + src/posix.cpp | 2 +- src/x86.h | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index 2a91344f2e..ae1ff9a240 100755 --- a/makefile +++ b/makefile @@ -6,6 +6,7 @@ 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/') diff --git a/src/posix.cpp b/src/posix.cpp index afa4c0ca38..1394a26886 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -627,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; diff --git a/src/x86.h b/src/x86.h index 42cf083d77..bda55bee7d 100644 --- a/src/x86.h +++ b/src/x86.h @@ -123,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]) From e641f23e6c595836bd2da4c83085a0541e6e1473 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 2 Aug 2012 12:14:15 -0600 Subject: [PATCH 24/95] fix "no newline at end of file" error on FreeBSD --- src/type-generator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/type-generator.cpp b/src/type-generator.cpp index f31b0f18c8..c53d0ee2cb 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -2207,5 +2207,7 @@ main(int ac, char** av) local::writeMaps(&out, declarations); } + out.write("\n"); + return 0; } From f03e5e8e552c80824599d840fc9bf753e1d04002 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 2 Aug 2012 12:15:15 -0600 Subject: [PATCH 25/95] clean up binary format code Linux, FreeBSD, and QNX all use ELF, so no need to distinguish between them when generating object files. To avoid confusion, I've switch from using operating system names to using binary format names where applicable. --- makefile | 31 +++++++++++++++---------------- src/arm.S | 2 +- src/binaryToObject/elf.cpp | 18 ++++++------------ src/binaryToObject/mach-o.cpp | 2 +- src/binaryToObject/main.cpp | 6 +++--- src/binaryToObject/pe.cpp | 2 +- src/binaryToObject/tools.cpp | 26 ++++++++++++++++---------- src/binaryToObject/tools.h | 21 ++++++++++----------- src/bootimage.cpp | 2 +- src/environment.h | 13 ++++++------- src/x86.cpp | 6 +++--- 11 files changed, 63 insertions(+), 66 deletions(-) diff --git a/makefile b/makefile index ae1ff9a240..34796f61f8 100755 --- a/makefile +++ b/makefile @@ -24,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 @@ -165,6 +164,8 @@ ifneq ($(platform),darwin) endif endif +target-format = elf + cxx = $(build-cxx) $(mflag) cc = $(build-cc) $(mflag) @@ -211,7 +212,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) @@ -314,7 +315,6 @@ ifeq ($(build-platform),darwin) endif ifeq ($(platform),qnx) - target-platform = linux cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) lflags = $(common-lflags) -lsocket ifeq ($(build-platform),qnx) @@ -346,6 +346,7 @@ ifeq ($(platform),freebsd) endif ifeq ($(platform),darwin) + target-format = macho ifeq (${OSX_SDK_SYSROOT},) OSX_SDK_SYSROOT = 10.4u endif @@ -427,6 +428,8 @@ ifeq ($(platform),darwin) endif ifeq ($(platform),windows) + target-format = pe + inc = "$(win32)/include" lib = "$(win32)/lib" @@ -854,20 +857,16 @@ 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 -endif - -ifeq ($(target-platform),freebsd) - cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_FREEBSD +ifeq ($(target-format),macho) + cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_MACHO endif class-name = $(patsubst $(1)/%.class,%,$(2)) @@ -1050,7 +1049,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 $(target-platform) $(arch) + _binary_classpath_jar_end $(target-format) $(arch) $(build)/javahome.jar: @echo "creating $(@)" @@ -1061,7 +1060,7 @@ $(build)/javahome.jar: $(javahome-object): $(build)/javahome.jar $(converter) @echo "creating $(@)" $(converter) $(<) $(@) _binary_javahome_jar_start \ - _binary_javahome_jar_end $(target-platform) $(arch) + _binary_javahome_jar_end $(target-format) $(arch) define compile-generator-object @echo "compiling $(@)" @@ -1122,7 +1121,7 @@ $(bootimage-generator): $(bootimage-generator-objects) arch=$(build-arch) \ target-arch=$(arch) \ platform=$(bootimage-platform) \ - target-platform=$(target-platform) \ + target-format=$(target-format) \ openjdk=$(openjdk) \ openjdk-src=$(openjdk-src) \ bootimage-generator= \ diff --git a/src/arm.S b/src/arm.S index e67dcc0681..e62c0a60e0 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 diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index f50e4b6eba..a2277c3488 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -197,8 +197,8 @@ public: const unsigned machine; - ElfPlatform(PlatformInfo::OperatingSystem os, PlatformInfo::Architecture arch): - Platform(PlatformInfo(os, arch)), + ElfPlatform(PlatformInfo::Architecture arch): + Platform(PlatformInfo(PlatformInfo::Elf, arch)), machine(getElfPlatform(arch)) {} class FileWriter { @@ -372,15 +372,9 @@ public: } }; -ElfPlatform elfLinuxX86Platform(PlatformInfo::Linux, PlatformInfo::x86); -ElfPlatform elfLinuxArmPlatform(PlatformInfo::Linux, PlatformInfo::Arm); -ElfPlatform elfLinuxPowerPCPlatform(PlatformInfo::Linux, PlatformInfo::PowerPC); -ElfPlatform elfLinuxX86_64Platform(PlatformInfo::Linux, PlatformInfo::x86_64); - -ElfPlatform elfFreeBSDx86Platform(PlatformInfo::FreeBSD, PlatformInfo::x86); -ElfPlatform elfFreeBSDArmPlatform(PlatformInfo::FreeBSD, PlatformInfo::Arm); -ElfPlatform elfFreeBSDPowerPCPlatform(PlatformInfo::FreeBSD, PlatformInfo::PowerPC); -ElfPlatform elfFreeBSDx86_64Platform(PlatformInfo::FreeBSD, PlatformInfo::x86_64); - +ElfPlatform elfX86Platform(PlatformInfo::x86); +ElfPlatform elfArmPlatform(PlatformInfo::Arm); +ElfPlatform elfPowerPCPlatform(PlatformInfo::PowerPC); +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 89961a74c5..9cc9059b93 100644 --- a/src/binaryToObject/tools.cpp +++ b/src/binaryToObject/tools.cpp @@ -85,17 +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; - } else if(strcmp(os, "freebsd") == 0) { - return FreeBSD; +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; } } diff --git a/src/binaryToObject/tools.h b/src/binaryToObject/tools.h index dde9140678..46bcd691e8 100644 --- a/src/binaryToObject/tools.h +++ b/src/binaryToObject/tools.h @@ -131,12 +131,11 @@ public: class PlatformInfo { public: - enum OperatingSystem { - Linux = AVIAN_PLATFORM_LINUX, - Windows = AVIAN_PLATFORM_WINDOWS, - Darwin = AVIAN_PLATFORM_DARWIN, - FreeBSD = AVIAN_PLATFORM_FREEBSD, - UnknownOS = AVIAN_PLATFORM_UNKNOWN + enum Format { + Elf = AVIAN_FORMAT_ELF, + Pe = AVIAN_FORMAT_PE, + MachO = AVIAN_FORMAT_MACHO, + UnknownFormat = AVIAN_FORMAT_UNKNOWN }; enum Architecture { @@ -147,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() { diff --git a/src/bootimage.cpp b/src/bootimage.cpp index bfcbe2220e..a4ac6331c6 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -1647,7 +1647,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/environment.h b/src/environment.h index 2d66407109..f24150cd0f 100644 --- a/src/environment.h +++ b/src/environment.h @@ -11,19 +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_PLATFORM_FREEBSD 4 +#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) diff --git a/src/x86.cpp b/src/x86.cpp index 2a6d39d0aa..47a7ab2ad6 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2781,7 +2781,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 +2803,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 +2814,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: From 296a1e5bab879c04ddcefc4257a31302afa819b0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 2 Aug 2012 12:47:48 -0600 Subject: [PATCH 26/95] use so-prefix and so-suffix to generate test library name This fixes the JNI test for Windows and OS X. --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 34796f61f8..246b7edb7c 100755 --- a/makefile +++ b/makefile @@ -821,7 +821,7 @@ 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 = $(test-build)/libtest.so +test-library = $(test-build)/$(so-prefix)test$(so-suffix) test-dep = $(test-build).dep test-extra-sources = $(wildcard $(test)/extra/*.java) From 2fb2fd9bb01931c8a370099c9258ac6e8cf4b5f8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 2 Aug 2012 12:56:15 -0600 Subject: [PATCH 27/95] put test library in same directory as avian executable This is a workaround for the fact that there's no precise equivalent to LD_LIBRARY_PATH available on Windows. --- makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/makefile b/makefile index 246b7edb7c..d8cd4f9df8 100755 --- a/makefile +++ b/makefile @@ -86,7 +86,7 @@ ifeq ($(build-platform),darwin) library-path-variable = DYLD_LIBRARY_PATH endif -library-path = $(library-path-variable)=$(test-build) +library-path = $(library-path-variable)=$(build) ifneq ($(openjdk),) openjdk-arch = $(arch) @@ -125,10 +125,10 @@ ifneq ($(openjdk),) test-executable = $(shell pwd)/$(executable-dynamic) ifeq ($(build-platform),darwin) library-path = \ - $(library-path-variable)=$(test-build):$(build):$(openjdk)/jre/lib + $(library-path-variable)=$(build):$(openjdk)/jre/lib else library-path = \ - $(library-path-variable)=$(test-build):$(build):$(openjdk)/jre/lib/$(openjdk-arch) + $(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch) endif javahome = "$$($(native-path) "$(openjdk)/jre")" endif @@ -821,7 +821,7 @@ 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 = $(test-build)/$(so-prefix)test$(so-suffix) +test-library = $(build)/$(so-prefix)test$(so-suffix) test-dep = $(test-build).dep test-extra-sources = $(wildcard $(test)/extra/*.java) From 5a09774353bdab1ab22a0ec9c71d0ac165cf2ccc Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Sat, 4 Aug 2012 07:29:39 -0600 Subject: [PATCH 28/95] tests don't compile when building with OpenJDK I get this error when compiling with "make openjdk=...." on both x86_64 and arm: compiling test classes test/Arrays.java:90: error: reference to equals is ambiguous, both method equals(float[],float[]) in Arrays and method equals(Object[],Object[]) in Arrays match expect(java.util.Arrays.equals(null, null)); test/Arrays.java:95: error: reference to hashCode is ambiguous, both method hashCode(double[]) in Arrays and method hashCode(Object[]) in Arrays match java.util.Arrays.hashCode(null); The attached patch fixes this. --- test/Arrays.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Arrays.java b/test/Arrays.java index e00bbf5688..42e958068a 100644 --- a/test/Arrays.java +++ b/test/Arrays.java @@ -87,12 +87,12 @@ public class Arrays { expect(! java.util.Arrays.equals(b, new Object[4])); expect(! java.util.Arrays.equals(a, null)); expect(! java.util.Arrays.equals(null, b)); - expect(java.util.Arrays.equals(null, null)); + 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); } } } From 59d7f5a47adf95aeae886f39f0c9ece1d7ff6d1e Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Sat, 4 Aug 2012 07:31:54 -0600 Subject: [PATCH 29/95] fix java.library.path on the ARM platform On the ARM platform, Avian compiled to use OpenJDK gets this error on startup: java/lang/UnsatisfiedLinkError: no zip in java.library.path at java/lang/ClassLoader.loadLibrary (line 1860) at java/lang/Runtime.loadLibrary0 (line 845) at java/lang/System.loadLibrary (line 1084) at java/lang/System.initializeSystemClass (line 1145) Using strace shows why: [pid 22431] stat64("/usr/lib/jvm/java-7-openjdk-armhf/jre/lib/i386/libzip.so", 0xbee377e0) = -1 ENOENT (No such file or directory) The attached patch uses "arm" instead of "i386" in that path. This fixes the problem. --- src/classpath-openjdk.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index febbf3b947..622600b3be 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -417,6 +417,8 @@ 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"); From ebd7f69c417c11e488c59808748ac729ac7940df Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 3 Aug 2012 20:00:27 -0600 Subject: [PATCH 30/95] fix a couple of QNX/ARM issues On QNX, we need to use msync to sync the instruction cache. Also, even though the compiler doesn't define __SOFTFP__, QNX uses the softfp ABI on ARM. --- src/arm.S | 4 ++-- src/arm.h | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/arm.S b/src/arm.S index e62c0a60e0..01d0839079 100644 --- a/src/arm.S +++ b/src/arm.S @@ -57,7 +57,7 @@ LOCAL(loop): // setup argument registers if necessary tst r6, r6 ldmneia r6, {r0-r3} -#if defined(__VFP_FP__) && (! defined(__SOFTFP__)) +#if defined(__VFP_FP__) && (! defined(__SOFTFP__)) && (! defined(__QNX__)) // and VFP registers vldmia r7, {d0-d7} #endif @@ -65,7 +65,7 @@ LOCAL(loop): blx r4 // call function add sp, sp, r5 // deallocate stack -#if defined(__VFP_FP__) && (! defined(__SOFTFP__)) +#if defined(__VFP_FP__) && (! defined(__SOFTFP__)) && (! defined(__QNX__)) cmp r8,#FLOAT_TYPE bne LOCAL(double) fmrs r0,s0 diff --git a/src/arm.h b/src/arm.h index 8be28f5bb2..8ae057d610 100644 --- a/src/arm.h +++ b/src/arm.h @@ -45,6 +45,9 @@ # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) #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]) @@ -100,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), @@ -117,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); @@ -156,7 +163,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, for (unsigned ati = 0; ati < argumentCount; ++ ati) { switch (argumentTypes[ati]) { case DOUBLE_TYPE: -#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) && !defined(__QNX__) { if (vfpIndex + Alignment <= VfpCount) { if (vfpIndex % Alignment) { From 248ff91d747f455ad5095651cf08b9a7d056142a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 4 Aug 2012 12:36:18 -0600 Subject: [PATCH 31/95] terminate zero-length char array with null char in stringUTFChars --- src/machine.cpp | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 964bfd5452..dbf2e12dfc 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3667,34 +3667,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 From 852d77d0b5c63cd93b480ebb52d35fdddf0b14e9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 4 Aug 2012 16:08:32 -0600 Subject: [PATCH 32/95] implement Arrays.toString(byte[]) --- classpath/java/util/Arrays.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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)); } From c63668c1ce6bccd99acb063d6b26aacf910c9c6e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 4 Aug 2012 16:11:27 -0600 Subject: [PATCH 33/95] fix ArrayIndexOutOfBoundsException when decoding a UTF-8 stream --- classpath/avian/Utf8.java | 24 +++++++-- classpath/java/io/InputStreamReader.java | 57 ++++++++++++++++++--- test/Strings.java | 64 +++++++++++++++++++++++- 3 files changed, 134 insertions(+), 11 deletions(-) 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/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/test/Strings.java b/test/Strings.java index d98c1f13f9..bfc498ae65 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(); + } + } + }); + + 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,8 @@ 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); } } From 96d5dae06c790fdadd43d88274f368951fcf1053 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 4 Aug 2012 18:41:44 -0600 Subject: [PATCH 34/95] specify UTF-8 explicitly in Strings.testDecode This fixes a test failure with the OpenJDK port. --- test/Strings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Strings.java b/test/Strings.java index bfc498ae65..bfba02268d 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -66,7 +66,7 @@ public class Strings { throw new RuntimeException(); } } - }); + }, "UTF-8"); char[] buffer = new char[2]; int offset = 0; From 021590af05e33885ec015e82ed565368a2e8a341 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 4 Aug 2012 18:50:43 -0600 Subject: [PATCH 35/95] fix JNI test for openjdk-src build --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index d8cd4f9df8..52266b30f2 100755 --- a/makefile +++ b/makefile @@ -872,7 +872,7 @@ 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) From 5a7c78e71ac7b4045c23d215162fb12848f1a5f3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Aug 2012 19:18:51 -0600 Subject: [PATCH 36/95] ignore case when looking for Main-Class manifest attribute Per the spec, attribute names should be case-insensitive: http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2518d60a13..909069ba0a 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, From 53b15d1bca1afcab55c7710530cff3fe9ee476ec Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Sun, 5 Aug 2012 19:31:20 -0600 Subject: [PATCH 37/95] look for initIDs in SunFontManager instead of FontManager OpenJDK 7 has refactored this code relative to OpenJDK 6, and now FontManager is an interface, with SunFontManager providing a (partial) implementation. --- src/classpath-openjdk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 622600b3be..422857e48e 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -534,7 +534,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 From 6aba7bef5af14f0dce4ad98c7ed0e196a9080676 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 6 Aug 2012 16:55:49 -0600 Subject: [PATCH 38/95] add java.lang.Deprecated --- classpath/java/lang/Deprecated.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 classpath/java/lang/Deprecated.java 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 { } From 3af278b5e6315a88d44de9f71ac45320b1041e50 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 7 Aug 2012 17:18:04 -0600 Subject: [PATCH 39/95] fix Clang warnings in windows.cpp --- src/windows.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)); From 2642a167e256d49efb7f485f328e6e55778af484 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 11 Aug 2012 06:45:13 -0600 Subject: [PATCH 40/95] fix Class.getPackage for system classes in OpenJDK build --- src/classpath-openjdk.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 422857e48e..8c5ed0e126 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3521,9 +3521,9 @@ extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_ClassLoaderDepth)(Thread*) { abort(); } extern "C" JNIEXPORT jstring JNICALL -EXPORT(JVM_GetSystemPackage)(Thread*, jstring) +EXPORT(JVM_GetSystemPackage)(Thread*, jstring s) { - return 0; + return s; } uint64_t From 01be4b23bb67c7eda434dcedb9fc2091dec9e3ff Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 11 Aug 2012 06:56:19 -0600 Subject: [PATCH 41/95] implement JNI methods needed by AWT These include PushLocalFrame, PopLocalFrame, NewDirectByteBuffer, GetDirectBufferAddress, and GetDirectBufferCapacity. --- classpath/java/nio/ArrayByteBuffer.java | 87 +++++++ classpath/java/nio/ByteBuffer.java | 243 ++++++++++--------- classpath/java/nio/DirectByteBuffer.java | 105 ++++++++ classpath/java/nio/FixedArrayByteBuffer.java | 58 +++++ classpath/sun/misc/Unsafe.java | 10 + src/builtin.cpp | 52 ++++ src/classpath-openjdk.cpp | 43 +--- src/compile.cpp | 39 +++ src/interpret.cpp | 43 +++- src/jnienv.cpp | 84 +++++-- src/processor.h | 6 + test/jni.cpp | 15 ++ 12 files changed, 620 insertions(+), 165 deletions(-) create mode 100644 classpath/java/nio/ArrayByteBuffer.java create mode 100644 classpath/java/nio/DirectByteBuffer.java create mode 100644 classpath/java/nio/FixedArrayByteBuffer.java diff --git a/classpath/java/nio/ArrayByteBuffer.java b/classpath/java/nio/ArrayByteBuffer.java new file mode 100644 index 0000000000..2f2e7d5024 --- /dev/null +++ b/classpath/java/nio/ArrayByteBuffer.java @@ -0,0 +1,87 @@ +/* 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 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) { + checkPut(position, src.remaining()); + src.get(array, arrayOffset + position, src.remaining()); + position += src.remaining(); + 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..73da8fbc78 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,51 @@ 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() { + 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 +97,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 +120,122 @@ 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)); + putShort(position, val); + position += 2; return this; } - public ByteBuffer putLong(long val) { - checkPut(8); - putInt((int)(val >> 32)); - putInt((int)val); - return this; - } - - public byte get() { - checkGet(1); - return array[arrayOffset+(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/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/src/builtin.cpp b/src/builtin.cpp index 9c3dca8508..c438aebea0 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -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-openjdk.cpp b/src/classpath-openjdk.cpp index 8c5ed0e126..b0e0c51a2c 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2396,13 +2396,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) @@ -2522,6 +2515,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) @@ -2784,32 +2785,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) @@ -3023,6 +2998,8 @@ 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"); + local::setProperty (t, method, *properties, "java.home", static_cast(t->m->classpath)->javaHome); diff --git a/src/compile.cpp b/src/compile.cpp index 166468dcec..07e7f53911 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; }; @@ -8778,6 +8791,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/interpret.cpp b/src/interpret.cpp index c3617122a5..4175f77146 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]; }; @@ -3010,6 +3023,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) { diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 5846bea7b2..e4abe152f5 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -407,24 +407,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,7 +421,7 @@ 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 @@ -3154,6 +3136,8 @@ GetPrimitiveArrayCritical(Thread* t, jarray array, jboolean* isCopy) *isCopy = true; } + expect(t, *array); + return reinterpret_cast(*array) + 2; } @@ -3276,6 +3260,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 +3600,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 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/test/jni.cpp b/test/jni.cpp index 8dd009325a..8c1ea91f05 100644 --- a/test/jni.cpp +++ b/test/jni.cpp @@ -36,3 +36,18 @@ Java_JNI_addMix return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20; } + +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)); +} From 242a6a0d0f9552150febe2a24cbeeeba5f47a989 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 11 Aug 2012 06:58:07 -0600 Subject: [PATCH 42/95] fix field offset calculation mismatch between type-generator.cpp and machine.cpp --- src/type-generator.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/type-generator.cpp b/src/type-generator.cpp index c53d0ee2cb..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); From 373a92d4d6dc9b6d81b91fcc88cfbce8e5a6f218 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 11 Aug 2012 08:01:44 -0600 Subject: [PATCH 43/95] add Buffers test --- test/Buffers.java | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 test/Buffers.java 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); + } +} From e2416ddb8504bcc6b202b908639eb158b5a745fe Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 11 Aug 2012 08:21:14 -0600 Subject: [PATCH 44/95] strip trailing separators when normalizing java.io.File.path This addresses the case of e.g. new File("c:/foo/").exists() returning false when the specified directory really does exist. --- classpath/java/io/File.java | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index d8bfd474b4..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_); @@ -148,13 +152,9 @@ public class File implements Serializable { } public String getParent() { - String p = path; - while (p.endsWith(FileSeparator)) { - p = p.substring(0, p.length() - 1); - } - int index = p.lastIndexOf(FileSeparator); + int index = path.lastIndexOf(FileSeparator); if (index >= 0) { - return p.substring(0, index); + return normalize(path.substring(0, index)); } else { return null; } From e2ff771baa47ba85066055101525162b1dc49c3b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 11 Aug 2012 08:56:21 -0600 Subject: [PATCH 45/95] handle basic argument substitution in MessageFormat.format Thanks to Remi for an initial version of this patch. --- classpath/java/text/MessageFormat.java | 10 ++++++++-- test/Strings.java | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) 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/test/Strings.java b/test/Strings.java index bfba02268d..a49b37c9e1 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -139,5 +139,12 @@ public class Strings { 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?")); } } From b3252215793d3f2304d8e0db66bb2e66244fcd91 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 11 Aug 2012 19:01:32 -0600 Subject: [PATCH 46/95] rename "resource" URL protocol to "avian_vm_resource" This fixes a problem with JOSM, which attaches its own meaning to the "resource" protocol. The new name is less likely to cause such conflicts. --- classpath/avian/{resource => avian_vm_resource}/Handler.java | 2 +- classpath/java/net/URL.java | 4 ++-- makefile | 2 +- src/finder.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename classpath/avian/{resource => avian_vm_resource}/Handler.java (98%) diff --git a/classpath/avian/resource/Handler.java b/classpath/avian/avian_vm_resource/Handler.java similarity index 98% rename from classpath/avian/resource/Handler.java rename to classpath/avian/avian_vm_resource/Handler.java index 51e8d1a838..dfad1f7964 100644 --- a/classpath/avian/resource/Handler.java +++ b/classpath/avian/avian_vm_resource/Handler.java @@ -8,7 +8,7 @@ There is NO WARRANTY for this software. See license.txt for details. */ -package avian.resource; +package avian.avian_vm_resource; import java.net.URL; import java.net.URLStreamHandler; diff --git a/classpath/java/net/URL.java b/classpath/java/net/URL.java index f80e327997..3c2852f394 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 ("avian_vm_resource".equals(protocol)) { + return new avian.avian_vm_resource.Handler(); } else if ("file".equals(protocol)) { return new avian.file.Handler(); } else if ("jar".equals(protocol)) { diff --git a/makefile b/makefile index 52266b30f2..eef4e14d0d 100755 --- a/makefile +++ b/makefile @@ -795,7 +795,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/avian_vm_resource/Handler.java ifneq ($(openjdk),) classpath-sources := $(classpath-sources) \ diff --git a/src/finder.cpp b/src/finder.cpp index ba8aef75f4..12c8edc8eb 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -602,7 +602,7 @@ class BuiltinElement: public JarElement { } virtual const char* urlPrefix() { - return "resource:"; + return "avian_vm_resource:"; } virtual const char* sourceUrl() { From f8e860999ad271d1f965cad23694b4496305049f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 12 Aug 2012 10:55:37 -0600 Subject: [PATCH 47/95] fix incorrect reporting of fixie collection status in heap.cpp This led to fixed-position objects being considered unreachable when they were actually still reachable, causing global weak JNI references to be cleared prematurely, most notably leading to crashes in AWT buffered image code. This commit also fixes a field offset calculation mismatch in bootimage.cpp relative to machine.cpp. --- src/bootimage.cpp | 18 +++---- src/heap.cpp | 122 +++++++++++++++++++++++++++++++++++++--------- src/heap.h | 1 + src/machine.cpp | 2 + 4 files changed, 107 insertions(+), 36 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index a4ac6331c6..4525b3ec05 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; @@ -441,11 +441,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; } @@ -540,8 +536,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, } } - // if (strcmp(name, "avian/VMClass.class") == 0) trap(); - if (hashMapFind(t, typeMaps, c, objectHash, objectEqual) == 0) { object array = makeByteArray (t, TypeMap::sizeInBytes @@ -1175,13 +1169,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) diff --git a/src/heap.cpp b/src/heap.cpp index ed5d8777d4..0bc37862fd 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,14 @@ 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->move(c, &(c->markedFixies)); } *needsVisit = false; @@ -1044,13 +1107,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 +1122,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 +1153,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 +1161,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)) { @@ -1871,7 +1934,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 +2009,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..c3f1f8b4c8 100644 --- a/src/heap.h +++ b/src/heap.h @@ -69,6 +69,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/machine.cpp b/src/machine.cpp index dbf2e12dfc..b9782ac3f0 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2690,6 +2690,8 @@ class HeapClient: public Heap::Client { virtual void visitRoots(Heap::Visitor* v) { ::visitRoots(m, v); + m->heap->postVisit(); + postVisit(m->rootThread, v); } From 47503854d58bfa53ca8ee36bf9616b2c3ffdefcb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 12 Aug 2012 11:17:59 -0600 Subject: [PATCH 48/95] Thread.sleep(0) should not sleep indefinitely Our implementation uses Object.wait(long) to implement Thread.sleep, which had the side effect of interpreting zero as infinity. However, for Thread.sleep, zero just means zero. I assume that doesn't mean "don't sleep at all", though, or else the app wouldn't have called Thread.sleep in the first place, so this patch sleeps for one millisecond when zero is passed -- just enough to yield the processor for a bit. Thread.yield might be a better choice in this case, but I assume the app would have called that directly if that's what it wanted. --- classpath/java/lang/Thread.java | 4 ++++ src/classpath-openjdk.cpp | 4 ++++ 2 files changed, 8 insertions(+) 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/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index b0e0c51a2c..a965fd676d 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3309,6 +3309,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); From b98abe3f94dbf552595554787ef2115c3009856c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 12 Aug 2012 14:31:58 -0600 Subject: [PATCH 49/95] fix float to integer conversion Java requires that NaNs be converted to zero and that numbers at or beyond the limits of integer representation be clamped to the largest or smallest value that can be represented, respectively. --- classpath/java/lang/Float.java | 4 +++ src/arm.cpp | 6 +++- src/compile.cpp | 31 +++++++++++++++--- src/interpret.cpp | 38 ++++++++++++++++++++--- src/x86.cpp | 6 +++- test/Floats.java | 57 ++++++++++++++++++++++++++++++++++ 6 files changed, 132 insertions(+), 10 deletions(-) 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/src/arm.cpp b/src/arm.cpp index 4f7c74b7d4..2810a8700e 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -2379,7 +2379,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 { diff --git a/src/compile.cpp b/src/compile.cpp index 07e7f53911..6837e9e7b1 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2587,13 +2587,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 isinf(f) == 1 ? INT32_MAX : INT32_MIN; + 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 isinf(f) == 1 ? INT64_MAX : INT64_MIN; + default: return f >= INT64_MAX ? INT64_MAX + : (f <= INT64_MIN ? INT64_MIN : static_cast(f)); + } } uint64_t @@ -2735,13 +2747,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 isinf(f) == 1 ? INT32_MAX : INT32_MIN; + 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 isinf(f) == 1 ? INT64_MAX : INT64_MIN; + default: return static_cast(f); + } } uint64_t diff --git a/src/interpret.cpp b/src/interpret.cpp index 4175f77146..e9f715d1de 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1078,11 +1078,28 @@ 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, isinf(f) == 1 ? INT32_MAX : INT32_MIN); 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, isinf(f) == 1 ? INT64_MAX : INT64_MIN); + break; + default: pushLong + (t, f >= INT64_MAX ? INT64_MAX + : (f <= INT64_MIN ? INT64_MIN : static_cast(f))); + break; + } } goto loop; case dadd: { @@ -1278,11 +1295,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, isinf(f) == 1 ? INT32_MAX : INT32_MIN); 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, isinf(f) == 1 ? INT64_MAX : INT64_MIN); + break; + default: pushLong(t, static_cast(f)); break; + } } goto loop; case fadd: { diff --git a/src/x86.cpp b/src/x86.cpp index 47a7ab2ad6..f8ed8abd0a 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -3064,7 +3064,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; 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); } } } From 20a290b992112f9b376d3a8d0180c1cca8dd21e2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 12 Aug 2012 14:52:48 -0600 Subject: [PATCH 50/95] use signbit instead of isinf to determine floating point sign glibc's use of isinf's return value to indicate sign is a non-standard extension which can't be relied upon on other platforms. --- src/compile.cpp | 8 ++++---- src/interpret.cpp | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 6837e9e7b1..50e2bfb9e2 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2590,7 +2590,7 @@ doubleToInt(int64_t a) double f = bitsToDouble(a); switch (fpclassify(f)) { case FP_NAN: return 0; - case FP_INFINITE: return isinf(f) == 1 ? INT32_MAX : INT32_MIN; + 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)); } @@ -2602,7 +2602,7 @@ doubleToLong(int64_t a) double f = bitsToDouble(a); switch (fpclassify(f)) { case FP_NAN: return 0; - case FP_INFINITE: return isinf(f) == 1 ? INT64_MAX : INT64_MIN; + 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)); } @@ -2750,7 +2750,7 @@ floatToInt(int32_t a) float f = bitsToFloat(a); switch (fpclassify(f)) { case FP_NAN: return 0; - case FP_INFINITE: return isinf(f) == 1 ? INT32_MAX : INT32_MIN; + 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)); } @@ -2762,7 +2762,7 @@ floatToLong(int32_t a) float f = bitsToFloat(a); switch (fpclassify(f)) { case FP_NAN: return 0; - case FP_INFINITE: return isinf(f) == 1 ? INT64_MAX : INT64_MIN; + case FP_INFINITE: return signbit(f) ? INT64_MIN : INT64_MAX; default: return static_cast(f); } } diff --git a/src/interpret.cpp b/src/interpret.cpp index e9f715d1de..6e18a3d3e7 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1081,7 +1081,7 @@ interpret3(Thread* t, const int base) double f = popDouble(t); switch (fpclassify(f)) { case FP_NAN: pushInt(t, 0); break; - case FP_INFINITE: pushInt(t, isinf(f) == 1 ? INT32_MAX : INT32_MIN); 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))); @@ -1093,8 +1093,7 @@ interpret3(Thread* t, const int base) double f = popDouble(t); switch (fpclassify(f)) { case FP_NAN: pushLong(t, 0); break; - case FP_INFINITE: pushLong(t, isinf(f) == 1 ? INT64_MAX : INT64_MIN); - 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))); @@ -1298,7 +1297,7 @@ interpret3(Thread* t, const int base) float f = popFloat(t); switch (fpclassify(f)) { case FP_NAN: pushInt(t, 0); break; - case FP_INFINITE: pushInt(t, isinf(f) == 1 ? INT32_MAX : INT32_MIN); 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; @@ -1309,7 +1308,7 @@ interpret3(Thread* t, const int base) float f = popFloat(t); switch (fpclassify(f)) { case FP_NAN: pushLong(t, 0); break; - case FP_INFINITE: pushLong(t, isinf(f) == 1 ? INT64_MAX : INT64_MIN); + case FP_INFINITE: pushLong(t, signbit(f) ? INT64_MIN : INT64_MAX); break; default: pushLong(t, static_cast(f)); break; } From 69ffa28e1b199d5dd02ea37e37a4a56a93471caa Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 11 Aug 2012 19:09:03 +0000 Subject: [PATCH 51/95] fix shift instruction implementations on ARM Unlike x86, ARM does not implicitly mask the shift value, so we must do so explicitly. --- src/arm.cpp | 92 +++++++++++++++++++++++++++++++++------------- src/interpret.cpp | 12 +++--- test/Integers.java | 46 ++++++++++++++++++++++- test/Longs.java | 18 +++++++++ 4 files changed, 136 insertions(+), 32 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 2810a8700e..1ff42c037d 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -634,72 +634,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 +955,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) diff --git a/src/interpret.cpp b/src/interpret.cpp index 6e18a3d3e7..da3e6c7853 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1930,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: @@ -1976,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: { @@ -2238,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: @@ -2284,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: { diff --git a/test/Integers.java b/test/Integers.java index c88803b518..a442db1150 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); @@ -266,5 +266,49 @@ public class Integers { 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); } + + { java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream(); + java.io.DataOutputStream dout = new java.io.DataOutputStream(bout); + dout.writeInt(0xCAFEBABE); + dout.flush(); + byte[] array = bout.toByteArray(); + expect((array[0] & 0xFF) == 0xCA); + expect((array[1] & 0xFF) == 0xFE); + expect((array[2] & 0xFF) == 0xBA); + expect((array[3] & 0xFF) == 0xBE); + } } } diff --git a/test/Longs.java b/test/Longs.java index 0472536f60..a4c7e182ea 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -337,6 +337,24 @@ 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); } } } From a3a816c9a451eb4ada31551c9c82f67deefb018b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 12 Aug 2012 20:58:07 -0600 Subject: [PATCH 52/95] remove test of DataOutputStream from Integers.java We haven't implemented that class yet, so the test only compiles with the OpenJDK port. --- test/Integers.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/Integers.java b/test/Integers.java index a442db1150..1420bb640d 100644 --- a/test/Integers.java +++ b/test/Integers.java @@ -299,16 +299,5 @@ public class Integers { { int b = 0xBE; expect(((b >>> 0) & 0xFF) == 0xBE); } - - { java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream(); - java.io.DataOutputStream dout = new java.io.DataOutputStream(bout); - dout.writeInt(0xCAFEBABE); - dout.flush(); - byte[] array = bout.toByteArray(); - expect((array[0] & 0xFF) == 0xCA); - expect((array[1] & 0xFF) == 0xFE); - expect((array[2] & 0xFF) == 0xBA); - expect((array[3] & 0xFF) == 0xBE); - } } } From fa5d76b43e3129130deb12c1a184abce804e8382 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 13 Aug 2012 08:26:39 -0600 Subject: [PATCH 53/95] fix 64-bit shifts on x86_32 --- src/x86.cpp | 58 +++++++++++++++++++++++++++++++++++++--------- test/Integers.java | 19 +++++++++++++-- test/Longs.java | 30 ++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 13 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index f8ed8abd0a..06a492dcfd 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) { + if (a->low != rcx) { + c->client->save(rcx); + Assembler::Register cx(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); @@ -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) { + if (a->low != rcx) { + c->client->save(rcx); + Assembler::Register cx(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); @@ -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) { + if (a->low != rcx) { + c->client->save(rcx); + Assembler::Register cx(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); @@ -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)); } @@ -3232,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); @@ -3302,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/test/Integers.java b/test/Integers.java index 1420bb640d..bbaa710351 100644 --- a/test/Integers.java +++ b/test/Integers.java @@ -262,8 +262,8 @@ 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); @@ -299,5 +299,20 @@ public class Integers { { 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/Longs.java b/test/Longs.java index a4c7e182ea..649ec6b2ff 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -355,6 +355,36 @@ public class Longs { { 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); } } } From 2abc4e28a52bfbb9b238dbacea51070549eef260 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 13 Aug 2012 08:36:36 -0600 Subject: [PATCH 54/95] handle missing classpath or jar file name gracefully --- src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 909069ba0a..fe2793c10d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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) From 665c4448bd595b3182d3d67c503f0a046dd8ded8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 13 Aug 2012 11:16:30 -0600 Subject: [PATCH 55/95] fix PowerPC floating point argument and return value marshalling --- src/powerpc.S | 13 +++++++++++-- src/powerpc.h | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) 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.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); From 95cf6cf941044b7d7e6b8f7f557c8a54db991b36 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 13 Aug 2012 11:17:34 -0600 Subject: [PATCH 56/95] fix integer shifts on PowerPC --- src/powerpc.cpp | 84 +++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 30 deletions(-) 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); + } } } From 127d56d0feb61aeb2d72ca6556dc823156ba4731 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 13 Aug 2012 09:19:42 +0000 Subject: [PATCH 57/95] fix register masks used for planning in arm.cpp We can't use a floating point register where an integer register is needed, or we may generate an invalid instruction. --- src/arm.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 1ff42c037d..97f9455495 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -2396,7 +2396,7 @@ class MyArchitecture: public Assembler::Architecture { { *thunk = false; *aTypeMask = ~0; - *aRegisterMask = ~static_cast(0); + *aRegisterMask = GPR_MASK64; switch (op) { case Negate: @@ -2453,7 +2453,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: @@ -2584,7 +2584,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)) { @@ -2592,7 +2592,7 @@ class MyArchitecture: public Assembler::Architecture { *cRegisterMask = 0; } else { *cTypeMask = (1 << RegisterOperand); - *cRegisterMask = ~static_cast(0); + *cRegisterMask = bRegisterMask; } } From ff9757e811033daf0ee1632f93d586ef47b15639 Mon Sep 17 00:00:00 2001 From: Gernot Kvas Date: Wed, 15 Aug 2012 17:27:27 -0600 Subject: [PATCH 58/95] fix Win32 build regressions Date: Wed, 15 Aug 2012 15:59:25 -0700 (PDT) From: Gernot Kvas Reply-To: avian@googlegroups.com To: avian@googlegroups.com Subject: Win32 build regression Hi, As I've forked on the July 19th and haven't updated since, I decided to merge master into my WinCE branch. I found out that the following commits have introduced build regressions on Windows: 1.)https://github.com/ReadyTalk/avian/commit/5a7c78e71ac7b4045c23d215162fb1284 8f1a5f3 => strncasecmp is undefined for Windows 2.)https://github.com/ReadyTalk/avian/commit/b98abe3f94dbf552595554787ef2115c3 009856c => fpclassify and related constants are undefined for Windows 3.)https://github.com/ReadyTalk/avian/commit/20a290b992112f9b376d3a8d0180c1cca 8dd21e2 => signbit is undefined for Windows I attached a patch that makes everything build through (within Visual Studio, the makefile still fails) --- src/common.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) 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 && From 38454ce7d432047c3ab2f010984e949a0e90dac8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 15 Aug 2012 17:42:31 -0600 Subject: [PATCH 59/95] fix MSVC build of test JNI library --- makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index eef4e14d0d..7782850780 100755 --- a/makefile +++ b/makefile @@ -566,7 +566,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) From 3372210f45e2d756987af79c3f0ac5f32540ba13 Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Thu, 16 Aug 2012 16:08:19 -0600 Subject: [PATCH 60/95] Added .get() implementation --- classpath/java/nio/ByteBuffer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java index 73da8fbc78..47eec8c1dc 100644 --- a/classpath/java/nio/ByteBuffer.java +++ b/classpath/java/nio/ByteBuffer.java @@ -173,6 +173,10 @@ public abstract class ByteBuffer return this; } + public byte get() { + return get(position++); + } + public byte get(int position) { checkGet(position, 1); return doGet(position); From bac4099acb0f6191fa55f68fe2a6fb4fe2dd517e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 17 Aug 2012 12:47:38 -0600 Subject: [PATCH 61/95] fix crash in findFrameMapInSimpleTable due to bug in instanceof implementation We weren't adding entries to the frame map for calls to the instanceof thunk when compiling methods. However, that thunk may trigger a GC, in which case we'll need to unwind the stack, which will lead to a crash if we don't have a frame map entry for that instruction. --- src/compile.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 50e2bfb9e2..e29f4e592a 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5064,21 +5064,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; From 1f1c3c4c414a62643f279f1527c43ff06788d016 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 24 Aug 2012 18:14:01 -0600 Subject: [PATCH 62/95] allow main thread to use DetachCurrentThread When I originally implemented DetachCurrentThread, I assumed it didn't make sense for the main thread to detach itself from the VM, and I was concerned that allowing it might cause problems for any other threads still attached. However, detaching the main thread is allowed by the JNI spec as of Java 2, and OpenJDK's java command does this just before calling DestroyJavaVM. Therefore, this commit ensures that the VM doesn't abort if the main thread is detached. --- src/jnienv.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index e4abe152f5..65fb57ab1e 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -45,8 +45,6 @@ DetachCurrentThread(Machine* m) { Thread* t = static_cast(m->localThread->get()); if (t) { - expect(t, t != m->rootThread); - m->localThread->set(0); ACQUIRE_RAW(t, t->m->stateLock); From c2b53497ab41d907f05dc0e5579fced2e85f2786 Mon Sep 17 00:00:00 2001 From: Gernot Kvas Date: Sun, 26 Aug 2012 17:27:22 +0200 Subject: [PATCH 63/95] Fix stacktrace when building with MSVC --- src/classpath-common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From 8c48a44e54400f999a8368a97ca257f94eacd164 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 29 Aug 2012 18:27:37 -0600 Subject: [PATCH 64/95] set main thread context classloader correctly for OpenJDK port sun.misc.Launcher has its own idea about what the application classloader should be, but we need to override it with the system classloader created by the VM. This is achieved by running Launcher.getLauncher (which has the side effect of setting Thread.contextClassLoader) and then overriding it. --- src/classpath-openjdk.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index a965fd676d..f4de3f9fca 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -623,6 +623,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* From 374bdb372650333317d4fe0359dd4ca4409ea4a8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 29 Aug 2012 18:32:45 -0600 Subject: [PATCH 65/95] implement Runtime.maxMemory for OpenJDK port Some apps refuse to run if Runtime.maxMemory returns a value that's "too small", so our stub implementation returning zero was not sufficient. Now we return the actual heap size limit in bytes. --- src/classpath-openjdk.cpp | 2 +- src/heap.cpp | 4 ++++ src/heap.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index f4de3f9fca..299441a9b7 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3116,7 +3116,7 @@ EXPORT(JVM_FreeMemory)() extern "C" JNIEXPORT jlong JNICALL EXPORT(JVM_MaxMemory)() { - return 0; + return local::globalMachine->heap->limit(); } extern "C" JNIEXPORT jint JNICALL diff --git a/src/heap.cpp b/src/heap.cpp index 0bc37862fd..b46faeda01 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1867,6 +1867,10 @@ class MyHeap: public Heap { c.immortalHeapEnd = start + sizeInWords; } + virtual unsigned limit() { + return c.limit; + } + virtual bool limitExceeded() { return c.count > c.limit; } diff --git a/src/heap.h b/src/heap.h index c3f1f8b4c8..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, From 7534eecdb368b7f493c0206dc7343aba7f56e93a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 29 Aug 2012 18:34:28 -0600 Subject: [PATCH 66/95] implement JVM_ConstantPoolGetDoubleAt --- src/classpath-openjdk.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 299441a9b7..844739e3e3 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -4678,9 +4678,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(&singletonValue(t, *pool, index - 1), &v, 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) From 9ceacf16e9c020ade36dd7e4149261010c17b1f8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 29 Aug 2012 18:34:51 -0600 Subject: [PATCH 67/95] don't throw an exception from resolveClass when throw_ == false resolveClass was correctly respecting throw_ == false if the requested class was not found, but it still threw an exception if e.g. the superclass was missing. Now we catch such exceptions and return null as appropriate. --- src/machine.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index b9782ac3f0..790c9fa1aa 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3983,6 +3983,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 +4039,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) { From 3f039864d1560a5aa570c6f4a07160761034b0d7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 29 Aug 2012 12:10:31 -0600 Subject: [PATCH 68/95] fix memcpy argument order bug in jvmConstantPoolGetDoubleAt --- src/classpath-openjdk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 844739e3e3..97c5a3372e 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -4684,7 +4684,7 @@ jvmConstantPoolGetDoubleAt(Thread* t, uintptr_t* arguments) jobject pool = reinterpret_cast(arguments[0]); jint index = arguments[1]; - double v; memcpy(&singletonValue(t, *pool, index - 1), &v, 8); + double v; memcpy(&v, &singletonValue(t, *pool, index - 1), 8); return doubleToBits(v); } From 24f682f5b676fd4cbf25592054022d9a410fbcc5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 3 Sep 2012 08:44:13 -0600 Subject: [PATCH 69/95] fix 64-bit shifts on x86_32 (part 2) My earlier attempt (fa5d76b) missed an important detail, and somehow I forgot to test the 32-bit OpenJDK build which made that omission obvious. Here's the fix. --- src/x86.cpp | 12 ++++++------ test/Longs.java | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index 06a492dcfd..acdb8f1f71 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2186,9 +2186,9 @@ shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, unsigned bSize, Assembler::Register* b) { if (TargetBytesPerWord == 4 and bSize == 8) { + Assembler::Register cx(rcx); if (a->low != rcx) { c->client->save(rcx); - Assembler::Register cx(rcx); ResolvedPromise promise(0x3F); Assembler::Constant mask(&promise); moveRR(c, 4, a, 4, &cx); @@ -2204,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); @@ -2232,9 +2232,9 @@ shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, unsigned bSize, Assembler::Register* b) { if (TargetBytesPerWord == 4 and bSize == 8) { + Assembler::Register cx(rcx); if (a->low != rcx) { c->client->save(rcx); - Assembler::Register cx(rcx); ResolvedPromise promise(0x3F); Assembler::Constant mask(&promise); moveRR(c, 4, a, 4, &cx); @@ -2250,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); @@ -2281,9 +2281,9 @@ unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a, unsigned bSize, Assembler::Register* b) { if (TargetBytesPerWord == 4 and bSize == 8) { + Assembler::Register cx(rcx); if (a->low != rcx) { c->client->save(rcx); - Assembler::Register cx(rcx); ResolvedPromise promise(0x3F); Assembler::Constant mask(&promise); moveRR(c, 4, a, 4, &cx); @@ -2299,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); diff --git a/test/Longs.java b/test/Longs.java index 649ec6b2ff..4d9395f7b0 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -385,6 +385,10 @@ public class Longs { { long b = 0xBEL; int x = 0; int y = 0xFF; expect(((b >>> x) & y) == 0xBEL); } + + { long b = 0xFFFFFFFFFFFFFFFFL; int s = 20; + expect((b >>> -s) == 0xFFFFF); + } } } From d88a33329aabd68b25b510e0c02fd4bccbdf434d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xerxes=20R=C3=A5nby?= Date: Wed, 5 Sep 2012 10:29:12 +0200 Subject: [PATCH 70/95] Add a non-versioned SONAME to Avian libjvm.so that matches the Hotspot Server/Client libjvm.so SONAME, this allow libjava.so in OpenJDK 7 to find the Avian libjvm.so during ldopen. --- makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index 7782850780..d84cd678e3 100755 --- a/makefile +++ b/makefile @@ -223,6 +223,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 @@ -1160,7 +1161,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) $(@) From db0c14d74238bc9fb48d88514acb525a268467e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xerxes=20R=C3=A5nby?= Date: Wed, 5 Sep 2012 14:31:30 +0200 Subject: [PATCH 71/95] Set java.vm.info based on makefile info= and set java.vm.version based on makefile version= in order to display relevant OpenJDK -version information. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matthias Klose Signed-off-by: Xerxes RÃ¥nby --- makefile | 1 + src/classpath-openjdk.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/makefile b/makefile index 7782850780..2dceb23b93 100755 --- a/makefile +++ b/makefile @@ -194,6 +194,7 @@ target-cflags = -DTARGET_BYTES_PER_WORD=$(pointer-size) 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) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 97c5a3372e..003b2ef1e2 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3006,6 +3006,12 @@ jvmInitProperties(Thread* t, uintptr_t* arguments) "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", From eee2ce27e412ebb2a098a3c24d9f7920f78ff00d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 7 Sep 2012 08:47:49 -0600 Subject: [PATCH 72/95] ignore DetachCurrentThread calls for the main thread My earlier commit to allow detaching the main thread (1f1c3c4) seems to have caused subtle stability problems (e.g. https://groups.google.com/group/avian/msg/d2c797c0dcf925c3), so for now we'll just ignore that operation, which leaks a bit of memory but should be harmless otherwise. --- src/jnienv.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 65fb57ab1e..f6eeb8c86f 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -45,17 +45,23 @@ DetachCurrentThread(Machine* m) { Thread* t = static_cast(m->localThread->get()); if (t) { - m->localThread->set(0); + // 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); - 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 { From 90fa4c9b69c077e0be4320fea1b02ec4fef669ac Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 7 Sep 2012 19:05:05 -0600 Subject: [PATCH 73/95] add JNI_GetCreatedJavaVMs stub Recent versions of IcedTea will not run unless libjvm.so exports this symbol. The quick fix is to provide a stub which just always returns -1 to indicate an error. I'll leave a proper implementation for when we need to support an app that actually uses this function. --- src/jnienv.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index f6eeb8c86f..b9e1ea00a4 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -3626,6 +3626,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) { From c918cbced149a34a1d0ab78922ac21c0d04f80b8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 11 Sep 2012 19:21:51 -0600 Subject: [PATCH 74/95] fix sun.misc.Unsafe.getLongVolatile for static fields on 32-bit platforms The existing code did not handle static field lookups for synchronization on 32-bit systems, which is necessary because such systems generally don't support atomic operations on 64-bit values. --- src/classpath-openjdk.cpp | 25 +++++++++++++++++++++---- src/machine.cpp | 7 +++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 003b2ef1e2..da31d9b687 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2292,11 +2292,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); + } } } diff --git a/src/machine.cpp b/src/machine.cpp index 790c9fa1aa..6ae39f7b30 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1128,7 +1128,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 +1242,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; From 2190d0e99acd565df1244212f7b33909b604aa3a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 12 Sep 2012 15:25:17 -0600 Subject: [PATCH 75/95] fix reads of out-of-bounds values in tokenizer.h --- src/tokenizer.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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); } From 3a5abaf58a9f8b3210fd4848d506eabc972f29ba Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 12 Sep 2012 17:23:19 -0600 Subject: [PATCH 76/95] fix incorrect reporting of fixie collection status in heap.cpp (part 2) My earlier fix (f8e8609) was almost -- but not quite -- sufficient. It asked the heap to mark the dead fixies too early, so some of them were marked dead even though they ultimately survived, causing us to clear weak JNI references when we shouldn't. --- src/machine.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 6ae39f7b30..24fd6c0a8e 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) { @@ -592,6 +594,8 @@ postVisit(Thread* t, Heap::Visitor* v) m->tenuredWeakReferences = firstNewTenuredWeakReference; } + m->heap->postVisit(); + for (Reference* r = m->jniReferences; r; r = r->next) { if (r->weak) { if (m->heap->status(r->target) == Heap::Unreachable) { @@ -2693,8 +2697,6 @@ class HeapClient: public Heap::Client { virtual void visitRoots(Heap::Visitor* v) { ::visitRoots(m, v); - m->heap->postVisit(); - postVisit(m->rootThread, v); } From 2d9bbec214280af9d95ec5c16141cba3ace5002f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 14 Sep 2012 11:40:26 -0600 Subject: [PATCH 77/95] fix a couple of ByteBuffer regressions The compact() and put(ByteBuffer) methods regressed as of the recent refactoring to support direct byte buffers. --- classpath/java/nio/ArrayByteBuffer.java | 11 ++++++++--- classpath/java/nio/ByteBuffer.java | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/classpath/java/nio/ArrayByteBuffer.java b/classpath/java/nio/ArrayByteBuffer.java index 2f2e7d5024..336945c1bb 100644 --- a/classpath/java/nio/ArrayByteBuffer.java +++ b/classpath/java/nio/ArrayByteBuffer.java @@ -31,6 +31,10 @@ class ArrayByteBuffer extends ByteBuffer { return b; } + public boolean hasArray() { + return true; + } + public byte[] array() { return array; } @@ -49,9 +53,10 @@ class ArrayByteBuffer extends ByteBuffer { } public ByteBuffer put(ByteBuffer src) { - checkPut(position, src.remaining()); - src.get(array, arrayOffset + position, src.remaining()); - position += src.remaining(); + int length = src.remaining(); + checkPut(position, length); + src.get(array, arrayOffset + position, length); + position += length; return this; } diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java index 47eec8c1dc..3a6548d2b3 100644 --- a/classpath/java/nio/ByteBuffer.java +++ b/classpath/java/nio/ByteBuffer.java @@ -53,13 +53,15 @@ public abstract class ByteBuffer } public ByteBuffer compact() { + int remaining = remaining(); + if (position != 0) { ByteBuffer b = slice(); position = 0; put(b); } - position = remaining(); + position = remaining; limit(capacity()); return this; From e20c5cd9c6f1f103aae88758f44575ab65795599 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 22 Sep 2012 20:22:33 -0600 Subject: [PATCH 78/95] fix a couple of OpenJDK reflection bugs We weren't wrapping exceptions thrown by invoked methods in InvocationTargetExceptions in JVM_InvokeMethod or JVM_NewInstanceFromConstructor. Also, JVM_GetCallerClass is supposed to ignore Method.invoke frames when walking the stack. --- src/classpath-openjdk.cpp | 18 +++++++++++++++++- src/machine.cpp | 21 +++++++++++++++++---- src/machine.h | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index da31d9b687..47b6b12d8a 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3802,7 +3802,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; @@ -4568,6 +4568,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 @@ -4606,6 +4614,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 { diff --git a/src/machine.cpp b/src/machine.cpp index 24fd6c0a8e..4f01f204da 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -4839,15 +4839,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; @@ -4861,7 +4873,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..35d07a78e9 100644 --- a/src/machine.h +++ b/src/machine.h @@ -3801,7 +3801,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); From 369320191176c132c0b1be8e62da25fa9d75a1f7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 24 Sep 2012 17:43:34 -0600 Subject: [PATCH 79/95] make JVM_GetSystemPackage a bit smarter The original stub implementation just echoed back its argument, but that confused URLClassLoader when dealing with sealed JARs -- returning a non-null value for a non-system class from JVM_GetSystemPackage made URLClassloader think it had already loaded a class from a package which was supposed to be sealed, resulting in SecurityExceptions which ultimately triggered NoClassDefFoundErrors. The solution is to only return non-null values for actual system classes. --- src/classpath-avian.cpp | 6 ++++ src/classpath-openjdk.cpp | 74 +++++++++++++++++++++++++++++++++++++-- src/machine.cpp | 2 ++ src/machine.h | 4 +++ 4 files changed, 83 insertions(+), 3 deletions(-) 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-openjdk.cpp b/src/classpath-openjdk.cpp index 47b6b12d8a..dd772f2eeb 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -638,6 +638,47 @@ 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() { @@ -3531,10 +3572,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 s) +uint64_t +jvmGetSystemPackage(Thread* t, uintptr_t* arguments) { - return s; + 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 diff --git a/src/machine.cpp b/src/machine.cpp index 4f01f204da..09a314b9f2 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -4099,6 +4099,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)); } diff --git a/src/machine.h b/src/machine.h index 35d07a78e9..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; }; From 23ea8f7d76a3b9573b2041eac0faf77daeb5642d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xerxes=20R=C3=A5nby?= Date: Tue, 25 Sep 2012 15:54:32 +0200 Subject: [PATCH 80/95] Fix missing armv4 blx and bkpt compile errors. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Xerxes RÃ¥nby --- src/arm.S | 10 ++++++++++ src/compile-arm.S | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/src/arm.S b/src/arm.S index 01d0839079..9958fc6610 100644 --- a/src/arm.S +++ b/src/arm.S @@ -62,7 +62,12 @@ LOCAL(loop): 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 #if defined(__VFP_FP__) && (! defined(__SOFTFP__)) && (! defined(__QNX__)) @@ -108,7 +113,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/compile-arm.S b/src/compile-arm.S index 427378c1f8..99eb6c07a8 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 @@ -228,5 +233,9 @@ LOCAL(vmJumpAndInvoke_getAddress_word): #else // not AVIAN_CONTINUATIONS // vmJumpAndInvoke should only be called when continuations are // enabled +#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) + // TODO: armv4 do not have bkpt +#else bkpt +#endif #endif // not AVIAN_CONTINUATIONS From 1d4c9d32fb3434c300b9833cdaef040712945292 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Sep 2012 15:03:14 -0600 Subject: [PATCH 81/95] return null from JNIEnv::GetSuperclass for interfaces per spec --- src/classpath-openjdk.cpp | 11 +++++++---- src/jnienv.cpp | 14 ++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index dd772f2eeb..938368b0d9 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2378,10 +2378,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 diff --git a/src/jnienv.cpp b/src/jnienv.cpp index b9e1ea00a4..9e1d7e9edf 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -431,12 +431,14 @@ GetObjectClass(Thread* t, jobject o) 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 From 2a15201b185a2402c69e7e0b558f0d4175f4bd25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xerxes=20R=C3=A5nby?= Date: Mon, 1 Oct 2012 13:39:18 +0200 Subject: [PATCH 82/95] gcc define __ARM_PCS_VFP for -mfloat-abi=hard, use it to detect armhf builds. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Xerxes RÃ¥nby --- src/arm.S | 4 ++-- src/arm.cpp | 12 +++++++++++- src/arm.h | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/arm.S b/src/arm.S index 9958fc6610..8f19b59171 100644 --- a/src/arm.S +++ b/src/arm.S @@ -57,7 +57,7 @@ LOCAL(loop): // setup argument registers if necessary tst r6, r6 ldmneia r6, {r0-r3} -#if defined(__VFP_FP__) && (! defined(__SOFTFP__)) && (! defined(__QNX__)) +#if defined(__ARM_PCS_VFP) // and VFP registers vldmia r7, {d0-d7} #endif @@ -70,7 +70,7 @@ LOCAL(loop): #endif add sp, sp, r5 // deallocate stack -#if defined(__VFP_FP__) && (! defined(__SOFTFP__)) && (! defined(__QNX__)) +#if defined(__ARM_PCS_VFP) cmp r8,#FLOAT_TYPE bne LOCAL(double) fmrs r0,s0 diff --git a/src/arm.cpp b/src/arm.cpp index 97f9455495..74f7da63bb 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -245,7 +245,17 @@ 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 } } diff --git a/src/arm.h b/src/arm.h index 8ae057d610..15299ec762 100644 --- a/src/arm.h +++ b/src/arm.h @@ -163,7 +163,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, for (unsigned ati = 0; ati < argumentCount; ++ ati) { switch (argumentTypes[ati]) { case DOUBLE_TYPE: -#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) && !defined(__QNX__) +#if defined(__ARM_PCS_VFP) { if (vfpIndex + Alignment <= VfpCount) { if (vfpIndex % Alignment) { From ab5ec510bf5531482230ba6e9e17a9af7e9caeb5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 3 Oct 2012 08:16:41 -0600 Subject: [PATCH 83/95] handle zero length arrays properly in JNIEnv::NewString --- src/jnienv.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 9e1d7e9edf..52da9559f7 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -241,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)); } From 1ce012aa68c3c6045a42f34ae474121738d7ad13 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 3 Oct 2012 09:43:51 -0600 Subject: [PATCH 84/95] fix abort in classpath-openjdk.cpp due to buffer overflow This addresses the case where -Djava.home=. https://github.com/ReadyTalk/avian/issues/15 --- src/classpath-openjdk.cpp | 78 ++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 938368b0d9..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"); @@ -424,16 +442,24 @@ class MyClasspath : public Classpath { 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 @@ -682,6 +708,7 @@ class MyClasspath : public Classpath { virtual void dispose() { + allocator->free(buffer, bufferSize); allocator->free(this, sizeof(*this)); } @@ -691,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; @@ -705,7 +734,6 @@ class MyClasspath : public Classpath { unsigned zipEntryMethodField; bool ranNetOnLoad; bool ranManagementOnLoad; - char buffer[BufferSize]; JmmInterface jmmInterface; }; From 16c526b775fa38b7877ccfc9ed6be966cc8bc060 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 3 Oct 2012 13:36:51 -0600 Subject: [PATCH 85/95] fix OS X 10.8 and iOS 6.0 builds This also adds support for Clang ARM builds, which involved removing unused functions from arm.cpp to avoid link-time warnings. --- makefile | 16 +++++-- src/arm.S | 4 ++ src/arm.cpp | 108 +--------------------------------------------- src/compile-arm.S | 26 ++++++++--- 4 files changed, 37 insertions(+), 117 deletions(-) diff --git a/makefile b/makefile index 735ab6f89d..6b611ebd2c 100755 --- a/makefile +++ b/makefile @@ -291,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 @@ -312,8 +317,10 @@ 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) @@ -389,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; \ diff --git a/src/arm.S b/src/arm.S index 8f19b59171..658df92200 100644 --- a/src/arm.S +++ b/src/arm.S @@ -56,7 +56,11 @@ LOCAL(loop): // setup argument registers if necessary tst r6, r6 +#ifdef __clang__ + ldmiane r6, {r0-r3} +#else ldmneia r6, {r0-r3} +#endif #if defined(__ARM_PCS_VFP) // and VFP registers vldmia r7, {d0-d7} diff --git a/src/arm.cpp b/src/arm.cpp index 74f7da63bb..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); } @@ -262,28 +192,9 @@ bool vfpSupported() { 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; @@ -577,7 +488,7 @@ isBranch(TernaryOperation op) return op > FloatMin; } -bool +bool UNUSED isFloatBranch(TernaryOperation op) { return op > JumpIfNotEqual; @@ -1407,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, diff --git a/src/compile-arm.S b/src/compile-arm.S index 99eb6c07a8..7db96279e9 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -128,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] @@ -215,27 +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 -#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) - // TODO: armv4 do not have bkpt -#else - bkpt -#endif + // enabled, so we force a crash if we reach here: + mov r1,#0 + ldr r1,[r1] #endif // not AVIAN_CONTINUATIONS From c680dd421575d871b93243cc577ed700c75fb38a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 3 Oct 2012 17:01:00 -0600 Subject: [PATCH 86/95] use ldmneia on Clang < 4 and GCC, ldmiane on Clang >= 4 I don't know why this instruction was renamed, but we have to deal with it. --- src/arm.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arm.S b/src/arm.S index 658df92200..23e66cefdd 100644 --- a/src/arm.S +++ b/src/arm.S @@ -56,7 +56,7 @@ LOCAL(loop): // setup argument registers if necessary tst r6, r6 -#ifdef __clang__ +#if (defined __APPLE__) && (defined __clang_major__) && (__clang_major__ >= 4) ldmiane r6, {r0-r3} #else ldmneia r6, {r0-r3} From f8d3494b1cd7ca96e28ab6767929d8b5f4a00980 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 5 Oct 2012 10:06:01 -0600 Subject: [PATCH 87/95] clear any weak/soft/phantom references to finalizable objects before queuing If we don't clear these references, we risk finalizing objects which can still be reached by one of the special reference types. It's a bit of a chicken-and-egg problem. We need to visit finalizable objects before visiting weak references, since some of the weak references and/or their targets may become reachable once the finalizable objects are visited. However, that ordering means we have no efficient way of distinguishing between objects which are reachable from one or more normal GC roots and those which are only reachable via the finalization queue. The solution is to clear all weak references to finalizable objects before visiting them. --- src/heap.cpp | 1 + src/machine.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/heap.cpp b/src/heap.cpp index b46faeda01..2dc23e904e 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1077,6 +1077,7 @@ update3(Context* c, void* o, bool* needsVisit) fprintf(stderr, "mark fixie %p\n", f); } f->marked(true); + f->dead(false); f->move(c, &(c->markedFixies)); } *needsVisit = false; diff --git a/src/machine.cpp b/src/machine.cpp index 09a314b9f2..743f56e41a 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -474,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) { @@ -482,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; @@ -594,8 +637,6 @@ postVisit(Thread* t, Heap::Visitor* v) m->tenuredWeakReferences = firstNewTenuredWeakReference; } - m->heap->postVisit(); - for (Reference* r = m->jniReferences; r; r = r->next) { if (r->weak) { if (m->heap->status(r->target) == Heap::Unreachable) { From 45073db421a5e8566d8a68a693648448865e0371 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 5 Oct 2012 10:56:07 -0600 Subject: [PATCH 88/95] fix Call[Static]MethodA float argument marshalling --- src/interpret.cpp | 2 +- test/JNI.java | 15 +++++++++++++++ test/jni.cpp | 20 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/interpret.cpp b/src/interpret.cpp index da3e6c7853..543363a7d3 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -2823,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: diff --git a/test/JNI.java b/test/JNI.java index dc24da9b8f..b4e93c0f75 100644 --- a/test/JNI.java +++ b/test/JNI.java @@ -7,6 +7,18 @@ public class JNI { 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, @@ -40,5 +52,8 @@ public class JNI { (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/jni.cpp b/test/jni.cpp index 8c1ea91f05..fe174edec9 100644 --- a/test/jni.cpp +++ b/test/jni.cpp @@ -37,6 +37,26 @@ Java_JNI_addMix + 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) { From 3a452309b36e3fc654d1f5a8a5d36fc20e1abde3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 6 Oct 2012 15:25:12 -0600 Subject: [PATCH 89/95] update static table class reference in updateClassTables Commit c918cbc added this reference to ensure sun.misc.Unsafe.getLongVolatile could be implemented efficiently on 32-bit platforms. However, I neglected to ensure the reference was updated to point to the final class instance instead of the temporary one used in parseClass. This led to extra memory usage and inconsistent locking behavior, plus broken bootimage builds. --- src/machine.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/machine.cpp b/src/machine.cpp index 743f56e41a..828de31fc0 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2296,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) { From 7946aaf48fe08c7ffcc84269f04826645ac3b8fc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 6 Oct 2012 15:30:59 -0600 Subject: [PATCH 90/95] update static table mapping code in bootimage.cpp to match machine.cpp Commit c918cbc added a reference to ensure sun.misc.Unsafe.getLongVolatile could be implemented efficiently on 32-bit platforms, but I forgot to update bootimage.cpp to account for it. --- src/bootimage.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 4525b3ec05..492366f6c2 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -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); @@ -454,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); @@ -462,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); @@ -535,7 +538,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, targetMemberOffset = pad(targetMemberOffset, TargetBytesPerWord); } } - + if (hashMapFind(t, typeMaps, c, objectHash, objectEqual) == 0) { object array = makeByteArray (t, TypeMap::sizeInBytes @@ -594,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); From a3c4b60f43f135f156ca4d1d9b33dfbf91f4afc9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 6 Oct 2012 15:33:24 -0600 Subject: [PATCH 91/95] rename package avian.avian_vm_resource to avian.avianvmresource This package name must match the URL protocol we use for loading embedded resources, but OpenJDK's URL class won't tolerate underscores in a protocol name. Also, I had not updated the names of the native methods in avian.avianvmresource.Handler, leading to UnsatisfiedLinkErrors when they were called. --- .../Handler.java | 2 +- classpath/java/net/URL.java | 4 ++-- makefile | 2 +- openjdk.pro | 4 +++- src/builtin.cpp | 12 ++++++------ src/finder.cpp | 2 +- 6 files changed, 14 insertions(+), 12 deletions(-) rename classpath/avian/{avian_vm_resource => avianvmresource}/Handler.java (98%) diff --git a/classpath/avian/avian_vm_resource/Handler.java b/classpath/avian/avianvmresource/Handler.java similarity index 98% rename from classpath/avian/avian_vm_resource/Handler.java rename to classpath/avian/avianvmresource/Handler.java index dfad1f7964..ea776c7e92 100644 --- a/classpath/avian/avian_vm_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.avian_vm_resource; +package avian.avianvmresource; import java.net.URL; import java.net.URLStreamHandler; diff --git a/classpath/java/net/URL.java b/classpath/java/net/URL.java index 3c2852f394..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 ("avian_vm_resource".equals(protocol)) { - return new avian.avian_vm_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/makefile b/makefile index 6b611ebd2c..8330ff31e0 100755 --- a/makefile +++ b/makefile @@ -806,7 +806,7 @@ ifneq ($(classpath),avian) $(classpath-src)/avian/VMClass.java \ $(classpath-src)/avian/VMField.java \ $(classpath-src)/avian/VMMethod.java \ - $(classpath-src)/avian/avian_vm_resource/Handler.java + $(classpath-src)/avian/avianvmresource/Handler.java ifneq ($(openjdk),) classpath-sources := $(classpath-sources) \ diff --git a/openjdk.pro b/openjdk.pro index 8207016de5..165a6067af 100644 --- a/openjdk.pro +++ b/openjdk.pro @@ -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/builtin.cpp b/src/builtin.cpp index c438aebea0..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); diff --git a/src/finder.cpp b/src/finder.cpp index 12c8edc8eb..bfe6214a9e 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -602,7 +602,7 @@ class BuiltinElement: public JarElement { } virtual const char* urlPrefix() { - return "avian_vm_resource:"; + return "avianvmresource:"; } virtual const char* sourceUrl() { From 3e0ab35ba1e7b6544e52ae4e95f80cae4247a498 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 13 Oct 2012 09:39:14 -0600 Subject: [PATCH 92/95] fix PersistentSet.remove side-effect bug The whole point of PersistentSet is to provide non-destructive write operations, which means the add and remove methods should have no effect on previous revisions. However, a bug in remove caused shared tree nodes to be modified, corrupting any revisions with which they were shared. --- classpath/avian/PersistentSet.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)) { From 8f308291b05b018ecd971bd30aa31b7db4d9630b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 13 Oct 2012 09:46:12 -0600 Subject: [PATCH 93/95] eliminate call stack recursion in compile method Some OSes (notably, Windows CE) restrict the size of the call stack such that recursive compilation of branch instructions can lead to stack overflow in methods with large numbers of such instructions. In fact, a worst-case method could even lead to overflow when the stack size limit is relatively generous. The solution is to convert this recursion into iteration with an explicit stack to maintain state about alternate paths through each branch. --- src/compile.cpp | 381 +++++++++++++++++++++++++++++++++++------------- src/zone.h | 45 ++++-- 2 files changed, 314 insertions(+), 112 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index e29f4e592a..c97234363d 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1388,6 +1388,10 @@ class Frame { } ~Frame() { + dispose(); + } + + void dispose() { if (level > 1) { context->eventLog.append(PopContextEvent); } @@ -3744,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; @@ -3802,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; @@ -3869,7 +3862,7 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip, return false; } - saveStateAndCompile(t, frame, newIp); + *newIpp = newIp; return true; } @@ -4043,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); @@ -4061,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); @@ -4318,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 @@ -4363,7 +4465,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (ip == codeLength(t, code)) { c->trap(); } - } return; + } goto next; case bipush: frame->pushInt @@ -4427,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 @@ -4442,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 @@ -4540,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 @@ -4553,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 @@ -4887,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(); @@ -4899,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: @@ -4910,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(); @@ -4939,9 +5047,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, default: abort(t); } - - saveStateAndCompile(t, frame, newIp); - } break; + } goto branch; case ifeq: case ifne: @@ -4950,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); @@ -4980,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); @@ -4999,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++); @@ -5298,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(); @@ -5358,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); @@ -5376,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())); @@ -5409,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 @@ -5567,7 +5671,8 @@ 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); @@ -5598,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: { @@ -5635,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(); @@ -6062,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)) { @@ -6071,7 +6172,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, handleExit(t, frame); c->return_(0, 0); - return; + goto next; case sipush: frame->pushInt @@ -6096,7 +6197,9 @@ 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); @@ -6119,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++)) { @@ -6199,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); } @@ -6208,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; 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; }; From 3665753d1f77b6de520438947857bb42e8b7d4d4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 13 Oct 2012 13:09:24 -0600 Subject: [PATCH 94/95] fix MSVC build regression --- src/compile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index c97234363d..86432bb131 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5679,7 +5679,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned initialIp, 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) { @@ -6205,7 +6205,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned initialIp, 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))); From be12db20cb50db7a21fd5484098fe372ad482908 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 16 Oct 2012 08:33:35 -0600 Subject: [PATCH 95/95] preserve all methods in avian.OpenJDK from removal in openjdk.pro OpenJDK.getDeclaringClass is called from JVM_GetDeclaringClass, so we need to tell ProGuard to preserve it along with the other method we had already included. --- openjdk.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openjdk.pro b/openjdk.pro index 165a6067af..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 {