diff --git a/classpath/java/lang/Boolean.java b/classpath/java/lang/Boolean.java new file mode 100644 index 0000000000..cfecde87ad --- /dev/null +++ b/classpath/java/lang/Boolean.java @@ -0,0 +1,13 @@ +package java.lang; + +public final class Boolean { + private final boolean value; + + public Boolean(boolean value) { + this.value = value; + } + + public boolean booleanValue() { + return value; + } +} diff --git a/classpath/java/lang/Byte.java b/classpath/java/lang/Byte.java new file mode 100644 index 0000000000..03250631a1 --- /dev/null +++ b/classpath/java/lang/Byte.java @@ -0,0 +1,13 @@ +package java.lang; + +public final class Byte { + private final byte value; + + public Byte(byte value) { + this.value = value; + } + + public byte byteValue() { + return value; + } +} diff --git a/classpath/java/lang/Character.java b/classpath/java/lang/Character.java new file mode 100644 index 0000000000..3a14f10e21 --- /dev/null +++ b/classpath/java/lang/Character.java @@ -0,0 +1,13 @@ +package java.lang; + +public final class Character { + private final char value; + + public Character(char value) { + this.value = value; + } + + public char charValue() { + return value; + } +} diff --git a/classpath/java/lang/Double.java b/classpath/java/lang/Double.java new file mode 100644 index 0000000000..8765d9541e --- /dev/null +++ b/classpath/java/lang/Double.java @@ -0,0 +1,13 @@ +package java.lang; + +public final class Double { + private final double value; + + public Double(double value) { + this.value = value; + } + + public double doubleValue() { + return value; + } +} diff --git a/classpath/java/lang/Float.java b/classpath/java/lang/Float.java new file mode 100644 index 0000000000..3e8d6b5eef --- /dev/null +++ b/classpath/java/lang/Float.java @@ -0,0 +1,13 @@ +package java.lang; + +public final class Float { + private final float value; + + public Float(float value) { + this.value = value; + } + + public float floatValue() { + return value; + } +} diff --git a/classpath/java/lang/Integer.java b/classpath/java/lang/Integer.java new file mode 100644 index 0000000000..68eb18b006 --- /dev/null +++ b/classpath/java/lang/Integer.java @@ -0,0 +1,13 @@ +package java.lang; + +public final class Integer { + private final int value; + + public Integer(int value) { + this.value = value; + } + + public int intValue() { + return value; + } +} diff --git a/classpath/java/lang/Long.java b/classpath/java/lang/Long.java index c4040168ff..ed0c74f157 100644 --- a/classpath/java/lang/Long.java +++ b/classpath/java/lang/Long.java @@ -1,6 +1,6 @@ package java.lang; -public class Long { +public final class Long { private final long value; public Long(long value) { diff --git a/classpath/java/lang/Short.java b/classpath/java/lang/Short.java new file mode 100644 index 0000000000..214cc0efe0 --- /dev/null +++ b/classpath/java/lang/Short.java @@ -0,0 +1,13 @@ +package java.lang; + +public final class Short { + private final short value; + + public Short(short value) { + this.value = value; + } + + public short shortValue() { + return value; + } +} diff --git a/classpath/java/lang/StringBuilder.java b/classpath/java/lang/StringBuilder.java index 4e4524ea18..a734bab1a6 100644 --- a/classpath/java/lang/StringBuilder.java +++ b/classpath/java/lang/StringBuilder.java @@ -10,14 +10,16 @@ public class StringBuilder { return this; } + public StringBuilder append(Object o) { + return append(o == null ? "null" : o.toString()); + } + public StringBuilder append(int v) { - append(String.valueOf(v)); - return this; + return append(String.valueOf(v)); } public StringBuilder append(long v) { - append(String.valueOf(v)); - return this; + return append(String.valueOf(v)); } public String toString() { diff --git a/classpath/java/lang/System.java b/classpath/java/lang/System.java index 30f4de747c..af5df4b24e 100644 --- a/classpath/java/lang/System.java +++ b/classpath/java/lang/System.java @@ -15,6 +15,8 @@ public abstract class System { public static native String getProperty(String name); + public static native void gc(); + public static class Output { public synchronized native void print(String s); diff --git a/classpath/java/lang/Void.java b/classpath/java/lang/Void.java new file mode 100644 index 0000000000..b1400cbd7f --- /dev/null +++ b/classpath/java/lang/Void.java @@ -0,0 +1,5 @@ +package java.lang; + +public final class Void { + +} diff --git a/classpath/java/lang/ref/Reference.java b/classpath/java/lang/ref/Reference.java index f195306a16..48451617c3 100644 --- a/classpath/java/lang/ref/Reference.java +++ b/classpath/java/lang/ref/Reference.java @@ -4,7 +4,7 @@ public abstract class Reference { private T target; private ReferenceQueue queue; private Object vmNext; - Reference next; + Reference next; protected Reference(T target, ReferenceQueue queue) { this.target = target; @@ -16,7 +16,7 @@ public abstract class Reference { } public void clear() { - target = 0; + target = null; } public boolean isEnqueued() { diff --git a/classpath/java/lang/ref/ReferenceQueue.java b/classpath/java/lang/ref/ReferenceQueue.java index 87ded829a1..dcf92cd42e 100644 --- a/classpath/java/lang/ref/ReferenceQueue.java +++ b/classpath/java/lang/ref/ReferenceQueue.java @@ -1,6 +1,6 @@ package java.lang.ref; -public abstract class ReferenceQueue { +public class ReferenceQueue { private Reference front; private Reference rear; diff --git a/makefile b/makefile index 114281bdb8..ea327eb334 100644 --- a/makefile +++ b/makefile @@ -16,7 +16,7 @@ src = src classpath = classpath test = test -input = $(cls)/Exceptions.class +input = $(cls)/References.class cxx = g++ cc = gcc diff --git a/src/builtin.cpp b/src/builtin.cpp index ffef0725dd..29358142a3 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -106,6 +106,14 @@ arraycopy(Thread* t, jobject src, jint srcOffset, jobject dst, jint dstOffset, t->exception = makeArrayStoreException(t); } +void +gc(Thread* t) +{ + ENTER(t, Thread::ExclusiveState); + + collect(t, Heap::MajorCollection); +} + jobject trace(Thread* t, jint skipCount) { @@ -217,6 +225,8 @@ populate(Thread* t, object map) reinterpret_cast(arraycopy) }, { "Java_java_lang_System_loadLibrary", reinterpret_cast(loadLibrary) }, + { "Java_java_lang_System_gc", + reinterpret_cast(gc) }, { "Java_java_lang_Thread_start", reinterpret_cast(start) }, diff --git a/src/heap.cpp b/src/heap.cpp index 85d68ddcd6..0f055b65db 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1438,7 +1438,9 @@ makeHeap(System* system) virtual Status status(void* p) { p = mask(p); - if (c.nextGen1.contains(p)) { + if (p == 0) { + return Null; + } else if (c.nextGen1.contains(p)) { return Reachable; } else if (c.nextGen2.contains(p) or (c.gen2.contains(p) diff --git a/src/heap.h b/src/heap.h index f8f25ba8b6..00b7ae45eb 100644 --- a/src/heap.h +++ b/src/heap.h @@ -13,6 +13,7 @@ class Heap { }; enum Status { + Null, Reachable, Unreachable, Tenured diff --git a/src/machine.cpp b/src/machine.cpp index 6346c21a67..0c45c4b693 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -142,7 +142,9 @@ referenceTargetUnreachable(Thread* t, object* p, Heap::Visitor* v) v->visit(p); jreferenceTarget(t, *p) = 0; - if (t->vm->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable) { + if (jreferenceQueue(t, *p) + and t->vm->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable) + { // queue is reachable - add the reference v->visit(&jreferenceQueue(t, *p)); @@ -161,6 +163,17 @@ referenceTargetUnreachable(Thread* t, object* p, Heap::Visitor* v) } } +void +referenceUnreachable(Thread* t, object* p, Heap::Visitor* v) +{ + if (jreferenceQueue(t, *p) + and t->vm->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable) + { + // queue is reachable - add the reference + referenceTargetUnreachable(t, p, v); + } +} + void referenceTargetReachable(Thread* t, object* p, Heap::Visitor* v) { @@ -222,12 +235,12 @@ postVisit(Thread* t, Heap::Visitor* v) for (object* p = &(m->weakReferences); *p;) { if (m->heap->status(*p) == Heap::Unreachable) { - // reference is unreachable - remove it from the list + // reference is unreachable + referenceUnreachable(t, p, v); *p = jreferenceNext(t, *p); } else if (m->heap->status(jreferenceTarget(t, *p)) == Heap::Unreachable) { - // target is unreachable - clear the reference, remove it from - // the list, and enqueue it if it has a live reference queue + // target is unreachable referenceTargetUnreachable(t, p, v); *p = jreferenceNext(t, *p); @@ -279,19 +292,19 @@ postVisit(Thread* t, Heap::Visitor* v) for (object* p = &(m->tenuredWeakReferences); *p;) { if (m->heap->status(*p) == Heap::Unreachable) { - // reference is unreachable - remove it from the list + // reference is unreachable + referenceUnreachable(t, p, v); *p = jreferenceNext(t, *p); } else if (m->heap->status(jreferenceTarget(t, *p)) == Heap::Unreachable) { - // target is unreachable - clear the reference, remove it from - // the list, and enqueue it if it has a live reference queue + // target is unreachable referenceTargetUnreachable(t, p, v); *p = jreferenceNext(t, *p); } else { - // target is reachable + // both reference and target are reachable referenceTargetReachable(t, p, v); p = &jreferenceNext(t, *p); @@ -1106,7 +1119,9 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_) // verify that the classes have the same layout expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_)); expect(t, classFixedSize(t, bootstrapClass) == classFixedSize(t, class_)); - expect(t, (classObjectMask(t, bootstrapClass) == 0 + expect(t, + (classVmFlags(t, bootstrapClass) & ReferenceFlag) + or (classObjectMask(t, bootstrapClass) == 0 and classObjectMask(t, class_) == 0) or intArrayEqual(t, classObjectMask(t, bootstrapClass), classObjectMask(t, class_))); @@ -1243,7 +1258,7 @@ Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder): stateLock(0), heapLock(0), classLock(0), - finalizerLock(0), + referenceLock(0), libraries(0), classMap(0), bootstrapClassMap(0), @@ -1262,7 +1277,7 @@ Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder): if (not system->success(system->make(&stateLock)) or not system->success(system->make(&heapLock)) or not system->success(system->make(&classLock)) or - not system->success(system->make(&finalizerLock))) + not system->success(system->make(&referenceLock))) { system->abort(); } @@ -1274,7 +1289,7 @@ Machine::dispose() stateLock->dispose(); heapLock->dispose(); classLock->dispose(); - finalizerLock->dispose(); + referenceLock->dispose(); if (libraries) { libraries->dispose(); @@ -1339,6 +1354,13 @@ Thread::Thread(Machine* m, Allocator* allocator, object javaThread, m->unsafe = false; + classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType)) + |= ReferenceFlag; + classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType)) + |= ReferenceFlag | WeakReferenceFlag; + classVmFlags(t, arrayBody(t, m->types, Machine::PhantomReferenceType)) + |= ReferenceFlag | WeakReferenceFlag; + m->bootstrapClassMap = makeHashMap(this, NormalMap, 0, 0); #include "type-java-initializations.cpp" @@ -2090,7 +2112,7 @@ addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)) { PROTECT(t, target); - ACQUIRE(t, t->vm->finalizerLock); + ACQUIRE(t, t->vm->referenceLock); t->vm->finalizers = makeFinalizer (t, 0, reinterpret_cast(finalize), t->vm->finalizers); diff --git a/src/machine.h b/src/machine.h index d2d3c82a60..cf2bf9d015 100644 --- a/src/machine.h +++ b/src/machine.h @@ -61,6 +61,9 @@ enum MapType { const int NativeLine = -1; const int UnknownLine = -2; +const unsigned ReferenceFlag = 1 << 0; +const unsigned WeakReferenceFlag = 1 << 1; + class Thread; typedef Thread JNIEnv; @@ -1106,7 +1109,7 @@ class Machine { System::Monitor* stateLock; System::Monitor* heapLock; System::Monitor* classLock; - System::Monitor* finalizerLock; + System::Monitor* referenceLock; System::Library* libraries; object classMap; object bootstrapClassMap; diff --git a/src/run.cpp b/src/run.cpp index 36c073ff97..f33d9e8c36 100644 --- a/src/run.cpp +++ b/src/run.cpp @@ -76,6 +76,18 @@ popFrame(Thread* t) } } +void +registerWeakReference(Thread* t, object r) +{ + PROTECT(t, r); + + ACQUIRE(t, t->vm->referenceLock); + + // jreferenceNext(t, r) + cast(r, 3 * BytesPerWord) = t->vm->weakReferences; + t->vm->weakReferences = r; +} + inline object make(Thread* t, object class_) { @@ -86,6 +98,10 @@ make(Thread* t, object class_) memset(static_cast(instance) + 1, 0, sizeInBytes - sizeof(object)); + if (UNLIKELY(classVmFlags(t, class_) & WeakReferenceFlag)) { + registerWeakReference(t, instance); + } + return instance; } @@ -1085,8 +1101,8 @@ run(Thread* t) uint8_t offset1 = codeBody(t, code, ip++); uint8_t offset2 = codeBody(t, code, ip++); - int32_t b = popInt(t); - int32_t a = popInt(t); + object b = popObject(t); + object a = popObject(t); if (a == b) { ip = (ip - 3) + static_cast(((offset1 << 8) | offset2)); @@ -1097,8 +1113,8 @@ run(Thread* t) uint8_t offset1 = codeBody(t, code, ip++); uint8_t offset2 = codeBody(t, code, ip++); - int32_t b = popInt(t); - int32_t a = popInt(t); + object b = popObject(t); + object a = popObject(t); if (a != b) { ip = (ip - 3) + static_cast(((offset1 << 8) | offset2)); diff --git a/test/References.java b/test/References.java new file mode 100644 index 0000000000..fcf473813c --- /dev/null +++ b/test/References.java @@ -0,0 +1,36 @@ +import java.lang.ref.ReferenceQueue; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.lang.ref.PhantomReference; + +public class References { + public static void main(String[] args) { + Object a = new Object(); + Object b = new Object(); + Object c = new Object(); + Object d = new Object(); + + ReferenceQueue q = new ReferenceQueue(); + + Reference ar = new WeakReference(a); + Reference br = new WeakReference(b, q); + Reference cr = new WeakReference(c, q); + Reference dr = new PhantomReference(d, q); + + a = b = c = d = cr = null; + + System.out.println("a: " + ar.get()); + System.out.println("b: " + br.get()); + System.out.println("d: " + dr.get()); + + System.gc(); + + System.out.println("a: " + ar.get()); + System.out.println("b: " + br.get()); + System.out.println("d: " + dr.get()); + + for (Reference r = q.poll(); r != null; r = q.poll()) { + System.out.println("polled: " + r.get()); + } + } +}