mirror of
https://github.com/corda/corda.git
synced 2025-06-21 16:49:45 +00:00
Merge branch 'master' of github.com:ReadyTalk/avian
This commit is contained in:
@ -252,7 +252,7 @@ public class PersistentSet <T> implements Iterable <T> {
|
|||||||
}
|
}
|
||||||
ancestors.next = new Cell(n, ancestors.next);
|
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)) {
|
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);
|
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)) {
|
if (! (sibling.right.red || sibling.left.red)) {
|
||||||
|
@ -50,9 +50,18 @@ public class Utf8 {
|
|||||||
while (i < offset+length) {
|
while (i < offset+length) {
|
||||||
int x = s8[i++];
|
int x = s8[i++];
|
||||||
if ((x & 0x080) == 0x0) { // 1 byte char
|
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);
|
cram(buf, j++, x);
|
||||||
} else if ((x & 0x0e0) == 0x0c0) { // 2 byte char
|
} else if ((x & 0x0e0) == 0x0c0) { // 2 byte char
|
||||||
|
if (i == offset + length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isMultiByte) {
|
if (!isMultiByte) {
|
||||||
buf = widen(buf, j, length-1);
|
buf = widen(buf, j, length-1);
|
||||||
isMultiByte = true;
|
isMultiByte = true;
|
||||||
@ -60,6 +69,10 @@ public class Utf8 {
|
|||||||
int y = s8[i++];
|
int y = s8[i++];
|
||||||
cram(buf, j++, ((x & 0x1f) << 6) | (y & 0x3f));
|
cram(buf, j++, ((x & 0x1f) << 6) | (y & 0x3f));
|
||||||
} else if ((x & 0x0f0) == 0x0e0) { // 3 byte char
|
} else if ((x & 0x0f0) == 0x0e0) { // 3 byte char
|
||||||
|
if (i + 1 >= offset + length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isMultiByte) {
|
if (!isMultiByte) {
|
||||||
buf = widen(buf, j, length-2);
|
buf = widen(buf, j, length-2);
|
||||||
isMultiByte = true;
|
isMultiByte = true;
|
||||||
@ -74,9 +87,14 @@ public class Utf8 {
|
|||||||
|
|
||||||
public static char[] decode16(byte[] s8, int offset, int length) {
|
public static char[] decode16(byte[] s8, int offset, int length) {
|
||||||
Object decoded = decode(s8, offset, length);
|
Object decoded = decode(s8, offset, length);
|
||||||
if (decoded instanceof char[]) return (char[])decoded;
|
if (decoded == null) {
|
||||||
|
return null;
|
||||||
|
} else if (decoded instanceof char[]) {
|
||||||
|
return (char[])decoded;
|
||||||
|
} else {
|
||||||
return (char[])widen(decoded, length, length);
|
return (char[])widen(decoded, length, length);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void cram(Object data, int index, int val) {
|
private static void cram(Object data, int index, int val) {
|
||||||
if (data instanceof byte[]) ((byte[])data)[index] = (byte)val;
|
if (data instanceof byte[]) ((byte[])data)[index] = (byte)val;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
There is NO WARRANTY for this software. See license.txt for
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
details. */
|
details. */
|
||||||
|
|
||||||
package avian.resource;
|
package avian.avianvmresource;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLStreamHandler;
|
import java.net.URLStreamHandler;
|
@ -402,7 +402,16 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass,
|
|||||||
return;
|
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();
|
pid_t pid = fork();
|
||||||
|
#endif
|
||||||
switch(pid){
|
switch(pid){
|
||||||
case -1: // error
|
case -1: // error
|
||||||
throwNewErrno(e, "java/io/IOException");
|
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) {
|
} else if (strcmp(chars, "os.name") == 0) {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
r = e->NewStringUTF("Mac OS X");
|
r = e->NewStringUTF("Mac OS X");
|
||||||
|
#elif defined __FreeBSD__
|
||||||
|
r = e->NewStringUTF("FreeBSD");
|
||||||
#else
|
#else
|
||||||
r = e->NewStringUTF("Linux");
|
r = e->NewStringUTF("Linux");
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
# define ONLY_ON_WINDOWS(x) x
|
# define ONLY_ON_WINDOWS(x) x
|
||||||
#else
|
#else
|
||||||
# include <netdb.h>
|
# include <netdb.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <netinet/in.h>
|
||||||
# define ONLY_ON_WINDOWS(x)
|
# define ONLY_ON_WINDOWS(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
# include <netdb.h>
|
# include <netdb.h>
|
||||||
# include <sys/select.h>
|
# include <sys/select.h>
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
# include <netinet/in.h>
|
||||||
|
# include <netinet/ip.h>
|
||||||
# include <netinet/tcp.h>
|
# include <netinet/tcp.h>
|
||||||
# include <sys/socket.h>
|
# include <sys/socket.h>
|
||||||
#endif
|
#endif
|
||||||
@ -257,7 +260,7 @@ setTcpNoDelay(JNIEnv* e, int d, bool on)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doListen(JNIEnv* e, int s, sockaddr_in* address)
|
doBind(JNIEnv* e, int s, sockaddr_in* address)
|
||||||
{
|
{
|
||||||
int opt = 1;
|
int opt = 1;
|
||||||
int r = ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
int r = ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||||
@ -272,8 +275,12 @@ doListen(JNIEnv* e, int s, sockaddr_in* address)
|
|||||||
throwIOException(e);
|
throwIOException(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
r = ::listen(s, 100);
|
void
|
||||||
|
doListen(JNIEnv* e, int s)
|
||||||
|
{
|
||||||
|
int r = ::listen(s, 100);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
throwIOException(e);
|
throwIOException(e);
|
||||||
}
|
}
|
||||||
@ -333,6 +340,26 @@ doRead(int fd, void* buffer, size_t count)
|
|||||||
#endif
|
#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
|
int
|
||||||
doWrite(int fd, const void* buffer, size_t count)
|
doWrite(int fd, const void* buffer, size_t count)
|
||||||
{
|
{
|
||||||
@ -344,9 +371,9 @@ doWrite(int fd, const void* buffer, size_t count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
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) {
|
if (s < 0) {
|
||||||
throwIOException(e);
|
throwIOException(e);
|
||||||
return s;
|
return s;
|
||||||
@ -378,7 +405,28 @@ Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv *e,
|
|||||||
init(e, &address, host, port);
|
init(e, &address, host, port);
|
||||||
if (e->ExceptionCheck()) return 0;
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,6 +439,16 @@ Java_java_nio_channels_SocketChannel_configureBlocking(JNIEnv *e,
|
|||||||
setBlocking(e, socket, blocking);
|
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
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e,
|
Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e,
|
||||||
jclass,
|
jclass,
|
||||||
@ -423,6 +481,24 @@ Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e,
|
|||||||
return s;
|
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
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e,
|
Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e,
|
||||||
jclass,
|
jclass,
|
||||||
@ -475,6 +551,57 @@ Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e,
|
|||||||
return r;
|
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
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e,
|
Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e,
|
||||||
jclass,
|
jclass,
|
||||||
@ -515,6 +642,18 @@ Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e,
|
|||||||
return r;
|
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
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e,
|
Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e,
|
||||||
@ -554,18 +693,29 @@ class Pipe {
|
|||||||
address.sin_family = AF_INET;
|
address.sin_family = AF_INET;
|
||||||
address.sin_port = 0;
|
address.sin_port = 0;
|
||||||
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //INADDR_LOOPBACK;
|
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //INADDR_LOOPBACK;
|
||||||
|
|
||||||
listener_ = makeSocket(e);
|
listener_ = makeSocket(e);
|
||||||
|
if (e->ExceptionCheck()) return;
|
||||||
|
|
||||||
setBlocking(e, listener_, false);
|
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);
|
socklen_t length = sizeof(sockaddr_in);
|
||||||
int r = getsockname(listener_, reinterpret_cast<sockaddr*>(&address),
|
int r = getsockname(listener_, reinterpret_cast<sockaddr*>(&address),
|
||||||
&length);
|
&length);
|
||||||
if (r) {
|
if (r) {
|
||||||
throwIOException(e);
|
throwIOException(e);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer_ = makeSocket(e);
|
writer_ = makeSocket(e);
|
||||||
|
if (e->ExceptionCheck()) return;
|
||||||
|
|
||||||
setBlocking(e, writer_, true);
|
setBlocking(e, writer_, true);
|
||||||
connected_ = ::doConnect(e, writer_, &address);
|
connected_ = ::doConnect(e, writer_, &address);
|
||||||
}
|
}
|
||||||
@ -663,6 +813,7 @@ Java_java_nio_channels_SocketSelector_natInit(JNIEnv* e, jclass)
|
|||||||
void *mem = malloc(sizeof(SelectorState));
|
void *mem = malloc(sizeof(SelectorState));
|
||||||
if (mem) {
|
if (mem) {
|
||||||
SelectorState *s = new (mem) SelectorState(e);
|
SelectorState *s = new (mem) SelectorState(e);
|
||||||
|
if (e->ExceptionCheck()) return 0;
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
FD_ZERO(&(s->read));
|
FD_ZERO(&(s->read));
|
||||||
|
@ -72,12 +72,16 @@ public class File implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String normalize(String path) {
|
private static String stripSeparators(String p) {
|
||||||
if ("\\".equals(FileSeparator)) {
|
while (p.endsWith(FileSeparator)) {
|
||||||
return path.replace('/', '\\');
|
p = p.substring(0, p.length() - 1);
|
||||||
} else {
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String normalize(String path) {
|
||||||
|
return stripSeparators
|
||||||
|
("\\".equals(FileSeparator) ? path.replace('/', '\\') : path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static native boolean rename(String old, String new_);
|
public static native boolean rename(String old, String new_);
|
||||||
@ -150,7 +154,7 @@ public class File implements Serializable {
|
|||||||
public String getParent() {
|
public String getParent() {
|
||||||
int index = path.lastIndexOf(FileSeparator);
|
int index = path.lastIndexOf(FileSeparator);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
return path.substring(0, index);
|
return normalize(path.substring(0, index));
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -239,11 +243,15 @@ public class File implements Serializable {
|
|||||||
|
|
||||||
public File[] listFiles(FilenameFilter filter) {
|
public File[] listFiles(FilenameFilter filter) {
|
||||||
String[] list = list(filter);
|
String[] list = list(filter);
|
||||||
|
if (list != null) {
|
||||||
File[] result = new File[list.length];
|
File[] result = new File[list.length];
|
||||||
for (int i = 0; i < list.length; ++i) {
|
for (int i = 0; i < list.length; ++i) {
|
||||||
result[i] = new File(this, list[i]);
|
result[i] = new File(this, list[i]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] list() {
|
public String[] list() {
|
||||||
@ -254,6 +262,7 @@ public class File implements Serializable {
|
|||||||
long handle = 0;
|
long handle = 0;
|
||||||
try {
|
try {
|
||||||
handle = openDir(path);
|
handle = openDir(path);
|
||||||
|
if (handle != 0) {
|
||||||
Pair list = null;
|
Pair list = null;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (String s = readDir(handle); s != null; s = readDir(handle)) {
|
for (String s = readDir(handle); s != null; s = readDir(handle)) {
|
||||||
@ -270,6 +279,9 @@ public class File implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (handle != 0) {
|
if (handle != 0) {
|
||||||
closeDir(handle);
|
closeDir(handle);
|
||||||
|
@ -13,6 +13,8 @@ package java.io;
|
|||||||
import avian.Utf8;
|
import avian.Utf8;
|
||||||
|
|
||||||
public class InputStreamReader extends Reader {
|
public class InputStreamReader extends Reader {
|
||||||
|
private static final int MultibytePadding = 4;
|
||||||
|
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
|
|
||||||
public InputStreamReader(InputStream in) {
|
public InputStreamReader(InputStream in) {
|
||||||
@ -29,18 +31,59 @@ public class InputStreamReader extends Reader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int read(char[] b, int offset, int length) throws IOException {
|
public int read(char[] b, int offset, int length) throws IOException {
|
||||||
byte[] buffer = new byte[length];
|
if (length == 0) {
|
||||||
int c = in.read(buffer);
|
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);
|
||||||
|
|
||||||
|
if (buffer16 != null) {
|
||||||
|
System.arraycopy(buffer16, 0, b, offset, buffer16.length);
|
||||||
|
|
||||||
|
c = buffer16.length + 1;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
-- bufferOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
System.arraycopy(buffer16, 0, b, offset, buffer16.length);
|
||||||
|
|
||||||
return 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 {
|
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 { }
|
@ -15,6 +15,10 @@ public final class Float extends Number {
|
|||||||
private static final int EXP_BIT_MASK = 0x7F800000;
|
private static final int EXP_BIT_MASK = 0x7F800000;
|
||||||
private static final int SIGNIF_BIT_MASK = 0x007FFFFF;
|
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;
|
private final float value;
|
||||||
|
|
||||||
public Float(String value) {
|
public Float(String value) {
|
||||||
|
@ -156,6 +156,10 @@ public class Thread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void sleep(long milliseconds) throws InterruptedException {
|
public static void sleep(long milliseconds) throws InterruptedException {
|
||||||
|
if (milliseconds <= 0) {
|
||||||
|
milliseconds = 1;
|
||||||
|
}
|
||||||
|
|
||||||
Thread t = currentThread();
|
Thread t = currentThread();
|
||||||
if (t.sleepLock == null) {
|
if (t.sleepLock == null) {
|
||||||
t.sleepLock = new Object();
|
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)) {
|
if ("http".equals(protocol) || "https".equals(protocol)) {
|
||||||
return new avian.http.Handler();
|
return new avian.http.Handler();
|
||||||
} else if ("resource".equals(protocol)) {
|
} else if ("avianvmresource".equals(protocol)) {
|
||||||
return new avian.resource.Handler();
|
return new avian.avianvmresource.Handler();
|
||||||
} else if ("file".equals(protocol)) {
|
} else if ("file".equals(protocol)) {
|
||||||
return new avian.file.Handler();
|
return new avian.file.Handler();
|
||||||
} else if ("jar".equals(protocol)) {
|
} 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
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
for any purpose with or without fee is hereby granted, provided
|
for any purpose with or without fee is hereby granted, provided
|
||||||
@ -10,13 +10,22 @@
|
|||||||
|
|
||||||
package java.nio;
|
package java.nio;
|
||||||
|
|
||||||
public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
|
public abstract class ByteBuffer
|
||||||
private final byte[] array;
|
extends Buffer
|
||||||
private int arrayOffset;
|
implements Comparable<ByteBuffer>
|
||||||
|
{
|
||||||
private final boolean readOnly;
|
private final boolean readOnly;
|
||||||
|
|
||||||
|
protected ByteBuffer(boolean readOnly) {
|
||||||
|
this.readOnly = readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
public static ByteBuffer allocate(int capacity) {
|
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) {
|
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) {
|
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) {
|
public abstract ByteBuffer asReadOnlyBuffer();
|
||||||
this.array = array;
|
|
||||||
this.readOnly = readOnly;
|
public abstract ByteBuffer slice();
|
||||||
arrayOffset = offset;
|
|
||||||
capacity = length;
|
protected abstract void doPut(int offset, byte val);
|
||||||
limit = capacity;
|
|
||||||
|
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 compact() {
|
||||||
|
int remaining = remaining();
|
||||||
|
|
||||||
|
if (position != 0) {
|
||||||
|
ByteBuffer b = slice();
|
||||||
position = 0;
|
position = 0;
|
||||||
|
put(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer asReadOnlyBuffer() {
|
position = remaining;
|
||||||
ByteBuffer b = new ByteBuffer(array, arrayOffset, capacity, true);
|
limit(capacity());
|
||||||
b.position(position());
|
|
||||||
b.limit(limit());
|
return this;
|
||||||
return b;
|
}
|
||||||
|
|
||||||
|
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) {
|
public int compareTo(ByteBuffer o) {
|
||||||
@ -60,37 +99,22 @@ public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] array() {
|
public byte[] array() {
|
||||||
return array;
|
throw new UnsupportedOperationException();
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer slice() {
|
|
||||||
return new ByteBuffer(array, arrayOffset + position, remaining(), true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int arrayOffset() {
|
public int arrayOffset() {
|
||||||
return arrayOffset;
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer compact() {
|
public ByteBuffer put(int offset, byte val) {
|
||||||
if (position != 0) {
|
checkPut(offset, 1);
|
||||||
System.arraycopy(array, arrayOffset+position, array, arrayOffset, remaining());
|
doPut(offset, val);
|
||||||
}
|
|
||||||
position=remaining();
|
|
||||||
limit(capacity());
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer put(byte val) {
|
public ByteBuffer put(byte val) {
|
||||||
checkPut(1);
|
put(position, val);
|
||||||
array[arrayOffset+(position++)] = val;
|
++ position;
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer put(ByteBuffer src) {
|
|
||||||
checkPut(src.remaining());
|
|
||||||
put(src.array, src.arrayOffset + src.position, src.remaining());
|
|
||||||
src.position += src.remaining();
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,125 +122,126 @@ public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
|
|||||||
return put(arr, 0, arr.length);
|
return put(arr, 0, arr.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer put(byte[] arr, int offset, int len) {
|
public ByteBuffer putLong(int position, long val) {
|
||||||
checkPut(len);
|
checkPut(position, 8);
|
||||||
System.arraycopy(arr, offset, array, arrayOffset+position, len);
|
|
||||||
position += len;
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer putInt(int position, int val) {
|
public ByteBuffer putInt(int position, int val) {
|
||||||
checkPut(position, 4);
|
checkPut(position, 4);
|
||||||
array[arrayOffset+position] = (byte)((val >> 24) & 0xff);
|
|
||||||
array[arrayOffset+position+1] = (byte)((val >> 16) & 0xff);
|
doPut(position , (byte) ((val >> 24) & 0xff));
|
||||||
array[arrayOffset+position+2] = (byte)((val >> 8) & 0xff);
|
doPut(position + 1, (byte) ((val >> 16) & 0xff));
|
||||||
array[arrayOffset+position+3] = (byte)((val ) & 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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer putInt(int val) {
|
public ByteBuffer putInt(int val) {
|
||||||
checkPut(4);
|
|
||||||
putInt(position, val);
|
putInt(position, val);
|
||||||
position += 4;
|
position += 4;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer putShort(short val) {
|
public ByteBuffer putShort(short val) {
|
||||||
checkPut(2);
|
putShort(position, val);
|
||||||
put((byte)((val >> 8) & 0xff));
|
position += 2;
|
||||||
put((byte)(val & 0xff));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer putLong(long val) {
|
|
||||||
checkPut(8);
|
|
||||||
putInt((int)(val >> 32));
|
|
||||||
putInt((int)val);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte get() {
|
public byte get() {
|
||||||
checkGet(1);
|
return get(position++);
|
||||||
return array[arrayOffset+(position++)];
|
}
|
||||||
|
|
||||||
|
public byte get(int position) {
|
||||||
|
checkGet(position, 1);
|
||||||
|
return doGet(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer get(byte[] dst) {
|
public ByteBuffer get(byte[] dst) {
|
||||||
return get(dst, 0, dst.length);
|
return get(dst, 0, dst.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer get(byte[] dst, int offset, int length) {
|
public long getLong(int position) {
|
||||||
checkGet(length);
|
checkGet(position, 8);
|
||||||
System.arraycopy(array, arrayOffset + position, dst, offset, length);
|
|
||||||
position += length;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte get(int position) {
|
return (((long) (doGet(position ) & 0xFF)) << 56)
|
||||||
checkGet(position, 1);
|
| (((long) (doGet(position + 1) & 0xFF)) << 48)
|
||||||
return array[arrayOffset+position];
|
| (((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) {
|
public int getInt(int position) {
|
||||||
checkGet(position, 4);
|
checkGet(position, 4);
|
||||||
|
|
||||||
int p = arrayOffset + position;
|
return (((int) (doGet(position ) & 0xFF)) << 24)
|
||||||
return ((array[p] & 0xFF) << 24)
|
| (((int) (doGet(position + 1) & 0xFF)) << 16)
|
||||||
| ((array[p + 1] & 0xFF) << 16)
|
| (((int) (doGet(position + 2) & 0xFF)) << 8)
|
||||||
| ((array[p + 2] & 0xFF) << 8)
|
| (((int) (doGet(position + 3) & 0xFF)) );
|
||||||
| ((array[p + 3] & 0xFF));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getShort(int position) {
|
public short getShort(int position) {
|
||||||
checkGet(position, 2);
|
checkGet(position, 2);
|
||||||
|
|
||||||
int p = arrayOffset + position;
|
return (short) (( ((int) (doGet(position ) & 0xFF)) << 8)
|
||||||
return (short) (((array[p] & 0xFF) << 8) | ((array[p + 1] & 0xFF)));
|
| (((int) (doGet(position + 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLong() {
|
public long getLong() {
|
||||||
checkGet(8);
|
long r = getLong(position);
|
||||||
long l = (long)getInt() << 32;
|
position += 8;
|
||||||
l |= (long)getInt() & 0xffffffffL;
|
return r;
|
||||||
return l;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPut(int amount) {
|
public int getInt() {
|
||||||
if (readOnly) throw new ReadOnlyBufferException();
|
int r = getInt(position);
|
||||||
if (amount > limit-position) throw new IndexOutOfBoundsException();
|
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 (readOnly) throw new ReadOnlyBufferException();
|
||||||
if (position < 0 || position+amount > limit)
|
if (position < 0 || position+amount > limit)
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkGet(int amount) {
|
protected void checkGet(int position, int amount) {
|
||||||
if (amount > limit-position) throw new IndexOutOfBoundsException();
|
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,
|
public StringBuffer format(Object[] args, StringBuffer target,
|
||||||
FieldPosition p)
|
FieldPosition p)
|
||||||
{
|
{
|
||||||
// todo
|
// todo: handle other format substitutions and escapes, and make
|
||||||
return target.append(pattern);
|
// 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)
|
public StringBuffer format(Object args, StringBuffer target, FieldPosition p)
|
||||||
|
@ -15,6 +15,11 @@ public abstract class AbstractList<T> extends AbstractCollection<T>
|
|||||||
{
|
{
|
||||||
protected int modCount;
|
protected int modCount;
|
||||||
|
|
||||||
|
public boolean add(T o) {
|
||||||
|
add(size(), o);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public Iterator<T> iterator() {
|
public Iterator<T> iterator() {
|
||||||
return listIterator();
|
return listIterator();
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,23 @@ public class Arrays {
|
|||||||
return asList(a).toString();
|
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) {
|
private static boolean equal(Object a, Object b) {
|
||||||
return (a == null && b == null) || (a != null && a.equals(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 long getAddress(long address);
|
||||||
|
|
||||||
public native void putAddress(long address, long x);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
105
makefile
105
makefile
@ -5,6 +5,8 @@ version = 0.6
|
|||||||
|
|
||||||
build-arch := $(shell uname -m \
|
build-arch := $(shell uname -m \
|
||||||
| sed 's/^i.86$$/i386/' \
|
| sed 's/^i.86$$/i386/' \
|
||||||
|
| sed 's/^x86pc$$/i386/' \
|
||||||
|
| sed 's/amd64/x86_64/' \
|
||||||
| sed 's/^arm.*$$/arm/' \
|
| sed 's/^arm.*$$/arm/' \
|
||||||
| sed 's/ppc/powerpc/')
|
| sed 's/ppc/powerpc/')
|
||||||
|
|
||||||
@ -22,7 +24,6 @@ target-arch = $(arch)
|
|||||||
bootimage-platform = \
|
bootimage-platform = \
|
||||||
$(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))
|
$(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))
|
||||||
platform = $(bootimage-platform)
|
platform = $(bootimage-platform)
|
||||||
target-platform = $(platform)
|
|
||||||
|
|
||||||
mode = fast
|
mode = fast
|
||||||
process = compile
|
process = compile
|
||||||
@ -85,6 +86,8 @@ ifeq ($(build-platform),darwin)
|
|||||||
library-path-variable = DYLD_LIBRARY_PATH
|
library-path-variable = DYLD_LIBRARY_PATH
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
library-path = $(library-path-variable)=$(build)
|
||||||
|
|
||||||
ifneq ($(openjdk),)
|
ifneq ($(openjdk),)
|
||||||
openjdk-arch = $(arch)
|
openjdk-arch = $(arch)
|
||||||
ifeq ($(arch),x86_64)
|
ifeq ($(arch),x86_64)
|
||||||
@ -161,6 +164,8 @@ ifneq ($(platform),darwin)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
target-format = elf
|
||||||
|
|
||||||
cxx = $(build-cxx) $(mflag)
|
cxx = $(build-cxx) $(mflag)
|
||||||
cc = $(build-cc) $(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)
|
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) \
|
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \
|
||||||
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
||||||
|
-DAVIAN_INFO="\"$(info)\"" \
|
||||||
-DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \
|
-DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \
|
||||||
-DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" $(target-cflags)
|
-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/ \
|
converter-cflags = -D__STDC_CONSTANT_MACROS -Isrc/binaryToObject -Isrc/ \
|
||||||
-fno-rtti -fno-exceptions \
|
-fno-rtti -fno-exceptions \
|
||||||
-DAVIAN_TARGET_ARCH=AVIAN_ARCH_UNKNOWN \
|
-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
|
-Wall -Wextra -Werror -Wunused-parameter -Winit-self -Wno-non-virtual-dtor
|
||||||
|
|
||||||
cflags = $(build-cflags)
|
cflags = $(build-cflags)
|
||||||
@ -218,6 +224,7 @@ build-lflags = -lz -lpthread -ldl
|
|||||||
|
|
||||||
lflags = $(common-lflags) -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
|
version-script-flag = -Wl,--version-script=openjdk.ld
|
||||||
|
|
||||||
build-system = posix
|
build-system = posix
|
||||||
@ -284,8 +291,13 @@ ifeq ($(arch),arm)
|
|||||||
ifneq ($(arch),$(build-arch))
|
ifneq ($(arch),$(build-arch))
|
||||||
ifeq ($(platform),darwin)
|
ifeq ($(platform),darwin)
|
||||||
ios-bin = $(developer-dir)/Platforms/iPhoneOS.platform/Developer/usr/bin
|
ios-bin = $(developer-dir)/Platforms/iPhoneOS.platform/Developer/usr/bin
|
||||||
|
ifeq ($(use-clang),true)
|
||||||
|
cxx = clang -std=c++11
|
||||||
|
cc = clang
|
||||||
|
else
|
||||||
cxx = $(ios-bin)/g++
|
cxx = $(ios-bin)/g++
|
||||||
cc = $(ios-bin)/gcc
|
cc = $(ios-bin)/gcc
|
||||||
|
endif
|
||||||
ar = $(ios-bin)/ar
|
ar = $(ios-bin)/ar
|
||||||
ranlib = $(ios-bin)/ranlib
|
ranlib = $(ios-bin)/ranlib
|
||||||
strip = $(ios-bin)/strip
|
strip = $(ios-bin)/strip
|
||||||
@ -305,11 +317,45 @@ endif
|
|||||||
|
|
||||||
ifeq ($(build-platform),darwin)
|
ifeq ($(build-platform),darwin)
|
||||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
|
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
|
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
|
endif
|
||||||
|
|
||||||
ifeq ($(platform),darwin)
|
ifeq ($(platform),darwin)
|
||||||
|
target-format = macho
|
||||||
ifeq (${OSX_SDK_SYSROOT},)
|
ifeq (${OSX_SDK_SYSROOT},)
|
||||||
OSX_SDK_SYSROOT = 10.4u
|
OSX_SDK_SYSROOT = 10.4u
|
||||||
endif
|
endif
|
||||||
@ -350,7 +396,8 @@ ifeq ($(platform),darwin)
|
|||||||
|
|
||||||
ifeq ($(arch),arm)
|
ifeq ($(arch),arm)
|
||||||
ios-version := \
|
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)/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.3.sdk; then echo 4.3; \
|
||||||
elif test -d $(sdk-dir)/iPhoneOS4.2.sdk; then echo 4.2; \
|
elif test -d $(sdk-dir)/iPhoneOS4.2.sdk; then echo 4.2; \
|
||||||
@ -391,6 +438,8 @@ ifeq ($(platform),darwin)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(platform),windows)
|
ifeq ($(platform),windows)
|
||||||
|
target-format = pe
|
||||||
|
|
||||||
inc = "$(win32)/include"
|
inc = "$(win32)/include"
|
||||||
lib = "$(win32)/lib"
|
lib = "$(win32)/lib"
|
||||||
|
|
||||||
@ -527,7 +576,8 @@ ifdef msvc
|
|||||||
cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \
|
cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \
|
||||||
-DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \
|
-DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \
|
||||||
-DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \
|
-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" \
|
-I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" \
|
||||||
-DTARGET_BYTES_PER_WORD=$(pointer-size)
|
-DTARGET_BYTES_PER_WORD=$(pointer-size)
|
||||||
|
|
||||||
@ -756,7 +806,7 @@ ifneq ($(classpath),avian)
|
|||||||
$(classpath-src)/avian/VMClass.java \
|
$(classpath-src)/avian/VMClass.java \
|
||||||
$(classpath-src)/avian/VMField.java \
|
$(classpath-src)/avian/VMField.java \
|
||||||
$(classpath-src)/avian/VMMethod.java \
|
$(classpath-src)/avian/VMMethod.java \
|
||||||
$(classpath-src)/avian/resource/Handler.java
|
$(classpath-src)/avian/avianvmresource/Handler.java
|
||||||
|
|
||||||
ifneq ($(openjdk),)
|
ifneq ($(openjdk),)
|
||||||
classpath-sources := $(classpath-sources) \
|
classpath-sources := $(classpath-sources) \
|
||||||
@ -777,9 +827,12 @@ vm-classes = \
|
|||||||
|
|
||||||
test-support-sources = $(shell find $(test)/avian/ -name '*.java')
|
test-support-sources = $(shell find $(test)/avian/ -name '*.java')
|
||||||
test-sources = $(wildcard $(test)/*.java)
|
test-sources = $(wildcard $(test)/*.java)
|
||||||
|
test-cpp-sources = $(wildcard $(test)/*.cpp)
|
||||||
test-sources += $(test-support-sources)
|
test-sources += $(test-support-sources)
|
||||||
test-support-classes = $(call java-classes, $(test-support-sources),$(test),$(test-build))
|
test-support-classes = $(call java-classes, $(test-support-sources),$(test),$(test-build))
|
||||||
test-classes = $(call java-classes,$(test-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-dep = $(test-build).dep
|
||||||
|
|
||||||
test-extra-sources = $(wildcard $(test)/extra/*.java)
|
test-extra-sources = $(wildcard $(test)/extra/*.java)
|
||||||
@ -815,22 +868,22 @@ ifeq ($(target-arch),arm)
|
|||||||
cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM
|
cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(target-platform),linux)
|
ifeq ($(target-format),elf)
|
||||||
cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_LINUX
|
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_ELF
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(target-platform),windows)
|
ifeq ($(target-format),pe)
|
||||||
cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_WINDOWS
|
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_PE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(target-platform),darwin)
|
ifeq ($(target-format),macho)
|
||||||
cflags += -DAVIAN_TARGET_PLATFORM=AVIAN_PLATFORM_DARWIN
|
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_MACHO
|
||||||
endif
|
endif
|
||||||
|
|
||||||
class-name = $(patsubst $(1)/%.class,%,$(2))
|
class-name = $(patsubst $(1)/%.class,%,$(2))
|
||||||
class-names = $(foreach x,$(2),$(call class-name,$(1),$(x)))
|
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)
|
test-args = $(test-flags) $(input)
|
||||||
|
|
||||||
@ -904,7 +957,7 @@ $(classpath-dep): $(classpath-sources)
|
|||||||
$(test-build)/%.class: $(test)/%.java
|
$(test-build)/%.class: $(test)/%.java
|
||||||
@echo $(<)
|
@echo $(<)
|
||||||
|
|
||||||
$(test-dep): $(test-sources)
|
$(test-dep): $(test-sources) $(test-library)
|
||||||
@echo "compiling test classes"
|
@echo "compiling test classes"
|
||||||
@mkdir -p $(test-build)
|
@mkdir -p $(test-build)
|
||||||
files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \
|
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)
|
$(vm-cpp-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends)
|
||||||
$(compile-object)
|
$(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
|
$(build)/%.o: $(lzma)/C/%.c
|
||||||
@echo "compiling $(@)"
|
@echo "compiling $(@)"
|
||||||
@mkdir -p $(dir $(@))
|
@mkdir -p $(dir $(@))
|
||||||
@ -994,7 +1060,7 @@ $(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep)
|
|||||||
$(classpath-object): $(build)/classpath.jar $(converter)
|
$(classpath-object): $(build)/classpath.jar $(converter)
|
||||||
@echo "creating $(@)"
|
@echo "creating $(@)"
|
||||||
$(converter) $(<) $(@) _binary_classpath_jar_start \
|
$(converter) $(<) $(@) _binary_classpath_jar_start \
|
||||||
_binary_classpath_jar_end $(platform) $(arch)
|
_binary_classpath_jar_end $(target-format) $(arch)
|
||||||
|
|
||||||
$(build)/javahome.jar:
|
$(build)/javahome.jar:
|
||||||
@echo "creating $(@)"
|
@echo "creating $(@)"
|
||||||
@ -1005,7 +1071,7 @@ $(build)/javahome.jar:
|
|||||||
$(javahome-object): $(build)/javahome.jar $(converter)
|
$(javahome-object): $(build)/javahome.jar $(converter)
|
||||||
@echo "creating $(@)"
|
@echo "creating $(@)"
|
||||||
$(converter) $(<) $(@) _binary_javahome_jar_start \
|
$(converter) $(<) $(@) _binary_javahome_jar_start \
|
||||||
_binary_javahome_jar_end $(platform) $(arch)
|
_binary_javahome_jar_end $(target-format) $(arch)
|
||||||
|
|
||||||
define compile-generator-object
|
define compile-generator-object
|
||||||
@echo "compiling $(@)"
|
@echo "compiling $(@)"
|
||||||
@ -1066,7 +1132,7 @@ $(bootimage-generator): $(bootimage-generator-objects)
|
|||||||
arch=$(build-arch) \
|
arch=$(build-arch) \
|
||||||
target-arch=$(arch) \
|
target-arch=$(arch) \
|
||||||
platform=$(bootimage-platform) \
|
platform=$(bootimage-platform) \
|
||||||
target-platform=$(platform) \
|
target-format=$(target-format) \
|
||||||
openjdk=$(openjdk) \
|
openjdk=$(openjdk) \
|
||||||
openjdk-src=$(openjdk-src) \
|
openjdk-src=$(openjdk-src) \
|
||||||
bootimage-generator= \
|
bootimage-generator= \
|
||||||
@ -1104,7 +1170,8 @@ ifdef msvc
|
|||||||
-IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest
|
-IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest
|
||||||
$(mt) -manifest $(@).manifest -outputresource:"$(@);2"
|
$(mt) -manifest $(@).manifest -outputresource:"$(@);2"
|
||||||
else
|
else
|
||||||
$(ld) $(^) $(version-script-flag) $(shared) $(lflags) $(bootimage-lflags) \
|
$(ld) $(^) $(version-script-flag) $(soname-flag) \
|
||||||
|
$(shared) $(lflags) $(bootimage-lflags) \
|
||||||
-o $(@)
|
-o $(@)
|
||||||
endif
|
endif
|
||||||
$(strip) $(strip-all) $(@)
|
$(strip) $(strip-all) $(@)
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
-keep class avian.OpenJDK {
|
-keep class avian.OpenJDK {
|
||||||
public static java.security.ProtectionDomain getProtectionDomain();
|
<methods>;
|
||||||
}
|
}
|
||||||
|
|
||||||
-keepclassmembers public class java.security.PrivilegedAction {
|
-keepclassmembers public class java.security.PrivilegedAction {
|
||||||
@ -208,7 +208,7 @@
|
|||||||
-keep class sun.nio.cs.UTF_8
|
-keep class sun.nio.cs.UTF_8
|
||||||
|
|
||||||
# loaded reflectively to handle embedded resources:
|
# loaded reflectively to handle embedded resources:
|
||||||
-keep class avian.resource.Handler
|
-keep class avian.avianvmresource.Handler
|
||||||
|
|
||||||
# refered to symbolically in MethodAccessorGenerator:
|
# refered to symbolically in MethodAccessorGenerator:
|
||||||
-keep class sun.reflect.MethodAccessorImpl {
|
-keep class sun.reflect.MethodAccessorImpl {
|
||||||
@ -244,3 +244,5 @@
|
|||||||
-keep class sun.nio.fs.UnixException {
|
-keep class sun.nio.fs.UnixException {
|
||||||
UnixException(int);
|
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
|
Copyright (c) 2008-2011, Avian Contributors
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software
|
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
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
details. */
|
details. */
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
.text
|
.text
|
||||||
|
|
||||||
#define LOCAL(x) .L##x
|
#define LOCAL(x) .L##x
|
||||||
@ -29,14 +31,18 @@ GLOBAL(vmNativeCall):
|
|||||||
r2 : memoryTable
|
r2 : memoryTable
|
||||||
r3 : memoryCount
|
r3 : memoryCount
|
||||||
[sp, #0] -> r6 : gprTable
|
[sp, #0] -> r6 : gprTable
|
||||||
|
[sp, #4] -> r7 : vfpTable
|
||||||
|
[sp, #8] -> r8 : returnType
|
||||||
*/
|
*/
|
||||||
mov ip, sp // save stack frame
|
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
|
// mv args into non-volatile regs
|
||||||
mov r4, r0
|
mov r4, r0
|
||||||
mov r5, r1
|
mov r5, r1
|
||||||
ldr r6, [ip]
|
ldr r6, [ip]
|
||||||
|
ldr r7, [ip, #4]
|
||||||
|
ldr r8, [ip, #8]
|
||||||
|
|
||||||
// setup stack arguments if necessary
|
// setup stack arguments if necessary
|
||||||
sub sp, sp, r5 // allocate stack
|
sub sp, sp, r5 // allocate stack
|
||||||
@ -50,12 +56,38 @@ LOCAL(loop):
|
|||||||
|
|
||||||
// setup argument registers if necessary
|
// setup argument registers if necessary
|
||||||
tst r6, r6
|
tst r6, r6
|
||||||
|
#if (defined __APPLE__) && (defined __clang_major__) && (__clang_major__ >= 4)
|
||||||
|
ldmiane r6, {r0-r3}
|
||||||
|
#else
|
||||||
ldmneia r6, {r0-r3}
|
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
|
blx r4 // call function
|
||||||
|
#endif
|
||||||
add sp, sp, r5 // deallocate stack
|
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)
|
.globl GLOBAL(vmJump)
|
||||||
.align 2
|
.align 2
|
||||||
@ -85,7 +117,12 @@ GLOBAL(vmRun):
|
|||||||
mov r12, r0
|
mov r12, r0
|
||||||
ldr r0, [r2, #CHECKPOINT_THREAD]
|
ldr r0, [r2, #CHECKPOINT_THREAD]
|
||||||
|
|
||||||
|
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||||
|
mov lr, pc
|
||||||
|
bx r12
|
||||||
|
#else
|
||||||
blx r12
|
blx r12
|
||||||
|
#endif
|
||||||
|
|
||||||
.globl GLOBAL(vmRun_returnAddress)
|
.globl GLOBAL(vmRun_returnAddress)
|
||||||
.align 2
|
.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; }
|
{ 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)
|
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); }
|
{ 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)
|
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; }
|
{ 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
|
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 bl(int offset) { return BRANCH(AL, 1, offset); }
|
||||||
inline int bx(int Rm) { return BRANCHX(AL, 0, Rm); }
|
inline int bx(int Rm) { return BRANCHX(AL, 0, Rm); }
|
||||||
inline int blx(int Rm) { return BRANCHX(AL, 1, 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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); }
|
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 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 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 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
|
// breakpoint instruction, this really has its own instruction format
|
||||||
inline int bkpt(int16_t immed) { return 0xe1200070 | (((unsigned)immed & 0xffff) >> 4 << 8) | (immed & 0xf); }
|
inline int bkpt(int16_t immed) { return 0xe1200070 | (((unsigned)immed & 0xffff) >> 4 << 8) | (immed & 0xf); }
|
||||||
// COPROCESSOR INSTRUCTIONS
|
// 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 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 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 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 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
|
// 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 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 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 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 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 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 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 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); }
|
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 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 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 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 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 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 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 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); }
|
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); }
|
inline int fsqrtd(int Dd, int Dm) { return COOP(AL, 0xb, 1, Dd, 11, 6, Dm); }
|
||||||
// double-precision comparison instructions
|
// double-precision comparison instructions
|
||||||
inline int fcmpd(int Dd, int Dm) { return COOP(AL, 0xb, 4, Dd, 11, 2, Dm); }
|
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
|
// 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 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 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); }
|
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
|
// 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 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); };
|
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
|
// 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 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); }
|
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
|
// 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); }
|
inline int fmrx(int Rd, int reg) { return mrc(10, 7, Rd, reg, 0); }
|
||||||
// these move around pairs of single-precision registers
|
// 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 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); }
|
inline int fmrrd(int Rd, int Rn, int Dm) { return mrrc(11, 1, Rd, Rn, Dm); }
|
||||||
// FLAG SETTERS
|
// FLAG SETTERS
|
||||||
inline int SETCOND(int ins, int cond) { return ((ins&0x0fffffff) | (cond<<28)); }
|
inline int SETCOND(int ins, int cond) { return ((ins&0x0fffffff) | (cond<<28)); }
|
||||||
inline int SETS(int ins) { return ins | 1<<20; }
|
inline int SETS(int ins) { return ins | 1<<20; }
|
||||||
// PSEUDO-INSTRUCTIONS
|
// 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 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 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 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 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 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 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 beq(int offset) { return SETCOND(b(offset), EQ); }
|
||||||
inline int bne(int offset) { return SETCOND(b(offset), NE); }
|
inline int bne(int offset) { return SETCOND(b(offset), NE); }
|
||||||
inline int bls(int offset) { return SETCOND(b(offset), LS); }
|
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); }
|
inline int fmstat() { return fmrx(15, FPSCR); }
|
||||||
// HARDWARE FLAGS
|
// HARDWARE FLAGS
|
||||||
bool vfpSupported() {
|
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 uint64_t MASK_LO32 = 0xffffffff;
|
||||||
const unsigned MASK_LO16 = 0xffff;
|
const unsigned MASK_LO16 = 0xffff;
|
||||||
const unsigned MASK_LO8 = 0xff;
|
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 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(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_GPRS = 16;
|
||||||
const int N_FPRS = 16;
|
const int N_FPRS = 16;
|
||||||
@ -567,7 +488,7 @@ isBranch(TernaryOperation op)
|
|||||||
return op > FloatMin;
|
return op > FloatMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool UNUSED
|
||||||
isFloatBranch(TernaryOperation op)
|
isFloatBranch(TernaryOperation op)
|
||||||
{
|
{
|
||||||
return op > JumpIfNotEqual;
|
return op > JumpIfNotEqual;
|
||||||
@ -634,72 +555,118 @@ write4(uint8_t* dst, uint32_t v)
|
|||||||
memcpy(dst, &v, 4);
|
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)
|
void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t)
|
||||||
{
|
{
|
||||||
if (size == 8) {
|
if (size == 8) {
|
||||||
int tmp1 = newTemp(con), tmp2 = newTemp(con);
|
int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con);
|
||||||
emit(con, lsl(tmp1, b->high, a->low));
|
ResolvedPromise maskPromise(0x3F);
|
||||||
emit(con, rsbi(tmp2, a->low, 32));
|
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, 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(mov(t->high, tmp1), MI));
|
||||||
emit(con, SETCOND(lsl(t->high, b->low, t->high), PL));
|
emit(con, SETCOND(lsl(t->high, b->low, t->high), PL));
|
||||||
emit(con, lsl(t->low, b->low, a->low));
|
emit(con, lsl(t->low, b->low, tmp3));
|
||||||
freeTemp(con, tmp1); freeTemp(con, tmp2);
|
freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3);
|
||||||
} else {
|
} 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)
|
void shiftLeftC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
|
||||||
{
|
{
|
||||||
assert(con, size == TargetBytesPerWord);
|
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)
|
void shiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t)
|
||||||
{
|
{
|
||||||
if (size == 8) {
|
if (size == 8) {
|
||||||
int tmp1 = newTemp(con), tmp2 = newTemp(con);
|
int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con);
|
||||||
emit(con, lsr(tmp1, b->low, a->low));
|
ResolvedPromise maskPromise(0x3F);
|
||||||
emit(con, rsbi(tmp2, a->low, 32));
|
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, 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(mov(t->low, tmp1), MI));
|
||||||
emit(con, SETCOND(asr(t->low, b->high, t->low), PL));
|
emit(con, SETCOND(asr(t->low, b->high, t->low), PL));
|
||||||
emit(con, asr(t->high, b->high, a->low));
|
emit(con, asr(t->high, b->high, tmp3));
|
||||||
freeTemp(con, tmp1); freeTemp(con, tmp2);
|
freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3);
|
||||||
} else {
|
} 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)
|
void shiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
|
||||||
{
|
{
|
||||||
assert(con, size == TargetBytesPerWord);
|
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)
|
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) {
|
if (size == 8) {
|
||||||
int tmpHi = newTemp(con), tmpLo = newTemp(con);
|
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, lsl(tmpLo, b->high, tmpHi));
|
||||||
emit(con, orr(t->low, t->low, tmpLo));
|
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, lsr(tmpLo, b->high, tmpHi));
|
||||||
emit(con, orr(t->low, t->low, tmpLo));
|
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, tmpHi); freeTemp(con, tmpLo);
|
||||||
}
|
}
|
||||||
|
freeTemp(con, tmpShift);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsignedShiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
|
void unsignedShiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
|
||||||
{
|
{
|
||||||
assert(con, size == TargetBytesPerWord);
|
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 {
|
class ConstantPoolEntry: public Promise {
|
||||||
@ -909,10 +876,6 @@ jumpR(Context* con, unsigned size UNUSED, Assembler::Register* target)
|
|||||||
emit(con, bx(target->low));
|
emit(con, bx(target->low));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
moveRR(Context* con, unsigned srcSize, Assembler::Register* src,
|
|
||||||
unsigned dstSize, Assembler::Register* dst);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
swapRR(Context* con, unsigned aSize, Assembler::Register* a,
|
swapRR(Context* con, unsigned aSize, Assembler::Register* a,
|
||||||
unsigned bSize, Assembler::Register* b)
|
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);
|
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
|
void
|
||||||
load(Context* con, unsigned srcSize, int base, int offset, int index,
|
load(Context* con, unsigned srcSize, int base, int offset, int index,
|
||||||
unsigned scale, unsigned dstSize, Assembler::Register* dst,
|
unsigned scale, unsigned dstSize, Assembler::Register* dst,
|
||||||
@ -2354,7 +2300,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
{
|
{
|
||||||
*thunk = false;
|
*thunk = false;
|
||||||
*aTypeMask = ~0;
|
*aTypeMask = ~0;
|
||||||
*aRegisterMask = ~static_cast<uint64_t>(0);
|
*aRegisterMask = GPR_MASK64;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Negate:
|
case Negate:
|
||||||
@ -2379,7 +2325,11 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Float2Int:
|
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);
|
*aTypeMask = (1 << RegisterOperand);
|
||||||
*aRegisterMask = FPR_MASK64;
|
*aRegisterMask = FPR_MASK64;
|
||||||
} else {
|
} else {
|
||||||
@ -2407,7 +2357,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
unsigned , uint8_t* bTypeMask, uint64_t* bRegisterMask)
|
unsigned , uint8_t* bTypeMask, uint64_t* bRegisterMask)
|
||||||
{
|
{
|
||||||
*bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
*bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
||||||
*bRegisterMask = ~static_cast<uint64_t>(0);
|
*bRegisterMask = GPR_MASK64;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Negate:
|
case Negate:
|
||||||
@ -2538,7 +2488,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
virtual void planDestination
|
virtual void planDestination
|
||||||
(TernaryOperation op,
|
(TernaryOperation op,
|
||||||
unsigned, uint8_t, uint64_t,
|
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)
|
unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask)
|
||||||
{
|
{
|
||||||
if (isBranch(op)) {
|
if (isBranch(op)) {
|
||||||
@ -2546,7 +2496,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
*cRegisterMask = 0;
|
*cRegisterMask = 0;
|
||||||
} else {
|
} else {
|
||||||
*cTypeMask = (1 << RegisterOperand);
|
*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))
|
THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss))
|
||||||
# define LINK_REGISTER(context) \
|
# define LINK_REGISTER(context) \
|
||||||
THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss))
|
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 IP_REGISTER(context) (context->uc_mcontext.arm_pc)
|
||||||
# define STACK_REGISTER(context) (context->uc_mcontext.arm_sp)
|
# define STACK_REGISTER(context) (context->uc_mcontext.arm_sp)
|
||||||
# define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip)
|
# define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip)
|
||||||
@ -55,7 +63,8 @@
|
|||||||
|
|
||||||
extern "C" uint64_t
|
extern "C" uint64_t
|
||||||
vmNativeCall(void* function, unsigned stackTotal, void* memoryTable,
|
vmNativeCall(void* function, unsigned stackTotal, void* memoryTable,
|
||||||
unsigned memoryCount, void* gprTable);
|
unsigned memoryCount, void* gprTable, void* vfpTable,
|
||||||
|
unsigned returnType);
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
@ -94,6 +103,8 @@ syncInstructionCache(const void* start, unsigned size)
|
|||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
sys_icache_invalidate(const_cast<void*>(start), size);
|
sys_icache_invalidate(const_cast<void*>(start), size);
|
||||||
|
#elif (defined __QNX__)
|
||||||
|
msync(const_cast<void*>(start), size, MS_INVALIDATE_ICACHE);
|
||||||
#else
|
#else
|
||||||
__clear_cache
|
__clear_cache
|
||||||
(const_cast<void*>(start),
|
(const_cast<void*>(start),
|
||||||
@ -111,6 +122,8 @@ atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_)
|
|||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
return OSAtomicCompareAndSwap32(old, new_, reinterpret_cast<int32_t*>(p));
|
return OSAtomicCompareAndSwap32(old, new_, reinterpret_cast<int32_t*>(p));
|
||||||
|
#elif (defined __QNX__)
|
||||||
|
return old == _smp_cmpxchg(p, old, new_);
|
||||||
#else
|
#else
|
||||||
int r = __kernel_cmpxchg(static_cast<int>(old), static_cast<int>(new_), reinterpret_cast<int*>(p));
|
int r = __kernel_cmpxchg(static_cast<int>(old), static_cast<int>(new_), reinterpret_cast<int*>(p));
|
||||||
return (!r ? true : false);
|
return (!r ? true : false);
|
||||||
@ -126,7 +139,7 @@ atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
|
|||||||
inline uint64_t
|
inline uint64_t
|
||||||
dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
|
dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
|
||||||
unsigned argumentCount, unsigned argumentsSize UNUSED,
|
unsigned argumentCount, unsigned argumentsSize UNUSED,
|
||||||
unsigned returnType UNUSED)
|
unsigned returnType)
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
const unsigned Alignment = 1;
|
const unsigned Alignment = 1;
|
||||||
@ -138,6 +151,11 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
|
|||||||
uintptr_t gprTable[GprCount];
|
uintptr_t gprTable[GprCount];
|
||||||
unsigned gprIndex = 0;
|
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
|
uintptr_t stack[(argumentCount * 8) / BytesPerWord]; // is > argumentSize to account for padding
|
||||||
unsigned stackIndex = 0;
|
unsigned stackIndex = 0;
|
||||||
|
|
||||||
@ -145,6 +163,40 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
|
|||||||
for (unsigned ati = 0; ati < argumentCount; ++ ati) {
|
for (unsigned ati = 0; ati < argumentCount; ++ ati) {
|
||||||
switch (argumentTypes[ati]) {
|
switch (argumentTypes[ati]) {
|
||||||
case DOUBLE_TYPE:
|
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: {
|
case INT64_TYPE: {
|
||||||
if (gprIndex + Alignment <= GprCount) { // pass argument in register(s)
|
if (gprIndex + Alignment <= GprCount) { // pass argument in register(s)
|
||||||
if (Alignment == 1
|
if (Alignment == 1
|
||||||
@ -188,11 +240,16 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
|
|||||||
memset(gprTable + gprIndex, 0, (GprCount-gprIndex)*4);
|
memset(gprTable + gprIndex, 0, (GprCount-gprIndex)*4);
|
||||||
gprIndex = GprCount;
|
gprIndex = GprCount;
|
||||||
}
|
}
|
||||||
|
if (vfpIndex < VfpCount) {
|
||||||
|
memset(vfpTable + vfpIndex, 0, (VfpCount-vfpIndex)*4);
|
||||||
|
vfpIndex = VfpCount;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned stackSize = stackIndex*BytesPerWord + ((stackIndex & 1) << 2);
|
unsigned stackSize = stackIndex*BytesPerWord + ((stackIndex & 1) << 2);
|
||||||
return vmNativeCall
|
return vmNativeCall
|
||||||
(function, stackSize, stack, stackIndex * BytesPerWord,
|
(function, stackSize, stack, stackIndex * BytesPerWord,
|
||||||
(gprIndex ? gprTable : 0));
|
(gprIndex ? gprTable : 0),
|
||||||
|
(vfpIndex ? vfpTable : 0), returnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -198,7 +198,7 @@ public:
|
|||||||
const unsigned machine;
|
const unsigned machine;
|
||||||
|
|
||||||
ElfPlatform(PlatformInfo::Architecture arch):
|
ElfPlatform(PlatformInfo::Architecture arch):
|
||||||
Platform(PlatformInfo(PlatformInfo::Linux, arch)),
|
Platform(PlatformInfo(PlatformInfo::Elf, arch)),
|
||||||
machine(getElfPlatform(arch)) {}
|
machine(getElfPlatform(arch)) {}
|
||||||
|
|
||||||
class FileWriter {
|
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> elfArmPlatform(PlatformInfo::Arm);
|
||||||
ElfPlatform<uint32_t, false> elfPowerPCPlatform(PlatformInfo::PowerPC);
|
ElfPlatform<uint32_t, false> elfPowerPCPlatform(PlatformInfo::PowerPC);
|
||||||
ElfPlatform<uint64_t> elfx86_64Platform(PlatformInfo::x86_64);
|
ElfPlatform<uint64_t> elfX86_64Platform(PlatformInfo::x86_64);
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -286,7 +286,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
MachOPlatform(PlatformInfo::Architecture arch):
|
MachOPlatform(PlatformInfo::Architecture arch):
|
||||||
Platform(PlatformInfo(PlatformInfo::Darwin, arch)) {}
|
Platform(PlatformInfo(PlatformInfo::MachO, arch)) {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,14 +41,14 @@ using namespace avian::tools;
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
writeObject(uint8_t* data, size_t size, OutputStream* out, const char* startName,
|
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,
|
const char* architecture, unsigned alignment, bool writable,
|
||||||
bool executable)
|
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) {
|
if(!platform) {
|
||||||
fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture);
|
fprintf(stderr, "unsupported platform: %s/%s\n", format, architecture);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
WindowsPlatform():
|
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;
|
WindowsPlatform<4> windows32Platform;
|
||||||
|
@ -85,15 +85,23 @@ void FileOutputStream::write(uint8_t byte) {
|
|||||||
|
|
||||||
Platform* Platform::first = 0;
|
Platform* Platform::first = 0;
|
||||||
|
|
||||||
PlatformInfo::OperatingSystem PlatformInfo::osFromString(const char* os) {
|
PlatformInfo::Format PlatformInfo::formatFromString(const char* format) {
|
||||||
if(strcmp(os, "linux") == 0) {
|
if (strcmp(format, "elf") == 0
|
||||||
return Linux;
|
or strcmp(format, "linux") == 0
|
||||||
} else if(strcmp(os, "windows") == 0) {
|
or strcmp(format, "freebsd") == 0
|
||||||
return Windows;
|
or strcmp(format, "qnx") == 0)
|
||||||
} else if(strcmp(os, "darwin") == 0) {
|
{
|
||||||
return Darwin;
|
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 {
|
} else {
|
||||||
return UnknownOS;
|
return UnknownFormat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,3 +131,4 @@ Platform* Platform::getPlatform(PlatformInfo info) {
|
|||||||
} // namespace tools
|
} // namespace tools
|
||||||
|
|
||||||
} // namespace avian
|
} // namespace avian
|
||||||
|
|
||||||
|
@ -131,11 +131,11 @@ public:
|
|||||||
|
|
||||||
class PlatformInfo {
|
class PlatformInfo {
|
||||||
public:
|
public:
|
||||||
enum OperatingSystem {
|
enum Format {
|
||||||
Linux = AVIAN_PLATFORM_LINUX,
|
Elf = AVIAN_FORMAT_ELF,
|
||||||
Windows = AVIAN_PLATFORM_WINDOWS,
|
Pe = AVIAN_FORMAT_PE,
|
||||||
Darwin = AVIAN_PLATFORM_DARWIN,
|
MachO = AVIAN_FORMAT_MACHO,
|
||||||
UnknownOS = AVIAN_PLATFORM_UNKNOWN
|
UnknownFormat = AVIAN_FORMAT_UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Architecture {
|
enum Architecture {
|
||||||
@ -146,18 +146,18 @@ public:
|
|||||||
UnknownArch = AVIAN_ARCH_UNKNOWN
|
UnknownArch = AVIAN_ARCH_UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
const OperatingSystem os;
|
const Format format;
|
||||||
const Architecture arch;
|
const Architecture arch;
|
||||||
|
|
||||||
static OperatingSystem osFromString(const char* os);
|
static Format formatFromString(const char* format);
|
||||||
static Architecture archFromString(const char* arch);
|
static Architecture archFromString(const char* arch);
|
||||||
|
|
||||||
inline PlatformInfo(OperatingSystem os, Architecture arch):
|
inline PlatformInfo(Format format, Architecture arch):
|
||||||
os(os),
|
format(format),
|
||||||
arch(arch) {}
|
arch(arch) {}
|
||||||
|
|
||||||
inline bool operator == (const PlatformInfo& other) {
|
inline bool operator == (const PlatformInfo& other) {
|
||||||
return os == other.os && arch == other.arch;
|
return format == other.format && arch == other.arch;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isLittleEndian() {
|
inline bool isLittleEndian() {
|
||||||
@ -194,3 +194,4 @@ public:
|
|||||||
} // namespace avian
|
} // namespace avian
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ const unsigned TargetFixieSizeInBytes = 8 + (TargetBytesPerWord * 2);
|
|||||||
const unsigned TargetFixieSizeInWords = ceiling
|
const unsigned TargetFixieSizeInWords = ceiling
|
||||||
(TargetFixieSizeInBytes, TargetBytesPerWord);
|
(TargetFixieSizeInBytes, TargetBytesPerWord);
|
||||||
const unsigned TargetFixieAge = 0;
|
const unsigned TargetFixieAge = 0;
|
||||||
const unsigned TargetFixieHasMask = 1;
|
const unsigned TargetFixieFlags = 2;
|
||||||
const unsigned TargetFixieSize = 4;
|
const unsigned TargetFixieSize = 4;
|
||||||
|
|
||||||
const bool DebugNativeTarget = false;
|
const bool DebugNativeTarget = false;
|
||||||
@ -310,7 +310,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
|||||||
if (endsWith(".class", name, nameSize)
|
if (endsWith(".class", name, nameSize)
|
||||||
and (className == 0 or strncmp(name, className, nameSize - 6) == 0))
|
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
|
object c = resolveSystemClass
|
||||||
(t, root(t, Machine::BootLoader),
|
(t, root(t, Machine::BootLoader),
|
||||||
makeByteArray(t, "%.*s", nameSize - 6, name), true);
|
makeByteArray(t, "%.*s", nameSize - 6, name), true);
|
||||||
@ -413,8 +413,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (strcmp(name, "java/lang/System$Property.class") == 0) trap();
|
|
||||||
|
|
||||||
{ object array = 0;
|
{ object array = 0;
|
||||||
PROTECT(t, array);
|
PROTECT(t, array);
|
||||||
|
|
||||||
@ -441,11 +439,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
|||||||
|
|
||||||
memberFields[memberIndex] = *f;
|
memberFields[memberIndex] = *f;
|
||||||
|
|
||||||
while (targetMemberOffset % f->targetSize) {
|
targetMemberOffset = f->targetOffset + f->targetSize;
|
||||||
++ targetMemberOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
targetMemberOffset += f->targetSize;
|
|
||||||
|
|
||||||
++ memberIndex;
|
++ memberIndex;
|
||||||
}
|
}
|
||||||
@ -458,7 +452,9 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
|||||||
targetMemberOffset = TargetBytesPerWord;
|
targetMemberOffset = TargetBytesPerWord;
|
||||||
}
|
}
|
||||||
|
|
||||||
Field staticFields[count + 2];
|
const unsigned StaticHeader = 3;
|
||||||
|
|
||||||
|
Field staticFields[count + StaticHeader];
|
||||||
|
|
||||||
init(new (staticFields) Field, Type_object, 0, BytesPerWord, 0,
|
init(new (staticFields) Field, Type_object, 0, BytesPerWord, 0,
|
||||||
TargetBytesPerWord);
|
TargetBytesPerWord);
|
||||||
@ -466,9 +462,12 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
|||||||
init(new (staticFields + 1) Field, Type_intptr_t, BytesPerWord,
|
init(new (staticFields + 1) Field, Type_intptr_t, BytesPerWord,
|
||||||
BytesPerWord, TargetBytesPerWord, TargetBytesPerWord);
|
BytesPerWord, TargetBytesPerWord, TargetBytesPerWord);
|
||||||
|
|
||||||
unsigned staticIndex = 2;
|
init(new (staticFields + 2) Field, Type_object, BytesPerWord * 2,
|
||||||
unsigned buildStaticOffset = BytesPerWord * 2;
|
BytesPerWord, TargetBytesPerWord * 2, TargetBytesPerWord);
|
||||||
unsigned targetStaticOffset = TargetBytesPerWord * 2;
|
|
||||||
|
unsigned staticIndex = StaticHeader;
|
||||||
|
unsigned buildStaticOffset = BytesPerWord * StaticHeader;
|
||||||
|
unsigned targetStaticOffset = TargetBytesPerWord * StaticHeader;
|
||||||
|
|
||||||
for (unsigned i = 0; i < vectorSize(t, fields); ++i) {
|
for (unsigned i = 0; i < vectorSize(t, fields); ++i) {
|
||||||
object field = vectorBody(t, fields, i);
|
object field = vectorBody(t, fields, i);
|
||||||
@ -540,8 +539,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (strcmp(name, "avian/VMClass.class") == 0) trap();
|
|
||||||
|
|
||||||
if (hashMapFind(t, typeMaps, c, objectHash, objectEqual) == 0) {
|
if (hashMapFind(t, typeMaps, c, objectHash, objectEqual) == 0) {
|
||||||
object array = makeByteArray
|
object array = makeByteArray
|
||||||
(t, TypeMap::sizeInBytes
|
(t, TypeMap::sizeInBytes
|
||||||
@ -600,7 +597,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
|||||||
if (endsWith(".class", name, nameSize)
|
if (endsWith(".class", name, nameSize)
|
||||||
and (className == 0 or strncmp(name, className, nameSize - 6) == 0))
|
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
|
object c = resolveSystemClass
|
||||||
(t, root(t, Machine::BootLoader),
|
(t, root(t, Machine::BootLoader),
|
||||||
makeByteArray(t, "%.*s", nameSize - 6, name), true);
|
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);
|
memset(heap + position, 0, TargetFixieSizeInBytes);
|
||||||
|
|
||||||
uint8_t age = FixieTenureThreshold + 1;
|
uint16_t age = targetV2(FixieTenureThreshold + 1);
|
||||||
memcpy(reinterpret_cast<uint8_t*>(heap + position)
|
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)
|
memcpy(reinterpret_cast<uint8_t*>(heap + position)
|
||||||
+ TargetFixieHasMask, &hasMask, 1);
|
+ TargetFixieFlags, &flags, 2);
|
||||||
|
|
||||||
uint32_t targetSize = targetV4(size);
|
uint32_t targetSize = targetV4(size);
|
||||||
memcpy(reinterpret_cast<uint8_t*>(heap + position)
|
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);
|
// 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) {
|
// if(!platform) {
|
||||||
// fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture);
|
// fprintf(stderr, "unsupported platform: %s/%s\n", os, architecture);
|
||||||
|
@ -155,7 +155,7 @@ Avian_java_lang_Runtime_exit
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength
|
Avian_avian_avianvmresource_Handler_00024ResourceInputStream_getContentLength
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
object path = reinterpret_cast<object>(*arguments);
|
object path = reinterpret_cast<object>(*arguments);
|
||||||
@ -179,7 +179,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
Avian_avian_resource_Handler_00024ResourceInputStream_open
|
Avian_avian_avianvmresource_Handler_00024ResourceInputStream_open
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
object path = reinterpret_cast<object>(*arguments);
|
object path = reinterpret_cast<object>(*arguments);
|
||||||
@ -200,7 +200,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
Avian_avian_resource_Handler_00024ResourceInputStream_available
|
Avian_avian_avianvmresource_Handler_00024ResourceInputStream_available
|
||||||
(Thread*, object, uintptr_t* arguments)
|
(Thread*, object, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
int64_t peer; memcpy(&peer, arguments, 8);
|
int64_t peer; memcpy(&peer, arguments, 8);
|
||||||
@ -211,7 +211,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_available
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
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)
|
(Thread*, object, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
int64_t peer; memcpy(&peer, arguments, 8);
|
int64_t peer; memcpy(&peer, arguments, 8);
|
||||||
@ -226,7 +226,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_read__JI
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
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)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
int64_t peer; memcpy(&peer, arguments, 8);
|
int64_t peer; memcpy(&peer, arguments, 8);
|
||||||
@ -251,7 +251,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_read__JI_3BII
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Avian_avian_resource_Handler_00024ResourceInputStream_close
|
Avian_avian_avianvmresource_Handler_00024ResourceInputStream_close
|
||||||
(Thread*, object, uintptr_t* arguments)
|
(Thread*, object, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
int64_t peer; memcpy(&peer, arguments, 8);
|
int64_t peer; memcpy(&peer, arguments, 8);
|
||||||
@ -511,3 +511,55 @@ Avian_sun_misc_Unsafe_getAddress__J
|
|||||||
|
|
||||||
return *reinterpret_cast<intptr_t*>(p);
|
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;
|
return AVIAN_CLASSPATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
updatePackageMap(Thread*, object)
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
dispose()
|
dispose()
|
||||||
{
|
{
|
||||||
|
@ -278,7 +278,7 @@ makeStackTraceElement(Thread* t, object e)
|
|||||||
THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, class_));
|
THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, class_));
|
||||||
replace('/', '.', RUNTIME_ARRAY_BODY(s),
|
replace('/', '.', RUNTIME_ARRAY_BODY(s),
|
||||||
reinterpret_cast<char*>(&byteArrayBody(t, class_, 0)));
|
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));
|
object method = methodName(t, traceElementMethod(t, e));
|
||||||
PROTECT(t, method);
|
PROTECT(t, method);
|
||||||
|
@ -349,48 +349,66 @@ clearInterrupted(Thread*);
|
|||||||
|
|
||||||
class MyClasspath : public Classpath {
|
class MyClasspath : public Classpath {
|
||||||
public:
|
public:
|
||||||
static const unsigned BufferSize = 1024;
|
|
||||||
|
|
||||||
MyClasspath(System* s, Allocator* allocator, const char* javaHome,
|
MyClasspath(System* s, Allocator* allocator, const char* javaHome,
|
||||||
const char* embedPrefix):
|
const char* embedPrefix):
|
||||||
allocator(allocator), ranNetOnLoad(0), ranManagementOnLoad(0)
|
allocator(allocator), ranNetOnLoad(0), ranManagementOnLoad(0)
|
||||||
{
|
{
|
||||||
class StringBuilder {
|
class StringBuilder {
|
||||||
public:
|
public:
|
||||||
StringBuilder(System* s, char* pointer, unsigned remaining):
|
StringBuilder(System* s, Allocator* allocator):
|
||||||
s(s), pointer(pointer), remaining(remaining)
|
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) {
|
void append(const char* append) {
|
||||||
unsigned length = strlen(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;
|
offset += length;
|
||||||
pointer += length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void append(char c) {
|
void append(char c) {
|
||||||
assert(s, remaining > 1);
|
ensure(2);
|
||||||
|
|
||||||
pointer[0] = c;
|
buffer[offset] = c;
|
||||||
pointer[1] = 0;
|
buffer[offset + 1] = 0;
|
||||||
|
|
||||||
-- remaining;
|
++ offset;
|
||||||
++ pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
char* pointer;
|
Allocator* allocator;
|
||||||
unsigned remaining;
|
unsigned bufferSize;
|
||||||
} sb(s, buffer, BufferSize);
|
char* buffer;
|
||||||
|
unsigned offset;
|
||||||
|
} sb(s, allocator);
|
||||||
|
|
||||||
this->javaHome = sb.pointer;
|
unsigned javaHomeOffset = sb.offset;
|
||||||
sb.append(javaHome);
|
sb.append(javaHome);
|
||||||
sb.append('\0');
|
sb.append('\0');
|
||||||
|
|
||||||
this->classpath = sb.pointer;
|
unsigned classpathOffset = sb.offset;
|
||||||
sb.append(AVIAN_CLASSPATH);
|
sb.append(AVIAN_CLASSPATH);
|
||||||
sb.append(s->pathSeparator());
|
sb.append(s->pathSeparator());
|
||||||
sb.append(javaHome);
|
sb.append(javaHome);
|
||||||
@ -409,7 +427,7 @@ class MyClasspath : public Classpath {
|
|||||||
sb.append("/lib/resources.jar");
|
sb.append("/lib/resources.jar");
|
||||||
sb.append('\0');
|
sb.append('\0');
|
||||||
|
|
||||||
this->libraryPath = sb.pointer;
|
unsigned libraryPathOffset = sb.offset;
|
||||||
sb.append(javaHome);
|
sb.append(javaHome);
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
sb.append("/bin");
|
sb.append("/bin");
|
||||||
@ -417,21 +435,31 @@ class MyClasspath : public Classpath {
|
|||||||
sb.append("/lib");
|
sb.append("/lib");
|
||||||
#elif defined ARCH_x86_64
|
#elif defined ARCH_x86_64
|
||||||
sb.append("/lib/amd64");
|
sb.append("/lib/amd64");
|
||||||
|
#elif defined ARCH_arm
|
||||||
|
sb.append("/lib/arm");
|
||||||
#else
|
#else
|
||||||
// todo: handle other architectures
|
// todo: handle other architectures
|
||||||
sb.append("/lib/i386");
|
sb.append("/lib/i386");
|
||||||
#endif
|
#endif
|
||||||
sb.append('\0');
|
sb.append('\0');
|
||||||
|
|
||||||
this->tzMappings = sb.pointer;
|
unsigned tzMappingsOffset = sb.offset;
|
||||||
sb.append(javaHome);
|
sb.append(javaHome);
|
||||||
sb.append("/lib/tzmappings");
|
sb.append("/lib/tzmappings");
|
||||||
this->tzMappingsLength = sb.pointer - tzMappings;
|
this->tzMappingsLength = sb.offset - tzMappingsOffset;
|
||||||
sb.append('\0');
|
sb.append('\0');
|
||||||
|
|
||||||
this->embedPrefix = sb.pointer;
|
unsigned embedPrefixOffset = sb.offset;
|
||||||
sb.append(embedPrefix);
|
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
|
virtual object
|
||||||
@ -532,7 +560,7 @@ class MyClasspath : public Classpath {
|
|||||||
virtual void
|
virtual void
|
||||||
resolveNative(Thread* t, object method)
|
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
|
&byteArrayBody(t, className(t, methodClass(t, method)), 0)) == 0
|
||||||
and strcmp(reinterpret_cast<const int8_t*>("initIDs"),
|
and strcmp(reinterpret_cast<const int8_t*>("initIDs"),
|
||||||
&byteArrayBody(t, methodName(t, method), 0)) == 0
|
&byteArrayBody(t, methodName(t, method), 0)) == 0
|
||||||
@ -621,6 +649,13 @@ class MyClasspath : public Classpath {
|
|||||||
t->m->processor->invoke
|
t->m->processor->invoke
|
||||||
(t, root(t, Machine::BootLoader), "java/lang/System",
|
(t, root(t, Machine::BootLoader), "java/lang/System",
|
||||||
"initializeSystemClass", "()V", 0);
|
"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*
|
virtual const char*
|
||||||
@ -629,9 +664,51 @@ class MyClasspath : public Classpath {
|
|||||||
return 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
|
virtual void
|
||||||
dispose()
|
dispose()
|
||||||
{
|
{
|
||||||
|
allocator->free(buffer, bufferSize);
|
||||||
allocator->free(this, sizeof(*this));
|
allocator->free(this, sizeof(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,6 +718,8 @@ class MyClasspath : public Classpath {
|
|||||||
const char* libraryPath;
|
const char* libraryPath;
|
||||||
const char* tzMappings;
|
const char* tzMappings;
|
||||||
const char* embedPrefix;
|
const char* embedPrefix;
|
||||||
|
char* buffer;
|
||||||
|
unsigned bufferSize;
|
||||||
unsigned tzMappingsLength;
|
unsigned tzMappingsLength;
|
||||||
unsigned embedPrefixLength;
|
unsigned embedPrefixLength;
|
||||||
unsigned filePathField;
|
unsigned filePathField;
|
||||||
@ -655,7 +734,6 @@ class MyClasspath : public Classpath {
|
|||||||
unsigned zipEntryMethodField;
|
unsigned zipEntryMethodField;
|
||||||
bool ranNetOnLoad;
|
bool ranNetOnLoad;
|
||||||
bool ranManagementOnLoad;
|
bool ranManagementOnLoad;
|
||||||
char buffer[BufferSize];
|
|
||||||
JmmInterface jmmInterface;
|
JmmInterface jmmInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2283,12 +2361,29 @@ fieldForOffsetInClass(Thread* t, object c, unsigned offset)
|
|||||||
object
|
object
|
||||||
fieldForOffset(Thread* t, object o, unsigned offset)
|
fieldForOffset(Thread* t, object o, unsigned offset)
|
||||||
{
|
{
|
||||||
object field = fieldForOffsetInClass(t, objectClass(t, o), offset);
|
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) {
|
if (field) {
|
||||||
return field;
|
return field;
|
||||||
} else {
|
} else {
|
||||||
abort(t);
|
abort(t);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace local
|
} // namespace local
|
||||||
@ -2311,10 +2406,13 @@ extern "C" JNIEXPORT int64_t JNICALL
|
|||||||
Avian_java_lang_Class_getSuperclass
|
Avian_java_lang_Class_getSuperclass
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
object super = classSuper
|
object class_ = jclassVmClass(t, reinterpret_cast<object>(arguments[0]));
|
||||||
(t, 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;
|
return super ? reinterpret_cast<int64_t>(getJClass(t, super)) : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void
|
extern "C" JNIEXPORT void
|
||||||
@ -2394,13 +2492,6 @@ Avian_sun_misc_Unsafe_staticFieldOffset
|
|||||||
(t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield)));
|
(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
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
Avian_sun_misc_Unsafe_arrayIndexScale
|
Avian_sun_misc_Unsafe_arrayIndexScale
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(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);
|
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
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
Avian_sun_misc_Unsafe_getLongVolatile
|
Avian_sun_misc_Unsafe_getLongVolatile
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
@ -2782,32 +2881,6 @@ Avian_sun_misc_Unsafe_park
|
|||||||
monitorRelease(t, local::interruptLock(t, t->javaThread));
|
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
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Avian_sun_misc_Unsafe_monitorEnter
|
Avian_sun_misc_Unsafe_monitorEnter
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
@ -3002,6 +3075,8 @@ jvmInitProperties(Thread* t, uintptr_t* arguments)
|
|||||||
local::setProperty(t, method, *properties, "path.separator", ":");
|
local::setProperty(t, method, *properties, "path.separator", ":");
|
||||||
# ifdef __APPLE__
|
# ifdef __APPLE__
|
||||||
local::setProperty(t, method, *properties, "os.name", "Mac OS X");
|
local::setProperty(t, method, *properties, "os.name", "Mac OS X");
|
||||||
|
# elif defined __FreeBSD__
|
||||||
|
local::setProperty(t, method, *properties, "os.name", "FreeBSD");
|
||||||
# else // not __APPLE__
|
# else // not __APPLE__
|
||||||
local::setProperty(t, method, *properties, "os.name", "Linux");
|
local::setProperty(t, method, *properties, "os.name", "Linux");
|
||||||
# endif // not __APPLE__
|
# endif // not __APPLE__
|
||||||
@ -3019,6 +3094,14 @@ jvmInitProperties(Thread* t, uintptr_t* arguments)
|
|||||||
local::setProperty(t, method, *properties, "java.vm.vendor",
|
local::setProperty(t, method, *properties, "java.vm.vendor",
|
||||||
"Avian Contributors");
|
"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
|
local::setProperty
|
||||||
(t, method, *properties, "java.home",
|
(t, method, *properties, "java.home",
|
||||||
static_cast<local::MyClasspath*>(t->m->classpath)->javaHome);
|
static_cast<local::MyClasspath*>(t->m->classpath)->javaHome);
|
||||||
@ -3128,7 +3211,7 @@ EXPORT(JVM_FreeMemory)()
|
|||||||
extern "C" JNIEXPORT jlong JNICALL
|
extern "C" JNIEXPORT jlong JNICALL
|
||||||
EXPORT(JVM_MaxMemory)()
|
EXPORT(JVM_MaxMemory)()
|
||||||
{
|
{
|
||||||
return 0;
|
return local::globalMachine->heap->limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
@ -3328,6 +3411,10 @@ jvmSleep(Thread* t, uintptr_t* arguments)
|
|||||||
{
|
{
|
||||||
jlong milliseconds; memcpy(&milliseconds, arguments, sizeof(jlong));
|
jlong milliseconds; memcpy(&milliseconds, arguments, sizeof(jlong));
|
||||||
|
|
||||||
|
if (milliseconds <= 0) {
|
||||||
|
milliseconds = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (threadSleepLock(t, t->javaThread) == 0) {
|
if (threadSleepLock(t, t->javaThread) == 0) {
|
||||||
object lock = makeJobject(t);
|
object lock = makeJobject(t);
|
||||||
set(t, t->javaThread, ThreadSleepLock, lock);
|
set(t, t->javaThread, ThreadSleepLock, lock);
|
||||||
@ -3516,10 +3603,37 @@ EXPORT(JVM_ClassDepth)(Thread*, jstring) { abort(); }
|
|||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
EXPORT(JVM_ClassLoaderDepth)(Thread*) { abort(); }
|
EXPORT(JVM_ClassLoaderDepth)(Thread*) { abort(); }
|
||||||
|
|
||||||
extern "C" JNIEXPORT jstring JNICALL
|
uint64_t
|
||||||
EXPORT(JVM_GetSystemPackage)(Thread*, jstring)
|
jvmGetSystemPackage(Thread* t, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
|
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;
|
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
|
uint64_t
|
||||||
@ -3787,7 +3901,7 @@ EXPORT(JVM_GetCallerClass)(Thread* t, int target)
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
object method = getCaller(t, target);
|
object method = getCaller(t, target, true);
|
||||||
|
|
||||||
return method ? makeLocalReference
|
return method ? makeLocalReference
|
||||||
(t, getJClass(t, methodClass(t, method))) : 0;
|
(t, getJClass(t, methodClass(t, method))) : 0;
|
||||||
@ -4553,6 +4667,14 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments)
|
|||||||
|
|
||||||
unsigned returnCode = methodReturnCode(t, vmMethod);
|
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;
|
object result;
|
||||||
if (args) {
|
if (args) {
|
||||||
result = t->m->processor->invokeArray
|
result = t->m->processor->invokeArray
|
||||||
@ -4591,6 +4713,14 @@ jvmNewInstanceFromConstructor(Thread* t, uintptr_t* arguments)
|
|||||||
(t, jclassVmClass(t, jconstructorClazz(t, *constructor))),
|
(t, jclassVmClass(t, jconstructorClazz(t, *constructor))),
|
||||||
jconstructorSlot(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) {
|
if (args) {
|
||||||
t->m->processor->invokeArray(t, method, instance, *args);
|
t->m->processor->invokeArray(t, method, instance, *args);
|
||||||
} else {
|
} else {
|
||||||
@ -4686,9 +4816,27 @@ extern "C" JNIEXPORT jfloat JNICALL
|
|||||||
EXPORT(JVM_ConstantPoolGetFloatAt)(Thread*, jobject, jobject, jint)
|
EXPORT(JVM_ConstantPoolGetFloatAt)(Thread*, jobject, jobject, jint)
|
||||||
{ abort(); }
|
{ 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
|
extern "C" JNIEXPORT jdouble JNICALL
|
||||||
EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread*, jobject, jobject, jint)
|
EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread* t, jobject, jobject pool,
|
||||||
{ abort(); }
|
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
|
extern "C" JNIEXPORT jstring JNICALL
|
||||||
EXPORT(JVM_ConstantPoolGetStringAt)(Thread*, jobject, jobject, jint)
|
EXPORT(JVM_ConstantPoolGetStringAt)(Thread*, jobject, jobject, jint)
|
||||||
|
30
src/common.h
30
src/common.h
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#include "float.h"
|
||||||
|
|
||||||
// don't complain about using 'this' in member initializers:
|
// don't complain about using 'this' in member initializers:
|
||||||
# pragma warning(disable:4355)
|
# pragma warning(disable:4355)
|
||||||
|
|
||||||
@ -37,6 +39,34 @@ typedef unsigned int uint32_t;
|
|||||||
typedef __int64 int64_t;
|
typedef __int64 int64_t;
|
||||||
typedef unsigned __int64 uint64_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 not !
|
||||||
# define or ||
|
# define or ||
|
||||||
# define and &&
|
# define and &&
|
||||||
|
@ -75,7 +75,12 @@ LOCAL(vmInvoke_argumentTest):
|
|||||||
mov r8, r0
|
mov r8, r0
|
||||||
|
|
||||||
// load and call function address
|
// load and call function address
|
||||||
|
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||||
|
mov lr, pc
|
||||||
|
bx r1
|
||||||
|
#else
|
||||||
blx r1
|
blx r1
|
||||||
|
#endif
|
||||||
|
|
||||||
.globl GLOBAL(vmInvoke_returnAddress)
|
.globl GLOBAL(vmInvoke_returnAddress)
|
||||||
.align 2
|
.align 2
|
||||||
@ -123,11 +128,18 @@ LOCAL(vmInvoke_continuationTest):
|
|||||||
ble LOCAL(vmInvoke_continuationLoop)
|
ble LOCAL(vmInvoke_continuationLoop)
|
||||||
|
|
||||||
ldr r7,[r5,#CONTINUATION_RETURN_ADDRESS_OFFSET]
|
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 r10,LOCAL(vmInvoke_returnAddress_word)
|
||||||
ldr r11,LOCAL(vmInvoke_getAddress_word)
|
ldr r11,LOCAL(vmInvoke_getAddress_word)
|
||||||
LOCAL(vmInvoke_getAddress):
|
LOCAL(vmInvoke_getAddress):
|
||||||
add r11,pc,r11
|
add r11,pc,r11
|
||||||
ldr r11,[r11,r10]
|
ldr r11,[r11,r10]
|
||||||
|
#endif // not __APPLE__
|
||||||
str r11,[sp,r7]
|
str r11,[sp,r7]
|
||||||
|
|
||||||
ldr r7,[r5,#CONTINUATION_NEXT]
|
ldr r7,[r5,#CONTINUATION_NEXT]
|
||||||
@ -210,23 +222,34 @@ LOCAL(vmJumpAndInvoke_argumentTest):
|
|||||||
mov sp,r2
|
mov sp,r2
|
||||||
|
|
||||||
// set return address to vmInvoke_returnAddress
|
// 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 r10,LOCAL(vmInvoke_returnAddress_word)
|
||||||
ldr r11,LOCAL(vmJumpAndInvoke_getAddress_word)
|
ldr r11,LOCAL(vmJumpAndInvoke_getAddress_word)
|
||||||
LOCAL(vmJumpAndInvoke_getAddress):
|
LOCAL(vmJumpAndInvoke_getAddress):
|
||||||
add r11,pc,r11
|
add r11,pc,r11
|
||||||
|
#endif // not __APPLE__
|
||||||
ldr lr,[r11,r10]
|
ldr lr,[r11,r10]
|
||||||
|
|
||||||
bx r1
|
bx r1
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
LOCAL(vmInvoke_returnAddress_word):
|
LOCAL(vmInvoke_returnAddress_word):
|
||||||
.word GLOBAL(vmInvoke_returnAddress)(GOT)
|
.word GLOBAL(vmInvoke_returnAddress)(GOT)
|
||||||
LOCAL(vmInvoke_getAddress_word):
|
LOCAL(vmInvoke_getAddress_word):
|
||||||
.word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmInvoke_getAddress)+8)
|
.word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmInvoke_getAddress)+8)
|
||||||
LOCAL(vmJumpAndInvoke_getAddress_word):
|
LOCAL(vmJumpAndInvoke_getAddress_word):
|
||||||
.word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmJumpAndInvoke_getAddress)+8)
|
.word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmJumpAndInvoke_getAddress)+8)
|
||||||
|
#endif // not __APPLE__
|
||||||
|
|
||||||
#else // not AVIAN_CONTINUATIONS
|
#else // not AVIAN_CONTINUATIONS
|
||||||
// vmJumpAndInvoke should only be called when continuations are
|
// vmJumpAndInvoke should only be called when continuations are
|
||||||
// enabled
|
// enabled, so we force a crash if we reach here:
|
||||||
bkpt
|
mov r1,#0
|
||||||
|
ldr r1,[r1]
|
||||||
#endif // not AVIAN_CONTINUATIONS
|
#endif // not AVIAN_CONTINUATIONS
|
||||||
|
460
src/compile.cpp
460
src/compile.cpp
@ -202,6 +202,17 @@ class MyThread: public Thread {
|
|||||||
bool methodIsMostRecent;
|
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,
|
static void doTransition(MyThread* t, void* ip, void* stack,
|
||||||
object continuation, MyThread::CallTrace* trace)
|
object continuation, MyThread::CallTrace* trace)
|
||||||
{
|
{
|
||||||
@ -255,6 +266,7 @@ class MyThread: public Thread {
|
|||||||
transition(0),
|
transition(0),
|
||||||
traceContext(0),
|
traceContext(0),
|
||||||
stackLimit(0),
|
stackLimit(0),
|
||||||
|
referenceFrame(0),
|
||||||
methodLockIsClean(true)
|
methodLockIsClean(true)
|
||||||
{
|
{
|
||||||
arch->acquire();
|
arch->acquire();
|
||||||
@ -280,6 +292,7 @@ class MyThread: public Thread {
|
|||||||
Context* transition;
|
Context* transition;
|
||||||
TraceContext* traceContext;
|
TraceContext* traceContext;
|
||||||
uintptr_t stackLimit;
|
uintptr_t stackLimit;
|
||||||
|
ReferenceFrame* referenceFrame;
|
||||||
bool methodLockIsClean;
|
bool methodLockIsClean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1375,6 +1388,10 @@ class Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
~Frame() {
|
~Frame() {
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
if (level > 1) {
|
if (level > 1) {
|
||||||
context->eventLog.append(PopContextEvent);
|
context->eventLog.append(PopContextEvent);
|
||||||
}
|
}
|
||||||
@ -2574,13 +2591,25 @@ doubleToFloat(int64_t a)
|
|||||||
int64_t
|
int64_t
|
||||||
doubleToInt(int64_t a)
|
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
|
int64_t
|
||||||
doubleToLong(int64_t a)
|
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
|
uint64_t
|
||||||
@ -2722,13 +2751,24 @@ floatToDouble(int32_t a)
|
|||||||
int64_t
|
int64_t
|
||||||
floatToInt(int32_t a)
|
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
|
int64_t
|
||||||
floatToLong(int32_t a)
|
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
|
uint64_t
|
||||||
@ -3708,21 +3748,10 @@ isReferenceTailCall(MyThread* t, object code, unsigned ip, object caller,
|
|||||||
(t, code, ip, caller, methodReferenceReturnCode(t, calleeReference));
|
(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
|
bool
|
||||||
integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
|
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)) {
|
if (ip + 3 > codeLength(t, code)) {
|
||||||
return false;
|
return false;
|
||||||
@ -3766,14 +3795,14 @@ integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveStateAndCompile(t, frame, newIp);
|
*newIpp = newIp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
|
floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
|
||||||
unsigned size, bool lessIfUnordered, Compiler::Operand* a,
|
unsigned size, bool lessIfUnordered, Compiler::Operand* a,
|
||||||
Compiler::Operand* b)
|
Compiler::Operand* b, unsigned* newIpp)
|
||||||
{
|
{
|
||||||
if (ip + 3 > codeLength(t, code)) {
|
if (ip + 3 > codeLength(t, code)) {
|
||||||
return false;
|
return false;
|
||||||
@ -3833,7 +3862,7 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveStateAndCompile(t, frame, newIp);
|
*newIpp = newIp;
|
||||||
return true;
|
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
|
void
|
||||||
compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
compile(MyThread* t, Frame* initialFrame, unsigned initialIp,
|
||||||
int exceptionHandlerStart)
|
int exceptionHandlerStart = -1)
|
||||||
{
|
{
|
||||||
THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap,
|
enum {
|
||||||
codeMaxStack(t, methodCode(t, initialFrame->context->method)));
|
Return,
|
||||||
Frame myFrame(initialFrame, RUNTIME_ARRAY_BODY(stackMap));
|
Unbranch,
|
||||||
Frame* frame = &myFrame;
|
Unsubroutine,
|
||||||
|
Untable0,
|
||||||
|
Untable1,
|
||||||
|
Unswitch
|
||||||
|
};
|
||||||
|
|
||||||
|
Frame* frame = initialFrame;
|
||||||
Compiler* c = frame->c;
|
Compiler* c = frame->c;
|
||||||
Context* context = frame->context;
|
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);
|
object code = methodCode(t, context->method);
|
||||||
PROTECT(t, code);
|
PROTECT(t, code);
|
||||||
|
|
||||||
@ -4025,7 +4163,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
if (context->visitTable[ip] ++) {
|
if (context->visitTable[ip] ++) {
|
||||||
// we've already visited this part of the code
|
// we've already visited this part of the code
|
||||||
frame->visitLogicalIp(ip);
|
frame->visitLogicalIp(ip);
|
||||||
return;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->startLogicalIp(ip);
|
frame->startLogicalIp(ip);
|
||||||
@ -4282,7 +4420,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
case areturn: {
|
case areturn: {
|
||||||
handleExit(t, frame);
|
handleExit(t, frame);
|
||||||
c->return_(TargetBytesPerWord, frame->popObject());
|
c->return_(TargetBytesPerWord, frame->popObject());
|
||||||
} return;
|
} goto next;
|
||||||
|
|
||||||
case arraylength: {
|
case arraylength: {
|
||||||
frame->pushInt
|
frame->pushInt
|
||||||
@ -4327,7 +4465,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
if (ip == codeLength(t, code)) {
|
if (ip == codeLength(t, code)) {
|
||||||
c->trap();
|
c->trap();
|
||||||
}
|
}
|
||||||
} return;
|
} goto next;
|
||||||
|
|
||||||
case bipush:
|
case bipush:
|
||||||
frame->pushInt
|
frame->pushInt
|
||||||
@ -4391,7 +4529,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
Compiler::Operand* a = frame->popLong();
|
Compiler::Operand* a = frame->popLong();
|
||||||
Compiler::Operand* b = 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
|
frame->pushInt
|
||||||
(c->call
|
(c->call
|
||||||
(c->constant
|
(c->constant
|
||||||
@ -4406,7 +4546,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
Compiler::Operand* a = frame->popLong();
|
Compiler::Operand* a = frame->popLong();
|
||||||
Compiler::Operand* b = 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
|
frame->pushInt
|
||||||
(c->call
|
(c->call
|
||||||
(c->constant
|
(c->constant
|
||||||
@ -4504,7 +4646,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
Compiler::Operand* a = frame->popInt();
|
Compiler::Operand* a = frame->popInt();
|
||||||
Compiler::Operand* b = 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
|
frame->pushInt
|
||||||
(c->call
|
(c->call
|
||||||
(c->constant
|
(c->constant
|
||||||
@ -4517,7 +4661,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
Compiler::Operand* a = frame->popInt();
|
Compiler::Operand* a = frame->popInt();
|
||||||
Compiler::Operand* b = 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
|
frame->pushInt
|
||||||
(c->call
|
(c->call
|
||||||
(c->constant
|
(c->constant
|
||||||
@ -4851,7 +4997,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
case if_acmpeq:
|
case if_acmpeq:
|
||||||
case if_acmpne: {
|
case if_acmpne: {
|
||||||
uint32_t offset = codeReadInt16(t, code, ip);
|
uint32_t offset = codeReadInt16(t, code, ip);
|
||||||
uint32_t newIp = (ip - 3) + offset;
|
newIp = (ip - 3) + offset;
|
||||||
assert(t, newIp < codeLength(t, code));
|
assert(t, newIp < codeLength(t, code));
|
||||||
|
|
||||||
Compiler::Operand* a = frame->popObject();
|
Compiler::Operand* a = frame->popObject();
|
||||||
@ -4863,9 +5009,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
} else {
|
} else {
|
||||||
c->jumpIfNotEqual(TargetBytesPerWord, a, b, target);
|
c->jumpIfNotEqual(TargetBytesPerWord, a, b, target);
|
||||||
}
|
}
|
||||||
|
} goto branch;
|
||||||
saveStateAndCompile(t, frame, newIp);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case if_icmpeq:
|
case if_icmpeq:
|
||||||
case if_icmpne:
|
case if_icmpne:
|
||||||
@ -4874,7 +5018,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
case if_icmplt:
|
case if_icmplt:
|
||||||
case if_icmple: {
|
case if_icmple: {
|
||||||
uint32_t offset = codeReadInt16(t, code, ip);
|
uint32_t offset = codeReadInt16(t, code, ip);
|
||||||
uint32_t newIp = (ip - 3) + offset;
|
newIp = (ip - 3) + offset;
|
||||||
assert(t, newIp < codeLength(t, code));
|
assert(t, newIp < codeLength(t, code));
|
||||||
|
|
||||||
Compiler::Operand* a = frame->popInt();
|
Compiler::Operand* a = frame->popInt();
|
||||||
@ -4903,9 +5047,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
default:
|
default:
|
||||||
abort(t);
|
abort(t);
|
||||||
}
|
}
|
||||||
|
} goto branch;
|
||||||
saveStateAndCompile(t, frame, newIp);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ifeq:
|
case ifeq:
|
||||||
case ifne:
|
case ifne:
|
||||||
@ -4914,7 +5056,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
case iflt:
|
case iflt:
|
||||||
case ifle: {
|
case ifle: {
|
||||||
uint32_t offset = codeReadInt16(t, code, ip);
|
uint32_t offset = codeReadInt16(t, code, ip);
|
||||||
uint32_t newIp = (ip - 3) + offset;
|
newIp = (ip - 3) + offset;
|
||||||
assert(t, newIp < codeLength(t, code));
|
assert(t, newIp < codeLength(t, code));
|
||||||
|
|
||||||
Compiler::Operand* target = frame->machineIp(newIp);
|
Compiler::Operand* target = frame->machineIp(newIp);
|
||||||
@ -4944,14 +5086,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
default:
|
default:
|
||||||
abort(t);
|
abort(t);
|
||||||
}
|
}
|
||||||
|
} goto branch;
|
||||||
saveStateAndCompile(t, frame, newIp);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ifnull:
|
case ifnull:
|
||||||
case ifnonnull: {
|
case ifnonnull: {
|
||||||
uint32_t offset = codeReadInt16(t, code, ip);
|
uint32_t offset = codeReadInt16(t, code, ip);
|
||||||
uint32_t newIp = (ip - 3) + offset;
|
newIp = (ip - 3) + offset;
|
||||||
assert(t, newIp < codeLength(t, code));
|
assert(t, newIp < codeLength(t, code));
|
||||||
|
|
||||||
Compiler::Operand* a = c->constant(0, Compiler::ObjectType);
|
Compiler::Operand* a = c->constant(0, Compiler::ObjectType);
|
||||||
@ -4963,9 +5103,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
} else {
|
} else {
|
||||||
c->jumpIfNotEqual(TargetBytesPerWord, a, b, target);
|
c->jumpIfNotEqual(TargetBytesPerWord, a, b, target);
|
||||||
}
|
}
|
||||||
|
} goto branch;
|
||||||
saveStateAndCompile(t, frame, newIp);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case iinc: {
|
case iinc: {
|
||||||
uint8_t index = codeBody(t, code, ip++);
|
uint8_t index = codeBody(t, code, ip++);
|
||||||
@ -5028,21 +5166,18 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
|
|
||||||
object argument;
|
object argument;
|
||||||
Thunk thunk;
|
Thunk thunk;
|
||||||
TraceElement* trace;
|
|
||||||
if (LIKELY(class_)) {
|
if (LIKELY(class_)) {
|
||||||
argument = class_;
|
argument = class_;
|
||||||
thunk = instanceOf64Thunk;
|
thunk = instanceOf64Thunk;
|
||||||
trace = 0;
|
|
||||||
} else {
|
} else {
|
||||||
argument = makePair(t, context->method, reference);
|
argument = makePair(t, context->method, reference);
|
||||||
thunk = instanceOfFromReferenceThunk;
|
thunk = instanceOfFromReferenceThunk;
|
||||||
trace = frame->trace(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->pushInt
|
frame->pushInt
|
||||||
(c->call
|
(c->call
|
||||||
(c->constant(getThunk(t, thunk), Compiler::AddressType),
|
(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),
|
3, c->register_(t->arch->thread()), frame->append(argument),
|
||||||
instance));
|
instance));
|
||||||
} break;
|
} break;
|
||||||
@ -5265,7 +5400,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
case freturn: {
|
case freturn: {
|
||||||
handleExit(t, frame);
|
handleExit(t, frame);
|
||||||
c->return_(4, frame->popInt());
|
c->return_(4, frame->popInt());
|
||||||
} return;
|
} goto next;
|
||||||
|
|
||||||
case ishl: {
|
case ishl: {
|
||||||
Compiler::Operand* a = frame->popInt();
|
Compiler::Operand* a = frame->popInt();
|
||||||
@ -5325,7 +5460,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
case jsr:
|
case jsr:
|
||||||
case jsr_w: {
|
case jsr_w: {
|
||||||
uint32_t thisIp;
|
uint32_t thisIp;
|
||||||
uint32_t newIp;
|
|
||||||
|
|
||||||
if (instruction == jsr) {
|
if (instruction == jsr) {
|
||||||
uint32_t offset = codeReadInt16(t, code, ip);
|
uint32_t offset = codeReadInt16(t, code, ip);
|
||||||
@ -5343,10 +5477,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
|
|
||||||
c->jmp(frame->machineIp(newIp));
|
c->jmp(frame->machineIp(newIp));
|
||||||
|
|
||||||
saveStateAndCompile(t, frame, newIp);
|
stack.pushValue(start);
|
||||||
|
stack.pushValue(ip);
|
||||||
frame->endSubroutine(start);
|
stack.pushValue(Unsubroutine);
|
||||||
} break;
|
ip = newIp;
|
||||||
|
} goto start;
|
||||||
|
|
||||||
case l2d: {
|
case l2d: {
|
||||||
frame->pushLong(c->i2f(8, 8, frame->popLong()));
|
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* a = frame->popLong();
|
||||||
Compiler::Operand* b = 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
|
frame->pushInt
|
||||||
(c->call
|
(c->call
|
||||||
(c->constant
|
(c->constant
|
||||||
@ -5534,14 +5671,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
(frame->addressPromise(c->machineIp(defaultIp)));
|
(frame->addressPromise(c->machineIp(defaultIp)));
|
||||||
|
|
||||||
Promise* start = 0;
|
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) {
|
for (int32_t i = 0; i < pairCount; ++i) {
|
||||||
unsigned index = ip + (i * 8);
|
unsigned index = ip + (i * 8);
|
||||||
int32_t key = codeReadInt32(t, code, index);
|
int32_t key = codeReadInt32(t, code, index);
|
||||||
uint32_t newIp = base + codeReadInt32(t, code, index);
|
uint32_t newIp = base + codeReadInt32(t, code, index);
|
||||||
assert(t, newIp < codeLength(t, code));
|
assert(t, newIp < codeLength(t, code));
|
||||||
|
|
||||||
RUNTIME_ARRAY_BODY(ipTable)[i] = newIp;
|
ipTable[i] = newIp;
|
||||||
|
|
||||||
Promise* p = c->poolAppend(key);
|
Promise* p = c->poolAppend(key);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
@ -5565,19 +5703,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
TARGET_THREAD_CODEIMAGE), address)
|
TARGET_THREAD_CODEIMAGE), address)
|
||||||
: 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) {
|
goto switchloop;
|
||||||
compile(t, frame, RUNTIME_ARRAY_BODY(ipTable)[i]);
|
|
||||||
|
|
||||||
c->restoreState(state);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// a switch statement with no cases, apparently
|
// a switch statement with no cases, apparently
|
||||||
c->jmp(frame->machineIp(defaultIp));
|
c->jmp(frame->machineIp(defaultIp));
|
||||||
}
|
|
||||||
|
|
||||||
ip = defaultIp;
|
ip = defaultIp;
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case lor: {
|
case lor: {
|
||||||
@ -5602,7 +5736,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
case dreturn: {
|
case dreturn: {
|
||||||
handleExit(t, frame);
|
handleExit(t, frame);
|
||||||
c->return_(8, frame->popLong());
|
c->return_(8, frame->popLong());
|
||||||
} return;
|
} goto next;
|
||||||
|
|
||||||
case lshl: {
|
case lshl: {
|
||||||
Compiler::Operand* a = frame->popInt();
|
Compiler::Operand* a = frame->popInt();
|
||||||
@ -6029,7 +6163,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
case ret: {
|
case ret: {
|
||||||
unsigned index = codeBody(t, code, ip);
|
unsigned index = codeBody(t, code, ip);
|
||||||
frame->returnFromSubroutine(index);
|
frame->returnFromSubroutine(index);
|
||||||
} return;
|
} goto next;
|
||||||
|
|
||||||
case return_:
|
case return_:
|
||||||
if (needsReturnBarrier(t, context->method)) {
|
if (needsReturnBarrier(t, context->method)) {
|
||||||
@ -6038,7 +6172,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
|
|
||||||
handleExit(t, frame);
|
handleExit(t, frame);
|
||||||
c->return_(0, 0);
|
c->return_(0, 0);
|
||||||
return;
|
goto next;
|
||||||
|
|
||||||
case sipush:
|
case sipush:
|
||||||
frame->pushInt
|
frame->pushInt
|
||||||
@ -6063,13 +6197,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
int32_t top = codeReadInt32(t, code, ip);
|
int32_t top = codeReadInt32(t, code, ip);
|
||||||
|
|
||||||
Promise* start = 0;
|
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) {
|
for (int32_t i = 0; i < top - bottom + 1; ++i) {
|
||||||
unsigned index = ip + (i * 4);
|
unsigned index = ip + (i * 4);
|
||||||
uint32_t newIp = base + codeReadInt32(t, code, index);
|
uint32_t newIp = base + codeReadInt32(t, code, index);
|
||||||
assert(t, newIp < codeLength(t, code));
|
assert(t, newIp < codeLength(t, code));
|
||||||
|
|
||||||
RUNTIME_ARRAY_BODY(ipTable)[i] = newIp;
|
ipTable[i] = newIp;
|
||||||
|
|
||||||
Promise* p = c->poolAppendPromise
|
Promise* p = c->poolAppendPromise
|
||||||
(frame->addressPromise(c->machineIp(newIp)));
|
(frame->addressPromise(c->machineIp(newIp)));
|
||||||
@ -6086,43 +6222,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
|
|
||||||
c->save(1, key);
|
c->save(1, key);
|
||||||
|
|
||||||
saveStateAndCompile(t, frame, defaultIp);
|
new (stack.push(sizeof(SwitchState))) SwitchState
|
||||||
|
(c->saveState(), count, defaultIp, key, start, bottom, top);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
stack.pushValue(Untable0);
|
||||||
ip = defaultIp;
|
ip = defaultIp;
|
||||||
} break;
|
} goto start;
|
||||||
|
|
||||||
case wide: {
|
case wide: {
|
||||||
switch (codeBody(t, code, ip++)) {
|
switch (codeBody(t, code, ip++)) {
|
||||||
@ -6166,7 +6271,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
unsigned index = codeReadInt16(t, code, ip);
|
unsigned index = codeReadInt16(t, code, ip);
|
||||||
c->jmp(loadLocal(context, 1, index));
|
c->jmp(loadLocal(context, 1, index));
|
||||||
frame->returnFromSubroutine(index);
|
frame->returnFromSubroutine(index);
|
||||||
} return;
|
} goto next;
|
||||||
|
|
||||||
default: abort(t);
|
default: abort(t);
|
||||||
}
|
}
|
||||||
@ -6175,6 +6280,113 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
default: abort(t);
|
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;
|
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
|
virtual object
|
||||||
invokeArray(Thread* t, object method, object this_, object arguments)
|
invokeArray(Thread* t, object method, object this_, object arguments)
|
||||||
{
|
{
|
||||||
|
@ -11,18 +11,18 @@
|
|||||||
#ifndef AVIAN_ENVIRONMENT_H
|
#ifndef AVIAN_ENVIRONMENT_H
|
||||||
#define AVIAN_ENVIRONMENT_H
|
#define AVIAN_ENVIRONMENT_H
|
||||||
|
|
||||||
#ifndef AVIAN_TARGET_PLATFORM
|
#ifndef AVIAN_TARGET_FORMAT
|
||||||
#error build system should have defined AVIAN_TARGET_PLATFORM
|
#error build system should have defined AVIAN_TARGET_FORMAT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef AVIAN_TARGET_ARCH
|
#ifndef AVIAN_TARGET_ARCH
|
||||||
#error build system should have defined AVIAN_TARGET_ARCH
|
#error build system should have defined AVIAN_TARGET_ARCH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define AVIAN_PLATFORM_UNKNOWN 0
|
#define AVIAN_FORMAT_UNKNOWN 0
|
||||||
#define AVIAN_PLATFORM_LINUX 1
|
#define AVIAN_FORMAT_ELF 1
|
||||||
#define AVIAN_PLATFORM_WINDOWS 2
|
#define AVIAN_FORMAT_PE 2
|
||||||
#define AVIAN_PLATFORM_DARWIN 3
|
#define AVIAN_FORMAT_MACHO 3
|
||||||
|
|
||||||
#define AVIAN_ARCH_UNKNOWN 0
|
#define AVIAN_ARCH_UNKNOWN 0
|
||||||
#define AVIAN_ARCH_X86 (1 << 8)
|
#define AVIAN_ARCH_X86 (1 << 8)
|
||||||
@ -31,3 +31,4 @@
|
|||||||
#define AVIAN_ARCH_POWERPC (4 << 8)
|
#define AVIAN_ARCH_POWERPC (4 << 8)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -602,7 +602,7 @@ class BuiltinElement: public JarElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual const char* urlPrefix() {
|
virtual const char* urlPrefix() {
|
||||||
return "resource:";
|
return "avianvmresource:";
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const char* sourceUrl() {
|
virtual const char* sourceUrl() {
|
||||||
|
127
src/heap.cpp
127
src/heap.cpp
@ -463,12 +463,15 @@ class Segment {
|
|||||||
|
|
||||||
class Fixie {
|
class Fixie {
|
||||||
public:
|
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,
|
Fixie(Context* c, unsigned size, bool hasMask, Fixie** handle,
|
||||||
bool immortal):
|
bool immortal):
|
||||||
age(immortal ? FixieTenureThreshold + 1 : 0),
|
age(immortal ? FixieTenureThreshold + 1 : 0),
|
||||||
hasMask(hasMask),
|
flags(hasMask ? HasMask : 0),
|
||||||
marked(false),
|
|
||||||
dirty(false),
|
|
||||||
size(size),
|
size(size),
|
||||||
next(0),
|
next(0),
|
||||||
handle(0)
|
handle(0)
|
||||||
@ -536,16 +539,54 @@ class Fixie {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned totalSize() {
|
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
|
// be sure to update e.g. TargetFixieSizeInBytes in bootimage.cpp if
|
||||||
// you add/remove/change fields in this class:
|
// you add/remove/change fields in this class:
|
||||||
|
|
||||||
uint8_t age;
|
uint16_t age;
|
||||||
uint8_t hasMask;
|
uint16_t flags;
|
||||||
uint8_t marked;
|
|
||||||
uint8_t dirty;
|
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
Fixie* next;
|
Fixie* next;
|
||||||
Fixie** handle;
|
Fixie** handle;
|
||||||
@ -850,11 +891,11 @@ free(Context* c, Fixie** fixies, bool resetImmortal)
|
|||||||
fprintf(stderr, "reset immortal fixie %p\n", f);
|
fprintf(stderr, "reset immortal fixie %p\n", f);
|
||||||
}
|
}
|
||||||
*p = f->next;
|
*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->next = 0;
|
||||||
f->handle = 0;
|
f->handle = 0;
|
||||||
f->marked = false;
|
f->marked(false);
|
||||||
f->dirty = false;
|
f->dirty(false);
|
||||||
} else {
|
} else {
|
||||||
p = &(f->next);
|
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
|
void
|
||||||
sweepFixies(Context* c)
|
sweepFixies(Context* c)
|
||||||
{
|
{
|
||||||
@ -898,14 +961,14 @@ sweepFixies(Context* c)
|
|||||||
|
|
||||||
if (f->age >= FixieTenureThreshold) {
|
if (f->age >= FixieTenureThreshold) {
|
||||||
if (DebugFixies) {
|
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()) {
|
if (not f->immortal()) {
|
||||||
c->tenuredFixieFootprint += f->totalSize();
|
c->tenuredFixieFootprint += f->totalSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->dirty) {
|
if (f->dirty()) {
|
||||||
f->add(c, &(c->dirtyTenuredFixies));
|
f->add(c, &(c->dirtyTenuredFixies));
|
||||||
} else {
|
} else {
|
||||||
f->add(c, &(c->tenuredFixies));
|
f->add(c, &(c->tenuredFixies));
|
||||||
@ -916,7 +979,7 @@ sweepFixies(Context* c)
|
|||||||
f->add(c, &(c->fixies));
|
f->add(c, &(c->fixies));
|
||||||
}
|
}
|
||||||
|
|
||||||
f->marked = false;
|
f->marked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
c->tenuredFixieCeiling = max
|
c->tenuredFixieCeiling = max
|
||||||
@ -1006,14 +1069,15 @@ update3(Context* c, void* o, bool* needsVisit)
|
|||||||
{
|
{
|
||||||
if (c->client->isFixed(o)) {
|
if (c->client->isFixed(o)) {
|
||||||
Fixie* f = fixie(o);
|
Fixie* f = fixie(o);
|
||||||
if ((not f->marked)
|
if ((not f->marked())
|
||||||
and (c->mode == Heap::MajorCollection
|
and (c->mode == Heap::MajorCollection
|
||||||
or f->age < FixieTenureThreshold))
|
or f->age < FixieTenureThreshold))
|
||||||
{
|
{
|
||||||
if (DebugFixies) {
|
if (DebugFixies) {
|
||||||
fprintf(stderr, "mark fixie %p\n", f);
|
fprintf(stderr, "mark fixie %p\n", f);
|
||||||
}
|
}
|
||||||
f->marked = true;
|
f->marked(true);
|
||||||
|
f->dead(false);
|
||||||
f->move(c, &(c->markedFixies));
|
f->move(c, &(c->markedFixies));
|
||||||
}
|
}
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
@ -1044,13 +1108,13 @@ update2(Context* c, void* o, bool* needsVisit)
|
|||||||
void
|
void
|
||||||
markDirty(Context* c, Fixie* f)
|
markDirty(Context* c, Fixie* f)
|
||||||
{
|
{
|
||||||
if (not f->dirty) {
|
if (not f->dirty()) {
|
||||||
#ifdef USE_ATOMIC_OPERATIONS
|
#ifdef USE_ATOMIC_OPERATIONS
|
||||||
ACQUIRE(c->lock);
|
ACQUIRE(c->lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (not f->dirty) {
|
if (not f->dirty()) {
|
||||||
f->dirty = true;
|
f->dirty(true);
|
||||||
f->move(c, &(c->dirtyTenuredFixies));
|
f->move(c, &(c->dirtyTenuredFixies));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1059,8 +1123,8 @@ markDirty(Context* c, Fixie* f)
|
|||||||
void
|
void
|
||||||
markClean(Context* c, Fixie* f)
|
markClean(Context* c, Fixie* f)
|
||||||
{
|
{
|
||||||
if (f->dirty) {
|
if (f->dirty()) {
|
||||||
f->dirty = false;
|
f->dirty(false);
|
||||||
if (f->immortal()) {
|
if (f->immortal()) {
|
||||||
f->remove(c);
|
f->remove(c);
|
||||||
} else {
|
} else {
|
||||||
@ -1090,7 +1154,7 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result)
|
|||||||
{
|
{
|
||||||
if (target and c->client->isFixed(target)) {
|
if (target and c->client->isFixed(target)) {
|
||||||
Fixie* f = fixie(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 (static_cast<unsigned>(f->age + 1) >= FixieTenureThreshold) {
|
||||||
if (DebugFixies) {
|
if (DebugFixies) {
|
||||||
@ -1098,7 +1162,7 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result)
|
|||||||
f, offset, f->body() + offset, result);
|
f, offset, f->body() + offset, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
f->dirty = true;
|
f->dirty(true);
|
||||||
markBit(f->mask(), offset);
|
markBit(f->mask(), offset);
|
||||||
}
|
}
|
||||||
} else if (seg->contains(p)) {
|
} else if (seg->contains(p)) {
|
||||||
@ -1804,6 +1868,10 @@ class MyHeap: public Heap {
|
|||||||
c.immortalHeapEnd = start + sizeInWords;
|
c.immortalHeapEnd = start + sizeInWords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual unsigned limit() {
|
||||||
|
return c.limit;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool limitExceeded() {
|
virtual bool limitExceeded() {
|
||||||
return c.count > c.limit;
|
return c.count > c.limit;
|
||||||
}
|
}
|
||||||
@ -1871,7 +1939,7 @@ class MyHeap: public Heap {
|
|||||||
|
|
||||||
if (c.client->isFixed(p)) {
|
if (c.client->isFixed(p)) {
|
||||||
Fixie* f = fixie(p);
|
Fixie* f = fixie(p);
|
||||||
assert(&c, offset == 0 or f->hasMask);
|
assert(&c, offset == 0 or f->hasMask());
|
||||||
|
|
||||||
bool dirty = false;
|
bool dirty = false;
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
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) {
|
virtual Status status(void* p) {
|
||||||
p = mask(p);
|
p = mask(p);
|
||||||
|
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
return Null;
|
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)) {
|
} else if (c.nextGen1.contains(p)) {
|
||||||
return Reachable;
|
return Reachable;
|
||||||
} else if (c.nextGen2.contains(p)
|
} else if (c.nextGen2.contains(p)
|
||||||
|
@ -59,6 +59,7 @@ class Heap: public Allocator {
|
|||||||
|
|
||||||
virtual void setClient(Client* client) = 0;
|
virtual void setClient(Client* client) = 0;
|
||||||
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0;
|
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0;
|
||||||
|
virtual unsigned limit() = 0;
|
||||||
virtual bool limitExceeded() = 0;
|
virtual bool limitExceeded() = 0;
|
||||||
virtual void collect(CollectionType type, unsigned footprint) = 0;
|
virtual void collect(CollectionType type, unsigned footprint) = 0;
|
||||||
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
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 mark(void* p, unsigned offset, unsigned count) = 0;
|
||||||
virtual void pad(void* p) = 0;
|
virtual void pad(void* p) = 0;
|
||||||
virtual void* follow(void* p) = 0;
|
virtual void* follow(void* p) = 0;
|
||||||
|
virtual void postVisit() = 0;
|
||||||
virtual Status status(void* p) = 0;
|
virtual Status status(void* p) = 0;
|
||||||
virtual CollectionType collectionType() = 0;
|
virtual CollectionType collectionType() = 0;
|
||||||
virtual void disposeFixies() = 0;
|
virtual void disposeFixies() = 0;
|
||||||
|
@ -28,18 +28,31 @@ const unsigned FrameFootprint = 4;
|
|||||||
|
|
||||||
class Thread: public vm::Thread {
|
class Thread: public vm::Thread {
|
||||||
public:
|
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):
|
Thread(Machine* m, object javaThread, vm::Thread* parent):
|
||||||
vm::Thread(m, javaThread, parent),
|
vm::Thread(m, javaThread, parent),
|
||||||
ip(0),
|
ip(0),
|
||||||
sp(0),
|
sp(0),
|
||||||
frame(-1),
|
frame(-1),
|
||||||
code(0)
|
code(0),
|
||||||
|
referenceFrame(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
unsigned ip;
|
unsigned ip;
|
||||||
unsigned sp;
|
unsigned sp;
|
||||||
int frame;
|
int frame;
|
||||||
object code;
|
object code;
|
||||||
|
ReferenceFrame* referenceFrame;
|
||||||
uintptr_t stack[0];
|
uintptr_t stack[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1065,11 +1078,27 @@ interpret3(Thread* t, const int base)
|
|||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case d2i: {
|
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;
|
} goto loop;
|
||||||
|
|
||||||
case d2l: {
|
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;
|
} goto loop;
|
||||||
|
|
||||||
case dadd: {
|
case dadd: {
|
||||||
@ -1265,11 +1294,24 @@ interpret3(Thread* t, const int base)
|
|||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case f2i: {
|
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;
|
} goto loop;
|
||||||
|
|
||||||
case f2l: {
|
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;
|
} goto loop;
|
||||||
|
|
||||||
case fadd: {
|
case fadd: {
|
||||||
@ -1888,14 +1930,14 @@ interpret3(Thread* t, const int base)
|
|||||||
int32_t b = popInt(t);
|
int32_t b = popInt(t);
|
||||||
int32_t a = popInt(t);
|
int32_t a = popInt(t);
|
||||||
|
|
||||||
pushInt(t, a << b);
|
pushInt(t, a << (b & 0x1F));
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case ishr: {
|
case ishr: {
|
||||||
int32_t b = popInt(t);
|
int32_t b = popInt(t);
|
||||||
int32_t a = popInt(t);
|
int32_t a = popInt(t);
|
||||||
|
|
||||||
pushInt(t, a >> b);
|
pushInt(t, a >> (b & 0x1F));
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case istore:
|
case istore:
|
||||||
@ -1934,7 +1976,7 @@ interpret3(Thread* t, const int base)
|
|||||||
int32_t b = popInt(t);
|
int32_t b = popInt(t);
|
||||||
uint32_t a = popInt(t);
|
uint32_t a = popInt(t);
|
||||||
|
|
||||||
pushInt(t, a >> b);
|
pushInt(t, a >> (b & 0x1F));
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case ixor: {
|
case ixor: {
|
||||||
@ -2196,14 +2238,14 @@ interpret3(Thread* t, const int base)
|
|||||||
int32_t b = popInt(t);
|
int32_t b = popInt(t);
|
||||||
int64_t a = popLong(t);
|
int64_t a = popLong(t);
|
||||||
|
|
||||||
pushLong(t, a << b);
|
pushLong(t, a << (b & 0x3F));
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case lshr: {
|
case lshr: {
|
||||||
int32_t b = popInt(t);
|
int32_t b = popInt(t);
|
||||||
int64_t a = popLong(t);
|
int64_t a = popLong(t);
|
||||||
|
|
||||||
pushLong(t, a >> b);
|
pushLong(t, a >> (b & 0x3F));
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case lstore:
|
case lstore:
|
||||||
@ -2242,7 +2284,7 @@ interpret3(Thread* t, const int base)
|
|||||||
int64_t b = popInt(t);
|
int64_t b = popInt(t);
|
||||||
uint64_t a = popLong(t);
|
uint64_t a = popLong(t);
|
||||||
|
|
||||||
pushLong(t, a >> b);
|
pushLong(t, a >> (b & 0x3F));
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case lxor: {
|
case lxor: {
|
||||||
@ -2781,7 +2823,7 @@ pushArguments(Thread* t, object this_, const char* spec,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'F': {
|
case 'F': {
|
||||||
pushFloat(t, arguments[index++].d);
|
pushFloat(t, arguments[index++].f);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
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
|
virtual object
|
||||||
invokeArray(vm::Thread* vmt, object method, object this_, object arguments)
|
invokeArray(vm::Thread* vmt, object method, object this_, object arguments)
|
||||||
{
|
{
|
||||||
@ -3166,7 +3236,7 @@ class MyProcessor: public Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose(vm::Thread* t) {
|
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() {
|
virtual void dispose() {
|
||||||
|
112
src/jnienv.cpp
112
src/jnienv.cpp
@ -45,8 +45,11 @@ DetachCurrentThread(Machine* m)
|
|||||||
{
|
{
|
||||||
Thread* t = static_cast<Thread*>(m->localThread->get());
|
Thread* t = static_cast<Thread*>(m->localThread->get());
|
||||||
if (t) {
|
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);
|
||||||
@ -58,6 +61,7 @@ DetachCurrentThread(Machine* m)
|
|||||||
enter(t, Thread::ZombieState);
|
enter(t, Thread::ZombieState);
|
||||||
|
|
||||||
t->state = Thread::JoinedState;
|
t->state = Thread::JoinedState;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@ -237,9 +241,8 @@ newString(Thread* t, uintptr_t* arguments)
|
|||||||
const jchar* chars = reinterpret_cast<const jchar*>(arguments[0]);
|
const jchar* chars = reinterpret_cast<const jchar*>(arguments[0]);
|
||||||
jsize size = arguments[1];
|
jsize size = arguments[1];
|
||||||
|
|
||||||
object a = 0;
|
object a = makeCharArray(t, size);
|
||||||
if (size) {
|
if (size) {
|
||||||
a = makeCharArray(t, size);
|
|
||||||
memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar));
|
memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,24 +410,6 @@ ExceptionCheck(Thread* t)
|
|||||||
return t->exception != 0;
|
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
|
uint64_t
|
||||||
getObjectClass(Thread* t, uintptr_t* arguments)
|
getObjectClass(Thread* t, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
@ -439,18 +424,20 @@ GetObjectClass(Thread* t, jobject o)
|
|||||||
{
|
{
|
||||||
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(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
|
uint64_t
|
||||||
getSuperclass(Thread* t, uintptr_t* arguments)
|
getSuperclass(Thread* t, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
object class_ = jclassVmClass(t, *reinterpret_cast<jclass>(arguments[0]));
|
||||||
|
if (classFlags(t, class_) & ACC_INTERFACE) {
|
||||||
object super = classSuper(t, jclassVmClass(t, *c));
|
return 0;
|
||||||
|
} else {
|
||||||
|
object super = classSuper(t, class_);
|
||||||
return super ? reinterpret_cast<uint64_t>
|
return super ? reinterpret_cast<uint64_t>
|
||||||
(makeLocalReference(t, getJClass(t, super))) : 0;
|
(makeLocalReference(t, getJClass(t, super))) : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass JNICALL
|
jclass JNICALL
|
||||||
@ -3154,6 +3141,8 @@ GetPrimitiveArrayCritical(Thread* t, jarray array, jboolean* isCopy)
|
|||||||
*isCopy = true;
|
*isCopy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expect(t, *array);
|
||||||
|
|
||||||
return reinterpret_cast<uintptr_t*>(*array) + 2;
|
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 {
|
struct JavaVMOption {
|
||||||
char* optionString;
|
char* optionString;
|
||||||
void* extraInfo;
|
void* extraInfo;
|
||||||
@ -3556,6 +3605,8 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
|
|||||||
envTable->MonitorExit = local::MonitorExit;
|
envTable->MonitorExit = local::MonitorExit;
|
||||||
envTable->GetJavaVM = local::GetJavaVM;
|
envTable->GetJavaVM = local::GetJavaVM;
|
||||||
envTable->IsSameObject = local::IsSameObject;
|
envTable->IsSameObject = local::IsSameObject;
|
||||||
|
envTable->PushLocalFrame = local::PushLocalFrame;
|
||||||
|
envTable->PopLocalFrame = local::PopLocalFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
@ -3576,6 +3627,13 @@ JNI_GetDefaultJavaVMInitArgs(void*)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
|
JNI_GetCreatedJavaVMs(Machine**, jsize, jsize*)
|
||||||
|
{
|
||||||
|
// todo
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
||||||
{
|
{
|
||||||
|
112
src/machine.cpp
112
src/machine.cpp
@ -273,6 +273,8 @@ killZombies(Thread* t, Thread* o)
|
|||||||
unsigned
|
unsigned
|
||||||
footprint(Thread* t)
|
footprint(Thread* t)
|
||||||
{
|
{
|
||||||
|
expect(t, t->criticalLevel == 0);
|
||||||
|
|
||||||
unsigned n = t->heapOffset + t->heapIndex + t->backupHeapIndex;
|
unsigned n = t->heapOffset + t->heapIndex + t->backupHeapIndex;
|
||||||
|
|
||||||
for (Thread* c = t->child; c; c = c->peer) {
|
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
|
void
|
||||||
postVisit(Thread* t, Heap::Visitor* v)
|
postVisit(Thread* t, Heap::Visitor* v)
|
||||||
{
|
{
|
||||||
@ -480,6 +501,30 @@ postVisit(Thread* t, Heap::Visitor* v)
|
|||||||
|
|
||||||
assert(t, m->finalizeQueue == 0);
|
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 firstNewTenuredFinalizer = 0;
|
||||||
object lastNewTenuredFinalizer = 0;
|
object lastNewTenuredFinalizer = 0;
|
||||||
|
|
||||||
@ -1128,7 +1173,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
|
|
||||||
unsigned count = s.read2();
|
unsigned count = s.read2();
|
||||||
if (count) {
|
if (count) {
|
||||||
unsigned staticOffset = BytesPerWord * 2;
|
unsigned staticOffset = BytesPerWord * 3;
|
||||||
unsigned staticCount = 0;
|
unsigned staticCount = 0;
|
||||||
|
|
||||||
object fieldTable = makeArray(t, count);
|
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*>
|
uint8_t* body = reinterpret_cast<uint8_t*>
|
||||||
(&singletonBody(t, staticTable, 0));
|
(&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]);
|
unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]);
|
||||||
while (offset % size) {
|
while (offset % size) {
|
||||||
++ offset;
|
++ 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) {
|
if (classFlags(t, newClass) & ACC_INTERFACE) {
|
||||||
object virtualTable = classVirtualTable(t, newClass);
|
object virtualTable = classVirtualTable(t, newClass);
|
||||||
if (virtualTable) {
|
if (virtualTable) {
|
||||||
@ -3667,7 +3720,6 @@ stringUTFChars(Thread* t, object string, unsigned start, unsigned length,
|
|||||||
assert(t, static_cast<unsigned>
|
assert(t, static_cast<unsigned>
|
||||||
(stringUTFLength(t, string, start, length)) == charsLength);
|
(stringUTFLength(t, string, start, length)) == charsLength);
|
||||||
|
|
||||||
if (length) {
|
|
||||||
object data = stringData(t, string);
|
object data = stringData(t, string);
|
||||||
if (objectClass(t, data) == type(t, Machine::ByteArrayType)) {
|
if (objectClass(t, data) == type(t, Machine::ByteArrayType)) {
|
||||||
memcpy(chars,
|
memcpy(chars,
|
||||||
@ -3694,7 +3746,6 @@ stringUTFChars(Thread* t, object string, unsigned start, unsigned length,
|
|||||||
}
|
}
|
||||||
chars[j] = 0;
|
chars[j] = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t
|
uint64_t
|
||||||
@ -3983,6 +4034,17 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size,
|
|||||||
return real;
|
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
|
object
|
||||||
resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
|
resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
|
||||||
Machine::Type throwType)
|
Machine::Type throwType)
|
||||||
@ -4028,9 +4090,24 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
|
|||||||
|
|
||||||
{ THREAD_RESOURCE(t, System::Region*, region, region->dispose());
|
{ 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
|
// parse class file
|
||||||
class_ = parseClass
|
class_ = reinterpret_cast<object>
|
||||||
(t, loader, region->start(), region->length(), throwType);
|
(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) {
|
if (Verbose) {
|
||||||
@ -4068,6 +4145,8 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
|
|||||||
|
|
||||||
if (class_) {
|
if (class_) {
|
||||||
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
|
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
|
||||||
|
|
||||||
|
t->m->classpath->updatePackageMap(t, class_);
|
||||||
} else if (throw_) {
|
} else if (throw_) {
|
||||||
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
|
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
|
||||||
}
|
}
|
||||||
@ -4808,15 +4887,27 @@ parseUtf8(Thread* t, const char* data, unsigned length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
getCaller(Thread* t, unsigned target)
|
getCaller(Thread* t, unsigned target, bool skipMethodInvoke)
|
||||||
{
|
{
|
||||||
class Visitor: public Processor::StackVisitor {
|
class Visitor: public Processor::StackVisitor {
|
||||||
public:
|
public:
|
||||||
Visitor(Thread* t, unsigned target):
|
Visitor(Thread* t, unsigned target, bool skipMethodInvoke):
|
||||||
t(t), method(0), count(0), target(target)
|
t(t), method(0), count(0), target(target),
|
||||||
|
skipMethodInvoke(skipMethodInvoke)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual bool visit(Processor::StackWalker* walker) {
|
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) {
|
if (count == target) {
|
||||||
method = walker->method();
|
method = walker->method();
|
||||||
return false;
|
return false;
|
||||||
@ -4830,7 +4921,8 @@ getCaller(Thread* t, unsigned target)
|
|||||||
object method;
|
object method;
|
||||||
unsigned count;
|
unsigned count;
|
||||||
unsigned target;
|
unsigned target;
|
||||||
} v(t, target);
|
bool skipMethodInvoke;
|
||||||
|
} v(t, target, skipMethodInvoke);
|
||||||
|
|
||||||
t->m->processor->walkStack(t, &v);
|
t->m->processor->walkStack(t, &v);
|
||||||
|
|
||||||
|
@ -1206,6 +1206,7 @@ class Machine {
|
|||||||
BootLoader,
|
BootLoader,
|
||||||
AppLoader,
|
AppLoader,
|
||||||
BootstrapClassMap,
|
BootstrapClassMap,
|
||||||
|
PackageMap,
|
||||||
FindLoadedClassMethod,
|
FindLoadedClassMethod,
|
||||||
LoadClassMethod,
|
LoadClassMethod,
|
||||||
MonitorMap,
|
MonitorMap,
|
||||||
@ -1550,6 +1551,9 @@ class Classpath {
|
|||||||
virtual const char*
|
virtual const char*
|
||||||
bootClasspath() = 0;
|
bootClasspath() = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
updatePackageMap(Thread* t, object class_) = 0;
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
dispose() = 0;
|
dispose() = 0;
|
||||||
};
|
};
|
||||||
@ -3801,7 +3805,7 @@ populateMultiArray(Thread* t, object array, int32_t* counts,
|
|||||||
unsigned index, unsigned dimensions);
|
unsigned index, unsigned dimensions);
|
||||||
|
|
||||||
object
|
object
|
||||||
getCaller(Thread* t, unsigned target);
|
getCaller(Thread* t, unsigned target, bool skipMethodInvoke = false);
|
||||||
|
|
||||||
object
|
object
|
||||||
defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length);
|
defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length);
|
||||||
|
@ -114,7 +114,7 @@ mainClass(const char* jar)
|
|||||||
unsigned length;
|
unsigned length;
|
||||||
while (readLine(region->start(), region->length(), &start, &length)) {
|
while (readLine(region->start(), region->length(), &start, &length)) {
|
||||||
const unsigned PrefixLength = 12;
|
const unsigned PrefixLength = 12;
|
||||||
if (strncmp("Main-Class: ", reinterpret_cast<const char*>
|
if (strncasecmp("Main-Class: ", reinterpret_cast<const char*>
|
||||||
(region->start() + start), PrefixLength) == 0)
|
(region->start() + start), PrefixLength) == 0)
|
||||||
{
|
{
|
||||||
result = static_cast<char*>(malloc(length + 1 - PrefixLength));
|
result = static_cast<char*>(malloc(length + 1 - PrefixLength));
|
||||||
@ -172,9 +172,11 @@ main(int ac, const char** av)
|
|||||||
if (strcmp(av[i], "-cp") == 0
|
if (strcmp(av[i], "-cp") == 0
|
||||||
or strcmp(av[i], "-classpath") == 0)
|
or strcmp(av[i], "-classpath") == 0)
|
||||||
{
|
{
|
||||||
|
if (i + 1 == ac) usageAndExit(av[0]);
|
||||||
classpath = av[++i];
|
classpath = av[++i];
|
||||||
} else if (strcmp(av[i], "-jar") == 0)
|
} else if (strcmp(av[i], "-jar") == 0)
|
||||||
{
|
{
|
||||||
|
if (i + 1 == ac) usageAndExit(av[0]);
|
||||||
jar = av[++i];
|
jar = av[++i];
|
||||||
} else if (strncmp(av[i], "-X", 2) == 0
|
} else if (strncmp(av[i], "-X", 2) == 0
|
||||||
or strncmp(av[i], "-D", 2) == 0)
|
or strncmp(av[i], "-D", 2) == 0)
|
||||||
|
@ -14,7 +14,13 @@
|
|||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
# include "CoreFoundation/CoreFoundation.h"
|
# include "CoreFoundation/CoreFoundation.h"
|
||||||
|
# include "sys/ucontext.h"
|
||||||
# undef assert
|
# undef assert
|
||||||
|
#else
|
||||||
|
# if defined __FreeBSD__
|
||||||
|
# include "limits.h"
|
||||||
|
# endif
|
||||||
|
# include "ucontext.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "sys/mman.h"
|
#include "sys/mman.h"
|
||||||
@ -28,7 +34,6 @@
|
|||||||
#include "unistd.h"
|
#include "unistd.h"
|
||||||
#include "pthread.h"
|
#include "pthread.h"
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "sys/ucontext.h"
|
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
#include "dirent.h"
|
#include "dirent.h"
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
@ -622,7 +627,7 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocateExecutable(unsigned sizeInBytes) {
|
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
|
// map to the lower 32 bits of memory when possible so as to avoid
|
||||||
// expensive relative jumps
|
// expensive relative jumps
|
||||||
const unsigned Extra = MAP_32BIT;
|
const unsigned Extra = MAP_32BIT;
|
||||||
@ -795,6 +800,13 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual FileType stat(const char* name, unsigned* length) {
|
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
|
// Ugly Hack Alert: It seems that the Apple iOS Simulator's stat
|
||||||
// implementation writes beyond the end of the struct stat we pass
|
// implementation writes beyond the end of the struct stat we pass
|
||||||
// it, which can clobber unrelated parts of the stack. Perhaps
|
// it, which can clobber unrelated parts of the stack. Perhaps
|
||||||
@ -804,6 +816,7 @@ class MySystem: public System {
|
|||||||
// made up and seems to work.
|
// made up and seems to work.
|
||||||
void* array[ceiling(sizeof(struct stat), sizeof(void*)) + 8];
|
void* array[ceiling(sizeof(struct stat), sizeof(void*)) + 8];
|
||||||
struct stat* s = reinterpret_cast<struct stat*>(array);
|
struct stat* s = reinterpret_cast<struct stat*>(array);
|
||||||
|
#endif
|
||||||
|
|
||||||
int r = ::stat(name, s);
|
int r = ::stat(name, s);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
|
@ -136,9 +136,18 @@ LOCAL(call):
|
|||||||
|
|
||||||
LOCAL(float):
|
LOCAL(float):
|
||||||
cmpwi r14,FLOAT_TYPE
|
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
|
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
|
cmpwi r14,INT64_TYPE
|
||||||
beq LOCAL(exit)
|
beq LOCAL(exit)
|
||||||
mr r4,r3
|
mr r4,r3
|
||||||
|
@ -672,6 +672,10 @@ write4(uint8_t* dst, uint32_t v)
|
|||||||
memcpy(dst, &v, 4);
|
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)
|
void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t)
|
||||||
{
|
{
|
||||||
if(size == 8) {
|
if(size == 8) {
|
||||||
@ -683,15 +687,23 @@ void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::
|
|||||||
emit(con, addi(tmp->high, a->low, -32));
|
emit(con, addi(tmp->high, a->low, -32));
|
||||||
emit(con, slw(tmp->low, b->low, tmp->high));
|
emit(con, slw(tmp->low, b->low, tmp->high));
|
||||||
emit(con, or_(t->high, t->high, tmp->low));
|
emit(con, or_(t->high, t->high, tmp->low));
|
||||||
freeTemp(con, tmp->high); freeTemp(con, tmp->low);
|
|
||||||
}
|
|
||||||
emit(con, slw(t->low, b->low, a->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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
void shiftLeftC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
|
||||||
{
|
{
|
||||||
int sh = getValue(a);
|
int sh = getValue(a);
|
||||||
if (size == 8) {
|
if (size == 8) {
|
||||||
|
sh &= 0x3F;
|
||||||
|
if (sh) {
|
||||||
if (sh < 32) {
|
if (sh < 32) {
|
||||||
emit(con, rlwinm(t->high,b->high,sh,0,31-sh));
|
emit(con, rlwinm(t->high,b->high,sh,0,31-sh));
|
||||||
emit(con, rlwimi(t->high,b->low,sh,32-sh,31));
|
emit(con, rlwimi(t->high,b->low,sh,32-sh,31));
|
||||||
@ -701,7 +713,10 @@ void shiftLeftC(Context* con, unsigned size, Assembler::Constant* a, Assembler::
|
|||||||
emit(con, li(t->low,0));
|
emit(con, li(t->low,0));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emit(con, slwi(t->low, b->low, sh));
|
moveRR(con, size, b, size, t);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emit(con, slwi(t->low, b->low, sh & 0x1F));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,6 +743,8 @@ void shiftRightC(Context* con, unsigned size, Assembler::Constant* a, Assembler:
|
|||||||
{
|
{
|
||||||
int sh = getValue(a);
|
int sh = getValue(a);
|
||||||
if(size == 8) {
|
if(size == 8) {
|
||||||
|
sh &= 0x3F;
|
||||||
|
if (sh) {
|
||||||
if (sh < 32) {
|
if (sh < 32) {
|
||||||
emit(con, rlwinm(t->low,b->low,32-sh,sh,31));
|
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, rlwimi(t->low,b->high,32-sh,0,sh-1));
|
||||||
@ -737,7 +754,10 @@ void shiftRightC(Context* con, unsigned size, Assembler::Constant* a, Assembler:
|
|||||||
emit(con, srawi(t->low,b->high,sh-32));
|
emit(con, srawi(t->low,b->high,sh-32));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emit(con, srawi(t->low, b->low, sh));
|
moveRR(con, size, b, size, t);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emit(con, srawi(t->low, b->low, sh & 0x1F));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,14 +777,11 @@ 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)
|
void unsignedShiftRightC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t)
|
||||||
{
|
{
|
||||||
int sh = getValue(a);
|
int sh = getValue(a);
|
||||||
if (size == 8) {
|
if (size == 8) {
|
||||||
|
if (sh & 0x3F) {
|
||||||
if (sh == 32) {
|
if (sh == 32) {
|
||||||
Assembler::Register high(b->high);
|
Assembler::Register high(b->high);
|
||||||
moveRR(con, 4, &high, 4, t);
|
moveRR(con, 4, &high, 4, t);
|
||||||
@ -778,7 +795,14 @@ void unsignedShiftRightC(Context* con, unsigned size, Assembler::Constant* a, As
|
|||||||
emit(con, li(t->high,0));
|
emit(con, li(t->high,0));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emit(con, srwi(t->low, b->low, sh));
|
moveRR(con, size, b, size, t);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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;
|
} break;
|
||||||
|
|
||||||
case DOUBLE_TYPE: {
|
case DOUBLE_TYPE: {
|
||||||
if (fprIndex + (8 / BytesPerWord) <= FprCount) {
|
if (fprIndex + 1 <= FprCount) {
|
||||||
memcpy(fprTable + fprIndex, arguments + ai, 8);
|
memcpy(fprTable + fprIndex, arguments + ai, 8);
|
||||||
++ fprIndex;
|
++ fprIndex;
|
||||||
SKIP(gprIndex, 8 / BytesPerWord);
|
SKIP(gprIndex, 8 / BytesPerWord);
|
||||||
|
@ -103,6 +103,12 @@ class Processor {
|
|||||||
virtual void
|
virtual void
|
||||||
disposeLocalReference(Thread* t, object* r) = 0;
|
disposeLocalReference(Thread* t, object* r) = 0;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
pushLocalFrame(Thread* t, unsigned capacity) = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
popLocalFrame(Thread* t) = 0;
|
||||||
|
|
||||||
virtual object
|
virtual object
|
||||||
invokeArray(Thread* t, object method, object this_, object arguments) = 0;
|
invokeArray(Thread* t, object method, object this_, object arguments) = 0;
|
||||||
|
|
||||||
|
@ -61,3 +61,4 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -32,13 +32,13 @@ class Tokenizer {
|
|||||||
{ }
|
{ }
|
||||||
|
|
||||||
bool hasMore() {
|
bool hasMore() {
|
||||||
while (*s == delimiter and s != limit) ++s;
|
while (s != limit and *s == delimiter) ++s;
|
||||||
return *s != 0 and s != limit;
|
return s != limit and *s != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token next() {
|
Token next() {
|
||||||
const char* p = s;
|
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);
|
return Token(p, s - p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,6 +871,13 @@ class MemberIterator {
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
while (types) {
|
while (types) {
|
||||||
|
if (member) {
|
||||||
|
assert(member->type == Object::Scalar);
|
||||||
|
offset_ = ((offset_ + size_) + (BytesPerWord - 1))
|
||||||
|
& ~(BytesPerWord - 1);
|
||||||
|
member = 0;
|
||||||
|
}
|
||||||
|
|
||||||
type = car(types);
|
type = car(types);
|
||||||
members = typeMembers(type);
|
members = typeMembers(type);
|
||||||
types = cdr(types);
|
types = cdr(types);
|
||||||
@ -2207,5 +2214,7 @@ main(int ac, char** av)
|
|||||||
local::writeMaps(&out, declarations);
|
local::writeMaps(&out, declarations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out.write("\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -876,7 +876,7 @@ class MySystem: public System {
|
|||||||
virtual void abort() {
|
virtual void abort() {
|
||||||
// trigger an EXCEPTION_ACCESS_VIOLATION, which we will catch and
|
// trigger an EXCEPTION_ACCESS_VIOLATION, which we will catch and
|
||||||
// generate a debug dump for
|
// generate a debug dump for
|
||||||
*static_cast<int*>(0) = 0;
|
*static_cast<volatile int*>(0) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
@ -929,7 +929,7 @@ dump(LPEXCEPTION_POINTERS e, const char* directory)
|
|||||||
char name[MAX_PATH];
|
char name[MAX_PATH];
|
||||||
_timeb tb;
|
_timeb tb;
|
||||||
FTIME(&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.time) * 1000)
|
||||||
+ static_cast<int64_t>(tb.millitm));
|
+ static_cast<int64_t>(tb.millitm));
|
||||||
|
|
||||||
|
@ -315,7 +315,7 @@ LOCAL(sse):
|
|||||||
movq 32(%rax),%xmm4
|
movq 32(%rax),%xmm4
|
||||||
movq 40(%rax),%xmm5
|
movq 40(%rax),%xmm5
|
||||||
movq 48(%rax),%xmm6
|
movq 48(%rax),%xmm6
|
||||||
movq 64(%rax),%xmm7
|
movq 56(%rax),%xmm7
|
||||||
|
|
||||||
LOCAL(call):
|
LOCAL(call):
|
||||||
call *-48(%rbp)
|
call *-48(%rbp)
|
||||||
|
68
src/x86.cpp
68
src/x86.cpp
@ -2164,7 +2164,9 @@ doShift(Context* c, UNUSED void (*shift)
|
|||||||
c->client->save(rcx);
|
c->client->save(rcx);
|
||||||
|
|
||||||
Assembler::Register cx(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);
|
shift(c, aSize, &cx, bSize, b);
|
||||||
} else {
|
} else {
|
||||||
maybeRex(c, bSize, b);
|
maybeRex(c, bSize, b);
|
||||||
@ -2183,9 +2185,16 @@ void
|
|||||||
shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||||
unsigned bSize, Assembler::Register* b)
|
unsigned bSize, Assembler::Register* b)
|
||||||
{
|
{
|
||||||
assert(c, a->low == rcx);
|
|
||||||
|
|
||||||
if (TargetBytesPerWord == 4 and bSize == 8) {
|
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
|
// shld
|
||||||
opcode(c, 0x0f, 0xa5);
|
opcode(c, 0x0f, 0xa5);
|
||||||
modrm(c, 0xc0, b->high, b->low);
|
modrm(c, 0xc0, b->high, b->low);
|
||||||
@ -2195,7 +2204,7 @@ shiftLeftRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
|||||||
|
|
||||||
ResolvedPromise promise(32);
|
ResolvedPromise promise(32);
|
||||||
Assembler::Constant constant(&promise);
|
Assembler::Constant constant(&promise);
|
||||||
compareCR(c, aSize, &constant, aSize, a);
|
compareCR(c, aSize, &constant, aSize, &cx);
|
||||||
|
|
||||||
opcode(c, 0x7c); //jl
|
opcode(c, 0x7c); //jl
|
||||||
c->code.append(2 + 2);
|
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
|
moveRR(c, 4, b, 4, &bh); // 2 bytes
|
||||||
xorRR(c, 4, b, 4, b); // 2 bytes
|
xorRR(c, 4, b, 4, b); // 2 bytes
|
||||||
} else {
|
} else {
|
||||||
|
assert(c, a->low == rcx);
|
||||||
|
|
||||||
maybeRex(c, bSize, a, b);
|
maybeRex(c, bSize, a, b);
|
||||||
opcode(c, 0xd3, 0xe0 + regCode(b));
|
opcode(c, 0xd3, 0xe0 + regCode(b));
|
||||||
}
|
}
|
||||||
@ -2220,8 +2231,16 @@ void
|
|||||||
shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||||
unsigned bSize, Assembler::Register* b)
|
unsigned bSize, Assembler::Register* b)
|
||||||
{
|
{
|
||||||
assert(c, a->low == rcx);
|
|
||||||
if (TargetBytesPerWord == 4 and bSize == 8) {
|
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
|
// shrd
|
||||||
opcode(c, 0x0f, 0xad);
|
opcode(c, 0x0f, 0xad);
|
||||||
modrm(c, 0xc0, b->low, b->high);
|
modrm(c, 0xc0, b->low, b->high);
|
||||||
@ -2231,7 +2250,7 @@ shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
|||||||
|
|
||||||
ResolvedPromise promise(32);
|
ResolvedPromise promise(32);
|
||||||
Assembler::Constant constant(&promise);
|
Assembler::Constant constant(&promise);
|
||||||
compareCR(c, aSize, &constant, aSize, a);
|
compareCR(c, aSize, &constant, aSize, &cx);
|
||||||
|
|
||||||
opcode(c, 0x7c); //jl
|
opcode(c, 0x7c); //jl
|
||||||
c->code.append(2 + 3);
|
c->code.append(2 + 3);
|
||||||
@ -2243,6 +2262,8 @@ shiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
|||||||
opcode(c, 0xc1, 0xf8 + b->high);
|
opcode(c, 0xc1, 0xf8 + b->high);
|
||||||
c->code.append(31);
|
c->code.append(31);
|
||||||
} else {
|
} else {
|
||||||
|
assert(c, a->low == rcx);
|
||||||
|
|
||||||
maybeRex(c, bSize, a, b);
|
maybeRex(c, bSize, a, b);
|
||||||
opcode(c, 0xd3, 0xf8 + regCode(b));
|
opcode(c, 0xd3, 0xf8 + regCode(b));
|
||||||
}
|
}
|
||||||
@ -2259,9 +2280,16 @@ void
|
|||||||
unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
||||||
unsigned bSize, Assembler::Register* b)
|
unsigned bSize, Assembler::Register* b)
|
||||||
{
|
{
|
||||||
assert(c, a->low == rcx);
|
|
||||||
|
|
||||||
if (TargetBytesPerWord == 4 and bSize == 8) {
|
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
|
// shrd
|
||||||
opcode(c, 0x0f, 0xad);
|
opcode(c, 0x0f, 0xad);
|
||||||
modrm(c, 0xc0, b->low, b->high);
|
modrm(c, 0xc0, b->low, b->high);
|
||||||
@ -2271,7 +2299,7 @@ unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, Assembler::Register* a,
|
|||||||
|
|
||||||
ResolvedPromise promise(32);
|
ResolvedPromise promise(32);
|
||||||
Assembler::Constant constant(&promise);
|
Assembler::Constant constant(&promise);
|
||||||
compareCR(c, aSize, &constant, aSize, a);
|
compareCR(c, aSize, &constant, aSize, &cx);
|
||||||
|
|
||||||
opcode(c, 0x7c); //jl
|
opcode(c, 0x7c); //jl
|
||||||
c->code.append(2 + 2);
|
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
|
moveRR(c, 4, &bh, 4, b); // 2 bytes
|
||||||
xorRR(c, 4, &bh, 4, &bh); // 2 bytes
|
xorRR(c, 4, &bh, 4, &bh); // 2 bytes
|
||||||
} else {
|
} else {
|
||||||
|
assert(c, a->low == rcx);
|
||||||
|
|
||||||
maybeRex(c, bSize, a, b);
|
maybeRex(c, bSize, a, b);
|
||||||
opcode(c, 0xd3, 0xe8 + regCode(b));
|
opcode(c, 0xd3, 0xe8 + regCode(b));
|
||||||
}
|
}
|
||||||
@ -2781,7 +2811,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual unsigned frameFootprint(unsigned footprint) {
|
virtual unsigned frameFootprint(unsigned footprint) {
|
||||||
#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS
|
#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE
|
||||||
return max(footprint, StackAlignmentInWords);
|
return max(footprint, StackAlignmentInWords);
|
||||||
#else
|
#else
|
||||||
return max(footprint > argumentRegisterCount() ?
|
return max(footprint > argumentRegisterCount() ?
|
||||||
@ -2803,7 +2833,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual unsigned argumentRegisterCount() {
|
virtual unsigned argumentRegisterCount() {
|
||||||
#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS
|
#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE
|
||||||
if (TargetBytesPerWord == 8) return 4; else
|
if (TargetBytesPerWord == 8) return 4; else
|
||||||
#else
|
#else
|
||||||
if (TargetBytesPerWord == 8) return 6; else
|
if (TargetBytesPerWord == 8) return 6; else
|
||||||
@ -2814,7 +2844,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
virtual int argumentRegister(unsigned index) {
|
virtual int argumentRegister(unsigned index) {
|
||||||
assert(&c, TargetBytesPerWord == 8);
|
assert(&c, TargetBytesPerWord == 8);
|
||||||
switch (index) {
|
switch (index) {
|
||||||
#if AVIAN_TARGET_PLATFORM == AVIAN_PLATFORM_WINDOWS
|
#if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE
|
||||||
case 0:
|
case 0:
|
||||||
return rcx;
|
return rcx;
|
||||||
case 1:
|
case 1:
|
||||||
@ -3064,7 +3094,11 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Float2Int:
|
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);
|
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
||||||
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
|
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
|
||||||
| FloatRegisterMask;
|
| FloatRegisterMask;
|
||||||
@ -3228,7 +3262,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
virtual void planSource
|
virtual void planSource
|
||||||
(TernaryOperation op,
|
(TernaryOperation op,
|
||||||
unsigned aSize, uint8_t *aTypeMask, uint64_t *aRegisterMask,
|
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)
|
unsigned, bool* thunk)
|
||||||
{
|
{
|
||||||
*aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand);
|
*aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand);
|
||||||
@ -3298,10 +3332,16 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
case ShiftLeft:
|
case ShiftLeft:
|
||||||
case ShiftRight:
|
case ShiftRight:
|
||||||
case UnsignedShiftRight: {
|
case UnsignedShiftRight: {
|
||||||
|
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)
|
*aRegisterMask = (static_cast<uint64_t>(GeneralRegisterMask) << 32)
|
||||||
| (static_cast<uint64_t>(1) << rcx);
|
| (static_cast<uint64_t>(1) << rcx);
|
||||||
const uint32_t mask = GeneralRegisterMask & ~(1 << rcx);
|
const uint32_t mask = GeneralRegisterMask & ~(1 << rcx);
|
||||||
*bRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
|
*bRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JumpIfFloatEqual:
|
case JumpIfFloatEqual:
|
||||||
|
18
src/x86.h
18
src/x86.h
@ -64,6 +64,18 @@
|
|||||||
# define FRAME_REGISTER(context) \
|
# define FRAME_REGISTER(context) \
|
||||||
THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss))
|
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
|
# else
|
||||||
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP])
|
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP])
|
||||||
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP])
|
# 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) \
|
# define FRAME_REGISTER(context) \
|
||||||
THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss))
|
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
|
# else
|
||||||
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
|
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
|
||||||
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP])
|
# 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:
|
public:
|
||||||
class Segment {
|
class Segment {
|
||||||
public:
|
public:
|
||||||
Segment(Segment* next, unsigned size): next(next), size(size) { }
|
Segment(Segment* next, unsigned size):
|
||||||
|
next(next), size(size), position(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
Segment* next;
|
Segment* next;
|
||||||
uintptr_t size;
|
uintptr_t size;
|
||||||
|
uintptr_t position;
|
||||||
uint8_t data[0];
|
uint8_t data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -31,7 +34,6 @@ class Zone: public Allocator {
|
|||||||
s(s),
|
s(s),
|
||||||
allocator(allocator),
|
allocator(allocator),
|
||||||
segment(0),
|
segment(0),
|
||||||
position(0),
|
|
||||||
minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 :
|
minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 :
|
||||||
minimumFootprint - sizeof(Segment))
|
minimumFootprint - sizeof(Segment))
|
||||||
{ }
|
{ }
|
||||||
@ -55,7 +57,7 @@ class Zone: public Allocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool tryEnsure(unsigned space) {
|
bool tryEnsure(unsigned space) {
|
||||||
if (segment == 0 or position + space > segment->size) {
|
if (segment == 0 or segment->position + space > segment->size) {
|
||||||
unsigned size = padToPage
|
unsigned size = padToPage
|
||||||
(max
|
(max
|
||||||
(space, max
|
(space, max
|
||||||
@ -72,26 +74,24 @@ class Zone: public Allocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
segment = new (p) Segment(segment, size - sizeof(Segment));
|
segment = new (p) Segment(segment, size - sizeof(Segment));
|
||||||
position = 0;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ensure(unsigned space) {
|
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));
|
unsigned size = padToPage(space + sizeof(Segment));
|
||||||
|
|
||||||
segment = new (allocator->allocate(size))
|
segment = new (allocator->allocate(size))
|
||||||
Segment(segment, size - sizeof(Segment));
|
Segment(segment, size - sizeof(Segment));
|
||||||
position = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size) {
|
virtual void* tryAllocate(unsigned size) {
|
||||||
size = pad(size);
|
size = pad(size);
|
||||||
if (tryEnsure(size)) {
|
if (tryEnsure(size)) {
|
||||||
void* r = segment->data + position;
|
void* r = segment->data + segment->position;
|
||||||
position += size;
|
segment->position += size;
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
@ -99,17 +99,41 @@ class Zone: public Allocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void* allocate(unsigned size) {
|
virtual void* allocate(unsigned size) {
|
||||||
|
size = pad(size);
|
||||||
void* p = tryAllocate(size);
|
void* p = tryAllocate(size);
|
||||||
if (p) {
|
if (p) {
|
||||||
return p;
|
return p;
|
||||||
} else {
|
} else {
|
||||||
ensure(size);
|
ensure(size);
|
||||||
void* r = segment->data + position;
|
void* r = segment->data + segment->position;
|
||||||
position += size;
|
segment->position += size;
|
||||||
return r;
|
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) {
|
virtual void free(const void*, unsigned) {
|
||||||
// not supported
|
// not supported
|
||||||
abort(s);
|
abort(s);
|
||||||
@ -119,7 +143,6 @@ class Zone: public Allocator {
|
|||||||
Allocator* allocator;
|
Allocator* allocator;
|
||||||
void* context;
|
void* context;
|
||||||
Segment* segment;
|
Segment* segment;
|
||||||
unsigned position;
|
|
||||||
unsigned minimumFootprint;
|
unsigned minimumFootprint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,14 +85,14 @@ public class Arrays {
|
|||||||
a[0] = new Object();
|
a[0] = new Object();
|
||||||
expect(! java.util.Arrays.equals(a, b));
|
expect(! java.util.Arrays.equals(a, b));
|
||||||
expect(! java.util.Arrays.equals(b, new Object[4]));
|
expect(! java.util.Arrays.equals(b, new Object[4]));
|
||||||
expect(! java.util.Arrays.equals(b, null));
|
expect(! java.util.Arrays.equals(a, null));
|
||||||
expect(! java.util.Arrays.equals(a, b));
|
expect(! java.util.Arrays.equals(null, b));
|
||||||
expect(java.util.Arrays.equals(null, null));
|
expect(java.util.Arrays.equals((Object[])null, (Object[])null));
|
||||||
b[0] = a[0];
|
b[0] = a[0];
|
||||||
expect(java.util.Arrays.equals(a, b));
|
expect(java.util.Arrays.equals(a, b));
|
||||||
|
|
||||||
java.util.Arrays.hashCode(a);
|
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();
|
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;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) throws Exception {
|
||||||
{ int foo = 1028;
|
{ int foo = 1028;
|
||||||
foo -= 1023;
|
foo -= 1023;
|
||||||
expect(foo == 5);
|
expect(foo == 5);
|
||||||
@ -262,9 +262,57 @@ public class Integers {
|
|||||||
expect(bytesPerLine == 24);
|
expect(bytesPerLine == 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
int y = -11760768;
|
{ int y = -11760768;
|
||||||
expect((y + 0x8000) == (-11760768 + 0x8000));
|
expect((y + 0x8000) == (-11760768 + 0x8000)); }
|
||||||
|
|
||||||
expect(Math.min(796, 1069) == 796);
|
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[0] == 337192406);
|
||||||
expect(z[1] == -437261072);
|
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;
|
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,
|
expect(new String(new byte[] { 99, 111, 109, 46, 101, 99, 111, 118, 97,
|
||||||
116, 101, 46, 110, 97, 116, 46, 98, 117,
|
116, 101, 46, 110, 97, 116, 46, 98, 117,
|
||||||
115, 46, 83, 121, 109, 98, 111, 108 })
|
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('b', 16), 16) == 'b');
|
||||||
expect(Character.forDigit(Character.digit('f', 16), 16) == 'f');
|
expect(Character.forDigit(Character.digit('f', 16), 16) == 'f');
|
||||||
expect(Character.forDigit(Character.digit('z', 36), 36) == 'z');
|
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));
|
||||||
|
}
|
Reference in New Issue
Block a user