mirror of
https://github.com/corda/corda.git
synced 2025-01-09 22:42:40 +00:00
Merge branch 'master' into armvfp
This commit is contained in:
commit
c989ea0529
10
classpath/avian/Atomic.java
Normal file
10
classpath/avian/Atomic.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package avian;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
public class Atomic {
|
||||||
|
public static native long getOffset(Field field);
|
||||||
|
|
||||||
|
public static native boolean compareAndSwapObject
|
||||||
|
(Object o, long offset, Object old, Object new_);
|
||||||
|
}
|
@ -51,7 +51,9 @@
|
|||||||
# endif
|
# endif
|
||||||
# include "unistd.h"
|
# include "unistd.h"
|
||||||
# include "limits.h"
|
# include "limits.h"
|
||||||
|
# include "signal.h"
|
||||||
# include "sys/time.h"
|
# include "sys/time.h"
|
||||||
|
# include "sys/types.h"
|
||||||
# include "sys/sysctl.h"
|
# include "sys/sysctl.h"
|
||||||
# include "sys/utsname.h"
|
# include "sys/utsname.h"
|
||||||
# include "sys/wait.h"
|
# include "sys/wait.h"
|
||||||
@ -281,6 +283,11 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid, jlong tid)
|
|||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_lang_Runtime_kill(JNIEnv*, jclass, jlong pid) {
|
||||||
|
TerminateProcess(reinterpret_cast<HANDLE>(pid), 1);
|
||||||
|
}
|
||||||
|
|
||||||
Locale getLocale() {
|
Locale getLocale() {
|
||||||
const char* lang = "";
|
const char* lang = "";
|
||||||
const char* reg = "";
|
const char* reg = "";
|
||||||
@ -468,6 +475,11 @@ Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid, jlong)
|
|||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_lang_Runtime_kill(JNIEnv*, jclass, jlong pid) {
|
||||||
|
kill((pid_t)pid, SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
Locale getLocale() {
|
Locale getLocale() {
|
||||||
Locale fallback;
|
Locale fallback;
|
||||||
|
|
||||||
|
@ -46,8 +46,7 @@ public class BufferedReader extends Reader {
|
|||||||
sb.append(buffer, position, i - position);
|
sb.append(buffer, position, i - position);
|
||||||
position = i + 1;
|
position = i + 1;
|
||||||
if(i+1 < limit && buffer[i+1] == '\n') {
|
if(i+1 < limit && buffer[i+1] == '\n') {
|
||||||
position = i + 1;
|
position = i + 2;
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
} else if (buffer[i] == '\n') {
|
} else if (buffer[i] == '\n') {
|
||||||
|
@ -61,6 +61,10 @@ public class File implements Serializable {
|
|||||||
return isFile(path);
|
return isFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAbsolute() {
|
||||||
|
return path.equals(toAbsolutePath(path));
|
||||||
|
}
|
||||||
|
|
||||||
private static native boolean canRead(String path);
|
private static native boolean canRead(String path);
|
||||||
|
|
||||||
public boolean canRead() {
|
public boolean canRead() {
|
||||||
|
@ -56,7 +56,7 @@ public abstract class InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void reset() throws IOException {
|
public void reset() throws IOException {
|
||||||
// ignore
|
throw new IOException("mark/reset not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean markSupported() {
|
public boolean markSupported() {
|
||||||
|
@ -12,16 +12,21 @@ package java.io;
|
|||||||
|
|
||||||
public class RandomAccessFile {
|
public class RandomAccessFile {
|
||||||
private long peer;
|
private long peer;
|
||||||
private long length;
|
private File file;
|
||||||
private long position = 0;
|
private long position = 0;
|
||||||
|
private long length;
|
||||||
|
|
||||||
public RandomAccessFile(String name, String mode)
|
public RandomAccessFile(String name, String mode)
|
||||||
throws FileNotFoundException
|
throws FileNotFoundException
|
||||||
{
|
{
|
||||||
if (! mode.equals("r")) throw new IllegalArgumentException();
|
if (! mode.equals("r")) throw new IllegalArgumentException();
|
||||||
|
file = new File(name);
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void open() throws FileNotFoundException {
|
||||||
long[] result = new long[2];
|
long[] result = new long[2];
|
||||||
open(name, result);
|
open(file.getPath(), result);
|
||||||
peer = result[0];
|
peer = result[0];
|
||||||
length = result[1];
|
length = result[1];
|
||||||
}
|
}
|
||||||
@ -29,7 +34,15 @@ public class RandomAccessFile {
|
|||||||
private static native void open(String name, long[] result)
|
private static native void open(String name, long[] result)
|
||||||
throws FileNotFoundException;
|
throws FileNotFoundException;
|
||||||
|
|
||||||
|
private void refresh() throws IOException {
|
||||||
|
if (file.length() != length) {
|
||||||
|
close();
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public long length() throws IOException {
|
public long length() throws IOException {
|
||||||
|
refresh();
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +51,7 @@ public class RandomAccessFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void seek(long position) throws IOException {
|
public void seek(long position) throws IOException {
|
||||||
if (position < 0 || position > length) throw new IOException();
|
if (position < 0 || position > length()) throw new IOException();
|
||||||
|
|
||||||
this.position = position;
|
this.position = position;
|
||||||
}
|
}
|
||||||
@ -50,12 +63,16 @@ public class RandomAccessFile {
|
|||||||
|
|
||||||
if (length == 0) return;
|
if (length == 0) return;
|
||||||
|
|
||||||
if (position + length > this.length) throw new EOFException();
|
if (position + length > this.length) {
|
||||||
|
if (position + length > length()) throw new EOFException();
|
||||||
|
}
|
||||||
|
|
||||||
if (offset < 0 || offset + length > buffer.length)
|
if (offset < 0 || offset + length > buffer.length)
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
|
|
||||||
copy(peer, position, buffer, offset, length);
|
copy(peer, position, buffer, offset, length);
|
||||||
|
|
||||||
|
position += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void copy(long peer, long position, byte[] buffer,
|
private static native void copy(long peer, long position, byte[] buffer,
|
||||||
|
@ -14,7 +14,7 @@ import java.lang.reflect.Method;
|
|||||||
|
|
||||||
public abstract class Enum<E extends Enum<E>> implements Comparable<E> {
|
public abstract class Enum<E extends Enum<E>> implements Comparable<E> {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final int ordinal;
|
protected final int ordinal;
|
||||||
|
|
||||||
public Enum(String name, int ordinal) {
|
public Enum(String name, int ordinal) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -12,6 +12,8 @@ package java.lang;
|
|||||||
|
|
||||||
public final class Float extends Number {
|
public final class Float extends Number {
|
||||||
public static final Class TYPE = Class.forCanonicalName("F");
|
public static final Class TYPE = Class.forCanonicalName("F");
|
||||||
|
private static final int EXP_BIT_MASK = 0x7F800000;
|
||||||
|
private static final int SIGNIF_BIT_MASK = 0x007FFFFF;
|
||||||
|
|
||||||
private final float value;
|
private final float value;
|
||||||
|
|
||||||
@ -89,6 +91,17 @@ public final class Float extends Number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int floatToIntBits(float value) {
|
||||||
|
int result = floatToRawIntBits(value);
|
||||||
|
|
||||||
|
// Check for NaN based on values of bit fields, maximum
|
||||||
|
// exponent and nonzero significand.
|
||||||
|
if (((result & EXP_BIT_MASK) == EXP_BIT_MASK) && (result & SIGNIF_BIT_MASK) != 0) {
|
||||||
|
result = 0x7fc00000;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static native int floatToRawIntBits(float value);
|
public static native int floatToRawIntBits(float value);
|
||||||
|
|
||||||
public static native float intBitsToFloat(int bits);
|
public static native float intBitsToFloat(int bits);
|
||||||
|
@ -122,6 +122,8 @@ public class Runtime {
|
|||||||
|
|
||||||
private static native void load(String name, boolean mapName);
|
private static native void load(String name, boolean mapName);
|
||||||
|
|
||||||
|
private static native void kill(long pid);
|
||||||
|
|
||||||
public native void gc();
|
public native void gc();
|
||||||
|
|
||||||
public native void exit(int code);
|
public native void exit(int code);
|
||||||
@ -147,7 +149,9 @@ public class Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
throw new RuntimeException("not implemented");
|
if (pid != 0) {
|
||||||
|
kill(pid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getInputStream() {
|
public InputStream getInputStream() {
|
||||||
|
@ -19,6 +19,8 @@ public final class URL {
|
|||||||
private String host;
|
private String host;
|
||||||
private int port;
|
private int port;
|
||||||
private String file;
|
private String file;
|
||||||
|
private String path;
|
||||||
|
private String query;
|
||||||
private String ref;
|
private String ref;
|
||||||
|
|
||||||
public URL(String s) throws MalformedURLException {
|
public URL(String s) throws MalformedURLException {
|
||||||
@ -56,6 +58,14 @@ public final class URL {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQuery() {
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
public URLConnection openConnection() throws IOException {
|
public URLConnection openConnection() throws IOException {
|
||||||
return handler.openConnection(this);
|
return handler.openConnection(this);
|
||||||
}
|
}
|
||||||
@ -90,5 +100,13 @@ public final class URL {
|
|||||||
this.port = port;
|
this.port = port;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.ref = ref;
|
this.ref = ref;
|
||||||
|
|
||||||
|
int q = file.lastIndexOf('?');
|
||||||
|
if (q != -1) {
|
||||||
|
this.query = file.substring(q + 1);
|
||||||
|
this.path = file.substring(0, q);
|
||||||
|
} else {
|
||||||
|
this.path = file;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,45 +15,50 @@ public abstract class Buffer {
|
|||||||
protected int position;
|
protected int position;
|
||||||
protected int limit;
|
protected int limit;
|
||||||
|
|
||||||
public int limit() {
|
public final int limit() {
|
||||||
return limit;
|
return limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int remaining() {
|
public final int remaining() {
|
||||||
return limit-position;
|
return limit-position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int position() {
|
public final int position() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int capacity() {
|
public final int capacity() {
|
||||||
return capacity;
|
return capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Buffer limit(int newLimit) {
|
public final Buffer limit(int newLimit) {
|
||||||
limit = newLimit;
|
limit = newLimit;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Buffer position(int newPosition) {
|
public final Buffer position(int newPosition) {
|
||||||
position = newPosition;
|
position = newPosition;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRemaining() {
|
public final boolean hasRemaining() {
|
||||||
return remaining() > 0;
|
return remaining() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Buffer clear() {
|
public final Buffer clear() {
|
||||||
position = 0;
|
position = 0;
|
||||||
limit = capacity;
|
limit = capacity;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Buffer flip() {
|
public final Buffer flip() {
|
||||||
limit = position;
|
limit = position;
|
||||||
position = 0;
|
position = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final Buffer rewind() {
|
||||||
|
position = 0;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,13 @@ public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
|
|||||||
position = 0;
|
position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ByteBuffer asReadOnlyBuffer() {
|
||||||
|
ByteBuffer b = new ByteBuffer(array, arrayOffset, capacity, true);
|
||||||
|
b.position(position());
|
||||||
|
b.limit(limit());
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
public int compareTo(ByteBuffer o) {
|
public int compareTo(ByteBuffer o) {
|
||||||
int end = (remaining() < o.remaining() ? remaining() : o.remaining());
|
int end = (remaining() < o.remaining() ? remaining() : o.remaining());
|
||||||
|
|
||||||
@ -159,6 +166,13 @@ public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
|
|||||||
| ((array[p + 3] & 0xFF));
|
| ((array[p + 3] & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public short getShort(int position) {
|
||||||
|
checkGet(position, 2);
|
||||||
|
|
||||||
|
int p = arrayOffset + position;
|
||||||
|
return (short) (((array[p] & 0xFF) << 8) | ((array[p + 1] & 0xFF)));
|
||||||
|
}
|
||||||
|
|
||||||
public int getInt() {
|
public int getInt() {
|
||||||
checkGet(4);
|
checkGet(4);
|
||||||
int i = get() << 24;
|
int i = get() << 24;
|
||||||
|
@ -72,4 +72,7 @@ public abstract class AbstractCollection<T> implements Collection<T> {
|
|||||||
|
|
||||||
public abstract Iterator<T> iterator();
|
public abstract Iterator<T> iterator();
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return Collections.toString(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2009, Avian Contributors
|
/* Copyright (c) 2009-2011, 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
|
||||||
@ -22,4 +22,20 @@ public abstract class AbstractList<T> extends AbstractCollection<T>
|
|||||||
public ListIterator<T> listIterator() {
|
public ListIterator<T> listIterator() {
|
||||||
return new Collections.ArrayListIterator(this);
|
return new Collections.ArrayListIterator(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int indexOf(Object o) {
|
||||||
|
int i = 0;
|
||||||
|
for (T v: this) {
|
||||||
|
if (o == null) {
|
||||||
|
if (v == null) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
} else if (o.equals(v)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
++ i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,18 @@ public class TreeSet<T> extends AbstractSet<T> implements Collection<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T first() {
|
||||||
|
if (isEmpty()) throw new NoSuchElementException();
|
||||||
|
|
||||||
|
return set.first().value().value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T last() {
|
||||||
|
if (isEmpty()) throw new NoSuchElementException();
|
||||||
|
|
||||||
|
return set.last().value().value;
|
||||||
|
}
|
||||||
|
|
||||||
public Iterator<T> iterator() {
|
public Iterator<T> iterator() {
|
||||||
return new MyIterator<T>(set.first());
|
return new MyIterator<T>(set.first());
|
||||||
}
|
}
|
||||||
|
45
classpath/java/util/UUID.java
Normal file
45
classpath/java/util/UUID.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package java.util;
|
||||||
|
|
||||||
|
public class UUID {
|
||||||
|
private final byte[] data;
|
||||||
|
|
||||||
|
private UUID(byte[] data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UUID randomUUID() {
|
||||||
|
byte[] array = new byte[16];
|
||||||
|
|
||||||
|
new Random().nextBytes(array);
|
||||||
|
|
||||||
|
array[6] &= 0x0f;
|
||||||
|
array[6] |= 0x40;
|
||||||
|
array[8] &= 0x3f;
|
||||||
|
array[8] |= 0x80;
|
||||||
|
|
||||||
|
return new UUID(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
toHex(sb, data, 0, 4); sb.append('-');
|
||||||
|
toHex(sb, data, 4, 2); sb.append('-');
|
||||||
|
toHex(sb, data, 6, 2); sb.append('-');
|
||||||
|
toHex(sb, data, 8, 2); sb.append('-');
|
||||||
|
toHex(sb, data, 10, 6);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static char toHex(int i) {
|
||||||
|
return (char) (i < 10 ? i + '0' : (i - 10) + 'A');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void toHex(StringBuilder sb, byte[] array, int offset,
|
||||||
|
int length)
|
||||||
|
{
|
||||||
|
for (int i = offset; i < offset + length; ++i) {
|
||||||
|
sb.append(toHex((array[i] >> 4) & 0xf));
|
||||||
|
sb.append(toHex((array[i] ) & 0xf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
classpath/java/util/concurrent/ConcurrentLinkedQueue.java
Normal file
93
classpath/java/util/concurrent/ConcurrentLinkedQueue.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package java.util.concurrent;
|
||||||
|
|
||||||
|
import avian.Atomic;
|
||||||
|
|
||||||
|
public class ConcurrentLinkedQueue<T> {
|
||||||
|
private static final long QueueHead;
|
||||||
|
private static final long QueueTail;
|
||||||
|
private static final long NodeNext;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
QueueHead = Atomic.getOffset
|
||||||
|
(ConcurrentLinkedQueue.class.getField("head"));
|
||||||
|
|
||||||
|
QueueTail = Atomic.getOffset
|
||||||
|
(ConcurrentLinkedQueue.class.getField("tail"));
|
||||||
|
|
||||||
|
NodeNext = Atomic.getOffset
|
||||||
|
(Node.class.getField("next"));
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private volatile Node<T> head = new Node(null, null);
|
||||||
|
private volatile Node<T> tail = head;
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
// todo: can we safely make this O(1)?
|
||||||
|
while (poll() != null) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(T value) {
|
||||||
|
Node<T> n = new Node(value, null);
|
||||||
|
while (true) {
|
||||||
|
Node<T> t = tail;
|
||||||
|
Node<T> next = tail.next;
|
||||||
|
if (t == tail) {
|
||||||
|
if (next != null) {
|
||||||
|
Atomic.compareAndSwapObject(this, QueueTail, t, next);
|
||||||
|
} else if (Atomic.compareAndSwapObject(tail, NodeNext, null, n)) {
|
||||||
|
Atomic.compareAndSwapObject(this, QueueTail, t, n);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T peek() {
|
||||||
|
return poll(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T poll() {
|
||||||
|
return poll(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T poll(boolean remove) {
|
||||||
|
while (true) {
|
||||||
|
Node<T> h = head;
|
||||||
|
Node<T> t = tail;
|
||||||
|
Node<T> next = head.next;
|
||||||
|
|
||||||
|
if (h == head) {
|
||||||
|
if (h == t) {
|
||||||
|
if (next != null) {
|
||||||
|
Atomic.compareAndSwapObject(this, QueueTail, t, next);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
T value = next.value;
|
||||||
|
if ((! remove)
|
||||||
|
|| Atomic.compareAndSwapObject(this, QueueHead, h, next))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Node<T> {
|
||||||
|
public volatile T value;
|
||||||
|
public volatile Node<T> next;
|
||||||
|
|
||||||
|
public Node(T value, Node<T> next) {
|
||||||
|
this.value = value;
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
makefile
23
makefile
@ -54,7 +54,7 @@ test = test
|
|||||||
|
|
||||||
classpath = avian
|
classpath = avian
|
||||||
|
|
||||||
test-executable = $(executable)
|
test-executable = $(shell pwd)/$(executable)
|
||||||
boot-classpath = $(classpath-build)
|
boot-classpath = $(classpath-build)
|
||||||
embed-prefix = /avian-embedded
|
embed-prefix = /avian-embedded
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ ifneq ($(openjdk),)
|
|||||||
boot-javahome-object = $(build)/boot-javahome.o
|
boot-javahome-object = $(build)/boot-javahome.o
|
||||||
else
|
else
|
||||||
options := $(options)-openjdk
|
options := $(options)-openjdk
|
||||||
test-executable = $(executable-dynamic)
|
test-executable = $(shell pwd)/$(executable-dynamic)
|
||||||
library-path = \
|
library-path = \
|
||||||
$(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch)
|
$(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch)
|
||||||
javahome = "$$($(native-path) "$(openjdk)/jre")"
|
javahome = "$$($(native-path) "$(openjdk)/jre")"
|
||||||
@ -246,7 +246,8 @@ ifeq ($(arch),arm)
|
|||||||
ifeq ($(build-platform),darwin)
|
ifeq ($(build-platform),darwin)
|
||||||
ios = true
|
ios = true
|
||||||
else
|
else
|
||||||
cflags += -marm -Wno-psabi
|
no-psabi = -Wno-psabi
|
||||||
|
cflags += -marm $(no-psabi)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(arch),$(build-arch))
|
ifneq ($(arch),$(build-arch))
|
||||||
@ -319,7 +320,7 @@ ifeq ($(platform),darwin)
|
|||||||
converter-cflags += -DOPPOSITE_ENDIAN
|
converter-cflags += -DOPPOSITE_ENDIAN
|
||||||
endif
|
endif
|
||||||
flags = -arch armv6 -isysroot \
|
flags = -arch armv6 -isysroot \
|
||||||
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/
|
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/
|
||||||
openjdk-extra-cflags += $(flags)
|
openjdk-extra-cflags += $(flags)
|
||||||
cflags += $(flags)
|
cflags += $(flags)
|
||||||
asmflags += $(flags)
|
asmflags += $(flags)
|
||||||
@ -372,7 +373,8 @@ ifeq ($(platform),windows)
|
|||||||
exe-suffix = .exe
|
exe-suffix = .exe
|
||||||
|
|
||||||
lflags = -L$(lib) $(common-lflags) -lws2_32 -mwindows -mconsole
|
lflags = -L$(lib) $(common-lflags) -lws2_32 -mwindows -mconsole
|
||||||
cflags = -I$(inc) $(common-cflags) -DWINVER=0x0500
|
cflags = -I$(inc) $(common-cflags) -DWINVER=0x0500 -DTARGET_PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
|
||||||
ifeq (,$(filter mingw32 cygwin,$(build-platform)))
|
ifeq (,$(filter mingw32 cygwin,$(build-platform)))
|
||||||
openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive
|
openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive
|
||||||
@ -446,6 +448,7 @@ ifeq ($(use-lto),true)
|
|||||||
ifeq ($(shell expr 4 \< $(gcc-major) \
|
ifeq ($(shell expr 4 \< $(gcc-major) \
|
||||||
\| \( 4 \<= $(gcc-major) \& 6 \<= $(gcc-minor) \)),1)
|
\| \( 4 \<= $(gcc-major) \& 6 \<= $(gcc-minor) \)),1)
|
||||||
optimization-cflags += -flto
|
optimization-cflags += -flto
|
||||||
|
no-lto = -fno-lto
|
||||||
lflags += $(optimization-cflags)
|
lflags += $(optimization-cflags)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
@ -584,12 +587,12 @@ endif
|
|||||||
cflags += $(extra-cflags)
|
cflags += $(extra-cflags)
|
||||||
lflags += $(extra-lflags)
|
lflags += $(extra-lflags)
|
||||||
|
|
||||||
|
openjdk-cflags += $(extra-cflags)
|
||||||
|
|
||||||
driver-source = $(src)/main.cpp
|
driver-source = $(src)/main.cpp
|
||||||
driver-object = $(build)/main.o
|
driver-object = $(build)/main.o
|
||||||
driver-dynamic-objects = \
|
driver-dynamic-objects = \
|
||||||
$(build)/main-dynamic.o \
|
$(build)/main-dynamic.o
|
||||||
$(build)/$(system).o \
|
|
||||||
$(build)/finder.o
|
|
||||||
|
|
||||||
boot-source = $(src)/boot.cpp
|
boot-source = $(src)/boot.cpp
|
||||||
boot-object = $(build)/boot.o
|
boot-object = $(build)/boot.o
|
||||||
@ -957,6 +960,8 @@ else
|
|||||||
endif
|
endif
|
||||||
$(strip) $(strip-all) $(@)
|
$(strip) $(strip-all) $(@)
|
||||||
|
|
||||||
|
# todo: the $(no-lto) flag below is due to odd undefined reference errors on
|
||||||
|
# Ubuntu 11.10 which may be fixable without disabling LTO.
|
||||||
$(executable-dynamic): $(driver-dynamic-objects) $(dynamic-library)
|
$(executable-dynamic): $(driver-dynamic-objects) $(dynamic-library)
|
||||||
@echo "linking $(@)"
|
@echo "linking $(@)"
|
||||||
ifdef msvc
|
ifdef msvc
|
||||||
@ -965,7 +970,7 @@ ifdef msvc
|
|||||||
-MANIFESTFILE:$(@).manifest
|
-MANIFESTFILE:$(@).manifest
|
||||||
$(mt) -manifest $(@).manifest -outputresource:"$(@);1"
|
$(mt) -manifest $(@).manifest -outputresource:"$(@);1"
|
||||||
else
|
else
|
||||||
$(ld) $(driver-dynamic-objects) -L$(build) -ljvm $(lflags) -o $(@)
|
$(ld) $(driver-dynamic-objects) -L$(build) -ljvm $(lflags) $(no-lto) -o $(@)
|
||||||
endif
|
endif
|
||||||
$(strip) $(strip-all) $(@)
|
$(strip) $(strip-all) $(@)
|
||||||
|
|
||||||
|
@ -2626,12 +2626,13 @@ class MyAssembler: public Assembler {
|
|||||||
poolSize += TargetBytesPerWord;
|
poolSize += TargetBytesPerWord;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needJump(b)) {
|
bool jump = needJump(b);
|
||||||
|
if (jump) {
|
||||||
write4
|
write4
|
||||||
(dst + dstOffset, ::b((poolSize + TargetBytesPerWord - 8) >> 2));
|
(dst + dstOffset, ::b((poolSize + TargetBytesPerWord - 8) >> 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
dstOffset += poolSize + TargetBytesPerWord;
|
dstOffset += poolSize + (jump ? TargetBytesPerWord : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned size = b->size - blockOffset;
|
unsigned size = b->size - blockOffset;
|
||||||
|
24
src/arm.h
24
src/arm.h
@ -146,18 +146,24 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes,
|
|||||||
switch (argumentTypes[ati]) {
|
switch (argumentTypes[ati]) {
|
||||||
case DOUBLE_TYPE:
|
case DOUBLE_TYPE:
|
||||||
case INT64_TYPE: {
|
case INT64_TYPE: {
|
||||||
if (gprIndex + Alignment <= GprCount) { // pass argument on registers
|
if (gprIndex + Alignment <= GprCount) { // pass argument in register(s)
|
||||||
if (gprIndex % Alignment) { // 8-byte alignment
|
if (Alignment == 1
|
||||||
memset(gprTable + gprIndex, 0, 4); // probably not necessary, but for good luck
|
and BytesPerWord < 8
|
||||||
++gprIndex;
|
and gprIndex + Alignment == GprCount)
|
||||||
}
|
{
|
||||||
|
gprTable[gprIndex++] = arguments[ai];
|
||||||
|
stack[stackIndex++] = arguments[ai + 1];
|
||||||
|
} else {
|
||||||
|
if (gprIndex % Alignment) {
|
||||||
|
++gprIndex;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(gprTable + gprIndex, arguments + ai, 8);
|
memcpy(gprTable + gprIndex, arguments + ai, 8);
|
||||||
gprIndex += 8 / BytesPerWord;
|
gprIndex += 8 / BytesPerWord;
|
||||||
|
}
|
||||||
} else { // pass argument on stack
|
} else { // pass argument on stack
|
||||||
gprIndex = GprCount;
|
gprIndex = GprCount;
|
||||||
if (stackIndex % Alignment) { // 8-byte alignment
|
if (stackIndex % Alignment) {
|
||||||
memset(stack + stackIndex, 0, 4); // probably not necessary, but for good luck
|
|
||||||
++stackIndex;
|
++stackIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,10 +211,12 @@ allFields(Thread* t, object typeMaps, object c, unsigned* count, object* array)
|
|||||||
includeMembers = false;
|
includeMembers = false;
|
||||||
*count += reinterpret_cast<TypeMap*>(&byteArrayBody(t, *array, 0))
|
*count += reinterpret_cast<TypeMap*>(&byteArrayBody(t, *array, 0))
|
||||||
->fixedFieldCount;
|
->fixedFieldCount;
|
||||||
} else if (classSuper(t, c)) {
|
} else {
|
||||||
includeMembers = true;
|
includeMembers = true;
|
||||||
fields = getNonStaticFields
|
if (classSuper(t, c)) {
|
||||||
(t, typeMaps, classSuper(t, c), fields, count, array);
|
fields = getNonStaticFields
|
||||||
|
(t, typeMaps, classSuper(t, c), fields, count, array);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classFieldTable(t, c)) {
|
if (classFieldTable(t, c)) {
|
||||||
@ -1314,9 +1316,9 @@ writeBootImage2(Thread* t, FILE* bootimageOutput, FILE* codeOutput,
|
|||||||
unsigned buildOffset = BytesPerWord;
|
unsigned buildOffset = BytesPerWord;
|
||||||
unsigned targetOffset = TargetBytesPerWord;
|
unsigned targetOffset = TargetBytesPerWord;
|
||||||
bool sawArray = false;
|
bool sawArray = false;
|
||||||
Type type;
|
Type type = Type_none;
|
||||||
unsigned buildSize;
|
unsigned buildSize = 0;
|
||||||
unsigned targetSize;
|
unsigned targetSize = 0;
|
||||||
for (unsigned j = 1; j < count; ++j) {
|
for (unsigned j = 1; j < count; ++j) {
|
||||||
switch (source[j - 1]) {
|
switch (source[j - 1]) {
|
||||||
case Type_object:
|
case Type_object:
|
||||||
|
@ -605,6 +605,33 @@ Avian_java_lang_Thread_yield
|
|||||||
t->m->system->yield();
|
t->m->system->yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
|
Avian_avian_Atomic_getOffset
|
||||||
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
return fieldOffset
|
||||||
|
(t, jfieldVmField(t, reinterpret_cast<object>(arguments[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
|
Avian_avian_Atomic_compareAndSwapObject
|
||||||
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
object target = reinterpret_cast<object>(arguments[0]);
|
||||||
|
int64_t offset; memcpy(&offset, arguments + 1, 8);
|
||||||
|
uintptr_t expect = arguments[3];
|
||||||
|
uintptr_t update = arguments[4];
|
||||||
|
|
||||||
|
bool success = atomicCompareAndSwap
|
||||||
|
(&cast<uintptr_t>(target, offset), expect, update);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
mark(t, target, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
Avian_avian_Classes_primitiveClass
|
Avian_avian_Classes_primitiveClass
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
|
@ -2594,15 +2594,25 @@ Avian_sun_misc_Unsafe_compareAndSwapObject
|
|||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
Avian_sun_misc_Unsafe_compareAndSwapLong
|
Avian_sun_misc_Unsafe_compareAndSwapLong
|
||||||
(Thread*, object, uintptr_t* arguments)
|
(Thread* t UNUSED, object, uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
object target = reinterpret_cast<object>(arguments[1]);
|
object target = reinterpret_cast<object>(arguments[1]);
|
||||||
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
||||||
uint64_t expect; memcpy(&expect, arguments + 4, 8);
|
uint64_t expect; memcpy(&expect, arguments + 4, 8);
|
||||||
uint64_t update; memcpy(&update, arguments + 6, 8);
|
uint64_t update; memcpy(&update, arguments + 6, 8);
|
||||||
|
|
||||||
|
#ifdef AVIAN_HAS_CAS64
|
||||||
return atomicCompareAndSwap64
|
return atomicCompareAndSwap64
|
||||||
(&cast<uint64_t>(target, offset), expect, update);
|
(&cast<uint64_t>(target, offset), expect, update);
|
||||||
|
#else
|
||||||
|
ACQUIRE_FIELD_FOR_WRITE(t, local::fieldForOffset(t, target, offset));
|
||||||
|
if (cast<uint64_t>(target, offset) == expect) {
|
||||||
|
cast<uint64_t>(target, offset) = update;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT int64_t JNICALL
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
@ -2747,17 +2757,27 @@ Avian_sun_misc_Unsafe_park
|
|||||||
bool absolute = arguments[1];
|
bool absolute = arguments[1];
|
||||||
int64_t time; memcpy(&time, arguments + 2, 8);
|
int64_t time; memcpy(&time, arguments + 2, 8);
|
||||||
|
|
||||||
|
int64_t then = t->m->system->now();
|
||||||
|
|
||||||
if (absolute) {
|
if (absolute) {
|
||||||
time -= t->m->system->now();
|
time -= then;
|
||||||
if (time <= 0) {
|
if (time <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
time /= 1000 * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
monitorAcquire(t, local::interruptLock(t, t->javaThread));
|
monitorAcquire(t, local::interruptLock(t, t->javaThread));
|
||||||
while (not (threadUnparked(t, t->javaThread)
|
while (time > 0
|
||||||
or monitorWait(t, local::interruptLock(t, t->javaThread), time)))
|
and (not (threadUnparked(t, t->javaThread)
|
||||||
{ }
|
or monitorWait
|
||||||
|
(t, local::interruptLock(t, t->javaThread), time))))
|
||||||
|
{
|
||||||
|
int64_t now = t->m->system->now();
|
||||||
|
time -= now - then;
|
||||||
|
then = now;
|
||||||
|
}
|
||||||
threadUnparked(t, t->javaThread) = false;
|
threadUnparked(t, t->javaThread) = false;
|
||||||
monitorRelease(t, local::interruptLock(t, t->javaThread));
|
monitorRelease(t, local::interruptLock(t, t->javaThread));
|
||||||
}
|
}
|
||||||
|
117
src/compile.cpp
117
src/compile.cpp
@ -2011,7 +2011,7 @@ findExceptionHandler(Thread* t, object method, void* ip)
|
|||||||
if (key >= start and key < end) {
|
if (key >= start and key < end) {
|
||||||
object catchType = arrayBody(t, table, i + 1);
|
object catchType = arrayBody(t, table, i + 1);
|
||||||
|
|
||||||
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
|
if (exceptionMatch(t, catchType, t->exception)) {
|
||||||
return compiled + intArrayBody(t, index, (i * 3) + 2);
|
return compiled + intArrayBody(t, index, (i * 3) + 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2274,7 +2274,7 @@ uintptr_t
|
|||||||
methodAddress(Thread* t, object method)
|
methodAddress(Thread* t, object method)
|
||||||
{
|
{
|
||||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||||
return nativeThunk(static_cast<MyThread*>(t));
|
return bootNativeThunk(static_cast<MyThread*>(t));
|
||||||
} else {
|
} else {
|
||||||
return methodCompiled(t, method);
|
return methodCompiled(t, method);
|
||||||
}
|
}
|
||||||
@ -8249,7 +8249,7 @@ class SignalHandler: public System::SignalHandler {
|
|||||||
t->exception = vm::root(t, root);
|
t->exception = vm::root(t, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
//printTrace(t, t->exception);
|
// printTrace(t, t->exception);
|
||||||
|
|
||||||
object continuation;
|
object continuation;
|
||||||
findUnwindTarget(t, ip, frame, stack, &continuation);
|
findUnwindTarget(t, ip, frame, stack, &continuation);
|
||||||
@ -8395,6 +8395,12 @@ class MyProcessor: public Processor {
|
|||||||
difference(&(t->virtualCallTarget), t));
|
difference(&(t->virtualCallTarget), t));
|
||||||
fprintf(stderr, "virtualCallIndex %d\n",
|
fprintf(stderr, "virtualCallIndex %d\n",
|
||||||
difference(&(t->virtualCallIndex), t));
|
difference(&(t->virtualCallIndex), t));
|
||||||
|
fprintf(stderr, "heapImage %d\n",
|
||||||
|
difference(&(t->heapImage), t));
|
||||||
|
fprintf(stderr, "codeImage %d\n",
|
||||||
|
difference(&(t->codeImage), t));
|
||||||
|
fprintf(stderr, "thunkTable %d\n",
|
||||||
|
difference(&(t->thunkTable), t));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8820,6 +8826,10 @@ class MyProcessor: public Processor {
|
|||||||
|
|
||||||
local::compileThunks(static_cast<MyThread*>(t), &codeAllocator);
|
local::compileThunks(static_cast<MyThread*>(t), &codeAllocator);
|
||||||
|
|
||||||
|
if (not (image and code)) {
|
||||||
|
bootThunks = thunks;
|
||||||
|
}
|
||||||
|
|
||||||
segFaultHandler.m = t->m;
|
segFaultHandler.m = t->m;
|
||||||
expect(t, t->m->system->success
|
expect(t, t->m->system->success
|
||||||
(t->m->system->handleSegFault(&segFaultHandler)));
|
(t->m->system->handleSegFault(&segFaultHandler)));
|
||||||
@ -8909,20 +8919,22 @@ compileMethod2(MyThread* t, void* ip)
|
|||||||
|
|
||||||
compile(t, codeAllocator(t), 0, target);
|
compile(t, codeAllocator(t), 0, target);
|
||||||
|
|
||||||
uintptr_t address;
|
|
||||||
if ((methodFlags(t, target) & ACC_NATIVE)
|
|
||||||
and useLongJump(t, reinterpret_cast<uintptr_t>(ip)))
|
|
||||||
{
|
|
||||||
address = bootNativeThunk(t);
|
|
||||||
} else {
|
|
||||||
address = methodAddress(t, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* updateIp = static_cast<uint8_t*>(ip);
|
uint8_t* updateIp = static_cast<uint8_t*>(ip);
|
||||||
|
|
||||||
MyProcessor* p = processor(t);
|
MyProcessor* p = processor(t);
|
||||||
|
|
||||||
if (updateIp < p->codeImage or updateIp >= p->codeImage + p->codeImageSize) {
|
bool updateCaller = updateIp < p->codeImage
|
||||||
|
or updateIp >= p->codeImage + p->codeImageSize;
|
||||||
|
|
||||||
|
uintptr_t address;
|
||||||
|
if (methodFlags(t, target) & ACC_NATIVE) {
|
||||||
|
address = useLongJump(t, reinterpret_cast<uintptr_t>(ip))
|
||||||
|
or (not updateCaller) ? bootNativeThunk(t) : nativeThunk(t);
|
||||||
|
} else {
|
||||||
|
address = methodAddress(t, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateCaller) {
|
||||||
UnaryOperation op;
|
UnaryOperation op;
|
||||||
if (callNodeFlags(t, node) & TraceElement::LongCall) {
|
if (callNodeFlags(t, node) & TraceElement::LongCall) {
|
||||||
if (callNodeFlags(t, node) & TraceElement::TailCall) {
|
if (callNodeFlags(t, node) & TraceElement::TailCall) {
|
||||||
@ -9225,6 +9237,52 @@ fixupHeap(MyThread* t UNUSED, uintptr_t* map, unsigned size, uintptr_t* heap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
resetClassRuntimeState(Thread* t, object c, uintptr_t* heap, unsigned heapSize)
|
||||||
|
{
|
||||||
|
classRuntimeDataIndex(t, c) = 0;
|
||||||
|
|
||||||
|
if (classArrayElementSize(t, c) == 0) {
|
||||||
|
object staticTable = classStaticTable(t, c);
|
||||||
|
if (staticTable) {
|
||||||
|
for (unsigned i = 0; i < singletonCount(t, staticTable); ++i) {
|
||||||
|
if (singletonIsObject(t, staticTable, i)
|
||||||
|
and (reinterpret_cast<uintptr_t*>
|
||||||
|
(singletonObject(t, staticTable, i)) < heap or
|
||||||
|
reinterpret_cast<uintptr_t*>
|
||||||
|
(singletonObject(t, staticTable, i)) > heap + heapSize))
|
||||||
|
{
|
||||||
|
singletonObject(t, staticTable, i) = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (classMethodTable(t, c)) {
|
||||||
|
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
|
||||||
|
object m = arrayBody(t, classMethodTable(t, c), i);
|
||||||
|
|
||||||
|
methodNativeID(t, m) = 0;
|
||||||
|
methodRuntimeDataIndex(t, m) = 0;
|
||||||
|
|
||||||
|
if (methodVmFlags(t, m) & ClassInitFlag) {
|
||||||
|
classVmFlags(t, c) |= NeedInitFlag;
|
||||||
|
classVmFlags(t, c) &= ~InitErrorFlag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t->m->processor->initVtable(t, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
resetRuntimeState(Thread* t, object map, uintptr_t* heap, unsigned heapSize)
|
||||||
|
{
|
||||||
|
for (HashMapIterator it(t, map); it.hasMore();) {
|
||||||
|
resetClassRuntimeState(t, tripleSecond(t, it.next()), heap, heapSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fixupMethods(Thread* t, object map, BootImage* image UNUSED, uint8_t* code)
|
fixupMethods(Thread* t, object map, BootImage* image UNUSED, uint8_t* code)
|
||||||
{
|
{
|
||||||
@ -9327,7 +9385,11 @@ boot(MyThread* t, BootImage* image, uint8_t* code)
|
|||||||
// fprintf(stderr, "code from %p to %p\n",
|
// fprintf(stderr, "code from %p to %p\n",
|
||||||
// code, code + image->codeSize);
|
// code, code + image->codeSize);
|
||||||
|
|
||||||
fixupHeap(t, heapMap, heapMapSizeInWords, heap);
|
static bool fixed = false;
|
||||||
|
|
||||||
|
if (not fixed) {
|
||||||
|
fixupHeap(t, heapMap, heapMapSizeInWords, heap);
|
||||||
|
}
|
||||||
|
|
||||||
t->m->heap->setImmortalHeap(heap, image->heapSize / BytesPerWord);
|
t->m->heap->setImmortalHeap(heap, image->heapSize / BytesPerWord);
|
||||||
|
|
||||||
@ -9372,11 +9434,30 @@ boot(MyThread* t, BootImage* image, uint8_t* code)
|
|||||||
|
|
||||||
findThunks(t, image, code);
|
findThunks(t, image, code);
|
||||||
|
|
||||||
fixupVirtualThunks(t, code);
|
if (fixed) {
|
||||||
|
resetRuntimeState
|
||||||
|
(t, classLoaderMap(t, root(t, Machine::BootLoader)), heap,
|
||||||
|
image->heapSize);
|
||||||
|
|
||||||
fixupMethods
|
resetRuntimeState
|
||||||
(t, classLoaderMap(t, root(t, Machine::BootLoader)), image, code);
|
(t, classLoaderMap(t, root(t, Machine::AppLoader)), heap,
|
||||||
fixupMethods(t, classLoaderMap(t, root(t, Machine::AppLoader)), image, code);
|
image->heapSize);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < arrayLength(t, t->m->types); ++i) {
|
||||||
|
resetClassRuntimeState
|
||||||
|
(t, type(t, static_cast<Machine::Type>(i)), heap, image->heapSize);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fixupVirtualThunks(t, code);
|
||||||
|
|
||||||
|
fixupMethods
|
||||||
|
(t, classLoaderMap(t, root(t, Machine::BootLoader)), image, code);
|
||||||
|
|
||||||
|
fixupMethods
|
||||||
|
(t, classLoaderMap(t, root(t, Machine::AppLoader)), image, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed = true;
|
||||||
|
|
||||||
setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0));
|
setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0));
|
||||||
}
|
}
|
||||||
|
@ -920,7 +920,7 @@ class MyFinder: public Finder {
|
|||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Finder*
|
JNIEXPORT Finder*
|
||||||
makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary)
|
makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary)
|
||||||
{
|
{
|
||||||
return new (a->allocate(sizeof(MyFinder))) MyFinder(s, a, path, bootLibrary);
|
return new (a->allocate(sizeof(MyFinder))) MyFinder(s, a, path, bootLibrary);
|
||||||
|
30
src/heap.cpp
30
src/heap.cpp
@ -544,9 +544,9 @@ class Fixie {
|
|||||||
// you add/remove/change fields in this class:
|
// you add/remove/change fields in this class:
|
||||||
|
|
||||||
uint8_t age;
|
uint8_t age;
|
||||||
bool hasMask;
|
uint8_t hasMask;
|
||||||
bool marked;
|
uint8_t marked;
|
||||||
bool dirty;
|
uint8_t dirty;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
Fixie* next;
|
Fixie* next;
|
||||||
Fixie** handle;
|
Fixie** handle;
|
||||||
@ -560,7 +560,7 @@ fixie(void* body)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
free(Context* c, Fixie** fixies);
|
free(Context* c, Fixie** fixies, bool resetImmortal = false);
|
||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
@ -630,9 +630,9 @@ class Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void disposeFixies() {
|
void disposeFixies() {
|
||||||
free(this, &tenuredFixies);
|
free(this, &tenuredFixies, true);
|
||||||
free(this, &dirtyTenuredFixies);
|
free(this, &dirtyTenuredFixies, true);
|
||||||
free(this, &fixies);
|
free(this, &fixies, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* system;
|
System* system;
|
||||||
@ -846,13 +846,25 @@ bitset(Context* c UNUSED, void* o)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
free(Context* c, Fixie** fixies)
|
free(Context* c, Fixie** fixies, bool resetImmortal)
|
||||||
{
|
{
|
||||||
for (Fixie** p = fixies; *p;) {
|
for (Fixie** p = fixies; *p;) {
|
||||||
Fixie* f = *p;
|
Fixie* f = *p;
|
||||||
|
|
||||||
if (f->immortal()) {
|
if (f->immortal()) {
|
||||||
p = &(f->next);
|
if (resetImmortal) {
|
||||||
|
if (DebugFixies) {
|
||||||
|
fprintf(stderr, "reset immortal fixie %p\n", f);
|
||||||
|
}
|
||||||
|
*p = f->next;
|
||||||
|
memset(f->mask(), 0, Fixie::maskSize(f->size, f->hasMask));
|
||||||
|
f->next = 0;
|
||||||
|
f->handle = 0;
|
||||||
|
f->marked = false;
|
||||||
|
f->dirty = false;
|
||||||
|
} else {
|
||||||
|
p = &(f->next);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
*p = f->next;
|
*p = f->next;
|
||||||
if (DebugFixies) {
|
if (DebugFixies) {
|
||||||
|
@ -698,7 +698,7 @@ findExceptionHandler(Thread* t, object method, unsigned ip)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
|
if (exceptionMatch(t, catchType, t->exception)) {
|
||||||
return eh;
|
return eh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3024,6 +3024,8 @@ boot(Thread* t, uintptr_t*)
|
|||||||
setRoot(t, Machine::OutOfMemoryError,
|
setRoot(t, Machine::OutOfMemoryError,
|
||||||
makeThrowable(t, Machine::OutOfMemoryErrorType));
|
makeThrowable(t, Machine::OutOfMemoryErrorType));
|
||||||
|
|
||||||
|
setRoot(t, Machine::Shutdown, makeThrowable(t, Machine::ThrowableType));
|
||||||
|
|
||||||
setRoot(t, Machine::FinalizerThread, t->m->classpath->makeThread(t, t));
|
setRoot(t, Machine::FinalizerThread, t->m->classpath->makeThread(t, t));
|
||||||
|
|
||||||
threadDaemon(t, root(t, Machine::FinalizerThread)) = true;
|
threadDaemon(t, root(t, Machine::FinalizerThread)) = true;
|
||||||
|
@ -45,6 +45,15 @@ void
|
|||||||
join(Thread* t, Thread* o)
|
join(Thread* t, Thread* o)
|
||||||
{
|
{
|
||||||
if (t != o) {
|
if (t != o) {
|
||||||
|
// todo: There's potentially a leak here on systems where we must
|
||||||
|
// call join on a thread in order to clean up all resources
|
||||||
|
// associated with it. If a thread has already been zombified by
|
||||||
|
// the time we get here, acquireSystem will return false, which
|
||||||
|
// means we can't safely join it because the System::Thread may
|
||||||
|
// already have been disposed. In that case, the thread has
|
||||||
|
// already exited (or will soon), but the OS will never free all
|
||||||
|
// its resources because it doesn't know we're completely done
|
||||||
|
// with it.
|
||||||
if (acquireSystem(t, o)) {
|
if (acquireSystem(t, o)) {
|
||||||
o->systemThread->join();
|
o->systemThread->join();
|
||||||
releaseSystem(t, o);
|
releaseSystem(t, o);
|
||||||
@ -138,35 +147,37 @@ dispose(Thread* t, Thread* o, bool remove)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
joinAll(Thread* m, Thread* o)
|
visitAll(Thread* m, Thread* o, void (*visit)(Thread*, Thread*))
|
||||||
{
|
{
|
||||||
for (Thread* p = o->child; p;) {
|
for (Thread* p = o->child; p;) {
|
||||||
Thread* child = p;
|
Thread* child = p;
|
||||||
p = p->peer;
|
p = p->peer;
|
||||||
joinAll(m, child);
|
visitAll(m, child, visit);
|
||||||
}
|
}
|
||||||
|
|
||||||
join(m, o);
|
visit(m, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
disposeAll(Thread* m, Thread* o)
|
disposeNoRemove(Thread* m, Thread* o)
|
||||||
{
|
{
|
||||||
for (Thread* p = o->child; p;) {
|
|
||||||
Thread* child = p;
|
|
||||||
p = p->peer;
|
|
||||||
disposeAll(m, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose(m, o, false);
|
dispose(m, o, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
interruptDaemon(Thread* m, Thread* o)
|
||||||
|
{
|
||||||
|
if (o->flags & Thread::DaemonFlag) {
|
||||||
|
interrupt(m, o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
turnOffTheLights(Thread* t)
|
turnOffTheLights(Thread* t)
|
||||||
{
|
{
|
||||||
expect(t, t->m->liveCount == 1);
|
expect(t, t->m->liveCount == 1);
|
||||||
|
|
||||||
joinAll(t, t->m->rootThread);
|
visitAll(t, t->m->rootThread, join);
|
||||||
|
|
||||||
enter(t, Thread::ExitState);
|
enter(t, Thread::ExitState);
|
||||||
|
|
||||||
@ -215,7 +226,7 @@ turnOffTheLights(Thread* t)
|
|||||||
|
|
||||||
Machine* m = t->m;
|
Machine* m = t->m;
|
||||||
|
|
||||||
disposeAll(t, t->m->rootThread);
|
visitAll(t, t->m->rootThread, disposeNoRemove);
|
||||||
|
|
||||||
System* s = m->system;
|
System* s = m->system;
|
||||||
Heap* h = m->heap;
|
Heap* h = m->heap;
|
||||||
@ -1662,13 +1673,17 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
set(t, addendum, ClassAddendumMethodTable,
|
set(t, addendum, ClassAddendumMethodTable,
|
||||||
classMethodTable(t, class_));
|
classMethodTable(t, class_));
|
||||||
|
|
||||||
unsigned oldLength = arrayLength(t, classMethodTable(t, class_));
|
unsigned oldLength = classMethodTable(t, class_) ?
|
||||||
|
arrayLength(t, classMethodTable(t, class_)) : 0;
|
||||||
|
|
||||||
object newMethodTable = makeArray
|
object newMethodTable = makeArray
|
||||||
(t, oldLength + listSize(t, abstractVirtuals));
|
(t, oldLength + listSize(t, abstractVirtuals));
|
||||||
|
|
||||||
memcpy(&arrayBody(t, newMethodTable, 0),
|
if (oldLength) {
|
||||||
&arrayBody(t, classMethodTable(t, class_), 0),
|
memcpy(&arrayBody(t, newMethodTable, 0),
|
||||||
oldLength * sizeof(object));
|
&arrayBody(t, classMethodTable(t, class_), 0),
|
||||||
|
oldLength * sizeof(object));
|
||||||
|
}
|
||||||
|
|
||||||
mark(t, newMethodTable, ArrayBody, oldLength);
|
mark(t, newMethodTable, ArrayBody, oldLength);
|
||||||
|
|
||||||
@ -2443,6 +2458,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder,
|
|||||||
collecting(false),
|
collecting(false),
|
||||||
triedBuiltinOnLoad(false),
|
triedBuiltinOnLoad(false),
|
||||||
dumpedHeapOnOOM(false),
|
dumpedHeapOnOOM(false),
|
||||||
|
alive(true),
|
||||||
heapPoolIndex(0)
|
heapPoolIndex(0)
|
||||||
{
|
{
|
||||||
heap->setClient(heapClient);
|
heap->setClient(heapClient);
|
||||||
@ -2566,7 +2582,7 @@ Thread::init()
|
|||||||
|
|
||||||
enter(this, ActiveState);
|
enter(this, ActiveState);
|
||||||
|
|
||||||
if (image and image) {
|
if (image and code) {
|
||||||
m->processor->boot(this, image, code);
|
m->processor->boot(this, image, code);
|
||||||
} else {
|
} else {
|
||||||
boot(this);
|
boot(this);
|
||||||
@ -2694,6 +2710,17 @@ shutDown(Thread* t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interrupt daemon threads and tell them to die
|
||||||
|
|
||||||
|
// todo: be more aggressive about killing daemon threads, e.g. at
|
||||||
|
// any GC point, not just at waits/sleeps
|
||||||
|
{ ACQUIRE(t, t->m->stateLock);
|
||||||
|
|
||||||
|
t->m->alive = false;
|
||||||
|
|
||||||
|
visitAll(t, t->m->rootThread, interruptDaemon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -3247,9 +3274,7 @@ classInitializer(Thread* t, object class_)
|
|||||||
{
|
{
|
||||||
object o = arrayBody(t, classMethodTable(t, class_), i);
|
object o = arrayBody(t, classMethodTable(t, class_), i);
|
||||||
|
|
||||||
if (vm::strcmp(reinterpret_cast<const int8_t*>("<clinit>"),
|
if (methodVmFlags(t, o) & ClassInitFlag) {
|
||||||
&byteArrayBody(t, methodName(t, o), 0)) == 0)
|
|
||||||
{
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3798,6 +3823,9 @@ initClass(Thread* t, object c)
|
|||||||
object
|
object
|
||||||
resolveObjectArrayClass(Thread* t, object loader, object elementClass)
|
resolveObjectArrayClass(Thread* t, object loader, object elementClass)
|
||||||
{
|
{
|
||||||
|
PROTECT(t, loader);
|
||||||
|
PROTECT(t, elementClass);
|
||||||
|
|
||||||
{ object arrayClass = classRuntimeDataArrayClass
|
{ object arrayClass = classRuntimeDataArrayClass
|
||||||
(t, getClassRuntimeData(t, elementClass));
|
(t, getClassRuntimeData(t, elementClass));
|
||||||
if (arrayClass) {
|
if (arrayClass) {
|
||||||
@ -3805,9 +3833,6 @@ resolveObjectArrayClass(Thread* t, object loader, object elementClass)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PROTECT(t, loader);
|
|
||||||
PROTECT(t, elementClass);
|
|
||||||
|
|
||||||
object elementSpec = className(t, elementClass);
|
object elementSpec = className(t, elementClass);
|
||||||
PROTECT(t, elementSpec);
|
PROTECT(t, elementSpec);
|
||||||
|
|
||||||
|
@ -157,8 +157,7 @@ const unsigned ContinuationFlag = 1 << 11;
|
|||||||
|
|
||||||
// method vmFlags:
|
// method vmFlags:
|
||||||
const unsigned ClassInitFlag = 1 << 0;
|
const unsigned ClassInitFlag = 1 << 0;
|
||||||
const unsigned CompiledFlag = 1 << 1;
|
const unsigned ConstructorFlag = 1 << 1;
|
||||||
const unsigned ConstructorFlag = 1 << 2;
|
|
||||||
|
|
||||||
#ifndef JNI_VERSION_1_6
|
#ifndef JNI_VERSION_1_6
|
||||||
#define JNI_VERSION_1_6 0x00010006
|
#define JNI_VERSION_1_6 0x00010006
|
||||||
@ -1266,6 +1265,7 @@ class Machine {
|
|||||||
ArithmeticException,
|
ArithmeticException,
|
||||||
ArrayIndexOutOfBoundsException,
|
ArrayIndexOutOfBoundsException,
|
||||||
OutOfMemoryError,
|
OutOfMemoryError,
|
||||||
|
Shutdown,
|
||||||
VirtualFileFinders,
|
VirtualFileFinders,
|
||||||
VirtualFiles
|
VirtualFiles
|
||||||
};
|
};
|
||||||
@ -1322,6 +1322,7 @@ class Machine {
|
|||||||
bool collecting;
|
bool collecting;
|
||||||
bool triedBuiltinOnLoad;
|
bool triedBuiltinOnLoad;
|
||||||
bool dumpedHeapOnOOM;
|
bool dumpedHeapOnOOM;
|
||||||
|
bool alive;
|
||||||
JavaVMVTable javaVMVTable;
|
JavaVMVTable javaVMVTable;
|
||||||
JNIEnvVTable jniEnvVTable;
|
JNIEnvVTable jniEnvVTable;
|
||||||
uintptr_t* heapPool[ThreadHeapPoolSize];
|
uintptr_t* heapPool[ThreadHeapPoolSize];
|
||||||
@ -1357,6 +1358,9 @@ run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*),
|
|||||||
void
|
void
|
||||||
checkDaemon(Thread* t);
|
checkDaemon(Thread* t);
|
||||||
|
|
||||||
|
object&
|
||||||
|
root(Thread* t, Machine::Root root);
|
||||||
|
|
||||||
extern "C" uint64_t
|
extern "C" uint64_t
|
||||||
vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments,
|
vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments,
|
||||||
void* checkpoint);
|
void* checkpoint);
|
||||||
@ -1507,7 +1511,7 @@ class Thread {
|
|||||||
|
|
||||||
vm::run(t, runThread, 0);
|
vm::run(t, runThread, 0);
|
||||||
|
|
||||||
if (t->exception) {
|
if (t->exception and t->exception != root(t, Machine::Shutdown)) {
|
||||||
printTrace(t, t->exception);
|
printTrace(t, t->exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3182,7 +3186,11 @@ wait(Thread* t, object o, int64_t milliseconds)
|
|||||||
bool interrupted = monitorWait(t, m, milliseconds);
|
bool interrupted = monitorWait(t, m, milliseconds);
|
||||||
|
|
||||||
if (interrupted) {
|
if (interrupted) {
|
||||||
throwNew(t, Machine::InterruptedExceptionType);
|
if (t->m->alive or (t->flags & Thread::DaemonFlag) == 0) {
|
||||||
|
throwNew(t, Machine::InterruptedExceptionType);
|
||||||
|
} else {
|
||||||
|
throw_(t, root(t, Machine::Shutdown));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throwNew(t, Machine::IllegalMonitorStateExceptionType);
|
throwNew(t, Machine::IllegalMonitorStateExceptionType);
|
||||||
@ -3256,6 +3264,14 @@ getAndClearInterrupted(Thread* t, Thread* target)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
exceptionMatch(Thread* t, object type, object exception)
|
||||||
|
{
|
||||||
|
return type == 0
|
||||||
|
or (exception != root(t, Machine::Shutdown)
|
||||||
|
and instanceOf(t, type, t->exception));
|
||||||
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
intern(Thread* t, object s);
|
intern(Thread* t, object s);
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
@ -197,7 +197,7 @@ class MySystem: public System {
|
|||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -410,7 +410,7 @@ class MySystem: public System {
|
|||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
expect(s, owner_ == 0);
|
expect(s, owner_ == 0);
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -441,7 +441,7 @@ class MySystem: public System {
|
|||||||
int r UNUSED = pthread_key_delete(key);
|
int r UNUSED = pthread_key_delete(key);
|
||||||
expect(s, r == 0);
|
expect(s, r == 0);
|
||||||
|
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -468,7 +468,7 @@ class MySystem: public System {
|
|||||||
if (start_) {
|
if (start_) {
|
||||||
munmap(start_, length_);
|
munmap(start_, length_);
|
||||||
}
|
}
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -494,7 +494,7 @@ class MySystem: public System {
|
|||||||
if (directory) {
|
if (directory) {
|
||||||
closedir(directory);
|
closedir(directory);
|
||||||
}
|
}
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -541,10 +541,10 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name_) {
|
if (name_) {
|
||||||
s->free(name_);
|
::free(const_cast<char*>(name_));
|
||||||
}
|
}
|
||||||
|
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -772,13 +772,22 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual FileType stat(const char* name, unsigned* length) {
|
virtual FileType stat(const char* name, unsigned* length) {
|
||||||
struct stat s;
|
// Ugly Hack Alert: It seems that the Apple iOS Simulator's stat
|
||||||
int r = ::stat(name, &s);
|
// implementation writes beyond the end of the struct stat we pass
|
||||||
|
// it, which can clobber unrelated parts of the stack. Perhaps
|
||||||
|
// this is due to some kind of header/library mismatch, but I've
|
||||||
|
// been unable to track it down so far. The workaround is to give
|
||||||
|
// it 8 words more than it should need, where 8 is a number I just
|
||||||
|
// made up and seems to work.
|
||||||
|
void* array[ceiling(sizeof(struct stat), sizeof(void*)) + 8];
|
||||||
|
struct stat* s = reinterpret_cast<struct stat*>(array);
|
||||||
|
|
||||||
|
int r = ::stat(name, s);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
if (S_ISREG(s.st_mode)) {
|
if (S_ISREG(s->st_mode)) {
|
||||||
*length = s.st_size;
|
*length = s->st_size;
|
||||||
return TypeFile;
|
return TypeFile;
|
||||||
} else if (S_ISDIR(s.st_mode)) {
|
} else if (S_ISDIR(s->st_mode)) {
|
||||||
*length = 0;
|
*length = 0;
|
||||||
return TypeDirectory;
|
return TypeDirectory;
|
||||||
} else {
|
} else {
|
||||||
@ -990,7 +999,7 @@ handleSignal(int signal, siginfo_t*, void* context)
|
|||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
System*
|
JNIEXPORT System*
|
||||||
makeSystem(const char*)
|
makeSystem(const char*)
|
||||||
{
|
{
|
||||||
return new (malloc(sizeof(MySystem))) MySystem();
|
return new (malloc(sizeof(MySystem))) MySystem();
|
||||||
|
@ -2733,11 +2733,12 @@ class MyAssembler: public Assembler {
|
|||||||
|
|
||||||
assert(&c, jumpTableSize);
|
assert(&c, jumpTableSize);
|
||||||
|
|
||||||
if (needJump(b)) {
|
bool jump = needJump(b);
|
||||||
|
if (jump) {
|
||||||
write4(dst + dstOffset, ::b(jumpTableSize + TargetBytesPerWord));
|
write4(dst + dstOffset, ::b(jumpTableSize + TargetBytesPerWord));
|
||||||
}
|
}
|
||||||
|
|
||||||
dstOffset += jumpTableSize + TargetBytesPerWord;
|
dstOffset += jumpTableSize + (jump ? TargetBytesPerWord : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned size = b->size - blockOffset;
|
unsigned size = b->size - blockOffset;
|
||||||
@ -2749,7 +2750,7 @@ class MyAssembler: public Assembler {
|
|||||||
dstOffset += size;
|
dstOffset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned index = c.code.length();
|
unsigned index = dstOffset;
|
||||||
assert(&c, index % TargetBytesPerWord == 0);
|
assert(&c, index % TargetBytesPerWord == 0);
|
||||||
for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) {
|
for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) {
|
||||||
e->address = dst + index;
|
e->address = dst + index;
|
||||||
|
@ -147,7 +147,7 @@ const unsigned TargetFieldOffset = 8;
|
|||||||
|
|
||||||
const unsigned TargetBitsPerWord = TargetBytesPerWord * 8;
|
const unsigned TargetBitsPerWord = TargetBytesPerWord * 8;
|
||||||
|
|
||||||
const uintptr_t TargetPointerMask
|
const target_uintptr_t TargetPointerMask
|
||||||
= ((~static_cast<target_uintptr_t>(0)) / TargetBytesPerWord)
|
= ((~static_cast<target_uintptr_t>(0)) / TargetBytesPerWord)
|
||||||
* TargetBytesPerWord;
|
* TargetBytesPerWord;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ class MySystem: public System {
|
|||||||
CloseHandle(event);
|
CloseHandle(event);
|
||||||
CloseHandle(mutex);
|
CloseHandle(mutex);
|
||||||
CloseHandle(thread);
|
CloseHandle(thread);
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
@ -150,7 +150,7 @@ class MySystem: public System {
|
|||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
CloseHandle(mutex);
|
CloseHandle(mutex);
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -377,7 +377,7 @@ class MySystem: public System {
|
|||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
assert(s, owner_ == 0);
|
assert(s, owner_ == 0);
|
||||||
CloseHandle(mutex);
|
CloseHandle(mutex);
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -408,7 +408,7 @@ class MySystem: public System {
|
|||||||
bool r UNUSED = TlsFree(key);
|
bool r UNUSED = TlsFree(key);
|
||||||
assert(s, r);
|
assert(s, r);
|
||||||
|
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -472,7 +472,7 @@ class MySystem: public System {
|
|||||||
if (handle and handle != INVALID_HANDLE_VALUE) {
|
if (handle and handle != INVALID_HANDLE_VALUE) {
|
||||||
FindClose(handle);
|
FindClose(handle);
|
||||||
}
|
}
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -523,10 +523,10 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name_) {
|
if (name_) {
|
||||||
s->free(name_);
|
::free(const_cast<char*>(name_));
|
||||||
}
|
}
|
||||||
|
|
||||||
s->free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -986,7 +986,7 @@ handleException(LPEXCEPTION_POINTERS e)
|
|||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
System*
|
JNIEXPORT System*
|
||||||
makeSystem(const char* crashDumpDirectory)
|
makeSystem(const char* crashDumpDirectory)
|
||||||
{
|
{
|
||||||
return new (malloc(sizeof(MySystem))) MySystem(crashDumpDirectory);
|
return new (malloc(sizeof(MySystem))) MySystem(crashDumpDirectory);
|
||||||
|
@ -255,6 +255,8 @@ atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define AVIAN_HAS_CAS64
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
atomicCompareAndSwap64(uint64_t* p, uint64_t old, uint64_t new_)
|
atomicCompareAndSwap64(uint64_t* p, uint64_t old, uint64_t new_)
|
||||||
{
|
{
|
||||||
|
29
test/Files.java
Normal file
29
test/Files.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class Files {
|
||||||
|
private static void expect(boolean v) {
|
||||||
|
if (! v) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void isAbsoluteTest(boolean absolutePath) {
|
||||||
|
File file = new File("test.txt");
|
||||||
|
if (absolutePath) {
|
||||||
|
file = file.getAbsoluteFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isAbsolute = file.isAbsolute();
|
||||||
|
|
||||||
|
if (absolutePath) {
|
||||||
|
expect(isAbsolute);
|
||||||
|
} else {
|
||||||
|
expect(!isAbsolute);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
isAbsoluteTest(true);
|
||||||
|
isAbsoluteTest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -229,5 +229,36 @@ public class Floats {
|
|||||||
double d = (double) z;
|
double d = (double) z;
|
||||||
expect(d == 12345.0);
|
expect(d == 12345.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test floatToIntBits
|
||||||
|
{
|
||||||
|
int orig = 0x7f800001;
|
||||||
|
float NaN = Float.intBitsToFloat(orig);
|
||||||
|
int result = Float.floatToIntBits(NaN);
|
||||||
|
int expected = 0x7fc00000;
|
||||||
|
expect(result == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int orig = 0x7f801001;
|
||||||
|
float NaN = Float.intBitsToFloat(orig);
|
||||||
|
int result = Float.floatToIntBits(NaN);
|
||||||
|
int expected = 0x7fc00000;
|
||||||
|
expect(result == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int orig = 0x00800001;
|
||||||
|
float number = Float.intBitsToFloat(orig);
|
||||||
|
int result = Float.floatToIntBits(number);
|
||||||
|
expect(result == orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int orig = 0x80800003;
|
||||||
|
float number = Float.intBitsToFloat(orig);
|
||||||
|
int result = Float.floatToIntBits(number);
|
||||||
|
expect(result == orig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
test/Processes.java
Normal file
31
test/Processes.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class Processes {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
final Process p = Runtime.getRuntime().exec("sleep 10");
|
||||||
|
new Thread() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
p.destroy();
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
try {
|
||||||
|
p.waitFor();
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
long stop = System.currentTimeMillis();
|
||||||
|
if(stop - start > 5000) {
|
||||||
|
throw new RuntimeException("test failed; we didn't kill the process...");
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
test/UrlTest.java
Normal file
42
test/UrlTest.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class UrlTest {
|
||||||
|
private static String query="var1=val1&var2=val2";
|
||||||
|
private static String path="testpath";
|
||||||
|
private static String domain="file://www.readytalk.com";
|
||||||
|
private static String file=path + "?" + query;
|
||||||
|
private static URL url;
|
||||||
|
|
||||||
|
private static void expect(boolean v) {
|
||||||
|
if (! v) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setupURL() throws MalformedURLException {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append(domain);
|
||||||
|
builder.append("/");
|
||||||
|
builder.append(file);
|
||||||
|
url = new URL(builder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testGetPath() {
|
||||||
|
expect(url.getPath().equals(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testGetFile() {
|
||||||
|
expect(url.getFile().equals(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testGetQuery() {
|
||||||
|
expect(url.getQuery().equals(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws MalformedURLException {
|
||||||
|
setupURL();
|
||||||
|
testGetPath();
|
||||||
|
testGetFile();
|
||||||
|
testGetQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user