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

View File

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

View File

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

View File

@ -56,7 +56,7 @@ public abstract class InputStream {
}
public void reset() throws IOException {
// ignore
throw new IOException("mark/reset not supported");
}
public boolean markSupported() {

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@ -72,4 +72,7 @@ public abstract class AbstractCollection<T> implements Collection<T> {
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
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;
}
}

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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