mirror of
https://github.com/corda/corda.git
synced 2025-01-09 14:33:30 +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
|
||||
# include "unistd.h"
|
||||
# include "limits.h"
|
||||
# include "signal.h"
|
||||
# include "sys/time.h"
|
||||
# include "sys/types.h"
|
||||
# include "sys/sysctl.h"
|
||||
# include "sys/utsname.h"
|
||||
# include "sys/wait.h"
|
||||
@ -281,6 +283,11 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid, jlong tid)
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_lang_Runtime_kill(JNIEnv*, jclass, jlong pid) {
|
||||
TerminateProcess(reinterpret_cast<HANDLE>(pid), 1);
|
||||
}
|
||||
|
||||
Locale getLocale() {
|
||||
const char* lang = "";
|
||||
const char* reg = "";
|
||||
@ -468,6 +475,11 @@ Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid, jlong)
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_lang_Runtime_kill(JNIEnv*, jclass, jlong pid) {
|
||||
kill((pid_t)pid, SIGTERM);
|
||||
}
|
||||
|
||||
Locale getLocale() {
|
||||
Locale fallback;
|
||||
|
||||
|
@ -46,8 +46,7 @@ public class BufferedReader extends Reader {
|
||||
sb.append(buffer, position, i - position);
|
||||
position = i + 1;
|
||||
if(i+1 < limit && buffer[i+1] == '\n') {
|
||||
position = i + 1;
|
||||
return sb.toString();
|
||||
position = i + 2;
|
||||
}
|
||||
return sb.toString();
|
||||
} else if (buffer[i] == '\n') {
|
||||
|
@ -61,6 +61,10 @@ public class File implements Serializable {
|
||||
return isFile(path);
|
||||
}
|
||||
|
||||
public boolean isAbsolute() {
|
||||
return path.equals(toAbsolutePath(path));
|
||||
}
|
||||
|
||||
private static native boolean canRead(String path);
|
||||
|
||||
public boolean canRead() {
|
||||
|
@ -56,7 +56,7 @@ public abstract class InputStream {
|
||||
}
|
||||
|
||||
public void reset() throws IOException {
|
||||
// ignore
|
||||
throw new IOException("mark/reset not supported");
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
|
@ -12,16 +12,21 @@ package java.io;
|
||||
|
||||
public class RandomAccessFile {
|
||||
private long peer;
|
||||
private long length;
|
||||
private File file;
|
||||
private long position = 0;
|
||||
|
||||
private long length;
|
||||
|
||||
public RandomAccessFile(String name, String mode)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
if (! mode.equals("r")) throw new IllegalArgumentException();
|
||||
file = new File(name);
|
||||
open();
|
||||
}
|
||||
|
||||
private void open() throws FileNotFoundException {
|
||||
long[] result = new long[2];
|
||||
open(name, result);
|
||||
open(file.getPath(), result);
|
||||
peer = result[0];
|
||||
length = result[1];
|
||||
}
|
||||
@ -29,7 +34,15 @@ public class RandomAccessFile {
|
||||
private static native void open(String name, long[] result)
|
||||
throws FileNotFoundException;
|
||||
|
||||
private void refresh() throws IOException {
|
||||
if (file.length() != length) {
|
||||
close();
|
||||
open();
|
||||
}
|
||||
}
|
||||
|
||||
public long length() throws IOException {
|
||||
refresh();
|
||||
return length;
|
||||
}
|
||||
|
||||
@ -38,7 +51,7 @@ public class RandomAccessFile {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -50,12 +63,16 @@ public class RandomAccessFile {
|
||||
|
||||
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)
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
|
||||
copy(peer, position, buffer, offset, length);
|
||||
|
||||
position += length;
|
||||
}
|
||||
|
||||
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> {
|
||||
private final String name;
|
||||
private final int ordinal;
|
||||
protected final int ordinal;
|
||||
|
||||
public Enum(String name, int ordinal) {
|
||||
this.name = name;
|
||||
|
@ -12,8 +12,10 @@ package java.lang;
|
||||
|
||||
public final class Float extends Number {
|
||||
public static final Class TYPE = Class.forCanonicalName("F");
|
||||
|
||||
private final float value;
|
||||
private static final int EXP_BIT_MASK = 0x7F800000;
|
||||
private static final int SIGNIF_BIT_MASK = 0x007FFFFF;
|
||||
|
||||
private final float value;
|
||||
|
||||
public Float(String value) {
|
||||
this.value = parseFloat(value);
|
||||
@ -88,6 +90,17 @@ public final class Float extends Number {
|
||||
throw new NumberFormatException(s);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -122,6 +122,8 @@ public class Runtime {
|
||||
|
||||
private static native void load(String name, boolean mapName);
|
||||
|
||||
private static native void kill(long pid);
|
||||
|
||||
public native void gc();
|
||||
|
||||
public native void exit(int code);
|
||||
@ -147,7 +149,9 @@ public class Runtime {
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
throw new RuntimeException("not implemented");
|
||||
if (pid != 0) {
|
||||
kill(pid);
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
|
@ -19,6 +19,8 @@ public final class URL {
|
||||
private String host;
|
||||
private int port;
|
||||
private String file;
|
||||
private String path;
|
||||
private String query;
|
||||
private String ref;
|
||||
|
||||
public URL(String s) throws MalformedURLException {
|
||||
@ -55,6 +57,14 @@ public final class URL {
|
||||
public String getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
public URLConnection openConnection() throws IOException {
|
||||
return handler.openConnection(this);
|
||||
@ -90,5 +100,13 @@ public final class URL {
|
||||
this.port = port;
|
||||
this.file = file;
|
||||
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 limit;
|
||||
|
||||
public int limit() {
|
||||
public final int limit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public int remaining() {
|
||||
public final int remaining() {
|
||||
return limit-position;
|
||||
}
|
||||
|
||||
public int position() {
|
||||
public final int position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public int capacity() {
|
||||
public final int capacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
public Buffer limit(int newLimit) {
|
||||
public final Buffer limit(int newLimit) {
|
||||
limit = newLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Buffer position(int newPosition) {
|
||||
public final Buffer position(int newPosition) {
|
||||
position = newPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasRemaining() {
|
||||
public final boolean hasRemaining() {
|
||||
return remaining() > 0;
|
||||
}
|
||||
|
||||
public Buffer clear() {
|
||||
public final Buffer clear() {
|
||||
position = 0;
|
||||
limit = capacity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Buffer flip() {
|
||||
public final Buffer flip() {
|
||||
limit = position;
|
||||
position = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final Buffer rewind() {
|
||||
position = 0;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,13 @@ public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
|
||||
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) {
|
||||
int end = (remaining() < o.remaining() ? remaining() : o.remaining());
|
||||
|
||||
@ -159,6 +166,13 @@ public class ByteBuffer extends Buffer implements Comparable<ByteBuffer> {
|
||||
| ((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() {
|
||||
checkGet(4);
|
||||
int i = get() << 24;
|
||||
|
@ -72,4 +72,7 @@ public abstract class AbstractCollection<T> implements Collection<T> {
|
||||
|
||||
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
|
||||
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() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,18 @@ public class TreeSet<T> extends AbstractSet<T> implements Collection<T> {
|
||||
add(item);
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
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
|
||||
|
||||
test-executable = $(executable)
|
||||
test-executable = $(shell pwd)/$(executable)
|
||||
boot-classpath = $(classpath-build)
|
||||
embed-prefix = /avian-embedded
|
||||
|
||||
@ -110,7 +110,7 @@ ifneq ($(openjdk),)
|
||||
boot-javahome-object = $(build)/boot-javahome.o
|
||||
else
|
||||
options := $(options)-openjdk
|
||||
test-executable = $(executable-dynamic)
|
||||
test-executable = $(shell pwd)/$(executable-dynamic)
|
||||
library-path = \
|
||||
$(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch)
|
||||
javahome = "$$($(native-path) "$(openjdk)/jre")"
|
||||
@ -246,7 +246,8 @@ ifeq ($(arch),arm)
|
||||
ifeq ($(build-platform),darwin)
|
||||
ios = true
|
||||
else
|
||||
cflags += -marm -Wno-psabi
|
||||
no-psabi = -Wno-psabi
|
||||
cflags += -marm $(no-psabi)
|
||||
endif
|
||||
|
||||
ifneq ($(arch),$(build-arch))
|
||||
@ -319,7 +320,7 @@ ifeq ($(platform),darwin)
|
||||
converter-cflags += -DOPPOSITE_ENDIAN
|
||||
endif
|
||||
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)
|
||||
cflags += $(flags)
|
||||
asmflags += $(flags)
|
||||
@ -372,7 +373,8 @@ ifeq ($(platform),windows)
|
||||
exe-suffix = .exe
|
||||
|
||||
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)))
|
||||
openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive
|
||||
@ -446,6 +448,7 @@ ifeq ($(use-lto),true)
|
||||
ifeq ($(shell expr 4 \< $(gcc-major) \
|
||||
\| \( 4 \<= $(gcc-major) \& 6 \<= $(gcc-minor) \)),1)
|
||||
optimization-cflags += -flto
|
||||
no-lto = -fno-lto
|
||||
lflags += $(optimization-cflags)
|
||||
endif
|
||||
endif
|
||||
@ -584,12 +587,12 @@ endif
|
||||
cflags += $(extra-cflags)
|
||||
lflags += $(extra-lflags)
|
||||
|
||||
openjdk-cflags += $(extra-cflags)
|
||||
|
||||
driver-source = $(src)/main.cpp
|
||||
driver-object = $(build)/main.o
|
||||
driver-dynamic-objects = \
|
||||
$(build)/main-dynamic.o \
|
||||
$(build)/$(system).o \
|
||||
$(build)/finder.o
|
||||
$(build)/main-dynamic.o
|
||||
|
||||
boot-source = $(src)/boot.cpp
|
||||
boot-object = $(build)/boot.o
|
||||
@ -957,6 +960,8 @@ else
|
||||
endif
|
||||
$(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)
|
||||
@echo "linking $(@)"
|
||||
ifdef msvc
|
||||
@ -965,7 +970,7 @@ ifdef msvc
|
||||
-MANIFESTFILE:$(@).manifest
|
||||
$(mt) -manifest $(@).manifest -outputresource:"$(@);1"
|
||||
else
|
||||
$(ld) $(driver-dynamic-objects) -L$(build) -ljvm $(lflags) -o $(@)
|
||||
$(ld) $(driver-dynamic-objects) -L$(build) -ljvm $(lflags) $(no-lto) -o $(@)
|
||||
endif
|
||||
$(strip) $(strip-all) $(@)
|
||||
|
||||
|
@ -2626,12 +2626,13 @@ class MyAssembler: public Assembler {
|
||||
poolSize += TargetBytesPerWord;
|
||||
}
|
||||
|
||||
if (needJump(b)) {
|
||||
bool jump = needJump(b);
|
||||
if (jump) {
|
||||
write4
|
||||
(dst + dstOffset, ::b((poolSize + TargetBytesPerWord - 8) >> 2));
|
||||
}
|
||||
|
||||
dstOffset += poolSize + TargetBytesPerWord;
|
||||
dstOffset += poolSize + (jump ? TargetBytesPerWord : 0);
|
||||
}
|
||||
|
||||
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]) {
|
||||
case DOUBLE_TYPE:
|
||||
case INT64_TYPE: {
|
||||
if (gprIndex + Alignment <= GprCount) { // pass argument on registers
|
||||
if (gprIndex % Alignment) { // 8-byte alignment
|
||||
memset(gprTable + gprIndex, 0, 4); // probably not necessary, but for good luck
|
||||
++gprIndex;
|
||||
if (gprIndex + Alignment <= GprCount) { // pass argument in register(s)
|
||||
if (Alignment == 1
|
||||
and BytesPerWord < 8
|
||||
and gprIndex + Alignment == GprCount)
|
||||
{
|
||||
gprTable[gprIndex++] = arguments[ai];
|
||||
stack[stackIndex++] = arguments[ai + 1];
|
||||
} else {
|
||||
if (gprIndex % Alignment) {
|
||||
++gprIndex;
|
||||
}
|
||||
|
||||
memcpy(gprTable + gprIndex, arguments + ai, 8);
|
||||
gprIndex += 8 / BytesPerWord;
|
||||
}
|
||||
|
||||
memcpy(gprTable + gprIndex, arguments + ai, 8);
|
||||
gprIndex += 8 / BytesPerWord;
|
||||
} else { // pass argument on stack
|
||||
gprIndex = GprCount;
|
||||
if (stackIndex % Alignment) { // 8-byte alignment
|
||||
memset(stack + stackIndex, 0, 4); // probably not necessary, but for good luck
|
||||
if (stackIndex % Alignment) {
|
||||
++stackIndex;
|
||||
}
|
||||
|
||||
|
@ -211,10 +211,12 @@ allFields(Thread* t, object typeMaps, object c, unsigned* count, object* array)
|
||||
includeMembers = false;
|
||||
*count += reinterpret_cast<TypeMap*>(&byteArrayBody(t, *array, 0))
|
||||
->fixedFieldCount;
|
||||
} else if (classSuper(t, c)) {
|
||||
} else {
|
||||
includeMembers = true;
|
||||
fields = getNonStaticFields
|
||||
(t, typeMaps, classSuper(t, c), fields, count, array);
|
||||
if (classSuper(t, c)) {
|
||||
fields = getNonStaticFields
|
||||
(t, typeMaps, classSuper(t, c), fields, count, array);
|
||||
}
|
||||
}
|
||||
|
||||
if (classFieldTable(t, c)) {
|
||||
@ -1314,9 +1316,9 @@ writeBootImage2(Thread* t, FILE* bootimageOutput, FILE* codeOutput,
|
||||
unsigned buildOffset = BytesPerWord;
|
||||
unsigned targetOffset = TargetBytesPerWord;
|
||||
bool sawArray = false;
|
||||
Type type;
|
||||
unsigned buildSize;
|
||||
unsigned targetSize;
|
||||
Type type = Type_none;
|
||||
unsigned buildSize = 0;
|
||||
unsigned targetSize = 0;
|
||||
for (unsigned j = 1; j < count; ++j) {
|
||||
switch (source[j - 1]) {
|
||||
case Type_object:
|
||||
|
@ -605,6 +605,33 @@ Avian_java_lang_Thread_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
|
||||
Avian_avian_Classes_primitiveClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
|
@ -2594,15 +2594,25 @@ Avian_sun_misc_Unsafe_compareAndSwapObject
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_sun_misc_Unsafe_compareAndSwapLong
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
(Thread* t UNUSED, object, uintptr_t* arguments)
|
||||
{
|
||||
object target = reinterpret_cast<object>(arguments[1]);
|
||||
int64_t offset; memcpy(&offset, arguments + 2, 8);
|
||||
uint64_t expect; memcpy(&expect, arguments + 4, 8);
|
||||
uint64_t update; memcpy(&update, arguments + 6, 8);
|
||||
|
||||
#ifdef AVIAN_HAS_CAS64
|
||||
return atomicCompareAndSwap64
|
||||
(&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
|
||||
@ -2747,17 +2757,27 @@ Avian_sun_misc_Unsafe_park
|
||||
bool absolute = arguments[1];
|
||||
int64_t time; memcpy(&time, arguments + 2, 8);
|
||||
|
||||
int64_t then = t->m->system->now();
|
||||
|
||||
if (absolute) {
|
||||
time -= t->m->system->now();
|
||||
time -= then;
|
||||
if (time <= 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
time /= 1000 * 1000;
|
||||
}
|
||||
|
||||
monitorAcquire(t, local::interruptLock(t, t->javaThread));
|
||||
while (not (threadUnparked(t, t->javaThread)
|
||||
or monitorWait(t, local::interruptLock(t, t->javaThread), time)))
|
||||
{ }
|
||||
while (time > 0
|
||||
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;
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -2274,7 +2274,7 @@ uintptr_t
|
||||
methodAddress(Thread* t, object method)
|
||||
{
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
return nativeThunk(static_cast<MyThread*>(t));
|
||||
return bootNativeThunk(static_cast<MyThread*>(t));
|
||||
} else {
|
||||
return methodCompiled(t, method);
|
||||
}
|
||||
@ -8249,7 +8249,7 @@ class SignalHandler: public System::SignalHandler {
|
||||
t->exception = vm::root(t, root);
|
||||
}
|
||||
|
||||
//printTrace(t, t->exception);
|
||||
// printTrace(t, t->exception);
|
||||
|
||||
object continuation;
|
||||
findUnwindTarget(t, ip, frame, stack, &continuation);
|
||||
@ -8395,6 +8395,12 @@ class MyProcessor: public Processor {
|
||||
difference(&(t->virtualCallTarget), t));
|
||||
fprintf(stderr, "virtualCallIndex %d\n",
|
||||
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);
|
||||
}
|
||||
|
||||
@ -8820,6 +8826,10 @@ class MyProcessor: public Processor {
|
||||
|
||||
local::compileThunks(static_cast<MyThread*>(t), &codeAllocator);
|
||||
|
||||
if (not (image and code)) {
|
||||
bootThunks = thunks;
|
||||
}
|
||||
|
||||
segFaultHandler.m = t->m;
|
||||
expect(t, t->m->system->success
|
||||
(t->m->system->handleSegFault(&segFaultHandler)));
|
||||
@ -8909,20 +8919,22 @@ compileMethod2(MyThread* t, void* ip)
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
if (callNodeFlags(t, node) & TraceElement::LongCall) {
|
||||
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
|
||||
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",
|
||||
// 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);
|
||||
|
||||
@ -9372,11 +9434,30 @@ boot(MyThread* t, BootImage* image, uint8_t* code)
|
||||
|
||||
findThunks(t, image, code);
|
||||
|
||||
fixupVirtualThunks(t, code);
|
||||
if (fixed) {
|
||||
resetRuntimeState
|
||||
(t, classLoaderMap(t, root(t, Machine::BootLoader)), heap,
|
||||
image->heapSize);
|
||||
|
||||
fixupMethods
|
||||
(t, classLoaderMap(t, root(t, Machine::BootLoader)), image, code);
|
||||
fixupMethods(t, classLoaderMap(t, root(t, Machine::AppLoader)), image, code);
|
||||
resetRuntimeState
|
||||
(t, classLoaderMap(t, root(t, Machine::AppLoader)), heap,
|
||||
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));
|
||||
}
|
||||
|
@ -920,7 +920,7 @@ class MyFinder: public Finder {
|
||||
|
||||
namespace vm {
|
||||
|
||||
Finder*
|
||||
JNIEXPORT Finder*
|
||||
makeFinder(System* s, Allocator* a, const char* path, const char* 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:
|
||||
|
||||
uint8_t age;
|
||||
bool hasMask;
|
||||
bool marked;
|
||||
bool dirty;
|
||||
uint8_t hasMask;
|
||||
uint8_t marked;
|
||||
uint8_t dirty;
|
||||
uint32_t size;
|
||||
Fixie* next;
|
||||
Fixie** handle;
|
||||
@ -560,7 +560,7 @@ fixie(void* body)
|
||||
}
|
||||
|
||||
void
|
||||
free(Context* c, Fixie** fixies);
|
||||
free(Context* c, Fixie** fixies, bool resetImmortal = false);
|
||||
|
||||
class Context {
|
||||
public:
|
||||
@ -630,9 +630,9 @@ class Context {
|
||||
}
|
||||
|
||||
void disposeFixies() {
|
||||
free(this, &tenuredFixies);
|
||||
free(this, &dirtyTenuredFixies);
|
||||
free(this, &fixies);
|
||||
free(this, &tenuredFixies, true);
|
||||
free(this, &dirtyTenuredFixies, true);
|
||||
free(this, &fixies, true);
|
||||
}
|
||||
|
||||
System* system;
|
||||
@ -846,13 +846,25 @@ bitset(Context* c UNUSED, void* o)
|
||||
}
|
||||
|
||||
void
|
||||
free(Context* c, Fixie** fixies)
|
||||
free(Context* c, Fixie** fixies, bool resetImmortal)
|
||||
{
|
||||
for (Fixie** p = fixies; *p;) {
|
||||
Fixie* f = *p;
|
||||
|
||||
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 {
|
||||
*p = f->next;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -3024,6 +3024,8 @@ boot(Thread* t, uintptr_t*)
|
||||
setRoot(t, Machine::OutOfMemoryError,
|
||||
makeThrowable(t, Machine::OutOfMemoryErrorType));
|
||||
|
||||
setRoot(t, Machine::Shutdown, makeThrowable(t, Machine::ThrowableType));
|
||||
|
||||
setRoot(t, Machine::FinalizerThread, t->m->classpath->makeThread(t, t));
|
||||
|
||||
threadDaemon(t, root(t, Machine::FinalizerThread)) = true;
|
||||
|
@ -45,6 +45,15 @@ void
|
||||
join(Thread* t, Thread* 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)) {
|
||||
o->systemThread->join();
|
||||
releaseSystem(t, o);
|
||||
@ -138,35 +147,37 @@ dispose(Thread* t, Thread* o, bool remove)
|
||||
}
|
||||
|
||||
void
|
||||
joinAll(Thread* m, Thread* o)
|
||||
visitAll(Thread* m, Thread* o, void (*visit)(Thread*, Thread*))
|
||||
{
|
||||
for (Thread* p = o->child; p;) {
|
||||
Thread* child = p;
|
||||
p = p->peer;
|
||||
joinAll(m, child);
|
||||
visitAll(m, child, visit);
|
||||
}
|
||||
|
||||
join(m, o);
|
||||
visit(m, o);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
interruptDaemon(Thread* m, Thread* o)
|
||||
{
|
||||
if (o->flags & Thread::DaemonFlag) {
|
||||
interrupt(m, o);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
turnOffTheLights(Thread* t)
|
||||
{
|
||||
expect(t, t->m->liveCount == 1);
|
||||
|
||||
joinAll(t, t->m->rootThread);
|
||||
visitAll(t, t->m->rootThread, join);
|
||||
|
||||
enter(t, Thread::ExitState);
|
||||
|
||||
@ -215,7 +226,7 @@ turnOffTheLights(Thread* t)
|
||||
|
||||
Machine* m = t->m;
|
||||
|
||||
disposeAll(t, t->m->rootThread);
|
||||
visitAll(t, t->m->rootThread, disposeNoRemove);
|
||||
|
||||
System* s = m->system;
|
||||
Heap* h = m->heap;
|
||||
@ -1662,13 +1673,17 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
set(t, addendum, ClassAddendumMethodTable,
|
||||
classMethodTable(t, class_));
|
||||
|
||||
unsigned oldLength = arrayLength(t, classMethodTable(t, class_));
|
||||
unsigned oldLength = classMethodTable(t, class_) ?
|
||||
arrayLength(t, classMethodTable(t, class_)) : 0;
|
||||
|
||||
object newMethodTable = makeArray
|
||||
(t, oldLength + listSize(t, abstractVirtuals));
|
||||
|
||||
memcpy(&arrayBody(t, newMethodTable, 0),
|
||||
&arrayBody(t, classMethodTable(t, class_), 0),
|
||||
oldLength * sizeof(object));
|
||||
if (oldLength) {
|
||||
memcpy(&arrayBody(t, newMethodTable, 0),
|
||||
&arrayBody(t, classMethodTable(t, class_), 0),
|
||||
oldLength * sizeof(object));
|
||||
}
|
||||
|
||||
mark(t, newMethodTable, ArrayBody, oldLength);
|
||||
|
||||
@ -2443,6 +2458,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder,
|
||||
collecting(false),
|
||||
triedBuiltinOnLoad(false),
|
||||
dumpedHeapOnOOM(false),
|
||||
alive(true),
|
||||
heapPoolIndex(0)
|
||||
{
|
||||
heap->setClient(heapClient);
|
||||
@ -2566,7 +2582,7 @@ Thread::init()
|
||||
|
||||
enter(this, ActiveState);
|
||||
|
||||
if (image and image) {
|
||||
if (image and code) {
|
||||
m->processor->boot(this, image, code);
|
||||
} else {
|
||||
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
|
||||
@ -3247,9 +3274,7 @@ classInitializer(Thread* t, object class_)
|
||||
{
|
||||
object o = arrayBody(t, classMethodTable(t, class_), i);
|
||||
|
||||
if (vm::strcmp(reinterpret_cast<const int8_t*>("<clinit>"),
|
||||
&byteArrayBody(t, methodName(t, o), 0)) == 0)
|
||||
{
|
||||
if (methodVmFlags(t, o) & ClassInitFlag) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
@ -3798,6 +3823,9 @@ initClass(Thread* t, object c)
|
||||
object
|
||||
resolveObjectArrayClass(Thread* t, object loader, object elementClass)
|
||||
{
|
||||
PROTECT(t, loader);
|
||||
PROTECT(t, elementClass);
|
||||
|
||||
{ object arrayClass = classRuntimeDataArrayClass
|
||||
(t, getClassRuntimeData(t, elementClass));
|
||||
if (arrayClass) {
|
||||
@ -3805,9 +3833,6 @@ resolveObjectArrayClass(Thread* t, object loader, object elementClass)
|
||||
}
|
||||
}
|
||||
|
||||
PROTECT(t, loader);
|
||||
PROTECT(t, elementClass);
|
||||
|
||||
object elementSpec = className(t, elementClass);
|
||||
PROTECT(t, elementSpec);
|
||||
|
||||
|
@ -157,8 +157,7 @@ const unsigned ContinuationFlag = 1 << 11;
|
||||
|
||||
// method vmFlags:
|
||||
const unsigned ClassInitFlag = 1 << 0;
|
||||
const unsigned CompiledFlag = 1 << 1;
|
||||
const unsigned ConstructorFlag = 1 << 2;
|
||||
const unsigned ConstructorFlag = 1 << 1;
|
||||
|
||||
#ifndef JNI_VERSION_1_6
|
||||
#define JNI_VERSION_1_6 0x00010006
|
||||
@ -1266,6 +1265,7 @@ class Machine {
|
||||
ArithmeticException,
|
||||
ArrayIndexOutOfBoundsException,
|
||||
OutOfMemoryError,
|
||||
Shutdown,
|
||||
VirtualFileFinders,
|
||||
VirtualFiles
|
||||
};
|
||||
@ -1322,6 +1322,7 @@ class Machine {
|
||||
bool collecting;
|
||||
bool triedBuiltinOnLoad;
|
||||
bool dumpedHeapOnOOM;
|
||||
bool alive;
|
||||
JavaVMVTable javaVMVTable;
|
||||
JNIEnvVTable jniEnvVTable;
|
||||
uintptr_t* heapPool[ThreadHeapPoolSize];
|
||||
@ -1357,6 +1358,9 @@ run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*),
|
||||
void
|
||||
checkDaemon(Thread* t);
|
||||
|
||||
object&
|
||||
root(Thread* t, Machine::Root root);
|
||||
|
||||
extern "C" uint64_t
|
||||
vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments,
|
||||
void* checkpoint);
|
||||
@ -1507,7 +1511,7 @@ class Thread {
|
||||
|
||||
vm::run(t, runThread, 0);
|
||||
|
||||
if (t->exception) {
|
||||
if (t->exception and t->exception != root(t, Machine::Shutdown)) {
|
||||
printTrace(t, t->exception);
|
||||
}
|
||||
|
||||
@ -3182,7 +3186,11 @@ wait(Thread* t, object o, int64_t milliseconds)
|
||||
bool interrupted = monitorWait(t, m, milliseconds);
|
||||
|
||||
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 {
|
||||
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
|
||||
intern(Thread* t, object s);
|
||||
|
||||
|
@ -169,7 +169,7 @@ class MySystem: public System {
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
pthread_t thread;
|
||||
@ -197,7 +197,7 @@ class MySystem: public System {
|
||||
|
||||
virtual void dispose() {
|
||||
pthread_mutex_destroy(&mutex);
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -410,7 +410,7 @@ class MySystem: public System {
|
||||
virtual void dispose() {
|
||||
expect(s, owner_ == 0);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -441,7 +441,7 @@ class MySystem: public System {
|
||||
int r UNUSED = pthread_key_delete(key);
|
||||
expect(s, r == 0);
|
||||
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -468,7 +468,7 @@ class MySystem: public System {
|
||||
if (start_) {
|
||||
munmap(start_, length_);
|
||||
}
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -494,7 +494,7 @@ class MySystem: public System {
|
||||
if (directory) {
|
||||
closedir(directory);
|
||||
}
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -541,10 +541,10 @@ class MySystem: public System {
|
||||
}
|
||||
|
||||
if (name_) {
|
||||
s->free(name_);
|
||||
::free(const_cast<char*>(name_));
|
||||
}
|
||||
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -772,13 +772,22 @@ class MySystem: public System {
|
||||
}
|
||||
|
||||
virtual FileType stat(const char* name, unsigned* length) {
|
||||
struct stat s;
|
||||
int r = ::stat(name, &s);
|
||||
// Ugly Hack Alert: It seems that the Apple iOS Simulator's stat
|
||||
// implementation writes beyond the end of the struct stat we pass
|
||||
// it, which can clobber unrelated parts of the stack. Perhaps
|
||||
// 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 (S_ISREG(s.st_mode)) {
|
||||
*length = s.st_size;
|
||||
if (S_ISREG(s->st_mode)) {
|
||||
*length = s->st_size;
|
||||
return TypeFile;
|
||||
} else if (S_ISDIR(s.st_mode)) {
|
||||
} else if (S_ISDIR(s->st_mode)) {
|
||||
*length = 0;
|
||||
return TypeDirectory;
|
||||
} else {
|
||||
@ -990,7 +999,7 @@ handleSignal(int signal, siginfo_t*, void* context)
|
||||
|
||||
namespace vm {
|
||||
|
||||
System*
|
||||
JNIEXPORT System*
|
||||
makeSystem(const char*)
|
||||
{
|
||||
return new (malloc(sizeof(MySystem))) MySystem();
|
||||
|
@ -2733,11 +2733,12 @@ class MyAssembler: public Assembler {
|
||||
|
||||
assert(&c, jumpTableSize);
|
||||
|
||||
if (needJump(b)) {
|
||||
bool jump = needJump(b);
|
||||
if (jump) {
|
||||
write4(dst + dstOffset, ::b(jumpTableSize + TargetBytesPerWord));
|
||||
}
|
||||
|
||||
dstOffset += jumpTableSize + TargetBytesPerWord;
|
||||
dstOffset += jumpTableSize + (jump ? TargetBytesPerWord : 0);
|
||||
}
|
||||
|
||||
unsigned size = b->size - blockOffset;
|
||||
@ -2749,7 +2750,7 @@ class MyAssembler: public Assembler {
|
||||
dstOffset += size;
|
||||
}
|
||||
|
||||
unsigned index = c.code.length();
|
||||
unsigned index = dstOffset;
|
||||
assert(&c, index % TargetBytesPerWord == 0);
|
||||
for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) {
|
||||
e->address = dst + index;
|
||||
|
@ -147,7 +147,7 @@ const unsigned TargetFieldOffset = 8;
|
||||
|
||||
const unsigned TargetBitsPerWord = TargetBytesPerWord * 8;
|
||||
|
||||
const uintptr_t TargetPointerMask
|
||||
const target_uintptr_t TargetPointerMask
|
||||
= ((~static_cast<target_uintptr_t>(0)) / TargetBytesPerWord)
|
||||
* TargetBytesPerWord;
|
||||
|
||||
|
@ -119,7 +119,7 @@ class MySystem: public System {
|
||||
CloseHandle(event);
|
||||
CloseHandle(mutex);
|
||||
CloseHandle(thread);
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
HANDLE thread;
|
||||
@ -150,7 +150,7 @@ class MySystem: public System {
|
||||
|
||||
virtual void dispose() {
|
||||
CloseHandle(mutex);
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -377,7 +377,7 @@ class MySystem: public System {
|
||||
virtual void dispose() {
|
||||
assert(s, owner_ == 0);
|
||||
CloseHandle(mutex);
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -408,7 +408,7 @@ class MySystem: public System {
|
||||
bool r UNUSED = TlsFree(key);
|
||||
assert(s, r);
|
||||
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -472,7 +472,7 @@ class MySystem: public System {
|
||||
if (handle and handle != INVALID_HANDLE_VALUE) {
|
||||
FindClose(handle);
|
||||
}
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -523,10 +523,10 @@ class MySystem: public System {
|
||||
}
|
||||
|
||||
if (name_) {
|
||||
s->free(name_);
|
||||
::free(const_cast<char*>(name_));
|
||||
}
|
||||
|
||||
s->free(this);
|
||||
::free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
@ -986,7 +986,7 @@ handleException(LPEXCEPTION_POINTERS e)
|
||||
|
||||
namespace vm {
|
||||
|
||||
System*
|
||||
JNIEXPORT System*
|
||||
makeSystem(const char* crashDumpDirectory)
|
||||
{
|
||||
return new (malloc(sizeof(MySystem))) MySystem(crashDumpDirectory);
|
||||
|
@ -255,6 +255,8 @@ atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_)
|
||||
#endif
|
||||
}
|
||||
|
||||
#define AVIAN_HAS_CAS64
|
||||
|
||||
inline bool
|
||||
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;
|
||||
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