Merge branch 'master' of github.com:ReadyTalk/avian

This commit is contained in:
Joshua Warner 2012-10-30 14:00:16 -06:00
commit 33fed1b710
75 changed files with 3202 additions and 767 deletions

View File

@ -252,7 +252,7 @@ public class PersistentSet <T> implements Iterable <T> {
}
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 <T> implements Iterable <T> {
}
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)) {

View File

@ -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) {

View File

@ -8,7 +8,7 @@
There is NO WARRANTY for this software. See license.txt for
details. */
package avian.resource;
package avian.avianvmresource;
import java.net.URL;
import java.net.URLStreamHandler;

View File

@ -402,7 +402,16 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass,
return;
}
#ifdef __QNX__
// fork(2) doesn't work in multithreaded QNX programs. See
// http://www.qnx.com/developers/docs/6.4.1/neutrino/getting_started/s1_procs.html
pid_t pid = vfork();
#else
// We might be able to just use vfork on all UNIX-style systems, but
// the manual makes it sound dangerous due to the shared
// parent/child address space, so we use fork if we can.
pid_t pid = fork();
#endif
switch(pid){
case -1: // error
throwNewErrno(e, "java/io/IOException");
@ -569,6 +578,8 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name,
} else if (strcmp(chars, "os.name") == 0) {
#ifdef __APPLE__
r = e->NewStringUTF("Mac OS X");
#elif defined __FreeBSD__
r = e->NewStringUTF("FreeBSD");
#else
r = e->NewStringUTF("Linux");
#endif

View File

@ -16,6 +16,8 @@
# define ONLY_ON_WINDOWS(x) x
#else
# include <netdb.h>
# include <sys/socket.h>
# include <netinet/in.h>
# define ONLY_ON_WINDOWS(x)
#endif

View File

@ -31,6 +31,9 @@
# include <errno.h>
# include <netdb.h>
# include <sys/select.h>
# include <arpa/inet.h>
# include <netinet/in.h>
# include <netinet/ip.h>
# include <netinet/tcp.h>
# include <sys/socket.h>
#endif
@ -257,7 +260,7 @@ setTcpNoDelay(JNIEnv* e, int d, bool on)
}
void
doListen(JNIEnv* e, int s, sockaddr_in* address)
doBind(JNIEnv* e, int s, sockaddr_in* address)
{
int opt = 1;
int r = ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
@ -272,8 +275,12 @@ doListen(JNIEnv* e, int s, sockaddr_in* address)
throwIOException(e);
return;
}
}
r = ::listen(s, 100);
void
doListen(JNIEnv* e, int s)
{
int r = ::listen(s, 100);
if (r != 0) {
throwIOException(e);
}
@ -333,6 +340,26 @@ doRead(int fd, void* buffer, size_t count)
#endif
}
int
doRecv(int fd, void* buffer, size_t count, int32_t* host, int32_t* port)
{
sockaddr address;
socklen_t length = sizeof(address);
int r = recvfrom
(fd, static_cast<char*>(buffer), count, 0, &address, &length);
if (r > 0) {
sockaddr_in a; memcpy(&a, &address, length);
*host = ntohl(a.sin_addr.s_addr);
*port = ntohs(a.sin_port);
} else {
*host = 0;
*port = 0;
}
return r;
}
int
doWrite(int fd, const void* buffer, size_t count)
{
@ -344,9 +371,9 @@ doWrite(int fd, const void* buffer, size_t count)
}
int
makeSocket(JNIEnv* e)
makeSocket(JNIEnv* e, int type = SOCK_STREAM, int protocol = IPPROTO_TCP)
{
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int s = ::socket(AF_INET, type, protocol);
if (s < 0) {
throwIOException(e);
return s;
@ -378,7 +405,28 @@ Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv *e,
init(e, &address, host, port);
if (e->ExceptionCheck()) return 0;
::doListen(e, s, &address);
::doBind(e, s, &address);
if (e->ExceptionCheck()) return 0;
::doListen(e, s);
return s;
}
extern "C" JNIEXPORT jint JNICALL
Java_java_nio_channels_DatagramChannel_bind(JNIEnv *e,
jclass,
jstring host,
jint port)
{
int s = makeSocket(e, SOCK_DGRAM, IPPROTO_UDP);
if (s < 0) return s;
if (e->ExceptionCheck()) return 0;
sockaddr_in address;
init(e, &address, host, port);
if (e->ExceptionCheck()) return 0;
::doBind(e, s, &address);
return s;
}
@ -391,6 +439,16 @@ Java_java_nio_channels_SocketChannel_configureBlocking(JNIEnv *e,
setBlocking(e, socket, blocking);
}
extern "C" JNIEXPORT void JNICALL
Java_java_nio_channels_DatagramChannel_configureBlocking(JNIEnv* e,
jclass c,
jint socket,
jboolean blocking)
{
return Java_java_nio_channels_SocketChannel_configureBlocking
(e, c, socket, blocking);
}
extern "C" JNIEXPORT void JNICALL
Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e,
jclass,
@ -423,6 +481,24 @@ Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e,
return s;
}
extern "C" JNIEXPORT jint JNICALL
Java_java_nio_channels_DatagramChannel_connect(JNIEnv *e,
jclass,
jstring host,
jint port)
{
int s = makeSocket(e, SOCK_DGRAM, IPPROTO_UDP);
if (e->ExceptionCheck()) return 0;
sockaddr_in address;
init(e, &address, host, port);
if (e->ExceptionCheck()) return 0;
::doConnect(e, s, &address);
return s;
}
extern "C" JNIEXPORT void JNICALL
Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e,
jclass,
@ -475,6 +551,57 @@ Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e,
return r;
}
extern "C" JNIEXPORT jint JNICALL
Java_java_nio_channels_DatagramChannel_receive(JNIEnv* e,
jclass,
jint socket,
jbyteArray buffer,
jint offset,
jint length,
jboolean blocking,
jintArray address)
{
int r;
int32_t host;
int32_t port;
if (blocking) {
uint8_t* buf = static_cast<uint8_t*>(allocate(e, length));
if (buf) {
r = ::doRecv(socket, buf, length, &host, &port);
if (r > 0) {
e->SetByteArrayRegion
(buffer, offset, r, reinterpret_cast<jbyte*>(buf));
}
free(buf);
} else {
return 0;
}
} else {
jboolean isCopy;
uint8_t* buf = static_cast<uint8_t*>
(e->GetPrimitiveArrayCritical(buffer, &isCopy));
r = ::doRecv(socket, buf + offset, length, &host, &port);
e->ReleasePrimitiveArrayCritical(buffer, buf, 0);
}
if (r < 0) {
if (eagain()) {
return 0;
} else {
throwIOException(e);
}
} else if (r == 0) {
return -1;
} else {
jint jhost = host; e->SetIntArrayRegion(address, 0, 1, &jhost);
jint jport = port; e->SetIntArrayRegion(address, 1, 1, &jport);
}
return r;
}
extern "C" JNIEXPORT jint JNICALL
Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e,
jclass,
@ -515,6 +642,18 @@ Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e,
return r;
}
extern "C" JNIEXPORT jint JNICALL
Java_java_nio_channels_DatagramChannel_write(JNIEnv* e,
jclass c,
jint socket,
jbyteArray buffer,
jint offset,
jint length,
jboolean blocking)
{
return Java_java_nio_channels_SocketChannel_natWrite
(e, c, socket, buffer, offset, length, blocking);
}
extern "C" JNIEXPORT void JNICALL
Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e,
@ -554,18 +693,29 @@ class Pipe {
address.sin_family = AF_INET;
address.sin_port = 0;
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //INADDR_LOOPBACK;
listener_ = makeSocket(e);
if (e->ExceptionCheck()) return;
setBlocking(e, listener_, false);
::doListen(e, listener_, &address);
::doBind(e, listener_, &address);
if (e->ExceptionCheck()) return;
::doListen(e, listener_);
if (e->ExceptionCheck()) return;
socklen_t length = sizeof(sockaddr_in);
int r = getsockname(listener_, reinterpret_cast<sockaddr*>(&address),
&length);
if (r) {
throwIOException(e);
return;
}
writer_ = makeSocket(e);
if (e->ExceptionCheck()) return;
setBlocking(e, writer_, true);
connected_ = ::doConnect(e, writer_, &address);
}
@ -663,6 +813,7 @@ Java_java_nio_channels_SocketSelector_natInit(JNIEnv* e, jclass)
void *mem = malloc(sizeof(SelectorState));
if (mem) {
SelectorState *s = new (mem) SelectorState(e);
if (e->ExceptionCheck()) return 0;
if (s) {
FD_ZERO(&(s->read));

View File

@ -72,12 +72,16 @@ public class File implements Serializable {
}
}
private static String normalize(String path) {
if ("\\".equals(FileSeparator)) {
return path.replace('/', '\\');
} else {
return path;
private static String stripSeparators(String p) {
while (p.endsWith(FileSeparator)) {
p = p.substring(0, p.length() - 1);
}
return p;
}
private static String normalize(String path) {
return stripSeparators
("\\".equals(FileSeparator) ? path.replace('/', '\\') : path);
}
public static native boolean rename(String old, String new_);
@ -150,7 +154,7 @@ public class File implements Serializable {
public String getParent() {
int index = path.lastIndexOf(FileSeparator);
if (index >= 0) {
return path.substring(0, index);
return normalize(path.substring(0, index));
} else {
return null;
}
@ -239,11 +243,15 @@ public class File implements Serializable {
public File[] listFiles(FilenameFilter filter) {
String[] list = list(filter);
File[] result = new File[list.length];
for (int i = 0; i < list.length; ++i) {
result[i] = new File(this, list[i]);
if (list != null) {
File[] result = new File[list.length];
for (int i = 0; i < list.length; ++i) {
result[i] = new File(this, list[i]);
}
return result;
} else {
return null;
}
return result;
}
public String[] list() {
@ -254,22 +262,26 @@ public class File implements Serializable {
long handle = 0;
try {
handle = openDir(path);
Pair list = null;
int count = 0;
for (String s = readDir(handle); s != null; s = readDir(handle)) {
if (filter == null || filter.accept(this, s)) {
list = new Pair(s, list);
++ count;
if (handle != 0) {
Pair list = null;
int count = 0;
for (String s = readDir(handle); s != null; s = readDir(handle)) {
if (filter == null || filter.accept(this, s)) {
list = new Pair(s, list);
++ count;
}
}
}
String[] result = new String[count];
for (int i = count - 1; i >= 0; --i) {
result[i] = list.value;
list = list.next;
}
String[] result = new String[count];
for (int i = count - 1; i >= 0; --i) {
result[i] = list.value;
list = list.next;
}
return result;
return result;
} else {
return null;
}
} finally {
if (handle != 0) {
closeDir(handle);

View File

@ -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 {

View File

@ -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 { }

View File

@ -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;

View File

@ -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();

View File

@ -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;
}

View File

@ -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 { }

View File

@ -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;
}

View File

@ -83,8 +83,8 @@ public final class URL {
{
if ("http".equals(protocol) || "https".equals(protocol)) {
return new avian.http.Handler();
} else if ("resource".equals(protocol)) {
return new avian.resource.Handler();
} else if ("avianvmresource".equals(protocol)) {
return new avian.avianvmresource.Handler();
} else if ("file".equals(protocol)) {
return new avian.file.Handler();
} else if ("jar".equals(protocol)) {

View File

@ -0,0 +1,92 @@
/* Copyright (c) 2008-2012, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.nio;
class ArrayByteBuffer extends ByteBuffer {
private final byte[] array;
private final int arrayOffset;
ArrayByteBuffer(byte[] array, int offset, int length, boolean readOnly) {
super(readOnly);
this.array = array;
this.arrayOffset = offset;
this.capacity = length;
this.limit = length;
this.position = 0;
}
public ByteBuffer asReadOnlyBuffer() {
ByteBuffer b = new ArrayByteBuffer(array, arrayOffset, capacity, true);
b.position(position());
b.limit(limit());
return b;
}
public boolean hasArray() {
return true;
}
public byte[] array() {
return array;
}
public ByteBuffer slice() {
return new ArrayByteBuffer
(array, arrayOffset + position, remaining(), true);
}
public int arrayOffset() {
return arrayOffset;
}
protected void doPut(int position, byte val) {
array[arrayOffset + position] = val;
}
public ByteBuffer put(ByteBuffer src) {
int length = src.remaining();
checkPut(position, length);
src.get(array, arrayOffset + position, length);
position += length;
return this;
}
public ByteBuffer put(byte[] src, int offset, int length) {
checkPut(position, length);
System.arraycopy(src, offset, array, arrayOffset + position, length);
position += length;
return this;
}
public ByteBuffer get(byte[] dst, int offset, int length) {
checkGet(position, length);
System.arraycopy(array, arrayOffset + position, dst, offset, length);
position += length;
return this;
}
protected byte doGet(int position) {
return array[arrayOffset+position];
}
public String toString() {
return "(ArrayByteBuffer with array: " + array
+ " arrayOffset: " + arrayOffset
+ " position: " + position
+ " limit: " + limit
+ " capacity: " + capacity + ")";
}
}

View File

@ -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<ByteBuffer> {
private final byte[] array;
private int arrayOffset;
public abstract class ByteBuffer
extends Buffer
implements Comparable<ByteBuffer>
{
private final boolean readOnly;
protected ByteBuffer(boolean readOnly) {
this.readOnly = readOnly;
}
public static ByteBuffer allocate(int capacity) {
return new ByteBuffer(new byte[capacity], 0, capacity, false);
return new ArrayByteBuffer(new byte[capacity], 0, capacity, false);
}
public static ByteBuffer allocateDirect(int capacity) {
return FixedArrayByteBuffer.make(capacity);
}
public static ByteBuffer wrap(byte[] array) {
@ -24,23 +33,53 @@ public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
}
public static ByteBuffer wrap(byte[] array, int offset, int length) {
return new ByteBuffer(array, offset, length, false);
return new ArrayByteBuffer(array, offset, length, false);
}
private ByteBuffer(byte[] array, int offset, int length, boolean readOnly) {
this.array = array;
this.readOnly = readOnly;
arrayOffset = offset;
capacity = length;
limit = capacity;
position = 0;
public abstract ByteBuffer asReadOnlyBuffer();
public abstract ByteBuffer slice();
protected abstract void doPut(int offset, byte val);
public abstract ByteBuffer put(byte[] arr, int offset, int len);
protected abstract byte doGet(int offset);
public abstract ByteBuffer get(byte[] dst, int offset, int length);
public boolean hasArray() {
return false;
}
public ByteBuffer asReadOnlyBuffer() {
ByteBuffer b = new ByteBuffer(array, arrayOffset, capacity, true);
b.position(position());
b.limit(limit());
return b;
public ByteBuffer compact() {
int remaining = remaining();
if (position != 0) {
ByteBuffer b = slice();
position = 0;
put(b);
}
position = remaining;
limit(capacity());
return this;
}
public ByteBuffer put(ByteBuffer src) {
if (src.hasArray()) {
checkPut(position, src.remaining());
put(src.array(), src.arrayOffset() + src.position, src.remaining());
src.position(src.position() + src.remaining());
return this;
} else {
byte[] buffer = new byte[src.remaining()];
src.get(buffer);
return put(buffer);
}
}
public int compareTo(ByteBuffer o) {
@ -60,37 +99,22 @@ public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
}
public byte[] array() {
return array;
}
public ByteBuffer slice() {
return new ByteBuffer(array, arrayOffset + position, remaining(), true);
throw new UnsupportedOperationException();
}
public int arrayOffset() {
return arrayOffset;
throw new UnsupportedOperationException();
}
public ByteBuffer compact() {
if (position != 0) {
System.arraycopy(array, arrayOffset+position, array, arrayOffset, remaining());
}
position=remaining();
limit(capacity());
public ByteBuffer put(int offset, byte val) {
checkPut(offset, 1);
doPut(offset, val);
return this;
}
public ByteBuffer put(byte val) {
checkPut(1);
array[arrayOffset+(position++)] = val;
return this;
}
public ByteBuffer put(ByteBuffer src) {
checkPut(src.remaining());
put(src.array, src.arrayOffset + src.position, src.remaining());
src.position += src.remaining();
put(position, val);
++ position;
return this;
}
@ -98,125 +122,126 @@ public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
return put(arr, 0, arr.length);
}
public ByteBuffer put(byte[] arr, int offset, int len) {
checkPut(len);
System.arraycopy(arr, offset, array, arrayOffset+position, len);
position += len;
public ByteBuffer putLong(int position, long val) {
checkPut(position, 8);
doPut(position , (byte) ((val >> 56) & 0xff));
doPut(position + 1, (byte) ((val >> 48) & 0xff));
doPut(position + 2, (byte) ((val >> 40) & 0xff));
doPut(position + 3, (byte) ((val >> 32) & 0xff));
doPut(position + 4, (byte) ((val >> 24) & 0xff));
doPut(position + 5, (byte) ((val >> 16) & 0xff));
doPut(position + 6, (byte) ((val >> 8) & 0xff));
doPut(position + 7, (byte) ((val ) & 0xff));
return this;
}
public ByteBuffer putInt(int position, int val) {
checkPut(position, 4);
array[arrayOffset+position] = (byte)((val >> 24) & 0xff);
array[arrayOffset+position+1] = (byte)((val >> 16) & 0xff);
array[arrayOffset+position+2] = (byte)((val >> 8) & 0xff);
array[arrayOffset+position+3] = (byte)((val ) & 0xff);
doPut(position , (byte) ((val >> 24) & 0xff));
doPut(position + 1, (byte) ((val >> 16) & 0xff));
doPut(position + 2, (byte) ((val >> 8) & 0xff));
doPut(position + 3, (byte) ((val ) & 0xff));
return this;
}
public ByteBuffer putShort(int position, short val) {
checkPut(position, 2);
doPut(position , (byte) ((val >> 8) & 0xff));
doPut(position + 1, (byte) ((val ) & 0xff));
return this;
}
public ByteBuffer putLong(long val) {
putLong(position, val);
position += 8;
return this;
}
public ByteBuffer putInt(int val) {
checkPut(4);
putInt(position, val);
position += 4;
return this;
}
public ByteBuffer putShort(short val) {
checkPut(2);
put((byte)((val >> 8) & 0xff));
put((byte)(val & 0xff));
return this;
}
public ByteBuffer putLong(long val) {
checkPut(8);
putInt((int)(val >> 32));
putInt((int)val);
putShort(position, val);
position += 2;
return this;
}
public byte get() {
checkGet(1);
return array[arrayOffset+(position++)];
return get(position++);
}
public byte get(int position) {
checkGet(position, 1);
return doGet(position);
}
public ByteBuffer get(byte[] dst) {
return get(dst, 0, dst.length);
}
public ByteBuffer get(byte[] dst, int offset, int length) {
checkGet(length);
System.arraycopy(array, arrayOffset + position, dst, offset, length);
position += length;
return this;
}
public long getLong(int position) {
checkGet(position, 8);
public byte get(int position) {
checkGet(position, 1);
return array[arrayOffset+position];
return (((long) (doGet(position ) & 0xFF)) << 56)
| (((long) (doGet(position + 1) & 0xFF)) << 48)
| (((long) (doGet(position + 2) & 0xFF)) << 40)
| (((long) (doGet(position + 3) & 0xFF)) << 32)
| (((long) (doGet(position + 4) & 0xFF)) << 24)
| (((long) (doGet(position + 5) & 0xFF)) << 16)
| (((long) (doGet(position + 6) & 0xFF)) << 8)
| (((long) (doGet(position + 7) & 0xFF)) );
}
public int getInt(int position) {
checkGet(position, 4);
int p = arrayOffset + position;
return ((array[p] & 0xFF) << 24)
| ((array[p + 1] & 0xFF) << 16)
| ((array[p + 2] & 0xFF) << 8)
| ((array[p + 3] & 0xFF));
return (((int) (doGet(position ) & 0xFF)) << 24)
| (((int) (doGet(position + 1) & 0xFF)) << 16)
| (((int) (doGet(position + 2) & 0xFF)) << 8)
| (((int) (doGet(position + 3) & 0xFF)) );
}
public short getShort(int position) {
checkGet(position, 2);
int p = arrayOffset + position;
return (short) (((array[p] & 0xFF) << 8) | ((array[p + 1] & 0xFF)));
}
public int getInt() {
checkGet(4);
int i = get() << 24;
i |= (get() & 0xff) << 16;
i |= (get() & 0xff) << 8;
i |= (get() & 0xff);
return i;
}
public short getShort() {
checkGet(2);
short s = (short)(get() << 8);
s |= get() & 0xff;
return s;
return (short) (( ((int) (doGet(position ) & 0xFF)) << 8)
| (((int) (doGet(position + 1) & 0xFF)) ));
}
public long getLong() {
checkGet(8);
long l = (long)getInt() << 32;
l |= (long)getInt() & 0xffffffffL;
return l;
long r = getLong(position);
position += 8;
return r;
}
private void checkPut(int amount) {
if (readOnly) throw new ReadOnlyBufferException();
if (amount > limit-position) throw new IndexOutOfBoundsException();
public int getInt() {
int r = getInt(position);
position += 4;
return r;
}
private void checkPut(int position, int amount) {
public short getShort() {
short r = getShort(position);
position += 2;
return r;
}
protected void checkPut(int position, int amount) {
if (readOnly) throw new ReadOnlyBufferException();
if (position < 0 || position+amount > limit)
throw new IndexOutOfBoundsException();
}
private void checkGet(int amount) {
protected void checkGet(int position, int amount) {
if (amount > limit-position) throw new IndexOutOfBoundsException();
}
private void checkGet(int position, int amount) {
if (position < 0 || position+amount > limit)
throw new IndexOutOfBoundsException();
}
public String toString() {
return "(ByteBuffer with array: " + array + " arrayOffset: " + arrayOffset + " position: " + position + " remaining; " + remaining() + ")";
}
}

View File

@ -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 + ")";
}
}

View File

@ -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 + ")";
}
}

View File

@ -0,0 +1,180 @@
/* Copyright (c) 2012, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.nio.channels;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.net.SocketAddress;
import java.net.InetSocketAddress;
import java.net.ProtocolFamily;
import java.net.Socket;
import java.net.SocketException;
import java.net.DatagramSocket;
import java.net.StandardProtocolFamily;
public class DatagramChannel extends SelectableChannel
implements ReadableByteChannel, WritableByteChannel
{
public static final int InvalidSocket = -1;
private int socket = InvalidSocket;
private boolean blocking = true;
public SelectableChannel configureBlocking(boolean v) throws IOException {
blocking = v;
if (socket != InvalidSocket) {
configureBlocking(socket, v);
}
return this;
}
int socketFD() {
return socket;
}
void handleReadyOps(int ops) {
// ignore
}
public static DatagramChannel open(ProtocolFamily family)
throws IOException
{
if (family.equals(StandardProtocolFamily.INET)) {
Socket.init();
return new DatagramChannel();
} else {
throw new UnsupportedOperationException();
}
}
public static DatagramChannel open()
throws IOException
{
return open(StandardProtocolFamily.INET);
}
public DatagramSocket socket() {
return new Handle();
}
public DatagramChannel bind(SocketAddress address) throws IOException {
InetSocketAddress inetAddress;
try {
inetAddress = (InetSocketAddress) address;
} catch (ClassCastException e) {
throw new UnsupportedAddressTypeException();
}
socket = bind(inetAddress.getHostName(), inetAddress.getPort());
return this;
}
public DatagramChannel connect(SocketAddress address) throws IOException {
InetSocketAddress inetAddress;
try {
inetAddress = (InetSocketAddress) address;
} catch (ClassCastException e) {
throw new UnsupportedAddressTypeException();
}
socket = connect(inetAddress.getHostName(), inetAddress.getPort());
return this;
}
public int write(ByteBuffer b) throws IOException {
if (b.remaining() == 0) return 0;
byte[] array = b.array();
if (array == null) throw new NullPointerException();
int c = write
(socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking);
if (c > 0) {
b.position(b.position() + c);
}
return c;
}
public int read(ByteBuffer b) throws IOException {
int p = b.position();
receive(b);
return b.position() - p;
}
public SocketAddress receive(ByteBuffer b) throws IOException {
if (b.remaining() == 0) return null;
byte[] array = b.array();
if (array == null) throw new NullPointerException();
int[] address = new int[2];
int c = receive
(socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking,
address);
if (c > 0) {
b.position(b.position() + c);
return new InetSocketAddress(ipv4ToString(address[0]), address[1]);
} else {
return null;
}
}
private static String ipv4ToString(int address) {
StringBuilder sb = new StringBuilder();
sb.append( address >> 24 ).append('.')
.append((address >> 16) & 0xFF).append('.')
.append((address >> 8) & 0xFF).append('.')
.append( address & 0xFF);
return sb.toString();
}
public class Handle extends DatagramSocket {
public SocketAddress getRemoteSocketAddress() {
throw new UnsupportedOperationException();
}
public void bind(SocketAddress address) throws SocketException {
try {
DatagramChannel.this.bind(address);
} catch (SocketException e) {
throw e;
} catch (IOException e) {
SocketException se = new SocketException();
se.initCause(e);
throw se;
}
}
}
private static native void configureBlocking(int socket, boolean blocking)
throws IOException;
private static native int bind(String hostname, int port)
throws IOException;
private static native int connect(String hostname, int port)
throws IOException;
private static native int write(int socket, byte[] array, int offset,
int length, boolean blocking)
throws IOException;
private static native int receive(int socket, byte[] array, int offset,
int length, boolean blocking,
int[] address)
throws IOException;
}

View File

@ -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)

View File

@ -15,6 +15,11 @@ public abstract class AbstractList<T> extends AbstractCollection<T>
{
protected int modCount;
public boolean add(T o) {
add(size(), o);
return true;
}
public Iterator<T> iterator() {
return listIterator();
}

View File

@ -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));
}

View File

@ -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);
}
}

109
makefile
View File

@ -5,6 +5,8 @@ version = 0.6
build-arch := $(shell uname -m \
| sed 's/^i.86$$/i386/' \
| sed 's/^x86pc$$/i386/' \
| sed 's/amd64/x86_64/' \
| sed 's/^arm.*$$/arm/' \
| sed 's/ppc/powerpc/')
@ -22,7 +24,6 @@ target-arch = $(arch)
bootimage-platform = \
$(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))
platform = $(bootimage-platform)
target-platform = $(platform)
mode = fast
process = compile
@ -85,6 +86,8 @@ ifeq ($(build-platform),darwin)
library-path-variable = DYLD_LIBRARY_PATH
endif
library-path = $(library-path-variable)=$(build)
ifneq ($(openjdk),)
openjdk-arch = $(arch)
ifeq ($(arch),x86_64)
@ -161,6 +164,8 @@ ifneq ($(platform),darwin)
endif
endif
target-format = elf
cxx = $(build-cxx) $(mflag)
cc = $(build-cc) $(mflag)
@ -186,9 +191,10 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
target-cflags = -DTARGET_BYTES_PER_WORD=$(pointer-size)
common-cflags = $(warnings) -fno-rtti -fno-exceptions \
common-cflags = $(warnings) -fno-rtti -fno-exceptions -I$(classpath-src) \
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
-DAVIAN_INFO="\"$(info)\"" \
-DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \
-DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" $(target-cflags)
@ -207,7 +213,7 @@ build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
converter-cflags = -D__STDC_CONSTANT_MACROS -Isrc/binaryToObject -Isrc/ \
-fno-rtti -fno-exceptions \
-DAVIAN_TARGET_ARCH=AVIAN_ARCH_UNKNOWN \
-DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_UNKNOWN \
-DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_UNKNOWN \
-Wall -Wextra -Werror -Wunused-parameter -Winit-self -Wno-non-virtual-dtor
cflags = $(build-cflags)
@ -218,6 +224,7 @@ build-lflags = -lz -lpthread -ldl
lflags = $(common-lflags) -lpthread -ldl
soname-flag = -Wl,-soname -Wl,$(so-prefix)jvm$(so-suffix)
version-script-flag = -Wl,--version-script=openjdk.ld
build-system = posix
@ -284,8 +291,13 @@ ifeq ($(arch),arm)
ifneq ($(arch),$(build-arch))
ifeq ($(platform),darwin)
ios-bin = $(developer-dir)/Platforms/iPhoneOS.platform/Developer/usr/bin
cxx = $(ios-bin)/g++
cc = $(ios-bin)/gcc
ifeq ($(use-clang),true)
cxx = clang -std=c++11
cc = clang
else
cxx = $(ios-bin)/g++
cc = $(ios-bin)/gcc
endif
ar = $(ios-bin)/ar
ranlib = $(ios-bin)/ranlib
strip = $(ios-bin)/strip
@ -305,11 +317,45 @@ endif
ifeq ($(build-platform),darwin)
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
cflags += -I/System/Library/Frameworks/JavaVM.framework/Headers/
cflags += -I/System/Library/Frameworks/JavaVM.framework/Headers/ \
-Wno-deprecated-declarations
build-lflags += -framework CoreFoundation
soname-flag =
endif
ifeq ($(platform),qnx)
cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
lflags = $(common-lflags) -lsocket
ifeq ($(build-platform),qnx)
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
build-lflags = $(common-lflags)
else
ifeq ($(arch),i386)
prefix = i486-pc-nto-qnx6.5.0-
else
prefix = arm-unknown-nto-qnx6.5.0-
endif
endif
cxx = $(prefix)g++
cc = $(prefix)gcc
ar = $(prefix)ar
ranlib = $(prefix)ranlib
strip = $(prefix)strip
rdynamic = -Wl,--export-dynamic
endif
ifeq ($(platform),freebsd)
# There is no -ldl on FreeBSD
build-lflags = $(common-lflags) -lz -lpthread
lflags = $(common-lflags) -lpthread
# include/freebsd instead of include/linux
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
"-I$(JAVA_HOME)/include/freebsd" -I$(src) -pthread
cflags = $(build-cflags)
endif
ifeq ($(platform),darwin)
target-format = macho
ifeq (${OSX_SDK_SYSROOT},)
OSX_SDK_SYSROOT = 10.4u
endif
@ -350,7 +396,8 @@ ifeq ($(platform),darwin)
ifeq ($(arch),arm)
ios-version := \
$(shell if test -d $(sdk-dir)/iPhoneOS5.1.sdk; then echo 5.1; \
$(shell if test -d $(sdk-dir)/iPhoneOS6.0.sdk; then echo 6.0; \
elif test -d $(sdk-dir)/iPhoneOS5.1.sdk; then echo 5.1; \
elif test -d $(sdk-dir)/iPhoneOS5.0.sdk; then echo 5.0; \
elif test -d $(sdk-dir)/iPhoneOS4.3.sdk; then echo 4.3; \
elif test -d $(sdk-dir)/iPhoneOS4.2.sdk; then echo 4.2; \
@ -391,6 +438,8 @@ ifeq ($(platform),darwin)
endif
ifeq ($(platform),windows)
target-format = pe
inc = "$(win32)/include"
lib = "$(win32)/lib"
@ -527,7 +576,8 @@ ifdef msvc
cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \
-DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \
-DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \
-Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I"$(build)" \
-Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I$(classpath-src) \
-I"$(build)" \
-I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" \
-DTARGET_BYTES_PER_WORD=$(pointer-size)
@ -756,7 +806,7 @@ ifneq ($(classpath),avian)
$(classpath-src)/avian/VMClass.java \
$(classpath-src)/avian/VMField.java \
$(classpath-src)/avian/VMMethod.java \
$(classpath-src)/avian/resource/Handler.java
$(classpath-src)/avian/avianvmresource/Handler.java
ifneq ($(openjdk),)
classpath-sources := $(classpath-sources) \
@ -777,9 +827,12 @@ vm-classes = \
test-support-sources = $(shell find $(test)/avian/ -name '*.java')
test-sources = $(wildcard $(test)/*.java)
test-cpp-sources = $(wildcard $(test)/*.cpp)
test-sources += $(test-support-sources)
test-support-classes = $(call java-classes, $(test-support-sources),$(test),$(test-build))
test-classes = $(call java-classes,$(test-sources),$(test),$(test-build))
test-cpp-objects = $(call cpp-objects,$(test-cpp-sources),$(test),$(test-build))
test-library = $(build)/$(so-prefix)test$(so-suffix)
test-dep = $(test-build).dep
test-extra-sources = $(wildcard $(test)/extra/*.java)
@ -815,22 +868,22 @@ ifeq ($(target-arch),arm)
cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM
endif
ifeq ($(target-platform),linux)
cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_LINUX
ifeq ($(target-format),elf)
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_ELF
endif
ifeq ($(target-platform),windows)
cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_WINDOWS
ifeq ($(target-format),pe)
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_PE
endif
ifeq ($(target-platform),darwin)
cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_DARWIN
ifeq ($(target-format),macho)
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_MACHO
endif
class-name = $(patsubst $(1)/%.class,%,$(2))
class-names = $(foreach x,$(2),$(call class-name,$(1),$(x)))
test-flags = -cp $(build)/test
test-flags = -Djava.library.path=$(build) -cp $(build)/test
test-args = $(test-flags) $(input)
@ -904,7 +957,7 @@ $(classpath-dep): $(classpath-sources)
$(test-build)/%.class: $(test)/%.java
@echo $(<)
$(test-dep): $(test-sources)
$(test-dep): $(test-sources) $(test-library)
@echo "compiling test classes"
@mkdir -p $(test-build)
files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \
@ -939,6 +992,19 @@ endef
$(vm-cpp-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends)
$(compile-object)
$(test-cpp-objects): $(test-build)/%.o: $(test)/%.cpp $(vm-depends)
$(compile-object)
$(test-library): $(test-cpp-objects)
@echo "linking $(@)"
ifdef msvc
$(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \
-IMPLIB:$(test-build)/$(name).lib -MANIFESTFILE:$(@).manifest
$(mt) -manifest $(@).manifest -outputresource:"$(@);2"
else
$(ld) $(^) $(shared) $(lflags) -o $(@)
endif
$(build)/%.o: $(lzma)/C/%.c
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
@ -994,7 +1060,7 @@ $(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep)
$(classpath-object): $(build)/classpath.jar $(converter)
@echo "creating $(@)"
$(converter) $(<) $(@) _binary_classpath_jar_start \
_binary_classpath_jar_end $(platform) $(arch)
_binary_classpath_jar_end $(target-format) $(arch)
$(build)/javahome.jar:
@echo "creating $(@)"
@ -1005,7 +1071,7 @@ $(build)/javahome.jar:
$(javahome-object): $(build)/javahome.jar $(converter)
@echo "creating $(@)"
$(converter) $(<) $(@) _binary_javahome_jar_start \
_binary_javahome_jar_end $(platform) $(arch)
_binary_javahome_jar_end $(target-format) $(arch)
define compile-generator-object
@echo "compiling $(@)"
@ -1066,7 +1132,7 @@ $(bootimage-generator): $(bootimage-generator-objects)
arch=$(build-arch) \
target-arch=$(arch) \
platform=$(bootimage-platform) \
target-platform=$(platform) \
target-format=$(target-format) \
openjdk=$(openjdk) \
openjdk-src=$(openjdk-src) \
bootimage-generator= \
@ -1104,7 +1170,8 @@ ifdef msvc
-IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest
$(mt) -manifest $(@).manifest -outputresource:"$(@);2"
else
$(ld) $(^) $(version-script-flag) $(shared) $(lflags) $(bootimage-lflags) \
$(ld) $(^) $(version-script-flag) $(soname-flag) \
$(shared) $(lflags) $(bootimage-lflags) \
-o $(@)
endif
$(strip) $(strip-all) $(@)

View File

@ -42,7 +42,7 @@
}
-keep class avian.OpenJDK {
public static java.security.ProtectionDomain getProtectionDomain();
<methods>;
}
-keepclassmembers public class java.security.PrivilegedAction {
@ -208,7 +208,7 @@
-keep class sun.nio.cs.UTF_8
# loaded reflectively to handle embedded resources:
-keep class avian.resource.Handler
-keep class avian.avianvmresource.Handler
# refered to symbolically in MethodAccessorGenerator:
-keep class sun.reflect.MethodAccessorImpl {
@ -244,3 +244,5 @@
-keep class sun.nio.fs.UnixException {
UnixException(int);
}
-keep class sun.net.www.protocol.jar.Handler

View File

@ -1,4 +1,4 @@
/* arm.S: JNI gluecode for ARM/Linux
/* arm.S: JNI gluecode for ARM
Copyright (c) 2008-2011, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
@ -9,6 +9,8 @@
There is NO WARRANTY for this software. See license.txt for
details. */
#include "types.h"
.text
#define LOCAL(x) .L##x
@ -29,14 +31,18 @@ GLOBAL(vmNativeCall):
r2 : memoryTable
r3 : memoryCount
[sp, #0] -> r6 : gprTable
[sp, #4] -> r7 : vfpTable
[sp, #8] -> r8 : returnType
*/
mov ip, sp // save stack frame
stmfd sp!, {r4-r6, lr} // save clobbered non-volatile regs
stmfd sp!, {r4-r8, lr} // save clobbered non-volatile regs
// mv args into non-volatile regs
mov r4, r0
mov r5, r1
ldr r6, [ip]
ldr r7, [ip, #4]
ldr r8, [ip, #8]
// setup stack arguments if necessary
sub sp, sp, r5 // allocate stack
@ -50,12 +56,38 @@ LOCAL(loop):
// setup argument registers if necessary
tst r6, r6
#if (defined __APPLE__) && (defined __clang_major__) && (__clang_major__ >= 4)
ldmiane r6, {r0-r3}
#else
ldmneia r6, {r0-r3}
#endif
#if defined(__ARM_PCS_VFP)
// and VFP registers
vldmia r7, {d0-d7}
#endif
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
mov lr, pc
bx r4
#else
blx r4 // call function
#endif
add sp, sp, r5 // deallocate stack
ldmfd sp!, {r4-r6, pc} // restore non-volatile regs and return
#if defined(__ARM_PCS_VFP)
cmp r8,#FLOAT_TYPE
bne LOCAL(double)
fmrs r0,s0
b LOCAL(exit)
LOCAL(double):
cmp r8,#DOUBLE_TYPE
bne LOCAL(exit)
fmrrd r0,r1,d0
#endif
LOCAL(exit):
ldmfd sp!, {r4-r8, pc} // restore non-volatile regs and return
.globl GLOBAL(vmJump)
.align 2
@ -85,7 +117,12 @@ GLOBAL(vmRun):
mov r12, r0
ldr r0, [r2, #CHECKPOINT_THREAD]
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
mov lr, pc
bx r12
#else
blx r12
#endif
.globl GLOBAL(vmRun_returnAddress)
.align 2

View File

@ -49,12 +49,6 @@ inline int XFER2(int cond, int P, int U, int W, int L, int Rn, int Rd, int S, in
{ return cond<<28 | P<<24 | U<<23 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | 1<<7 | S<<6 | H<<5 | 1<<4 | Rm; }
inline int XFER2I(int cond, int P, int U, int W, int L, int Rn, int Rd, int offsetH, int S, int H, int offsetL)
{ return cond<<28 | P<<24 | U<<23 | 1<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offsetH<<8 | 1<<7 | S<<6 | H<<5 | 1<<4 | (offsetL&0xf); }
inline int BLOCKXFER(int cond, int P, int U, int S, int W, int L, int Rn, int rlist)
{ return cond<<28 | 4<<25 | P<<24 | U<<23 | S<<22 | W<<21 | L<<20 | Rn<<16 | rlist; }
inline int SWI(int cond, int imm)
{ return cond<<28 | 0x0f<<24 | (imm&0xffffff); }
inline int SWAP(int cond, int B, int Rn, int Rd, int Rm)
{ return cond<<28 | 1<<24 | B<<22 | Rn<<16 | Rd<<12 | 9<<4 | Rm; }
inline int COOP(int cond, int opcode_1, int CRn, int CRd, int cp_num, int opcode_2, int CRm)
{ return cond<<28 | 0xe<<24 | opcode_1<<20 | CRn<<16 | CRd<<12 | cp_num<<8 | opcode_2<<5 | CRm; }
inline int COXFER(int cond, int P, int U, int N, int W, int L, int Rn, int CRd, int cp_num, int offset) // offset is in words, not bytes
@ -71,41 +65,29 @@ inline int b(int offset) { return BRANCH(AL, 0, offset); }
inline int bl(int offset) { return BRANCH(AL, 1, offset); }
inline int bx(int Rm) { return BRANCHX(AL, 0, Rm); }
inline int blx(int Rm) { return BRANCHX(AL, 1, Rm); }
inline int swi(int imm) { return SWI(AL, imm); }
inline int and_(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x0, 0, Rn, Rd, shift, Sh, Rm); }
inline int eor(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x1, 0, Rn, Rd, shift, Sh, Rm); }
inline int sub(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x2, 0, Rn, Rd, shift, Sh, Rm); }
inline int rsb(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x3, 0, Rn, Rd, shift, Sh, Rm); }
inline int add(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x4, 0, Rn, Rd, shift, Sh, Rm); }
inline int adc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x5, 0, Rn, Rd, shift, Sh, Rm); }
inline int sbc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x6, 0, Rn, Rd, shift, Sh, Rm); }
inline int rsc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x7, 0, Rn, Rd, shift, Sh, Rm); }
inline int tst(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x8, 1, Rn, 0, shift, Sh, Rm); }
inline int teq(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x9, 1, Rn, 0, shift, Sh, Rm); }
inline int cmp(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xa, 1, Rn, 0, shift, Sh, Rm); }
inline int cmn(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xb, 1, Rn, 0, shift, Sh, Rm); }
inline int orr(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xc, 0, Rn, Rd, shift, Sh, Rm); }
inline int mov(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xd, 0, 0, Rd, shift, Sh, Rm); }
inline int bic(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xe, 0, Rn, Rd, shift, Sh, Rm); }
inline int mvn(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xf, 0, 0, Rd, shift, Sh, Rm); }
inline int andi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x0, 0, Rn, Rd, rot, imm); }
inline int eori(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x1, 0, Rn, Rd, rot, imm); }
inline int subi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x2, 0, Rn, Rd, rot, imm); }
inline int rsbi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x3, 0, Rn, Rd, rot, imm); }
inline int addi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x4, 0, Rn, Rd, rot, imm); }
inline int adci(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x5, 0, Rn, Rd, rot, imm); }
inline int bici(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xe, 0, Rn, Rd, rot, imm); }
inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0xa, 1, Rn, 0, rot, imm); }
inline int orri(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xc, 0, Rn, Rd, rot, imm); }
inline int movi(int Rd, int imm, int rot=0) { return DATAI(AL, 0xd, 0, 0, Rd, rot, imm); }
inline int orrsh(int Rd, int Rn, int Rm, int Rs, int Sh) { return DATAS(AL, 0xc, 0, Rn, Rd, Rs, Sh, Rm); }
inline int movsh(int Rd, int Rm, int Rs, int Sh) { return DATAS(AL, 0xd, 0, 0, Rd, Rs, Sh, Rm); }
inline int mul(int Rd, int Rm, int Rs) { return MULTIPLY(AL, 0, 0, Rd, 0, Rs, Rm); }
inline int mla(int Rd, int Rm, int Rs, int Rn) { return MULTIPLY(AL, 1, 0, Rd, Rn, Rs, Rm); }
inline int umull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, RdHi, RdLo, Rs, Rm); }
inline int umlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 5, 0, RdHi, RdLo, Rs, Rm); }
inline int smull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdHi, RdLo, Rs, Rm); }
inline int smlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 7, 0, RdHi, RdLo, Rs, Rm); }
inline int ldr(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 1, Rn, Rd, 0, 0, Rm); }
inline int ldri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 1, Rn, Rd, abs(imm)); }
inline int ldrb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 1, Rn, Rd, 0, 0, Rm); }
@ -122,39 +104,19 @@ inline int ldrsh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd,
inline int ldrshi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 1, abs(imm)&0xf); }
inline int ldrsb(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 0, Rm); }
inline int ldrsbi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 0, abs(imm)&0xf); }
inline int pop(int Rd) { return XFERI(AL, 0, 1, 0, 0, 1, 13, Rd, 4); }
inline int ldmfd(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 1, 1, Rn, rlist); }
inline int stmfd(int Rn, int rlist) { return BLOCKXFER(AL, 1, 0, 0, 1, 0, Rn, rlist); }
inline int swp(int Rd, int Rm, int Rn) { return SWAP(AL, 0, Rn, Rd, Rm); }
inline int swpb(int Rd, int Rm, int Rn) { return SWAP(AL, 1, Rn, Rd, Rm); }
// breakpoint instruction, this really has its own instruction format
inline int bkpt(int16_t immed) { return 0xe1200070 | (((unsigned)immed & 0xffff) >> 4 << 8) | (immed & 0xf); }
// COPROCESSOR INSTRUCTIONS
inline int cdp(int coproc, int opcode_1, int CRd, int CRn, int CRm, int opcode_2) { return COOP(AL, opcode_1, CRn, CRd, coproc, opcode_2, CRm); }
inline int mcr(int coproc, int opcode_1, int Rd, int CRn, int CRm, int opcode_2=0) { return COREG(AL, opcode_1, 0, CRn, Rd, coproc, opcode_2, CRm); }
inline int mcrr(int coproc, int opcode, int Rd, int Rn, int CRm) { return COREG2(AL, 0, Rn, Rd, coproc, opcode, CRm); }
inline int mrc(int coproc, int opcode_1, int Rd, int CRn, int CRm, int opcode_2=0) { return COREG(AL, opcode_1, 1, CRn, Rd, coproc, opcode_2, CRm); }
inline int mrrc(int coproc, int opcode, int Rd, int Rn, int CRm) { return COREG2(AL, 1, Rn, Rd, coproc, opcode, CRm); }
inline int ldc(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 0, W, 1, Rn, CRd, coproc, offset); }
inline int ldcl(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 1, W, 1, Rn, CRd, coproc, offset); }
inline int stc(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 0, W, 0, Rn, CRd, coproc, offset); }
inline int stcl(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 1, W, 0, Rn, CRd, coproc, offset); }
// VFP FLOATING-POINT INSTRUCTIONS
inline int fmacs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
inline int fnmacs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); }
inline int fmscs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|1, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
inline int fnmscs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|1, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); }
inline int fmuls(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
inline int fnmuls(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); }
inline int fadds(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|3, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
inline int fsubs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|3, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); }
inline int fdivs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|8, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
inline int fmacd(int Dd, int Dn, int Dm) { return COOP(AL, 0, Dn, Dd, 11, 0, Dm); }
inline int fnmacd(int Dd, int Dn, int Dm) { return COOP(AL, 0, Dn, Dd, 11, 2, Dm); }
inline int fmscd(int Dd, int Dn, int Dm) { return COOP(AL, 1, Dn, Dd, 11, 0, Dm); }
inline int fnmscd(int Dd, int Dn, int Dm) { return COOP(AL, 1, Dn, Dd, 11, 2, Dm); }
inline int fmuld(int Dd, int Dn, int Dm) { return COOP(AL, 2, Dn, Dd, 11, 0, Dm); }
inline int fnmuld(int Dd, int Dn, int Dm) { return COOP(AL, 2, Dn, Dd, 11, 2, Dm); }
inline int faddd(int Dd, int Dn, int Dm) { return COOP(AL, 3, Dn, Dd, 11, 0, Dm); }
inline int fsubd(int Dd, int Dn, int Dm) { return COOP(AL, 3, Dn, Dd, 11, 2, Dm); }
inline int fdivd(int Dd, int Dn, int Dm) { return COOP(AL, 8, Dn, Dd, 11, 0, Dm); }
@ -163,15 +125,8 @@ inline int fabss(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0, Sd>>1, 10,
inline int fnegs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 1, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
inline int fsqrts(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 1, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
inline int fcmps(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 4, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
inline int fcmpes(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 4, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
inline int fcmpzs(int Sd) { return COOP(AL, 0xb|(Sd&1)<<2, 5, Sd>>1, 10, 2, 0); }
inline int fcmpezs(int Sd) { return COOP(AL, 0xb|(Sd&1)<<2, 5, Sd>>1, 10, 6, 0); }
inline int fcvtds(int Dd, int Sm) { return COOP(AL, 0xb, 7, Dd, 10, 6|(Sm&1), Sm>>1); }
inline int fuitos(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 8, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
inline int fsitos(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 8, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
inline int ftouis(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
inline int ftouizs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
inline int ftosis(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
inline int ftosizs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
inline int fcpyd(int Dd, int Dm) { return COOP(AL, 0xb, 0, Dd, 11, 2, Dm); }
inline int fabsd(int Dd, int Dm) { return COOP(AL, 0xb, 0, Dd, 11, 6, Dm); }
@ -179,24 +134,10 @@ inline int fnegd(int Dd, int Dm) { return COOP(AL, 0xb, 1, Dd, 11, 2, Dm); }
inline int fsqrtd(int Dd, int Dm) { return COOP(AL, 0xb, 1, Dd, 11, 6, Dm); }
// double-precision comparison instructions
inline int fcmpd(int Dd, int Dm) { return COOP(AL, 0xb, 4, Dd, 11, 2, Dm); }
inline int fcmped(int Dd, int Dm) { return COOP(AL, 0xb, 4, Dd, 11, 6, Dm); }
inline int fcmpzd(int Dd) { return COOP(AL, 0xb, 5, Dd, 11, 2, 0); }
inline int fcmpezd(int Dd) { return COOP(AL, 0xb, 5, Dd, 11, 6, 0); }
// double-precision conversion instructions
inline int fcvtsd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 7, Sd>>1, 11, 6, Dm); }
inline int fuitod(int Dd, int Sm) { return COOP(AL, 0xb, 8, Dd, 11, 2|(Sm&1), Sm>>1); }
inline int fsitod(int Dd, int Sm) { return COOP(AL, 0xb, 8, Dd, 11, 6|(Sm&1), Sm>>1); }
inline int ftouid(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 11, 2, Dm); }
inline int ftouizd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 11, 6, Dm); }
inline int ftosid(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 11, 2, Dm); }
inline int ftosizd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 11, 6, Dm); }
// these are the multiple load/store analogs for VFP, useless for now
inline int fldms(int Rn, int Sd, int count) { return COXFER(AL, 0, 1, Sd&1, 0, 1, Rn, Sd>>1, 10, count); }
inline int fldmd(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 1, Rn, Dd, 11, count<<1); }
inline int fldmx(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 1, Rn, Dd, 11, count<<1|1); }
inline int fstms(int Rn, int Sd, int count) { return COXFER(AL, 0, 1, Sd&1, 0, 0, Rn, Sd>>1, 10, count); }
inline int fstmd(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 0, Rn, Dd, 11, count<<1); }
inline int fstmx(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 0, Rn, Dd, 11, count<<1|1); }
// single load/store instructions for both precision types
inline int flds(int Sd, int Rn, int offset=0) { return COXFER(AL, 1, 1, Sd&1, 0, 1, Rn, Sd>>1, 10, offset); };
inline int fldd(int Dd, int Rn, int offset=0) { return COXFER(AL, 1, 1, 0, 0, 1, Rn, Dd, 11, offset); };
@ -205,32 +146,21 @@ inline int fstd(int Dd, int Rn, int offset=0) { return COXFER(AL, 1, 1, 0, 0, 0,
// move between GPRs and FPRs
inline int fmsr(int Sn, int Rd) { return mcr(10, 0, Rd, Sn>>1, 0, (Sn&1)<<2); }
inline int fmrs(int Rd, int Sn) { return mrc(10, 0, Rd, Sn>>1, 0, (Sn&1)<<2); }
/* move to/from the low/high parts of double-precision registers,
seemingly redundant */
inline int fmdlr(int Dn, int Rd) { return mcr(11, 0, Rd, Dn, 0); }
inline int fmrdl(int Rd, int Dn) { return mrc(11, 0, Rd, Dn, 0); }
inline int fmdhr(int Dn, int Rd) { return mcr(11, 1, Rd, Dn, 0); }
inline int fmrdh(int Rd, int Dn) { return mrc(11, 1, Rd, Dn, 0); }
// move to/from VFP system registers
inline int fmxr(int reg, int Rd) { return mcr(10, 7, Rd, reg, 0); }
inline int fmrx(int Rd, int reg) { return mrc(10, 7, Rd, reg, 0); }
// these move around pairs of single-precision registers
inline int fmsrr(int Sm, int Rd, int Rn) { return mcrr(10, 1 | ((Sm&1)<<1), Rd, Rn, Sm>>1); }
inline int fmrrs(int Rd, int Rn, int Sm) { return mrrc(10, 1 | ((Sm&1)<<1), Rd, Rn, Sm>>1); }
inline int fmdrr(int Dm, int Rd, int Rn) { return mcrr(11, 1, Rd, Rn, Dm); }
inline int fmrrd(int Rd, int Rn, int Dm) { return mrrc(11, 1, Rd, Rn, Dm); }
// FLAG SETTERS
inline int SETCOND(int ins, int cond) { return ((ins&0x0fffffff) | (cond<<28)); }
inline int SETS(int ins) { return ins | 1<<20; }
// PSEUDO-INSTRUCTIONS
inline int nop() { return mov(0, 0); }
inline int lsl(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, LSL); }
inline int lsli(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSL, imm); }
inline int lsr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, LSR); }
inline int lsri(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSR, imm); }
inline int asr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ASR); }
inline int asri(int Rd, int Rm, int imm) { return mov(Rd, Rm, ASR, imm); }
inline int ror(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ROR); }
inline int beq(int offset) { return SETCOND(b(offset), EQ); }
inline int bne(int offset) { return SETCOND(b(offset), NE); }
inline int bls(int offset) { return SETCOND(b(offset), LS); }
@ -245,35 +175,26 @@ inline int bpl(int offset) { return SETCOND(b(offset), PL); }
inline int fmstat() { return fmrx(15, FPSCR); }
// HARDWARE FLAGS
bool vfpSupported() {
return true; // TODO
// TODO: Use at runtime detection
#if defined(__ARM_PCS_VFP)
// armhf
return true;
#else
// armel
// TODO: allow VFP use for -mfloat-abi=softfp armel builds.
// GCC -mfloat-abi=softfp flag allows use of VFP while remaining compatible
// with soft-float code.
return false;
#endif
}
}
const uint64_t MASK_LO32 = 0xffffffff;
const unsigned MASK_LO16 = 0xffff;
const unsigned MASK_LO8 = 0xff;
inline unsigned lo32(int64_t i) { return (unsigned)(i&MASK_LO32); }
inline unsigned hi32(int64_t i) { return (unsigned)(i>>32); }
inline unsigned lo16(int64_t i) { return (unsigned)(i&MASK_LO16); }
inline unsigned hi16(int64_t i) { return lo16(i>>16); }
inline unsigned lo8(int64_t i) { return (unsigned)(i&MASK_LO8); }
inline unsigned hi8(int64_t i) { return lo8(i>>8); }
inline int ha16(int32_t i) {
return ((i >> 16) + ((i & 0x8000) ? 1 : 0)) & 0xffff;
}
inline int unha16(int32_t high, int32_t low) {
return ((high - ((low & 0x8000) ? 1 : 0)) << 16) | low;
}
inline bool isInt8(target_intptr_t v) { return v == static_cast<int8_t>(v); }
inline bool isInt16(target_intptr_t v) { return v == static_cast<int16_t>(v); }
inline bool isInt24(target_intptr_t v) { return v == (v & 0xffffff); }
inline bool isInt32(target_intptr_t v) { return v == static_cast<int32_t>(v); }
inline int carry16(target_intptr_t v) { return static_cast<int16_t>(v) < 0 ? 1 : 0; }
inline bool isOfWidth(int64_t i, int size) { return static_cast<uint64_t>(i) >> size == 0; }
inline bool isOfWidth(int i, int size) { return static_cast<unsigned>(i) >> size == 0; }
const int N_GPRS = 16;
const int N_FPRS = 16;
@ -567,7 +488,7 @@ isBranch(TernaryOperation op)
return op > FloatMin;
}
bool
bool UNUSED
isFloatBranch(TernaryOperation op)
{
return op > JumpIfNotEqual;
@ -634,72 +555,118 @@ write4(uint8_t* dst, uint32_t v)
memcpy(dst, &v, 4);
}
void
andC(Context* con, unsigned size, Assembler::Constant* a,
Assembler::Register* b, Assembler::Register* dst);
void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t)
{
if (size == 8) {
int tmp1 = newTemp(con), tmp2 = newTemp(con);
emit(con, lsl(tmp1, b->high, a->low));
emit(con, rsbi(tmp2, a->low, 32));
int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con);
ResolvedPromise maskPromise(0x3F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmp3);
andC(con, 4, &mask, a, &dst);
emit(con, lsl(tmp1, b->high, tmp3));
emit(con, rsbi(tmp2, tmp3, 32));
emit(con, orrsh(tmp1, tmp1, b->low, tmp2, LSR));
emit(con, SETS(subi(t->high, a->low, 32)));
emit(con, SETS(subi(t->high, tmp3, 32)));
emit(con, SETCOND(mov(t->high, tmp1), MI));
emit(con, SETCOND(lsl(t->high, b->low, t->high), PL));
emit(con, lsl(t->low, b->low, a->low));
freeTemp(con, tmp1); freeTemp(con, tmp2);
emit(con, lsl(t->low, b->low, tmp3));
freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3);
} else {
emit(con, lsl(t->low, b->low, a->low));
int tmp = newTemp(con);
ResolvedPromise maskPromise(0x1F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmp);
andC(con, size, &mask, a, &dst);
emit(con, lsl(t->low, b->low, tmp));
freeTemp(con, tmp);
}
}
void
moveRR(Context* con, unsigned srcSize, Assembler::Register* src,
unsigned dstSize, Assembler::Register* dst);
void shiftLeftC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
{
assert(con, size == TargetBytesPerWord);
emit(con, lsli(t->low, b->low, getValue(a)));
if (getValue(a) & 0x1F) {
emit(con, lsli(t->low, b->low, getValue(a) & 0x1F));
} else {
moveRR(con, size, b, size, t);
}
}
void shiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t)
{
if (size == 8) {
int tmp1 = newTemp(con), tmp2 = newTemp(con);
emit(con, lsr(tmp1, b->low, a->low));
emit(con, rsbi(tmp2, a->low, 32));
int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con);
ResolvedPromise maskPromise(0x3F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmp3);
andC(con, 4, &mask, a, &dst);
emit(con, lsr(tmp1, b->low, tmp3));
emit(con, rsbi(tmp2, tmp3, 32));
emit(con, orrsh(tmp1, tmp1, b->high, tmp2, LSL));
emit(con, SETS(subi(t->low, a->low, 32)));
emit(con, SETS(subi(t->low, tmp3, 32)));
emit(con, SETCOND(mov(t->low, tmp1), MI));
emit(con, SETCOND(asr(t->low, b->high, t->low), PL));
emit(con, asr(t->high, b->high, a->low));
freeTemp(con, tmp1); freeTemp(con, tmp2);
emit(con, asr(t->high, b->high, tmp3));
freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3);
} else {
emit(con, asr(t->low, b->low, a->low));
int tmp = newTemp(con);
ResolvedPromise maskPromise(0x1F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmp);
andC(con, size, &mask, a, &dst);
emit(con, asr(t->low, b->low, tmp));
freeTemp(con, tmp);
}
}
void shiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
{
assert(con, size == TargetBytesPerWord);
emit(con, asri(t->low, b->low, getValue(a)));
if (getValue(a) & 0x1F) {
emit(con, asri(t->low, b->low, getValue(a) & 0x1F));
} else {
moveRR(con, size, b, size, t);
}
}
void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t)
{
emit(con, lsr(t->low, b->low, a->low));
int tmpShift = newTemp(con);
ResolvedPromise maskPromise(size == 8 ? 0x3F : 0x1F);
Assembler::Constant mask(&maskPromise);
Assembler::Register dst(tmpShift);
andC(con, 4, &mask, a, &dst);
emit(con, lsr(t->low, b->low, tmpShift));
if (size == 8) {
int tmpHi = newTemp(con), tmpLo = newTemp(con);
emit(con, SETS(rsbi(tmpHi, a->low, 32)));
emit(con, SETS(rsbi(tmpHi, tmpShift, 32)));
emit(con, lsl(tmpLo, b->high, tmpHi));
emit(con, orr(t->low, t->low, tmpLo));
emit(con, addi(tmpHi, a->low, -32));
emit(con, addi(tmpHi, tmpShift, -32));
emit(con, lsr(tmpLo, b->high, tmpHi));
emit(con, orr(t->low, t->low, tmpLo));
emit(con, lsr(t->high, b->high, a->low));
emit(con, lsr(t->high, b->high, tmpShift));
freeTemp(con, tmpHi); freeTemp(con, tmpLo);
}
freeTemp(con, tmpShift);
}
void unsignedShiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
{
assert(con, size == TargetBytesPerWord);
emit(con, lsri(t->low, b->low, getValue(a)));
if (getValue(a) & 0x1F) {
emit(con, lsri(t->low, b->low, getValue(a) & 0x1F));
} else {
moveRR(con, size, b, size, t);
}
}
class ConstantPoolEntry: public Promise {
@ -909,10 +876,6 @@ jumpR(Context* con, unsigned size UNUSED, Assembler::Register* target)
emit(con, bx(target->low));
}
void
moveRR(Context* con, unsigned srcSize, Assembler::Register* src,
unsigned dstSize, Assembler::Register* dst);
void
swapRR(Context* con, unsigned aSize, Assembler::Register* a,
unsigned bSize, Assembler::Register* b)
@ -1355,23 +1318,6 @@ moveRM(Context* con, unsigned srcSize, Assembler::Register* src,
store(con, srcSize, src, dst->base, dst->offset, dst->index, dst->scale, true);
}
void
moveAndUpdateRM(Context* con, unsigned srcSize UNUSED, Assembler::Register* src,
unsigned dstSize UNUSED, Assembler::Memory* dst)
{
assert(con, srcSize == TargetBytesPerWord);
assert(con, dstSize == TargetBytesPerWord);
if (dst->index == NoRegister) {
emit(con, stri(src->low, dst->base, dst->offset, dst->offset ? 1 : 0));
} else {
assert(con, dst->offset == 0);
assert(con, dst->scale == 1);
emit(con, str(src->low, dst->base, dst->index, 1));
}
}
void
load(Context* con, unsigned srcSize, int base, int offset, int index,
unsigned scale, unsigned dstSize, Assembler::Register* dst,
@ -2354,7 +2300,7 @@ class MyArchitecture: public Assembler::Architecture {
{
*thunk = false;
*aTypeMask = ~0;
*aRegisterMask = ~static_cast<uint64_t>(0);
*aRegisterMask = GPR_MASK64;
switch (op) {
case Negate:
@ -2379,7 +2325,11 @@ class MyArchitecture: public Assembler::Architecture {
break;
case Float2Int:
if (vfpSupported() && bSize == 4) {
// todo: Java requires different semantics than SSE for
// converting floats to integers, we we need to either use
// thunks or produce inline machine code which handles edge
// cases properly.
if (false && vfpSupported() && bSize == 4) {
*aTypeMask = (1 << RegisterOperand);
*aRegisterMask = FPR_MASK64;
} else {
@ -2407,7 +2357,7 @@ class MyArchitecture: public Assembler::Architecture {
unsigned , uint8_t* bTypeMask, uint64_t* bRegisterMask)
{
*bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
*bRegisterMask = ~static_cast<uint64_t>(0);
*bRegisterMask = GPR_MASK64;
switch (op) {
case Negate:
@ -2538,7 +2488,7 @@ class MyArchitecture: public Assembler::Architecture {
virtual void planDestination
(TernaryOperation op,
unsigned, uint8_t, uint64_t,
unsigned, uint8_t, const uint64_t,
unsigned, uint8_t, const uint64_t bRegisterMask,
unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask)
{
if (isBranch(op)) {
@ -2546,7 +2496,7 @@ class MyArchitecture: public Assembler::Architecture {
*cRegisterMask = 0;
} else {
*cTypeMask = (1 << RegisterOperand);
*cRegisterMask = ~static_cast<uint64_t>(0);
*cRegisterMask = bRegisterMask;
}
}

View File

@ -44,7 +44,15 @@
THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss))
# define LINK_REGISTER(context) \
THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss))
#else // not __APPLE__
#elif (defined __QNX__)
# include "arm/smpxchg.h"
# include "sys/mman.h"
# define IP_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_PC])
# define STACK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_SP])
# define THREAD_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_IP])
# define LINK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_LR])
#else
# define IP_REGISTER(context) (context->uc_mcontext.arm_pc)
# define STACK_REGISTER(context) (context->uc_mcontext.arm_sp)
# define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip)
@ -55,7 +63,8 @@
extern "C" uint64_t
vmNativeCall(void* function, unsigned stackTotal, void* memoryTable,
unsigned memoryCount, void* gprTable);
unsigned memoryCount, void* gprTable, void* vfpTable,
unsigned returnType);
namespace vm {
@ -94,6 +103,8 @@ syncInstructionCache(const void* start, unsigned size)
{
#ifdef __APPLE__
sys_icache_invalidate(const_cast<void*>(start), size);
#elif (defined __QNX__)
msync(const_cast<void*>(start), size, MS_INVALIDATE_ICACHE);
#else
__clear_cache
(const_cast<void*>(start),
@ -111,6 +122,8 @@ atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_)
{
#ifdef __APPLE__
return OSAtomicCompareAndSwap32(old, new_, reinterpret_cast<int32_t*>(p));
#elif (defined __QNX__)
return old == _smp_cmpxchg(p, old, new_);
#else
int r = __kernel_cmpxchg(static_cast<int>(old), static_cast<int>(new_), reinterpret_cast<int*>(p));
return (!r ? true : false);
@ -126,7 +139,7 @@ atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
inline uint64_t
dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
unsigned argumentCount, unsigned argumentsSize UNUSED,
unsigned returnType UNUSED)
unsigned returnType)
{
#ifdef __APPLE__
const unsigned Alignment = 1;
@ -138,6 +151,11 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
uintptr_t gprTable[GprCount];
unsigned gprIndex = 0;
const unsigned VfpCount = 16;
uintptr_t vfpTable[VfpCount];
unsigned vfpIndex = 0;
unsigned vfpBackfillIndex UNUSED = 0;
uintptr_t stack[(argumentCount * 8) / BytesPerWord]; // is > argumentSize to account for padding
unsigned stackIndex = 0;
@ -145,6 +163,40 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
for (unsigned ati = 0; ati < argumentCount; ++ ati) {
switch (argumentTypes[ati]) {
case DOUBLE_TYPE:
#if defined(__ARM_PCS_VFP)
{
if (vfpIndex + Alignment <= VfpCount) {
if (vfpIndex % Alignment) {
vfpBackfillIndex = vfpIndex;
++ vfpIndex;
}
memcpy(vfpTable + vfpIndex, arguments + ai, 8);
vfpIndex += 8 / BytesPerWord;
} else {
vfpIndex = VfpCount;
if (stackIndex % Alignment) {
++ stackIndex;
}
memcpy(stack + stackIndex, arguments + ai, 8);
stackIndex += 8 / BytesPerWord;
}
ai += 8 / BytesPerWord;
} break;
case FLOAT_TYPE:
if (vfpBackfillIndex) {
vfpTable[vfpBackfillIndex] = arguments[ai];
vfpBackfillIndex = 0;
} else if (vfpIndex < VfpCount) {
vfpTable[vfpIndex++] = arguments[ai];
} else {
stack[stackIndex++] = arguments[ai];
}
++ ai;
break;
#endif
case INT64_TYPE: {
if (gprIndex + Alignment <= GprCount) { // pass argument in register(s)
if (Alignment == 1
@ -188,11 +240,16 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
memset(gprTable + gprIndex, 0, (GprCount-gprIndex)*4);
gprIndex = GprCount;
}
if (vfpIndex < VfpCount) {
memset(vfpTable + vfpIndex, 0, (VfpCount-vfpIndex)*4);
vfpIndex = VfpCount;
}
unsigned stackSize = stackIndex*BytesPerWord + ((stackIndex & 1) << 2);
return vmNativeCall
(function, stackSize, stack, stackIndex * BytesPerWord,
(gprIndex ? gprTable : 0));
(gprIndex ? gprTable : 0),
(vfpIndex ? vfpTable : 0), returnType);
}
} // namespace vm

View File

@ -198,7 +198,7 @@ public:
const unsigned machine;
ElfPlatform(PlatformInfo::Architecture arch):
Platform(PlatformInfo(PlatformInfo::Linux, arch)),
Platform(PlatformInfo(PlatformInfo::Elf, arch)),
machine(getElfPlatform(arch)) {}
class FileWriter {
@ -372,10 +372,9 @@ public:
}
};
ElfPlatform<uint32_t> elfx86Platform(PlatformInfo::x86);
ElfPlatform<uint32_t> elfX86Platform(PlatformInfo::x86);
ElfPlatform<uint32_t> elfArmPlatform(PlatformInfo::Arm);
ElfPlatform<uint32_t, false> elfPowerPCPlatform(PlatformInfo::PowerPC);
ElfPlatform<uint64_t> elfx86_64Platform(PlatformInfo::x86_64);
ElfPlatform<uint64_t> elfX86_64Platform(PlatformInfo::x86_64);
} // namespace

View File

@ -286,7 +286,7 @@ public:
}
MachOPlatform(PlatformInfo::Architecture arch):
Platform(PlatformInfo(PlatformInfo::Darwin, arch)) {}
Platform(PlatformInfo(PlatformInfo::MachO, arch)) {}
};

View File

@ -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;
}

View File

@ -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;

View File

@ -85,15 +85,23 @@ void FileOutputStream::write(uint8_t byte) {
Platform* Platform::first = 0;
PlatformInfo::OperatingSystem PlatformInfo::osFromString(const char* os) {
if(strcmp(os, "linux") == 0) {
return Linux;
} else if(strcmp(os, "windows") == 0) {
return Windows;
} else if(strcmp(os, "darwin") == 0) {
return Darwin;
PlatformInfo::Format PlatformInfo::formatFromString(const char* format) {
if (strcmp(format, "elf") == 0
or strcmp(format, "linux") == 0
or strcmp(format, "freebsd") == 0
or strcmp(format, "qnx") == 0)
{
return Elf;
} else if (strcmp(format, "pe") == 0
or strcmp(format, "windows") == 0)
{
return Pe;
} else if (strcmp(format, "macho") == 0
or strcmp(format, "darwin") == 0)
{
return MachO;
} else {
return UnknownOS;
return UnknownFormat;
}
}
@ -122,4 +130,5 @@ Platform* Platform::getPlatform(PlatformInfo info) {
} // namespace tools
} // namespace avian
} // namespace avian

View File

@ -131,11 +131,11 @@ public:
class PlatformInfo {
public:
enum OperatingSystem {
Linux = AVIAN_PLATFORM_LINUX,
Windows = AVIAN_PLATFORM_WINDOWS,
Darwin = AVIAN_PLATFORM_DARWIN,
UnknownOS = AVIAN_PLATFORM_UNKNOWN
enum Format {
Elf = AVIAN_FORMAT_ELF,
Pe = AVIAN_FORMAT_PE,
MachO = AVIAN_FORMAT_MACHO,
UnknownFormat = AVIAN_FORMAT_UNKNOWN
};
enum Architecture {
@ -146,18 +146,18 @@ public:
UnknownArch = AVIAN_ARCH_UNKNOWN
};
const OperatingSystem os;
const Format format;
const Architecture arch;
static OperatingSystem osFromString(const char* os);
static Format formatFromString(const char* format);
static Architecture archFromString(const char* arch);
inline PlatformInfo(OperatingSystem os, Architecture arch):
os(os),
inline PlatformInfo(Format format, Architecture arch):
format(format),
arch(arch) {}
inline bool operator == (const PlatformInfo& other) {
return os == other.os && arch == other.arch;
return format == other.format && arch == other.arch;
}
inline bool isLittleEndian() {
@ -193,4 +193,5 @@ public:
} // namespace avian
#endif
#endif

View File

@ -34,7 +34,7 @@ const unsigned TargetFixieSizeInBytes = 8 + (TargetBytesPerWord * 2);
const unsigned TargetFixieSizeInWords = ceiling
(TargetFixieSizeInBytes, TargetBytesPerWord);
const unsigned TargetFixieAge = 0;
const unsigned TargetFixieHasMask = 1;
const unsigned TargetFixieFlags = 2;
const unsigned TargetFixieSize = 4;
const bool DebugNativeTarget = false;
@ -310,7 +310,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
if (endsWith(".class", name, nameSize)
and (className == 0 or strncmp(name, className, nameSize - 6) == 0))
{
// fprintf(stderr, "%.*s\n", nameSize - 6, name);
// fprintf(stderr, "pass 1 %.*s\n", nameSize - 6, name);
object c = resolveSystemClass
(t, root(t, Machine::BootLoader),
makeByteArray(t, "%.*s", nameSize - 6, name), true);
@ -412,8 +412,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
objectHash);
}
}
// if (strcmp(name, "java/lang/System$Property.class") == 0) trap();
{ object array = 0;
PROTECT(t, array);
@ -441,11 +439,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
memberFields[memberIndex] = *f;
while (targetMemberOffset % f->targetSize) {
++ targetMemberOffset;
}
targetMemberOffset += f->targetSize;
targetMemberOffset = f->targetOffset + f->targetSize;
++ memberIndex;
}
@ -458,7 +452,9 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
targetMemberOffset = TargetBytesPerWord;
}
Field staticFields[count + 2];
const unsigned StaticHeader = 3;
Field staticFields[count + StaticHeader];
init(new (staticFields) Field, Type_object, 0, BytesPerWord, 0,
TargetBytesPerWord);
@ -466,9 +462,12 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
init(new (staticFields + 1) Field, Type_intptr_t, BytesPerWord,
BytesPerWord, TargetBytesPerWord, TargetBytesPerWord);
unsigned staticIndex = 2;
unsigned buildStaticOffset = BytesPerWord * 2;
unsigned targetStaticOffset = TargetBytesPerWord * 2;
init(new (staticFields + 2) Field, Type_object, BytesPerWord * 2,
BytesPerWord, TargetBytesPerWord * 2, TargetBytesPerWord);
unsigned staticIndex = StaticHeader;
unsigned buildStaticOffset = BytesPerWord * StaticHeader;
unsigned targetStaticOffset = TargetBytesPerWord * StaticHeader;
for (unsigned i = 0; i < vectorSize(t, fields); ++i) {
object field = vectorBody(t, fields, i);
@ -539,9 +538,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
targetMemberOffset = pad(targetMemberOffset, TargetBytesPerWord);
}
}
// if (strcmp(name, "avian/VMClass.class") == 0) trap();
if (hashMapFind(t, typeMaps, c, objectHash, objectEqual) == 0) {
object array = makeByteArray
(t, TypeMap::sizeInBytes
@ -600,7 +597,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
if (endsWith(".class", name, nameSize)
and (className == 0 or strncmp(name, className, nameSize - 6) == 0))
{
// fprintf(stderr, "%.*s\n", nameSize - 6, name);
// fprintf(stderr, "pass 2 %.*s\n", nameSize - 6, name);
object c = resolveSystemClass
(t, root(t, Machine::BootLoader),
makeByteArray(t, "%.*s", nameSize - 6, name), true);
@ -1175,13 +1172,13 @@ makeHeapImage(Thread* t, BootImage* image, target_uintptr_t* heap,
memset(heap + position, 0, TargetFixieSizeInBytes);
uint8_t age = FixieTenureThreshold + 1;
uint16_t age = targetV2(FixieTenureThreshold + 1);
memcpy(reinterpret_cast<uint8_t*>(heap + position)
+ TargetFixieAge, &age, 1);
+ TargetFixieAge, &age, 2);
uint8_t hasMask = true;
uint16_t flags = targetV2(1);
memcpy(reinterpret_cast<uint8_t*>(heap + position)
+ TargetFixieHasMask, &hasMask, 1);
+ TargetFixieFlags, &flags, 2);
uint32_t targetSize = targetV4(size);
memcpy(reinterpret_cast<uint8_t*>(heap + position)
@ -1647,7 +1644,7 @@ writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutp
// fwrite(code, pad(image->codeSize, TargetBytesPerWord), 1, codeOutput);
Platform* platform = Platform::getPlatform(PlatformInfo((PlatformInfo::OperatingSystem)AVIAN_TARGET_PLATFORM, (PlatformInfo::Architecture)AVIAN_TARGET_ARCH));
Platform* platform = Platform::getPlatform(PlatformInfo((PlatformInfo::Format)AVIAN_TARGET_FORMAT, (PlatformInfo::Architecture)AVIAN_TARGET_ARCH));
// if(!platform) {
// fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture);

View File

@ -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<object>(*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<object>(*arguments);
@ -200,7 +200,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_resource_Handler_00024ResourceInputStream_available
Avian_avian_avianvmresource_Handler_00024ResourceInputStream_available
(Thread*, object, uintptr_t* arguments)
{
int64_t peer; memcpy(&peer, arguments, 8);
@ -211,7 +211,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_available
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_resource_Handler_00024ResourceInputStream_read__JI
Avian_avian_avianvmresource_Handler_00024ResourceInputStream_read__JI
(Thread*, object, uintptr_t* arguments)
{
int64_t peer; memcpy(&peer, arguments, 8);
@ -226,7 +226,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_read__JI
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_resource_Handler_00024ResourceInputStream_read__JI_3BII
Avian_avian_avianvmresource_Handler_00024ResourceInputStream_read__JI_3BII
(Thread* t, object, uintptr_t* arguments)
{
int64_t peer; memcpy(&peer, arguments, 8);
@ -251,7 +251,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_read__JI_3BII
}
extern "C" JNIEXPORT void JNICALL
Avian_avian_resource_Handler_00024ResourceInputStream_close
Avian_avian_avianvmresource_Handler_00024ResourceInputStream_close
(Thread*, object, uintptr_t* arguments)
{
int64_t peer; memcpy(&peer, arguments, 8);
@ -511,3 +511,55 @@ Avian_sun_misc_Unsafe_getAddress__J
return *reinterpret_cast<intptr_t*>(p);
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_copyMemory
(Thread* t, object, uintptr_t* arguments)
{
object srcBase = reinterpret_cast<object>(arguments[1]);
int64_t srcOffset; memcpy(&srcOffset, arguments + 2, 8);
object dstBase = reinterpret_cast<object>(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<uint8_t>(srcBase, srcOffset)
: reinterpret_cast<uint8_t*>(srcOffset);
void* dst = dstBase
? &cast<uint8_t>(dstBase, dstOffset)
: reinterpret_cast<uint8_t*>(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<object>(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<intptr_t>(array) + ArrayBody;
return reinterpret_cast<intptr_t>(array);
}

View File

@ -88,6 +88,12 @@ class MyClasspath : public Classpath {
return AVIAN_CLASSPATH;
}
virtual void
updatePackageMap(Thread*, object)
{
// ignore
}
virtual void
dispose()
{

View File

@ -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<char*>(&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);

View File

@ -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<char*>(allocator->allocate(bufferSize))),
offset(0)
{ }
void ensure(unsigned capacity) {
if (capacity > bufferSize) {
unsigned size = max(bufferSize * 2, capacity);
char* b = static_cast<char*>(allocator->allocate(size));
if (offset) {
memcpy(b, buffer, offset);
}
allocator->free(buffer, bufferSize);
buffer = b;
bufferSize = size;
}
}
void append(const char* append) {
unsigned length = strlen(append);
expect(s, remaining > length);
ensure(offset + length + 1);
strncpy(pointer, append, remaining);
strncpy(buffer + offset, append, length + 1);
remaining -= length;
pointer += length;
offset += length;
}
void append(char c) {
assert(s, remaining > 1);
ensure(2);
pointer[0] = c;
pointer[1] = 0;
buffer[offset] = c;
buffer[offset + 1] = 0;
-- remaining;
++ pointer;
++ offset;
}
System* s;
char* pointer;
unsigned remaining;
} sb(s, buffer, BufferSize);
Allocator* allocator;
unsigned bufferSize;
char* buffer;
unsigned offset;
} sb(s, allocator);
this->javaHome = sb.pointer;
unsigned javaHomeOffset = sb.offset;
sb.append(javaHome);
sb.append('\0');
this->classpath = sb.pointer;
unsigned classpathOffset = sb.offset;
sb.append(AVIAN_CLASSPATH);
sb.append(s->pathSeparator());
sb.append(javaHome);
@ -409,7 +427,7 @@ class MyClasspath : public Classpath {
sb.append("/lib/resources.jar");
sb.append('\0');
this->libraryPath = sb.pointer;
unsigned libraryPathOffset = sb.offset;
sb.append(javaHome);
#ifdef PLATFORM_WINDOWS
sb.append("/bin");
@ -417,21 +435,31 @@ class MyClasspath : public Classpath {
sb.append("/lib");
#elif defined ARCH_x86_64
sb.append("/lib/amd64");
#elif defined ARCH_arm
sb.append("/lib/arm");
#else
// todo: handle other architectures
sb.append("/lib/i386");
#endif
sb.append('\0');
this->tzMappings = sb.pointer;
unsigned tzMappingsOffset = sb.offset;
sb.append(javaHome);
sb.append("/lib/tzmappings");
this->tzMappingsLength = sb.pointer - tzMappings;
this->tzMappingsLength = sb.offset - tzMappingsOffset;
sb.append('\0');
this->embedPrefix = sb.pointer;
unsigned embedPrefixOffset = sb.offset;
sb.append(embedPrefix);
this->embedPrefixLength = sb.pointer - this->embedPrefix;
this->embedPrefixLength = sb.offset - embedPrefixOffset;
this->javaHome = sb.buffer + javaHomeOffset;
this->classpath = sb.buffer + classpathOffset;
this->libraryPath = sb.buffer + libraryPathOffset;
this->tzMappings = sb.buffer + tzMappingsOffset;
this->embedPrefix = sb.buffer + embedPrefixOffset;
this->buffer = sb.buffer;
this->bufferSize = sb.bufferSize;
}
virtual object
@ -532,7 +560,7 @@ class MyClasspath : public Classpath {
virtual void
resolveNative(Thread* t, object method)
{
if (strcmp(reinterpret_cast<const int8_t*>("sun/font/FontManager"),
if (strcmp(reinterpret_cast<const int8_t*>("sun/font/SunFontManager"),
&byteArrayBody(t, className(t, methodClass(t, method)), 0)) == 0
and strcmp(reinterpret_cast<const int8_t*>("initIDs"),
&byteArrayBody(t, methodName(t, method), 0)) == 0
@ -621,6 +649,13 @@ class MyClasspath : public Classpath {
t->m->processor->invoke
(t, root(t, Machine::BootLoader), "java/lang/System",
"initializeSystemClass", "()V", 0);
t->m->processor->invoke
(t, root(t, Machine::BootLoader), "sun/misc/Launcher",
"getLauncher", "()Lsun/misc/Launcher;", 0);
set(t, t->javaThread, ThreadContextClassLoader,
root(t, Machine::AppLoader));
}
virtual const char*
@ -629,9 +664,51 @@ class MyClasspath : public Classpath {
return classpath;
}
virtual void
updatePackageMap(Thread* t, object class_)
{
PROTECT(t, class_);
if (root(t, Machine::PackageMap) == 0) {
setRoot(t, Machine::PackageMap, makeHashMap(t, 0, 0));
}
object className = vm::className(t, class_);
if ('[' != byteArrayBody(t, className, 0)) {
THREAD_RUNTIME_ARRAY
(t, char, packageName, byteArrayLength(t, className));
char* s = reinterpret_cast<char*>(&byteArrayBody(t, className, 0));
char* p = strrchr(s, '/');
if (p) {
int length = (p - s) + 1;
memcpy(RUNTIME_ARRAY_BODY(packageName),
&byteArrayBody(t, className, 0),
length);
RUNTIME_ARRAY_BODY(packageName)[length] = 0;
object key = vm::makeByteArray(t, "%s", packageName);
hashMapRemove
(t, root(t, Machine::PackageMap), key, byteArrayHash,
byteArrayEqual);
object source = classSource(t, class_);
if (source == 0) {
source = vm::makeByteArray(t, "avian-dummy-package-source");
}
hashMapInsert
(t, root(t, Machine::PackageMap), key, source, byteArrayHash);
}
}
}
virtual void
dispose()
{
allocator->free(buffer, bufferSize);
allocator->free(this, sizeof(*this));
}
@ -641,6 +718,8 @@ class MyClasspath : public Classpath {
const char* libraryPath;
const char* tzMappings;
const char* embedPrefix;
char* buffer;
unsigned bufferSize;
unsigned tzMappingsLength;
unsigned embedPrefixLength;
unsigned filePathField;
@ -655,7 +734,6 @@ class MyClasspath : public Classpath {
unsigned zipEntryMethodField;
bool ranNetOnLoad;
bool ranManagementOnLoad;
char buffer[BufferSize];
JmmInterface jmmInterface;
};
@ -2283,11 +2361,28 @@ fieldForOffsetInClass(Thread* t, object c, unsigned offset)
object
fieldForOffset(Thread* t, object o, unsigned offset)
{
object field = fieldForOffsetInClass(t, objectClass(t, o), offset);
if (field) {
return field;
} else {
object c = objectClass(t, o);
if (classVmFlags(t, c) & SingletonFlag) {
c = singletonObject(t, o, 0);
object table = classFieldTable(t, c);
if (table) {
for (unsigned i = 0; i < objectArrayLength(t, table); ++i) {
object field = objectArrayBody(t, table, i);
if ((fieldFlags(t, field) & ACC_STATIC)
and fieldOffset(t, field) == offset)
{
return field;
}
}
}
abort(t);
} else {
object field = fieldForOffsetInClass(t, c, offset);
if (field) {
return field;
} else {
abort(t);
}
}
}
@ -2311,10 +2406,13 @@ extern "C" JNIEXPORT int64_t JNICALL
Avian_java_lang_Class_getSuperclass
(Thread* t, object, uintptr_t* arguments)
{
object super = classSuper
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[0])));
return super ? reinterpret_cast<int64_t>(getJClass(t, super)) : 0;
object class_ = jclassVmClass(t, reinterpret_cast<object>(arguments[0]));
if (classFlags(t, class_) & ACC_INTERFACE) {
return 0;
} else {
object super = classSuper(t, class_);
return super ? reinterpret_cast<int64_t>(getJClass(t, super)) : 0;
}
}
extern "C" JNIEXPORT void
@ -2394,13 +2492,6 @@ Avian_sun_misc_Unsafe_staticFieldOffset
(t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield)));
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_arrayBaseOffset
(Thread*, object, uintptr_t*)
{
return BytesPerWord * 2;
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_arrayIndexScale
(Thread* t, object, uintptr_t* arguments)
@ -2520,6 +2611,14 @@ Avian_sun_misc_Unsafe_getLong__Ljava_lang_Object_2J
return cast<int64_t>(o, offset);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getDouble__Ljava_lang_Object_2J
(Thread* t, object method, uintptr_t* arguments)
{
return Avian_sun_misc_Unsafe_getLong__Ljava_lang_Object_2J
(t, method, arguments);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getLongVolatile
(Thread* t, object, uintptr_t* arguments)
@ -2782,32 +2881,6 @@ Avian_sun_misc_Unsafe_park
monitorRelease(t, local::interruptLock(t, t->javaThread));
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_copyMemory
(Thread* t, object, uintptr_t* arguments)
{
object srcBase = reinterpret_cast<object>(arguments[1]);
int64_t srcOffset; memcpy(&srcOffset, arguments + 2, 8);
object dstBase = reinterpret_cast<object>(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<uint8_t>(srcBase, srcOffset)
: reinterpret_cast<uint8_t*>(srcOffset);
void* dst = dstBase
? &cast<uint8_t>(dstBase, dstOffset)
: reinterpret_cast<uint8_t*>(dstOffset);
memcpy(dst, src, count);
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_monitorEnter
(Thread* t, object, uintptr_t* arguments)
@ -3002,6 +3075,8 @@ jvmInitProperties(Thread* t, uintptr_t* arguments)
local::setProperty(t, method, *properties, "path.separator", ":");
# ifdef __APPLE__
local::setProperty(t, method, *properties, "os.name", "Mac OS X");
# elif defined __FreeBSD__
local::setProperty(t, method, *properties, "os.name", "FreeBSD");
# else // not __APPLE__
local::setProperty(t, method, *properties, "os.name", "Linux");
# endif // not __APPLE__
@ -3019,6 +3094,14 @@ jvmInitProperties(Thread* t, uintptr_t* arguments)
local::setProperty(t, method, *properties, "java.vm.vendor",
"Avian Contributors");
local::setProperty(t, method, *properties, "java.vm.name","Avian");
#ifdef AVIAN_VERSION
local::setProperty(t, method, *properties, "java.vm.version",AVIAN_VERSION);
#endif
#ifdef AVIAN_INFO
local::setProperty(t, method, *properties, "java.vm.info",AVIAN_INFO);
#endif
local::setProperty
(t, method, *properties, "java.home",
static_cast<local::MyClasspath*>(t->m->classpath)->javaHome);
@ -3128,7 +3211,7 @@ EXPORT(JVM_FreeMemory)()
extern "C" JNIEXPORT jlong JNICALL
EXPORT(JVM_MaxMemory)()
{
return 0;
return local::globalMachine->heap->limit();
}
extern "C" JNIEXPORT jint JNICALL
@ -3328,6 +3411,10 @@ jvmSleep(Thread* t, uintptr_t* arguments)
{
jlong milliseconds; memcpy(&milliseconds, arguments, sizeof(jlong));
if (milliseconds <= 0) {
milliseconds = 1;
}
if (threadSleepLock(t, t->javaThread) == 0) {
object lock = makeJobject(t);
set(t, t->javaThread, ThreadSleepLock, lock);
@ -3516,10 +3603,37 @@ EXPORT(JVM_ClassDepth)(Thread*, jstring) { abort(); }
extern "C" JNIEXPORT jint JNICALL
EXPORT(JVM_ClassLoaderDepth)(Thread*) { abort(); }
extern "C" JNIEXPORT jstring JNICALL
EXPORT(JVM_GetSystemPackage)(Thread*, jstring)
uint64_t
jvmGetSystemPackage(Thread* t, uintptr_t* arguments)
{
return 0;
jstring s = reinterpret_cast<jstring>(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<uintptr_t>
(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<uintptr_t>(s) };
return reinterpret_cast<jstring>(run(t, jvmGetSystemPackage, arguments));
}
uint64_t
@ -3787,7 +3901,7 @@ EXPORT(JVM_GetCallerClass)(Thread* t, int target)
{
ENTER(t, Thread::ActiveState);
object method = getCaller(t, target);
object method = getCaller(t, target, true);
return method ? makeLocalReference
(t, getJClass(t, methodClass(t, method))) : 0;
@ -4553,6 +4667,14 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments)
unsigned returnCode = methodReturnCode(t, vmMethod);
THREAD_RESOURCE0(t, {
if (t->exception) {
object exception = t->exception;
t->exception = makeThrowable
(t, Machine::InvocationTargetExceptionType, 0, 0, exception);
}
});
object result;
if (args) {
result = t->m->processor->invokeArray
@ -4591,6 +4713,14 @@ jvmNewInstanceFromConstructor(Thread* t, uintptr_t* arguments)
(t, jclassVmClass(t, jconstructorClazz(t, *constructor))),
jconstructorSlot(t, *constructor));
THREAD_RESOURCE0(t, {
if (t->exception) {
object exception = t->exception;
t->exception = makeThrowable
(t, Machine::InvocationTargetExceptionType, 0, 0, exception);
}
});
if (args) {
t->m->processor->invokeArray(t, method, instance, *args);
} else {
@ -4686,9 +4816,27 @@ extern "C" JNIEXPORT jfloat JNICALL
EXPORT(JVM_ConstantPoolGetFloatAt)(Thread*, jobject, jobject, jint)
{ abort(); }
uint64_t
jvmConstantPoolGetDoubleAt(Thread* t, uintptr_t* arguments)
{
jobject pool = reinterpret_cast<jobject>(arguments[0]);
jint index = arguments[1];
double v; memcpy(&v, &singletonValue(t, *pool, index - 1), 8);
return doubleToBits(v);
}
extern "C" JNIEXPORT jdouble JNICALL
EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread*, jobject, jobject, jint)
{ abort(); }
EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread* t, jobject, jobject pool,
jint index)
{
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(pool),
static_cast<uintptr_t>(index) };
return bitsToDouble
(run(t, jvmConstantPoolGetDoubleAt, arguments));
}
extern "C" JNIEXPORT jstring JNICALL
EXPORT(JVM_ConstantPoolGetStringAt)(Thread*, jobject, jobject, jint)

View File

@ -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 &&

View File

@ -75,7 +75,12 @@ LOCAL(vmInvoke_argumentTest):
mov r8, r0
// load and call function address
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
mov lr, pc
bx r1
#else
blx r1
#endif
.globl GLOBAL(vmInvoke_returnAddress)
.align 2
@ -123,11 +128,18 @@ LOCAL(vmInvoke_continuationTest):
ble LOCAL(vmInvoke_continuationLoop)
ldr r7,[r5,#CONTINUATION_RETURN_ADDRESS_OFFSET]
#ifdef __APPLE__
movw r11, :lower16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmInvoke_getAddress)+8))
movt r11, :upper16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmInvoke_getAddress)+8))
LOCAL(vmInvoke_getAddress):
add r11, pc, r11
#else // not __APPLE__
ldr r10,LOCAL(vmInvoke_returnAddress_word)
ldr r11,LOCAL(vmInvoke_getAddress_word)
LOCAL(vmInvoke_getAddress):
add r11,pc,r11
ldr r11,[r11,r10]
#endif // not __APPLE__
str r11,[sp,r7]
ldr r7,[r5,#CONTINUATION_NEXT]
@ -210,23 +222,34 @@ LOCAL(vmJumpAndInvoke_argumentTest):
mov sp,r2
// set return address to vmInvoke_returnAddress
#ifdef __APPLE__
movw r11, :lower16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmJumpAndInvoke_getAddress)+8))
movt r11, :upper16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmJumpAndInvoke_getAddress)+8))
LOCAL(vmJumpAndInvoke_getAddress):
add r11, pc, r11
#else // not __APPLE__
ldr r10,LOCAL(vmInvoke_returnAddress_word)
ldr r11,LOCAL(vmJumpAndInvoke_getAddress_word)
LOCAL(vmJumpAndInvoke_getAddress):
add r11,pc,r11
#endif // not __APPLE__
ldr lr,[r11,r10]
bx r1
#ifndef __APPLE__
LOCAL(vmInvoke_returnAddress_word):
.word GLOBAL(vmInvoke_returnAddress)(GOT)
LOCAL(vmInvoke_getAddress_word):
.word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmInvoke_getAddress)+8)
LOCAL(vmJumpAndInvoke_getAddress_word):
.word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmJumpAndInvoke_getAddress)+8)
#endif // not __APPLE__
#else // not AVIAN_CONTINUATIONS
// vmJumpAndInvoke should only be called when continuations are
// enabled
bkpt
// enabled, so we force a crash if we reach here:
mov r1,#0
ldr r1,[r1]
#endif // not AVIAN_CONTINUATIONS

View File

@ -202,6 +202,17 @@ class MyThread: public Thread {
bool methodIsMostRecent;
};
class ReferenceFrame {
public:
ReferenceFrame(ReferenceFrame* next, Reference* reference):
next(next),
reference(reference)
{ }
ReferenceFrame* next;
Reference* reference;
};
static void doTransition(MyThread* t, void* ip, void* stack,
object continuation, MyThread::CallTrace* trace)
{
@ -255,6 +266,7 @@ class MyThread: public Thread {
transition(0),
traceContext(0),
stackLimit(0),
referenceFrame(0),
methodLockIsClean(true)
{
arch->acquire();
@ -280,6 +292,7 @@ class MyThread: public Thread {
Context* transition;
TraceContext* traceContext;
uintptr_t stackLimit;
ReferenceFrame* referenceFrame;
bool methodLockIsClean;
};
@ -1375,6 +1388,10 @@ class Frame {
}
~Frame() {
dispose();
}
void dispose() {
if (level > 1) {
context->eventLog.append(PopContextEvent);
}
@ -2574,13 +2591,25 @@ doubleToFloat(int64_t a)
int64_t
doubleToInt(int64_t a)
{
return static_cast<int32_t>(bitsToDouble(a));
double f = bitsToDouble(a);
switch (fpclassify(f)) {
case FP_NAN: return 0;
case FP_INFINITE: return signbit(f) ? INT32_MIN : INT32_MAX;
default: return f >= INT32_MAX ? INT32_MAX
: (f <= INT32_MIN ? INT32_MIN : static_cast<int32_t>(f));
}
}
int64_t
doubleToLong(int64_t a)
{
return static_cast<int64_t>(bitsToDouble(a));
double f = bitsToDouble(a);
switch (fpclassify(f)) {
case FP_NAN: return 0;
case FP_INFINITE: return signbit(f) ? INT64_MIN : INT64_MAX;
default: return f >= INT64_MAX ? INT64_MAX
: (f <= INT64_MIN ? INT64_MIN : static_cast<int64_t>(f));
}
}
uint64_t
@ -2722,13 +2751,24 @@ floatToDouble(int32_t a)
int64_t
floatToInt(int32_t a)
{
return static_cast<int32_t>(bitsToFloat(a));
float f = bitsToFloat(a);
switch (fpclassify(f)) {
case FP_NAN: return 0;
case FP_INFINITE: return signbit(f) ? INT32_MIN : INT32_MAX;
default: return f >= INT32_MAX ? INT32_MAX
: (f <= INT32_MIN ? INT32_MIN : static_cast<int32_t>(f));
}
}
int64_t
floatToLong(int32_t a)
{
return static_cast<int64_t>(bitsToFloat(a));
float f = bitsToFloat(a);
switch (fpclassify(f)) {
case FP_NAN: return 0;
case FP_INFINITE: return signbit(f) ? INT64_MIN : INT64_MAX;
default: return static_cast<int64_t>(f);
}
}
uint64_t
@ -3708,21 +3748,10 @@ isReferenceTailCall(MyThread* t, object code, unsigned ip, object caller,
(t, code, ip, caller, methodReferenceReturnCode(t, calleeReference));
}
void
compile(MyThread* t, Frame* initialFrame, unsigned ip,
int exceptionHandlerStart = -1);
void
saveStateAndCompile(MyThread* t, Frame* initialFrame, unsigned ip)
{
Compiler::State* state = initialFrame->c->saveState();
compile(t, initialFrame, ip);
initialFrame->c->restoreState(state);
}
bool
integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
unsigned size, Compiler::Operand* a, Compiler::Operand* b)
unsigned size, Compiler::Operand* a, Compiler::Operand* b,
unsigned* newIpp)
{
if (ip + 3 > codeLength(t, code)) {
return false;
@ -3766,14 +3795,14 @@ integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
return false;
}
saveStateAndCompile(t, frame, newIp);
*newIpp = newIp;
return true;
}
bool
floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
unsigned size, bool lessIfUnordered, Compiler::Operand* a,
Compiler::Operand* b)
Compiler::Operand* b, unsigned* newIpp)
{
if (ip + 3 > codeLength(t, code)) {
return false;
@ -3833,7 +3862,7 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
return false;
}
saveStateAndCompile(t, frame, newIp);
*newIpp = newIp;
return true;
}
@ -4007,17 +4036,126 @@ targetFieldOffset(Context* context, object field)
}
}
class Stack {
public:
class MyResource: public Thread::Resource {
public:
MyResource(Stack* s): Resource(s->thread), s(s) { }
virtual void release() {
s->zone.dispose();
}
Stack* s;
};
Stack(MyThread* t):
thread(t),
zone(t->m->system, t->m->heap, 0),
resource(this)
{ }
~Stack() {
zone.dispose();
}
void pushValue(uintptr_t v) {
*static_cast<uintptr_t*>(push(BytesPerWord)) = v;
}
uintptr_t peekValue(unsigned offset) {
return *static_cast<uintptr_t*>(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<Frame*>
(reinterpret_cast<uint8_t*>(this) - pad(count * 4) - pad(sizeof(Frame)));
}
uint32_t* ipTable() {
return reinterpret_cast<uint32_t*>
(reinterpret_cast<uint8_t*>(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<uint8_t*>(stack.push(stackSize));
frame = new (stack.push(sizeof(Frame))) Frame(frame, stackMap);
loop:
object code = methodCode(t, context->method);
PROTECT(t, code);
@ -4025,7 +4163,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
if (context->visitTable[ip] ++) {
// we've already visited this part of the code
frame->visitLogicalIp(ip);
return;
goto next;
}
frame->startLogicalIp(ip);
@ -4282,7 +4420,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
case areturn: {
handleExit(t, frame);
c->return_(TargetBytesPerWord, frame->popObject());
} return;
} goto next;
case arraylength: {
frame->pushInt
@ -4327,7 +4465,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
if (ip == codeLength(t, code)) {
c->trap();
}
} return;
} goto next;
case bipush:
frame->pushInt
@ -4391,7 +4529,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
if (not floatBranch(t, frame, code, ip, 8, false, a, b)) {
if (floatBranch(t, frame, code, ip, 8, false, a, b, &newIp)) {
goto branch;
} else {
frame->pushInt
(c->call
(c->constant
@ -4406,7 +4546,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
if (not floatBranch(t, frame, code, ip, 8, true, a, b)) {
if (floatBranch(t, frame, code, ip, 8, true, a, b, &newIp)) {
goto branch;
} else {
frame->pushInt
(c->call
(c->constant
@ -4504,7 +4646,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
if (not floatBranch(t, frame, code, ip, 4, false, a, b)) {
if (floatBranch(t, frame, code, ip, 4, false, a, b, &newIp)) {
goto branch;
} else {
frame->pushInt
(c->call
(c->constant
@ -4517,7 +4661,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
if (not floatBranch(t, frame, code, ip, 4, true, a, b)) {
if (floatBranch(t, frame, code, ip, 4, true, a, b, &newIp)) {
goto branch;
} else {
frame->pushInt
(c->call
(c->constant
@ -4851,7 +4997,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
case if_acmpeq:
case if_acmpne: {
uint32_t offset = codeReadInt16(t, code, ip);
uint32_t newIp = (ip - 3) + offset;
newIp = (ip - 3) + offset;
assert(t, newIp < codeLength(t, code));
Compiler::Operand* a = frame->popObject();
@ -4863,9 +5009,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
} else {
c->jumpIfNotEqual(TargetBytesPerWord, a, b, target);
}
saveStateAndCompile(t, frame, newIp);
} break;
} goto branch;
case if_icmpeq:
case if_icmpne:
@ -4874,7 +5018,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
case if_icmplt:
case if_icmple: {
uint32_t offset = codeReadInt16(t, code, ip);
uint32_t newIp = (ip - 3) + offset;
newIp = (ip - 3) + offset;
assert(t, newIp < codeLength(t, code));
Compiler::Operand* a = frame->popInt();
@ -4903,9 +5047,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
default:
abort(t);
}
saveStateAndCompile(t, frame, newIp);
} break;
} goto branch;
case ifeq:
case ifne:
@ -4914,7 +5056,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
case iflt:
case ifle: {
uint32_t offset = codeReadInt16(t, code, ip);
uint32_t newIp = (ip - 3) + offset;
newIp = (ip - 3) + offset;
assert(t, newIp < codeLength(t, code));
Compiler::Operand* target = frame->machineIp(newIp);
@ -4944,14 +5086,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
default:
abort(t);
}
saveStateAndCompile(t, frame, newIp);
} break;
} goto branch;
case ifnull:
case ifnonnull: {
uint32_t offset = codeReadInt16(t, code, ip);
uint32_t newIp = (ip - 3) + offset;
newIp = (ip - 3) + offset;
assert(t, newIp < codeLength(t, code));
Compiler::Operand* a = c->constant(0, Compiler::ObjectType);
@ -4963,9 +5103,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
} else {
c->jumpIfNotEqual(TargetBytesPerWord, a, b, target);
}
saveStateAndCompile(t, frame, newIp);
} break;
} goto branch;
case iinc: {
uint8_t index = codeBody(t, code, ip++);
@ -5028,21 +5166,18 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
object argument;
Thunk thunk;
TraceElement* trace;
if (LIKELY(class_)) {
argument = class_;
thunk = instanceOf64Thunk;
trace = 0;
} else {
argument = makePair(t, context->method, reference);
thunk = instanceOfFromReferenceThunk;
trace = frame->trace(0, 0);
}
frame->pushInt
(c->call
(c->constant(getThunk(t, thunk), Compiler::AddressType),
0, trace, 4, Compiler::IntegerType,
0, frame->trace(0, 0), 4, Compiler::IntegerType,
3, c->register_(t->arch->thread()), frame->append(argument),
instance));
} break;
@ -5265,7 +5400,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
case freturn: {
handleExit(t, frame);
c->return_(4, frame->popInt());
} return;
} goto next;
case ishl: {
Compiler::Operand* a = frame->popInt();
@ -5325,7 +5460,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
case jsr:
case jsr_w: {
uint32_t thisIp;
uint32_t newIp;
if (instruction == jsr) {
uint32_t offset = codeReadInt16(t, code, ip);
@ -5343,10 +5477,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
c->jmp(frame->machineIp(newIp));
saveStateAndCompile(t, frame, newIp);
frame->endSubroutine(start);
} break;
stack.pushValue(start);
stack.pushValue(ip);
stack.pushValue(Unsubroutine);
ip = newIp;
} goto start;
case l2d: {
frame->pushLong(c->i2f(8, 8, frame->popLong()));
@ -5376,7 +5511,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
if (not integerBranch(t, frame, code, ip, 8, a, b)) {
if (integerBranch(t, frame, code, ip, 8, a, b, &newIp)) {
goto branch;
} else {
frame->pushInt
(c->call
(c->constant
@ -5534,14 +5671,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
(frame->addressPromise(c->machineIp(defaultIp)));
Promise* start = 0;
THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, pairCount);
uint32_t* ipTable = static_cast<uint32_t*>
(stack.push(sizeof(uint32_t) * pairCount));
for (int32_t i = 0; i < pairCount; ++i) {
unsigned index = ip + (i * 8);
int32_t key = codeReadInt32(t, code, index);
uint32_t newIp = base + codeReadInt32(t, code, index);
assert(t, newIp < codeLength(t, code));
RUNTIME_ARRAY_BODY(ipTable)[i] = newIp;
ipTable[i] = newIp;
Promise* p = c->poolAppend(key);
if (i == 0) {
@ -5565,19 +5703,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
TARGET_THREAD_CODEIMAGE), address)
: address);
Compiler::State* state = c->saveState();
new (stack.push(sizeof(SwitchState))) SwitchState
(c->saveState(), pairCount, defaultIp, 0, 0, 0, 0);
for (int32_t i = 0; i < pairCount; ++i) {
compile(t, frame, RUNTIME_ARRAY_BODY(ipTable)[i]);
c->restoreState(state);
}
goto switchloop;
} else {
// a switch statement with no cases, apparently
c->jmp(frame->machineIp(defaultIp));
ip = defaultIp;
}
ip = defaultIp;
} break;
case lor: {
@ -5602,7 +5736,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
case dreturn: {
handleExit(t, frame);
c->return_(8, frame->popLong());
} return;
} goto next;
case lshl: {
Compiler::Operand* a = frame->popInt();
@ -6029,7 +6163,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
case ret: {
unsigned index = codeBody(t, code, ip);
frame->returnFromSubroutine(index);
} return;
} goto next;
case return_:
if (needsReturnBarrier(t, context->method)) {
@ -6038,7 +6172,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
handleExit(t, frame);
c->return_(0, 0);
return;
goto next;
case sipush:
frame->pushInt
@ -6063,13 +6197,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
int32_t top = codeReadInt32(t, code, ip);
Promise* start = 0;
THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, top - bottom + 1);
unsigned count = top - bottom + 1;
uint32_t* ipTable = static_cast<uint32_t*>
(stack.push(sizeof(uint32_t) * count));
for (int32_t i = 0; i < top - bottom + 1; ++i) {
unsigned index = ip + (i * 4);
uint32_t newIp = base + codeReadInt32(t, code, index);
assert(t, newIp < codeLength(t, code));
RUNTIME_ARRAY_BODY(ipTable)[i] = newIp;
ipTable[i] = newIp;
Promise* p = c->poolAppendPromise
(frame->addressPromise(c->machineIp(newIp)));
@ -6086,43 +6222,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
c->save(1, key);
saveStateAndCompile(t, frame, defaultIp);
c->jumpIfGreater(4, c->constant(top, Compiler::IntegerType), key,
frame->machineIp(defaultIp));
c->save(1, key);
saveStateAndCompile(t, frame, defaultIp);
Compiler::Operand* normalizedKey
= (bottom
? c->sub(4, c->constant(bottom, Compiler::IntegerType), key) : key);
Compiler::Operand* entry = c->memory
(frame->absoluteAddressOperand(start), Compiler::AddressType, 0,
normalizedKey, TargetBytesPerWord);
c->jmp
(c->load
(TargetBytesPerWord, TargetBytesPerWord, context->bootContext
? c->add
(TargetBytesPerWord, c->memory
(c->register_(t->arch->thread()), Compiler::AddressType,
TARGET_THREAD_CODEIMAGE), entry)
: entry,
TargetBytesPerWord));
Compiler::State* state = c->saveState();
for (int32_t i = 0; i < top - bottom + 1; ++i) {
compile(t, frame, RUNTIME_ARRAY_BODY(ipTable)[i]);
c->restoreState(state);
}
new (stack.push(sizeof(SwitchState))) SwitchState
(c->saveState(), count, defaultIp, key, start, bottom, top);
stack.pushValue(Untable0);
ip = defaultIp;
} break;
} goto start;
case wide: {
switch (codeBody(t, code, ip++)) {
@ -6166,7 +6271,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
unsigned index = codeReadInt16(t, code, ip);
c->jmp(loadLocal(context, 1, index));
frame->returnFromSubroutine(index);
} return;
} goto next;
default: abort(t);
}
@ -6175,6 +6280,113 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
default: abort(t);
}
}
next:
frame->dispose();
frame = 0;
stack.pop(sizeof(Frame));
stack.pop(stackSize);
switch (stack.popValue()) {
case Return:
return;
case Unbranch:
ip = stack.popValue();
c->restoreState(reinterpret_cast<Compiler::State*>(stack.popValue()));
frame = static_cast<Frame*>(stack.peek(sizeof(Frame)));
goto loop;
case Untable0: {
SwitchState* s = static_cast<SwitchState*>
(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<SwitchState*>
(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<SwitchState*>
(stack.peek(sizeof(SwitchState)));
frame = s->frame();
c->restoreState
(static_cast<SwitchState*>(stack.peek(sizeof(SwitchState)))->state);
} goto switchloop;
case Unsubroutine: {
ip = stack.popValue();
unsigned start = stack.popValue();
frame = reinterpret_cast<Frame*>(stack.peek(sizeof(Frame)));
frame->endSubroutine(start);
} goto loop;
default:
abort(t);
}
switchloop: {
SwitchState* s = static_cast<SwitchState*>
(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<Frame*>(stack.peek(sizeof(Frame)));
goto loop;
}
}
branch:
stack.pushValue(reinterpret_cast<uintptr_t>(c->saveState()));
stack.pushValue(ip);
stack.pushValue(Unbranch);
ip = newIp;
goto start;
}
FILE* compileLog = 0;
@ -8778,6 +8990,32 @@ class MyProcessor: public Processor {
}
}
virtual bool
pushLocalFrame(Thread* vmt, unsigned)
{
MyThread* t = static_cast<MyThread*>(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<MyThread*>(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)
{

View File

@ -11,18 +11,18 @@
#ifndef AVIAN_ENVIRONMENT_H
#define AVIAN_ENVIRONMENT_H
#ifndef AVIAN_TARGET_PLATFORM
#error build system should have defined AVIAN_TARGET_PLATFORM
#ifndef AVIAN_TARGET_FORMAT
#error build system should have defined AVIAN_TARGET_FORMAT
#endif
#ifndef AVIAN_TARGET_ARCH
#error build system should have defined AVIAN_TARGET_ARCH
#endif
#define AVIAN_PLATFORM_UNKNOWN 0
#define AVIAN_PLATFORM_LINUX 1
#define AVIAN_PLATFORM_WINDOWS 2
#define AVIAN_PLATFORM_DARWIN 3
#define AVIAN_FORMAT_UNKNOWN 0
#define AVIAN_FORMAT_ELF 1
#define AVIAN_FORMAT_PE 2
#define AVIAN_FORMAT_MACHO 3
#define AVIAN_ARCH_UNKNOWN 0
#define AVIAN_ARCH_X86 (1 << 8)
@ -30,4 +30,5 @@
#define AVIAN_ARCH_ARM (3 << 8)
#define AVIAN_ARCH_POWERPC (4 << 8)
#endif
#endif

View File

@ -602,7 +602,7 @@ class BuiltinElement: public JarElement {
}
virtual const char* urlPrefix() {
return "resource:";
return "avianvmresource:";
}
virtual const char* sourceUrl() {

View File

@ -463,12 +463,15 @@ class Segment {
class Fixie {
public:
static const unsigned HasMask = 1 << 0;
static const unsigned Marked = 1 << 1;
static const unsigned Dirty = 1 << 2;
static const unsigned Dead = 1 << 3;
Fixie(Context* c, unsigned size, bool hasMask, Fixie** handle,
bool immortal):
age(immortal ? FixieTenureThreshold + 1 : 0),
hasMask(hasMask),
marked(false),
dirty(false),
flags(hasMask ? HasMask : 0),
size(size),
next(0),
handle(0)
@ -536,16 +539,54 @@ class Fixie {
}
unsigned totalSize() {
return totalSize(size, hasMask);
return totalSize(size, hasMask());
}
bool hasMask() {
return (flags & HasMask) != 0;
}
bool marked() {
return (flags & Marked) != 0;
}
void marked(bool v) {
if (v) {
flags |= Marked;
} else {
flags &= ~Marked;
}
}
bool dirty() {
return (flags & Dirty) != 0;
}
void dirty(bool v) {
if (v) {
flags |= Dirty;
} else {
flags &= ~Dirty;
}
}
bool dead() {
return (flags & Dead) != 0;
}
void dead(bool v) {
if (v) {
flags |= Dead;
} else {
flags &= ~Dead;
}
}
// be sure to update e.g. TargetFixieSizeInBytes in bootimage.cpp if
// you add/remove/change fields in this class:
uint8_t age;
uint8_t hasMask;
uint8_t marked;
uint8_t dirty;
uint16_t age;
uint16_t flags;
uint32_t size;
Fixie* next;
Fixie** handle;
@ -850,11 +891,11 @@ free(Context* c, Fixie** fixies, bool resetImmortal)
fprintf(stderr, "reset immortal fixie %p\n", f);
}
*p = f->next;
memset(f->mask(), 0, Fixie::maskSize(f->size, f->hasMask));
memset(f->mask(), 0, Fixie::maskSize(f->size, f->hasMask()));
f->next = 0;
f->handle = 0;
f->marked = false;
f->dirty = false;
f->marked(false);
f->dirty(false);
} else {
p = &(f->next);
}
@ -868,6 +909,28 @@ free(Context* c, Fixie** fixies, bool resetImmortal)
}
}
void
kill(Fixie* fixies)
{
for (Fixie* f = fixies; f; f = f->next) {
if (! f->immortal()) {
f->dead(true);
}
}
}
void
killFixies(Context* c)
{
assert(c, c->markedFixies == 0);
if (c->mode == Heap::MajorCollection) {
kill(c->tenuredFixies);
kill(c->dirtyTenuredFixies);
}
kill(c->fixies);
}
void
sweepFixies(Context* c)
{
@ -898,14 +961,14 @@ sweepFixies(Context* c)
if (f->age >= FixieTenureThreshold) {
if (DebugFixies) {
fprintf(stderr, "tenure fixie %p (dirty: %d)\n", f, f->dirty);
fprintf(stderr, "tenure fixie %p (dirty: %d)\n", f, f->dirty());
}
if (not f->immortal()) {
c->tenuredFixieFootprint += f->totalSize();
}
if (f->dirty) {
if (f->dirty()) {
f->add(c, &(c->dirtyTenuredFixies));
} else {
f->add(c, &(c->tenuredFixies));
@ -916,7 +979,7 @@ sweepFixies(Context* c)
f->add(c, &(c->fixies));
}
f->marked = false;
f->marked(false);
}
c->tenuredFixieCeiling = max
@ -1006,14 +1069,15 @@ update3(Context* c, void* o, bool* needsVisit)
{
if (c->client->isFixed(o)) {
Fixie* f = fixie(o);
if ((not f->marked)
if ((not f->marked())
and (c->mode == Heap::MajorCollection
or f->age < FixieTenureThreshold))
{
if (DebugFixies) {
fprintf(stderr, "mark fixie %p\n", f);
}
f->marked = true;
f->marked(true);
f->dead(false);
f->move(c, &(c->markedFixies));
}
*needsVisit = false;
@ -1044,13 +1108,13 @@ update2(Context* c, void* o, bool* needsVisit)
void
markDirty(Context* c, Fixie* f)
{
if (not f->dirty) {
if (not f->dirty()) {
#ifdef USE_ATOMIC_OPERATIONS
ACQUIRE(c->lock);
#endif
if (not f->dirty) {
f->dirty = true;
if (not f->dirty()) {
f->dirty(true);
f->move(c, &(c->dirtyTenuredFixies));
}
}
@ -1059,8 +1123,8 @@ markDirty(Context* c, Fixie* f)
void
markClean(Context* c, Fixie* f)
{
if (f->dirty) {
f->dirty = false;
if (f->dirty()) {
f->dirty(false);
if (f->immortal()) {
f->remove(c);
} else {
@ -1090,7 +1154,7 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result)
{
if (target and c->client->isFixed(target)) {
Fixie* f = fixie(target);
assert(c, offset == 0 or f->hasMask);
assert(c, offset == 0 or f->hasMask());
if (static_cast<unsigned>(f->age + 1) >= FixieTenureThreshold) {
if (DebugFixies) {
@ -1098,7 +1162,7 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result)
f, offset, f->body() + offset, result);
}
f->dirty = true;
f->dirty(true);
markBit(f->mask(), offset);
}
} else if (seg->contains(p)) {
@ -1804,6 +1868,10 @@ class MyHeap: public Heap {
c.immortalHeapEnd = start + sizeInWords;
}
virtual unsigned limit() {
return c.limit;
}
virtual bool limitExceeded() {
return c.count > c.limit;
}
@ -1871,7 +1939,7 @@ class MyHeap: public Heap {
if (c.client->isFixed(p)) {
Fixie* f = fixie(p);
assert(&c, offset == 0 or f->hasMask);
assert(&c, offset == 0 or f->hasMask());
bool dirty = false;
for (unsigned i = 0; i < count; ++i) {
@ -1946,11 +2014,22 @@ class MyHeap: public Heap {
}
}
virtual void postVisit() {
killFixies(&c);
}
virtual Status status(void* p) {
p = mask(p);
if (p == 0) {
return Null;
} else if (c.client->isFixed(p)) {
Fixie* f = fixie(p);
return f->dead()
? Unreachable
: (static_cast<unsigned>(f->age + 1) < FixieTenureThreshold
? Reachable
: Tenured);
} else if (c.nextGen1.contains(p)) {
return Reachable;
} else if (c.nextGen2.contains(p)

View File

@ -59,6 +59,7 @@ class Heap: public Allocator {
virtual void setClient(Client* client) = 0;
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0;
virtual unsigned limit() = 0;
virtual bool limitExceeded() = 0;
virtual void collect(CollectionType type, unsigned footprint) = 0;
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
@ -69,6 +70,7 @@ class Heap: public Allocator {
virtual void mark(void* p, unsigned offset, unsigned count) = 0;
virtual void pad(void* p) = 0;
virtual void* follow(void* p) = 0;
virtual void postVisit() = 0;
virtual Status status(void* p) = 0;
virtual CollectionType collectionType() = 0;
virtual void disposeFixies() = 0;

View File

@ -28,18 +28,31 @@ const unsigned FrameFootprint = 4;
class Thread: public vm::Thread {
public:
class ReferenceFrame {
public:
ReferenceFrame(ReferenceFrame* next, unsigned sp):
next(next),
sp(sp)
{ }
ReferenceFrame* next;
unsigned sp;
};
Thread(Machine* m, object javaThread, vm::Thread* parent):
vm::Thread(m, javaThread, parent),
ip(0),
sp(0),
frame(-1),
code(0)
code(0),
referenceFrame(0)
{ }
unsigned ip;
unsigned sp;
int frame;
object code;
ReferenceFrame* referenceFrame;
uintptr_t stack[0];
};
@ -1065,11 +1078,27 @@ interpret3(Thread* t, const int base)
} goto loop;
case d2i: {
pushInt(t, static_cast<int32_t>(popDouble(t)));
double f = popDouble(t);
switch (fpclassify(f)) {
case FP_NAN: pushInt(t, 0); break;
case FP_INFINITE: pushInt(t, signbit(f) ? INT32_MIN : INT32_MAX); break;
default: pushInt
(t, f >= INT32_MAX ? INT32_MAX
: (f <= INT32_MIN ? INT32_MIN : static_cast<int32_t>(f)));
break;
}
} goto loop;
case d2l: {
pushLong(t, static_cast<int64_t>(popDouble(t)));
double f = popDouble(t);
switch (fpclassify(f)) {
case FP_NAN: pushLong(t, 0); break;
case FP_INFINITE: pushLong(t, signbit(f) ? INT64_MIN : INT64_MAX); break;
default: pushLong
(t, f >= INT64_MAX ? INT64_MAX
: (f <= INT64_MIN ? INT64_MIN : static_cast<int64_t>(f)));
break;
}
} goto loop;
case dadd: {
@ -1265,11 +1294,24 @@ interpret3(Thread* t, const int base)
} goto loop;
case f2i: {
pushInt(t, static_cast<int32_t>(popFloat(t)));
float f = popFloat(t);
switch (fpclassify(f)) {
case FP_NAN: pushInt(t, 0); break;
case FP_INFINITE: pushInt(t, signbit(f) ? INT32_MIN : INT32_MAX); break;
default: pushInt(t, f >= INT32_MAX ? INT32_MAX
: (f <= INT32_MIN ? INT32_MIN : static_cast<int32_t>(f)));
break;
}
} goto loop;
case f2l: {
pushLong(t, static_cast<int64_t>(popFloat(t)));
float f = popFloat(t);
switch (fpclassify(f)) {
case FP_NAN: pushLong(t, 0); break;
case FP_INFINITE: pushLong(t, signbit(f) ? INT64_MIN : INT64_MAX);
break;
default: pushLong(t, static_cast<int64_t>(f)); break;
}
} goto loop;
case fadd: {
@ -1888,14 +1930,14 @@ interpret3(Thread* t, const int base)
int32_t b = popInt(t);
int32_t a = popInt(t);
pushInt(t, a << b);
pushInt(t, a << (b & 0x1F));
} goto loop;
case ishr: {
int32_t b = popInt(t);
int32_t a = popInt(t);
pushInt(t, a >> b);
pushInt(t, a >> (b & 0x1F));
} goto loop;
case istore:
@ -1934,7 +1976,7 @@ interpret3(Thread* t, const int base)
int32_t b = popInt(t);
uint32_t a = popInt(t);
pushInt(t, a >> b);
pushInt(t, a >> (b & 0x1F));
} goto loop;
case ixor: {
@ -2196,14 +2238,14 @@ interpret3(Thread* t, const int base)
int32_t b = popInt(t);
int64_t a = popLong(t);
pushLong(t, a << b);
pushLong(t, a << (b & 0x3F));
} goto loop;
case lshr: {
int32_t b = popInt(t);
int64_t a = popLong(t);
pushLong(t, a >> b);
pushLong(t, a >> (b & 0x3F));
} goto loop;
case lstore:
@ -2242,7 +2284,7 @@ interpret3(Thread* t, const int base)
int64_t b = popInt(t);
uint64_t a = popLong(t);
pushLong(t, a >> b);
pushLong(t, a >> (b & 0x3F));
} goto loop;
case lxor: {
@ -2781,7 +2823,7 @@ pushArguments(Thread* t, object this_, const char* spec,
break;
case 'F': {
pushFloat(t, arguments[index++].d);
pushFloat(t, arguments[index++].f);
} break;
default:
@ -3010,6 +3052,34 @@ class MyProcessor: public Processor {
}
}
virtual bool
pushLocalFrame(vm::Thread* vmt, unsigned capacity)
{
Thread* t = static_cast<Thread*>(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<Thread*>(vmt);
Thread::ReferenceFrame* f = t->referenceFrame;
t->referenceFrame = f->next;
t->sp = f->sp;
t->m->heap->free(f, sizeof(Thread::ReferenceFrame));
}
virtual object
invokeArray(vm::Thread* vmt, object method, object this_, object arguments)
{
@ -3166,7 +3236,7 @@ class MyProcessor: public Processor {
}
virtual void dispose(vm::Thread* t) {
t->m->heap->free(t, sizeof(Thread));
t->m->heap->free(t, sizeof(Thread) + t->m->stackSizeInBytes);
}
virtual void dispose() {

View File

@ -45,19 +45,23 @@ DetachCurrentThread(Machine* m)
{
Thread* t = static_cast<Thread*>(m->localThread->get());
if (t) {
expect(t, t != m->rootThread);
// todo: detaching the root thread seems to cause stability
// problems which I haven't yet had a chance to investigate
// thoroughly. Meanwhile, we just ignore requests to detach it,
// which leaks a bit of memory but should be harmless otherwise.
if (m->rootThread != t) {
m->localThread->set(0);
m->localThread->set(0);
ACQUIRE_RAW(t, t->m->stateLock);
ACQUIRE_RAW(t, t->m->stateLock);
enter(t, Thread::ActiveState);
enter(t, Thread::ActiveState);
threadPeer(t, t->javaThread) = 0;
threadPeer(t, t->javaThread) = 0;
enter(t, Thread::ZombieState);
enter(t, Thread::ZombieState);
t->state = Thread::JoinedState;
t->state = Thread::JoinedState;
}
return 0;
} else {
@ -237,9 +241,8 @@ newString(Thread* t, uintptr_t* arguments)
const jchar* chars = reinterpret_cast<const jchar*>(arguments[0]);
jsize size = arguments[1];
object a = 0;
object a = makeCharArray(t, size);
if (size) {
a = makeCharArray(t, size);
memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar));
}
@ -407,24 +410,6 @@ ExceptionCheck(Thread* t)
return t->exception != 0;
}
jobject JNICALL
NewDirectByteBuffer(Thread*, void*, jlong)
{
return 0;
}
void* JNICALL
GetDirectBufferAddress(Thread*, jobject)
{
return 0;
}
jlong JNICALL
GetDirectBufferCapacity(Thread*, jobject)
{
return -1;
}
uint64_t
getObjectClass(Thread* t, uintptr_t* arguments)
{
@ -439,18 +424,20 @@ GetObjectClass(Thread* t, jobject o)
{
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(o) };
return reinterpret_cast<jobject>(run(t, getObjectClass, arguments));
return reinterpret_cast<jclass>(run(t, getObjectClass, arguments));
}
uint64_t
getSuperclass(Thread* t, uintptr_t* arguments)
{
jclass c = reinterpret_cast<jclass>(arguments[0]);
object super = classSuper(t, jclassVmClass(t, *c));
return super ? reinterpret_cast<uint64_t>
(makeLocalReference(t, getJClass(t, super))) : 0;
object class_ = jclassVmClass(t, *reinterpret_cast<jclass>(arguments[0]));
if (classFlags(t, class_) & ACC_INTERFACE) {
return 0;
} else {
object super = classSuper(t, class_);
return super ? reinterpret_cast<uint64_t>
(makeLocalReference(t, getJClass(t, super))) : 0;
}
}
jclass JNICALL
@ -3154,6 +3141,8 @@ GetPrimitiveArrayCritical(Thread* t, jarray array, jboolean* isCopy)
*isCopy = true;
}
expect(t, *array);
return reinterpret_cast<uintptr_t*>(*array) + 2;
}
@ -3276,6 +3265,66 @@ IsSameObject(Thread* t, jobject a, jobject b)
}
}
uint64_t
pushLocalFrame(Thread* t, uintptr_t* arguments)
{
if (t->m->processor->pushLocalFrame(t, arguments[0])) {
return 1;
} else {
throw_(t, root(t, Machine::OutOfMemoryError));
}
}
jint JNICALL
PushLocalFrame(Thread* t, jint capacity)
{
uintptr_t arguments[] = { static_cast<uintptr_t>(capacity) };
return run(t, pushLocalFrame, arguments) ? 0 : -1;
}
uint64_t
popLocalFrame(Thread* t, uintptr_t* arguments)
{
object result = *reinterpret_cast<jobject>(arguments[0]);
PROTECT(t, result);
t->m->processor->popLocalFrame(t);
return reinterpret_cast<uint64_t>(makeLocalReference(t, result));
}
jobject JNICALL
PopLocalFrame(Thread* t, jobject result)
{
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(result) };
return reinterpret_cast<jobject>(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, "<init>", "(JI)V"),
reinterpret_cast<jlong>(p),
static_cast<jint>(capacity));
}
void* JNICALL
GetDirectBufferAddress(Thread* t, jobject b)
{
return reinterpret_cast<void*>
(GetLongField(t, b, GetFieldID(t, GetObjectClass(t, b), "address", "J")));
}
jlong JNICALL
GetDirectBufferCapacity(Thread* t, jobject b)
{
return GetIntField
(t, b, GetFieldID(t, GetObjectClass(t, b), "capacity", "I"));
}
struct JavaVMOption {
char* optionString;
void* extraInfo;
@ -3556,6 +3605,8 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
envTable->MonitorExit = local::MonitorExit;
envTable->GetJavaVM = local::GetJavaVM;
envTable->IsSameObject = local::IsSameObject;
envTable->PushLocalFrame = local::PushLocalFrame;
envTable->PopLocalFrame = local::PopLocalFrame;
}
} // namespace vm
@ -3576,6 +3627,13 @@ JNI_GetDefaultJavaVMInitArgs(void*)
return 0;
}
extern "C" JNIEXPORT jint JNICALL
JNI_GetCreatedJavaVMs(Machine**, jsize, jsize*)
{
// todo
return -1;
}
extern "C" JNIEXPORT jint JNICALL
JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
{

View File

@ -273,6 +273,8 @@ killZombies(Thread* t, Thread* o)
unsigned
footprint(Thread* t)
{
expect(t, t->criticalLevel == 0);
unsigned n = t->heapOffset + t->heapIndex + t->backupHeapIndex;
for (Thread* c = t->child; c; c = c->peer) {
@ -472,6 +474,25 @@ referenceTargetReachable(Thread* t, Heap::Visitor* v, object* p)
}
}
bool
isFinalizable(Thread* t, object o)
{
return t->m->heap->status(o) == Heap::Unreachable
and (classVmFlags
(t, static_cast<object>(t->m->heap->follow(objectClass(t, o))))
& HasFinalizerFlag);
}
void
clearTargetIfFinalizable(Thread* t, object r)
{
if (isFinalizable
(t, static_cast<object>(t->m->heap->follow(jreferenceTarget(t, r)))))
{
jreferenceTarget(t, r) = 0;
}
}
void
postVisit(Thread* t, Heap::Visitor* v)
{
@ -480,6 +501,30 @@ postVisit(Thread* t, Heap::Visitor* v)
assert(t, m->finalizeQueue == 0);
m->heap->postVisit();
for (object p = m->weakReferences; p;) {
object r = static_cast<object>(m->heap->follow(p));
p = jreferenceVmNext(t, r);
clearTargetIfFinalizable(t, r);
}
if (major) {
for (object p = m->tenuredWeakReferences; p;) {
object r = static_cast<object>(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<object>(t->m->heap->follow(r->target))))
{
r->target = 0;
}
}
object firstNewTenuredFinalizer = 0;
object lastNewTenuredFinalizer = 0;
@ -1128,7 +1173,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
unsigned count = s.read2();
if (count) {
unsigned staticOffset = BytesPerWord * 2;
unsigned staticOffset = BytesPerWord * 3;
unsigned staticCount = 0;
object fieldTable = makeArray(t, count);
@ -1242,7 +1287,10 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
uint8_t* body = reinterpret_cast<uint8_t*>
(&singletonBody(t, staticTable, 0));
for (unsigned i = 0, offset = 0; i < staticCount; ++i) {
memcpy(body, &class_, BytesPerWord);
singletonMarkObject(t, staticTable, 0);
for (unsigned i = 0, offset = BytesPerWord; i < staticCount; ++i) {
unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]);
while (offset % size) {
++ offset;
@ -2248,6 +2296,11 @@ updateClassTables(Thread* t, object newClass, object oldClass)
}
}
object staticTable = classStaticTable(t, newClass);
if (staticTable) {
set(t, staticTable, SingletonBody, newClass);
}
if (classFlags(t, newClass) & ACC_INTERFACE) {
object virtualTable = classVirtualTable(t, newClass);
if (virtualTable) {
@ -3667,34 +3720,32 @@ stringUTFChars(Thread* t, object string, unsigned start, unsigned length,
assert(t, static_cast<unsigned>
(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<char>(c);
} else if (c < 0x800) { // two-byte char
chars[j++] = static_cast<char>(0x0c0 | (c >> 6));
chars[j++] = static_cast<char>(0x080 | (c & 0x03f));
} else { // three-byte char
chars[j++] = static_cast<char>(0x0e0 | ((c >> 12) & 0x0f));
chars[j++] = static_cast<char>(0x080 | ((c >> 6) & 0x03f));
chars[j++] = static_cast<char>(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<char>(c);
} else if (c < 0x800) { // two-byte char
chars[j++] = static_cast<char>(0x0c0 | (c >> 6));
chars[j++] = static_cast<char>(0x080 | (c & 0x03f));
} else { // three-byte char
chars[j++] = static_cast<char>(0x0e0 | ((c >> 12) & 0x0f));
chars[j++] = static_cast<char>(0x080 | ((c >> 6) & 0x03f));
chars[j++] = static_cast<char>(0x080 | (c & 0x03f));
}
chars[j] = 0;
}
}
}
chars[j] = 0;
}
}
uint64_t
@ -3983,6 +4034,17 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size,
return real;
}
uint64_t
runParseClass(Thread* t, uintptr_t* arguments)
{
object loader = reinterpret_cast<object>(arguments[0]);
System::Region* region = reinterpret_cast<System::Region*>(arguments[1]);
Machine::Type throwType = static_cast<Machine::Type>(arguments[2]);
return reinterpret_cast<uintptr_t>
(parseClass(t, loader, region->start(), region->length(), throwType));
}
object
resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
Machine::Type throwType)
@ -4028,9 +4090,24 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
{ THREAD_RESOURCE(t, System::Region*, region, region->dispose());
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(loader),
reinterpret_cast<uintptr_t>(region),
static_cast<uintptr_t>(throwType) };
// parse class file
class_ = parseClass
(t, loader, region->start(), region->length(), throwType);
class_ = reinterpret_cast<object>
(runRaw(t, runParseClass, arguments));
if (UNLIKELY(t->exception)) {
if (throw_) {
object e = t->exception;
t->exception = 0;
vm::throw_(t, e);
} else {
t->exception = 0;
return 0;
}
}
}
if (Verbose) {
@ -4068,6 +4145,8 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
if (class_) {
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
t->m->classpath->updatePackageMap(t, class_);
} else if (throw_) {
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
}
@ -4808,15 +4887,27 @@ parseUtf8(Thread* t, const char* data, unsigned length)
}
object
getCaller(Thread* t, unsigned target)
getCaller(Thread* t, unsigned target, bool skipMethodInvoke)
{
class Visitor: public Processor::StackVisitor {
public:
Visitor(Thread* t, unsigned target):
t(t), method(0), count(0), target(target)
Visitor(Thread* t, unsigned target, bool skipMethodInvoke):
t(t), method(0), count(0), target(target),
skipMethodInvoke(skipMethodInvoke)
{ }
virtual bool visit(Processor::StackWalker* walker) {
if (skipMethodInvoke
and methodClass
(t, walker->method()) == type(t, Machine::JmethodType)
and strcmp
(&byteArrayBody(t, methodName(t, walker->method()), 0),
reinterpret_cast<const int8_t*>("invoke"))
== 0)
{
return true;
}
if (count == target) {
method = walker->method();
return false;
@ -4830,7 +4921,8 @@ getCaller(Thread* t, unsigned target)
object method;
unsigned count;
unsigned target;
} v(t, target);
bool skipMethodInvoke;
} v(t, target, skipMethodInvoke);
t->m->processor->walkStack(t, &v);

View File

@ -1206,6 +1206,7 @@ class Machine {
BootLoader,
AppLoader,
BootstrapClassMap,
PackageMap,
FindLoadedClassMethod,
LoadClassMethod,
MonitorMap,
@ -1550,6 +1551,9 @@ class Classpath {
virtual const char*
bootClasspath() = 0;
virtual void
updatePackageMap(Thread* t, object class_) = 0;
virtual void
dispose() = 0;
};
@ -3801,7 +3805,7 @@ populateMultiArray(Thread* t, object array, int32_t* counts,
unsigned index, unsigned dimensions);
object
getCaller(Thread* t, unsigned target);
getCaller(Thread* t, unsigned target, bool skipMethodInvoke = false);
object
defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length);

View File

@ -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<const char*>
(region->start() + start), PrefixLength) == 0)
if (strncasecmp("Main-Class: ", reinterpret_cast<const char*>
(region->start() + start), PrefixLength) == 0)
{
result = static_cast<char*>(malloc(length + 1 - PrefixLength));
memcpy(result, region->start() + start + PrefixLength,
@ -172,9 +172,11 @@ main(int ac, const char** av)
if (strcmp(av[i], "-cp") == 0
or strcmp(av[i], "-classpath") == 0)
{
if (i + 1 == ac) usageAndExit(av[0]);
classpath = av[++i];
} else if (strcmp(av[i], "-jar") == 0)
{
if (i + 1 == ac) usageAndExit(av[0]);
jar = av[++i];
} else if (strncmp(av[i], "-X", 2) == 0
or strncmp(av[i], "-D", 2) == 0)

View File

@ -14,7 +14,13 @@
#ifdef __APPLE__
# include "CoreFoundation/CoreFoundation.h"
# include "sys/ucontext.h"
# undef assert
#else
# if defined __FreeBSD__
# include "limits.h"
# endif
# include "ucontext.h"
#endif
#include "sys/mman.h"
@ -28,7 +34,6 @@
#include "unistd.h"
#include "pthread.h"
#include "signal.h"
#include "sys/ucontext.h"
#include "stdint.h"
#include "dirent.h"
#include "sched.h"
@ -622,7 +627,7 @@ class MySystem: public System {
}
virtual void* tryAllocateExecutable(unsigned sizeInBytes) {
#if (! defined __APPLE__) && (defined __x86_64__)
#ifdef MAP_32BIT
// map to the lower 32 bits of memory when possible so as to avoid
// expensive relative jumps
const unsigned Extra = MAP_32BIT;
@ -795,6 +800,13 @@ class MySystem: public System {
}
virtual FileType stat(const char* name, unsigned* length) {
#ifdef __FreeBSD__
// Now the hack below causes the error "Dereferencing type-punned
// pointer will break strict aliasing rules", so another workaround
// is needed...
struct stat ss;
struct stat* s = &ss;
#else
// Ugly Hack Alert: It seems that the Apple iOS Simulator's stat
// implementation writes beyond the end of the struct stat we pass
// it, which can clobber unrelated parts of the stack. Perhaps
@ -804,6 +816,7 @@ class MySystem: public System {
// made up and seems to work.
void* array[ceiling(sizeof(struct stat), sizeof(void*)) + 8];
struct stat* s = reinterpret_cast<struct stat*>(array);
#endif
int r = ::stat(name, s);
if (r == 0) {

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -60,4 +60,5 @@
# error
#endif
#endif
#endif

View File

@ -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);
}

View File

@ -871,6 +871,13 @@ class MemberIterator {
return true;
} else {
while (types) {
if (member) {
assert(member->type == Object::Scalar);
offset_ = ((offset_ + size_) + (BytesPerWord - 1))
& ~(BytesPerWord - 1);
member = 0;
}
type = car(types);
members = typeMembers(type);
types = cdr(types);
@ -2207,5 +2214,7 @@ main(int ac, char** av)
local::writeMaps(&out, declarations);
}
out.write("\n");
return 0;
}

View File

@ -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<int*>(0) = 0;
*static_cast<volatile int*>(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<int64_t>(tb.time) * 1000)
+ static_cast<int64_t>(tb.millitm));

View File

@ -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)

View File

@ -2164,7 +2164,9 @@ doShift(Context* c, UNUSED void (*shift)
c->client->save(rcx);
Assembler::Register cx(rcx);
moveCR(c, 4, a, 4, &cx);
ResolvedPromise promise(v & 0x3F);
Assembler::Constant masked(&promise);
moveCR(c, 4, &masked, 4, &cx);
shift(c, aSize, &cx, bSize, b);
} else {
maybeRex(c, bSize, b);
@ -2183,9 +2185,16 @@ void
shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
unsigned bSize, Assembler::Register* b)
{
assert(c, a->low == rcx);
if (TargetBytesPerWord == 4 and bSize == 8) {
Assembler::Register cx(rcx);
if (a->low != rcx) {
c->client->save(rcx);
ResolvedPromise promise(0x3F);
Assembler::Constant mask(&promise);
moveRR(c, 4, a, 4, &cx);
andCR(c, 4, &mask, 4, &cx);
}
// shld
opcode(c, 0x0f, 0xa5);
modrm(c, 0xc0, b->high, b->low);
@ -2195,7 +2204,7 @@ shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
ResolvedPromise promise(32);
Assembler::Constant constant(&promise);
compareCR(c, aSize, &constant, aSize, a);
compareCR(c, aSize, &constant, aSize, &cx);
opcode(c, 0x7c); //jl
c->code.append(2 + 2);
@ -2204,6 +2213,8 @@ shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
moveRR(c, 4, b, 4, &bh); // 2 bytes
xorRR(c, 4, b, 4, b); // 2 bytes
} else {
assert(c, a->low == rcx);
maybeRex(c, bSize, a, b);
opcode(c, 0xd3, 0xe0 + regCode(b));
}
@ -2220,8 +2231,16 @@ void
shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
unsigned bSize, Assembler::Register* b)
{
assert(c, a->low == rcx);
if (TargetBytesPerWord == 4 and bSize == 8) {
Assembler::Register cx(rcx);
if (a->low != rcx) {
c->client->save(rcx);
ResolvedPromise promise(0x3F);
Assembler::Constant mask(&promise);
moveRR(c, 4, a, 4, &cx);
andCR(c, 4, &mask, 4, &cx);
}
// shrd
opcode(c, 0x0f, 0xad);
modrm(c, 0xc0, b->low, b->high);
@ -2231,7 +2250,7 @@ shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
ResolvedPromise promise(32);
Assembler::Constant constant(&promise);
compareCR(c, aSize, &constant, aSize, a);
compareCR(c, aSize, &constant, aSize, &cx);
opcode(c, 0x7c); //jl
c->code.append(2 + 3);
@ -2243,6 +2262,8 @@ shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
opcode(c, 0xc1, 0xf8 + b->high);
c->code.append(31);
} else {
assert(c, a->low == rcx);
maybeRex(c, bSize, a, b);
opcode(c, 0xd3, 0xf8 + regCode(b));
}
@ -2259,9 +2280,16 @@ void
unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
unsigned bSize, Assembler::Register* b)
{
assert(c, a->low == rcx);
if (TargetBytesPerWord == 4 and bSize == 8) {
Assembler::Register cx(rcx);
if (a->low != rcx) {
c->client->save(rcx);
ResolvedPromise promise(0x3F);
Assembler::Constant mask(&promise);
moveRR(c, 4, a, 4, &cx);
andCR(c, 4, &mask, 4, &cx);
}
// shrd
opcode(c, 0x0f, 0xad);
modrm(c, 0xc0, b->low, b->high);
@ -2271,7 +2299,7 @@ unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
ResolvedPromise promise(32);
Assembler::Constant constant(&promise);
compareCR(c, aSize, &constant, aSize, a);
compareCR(c, aSize, &constant, aSize, &cx);
opcode(c, 0x7c); //jl
c->code.append(2 + 2);
@ -2280,6 +2308,8 @@ unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
moveRR(c, 4, &bh, 4, b); // 2 bytes
xorRR(c, 4, &bh, 4, &bh); // 2 bytes
} else {
assert(c, a->low == rcx);
maybeRex(c, bSize, a, b);
opcode(c, 0xd3, 0xe8 + regCode(b));
}
@ -2781,7 +2811,7 @@ class MyArchitecture: public Assembler::Architecture {
}
virtual unsigned frameFootprint(unsigned footprint) {
#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS
#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE
return max(footprint, StackAlignmentInWords);
#else
return max(footprint > argumentRegisterCount() ?
@ -2803,7 +2833,7 @@ class MyArchitecture: public Assembler::Architecture {
}
virtual unsigned argumentRegisterCount() {
#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS
#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE
if (TargetBytesPerWord == 8) return 4; else
#else
if (TargetBytesPerWord == 8) return 6; else
@ -2814,7 +2844,7 @@ class MyArchitecture: public Assembler::Architecture {
virtual int argumentRegister(unsigned index) {
assert(&c, TargetBytesPerWord == 8);
switch (index) {
#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS
#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE
case 0:
return rcx;
case 1:
@ -3064,7 +3094,11 @@ class MyArchitecture: public Assembler::Architecture {
break;
case Float2Int:
if (useSSE(&c) and bSize <= TargetBytesPerWord) {
// todo: Java requires different semantics than SSE for
// converting floats to integers, we we need to either use
// thunks or produce inline machine code which handles edge
// cases properly.
if (false and useSSE(&c) and bSize <= TargetBytesPerWord) {
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
| FloatRegisterMask;
@ -3228,7 +3262,7 @@ class MyArchitecture: public Assembler::Architecture {
virtual void planSource
(TernaryOperation op,
unsigned aSize, uint8_t *aTypeMask, uint64_t *aRegisterMask,
unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask,
unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask,
unsigned, bool* thunk)
{
*aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand);
@ -3298,10 +3332,16 @@ class MyArchitecture: public Assembler::Architecture {
case ShiftLeft:
case ShiftRight:
case UnsignedShiftRight: {
*aRegisterMask = (static_cast<uint64_t>(GeneralRegisterMask) << 32)
| (static_cast<uint64_t>(1) << rcx);
const uint32_t mask = GeneralRegisterMask & ~(1 << rcx);
*bRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
if (TargetBytesPerWord == 4 and bSize == 8) {
const uint32_t mask = GeneralRegisterMask & ~(1 << rcx);
*aRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
*bRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
} else {
*aRegisterMask = (static_cast<uint64_t>(GeneralRegisterMask) << 32)
| (static_cast<uint64_t>(1) << rcx);
const uint32_t mask = GeneralRegisterMask & ~(1 << rcx);
*bRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
}
} break;
case JumpIfFloatEqual:

View File

@ -64,6 +64,18 @@
# define FRAME_REGISTER(context) \
THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss))
# elif (defined __QNX__)
# define IP_REGISTER(context) (context->uc_mcontext.cpu.eip)
# define STACK_REGISTER(context) (context->uc_mcontext.cpu.esp)
# define THREAD_REGISTER(context) (context->uc_mcontext.cpu.ebx)
# define LINK_REGISTER(context) (context->uc_mcontext.cpu.ecx)
# define FRAME_REGISTER(context) (context->uc_mcontext.cpu.ebp)
# elif (defined __FreeBSD__)
# define IP_REGISTER(context) (context->uc_mcontext.mc_eip)
# define STACK_REGISTER(context) (context->uc_mcontext.mc_esp)
# define THREAD_REGISTER(context) (context->uc_mcontext.mc_ebx)
# define LINK_REGISTER(context) (context->uc_mcontext.mc_ecx)
# define FRAME_REGISTER(context) (context->uc_mcontext.mc_ebp)
# else
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP])
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP])
@ -111,6 +123,12 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*,
# define FRAME_REGISTER(context) \
THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss))
# elif (defined __FreeBSD__)
# define IP_REGISTER(context) (context->uc_mcontext.mc_rip)
# define STACK_REGISTER(context) (context->uc_mcontext.mc_rsp)
# define THREAD_REGISTER(context) (context->uc_mcontext.mc_rbx)
# define LINK_REGISTER(context) (context->uc_mcontext.mc_rcx)
# define FRAME_REGISTER(context) (context->uc_mcontext.mc_rbp)
# else
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP])

View File

@ -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;
};

View File

@ -85,14 +85,14 @@ public class Arrays {
a[0] = new Object();
expect(! java.util.Arrays.equals(a, b));
expect(! java.util.Arrays.equals(b, new Object[4]));
expect(! java.util.Arrays.equals(b, null));
expect(! java.util.Arrays.equals(a, b));
expect(java.util.Arrays.equals(null, null));
expect(! java.util.Arrays.equals(a, null));
expect(! java.util.Arrays.equals(null, b));
expect(java.util.Arrays.equals((Object[])null, (Object[])null));
b[0] = a[0];
expect(java.util.Arrays.equals(a, b));
java.util.Arrays.hashCode(a);
java.util.Arrays.hashCode(null);
java.util.Arrays.hashCode((Object[])null);
}
}
}

109
test/Buffers.java Normal file
View File

@ -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);
}
}

88
test/Datagrams.java Normal file
View File

@ -0,0 +1,88 @@
import java.net.SocketAddress;
import java.net.InetSocketAddress;
import java.net.ProtocolFamily;
import java.net.StandardProtocolFamily;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.Selector;
import java.nio.channels.SelectionKey;
public class Datagrams {
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
private static boolean equal(byte[] a, int aOffset, byte[] b, int bOffset,
int length)
{
for (int i = 0; i < length; ++i) {
if (a[aOffset + i] != b[bOffset + i]) return false;
}
return true;
}
public static void main(String[] args) throws Exception {
final String Hostname = "localhost";
final int Port = 22043;
final SocketAddress Address = new InetSocketAddress(Hostname, Port);
final byte[] Message = "hello, world!".getBytes();
DatagramChannel out = DatagramChannel.open();
try {
out.configureBlocking(false);
out.connect(Address);
DatagramChannel in = DatagramChannel.open();
try {
in.configureBlocking(false);
in.socket().bind(Address);
Selector selector = Selector.open();
try {
SelectionKey outKey = out.register
(selector, SelectionKey.OP_WRITE, null);
SelectionKey inKey = in.register
(selector, SelectionKey.OP_READ, null);
int state = 0;
ByteBuffer inBuffer = ByteBuffer.allocate(Message.length);
loop: while (true) {
selector.select();
switch (state) {
case 0: {
if (outKey.isWritable()) {
out.write(ByteBuffer.wrap(Message));
state = 1;
}
} break;
case 1: {
if (inKey.isReadable()) {
in.receive(inBuffer);
if (! inBuffer.hasRemaining()) {
expect(equal(inBuffer.array(),
inBuffer.arrayOffset(),
Message,
0,
Message.length));
break loop;
}
}
} break;
default: throw new RuntimeException();
}
}
} finally {
selector.close();
}
} finally {
in.close();
}
} finally {
out.close();
}
}
}

View File

@ -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);
}
}

View File

@ -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); }
}
}

View File

@ -20,7 +20,7 @@ public class Integers {
return m;
}
public static void main(String[] args) {
public static void main(String[] args) throws Exception {
{ int foo = 1028;
foo -= 1023;
expect(foo == 5);
@ -262,9 +262,57 @@ public class Integers {
expect(bytesPerLine == 24);
}
int y = -11760768;
expect((y + 0x8000) == (-11760768 + 0x8000));
{ int y = -11760768;
expect((y + 0x8000) == (-11760768 + 0x8000)); }
expect(Math.min(796, 1069) == 796);
{ int b = 1;
expect((b << 32) == 1); }
{ int b = 0xFFFFFFFF;
expect((b >>> -1) == 1); }
{ int b = 0x10000000;
expect((b >> -31) == 0x8000000); }
{ int b = 1; int s = 32;
expect((b << s) == 1); }
{ int b = 0xFFFFFFFF; int s = -1;
expect((b >>> s) == 1); }
{ int b = 0x10000000; int s = -31;
expect((b >> s) == 0x8000000); }
{ int b = 0xBE;
expect((b & 0xFF) == 0xBE); }
{ int b = 0xBE;
expect((b >>> 0) == 0xBE); }
{ int b = 0xBE;
expect((b >> 0) == 0xBE); }
{ int b = 0xBE;
expect((b << 0) == 0xBE); }
{ int b = 0xBE;
expect(((b >>> 0) & 0xFF) == 0xBE); }
{ int b = 0xBE; int x = 0xFF;
expect((b & x) == 0xBE); }
{ int b = 0xBE; int x = 0;
expect((b >>> x) == 0xBE); }
{ int b = 0xBE; int x = 0;
expect((b >> x) == 0xBE); }
{ int b = 0xBE; int x = 0;
expect((b << x) == 0xBE); }
{ int b = 0xBE; int x = 0; int y = 0xFF;
expect(((b >>> x) & y) == 0xBE); }
}
}

59
test/JNI.java Normal file
View File

@ -0,0 +1,59 @@
public class JNI {
static {
System.loadLibrary("test");
}
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
private static float echo(float f) {
return f;
}
private static native float doEcho(float f);
private static double echo(double f) {
return f;
}
private static native double doEcho(double f);
private static native double addDoubles
(double a1, double a2, double a3, double a4, double a5, double a6,
double a7, double a8, double a9, double a10, double a11, double a12,
double a13, double a14, double a15, double a16, double a17, double a18,
double a19, double a20);
private static native float addFloats
(float a1, float a2, float a3, float a4, float a5, float a6,
float a7, float a8, float a9, float a10, float a11, float a12,
float a13, float a14, float a15, float a16, float a17, float a18,
float a19, float a20);
private static native double addMix
(float a1, double a2, float a3, double a4, float a5, float a6,
float a7, float a8, float a9, float a10, float a11, float a12,
float a13, float a14, float a15, double a16, float a17, float a18,
float a19, float a20);
public static void main(String[] args) {
expect(addDoubles
(1.0d, 2.0d, 3.0d, 4.0d, 5.0d, 6.0d, 7.0d, 8.0d, 9.0d, 10.0d, 11.0d,
12.0d, 13.0d, 14.0d, 15.0d, 16.0d, 17.0d, 18.0d, 19.0d, 20.0d)
== 210.0d);
expect(addFloats
(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f,
12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f)
== 210.0f);
expect(addMix
(1.0f, 2.0d, 3.0f, 4.0d, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f,
12.0f, 13.0f, 14.0f, 15.0f, 16.0d, 17.0f, 18.0f, 19.0f, 20.0f)
== 210.0d);
expect(doEcho(42.0f) == 42.0f);
expect(doEcho(42.0d) == 42.0d);
}
}

View File

@ -337,6 +337,58 @@ public class Longs {
expect(z[0] == 337192406);
expect(z[1] == -437261072);
}
{ long b = 1;
expect((b << 64) == 1); }
{ long b = 0xFFFFFFFFFFFFFFFFL;
expect((b >>> -1) == 1); }
{ long b = 0x10000000000L;
expect((b >> -63) == 0x8000000000L); }
{ long b = 1; int s = 64;
expect((b << s) == 1); }
{ long b = 0xFFFFFFFFFFFFFFFFL; int s = -1;
expect((b >>> s) == 1); }
{ long b = 0x10000000000L; int s = -63;
expect((b >> s) == 0x8000000000L); }
{ long b = 0xBEL;
expect((b & 0xFF) == 0xBEL); }
{ long b = 0xBEL;
expect((b >>> 0) == 0xBEL); }
{ long b = 0xBEL;
expect((b >> 0) == 0xBEL); }
{ long b = 0xBEL;
expect((b << 0) == 0xBEL); }
{ long b = 0xBEL;
expect(((b >>> 0) & 0xFF) == 0xBEL); }
{ long b = 0xBEL; int x = 0xFF;
expect((b & x) == 0xBEL); }
{ long b = 0xBEL; int x = 0;
expect((b >>> x) == 0xBEL); }
{ long b = 0xBEL; int x = 0;
expect((b >> x) == 0xBEL); }
{ long b = 0xBEL; int x = 0;
expect((b << x) == 0xBEL); }
{ long b = 0xBEL; int x = 0; int y = 0xFF;
expect(((b >>> x) & y) == 0xBEL); }
{ long b = 0xFFFFFFFFFFFFFFFFL; int s = 20;
expect((b >>> -s) == 0xFFFFF);
}
}
}

View File

@ -21,7 +21,66 @@ public class Strings {
return true;
}
public static void main(String[] args) {
private static void testDecode(final boolean prematureEOS) throws Exception {
java.io.Reader r = new java.io.InputStreamReader
(new java.io.InputStream() {
int state = 0;
public int read() {
throw new UnsupportedOperationException();
}
public int read(byte[] b, int offset, int length) {
if (length == 0) return 0;
switch (state) {
case 0:
b[offset] = (byte) 0xc2;
state = 1;
return 1;
case 1:
b[offset] = (byte) 0xae;
state = 2;
return 1;
case 2:
b[offset] = (byte) 0xea;
state = 3;
return 1;
case 3:
b[offset] = (byte) 0xba;
state = prematureEOS ? 5 : 4;
return 1;
case 4:
b[offset] = (byte) 0xaf;
state = 5;
return 1;
case 5:
return -1;
default:
throw new RuntimeException();
}
}
}, "UTF-8");
char[] buffer = new char[2];
int offset = 0;
while (offset < buffer.length) {
int c = r.read(buffer, offset, buffer.length - offset);
if (c == -1) break;
offset += c;
}
expect(new String(buffer, 0, offset).equals
(prematureEOS ? "\u00ae\ufffd" : "\u00ae\uaeaf"));
}
public static void main(String[] args) throws Exception {
expect(new String(new byte[] { 99, 111, 109, 46, 101, 99, 111, 118, 97,
116, 101, 46, 110, 97, 116, 46, 98, 117,
115, 46, 83, 121, 109, 98, 111, 108 })
@ -77,5 +136,15 @@ public class Strings {
expect(Character.forDigit(Character.digit('b', 16), 16) == 'b');
expect(Character.forDigit(Character.digit('f', 16), 16) == 'f');
expect(Character.forDigit(Character.digit('z', 36), 36) == 'z');
testDecode(false);
testDecode(true);
expect
(java.text.MessageFormat.format
("{0} enjoy {1} {2}. do {4}? {4} do?",
"I", "grape", "nuts", "foobar",
new Object() { public String toString() { return "you"; } })
.equals("I enjoy grape nuts. do you? you do?"));
}
}

73
test/jni.cpp Normal file
View File

@ -0,0 +1,73 @@
#include <jni.h>
#include "jni-util.h"
extern "C" JNIEXPORT jdouble JNICALL
Java_JNI_addDoubles
(JNIEnv*, jclass,
jdouble a1, jdouble a2, jdouble a3, jdouble a4, jdouble a5, jdouble a6,
jdouble a7, jdouble a8, jdouble a9, jdouble a10, jdouble a11, jdouble a12,
jdouble a13, jdouble a14, jdouble a15, jdouble a16, jdouble a17, jdouble a18,
jdouble a19, jdouble a20)
{
return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13
+ a14 + a15 + a16 + a17 + a18 + a19 + a20;
}
extern "C" JNIEXPORT jfloat JNICALL
Java_JNI_addFloats
(JNIEnv*, jclass,
jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6,
jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12,
jfloat a13, jfloat a14, jfloat a15, jfloat a16, jfloat a17, jfloat a18,
jfloat a19, jfloat a20)
{
return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13
+ a14 + a15 + a16 + a17 + a18 + a19 + a20;
}
extern "C" JNIEXPORT jdouble JNICALL
Java_JNI_addMix
(JNIEnv*, jclass,
jfloat a1, jdouble a2, jfloat a3, jdouble a4, jfloat a5, jfloat a6,
jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12,
jfloat a13, jfloat a14, jfloat a15, jdouble a16, jfloat a17, jfloat a18,
jfloat a19, jfloat a20)
{
return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13
+ a14 + a15 + a16 + a17 + a18 + a19 + a20;
}
extern "C" JNIEXPORT jfloat JNICALL
Java_JNI_doEcho__F(JNIEnv* e, jclass c, jfloat f)
{
jvalue value;
value.f = f;
jvalue array[] = { value };
return e->CallStaticFloatMethodA
(c, e->GetStaticMethodID(c, "echo", "(F)F"), array);
}
extern "C" JNIEXPORT jdouble JNICALL
Java_JNI_doEcho__D(JNIEnv* e, jclass c, jdouble f)
{
jvalue value;
value.d = f;
jvalue array[] = { value };
return e->CallStaticDoubleMethodA
(c, e->GetStaticMethodID(c, "echo", "(D)D"), array);
}
extern "C" JNIEXPORT jobject JNICALL
Java_Buffers_allocateNative(JNIEnv* e, jclass, jint capacity)
{
void* p = allocate(e, capacity);
if (p == 0) return 0;
return e->NewDirectByteBuffer(p, capacity);
}
extern "C" JNIEXPORT void JNICALL
Java_Buffers_freeNative(JNIEnv* e, jclass, jobject b)
{
free(e->GetDirectBufferAddress(b));
}