mirror of
https://github.com/corda/corda.git
synced 2025-01-19 11:16:54 +00:00
Merge branch 'master' of github.com:ReadyTalk/avian
This commit is contained in:
commit
33fed1b710
@ -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)) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
17
classpath/java/lang/Deprecated.java
Normal file
17
classpath/java/lang/Deprecated.java
Normal 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 { }
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
19
classpath/java/net/DatagramSocket.java
Normal file
19
classpath/java/net/DatagramSocket.java
Normal 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;
|
||||
}
|
13
classpath/java/net/ProtocolFamily.java
Normal file
13
classpath/java/net/ProtocolFamily.java
Normal 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 { }
|
15
classpath/java/net/StandardProtocolFamily.java
Normal file
15
classpath/java/net/StandardProtocolFamily.java
Normal 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;
|
||||
}
|
@ -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)) {
|
||||
|
92
classpath/java/nio/ArrayByteBuffer.java
Normal file
92
classpath/java/nio/ArrayByteBuffer.java
Normal 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 + ")";
|
||||
}
|
||||
}
|
@ -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() + ")";
|
||||
}
|
||||
}
|
||||
|
105
classpath/java/nio/DirectByteBuffer.java
Normal file
105
classpath/java/nio/DirectByteBuffer.java
Normal 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 + ")";
|
||||
}
|
||||
}
|
58
classpath/java/nio/FixedArrayByteBuffer.java
Normal file
58
classpath/java/nio/FixedArrayByteBuffer.java
Normal 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 + ")";
|
||||
}
|
||||
}
|
180
classpath/java/nio/channels/DatagramChannel.java
Normal file
180
classpath/java/nio/channels/DatagramChannel.java
Normal 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;
|
||||
}
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
109
makefile
@ -5,6 +5,8 @@ version = 0.6
|
||||
|
||||
build-arch := $(shell uname -m \
|
||||
| sed 's/^i.86$$/i386/' \
|
||||
| sed 's/^x86pc$$/i386/' \
|
||||
| sed 's/amd64/x86_64/' \
|
||||
| sed 's/^arm.*$$/arm/' \
|
||||
| sed 's/ppc/powerpc/')
|
||||
|
||||
@ -22,7 +24,6 @@ target-arch = $(arch)
|
||||
bootimage-platform = \
|
||||
$(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))
|
||||
platform = $(bootimage-platform)
|
||||
target-platform = $(platform)
|
||||
|
||||
mode = fast
|
||||
process = compile
|
||||
@ -85,6 +86,8 @@ ifeq ($(build-platform),darwin)
|
||||
library-path-variable = DYLD_LIBRARY_PATH
|
||||
endif
|
||||
|
||||
library-path = $(library-path-variable)=$(build)
|
||||
|
||||
ifneq ($(openjdk),)
|
||||
openjdk-arch = $(arch)
|
||||
ifeq ($(arch),x86_64)
|
||||
@ -161,6 +164,8 @@ ifneq ($(platform),darwin)
|
||||
endif
|
||||
endif
|
||||
|
||||
target-format = elf
|
||||
|
||||
cxx = $(build-cxx) $(mflag)
|
||||
cc = $(build-cc) $(mflag)
|
||||
|
||||
@ -186,9 +191,10 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
|
||||
|
||||
target-cflags = -DTARGET_BYTES_PER_WORD=$(pointer-size)
|
||||
|
||||
common-cflags = $(warnings) -fno-rtti -fno-exceptions \
|
||||
common-cflags = $(warnings) -fno-rtti -fno-exceptions -I$(classpath-src) \
|
||||
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \
|
||||
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
||||
-DAVIAN_INFO="\"$(info)\"" \
|
||||
-DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \
|
||||
-DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" $(target-cflags)
|
||||
|
||||
@ -207,7 +213,7 @@ build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
||||
converter-cflags = -D__STDC_CONSTANT_MACROS -Isrc/binaryToObject -Isrc/ \
|
||||
-fno-rtti -fno-exceptions \
|
||||
-DAVIAN_TARGET_ARCH=AVIAN_ARCH_UNKNOWN \
|
||||
-DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_UNKNOWN \
|
||||
-DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_UNKNOWN \
|
||||
-Wall -Wextra -Werror -Wunused-parameter -Winit-self -Wno-non-virtual-dtor
|
||||
|
||||
cflags = $(build-cflags)
|
||||
@ -218,6 +224,7 @@ build-lflags = -lz -lpthread -ldl
|
||||
|
||||
lflags = $(common-lflags) -lpthread -ldl
|
||||
|
||||
soname-flag = -Wl,-soname -Wl,$(so-prefix)jvm$(so-suffix)
|
||||
version-script-flag = -Wl,--version-script=openjdk.ld
|
||||
|
||||
build-system = posix
|
||||
@ -284,8 +291,13 @@ ifeq ($(arch),arm)
|
||||
ifneq ($(arch),$(build-arch))
|
||||
ifeq ($(platform),darwin)
|
||||
ios-bin = $(developer-dir)/Platforms/iPhoneOS.platform/Developer/usr/bin
|
||||
cxx = $(ios-bin)/g++
|
||||
cc = $(ios-bin)/gcc
|
||||
ifeq ($(use-clang),true)
|
||||
cxx = clang -std=c++11
|
||||
cc = clang
|
||||
else
|
||||
cxx = $(ios-bin)/g++
|
||||
cc = $(ios-bin)/gcc
|
||||
endif
|
||||
ar = $(ios-bin)/ar
|
||||
ranlib = $(ios-bin)/ranlib
|
||||
strip = $(ios-bin)/strip
|
||||
@ -305,11 +317,45 @@ endif
|
||||
|
||||
ifeq ($(build-platform),darwin)
|
||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
|
||||
cflags += -I/System/Library/Frameworks/JavaVM.framework/Headers/
|
||||
cflags += -I/System/Library/Frameworks/JavaVM.framework/Headers/ \
|
||||
-Wno-deprecated-declarations
|
||||
build-lflags += -framework CoreFoundation
|
||||
soname-flag =
|
||||
endif
|
||||
|
||||
ifeq ($(platform),qnx)
|
||||
cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
|
||||
lflags = $(common-lflags) -lsocket
|
||||
ifeq ($(build-platform),qnx)
|
||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
|
||||
build-lflags = $(common-lflags)
|
||||
else
|
||||
ifeq ($(arch),i386)
|
||||
prefix = i486-pc-nto-qnx6.5.0-
|
||||
else
|
||||
prefix = arm-unknown-nto-qnx6.5.0-
|
||||
endif
|
||||
endif
|
||||
cxx = $(prefix)g++
|
||||
cc = $(prefix)gcc
|
||||
ar = $(prefix)ar
|
||||
ranlib = $(prefix)ranlib
|
||||
strip = $(prefix)strip
|
||||
rdynamic = -Wl,--export-dynamic
|
||||
endif
|
||||
|
||||
ifeq ($(platform),freebsd)
|
||||
# There is no -ldl on FreeBSD
|
||||
build-lflags = $(common-lflags) -lz -lpthread
|
||||
lflags = $(common-lflags) -lpthread
|
||||
# include/freebsd instead of include/linux
|
||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
||||
"-I$(JAVA_HOME)/include/freebsd" -I$(src) -pthread
|
||||
cflags = $(build-cflags)
|
||||
endif
|
||||
|
||||
ifeq ($(platform),darwin)
|
||||
target-format = macho
|
||||
ifeq (${OSX_SDK_SYSROOT},)
|
||||
OSX_SDK_SYSROOT = 10.4u
|
||||
endif
|
||||
@ -350,7 +396,8 @@ ifeq ($(platform),darwin)
|
||||
|
||||
ifeq ($(arch),arm)
|
||||
ios-version := \
|
||||
$(shell if test -d $(sdk-dir)/iPhoneOS5.1.sdk; then echo 5.1; \
|
||||
$(shell if test -d $(sdk-dir)/iPhoneOS6.0.sdk; then echo 6.0; \
|
||||
elif test -d $(sdk-dir)/iPhoneOS5.1.sdk; then echo 5.1; \
|
||||
elif test -d $(sdk-dir)/iPhoneOS5.0.sdk; then echo 5.0; \
|
||||
elif test -d $(sdk-dir)/iPhoneOS4.3.sdk; then echo 4.3; \
|
||||
elif test -d $(sdk-dir)/iPhoneOS4.2.sdk; then echo 4.2; \
|
||||
@ -391,6 +438,8 @@ ifeq ($(platform),darwin)
|
||||
endif
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
target-format = pe
|
||||
|
||||
inc = "$(win32)/include"
|
||||
lib = "$(win32)/lib"
|
||||
|
||||
@ -527,7 +576,8 @@ ifdef msvc
|
||||
cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \
|
||||
-DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \
|
||||
-DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \
|
||||
-Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I"$(build)" \
|
||||
-Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I$(classpath-src) \
|
||||
-I"$(build)" \
|
||||
-I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" \
|
||||
-DTARGET_BYTES_PER_WORD=$(pointer-size)
|
||||
|
||||
@ -756,7 +806,7 @@ ifneq ($(classpath),avian)
|
||||
$(classpath-src)/avian/VMClass.java \
|
||||
$(classpath-src)/avian/VMField.java \
|
||||
$(classpath-src)/avian/VMMethod.java \
|
||||
$(classpath-src)/avian/resource/Handler.java
|
||||
$(classpath-src)/avian/avianvmresource/Handler.java
|
||||
|
||||
ifneq ($(openjdk),)
|
||||
classpath-sources := $(classpath-sources) \
|
||||
@ -777,9 +827,12 @@ vm-classes = \
|
||||
|
||||
test-support-sources = $(shell find $(test)/avian/ -name '*.java')
|
||||
test-sources = $(wildcard $(test)/*.java)
|
||||
test-cpp-sources = $(wildcard $(test)/*.cpp)
|
||||
test-sources += $(test-support-sources)
|
||||
test-support-classes = $(call java-classes, $(test-support-sources),$(test),$(test-build))
|
||||
test-classes = $(call java-classes,$(test-sources),$(test),$(test-build))
|
||||
test-cpp-objects = $(call cpp-objects,$(test-cpp-sources),$(test),$(test-build))
|
||||
test-library = $(build)/$(so-prefix)test$(so-suffix)
|
||||
test-dep = $(test-build).dep
|
||||
|
||||
test-extra-sources = $(wildcard $(test)/extra/*.java)
|
||||
@ -815,22 +868,22 @@ ifeq ($(target-arch),arm)
|
||||
cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM
|
||||
endif
|
||||
|
||||
ifeq ($(target-platform),linux)
|
||||
cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_LINUX
|
||||
ifeq ($(target-format),elf)
|
||||
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_ELF
|
||||
endif
|
||||
|
||||
ifeq ($(target-platform),windows)
|
||||
cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_WINDOWS
|
||||
ifeq ($(target-format),pe)
|
||||
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_PE
|
||||
endif
|
||||
|
||||
ifeq ($(target-platform),darwin)
|
||||
cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_DARWIN
|
||||
ifeq ($(target-format),macho)
|
||||
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_MACHO
|
||||
endif
|
||||
|
||||
class-name = $(patsubst $(1)/%.class,%,$(2))
|
||||
class-names = $(foreach x,$(2),$(call class-name,$(1),$(x)))
|
||||
|
||||
test-flags = -cp $(build)/test
|
||||
test-flags = -Djava.library.path=$(build) -cp $(build)/test
|
||||
|
||||
test-args = $(test-flags) $(input)
|
||||
|
||||
@ -904,7 +957,7 @@ $(classpath-dep): $(classpath-sources)
|
||||
$(test-build)/%.class: $(test)/%.java
|
||||
@echo $(<)
|
||||
|
||||
$(test-dep): $(test-sources)
|
||||
$(test-dep): $(test-sources) $(test-library)
|
||||
@echo "compiling test classes"
|
||||
@mkdir -p $(test-build)
|
||||
files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \
|
||||
@ -939,6 +992,19 @@ endef
|
||||
$(vm-cpp-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends)
|
||||
$(compile-object)
|
||||
|
||||
$(test-cpp-objects): $(test-build)/%.o: $(test)/%.cpp $(vm-depends)
|
||||
$(compile-object)
|
||||
|
||||
$(test-library): $(test-cpp-objects)
|
||||
@echo "linking $(@)"
|
||||
ifdef msvc
|
||||
$(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \
|
||||
-IMPLIB:$(test-build)/$(name).lib -MANIFESTFILE:$(@).manifest
|
||||
$(mt) -manifest $(@).manifest -outputresource:"$(@);2"
|
||||
else
|
||||
$(ld) $(^) $(shared) $(lflags) -o $(@)
|
||||
endif
|
||||
|
||||
$(build)/%.o: $(lzma)/C/%.c
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p $(dir $(@))
|
||||
@ -994,7 +1060,7 @@ $(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep)
|
||||
$(classpath-object): $(build)/classpath.jar $(converter)
|
||||
@echo "creating $(@)"
|
||||
$(converter) $(<) $(@) _binary_classpath_jar_start \
|
||||
_binary_classpath_jar_end $(platform) $(arch)
|
||||
_binary_classpath_jar_end $(target-format) $(arch)
|
||||
|
||||
$(build)/javahome.jar:
|
||||
@echo "creating $(@)"
|
||||
@ -1005,7 +1071,7 @@ $(build)/javahome.jar:
|
||||
$(javahome-object): $(build)/javahome.jar $(converter)
|
||||
@echo "creating $(@)"
|
||||
$(converter) $(<) $(@) _binary_javahome_jar_start \
|
||||
_binary_javahome_jar_end $(platform) $(arch)
|
||||
_binary_javahome_jar_end $(target-format) $(arch)
|
||||
|
||||
define compile-generator-object
|
||||
@echo "compiling $(@)"
|
||||
@ -1066,7 +1132,7 @@ $(bootimage-generator): $(bootimage-generator-objects)
|
||||
arch=$(build-arch) \
|
||||
target-arch=$(arch) \
|
||||
platform=$(bootimage-platform) \
|
||||
target-platform=$(platform) \
|
||||
target-format=$(target-format) \
|
||||
openjdk=$(openjdk) \
|
||||
openjdk-src=$(openjdk-src) \
|
||||
bootimage-generator= \
|
||||
@ -1104,7 +1170,8 @@ ifdef msvc
|
||||
-IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest
|
||||
$(mt) -manifest $(@).manifest -outputresource:"$(@);2"
|
||||
else
|
||||
$(ld) $(^) $(version-script-flag) $(shared) $(lflags) $(bootimage-lflags) \
|
||||
$(ld) $(^) $(version-script-flag) $(soname-flag) \
|
||||
$(shared) $(lflags) $(bootimage-lflags) \
|
||||
-o $(@)
|
||||
endif
|
||||
$(strip) $(strip-all) $(@)
|
||||
|
@ -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
|
||||
|
43
src/arm.S
43
src/arm.S
@ -1,4 +1,4 @@
|
||||
/* arm.S: JNI gluecode for ARM/Linux
|
||||
/* arm.S: JNI gluecode for ARM
|
||||
Copyright (c) 2008-2011, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
@ -9,6 +9,8 @@
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#include "types.h"
|
||||
|
||||
.text
|
||||
|
||||
#define LOCAL(x) .L##x
|
||||
@ -29,14 +31,18 @@ GLOBAL(vmNativeCall):
|
||||
r2 : memoryTable
|
||||
r3 : memoryCount
|
||||
[sp, #0] -> r6 : gprTable
|
||||
[sp, #4] -> r7 : vfpTable
|
||||
[sp, #8] -> r8 : returnType
|
||||
*/
|
||||
mov ip, sp // save stack frame
|
||||
stmfd sp!, {r4-r6, lr} // save clobbered non-volatile regs
|
||||
stmfd sp!, {r4-r8, lr} // save clobbered non-volatile regs
|
||||
|
||||
// mv args into non-volatile regs
|
||||
mov r4, r0
|
||||
mov r5, r1
|
||||
ldr r6, [ip]
|
||||
ldr r7, [ip, #4]
|
||||
ldr r8, [ip, #8]
|
||||
|
||||
// setup stack arguments if necessary
|
||||
sub sp, sp, r5 // allocate stack
|
||||
@ -50,12 +56,38 @@ LOCAL(loop):
|
||||
|
||||
// setup argument registers if necessary
|
||||
tst r6, r6
|
||||
#if (defined __APPLE__) && (defined __clang_major__) && (__clang_major__ >= 4)
|
||||
ldmiane r6, {r0-r3}
|
||||
#else
|
||||
ldmneia r6, {r0-r3}
|
||||
#endif
|
||||
#if defined(__ARM_PCS_VFP)
|
||||
// and VFP registers
|
||||
vldmia r7, {d0-d7}
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||
mov lr, pc
|
||||
bx r4
|
||||
#else
|
||||
blx r4 // call function
|
||||
#endif
|
||||
add sp, sp, r5 // deallocate stack
|
||||
|
||||
ldmfd sp!, {r4-r6, pc} // restore non-volatile regs and return
|
||||
#if defined(__ARM_PCS_VFP)
|
||||
cmp r8,#FLOAT_TYPE
|
||||
bne LOCAL(double)
|
||||
fmrs r0,s0
|
||||
b LOCAL(exit)
|
||||
|
||||
LOCAL(double):
|
||||
cmp r8,#DOUBLE_TYPE
|
||||
bne LOCAL(exit)
|
||||
fmrrd r0,r1,d0
|
||||
#endif
|
||||
|
||||
LOCAL(exit):
|
||||
ldmfd sp!, {r4-r8, pc} // restore non-volatile regs and return
|
||||
|
||||
.globl GLOBAL(vmJump)
|
||||
.align 2
|
||||
@ -85,7 +117,12 @@ GLOBAL(vmRun):
|
||||
mov r12, r0
|
||||
ldr r0, [r2, #CHECKPOINT_THREAD]
|
||||
|
||||
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||
mov lr, pc
|
||||
bx r12
|
||||
#else
|
||||
blx r12
|
||||
#endif
|
||||
|
||||
.globl GLOBAL(vmRun_returnAddress)
|
||||
.align 2
|
||||
|
226
src/arm.cpp
226
src/arm.cpp
@ -49,12 +49,6 @@ inline int XFER2(int cond, int P, int U, int W, int L, int Rn, int Rd, int S, in
|
||||
{ return cond<<28 | P<<24 | U<<23 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | 1<<7 | S<<6 | H<<5 | 1<<4 | Rm; }
|
||||
inline int XFER2I(int cond, int P, int U, int W, int L, int Rn, int Rd, int offsetH, int S, int H, int offsetL)
|
||||
{ return cond<<28 | P<<24 | U<<23 | 1<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offsetH<<8 | 1<<7 | S<<6 | H<<5 | 1<<4 | (offsetL&0xf); }
|
||||
inline int BLOCKXFER(int cond, int P, int U, int S, int W, int L, int Rn, int rlist)
|
||||
{ return cond<<28 | 4<<25 | P<<24 | U<<23 | S<<22 | W<<21 | L<<20 | Rn<<16 | rlist; }
|
||||
inline int SWI(int cond, int imm)
|
||||
{ return cond<<28 | 0x0f<<24 | (imm&0xffffff); }
|
||||
inline int SWAP(int cond, int B, int Rn, int Rd, int Rm)
|
||||
{ return cond<<28 | 1<<24 | B<<22 | Rn<<16 | Rd<<12 | 9<<4 | Rm; }
|
||||
inline int COOP(int cond, int opcode_1, int CRn, int CRd, int cp_num, int opcode_2, int CRm)
|
||||
{ return cond<<28 | 0xe<<24 | opcode_1<<20 | CRn<<16 | CRd<<12 | cp_num<<8 | opcode_2<<5 | CRm; }
|
||||
inline int COXFER(int cond, int P, int U, int N, int W, int L, int Rn, int CRd, int cp_num, int offset) // offset is in words, not bytes
|
||||
@ -71,41 +65,29 @@ inline int b(int offset) { return BRANCH(AL, 0, offset); }
|
||||
inline int bl(int offset) { return BRANCH(AL, 1, offset); }
|
||||
inline int bx(int Rm) { return BRANCHX(AL, 0, Rm); }
|
||||
inline int blx(int Rm) { return BRANCHX(AL, 1, Rm); }
|
||||
inline int swi(int imm) { return SWI(AL, imm); }
|
||||
inline int and_(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x0, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int eor(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x1, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int sub(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x2, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int rsb(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x3, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int add(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x4, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int adc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x5, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int sbc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x6, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int rsc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x7, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int tst(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x8, 1, Rn, 0, shift, Sh, Rm); }
|
||||
inline int teq(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x9, 1, Rn, 0, shift, Sh, Rm); }
|
||||
inline int cmp(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xa, 1, Rn, 0, shift, Sh, Rm); }
|
||||
inline int cmn(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xb, 1, Rn, 0, shift, Sh, Rm); }
|
||||
inline int orr(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xc, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int mov(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xd, 0, 0, Rd, shift, Sh, Rm); }
|
||||
inline int bic(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xe, 0, Rn, Rd, shift, Sh, Rm); }
|
||||
inline int mvn(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xf, 0, 0, Rd, shift, Sh, Rm); }
|
||||
inline int andi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x0, 0, Rn, Rd, rot, imm); }
|
||||
inline int eori(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x1, 0, Rn, Rd, rot, imm); }
|
||||
inline int subi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x2, 0, Rn, Rd, rot, imm); }
|
||||
inline int rsbi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x3, 0, Rn, Rd, rot, imm); }
|
||||
inline int addi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x4, 0, Rn, Rd, rot, imm); }
|
||||
inline int adci(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x5, 0, Rn, Rd, rot, imm); }
|
||||
inline int bici(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xe, 0, Rn, Rd, rot, imm); }
|
||||
inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0xa, 1, Rn, 0, rot, imm); }
|
||||
inline int orri(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xc, 0, Rn, Rd, rot, imm); }
|
||||
inline int movi(int Rd, int imm, int rot=0) { return DATAI(AL, 0xd, 0, 0, Rd, rot, imm); }
|
||||
inline int orrsh(int Rd, int Rn, int Rm, int Rs, int Sh) { return DATAS(AL, 0xc, 0, Rn, Rd, Rs, Sh, Rm); }
|
||||
inline int movsh(int Rd, int Rm, int Rs, int Sh) { return DATAS(AL, 0xd, 0, 0, Rd, Rs, Sh, Rm); }
|
||||
inline int mul(int Rd, int Rm, int Rs) { return MULTIPLY(AL, 0, 0, Rd, 0, Rs, Rm); }
|
||||
inline int mla(int Rd, int Rm, int Rs, int Rn) { return MULTIPLY(AL, 1, 0, Rd, Rn, Rs, Rm); }
|
||||
inline int umull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, RdHi, RdLo, Rs, Rm); }
|
||||
inline int umlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 5, 0, RdHi, RdLo, Rs, Rm); }
|
||||
inline int smull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdHi, RdLo, Rs, Rm); }
|
||||
inline int smlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 7, 0, RdHi, RdLo, Rs, Rm); }
|
||||
inline int ldr(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 1, Rn, Rd, 0, 0, Rm); }
|
||||
inline int ldri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 1, Rn, Rd, abs(imm)); }
|
||||
inline int ldrb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 1, Rn, Rd, 0, 0, Rm); }
|
||||
@ -122,39 +104,19 @@ inline int ldrsh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd,
|
||||
inline int ldrshi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 1, abs(imm)&0xf); }
|
||||
inline int ldrsb(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 0, Rm); }
|
||||
inline int ldrsbi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 0, abs(imm)&0xf); }
|
||||
inline int pop(int Rd) { return XFERI(AL, 0, 1, 0, 0, 1, 13, Rd, 4); }
|
||||
inline int ldmfd(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 1, 1, Rn, rlist); }
|
||||
inline int stmfd(int Rn, int rlist) { return BLOCKXFER(AL, 1, 0, 0, 1, 0, Rn, rlist); }
|
||||
inline int swp(int Rd, int Rm, int Rn) { return SWAP(AL, 0, Rn, Rd, Rm); }
|
||||
inline int swpb(int Rd, int Rm, int Rn) { return SWAP(AL, 1, Rn, Rd, Rm); }
|
||||
// breakpoint instruction, this really has its own instruction format
|
||||
inline int bkpt(int16_t immed) { return 0xe1200070 | (((unsigned)immed & 0xffff) >> 4 << 8) | (immed & 0xf); }
|
||||
// COPROCESSOR INSTRUCTIONS
|
||||
inline int cdp(int coproc, int opcode_1, int CRd, int CRn, int CRm, int opcode_2) { return COOP(AL, opcode_1, CRn, CRd, coproc, opcode_2, CRm); }
|
||||
inline int mcr(int coproc, int opcode_1, int Rd, int CRn, int CRm, int opcode_2=0) { return COREG(AL, opcode_1, 0, CRn, Rd, coproc, opcode_2, CRm); }
|
||||
inline int mcrr(int coproc, int opcode, int Rd, int Rn, int CRm) { return COREG2(AL, 0, Rn, Rd, coproc, opcode, CRm); }
|
||||
inline int mrc(int coproc, int opcode_1, int Rd, int CRn, int CRm, int opcode_2=0) { return COREG(AL, opcode_1, 1, CRn, Rd, coproc, opcode_2, CRm); }
|
||||
inline int mrrc(int coproc, int opcode, int Rd, int Rn, int CRm) { return COREG2(AL, 1, Rn, Rd, coproc, opcode, CRm); }
|
||||
inline int ldc(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 0, W, 1, Rn, CRd, coproc, offset); }
|
||||
inline int ldcl(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 1, W, 1, Rn, CRd, coproc, offset); }
|
||||
inline int stc(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 0, W, 0, Rn, CRd, coproc, offset); }
|
||||
inline int stcl(int coproc, int CRd, int Rn, int offset=0, int W=0) { return COXFER(AL, 1, 1, 1, W, 0, Rn, CRd, coproc, offset); }
|
||||
// VFP FLOATING-POINT INSTRUCTIONS
|
||||
inline int fmacs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
|
||||
inline int fnmacs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); }
|
||||
inline int fmscs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|1, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
|
||||
inline int fnmscs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|1, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); }
|
||||
inline int fmuls(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
|
||||
inline int fnmuls(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); }
|
||||
inline int fadds(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|3, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
|
||||
inline int fsubs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|3, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); }
|
||||
inline int fdivs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|8, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); }
|
||||
inline int fmacd(int Dd, int Dn, int Dm) { return COOP(AL, 0, Dn, Dd, 11, 0, Dm); }
|
||||
inline int fnmacd(int Dd, int Dn, int Dm) { return COOP(AL, 0, Dn, Dd, 11, 2, Dm); }
|
||||
inline int fmscd(int Dd, int Dn, int Dm) { return COOP(AL, 1, Dn, Dd, 11, 0, Dm); }
|
||||
inline int fnmscd(int Dd, int Dn, int Dm) { return COOP(AL, 1, Dn, Dd, 11, 2, Dm); }
|
||||
inline int fmuld(int Dd, int Dn, int Dm) { return COOP(AL, 2, Dn, Dd, 11, 0, Dm); }
|
||||
inline int fnmuld(int Dd, int Dn, int Dm) { return COOP(AL, 2, Dn, Dd, 11, 2, Dm); }
|
||||
inline int faddd(int Dd, int Dn, int Dm) { return COOP(AL, 3, Dn, Dd, 11, 0, Dm); }
|
||||
inline int fsubd(int Dd, int Dn, int Dm) { return COOP(AL, 3, Dn, Dd, 11, 2, Dm); }
|
||||
inline int fdivd(int Dd, int Dn, int Dm) { return COOP(AL, 8, Dn, Dd, 11, 0, Dm); }
|
||||
@ -163,15 +125,8 @@ inline int fabss(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0, Sd>>1, 10,
|
||||
inline int fnegs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 1, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
|
||||
inline int fsqrts(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 1, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
|
||||
inline int fcmps(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 4, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
|
||||
inline int fcmpes(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 4, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
|
||||
inline int fcmpzs(int Sd) { return COOP(AL, 0xb|(Sd&1)<<2, 5, Sd>>1, 10, 2, 0); }
|
||||
inline int fcmpezs(int Sd) { return COOP(AL, 0xb|(Sd&1)<<2, 5, Sd>>1, 10, 6, 0); }
|
||||
inline int fcvtds(int Dd, int Sm) { return COOP(AL, 0xb, 7, Dd, 10, 6|(Sm&1), Sm>>1); }
|
||||
inline int fuitos(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 8, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
|
||||
inline int fsitos(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 8, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
|
||||
inline int ftouis(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
|
||||
inline int ftouizs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
|
||||
inline int ftosis(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 10, 2|(Sm&1), Sm>>1); }
|
||||
inline int ftosizs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 10, 6|(Sm&1), Sm>>1); }
|
||||
inline int fcpyd(int Dd, int Dm) { return COOP(AL, 0xb, 0, Dd, 11, 2, Dm); }
|
||||
inline int fabsd(int Dd, int Dm) { return COOP(AL, 0xb, 0, Dd, 11, 6, Dm); }
|
||||
@ -179,24 +134,10 @@ inline int fnegd(int Dd, int Dm) { return COOP(AL, 0xb, 1, Dd, 11, 2, Dm); }
|
||||
inline int fsqrtd(int Dd, int Dm) { return COOP(AL, 0xb, 1, Dd, 11, 6, Dm); }
|
||||
// double-precision comparison instructions
|
||||
inline int fcmpd(int Dd, int Dm) { return COOP(AL, 0xb, 4, Dd, 11, 2, Dm); }
|
||||
inline int fcmped(int Dd, int Dm) { return COOP(AL, 0xb, 4, Dd, 11, 6, Dm); }
|
||||
inline int fcmpzd(int Dd) { return COOP(AL, 0xb, 5, Dd, 11, 2, 0); }
|
||||
inline int fcmpezd(int Dd) { return COOP(AL, 0xb, 5, Dd, 11, 6, 0); }
|
||||
// double-precision conversion instructions
|
||||
inline int fcvtsd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 7, Sd>>1, 11, 6, Dm); }
|
||||
inline int fuitod(int Dd, int Sm) { return COOP(AL, 0xb, 8, Dd, 11, 2|(Sm&1), Sm>>1); }
|
||||
inline int fsitod(int Dd, int Sm) { return COOP(AL, 0xb, 8, Dd, 11, 6|(Sm&1), Sm>>1); }
|
||||
inline int ftouid(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 11, 2, Dm); }
|
||||
inline int ftouizd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xc, Sd>>1, 11, 6, Dm); }
|
||||
inline int ftosid(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 11, 2, Dm); }
|
||||
inline int ftosizd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 11, 6, Dm); }
|
||||
// these are the multiple load/store analogs for VFP, useless for now
|
||||
inline int fldms(int Rn, int Sd, int count) { return COXFER(AL, 0, 1, Sd&1, 0, 1, Rn, Sd>>1, 10, count); }
|
||||
inline int fldmd(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 1, Rn, Dd, 11, count<<1); }
|
||||
inline int fldmx(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 1, Rn, Dd, 11, count<<1|1); }
|
||||
inline int fstms(int Rn, int Sd, int count) { return COXFER(AL, 0, 1, Sd&1, 0, 0, Rn, Sd>>1, 10, count); }
|
||||
inline int fstmd(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 0, Rn, Dd, 11, count<<1); }
|
||||
inline int fstmx(int Rn, int Dd, int count) { return COXFER(AL, 0, 1, 0, 0, 0, Rn, Dd, 11, count<<1|1); }
|
||||
// single load/store instructions for both precision types
|
||||
inline int flds(int Sd, int Rn, int offset=0) { return COXFER(AL, 1, 1, Sd&1, 0, 1, Rn, Sd>>1, 10, offset); };
|
||||
inline int fldd(int Dd, int Rn, int offset=0) { return COXFER(AL, 1, 1, 0, 0, 1, Rn, Dd, 11, offset); };
|
||||
@ -205,32 +146,21 @@ inline int fstd(int Dd, int Rn, int offset=0) { return COXFER(AL, 1, 1, 0, 0, 0,
|
||||
// move between GPRs and FPRs
|
||||
inline int fmsr(int Sn, int Rd) { return mcr(10, 0, Rd, Sn>>1, 0, (Sn&1)<<2); }
|
||||
inline int fmrs(int Rd, int Sn) { return mrc(10, 0, Rd, Sn>>1, 0, (Sn&1)<<2); }
|
||||
/* move to/from the low/high parts of double-precision registers,
|
||||
seemingly redundant */
|
||||
inline int fmdlr(int Dn, int Rd) { return mcr(11, 0, Rd, Dn, 0); }
|
||||
inline int fmrdl(int Rd, int Dn) { return mrc(11, 0, Rd, Dn, 0); }
|
||||
inline int fmdhr(int Dn, int Rd) { return mcr(11, 1, Rd, Dn, 0); }
|
||||
inline int fmrdh(int Rd, int Dn) { return mrc(11, 1, Rd, Dn, 0); }
|
||||
// move to/from VFP system registers
|
||||
inline int fmxr(int reg, int Rd) { return mcr(10, 7, Rd, reg, 0); }
|
||||
inline int fmrx(int Rd, int reg) { return mrc(10, 7, Rd, reg, 0); }
|
||||
// these move around pairs of single-precision registers
|
||||
inline int fmsrr(int Sm, int Rd, int Rn) { return mcrr(10, 1 | ((Sm&1)<<1), Rd, Rn, Sm>>1); }
|
||||
inline int fmrrs(int Rd, int Rn, int Sm) { return mrrc(10, 1 | ((Sm&1)<<1), Rd, Rn, Sm>>1); }
|
||||
inline int fmdrr(int Dm, int Rd, int Rn) { return mcrr(11, 1, Rd, Rn, Dm); }
|
||||
inline int fmrrd(int Rd, int Rn, int Dm) { return mrrc(11, 1, Rd, Rn, Dm); }
|
||||
// FLAG SETTERS
|
||||
inline int SETCOND(int ins, int cond) { return ((ins&0x0fffffff) | (cond<<28)); }
|
||||
inline int SETS(int ins) { return ins | 1<<20; }
|
||||
// PSEUDO-INSTRUCTIONS
|
||||
inline int nop() { return mov(0, 0); }
|
||||
inline int lsl(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, LSL); }
|
||||
inline int lsli(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSL, imm); }
|
||||
inline int lsr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, LSR); }
|
||||
inline int lsri(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSR, imm); }
|
||||
inline int asr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ASR); }
|
||||
inline int asri(int Rd, int Rm, int imm) { return mov(Rd, Rm, ASR, imm); }
|
||||
inline int ror(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ROR); }
|
||||
inline int beq(int offset) { return SETCOND(b(offset), EQ); }
|
||||
inline int bne(int offset) { return SETCOND(b(offset), NE); }
|
||||
inline int bls(int offset) { return SETCOND(b(offset), LS); }
|
||||
@ -245,35 +175,26 @@ inline int bpl(int offset) { return SETCOND(b(offset), PL); }
|
||||
inline int fmstat() { return fmrx(15, FPSCR); }
|
||||
// HARDWARE FLAGS
|
||||
bool vfpSupported() {
|
||||
return true; // TODO
|
||||
// TODO: Use at runtime detection
|
||||
#if defined(__ARM_PCS_VFP)
|
||||
// armhf
|
||||
return true;
|
||||
#else
|
||||
// armel
|
||||
// TODO: allow VFP use for -mfloat-abi=softfp armel builds.
|
||||
// GCC -mfloat-abi=softfp flag allows use of VFP while remaining compatible
|
||||
// with soft-float code.
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
const uint64_t MASK_LO32 = 0xffffffff;
|
||||
const unsigned MASK_LO16 = 0xffff;
|
||||
const unsigned MASK_LO8 = 0xff;
|
||||
inline unsigned lo32(int64_t i) { return (unsigned)(i&MASK_LO32); }
|
||||
inline unsigned hi32(int64_t i) { return (unsigned)(i>>32); }
|
||||
inline unsigned lo16(int64_t i) { return (unsigned)(i&MASK_LO16); }
|
||||
inline unsigned hi16(int64_t i) { return lo16(i>>16); }
|
||||
inline unsigned lo8(int64_t i) { return (unsigned)(i&MASK_LO8); }
|
||||
inline unsigned hi8(int64_t i) { return lo8(i>>8); }
|
||||
|
||||
inline int ha16(int32_t i) {
|
||||
return ((i >> 16) + ((i & 0x8000) ? 1 : 0)) & 0xffff;
|
||||
}
|
||||
inline int unha16(int32_t high, int32_t low) {
|
||||
return ((high - ((low & 0x8000) ? 1 : 0)) << 16) | low;
|
||||
}
|
||||
|
||||
inline bool isInt8(target_intptr_t v) { return v == static_cast<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;
|
||||
}
|
||||
}
|
||||
|
||||
|
65
src/arm.h
65
src/arm.h
@ -44,7 +44,15 @@
|
||||
THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss))
|
||||
# define LINK_REGISTER(context) \
|
||||
THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss))
|
||||
#else // not __APPLE__
|
||||
#elif (defined __QNX__)
|
||||
# include "arm/smpxchg.h"
|
||||
# include "sys/mman.h"
|
||||
|
||||
# define IP_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_PC])
|
||||
# define STACK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_SP])
|
||||
# define THREAD_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_IP])
|
||||
# define LINK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_LR])
|
||||
#else
|
||||
# define IP_REGISTER(context) (context->uc_mcontext.arm_pc)
|
||||
# define STACK_REGISTER(context) (context->uc_mcontext.arm_sp)
|
||||
# define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip)
|
||||
@ -55,7 +63,8 @@
|
||||
|
||||
extern "C" uint64_t
|
||||
vmNativeCall(void* function, unsigned stackTotal, void* memoryTable,
|
||||
unsigned memoryCount, void* gprTable);
|
||||
unsigned memoryCount, void* gprTable, void* vfpTable,
|
||||
unsigned returnType);
|
||||
|
||||
namespace vm {
|
||||
|
||||
@ -94,6 +103,8 @@ syncInstructionCache(const void* start, unsigned size)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
sys_icache_invalidate(const_cast<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
|
||||
|
@ -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
|
||||
|
@ -286,7 +286,7 @@ public:
|
||||
}
|
||||
|
||||
MachOPlatform(PlatformInfo::Architecture arch):
|
||||
Platform(PlatformInfo(PlatformInfo::Darwin, arch)) {}
|
||||
Platform(PlatformInfo(PlatformInfo::MachO, arch)) {}
|
||||
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -88,6 +88,12 @@ class MyClasspath : public Classpath {
|
||||
return AVIAN_CLASSPATH;
|
||||
}
|
||||
|
||||
virtual void
|
||||
updatePackageMap(Thread*, object)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
virtual void
|
||||
dispose()
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
30
src/common.h
30
src/common.h
@ -25,6 +25,8 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include "float.h"
|
||||
|
||||
// don't complain about using 'this' in member initializers:
|
||||
# pragma warning(disable:4355)
|
||||
|
||||
@ -37,6 +39,34 @@ typedef unsigned int uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
#define strncasecmp _strnicmp
|
||||
|
||||
#define FP_NAN 0
|
||||
#define FP_INFINITE 1
|
||||
#define FP_UNDEF 2
|
||||
|
||||
inline int fpclassify(double d) {
|
||||
|
||||
switch(_fpclass(d)) {
|
||||
case _FPCLASS_SNAN:
|
||||
case _FPCLASS_QNAN:
|
||||
return FP_NAN;
|
||||
case _FPCLASS_PINF:
|
||||
case _FPCLASS_NINF:
|
||||
return FP_INFINITE;
|
||||
}
|
||||
return FP_UNDEF;
|
||||
}
|
||||
|
||||
#define INT32_MIN ((int32_t) _I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t) _I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
|
||||
inline int signbit(double d) {
|
||||
return _copysign(1.0, d) < 0;
|
||||
}
|
||||
|
||||
# define not !
|
||||
# define or ||
|
||||
# define and &&
|
||||
|
@ -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
|
||||
|
460
src/compile.cpp
460
src/compile.cpp
@ -202,6 +202,17 @@ class MyThread: public Thread {
|
||||
bool methodIsMostRecent;
|
||||
};
|
||||
|
||||
class ReferenceFrame {
|
||||
public:
|
||||
ReferenceFrame(ReferenceFrame* next, Reference* reference):
|
||||
next(next),
|
||||
reference(reference)
|
||||
{ }
|
||||
|
||||
ReferenceFrame* next;
|
||||
Reference* reference;
|
||||
};
|
||||
|
||||
static void doTransition(MyThread* t, void* ip, void* stack,
|
||||
object continuation, MyThread::CallTrace* trace)
|
||||
{
|
||||
@ -255,6 +266,7 @@ class MyThread: public Thread {
|
||||
transition(0),
|
||||
traceContext(0),
|
||||
stackLimit(0),
|
||||
referenceFrame(0),
|
||||
methodLockIsClean(true)
|
||||
{
|
||||
arch->acquire();
|
||||
@ -280,6 +292,7 @@ class MyThread: public Thread {
|
||||
Context* transition;
|
||||
TraceContext* traceContext;
|
||||
uintptr_t stackLimit;
|
||||
ReferenceFrame* referenceFrame;
|
||||
bool methodLockIsClean;
|
||||
};
|
||||
|
||||
@ -1375,6 +1388,10 @@ class Frame {
|
||||
}
|
||||
|
||||
~Frame() {
|
||||
dispose();
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
if (level > 1) {
|
||||
context->eventLog.append(PopContextEvent);
|
||||
}
|
||||
@ -2574,13 +2591,25 @@ doubleToFloat(int64_t a)
|
||||
int64_t
|
||||
doubleToInt(int64_t a)
|
||||
{
|
||||
return static_cast<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)
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -602,7 +602,7 @@ class BuiltinElement: public JarElement {
|
||||
}
|
||||
|
||||
virtual const char* urlPrefix() {
|
||||
return "resource:";
|
||||
return "avianvmresource:";
|
||||
}
|
||||
|
||||
virtual const char* sourceUrl() {
|
||||
|
127
src/heap.cpp
127
src/heap.cpp
@ -463,12 +463,15 @@ class Segment {
|
||||
|
||||
class Fixie {
|
||||
public:
|
||||
static const unsigned HasMask = 1 << 0;
|
||||
static const unsigned Marked = 1 << 1;
|
||||
static const unsigned Dirty = 1 << 2;
|
||||
static const unsigned Dead = 1 << 3;
|
||||
|
||||
Fixie(Context* c, unsigned size, bool hasMask, Fixie** handle,
|
||||
bool immortal):
|
||||
age(immortal ? FixieTenureThreshold + 1 : 0),
|
||||
hasMask(hasMask),
|
||||
marked(false),
|
||||
dirty(false),
|
||||
flags(hasMask ? HasMask : 0),
|
||||
size(size),
|
||||
next(0),
|
||||
handle(0)
|
||||
@ -536,16 +539,54 @@ class Fixie {
|
||||
}
|
||||
|
||||
unsigned totalSize() {
|
||||
return totalSize(size, hasMask);
|
||||
return totalSize(size, hasMask());
|
||||
}
|
||||
|
||||
bool hasMask() {
|
||||
return (flags & HasMask) != 0;
|
||||
}
|
||||
|
||||
bool marked() {
|
||||
return (flags & Marked) != 0;
|
||||
}
|
||||
|
||||
void marked(bool v) {
|
||||
if (v) {
|
||||
flags |= Marked;
|
||||
} else {
|
||||
flags &= ~Marked;
|
||||
}
|
||||
}
|
||||
|
||||
bool dirty() {
|
||||
return (flags & Dirty) != 0;
|
||||
}
|
||||
|
||||
void dirty(bool v) {
|
||||
if (v) {
|
||||
flags |= Dirty;
|
||||
} else {
|
||||
flags &= ~Dirty;
|
||||
}
|
||||
}
|
||||
|
||||
bool dead() {
|
||||
return (flags & Dead) != 0;
|
||||
}
|
||||
|
||||
void dead(bool v) {
|
||||
if (v) {
|
||||
flags |= Dead;
|
||||
} else {
|
||||
flags &= ~Dead;
|
||||
}
|
||||
}
|
||||
|
||||
// be sure to update e.g. TargetFixieSizeInBytes in bootimage.cpp if
|
||||
// you add/remove/change fields in this class:
|
||||
|
||||
uint8_t age;
|
||||
uint8_t hasMask;
|
||||
uint8_t marked;
|
||||
uint8_t dirty;
|
||||
uint16_t age;
|
||||
uint16_t flags;
|
||||
uint32_t size;
|
||||
Fixie* next;
|
||||
Fixie** handle;
|
||||
@ -850,11 +891,11 @@ free(Context* c, Fixie** fixies, bool resetImmortal)
|
||||
fprintf(stderr, "reset immortal fixie %p\n", f);
|
||||
}
|
||||
*p = f->next;
|
||||
memset(f->mask(), 0, Fixie::maskSize(f->size, f->hasMask));
|
||||
memset(f->mask(), 0, Fixie::maskSize(f->size, f->hasMask()));
|
||||
f->next = 0;
|
||||
f->handle = 0;
|
||||
f->marked = false;
|
||||
f->dirty = false;
|
||||
f->marked(false);
|
||||
f->dirty(false);
|
||||
} else {
|
||||
p = &(f->next);
|
||||
}
|
||||
@ -868,6 +909,28 @@ free(Context* c, Fixie** fixies, bool resetImmortal)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kill(Fixie* fixies)
|
||||
{
|
||||
for (Fixie* f = fixies; f; f = f->next) {
|
||||
if (! f->immortal()) {
|
||||
f->dead(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
killFixies(Context* c)
|
||||
{
|
||||
assert(c, c->markedFixies == 0);
|
||||
|
||||
if (c->mode == Heap::MajorCollection) {
|
||||
kill(c->tenuredFixies);
|
||||
kill(c->dirtyTenuredFixies);
|
||||
}
|
||||
kill(c->fixies);
|
||||
}
|
||||
|
||||
void
|
||||
sweepFixies(Context* c)
|
||||
{
|
||||
@ -898,14 +961,14 @@ sweepFixies(Context* c)
|
||||
|
||||
if (f->age >= FixieTenureThreshold) {
|
||||
if (DebugFixies) {
|
||||
fprintf(stderr, "tenure fixie %p (dirty: %d)\n", f, f->dirty);
|
||||
fprintf(stderr, "tenure fixie %p (dirty: %d)\n", f, f->dirty());
|
||||
}
|
||||
|
||||
if (not f->immortal()) {
|
||||
c->tenuredFixieFootprint += f->totalSize();
|
||||
}
|
||||
|
||||
if (f->dirty) {
|
||||
if (f->dirty()) {
|
||||
f->add(c, &(c->dirtyTenuredFixies));
|
||||
} else {
|
||||
f->add(c, &(c->tenuredFixies));
|
||||
@ -916,7 +979,7 @@ sweepFixies(Context* c)
|
||||
f->add(c, &(c->fixies));
|
||||
}
|
||||
|
||||
f->marked = false;
|
||||
f->marked(false);
|
||||
}
|
||||
|
||||
c->tenuredFixieCeiling = max
|
||||
@ -1006,14 +1069,15 @@ update3(Context* c, void* o, bool* needsVisit)
|
||||
{
|
||||
if (c->client->isFixed(o)) {
|
||||
Fixie* f = fixie(o);
|
||||
if ((not f->marked)
|
||||
if ((not f->marked())
|
||||
and (c->mode == Heap::MajorCollection
|
||||
or f->age < FixieTenureThreshold))
|
||||
{
|
||||
if (DebugFixies) {
|
||||
fprintf(stderr, "mark fixie %p\n", f);
|
||||
}
|
||||
f->marked = true;
|
||||
f->marked(true);
|
||||
f->dead(false);
|
||||
f->move(c, &(c->markedFixies));
|
||||
}
|
||||
*needsVisit = false;
|
||||
@ -1044,13 +1108,13 @@ update2(Context* c, void* o, bool* needsVisit)
|
||||
void
|
||||
markDirty(Context* c, Fixie* f)
|
||||
{
|
||||
if (not f->dirty) {
|
||||
if (not f->dirty()) {
|
||||
#ifdef USE_ATOMIC_OPERATIONS
|
||||
ACQUIRE(c->lock);
|
||||
#endif
|
||||
|
||||
if (not f->dirty) {
|
||||
f->dirty = true;
|
||||
if (not f->dirty()) {
|
||||
f->dirty(true);
|
||||
f->move(c, &(c->dirtyTenuredFixies));
|
||||
}
|
||||
}
|
||||
@ -1059,8 +1123,8 @@ markDirty(Context* c, Fixie* f)
|
||||
void
|
||||
markClean(Context* c, Fixie* f)
|
||||
{
|
||||
if (f->dirty) {
|
||||
f->dirty = false;
|
||||
if (f->dirty()) {
|
||||
f->dirty(false);
|
||||
if (f->immortal()) {
|
||||
f->remove(c);
|
||||
} else {
|
||||
@ -1090,7 +1154,7 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result)
|
||||
{
|
||||
if (target and c->client->isFixed(target)) {
|
||||
Fixie* f = fixie(target);
|
||||
assert(c, offset == 0 or f->hasMask);
|
||||
assert(c, offset == 0 or f->hasMask());
|
||||
|
||||
if (static_cast<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)
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
128
src/jnienv.cpp
128
src/jnienv.cpp
@ -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)
|
||||
{
|
||||
|
162
src/machine.cpp
162
src/machine.cpp
@ -273,6 +273,8 @@ killZombies(Thread* t, Thread* o)
|
||||
unsigned
|
||||
footprint(Thread* t)
|
||||
{
|
||||
expect(t, t->criticalLevel == 0);
|
||||
|
||||
unsigned n = t->heapOffset + t->heapIndex + t->backupHeapIndex;
|
||||
|
||||
for (Thread* c = t->child; c; c = c->peer) {
|
||||
@ -472,6 +474,25 @@ referenceTargetReachable(Thread* t, Heap::Visitor* v, object* p)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
isFinalizable(Thread* t, object o)
|
||||
{
|
||||
return t->m->heap->status(o) == Heap::Unreachable
|
||||
and (classVmFlags
|
||||
(t, static_cast<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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -60,4 +60,5 @@
|
||||
# error
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
|
76
src/x86.cpp
76
src/x86.cpp
@ -2164,7 +2164,9 @@ doShift(Context* c, UNUSED void (*shift)
|
||||
c->client->save(rcx);
|
||||
|
||||
Assembler::Register cx(rcx);
|
||||
moveCR(c, 4, a, 4, &cx);
|
||||
ResolvedPromise promise(v & 0x3F);
|
||||
Assembler::Constant masked(&promise);
|
||||
moveCR(c, 4, &masked, 4, &cx);
|
||||
shift(c, aSize, &cx, bSize, b);
|
||||
} else {
|
||||
maybeRex(c, bSize, b);
|
||||
@ -2183,9 +2185,16 @@ void
|
||||
shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||
unsigned bSize, Assembler::Register* b)
|
||||
{
|
||||
assert(c, a->low == rcx);
|
||||
|
||||
if (TargetBytesPerWord == 4 and bSize == 8) {
|
||||
Assembler::Register cx(rcx);
|
||||
if (a->low != rcx) {
|
||||
c->client->save(rcx);
|
||||
ResolvedPromise promise(0x3F);
|
||||
Assembler::Constant mask(&promise);
|
||||
moveRR(c, 4, a, 4, &cx);
|
||||
andCR(c, 4, &mask, 4, &cx);
|
||||
}
|
||||
|
||||
// shld
|
||||
opcode(c, 0x0f, 0xa5);
|
||||
modrm(c, 0xc0, b->high, b->low);
|
||||
@ -2195,7 +2204,7 @@ shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||
|
||||
ResolvedPromise promise(32);
|
||||
Assembler::Constant constant(&promise);
|
||||
compareCR(c, aSize, &constant, aSize, a);
|
||||
compareCR(c, aSize, &constant, aSize, &cx);
|
||||
|
||||
opcode(c, 0x7c); //jl
|
||||
c->code.append(2 + 2);
|
||||
@ -2204,6 +2213,8 @@ shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||
moveRR(c, 4, b, 4, &bh); // 2 bytes
|
||||
xorRR(c, 4, b, 4, b); // 2 bytes
|
||||
} else {
|
||||
assert(c, a->low == rcx);
|
||||
|
||||
maybeRex(c, bSize, a, b);
|
||||
opcode(c, 0xd3, 0xe0 + regCode(b));
|
||||
}
|
||||
@ -2220,8 +2231,16 @@ void
|
||||
shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||
unsigned bSize, Assembler::Register* b)
|
||||
{
|
||||
assert(c, a->low == rcx);
|
||||
if (TargetBytesPerWord == 4 and bSize == 8) {
|
||||
Assembler::Register cx(rcx);
|
||||
if (a->low != rcx) {
|
||||
c->client->save(rcx);
|
||||
ResolvedPromise promise(0x3F);
|
||||
Assembler::Constant mask(&promise);
|
||||
moveRR(c, 4, a, 4, &cx);
|
||||
andCR(c, 4, &mask, 4, &cx);
|
||||
}
|
||||
|
||||
// shrd
|
||||
opcode(c, 0x0f, 0xad);
|
||||
modrm(c, 0xc0, b->low, b->high);
|
||||
@ -2231,7 +2250,7 @@ shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||
|
||||
ResolvedPromise promise(32);
|
||||
Assembler::Constant constant(&promise);
|
||||
compareCR(c, aSize, &constant, aSize, a);
|
||||
compareCR(c, aSize, &constant, aSize, &cx);
|
||||
|
||||
opcode(c, 0x7c); //jl
|
||||
c->code.append(2 + 3);
|
||||
@ -2243,6 +2262,8 @@ shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||
opcode(c, 0xc1, 0xf8 + b->high);
|
||||
c->code.append(31);
|
||||
} else {
|
||||
assert(c, a->low == rcx);
|
||||
|
||||
maybeRex(c, bSize, a, b);
|
||||
opcode(c, 0xd3, 0xf8 + regCode(b));
|
||||
}
|
||||
@ -2259,9 +2280,16 @@ void
|
||||
unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||
unsigned bSize, Assembler::Register* b)
|
||||
{
|
||||
assert(c, a->low == rcx);
|
||||
|
||||
if (TargetBytesPerWord == 4 and bSize == 8) {
|
||||
Assembler::Register cx(rcx);
|
||||
if (a->low != rcx) {
|
||||
c->client->save(rcx);
|
||||
ResolvedPromise promise(0x3F);
|
||||
Assembler::Constant mask(&promise);
|
||||
moveRR(c, 4, a, 4, &cx);
|
||||
andCR(c, 4, &mask, 4, &cx);
|
||||
}
|
||||
|
||||
// shrd
|
||||
opcode(c, 0x0f, 0xad);
|
||||
modrm(c, 0xc0, b->low, b->high);
|
||||
@ -2271,7 +2299,7 @@ unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||
|
||||
ResolvedPromise promise(32);
|
||||
Assembler::Constant constant(&promise);
|
||||
compareCR(c, aSize, &constant, aSize, a);
|
||||
compareCR(c, aSize, &constant, aSize, &cx);
|
||||
|
||||
opcode(c, 0x7c); //jl
|
||||
c->code.append(2 + 2);
|
||||
@ -2280,6 +2308,8 @@ unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||
moveRR(c, 4, &bh, 4, b); // 2 bytes
|
||||
xorRR(c, 4, &bh, 4, &bh); // 2 bytes
|
||||
} else {
|
||||
assert(c, a->low == rcx);
|
||||
|
||||
maybeRex(c, bSize, a, b);
|
||||
opcode(c, 0xd3, 0xe8 + regCode(b));
|
||||
}
|
||||
@ -2781,7 +2811,7 @@ class MyArchitecture: public Assembler::Architecture {
|
||||
}
|
||||
|
||||
virtual unsigned frameFootprint(unsigned footprint) {
|
||||
#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS
|
||||
#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE
|
||||
return max(footprint, StackAlignmentInWords);
|
||||
#else
|
||||
return max(footprint > argumentRegisterCount() ?
|
||||
@ -2803,7 +2833,7 @@ class MyArchitecture: public Assembler::Architecture {
|
||||
}
|
||||
|
||||
virtual unsigned argumentRegisterCount() {
|
||||
#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS
|
||||
#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE
|
||||
if (TargetBytesPerWord == 8) return 4; else
|
||||
#else
|
||||
if (TargetBytesPerWord == 8) return 6; else
|
||||
@ -2814,7 +2844,7 @@ class MyArchitecture: public Assembler::Architecture {
|
||||
virtual int argumentRegister(unsigned index) {
|
||||
assert(&c, TargetBytesPerWord == 8);
|
||||
switch (index) {
|
||||
#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS
|
||||
#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE
|
||||
case 0:
|
||||
return rcx;
|
||||
case 1:
|
||||
@ -3064,7 +3094,11 @@ class MyArchitecture: public Assembler::Architecture {
|
||||
break;
|
||||
|
||||
case Float2Int:
|
||||
if (useSSE(&c) and bSize <= TargetBytesPerWord) {
|
||||
// todo: Java requires different semantics than SSE for
|
||||
// converting floats to integers, we we need to either use
|
||||
// thunks or produce inline machine code which handles edge
|
||||
// cases properly.
|
||||
if (false and useSSE(&c) and bSize <= TargetBytesPerWord) {
|
||||
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
||||
*aRegisterMask = (static_cast<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:
|
||||
|
18
src/x86.h
18
src/x86.h
@ -64,6 +64,18 @@
|
||||
# define FRAME_REGISTER(context) \
|
||||
THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss))
|
||||
|
||||
# elif (defined __QNX__)
|
||||
# define IP_REGISTER(context) (context->uc_mcontext.cpu.eip)
|
||||
# define STACK_REGISTER(context) (context->uc_mcontext.cpu.esp)
|
||||
# define THREAD_REGISTER(context) (context->uc_mcontext.cpu.ebx)
|
||||
# define LINK_REGISTER(context) (context->uc_mcontext.cpu.ecx)
|
||||
# define FRAME_REGISTER(context) (context->uc_mcontext.cpu.ebp)
|
||||
# elif (defined __FreeBSD__)
|
||||
# define IP_REGISTER(context) (context->uc_mcontext.mc_eip)
|
||||
# define STACK_REGISTER(context) (context->uc_mcontext.mc_esp)
|
||||
# define THREAD_REGISTER(context) (context->uc_mcontext.mc_ebx)
|
||||
# define LINK_REGISTER(context) (context->uc_mcontext.mc_ecx)
|
||||
# define FRAME_REGISTER(context) (context->uc_mcontext.mc_ebp)
|
||||
# else
|
||||
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP])
|
||||
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP])
|
||||
@ -111,6 +123,12 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*,
|
||||
# define FRAME_REGISTER(context) \
|
||||
THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss))
|
||||
|
||||
# elif (defined __FreeBSD__)
|
||||
# define IP_REGISTER(context) (context->uc_mcontext.mc_rip)
|
||||
# define STACK_REGISTER(context) (context->uc_mcontext.mc_rsp)
|
||||
# define THREAD_REGISTER(context) (context->uc_mcontext.mc_rbx)
|
||||
# define LINK_REGISTER(context) (context->uc_mcontext.mc_rcx)
|
||||
# define FRAME_REGISTER(context) (context->uc_mcontext.mc_rbp)
|
||||
# else
|
||||
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
|
||||
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP])
|
||||
|
45
src/zone.h
45
src/zone.h
@ -20,10 +20,13 @@ class Zone: public Allocator {
|
||||
public:
|
||||
class Segment {
|
||||
public:
|
||||
Segment(Segment* next, unsigned size): next(next), size(size) { }
|
||||
Segment(Segment* next, unsigned size):
|
||||
next(next), size(size), position(0)
|
||||
{ }
|
||||
|
||||
Segment* next;
|
||||
uintptr_t size;
|
||||
uintptr_t position;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
@ -31,7 +34,6 @@ class Zone: public Allocator {
|
||||
s(s),
|
||||
allocator(allocator),
|
||||
segment(0),
|
||||
position(0),
|
||||
minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 :
|
||||
minimumFootprint - sizeof(Segment))
|
||||
{ }
|
||||
@ -55,7 +57,7 @@ class Zone: public Allocator {
|
||||
}
|
||||
|
||||
bool tryEnsure(unsigned space) {
|
||||
if (segment == 0 or position + space > segment->size) {
|
||||
if (segment == 0 or segment->position + space > segment->size) {
|
||||
unsigned size = padToPage
|
||||
(max
|
||||
(space, max
|
||||
@ -72,26 +74,24 @@ class Zone: public Allocator {
|
||||
}
|
||||
|
||||
segment = new (p) Segment(segment, size - sizeof(Segment));
|
||||
position = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ensure(unsigned space) {
|
||||
if (segment == 0 or position + space > segment->size) {
|
||||
if (segment == 0 or segment->position + space > segment->size) {
|
||||
unsigned size = padToPage(space + sizeof(Segment));
|
||||
|
||||
segment = new (allocator->allocate(size))
|
||||
Segment(segment, size - sizeof(Segment));
|
||||
position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void* tryAllocate(unsigned size) {
|
||||
size = pad(size);
|
||||
if (tryEnsure(size)) {
|
||||
void* r = segment->data + position;
|
||||
position += size;
|
||||
void* r = segment->data + segment->position;
|
||||
segment->position += size;
|
||||
return r;
|
||||
} else {
|
||||
return 0;
|
||||
@ -99,17 +99,41 @@ class Zone: public Allocator {
|
||||
}
|
||||
|
||||
virtual void* allocate(unsigned size) {
|
||||
size = pad(size);
|
||||
void* p = tryAllocate(size);
|
||||
if (p) {
|
||||
return p;
|
||||
} else {
|
||||
ensure(size);
|
||||
void* r = segment->data + position;
|
||||
position += size;
|
||||
void* r = segment->data + segment->position;
|
||||
segment->position += size;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
void* peek(unsigned size) {
|
||||
size = pad(size);
|
||||
Segment* s = segment;
|
||||
while (s->position < size) {
|
||||
size -= s->position;
|
||||
s = s->next;
|
||||
}
|
||||
return s->data + (s->position - size);
|
||||
}
|
||||
|
||||
void pop(unsigned size) {
|
||||
size = pad(size);
|
||||
Segment* s = segment;
|
||||
while (s->position < size) {
|
||||
size -= s->position;
|
||||
Segment* next = s->next;
|
||||
allocator->free(s, sizeof(Segment) + s->size);
|
||||
s = next;
|
||||
}
|
||||
s->position -= size;
|
||||
segment = s;
|
||||
}
|
||||
|
||||
virtual void free(const void*, unsigned) {
|
||||
// not supported
|
||||
abort(s);
|
||||
@ -119,7 +143,6 @@ class Zone: public Allocator {
|
||||
Allocator* allocator;
|
||||
void* context;
|
||||
Segment* segment;
|
||||
unsigned position;
|
||||
unsigned minimumFootprint;
|
||||
};
|
||||
|
||||
|
@ -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
109
test/Buffers.java
Normal 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
88
test/Datagrams.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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); }
|
||||
}
|
||||
}
|
||||
|
@ -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
59
test/JNI.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
73
test/jni.cpp
Normal 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));
|
||||
}
|
Loading…
Reference in New Issue
Block a user