Merge branch 'master' into armvfp

This commit is contained in:
JET 2012-01-16 11:26:03 -07:00
commit c989ea0529
39 changed files with 742 additions and 135 deletions

View 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_);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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