|
View:
New views
1 Messages
—
Rating Filter:
Alert me
|
|
|
SF.net SVN: jikesrvm:[15732] rvmroot/trunkRevision: 15732
http://jikesrvm.svn.sourceforge.net/jikesrvm/?rev=15732&view=rev Author: rgarner Date: 2009-07-22 07:44:58 +0000 (Wed, 22 Jul 2009) Log Message: ----------- Major revision of MMTk Harness, addressing RVM-839, RVM-840 and RVM-838 and with a bunch of refactoring along the way. Highlights include: - Support for reference types, and associated test script - Watch points for individual objects - Sanity checker uses read barrier, making Poisoned collector work. - Simulated Memory class refactored to avoid static initialization races - Several synchronization bugs fixed - Some refactoring of the schedulers Modified Paths: -------------- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ActivePlan.java rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Assert.java rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Barriers.java rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Collection.java rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Debug.java rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Memory.java rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ReferenceProcessor.java rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Scanning.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Collector.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Harness.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutator.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Env.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Trace.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/parser/GlobalDefs.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocOp.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocUserOp.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/AbstractType.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/BooleanType.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/Field.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/IntType.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/ObjectType.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/StringType.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/Type.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/TypeReference.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/VoidType.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/options/HarnessOptionSet.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/sanity/HeapEntry.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/sanity/HeapSnapshot.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/sanity/Sanity.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/sanity/Traversal.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/Scheduler.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/JavaThread.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/JavaThreadModel.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/RawThread.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/RawThreadModel.java rvmroot/trunk/MMTk/harness/test-scripts/Lists.script rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Address.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Extent.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/ObjectReference.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Offset.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Word.java rvmroot/trunk/bin/test-mmtk Added Paths: ----------- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutators.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/OutOfMemory.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/PhantomReferenceValue.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ReferenceValue.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/SoftReferenceValue.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/WeakReferenceValue.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/ReferenceType.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/options/SanityUsesReadBarrier.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/options/WatchObject.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/MMTkThread.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/CollectorContextThread.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/CollectorThread.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/javathreads/MutatorThread.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/CollectorContextThread.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/CollectorThread.java rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/scheduler/rawthreads/MutatorThread.java rvmroot/trunk/MMTk/harness/test-scripts/ReferenceTypes.script rvmroot/trunk/MMTk/harness/test-scripts/SpreadAlloc16.options rvmroot/trunk/MMTk/harness/test-scripts/SpreadAlloc16.script rvmroot/trunk/MMTk/harness/test-scripts/lang/phantomref.script rvmroot/trunk/MMTk/harness/test-scripts/lang/softref.script rvmroot/trunk/MMTk/harness/test-scripts/lang/weakref.script rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/ rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/ArchitecturalWord.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/ArchitecturalWord32.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/ArchitecturalWord64.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/Architecture.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/MemoryConstants.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/MemoryPage.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/PageTable.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/harness/SimulatedMemory.java rvmroot/trunk/bin/test-mmtk-selected Removed Paths: ------------- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/MMTkThread.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/ArchitecturalWord.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/ArchitecturalWord32.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/ArchitecturalWord64.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/Architecture.java rvmroot/trunk/MMTk/harness/vmmagic/org/vmmagic/unboxed/SimulatedMemory.java Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ActivePlan.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ActivePlan.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ActivePlan.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -12,8 +12,11 @@ */ package org.mmtk.harness.vm; +import java.util.concurrent.BlockingQueue; + import org.mmtk.harness.Collector; import org.mmtk.harness.Mutator; +import org.mmtk.harness.Mutators; import org.mmtk.harness.scheduler.Scheduler; import org.mmtk.plan.Plan; import org.mmtk.plan.CollectorContext; @@ -29,7 +32,10 @@ @Uninterruptible public final class ActivePlan extends org.mmtk.vm.ActivePlan { - /** Initialise static state */ + /** + * Initialise static state + * @param prefix The name of the plan class (prefix for the associated classes) + */ public static void init(String prefix) { try { constraints = (PlanConstraints)Class.forName(prefix + "Constraints").newInstance(); @@ -49,9 +55,6 @@ /** The global constraints */ public static PlanConstraints constraints; - /** Used for iterating over mutators */ - private static int mutatorIndex; - /** @return The active Plan instance. */ @Override public Plan global() { return plan; }; @@ -76,9 +79,11 @@ @Override public int collectorCount() { return Collector.count(); } + private BlockingQueue<Mutator> mutators = null; + /** Reset the mutator iterator */ @Override - public void resetMutatorIterator() { mutatorIndex = 0; } + public void resetMutatorIterator() { mutators = null; } /** * Return the next <code>MutatorContext</code> in a @@ -91,8 +96,11 @@ @Override public MutatorContext getNextMutator() { synchronized(ActivePlan.class) { - if (mutatorIndex >= Mutator.count()) return null; - return Mutator.get(mutatorIndex++).getContext(); + if (mutators == null) { + mutators = Mutators.getAll(); + } } + Mutator m = mutators.poll(); + return m == null ? null : m.getContext(); } } Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Assert.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Assert.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Assert.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -14,6 +14,9 @@ import org.vmmagic.pragma.Uninterruptible; +/** + * MMTk Harness implementation of Assert + */ @Uninterruptible public class Assert extends org.mmtk.vm.Assert { @@ -29,6 +32,7 @@ * * @param message the string to log */ + @Override public void fail(String message) { throw new RuntimeException("Assertion Failed: " + message); } @@ -40,6 +44,7 @@ * * @param cond the condition to be checked */ + @Override public void _assert(boolean cond) { if (!cond) fail(""); } @@ -52,6 +57,7 @@ * @param cond the condition to be checked * @param message the message to print */ + @Override public void _assert(boolean cond, String message) { if (!cond) fail(message); } @@ -59,6 +65,7 @@ /** * Print a stack trace */ + @Override public void dumpStack() { new Exception().printStackTrace(); } @@ -70,11 +77,13 @@ * * @return <code>true</code> if the virtual machine is running */ + @Override public boolean runningVM() { return true; } /** @return true if assertions should be verified */ + @Override protected boolean getVerifyAssertionsConstant() { return true; } Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Barriers.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Barriers.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Barriers.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -15,6 +15,9 @@ import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.*; +/** + * MMTk Harness implementation of Barriers interface + */ @Uninterruptible public class Barriers extends org.mmtk.vm.Barriers { /** @@ -27,6 +30,7 @@ * @param index the index of the element to set * @param value the new value for the element */ + @Override public void setArrayNoBarrier(Object [] dst, int index, Object value) { dst[index] = value; } @@ -41,6 +45,7 @@ * @param metaDataB Unused * @param mode The context in which the write is occuring */ + @Override public void performWriteInBarrier(ObjectReference ref, Address slot, ObjectReference target, Word metaDataA, Word metaDataB, int mode) { @@ -57,6 +62,7 @@ * @param metaDataB Unused * @param mode The context in which the write is occuring */ + @Override public void performRawWriteInBarrier(ObjectReference ref, Address slot, Word rawTarget, Word metaDataA, Word metaDataB, int mode) { @@ -73,6 +79,7 @@ * @param mode The context in which the write is occuring * @return the read value */ + @Override public ObjectReference performReadInBarrier(ObjectReference ref, Address slot, Word metaDataA, Word metaDataB, int mode) { return slot.loadObjectReference(); @@ -88,6 +95,7 @@ * @param mode The context in which the write is occuring * @return the read value */ + @Override public Word performRawReadInBarrier(ObjectReference ref, Address slot, Word metaDataA, Word metaDataB, int mode) { return slot.loadWord(); @@ -105,6 +113,7 @@ * @param mode The context in which the write is occuring * @return The value that was replaced by the write. */ + @Override public ObjectReference performWriteInBarrierAtomic(ObjectReference ref, Address slot, ObjectReference target, Word metaDataA, Word metaDataB, int mode) { @@ -127,6 +136,7 @@ * @param mode The context in which the write is occuring * @return The raw value that was replaced by the write. */ + @Override public Word performRawWriteInBarrierAtomic(ObjectReference ref, Address slot, Word rawTarget, Word metaDataA, Word metaDataB, int mode) { @@ -149,6 +159,7 @@ * @param mode The context in which the write is occuring * @return True if the compare and swap was successful */ + @Override public boolean tryCompareAndSwapWriteInBarrier(ObjectReference ref, Address slot, ObjectReference old, ObjectReference target, Word metaDataA, Word metaDataB, int mode) { @@ -167,6 +178,7 @@ * @param mode The context in which the write is occuring * @return True if the compare and swap was successful */ + @Override public boolean tryRawCompareAndSwapWriteInBarrier(ObjectReference ref, Address slot, Word rawOld, Word rawTarget, Word metaDataA, Word metaDataB, int mode) { Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Collection.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Collection.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Collection.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -15,6 +15,8 @@ import org.mmtk.harness.Collector; import org.mmtk.harness.Harness; import org.mmtk.harness.Mutator; +import org.mmtk.harness.Mutators; +import org.mmtk.harness.exception.OutOfMemory; import org.mmtk.harness.scheduler.Scheduler; import org.mmtk.plan.CollectorContext; import org.mmtk.plan.MutatorContext; @@ -37,6 +39,7 @@ * @param why the reason why a collection was triggered. 0 to * <code>TRIGGER_REASONS - 1</code>. */ + @Override public void triggerCollection(int why) { if (Options.verbose.getValue() >= 4) { new Exception("Collection trigger: " + triggerReasons[why]).printStackTrace(); @@ -57,19 +60,20 @@ mutator.reportCollectionAttempt(); } - if (mutator.isOutOfMemory()) throw new Mutator.OutOfMemory(); + if (mutator.isOutOfMemory()) throw new OutOfMemory(); Collector.triggerGC(why); Scheduler.waitForGC(); if (mutator.isOutOfMemory() && !mutator.isPhysicalAllocationFailure()) { - throw new Mutator.OutOfMemory(); + throw new OutOfMemory(); } } /** * Joins an already requested collection. */ + @Override public void joinCollection() { while (Plan.isCollectionTriggered()) { /* allow a gc thread to run */ @@ -77,7 +81,7 @@ } Mutator mutator = Mutator.current(); if (mutator.isOutOfMemory() && !mutator.isPhysicalAllocationFailure()) { - throw new Mutator.OutOfMemory(); + throw new OutOfMemory(); } } @@ -88,6 +92,7 @@ * @param why the reason why a collection was triggered. 0 to * <code>TRIGGER_REASONS - 1</code>. */ + @Override public void triggerAsyncCollection(int why) { Plan.setCollectionTriggered(); if (Options.verbose.getValue() >= 1) { @@ -102,13 +107,13 @@ } /** - * The maximum number collection attempts across threads. + * @return The maximum number of collection attempts across threads. */ + @Override public int maximumCollectionAttempt() { int max = 1; - for(int m=0; m < Mutator.count(); m++) { - Mutator mutator = Mutator.get(m); - int current = mutator.getCollectionAttempts(); + for(Mutator m : Mutators.getAll()) { + int current = m.getCollectionAttempts(); if (current > max) max = current; } return max + Collector.getCollectionAttemptBase(); @@ -117,6 +122,7 @@ /** * Report that the allocation has succeeded. */ + @Override public void reportAllocationSuccess() { Mutator mutator = Mutator.current(); mutator.setOutOfMemory(false); @@ -127,6 +133,7 @@ /** * Report that a physical allocation has failed. */ + @Override public void reportPhysicalAllocationFailed() { Mutator.current().setPhysicalAllocationFailure(true); } @@ -135,6 +142,7 @@ * Does the VM consider this an emergency alloction, where the normal * heap size rules can be ignored. */ + @Override public boolean isEmergencyAllocation() { // Not required return false; @@ -148,6 +156,7 @@ * * @return True if GC is not in progress. */ + @Override public boolean noThreadsInGC() { return Scheduler.noThreadsInGC(); } @@ -157,6 +166,7 @@ * * @param m the mutator to prepare */ + @Override public void prepareMutator(MutatorContext m) { // Nothing to do } @@ -166,6 +176,7 @@ * * @param c the collector to prepare */ + @Override public void prepareCollector(CollectorContext c) { // Nothing to do } @@ -174,11 +185,13 @@ * Rendezvous with all other processors, returning the rank * (that is, the order this processor arrived at the barrier). */ + @Override public int rendezvous(int where) { return Collector.rendezvous(where); } /** @return The number of active collector threads */ + @Override public int activeGCThreads() { return Harness.collectors.getValue(); } @@ -187,6 +200,7 @@ * @return The ordinal ID of the running collector thread w.r.t. * the set of active collector threads (zero based) */ + @Override public int activeGCThreadOrdinal() { return Collector.current().getContext().getId(); } @@ -203,6 +217,7 @@ * will trigger the flush and then yield until all processors have * flushed. */ + @Override public void requestMutatorFlush() { Assert.notImplemented(); } Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Debug.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Debug.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Debug.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -16,6 +16,7 @@ import org.mmtk.harness.lang.Trace.Item; import org.mmtk.harness.sanity.FromSpaceInvariant; import org.mmtk.plan.Simple; +import org.mmtk.plan.TraceLocal; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.ObjectReference; @@ -48,7 +49,7 @@ */ @Override public void arrayRemsetEntry(Address start, Address guard) { - Trace.trace(Item.COLLECT, "arrayRemset: [%s,%s)", start, guard); + Trace.trace(Item.REMSET, "arrayRemset: [%s,%s)", start, guard); } /** @@ -56,7 +57,7 @@ */ @Override public void modbufEntry(ObjectReference object) { - Trace.trace(Item.COLLECT, "modbuf: %s", format(object)); + Trace.trace(Item.REMSET, "modbuf: %s", format(object)); } /** @@ -64,7 +65,7 @@ */ @Override public void remsetEntry(Address slot) { - Trace.trace(Item.COLLECT, "remset: %s->%s", format(slot), format(slot.loadObjectReference())); + Trace.trace(Item.REMSET, "remset: %s->%s", format(slot), format(slot.loadObjectReference())); } /** @@ -76,4 +77,14 @@ new FromSpaceInvariant(); } } + + /** + * @see org.mmtk.vm.Debug#traceObject(org.mmtk.plan.TraceLocal, org.vmmagic.unboxed.ObjectReference) + */ + @Override + public void traceObject(TraceLocal trace, ObjectReference object) { + Trace.trace(Item.TRACEOBJECT, "traceObject: %s", format(object)); + } + + } Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -135,12 +135,13 @@ /** * Create a new ReferenceProcessor instance using the appropriate VM-specific * concrete ReferenceProcessor sub-class. + * @param semantics The reference semantics for this processor * * @see ReferenceProcessor * @return A concrete VM-specific ReferenceProcessor instance. */ public ReferenceProcessor newReferenceProcessor(ReferenceProcessor.Semantics semantics) { - return new ReferenceProcessor(); + return ReferenceProcessor.getProcessorFor(semantics); } /** Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Memory.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Memory.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Memory.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -17,6 +17,8 @@ import org.mmtk.utility.heap.VMRequest; import org.vmmagic.unboxed.*; +import org.vmmagic.unboxed.harness.MemoryConstants; +import org.vmmagic.unboxed.harness.SimulatedMemory; import org.vmmagic.pragma.*; @Uninterruptible @@ -207,17 +209,17 @@ /** @return The highest address in the contiguous address space available to MMTk */ protected Address getAvailableEndConstant() { return HEAP_END; } /** @return The log base two of the size of an address */ - protected byte getLogBytesInAddressConstant() { return (byte) SimulatedMemory.LOG_BYTES_IN_WORD; } + protected byte getLogBytesInAddressConstant() { return (byte) MemoryConstants.LOG_BYTES_IN_WORD; } /** @return The log base two of the size of a word */ - protected byte getLogBytesInWordConstant() { return (byte) SimulatedMemory.LOG_BYTES_IN_WORD; } + protected byte getLogBytesInWordConstant() { return (byte) MemoryConstants.LOG_BYTES_IN_WORD; } /** @return The log base two of the size of an OS page */ - protected byte getLogBytesInPageConstant() { return SimulatedMemory.LOG_BYTES_IN_PAGE; } + protected byte getLogBytesInPageConstant() { return MemoryConstants.LOG_BYTES_IN_PAGE; } /** @return The log base two of the minimum allocation alignment */ - protected byte getLogMinAlignmentConstant() { return (byte) SimulatedMemory.LOG_BYTES_IN_WORD; } + protected byte getLogMinAlignmentConstant() { return (byte) MemoryConstants.LOG_BYTES_IN_WORD; } /** @return The log base two of (MAX_ALIGNMENT/MIN_ALIGNMENT) */ protected byte getMaxAlignmentShiftConstant() { return 1; } /** @return The maximum number of bytes of padding to prepend to an object */ - protected int getMaxBytesPaddingConstant() { return SimulatedMemory.BYTES_IN_WORD; } + protected int getMaxBytesPaddingConstant() { return MemoryConstants.BYTES_IN_WORD; } /** @return The value to store in alignment holes */ protected int getAlignmentValueConstant() { return ObjectModel.ALIGNMENT_VALUE; } } Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -13,9 +13,11 @@ package org.mmtk.harness.vm; import java.io.PrintStream; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; -import java.util.Stack; +import java.util.Collection; import org.mmtk.harness.Collector; import org.mmtk.harness.Mutator; @@ -27,45 +29,46 @@ import org.mmtk.policy.Space; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.*; +import org.vmmagic.unboxed.harness.ArchitecturalWord; +import org.vmmagic.unboxed.harness.MemoryConstants; +import org.vmmagic.unboxed.harness.SimulatedMemory; +/** + * MMTk Harness implementation of MMTk object model + * Object id (age in allocations); (Word) + * Allocation site (Word) + * The size of the data section in words. (UInt16) + * The number of reference words. (UInt16) + * Status Word (includes GC) + * References + * Data + */ @Uninterruptible public final class ObjectModel extends org.mmtk.vm.ObjectModel { - /* - * The object model for the harness stores: - * - * Object id (age in allocations); (Word) - * Allocation site (Word) - * The size of the data section in words. (UInt16) - * The number of reference words. (UInt16) - * Status Word (includes GC) - * References - * Data - */ - private static final boolean IS_32_BIT = ArchitecturalWord.getModel().bitsInWord() == 32; /** The total header size (including any requested GC words) */ public static final int HEADER_WORDS = (IS_32_BIT ? 5 : 3) + ActivePlan.constraints.gcHeaderWords(); /** The number of bytes in the header */ - private static final int HEADER_SIZE = HEADER_WORDS << SimulatedMemory.LOG_BYTES_IN_WORD; + private static final int HEADER_SIZE = HEADER_WORDS << MemoryConstants.LOG_BYTES_IN_WORD; /** The number of bytes requested for GC in the header */ - private static final int GC_HEADER_BYTES = ActivePlan.constraints.gcHeaderWords() << SimulatedMemory.LOG_BYTES_IN_WORD; + private static final int GC_HEADER_BYTES = ActivePlan.constraints.gcHeaderWords() << MemoryConstants.LOG_BYTES_IN_WORD; /** The offset of the first GC header word */ private static final Offset GC_OFFSET = Offset.zero(); /** The offset of the object ID */ private static final Offset ID_OFFSET = GC_OFFSET.plus(GC_HEADER_BYTES); /** The offset of the allocation site */ - private static final Offset SITE_OFFSET = ID_OFFSET.plus(SimulatedMemory.BYTES_IN_INT); + private static final Offset SITE_OFFSET = ID_OFFSET.plus(MemoryConstants.BYTES_IN_INT); /** The offset of the UInt16 storing the number of data fields */ - private static final Offset DATACOUNT_OFFSET = SITE_OFFSET.plus(SimulatedMemory.BYTES_IN_INT); + private static final Offset DATACOUNT_OFFSET = SITE_OFFSET.plus(MemoryConstants.BYTES_IN_INT); /** The offset of the UInt16 storing the number of reference fields */ - private static final Offset REFCOUNT_OFFSET = DATACOUNT_OFFSET.plus(SimulatedMemory.BYTES_IN_INT); + private static final Offset REFCOUNT_OFFSET = DATACOUNT_OFFSET.plus(MemoryConstants.BYTES_IN_INT); /** The offset of the status word */ - private static final Offset STATUS_OFFSET = REFCOUNT_OFFSET.plus(SimulatedMemory.BYTES_IN_INT); + private static final Offset STATUS_OFFSET = REFCOUNT_OFFSET.plus(MemoryConstants.BYTES_IN_INT); /** The offset of the first reference field. */ - public static final Offset REFS_OFFSET = STATUS_OFFSET.plus(SimulatedMemory.BYTES_IN_WORD); + public static final Offset REFS_OFFSET = STATUS_OFFSET.plus(MemoryConstants.BYTES_IN_WORD); @SuppressWarnings("unused") private static void printObjectLayout(PrintStream wr) { @@ -84,11 +87,11 @@ public static final int MAX_REF_FIELDS = Integer.MAX_VALUE; /** Has this object been hashed? */ - private static final int HASHED = 0x1 << (3 * SimulatedMemory.BITS_IN_BYTE); + private static final int HASHED = 0x1 << (3 * MemoryConstants.BITS_IN_BYTE); /** Has this object been moved since it was hashed? */ - private static final int HASHED_AND_MOVED = 0x3 << (3 * SimulatedMemory.BITS_IN_BYTE); + private static final int HASHED_AND_MOVED = 0x3 << (3 * MemoryConstants.BITS_IN_BYTE); /** Is this object 8 byte aligned */ - private static final int DOUBLE_ALIGN = 0x1 << (2 * SimulatedMemory.BITS_IN_BYTE); + private static final int DOUBLE_ALIGN = 0x1 << (2 * MemoryConstants.BITS_IN_BYTE); /** The value placed in alignment holes */ public static final int ALIGNMENT_VALUE = 1; @@ -105,7 +108,9 @@ return nextObjectId++; } - /** Return the last object ID allocated - for error reporting: NOT THREAD SAFE!!! */ + /** + * @return the last object ID allocated - for error reporting: NOT THREAD SAFE!!! + */ public static int lastObjectId() { return nextObjectId; } @@ -124,11 +129,17 @@ return watchSet.contains(getId(object)); } + /** + * Add the specified object (numbered in allocation order) to the watch set. + * @param id Object ID + */ + public static void watchObject(int id) { + watchSet.add(id); + } + static { - //printObjectLayout(System.out); + //printObjectLayout(System.out); // Sometimes helps debug the object header layout assert REFS_OFFSET.EQ(Offset.fromIntSignExtend(HEADER_SIZE)); - //watchSet.add(4109); - //watchSet.add(8205); } /** @@ -138,15 +149,20 @@ * @param refCount The number of reference fields. * @param dataCount The number of data fields. * @param doubleAlign Align the object at an 8 byte boundary? + * @param site The allocation site * @return The new ObjectReference. */ public static ObjectReference allocateObject(MutatorContext context, int refCount, int dataCount, boolean doubleAlign, int site) { - int bytes = (HEADER_WORDS + refCount + dataCount) << SimulatedMemory.LOG_BYTES_IN_WORD; + int bytes = (HEADER_WORDS + refCount + dataCount) << MemoryConstants.LOG_BYTES_IN_WORD; int align = ArchitecturalWord.getModel().bitsInWord() == 64 ? - SimulatedMemory.BYTES_IN_WORD : - (doubleAlign ? 2 : 1) * SimulatedMemory.BYTES_IN_INT; - int allocator = context.checkAllocator(bytes, align, Plan.ALLOC_DEFAULT); + MemoryConstants.BYTES_IN_WORD : + (doubleAlign ? 2 : 1) * MemoryConstants.BYTES_IN_INT; + int allocator = context.checkAllocator(bytes, align, refCount == 0 ? Plan.ALLOC_NON_REFERENCE : Plan.ALLOC_DEFAULT); +// if (allocator == Plan.ALLOC_LOS) { +// System.out.printf("Allocating %d bytes in LOS%n",bytes); +// } + // Allocate the raw memory Address region = context.alloc(bytes, align, 0, allocator, 0); @@ -201,6 +217,8 @@ /** * Get the call site identifier. + * @param object The object + * @return The call site */ public static int getSite(ObjectReference object) { return object.toAddress().loadInt(SITE_OFFSET); @@ -208,6 +226,8 @@ /** * Get the number of data words in the object. + * @param object The object + * @return The data count */ public static int getDataCount(ObjectReference object) { return object.toAddress().loadInt(DATACOUNT_OFFSET); @@ -232,34 +252,39 @@ /** * Get the current size of an object. + * @param object The object + * @return The object size in bytes */ public static int getSize(ObjectReference object) { int refs = getRefs(object); int data = getDataCount(object); boolean includesHash = (object.toAddress().loadInt(STATUS_OFFSET) & HASHED_AND_MOVED) == HASHED_AND_MOVED; - return getSize(refs, data) + (includesHash ? SimulatedMemory.BYTES_IN_WORD : 0); + return getSize(refs, data) + (includesHash ? MemoryConstants.BYTES_IN_WORD : 0); } /** * Get the size this object will require when copied. + * @param object The object + * @return The object size in bytes after copying */ public static int getCopiedSize(ObjectReference object) { int refs = getRefs(object); int data = getDataCount(object); boolean needsHash = (object.toAddress().loadInt(STATUS_OFFSET) & HASHED) == HASHED; - return getSize(refs, data) + (needsHash ? SimulatedMemory.BYTES_IN_WORD : 0); + return getSize(refs, data) + (needsHash ? MemoryConstants.BYTES_IN_WORD : 0); } /** - * Return the address of the specified reference. + * Return the address of a reference field in an object. * * @param object The object with the references. * @param index The reference index. + * @return The address of the specified reference field */ public static Address getRefSlot(ObjectReference object, int index) { - return object.toAddress().plus(REFS_OFFSET).plus(index << SimulatedMemory.LOG_BYTES_IN_WORD); + return object.toAddress().plus(REFS_OFFSET).plus(index << MemoryConstants.LOG_BYTES_IN_WORD); } /** @@ -267,6 +292,7 @@ * * @param object The object with the data slot. * @param index The data slot index. + * @return The address of the specified data field */ public static Address getDataSlot(ObjectReference object, int index) { return getRefSlot(object, index + getRefs(object)); @@ -274,14 +300,19 @@ /** * Calculate the size of an object. + * @param refs Number of reference fields + * @param data Number of data fields + * @return Size in bytes of the object */ public static int getSize(int refs, int data) { - return (HEADER_WORDS + refs + data) << SimulatedMemory.LOG_BYTES_IN_WORD; + return (HEADER_WORDS + refs + data) << MemoryConstants.LOG_BYTES_IN_WORD; } /** - * Return the next object id to be allocated. + * Return the next object id to be allocated. For debugging/formatting + * purposes - not thread safe. + * @return The next object ID */ public static int nextObjectId() { return nextObjectId; @@ -304,9 +335,9 @@ } while (!addr.attempt(old, old | HASHED, STATUS_OFFSET)); } else if (status == HASHED_AND_MOVED) { // Load stored hash code - return addr.loadInt(Offset.fromIntZeroExtend(getSize(ref) - SimulatedMemory.BYTES_IN_WORD)); + return addr.loadInt(Offset.fromIntZeroExtend(getSize(ref) - MemoryConstants.BYTES_IN_WORD)); } - return addr.toInt() >>> SimulatedMemory.LOG_BYTES_IN_WORD; + return addr.toInt() >>> MemoryConstants.LOG_BYTES_IN_WORD; } /** @@ -334,7 +365,7 @@ addressAndSpaceString(from),addressAndSpaceString(to)); Address fromRegion = from.toAddress(); - for(int i=0; i < oldBytes; i += SimulatedMemory.BYTES_IN_INT) { + for(int i=0; i < oldBytes; i += MemoryConstants.BYTES_IN_INT) { toRegion.plus(i).store(fromRegion.plus(i).loadInt()); } @@ -376,7 +407,7 @@ } int bytes = getSize(from); Address fromRegion = from.toAddress(); - for(int i=0; i < bytes; i += SimulatedMemory.BYTES_IN_WORD) { + for(int i=0; i < bytes; i += MemoryConstants.BYTES_IN_WORD) { toRegion.plus(i).store(fromRegion.plus(i).loadInt()); } @@ -384,7 +415,7 @@ if ((status & HASHED_AND_MOVED) == HASHED) { toRegion.store(status | HASHED_AND_MOVED, STATUS_OFFSET); toRegion.store(getHashCode(from), Offset.fromIntZeroExtend(bytes)); - bytes += SimulatedMemory.BYTES_IN_WORD; + bytes += MemoryConstants.BYTES_IN_WORD; } if (Trace.isEnabled(Item.COLLECT)) { @@ -429,7 +460,7 @@ */ public int getAlignWhenCopied(ObjectReference object) { boolean doubleAlign = (object.toAddress().loadInt(STATUS_OFFSET) & DOUBLE_ALIGN) == DOUBLE_ALIGN; - return (doubleAlign ? 2 : 1) * SimulatedMemory.BYTES_IN_WORD; + return (doubleAlign ? 2 : 1) * MemoryConstants.BYTES_IN_WORD; } /** @@ -459,7 +490,7 @@ public ObjectReference getNextObject(ObjectReference object) { Address nextAddress = object.toAddress().plus(getSize(object)); if (nextAddress.loadInt() == ALIGNMENT_VALUE) { - nextAddress = nextAddress.plus(SimulatedMemory.BYTES_IN_WORD); + nextAddress = nextAddress.plus(MemoryConstants.BYTES_IN_WORD); } if (nextAddress.loadWord().isZero()) { return ObjectReference.nullReference(); @@ -473,7 +504,7 @@ @Override public ObjectReference getObjectFromStartAddress(Address start) { if ((start.loadInt() & ALIGNMENT_VALUE) != 0) { - start = start.plus(SimulatedMemory.BYTES_IN_WORD); + start = start.plus(MemoryConstants.BYTES_IN_WORD); } return start.toObjectReference(); } @@ -549,7 +580,7 @@ @Override public boolean attemptAvailableBits(ObjectReference object, Word oldVal, Word newVal) { if (Trace.isEnabled(Item.AVBYTE) || isWatched(object)) { - Trace.printf(Item.AVBYTE,"%s.status:%s->%s", object,oldVal,newVal); + Trace.printf(Item.AVBYTE,"%s.status:%s->%s%n", getString(object),oldVal,newVal); } return object.toAddress().attempt(oldVal, newVal, STATUS_OFFSET); } @@ -576,7 +607,7 @@ public void writeAvailableByte(ObjectReference object, byte val) { if (Trace.isEnabled(Item.AVBYTE) || isWatched(object)) { byte old = object.toAddress().loadByte(STATUS_OFFSET); - Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d", object,old,val); + Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d%n", getString(object),old,val); } object.toAddress().store(val, STATUS_OFFSET); } @@ -602,7 +633,7 @@ public void writeAvailableBitsWord(ObjectReference object, Word val) { if (Trace.isEnabled(Item.AVBYTE) || isWatched(object)) { byte old = object.toAddress().loadByte(STATUS_OFFSET); - Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d", object,old,val.and(Word.fromIntZeroExtend(0xFF)).toInt()); + Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d%n", getString(object),old,val.and(Word.fromIntZeroExtend(0xFF)).toInt()); } object.toAddress().store(val, STATUS_OFFSET); } @@ -692,14 +723,18 @@ /** * Format the object for dumping, and trim to a max width. + * @param width Max output width + * @param object The object to dump + * @return The formatted object */ public static String formatObject(int width, ObjectReference object) { String base = getString(object); - return base.substring(base.length() - width); + return base.substring(Math.max(base.length() - width,0)); } /** * Print an object's header + * @param object The object reference */ public static void dumpObjectHeader(ObjectReference object) { int gcWord = object.toAddress().loadInt(GC_OFFSET); @@ -708,14 +743,17 @@ } /** - * Dump (logical) information for an object. + * Dump (logical) information for an object. Returns the non-null pointers + * in the object. * @param width Output width * @param object The object whose information is to be dumped + * @return The non-null references in the object */ - public static void dumpLogicalObject(int width, ObjectReference object, Stack<ObjectReference> workStack) { + public static Collection<ObjectReference> dumpLogicalObject(int width, ObjectReference object) { int refCount = getRefs(object); int dataCount = getDataCount(object); boolean hashed = (object.toAddress().loadInt(STATUS_OFFSET) & HASHED) == HASHED; + List<ObjectReference> pointers = new ArrayList<ObjectReference>(refCount); System.err.printf(" Object %s <%d %d %1s> [", ObjectModel.formatObject(width, object), refCount, dataCount, (hashed ? "H" : "")); if (refCount > 0) { for(int i=0; i < refCount; i++) { @@ -723,11 +761,12 @@ System.err.print(" "); System.err.print(ObjectModel.formatObject(width, ref)); if (!ref.isNull()) { - workStack.push(ref); + pointers.add(ref); } } } System.err.println(" ]"); + return pointers; } /** @@ -737,6 +776,7 @@ * @return "Object[size b nR/mD] */ public static String getString(ObjectReference ref) { + if (ref.isNull()) return "<null>"; int refs = getRefs(ref); int data = getDataCount(ref); return addressAndSpaceString(ref)+objectIdString(ref)+refs + "R" + data + "D"; @@ -762,7 +802,7 @@ /** * Address and space name (eg 0x45678900/ms) - * @param ref The object + * @param addr The object * @return "address/space" */ public static String addressAndSpaceString(Address addr) { Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ReferenceProcessor.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ReferenceProcessor.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/ReferenceProcessor.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -12,47 +12,140 @@ */ package org.mmtk.harness.vm; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.mmtk.harness.lang.Trace; +import org.mmtk.harness.lang.Trace.Item; +import org.mmtk.harness.lang.runtime.ReferenceValue; import org.mmtk.plan.TraceLocal; import org.vmmagic.pragma.Uninterruptible; +import org.vmmagic.unboxed.ObjectReference; /** * This class manages SoftReferences, WeakReferences, and * PhantomReferences. + * + * The harness only provides reference types to ensure that the MMTk + * Plan processes them correctly, so all types have the semantics + * of weak references. */ @Uninterruptible -public class ReferenceProcessor extends org.mmtk.vm.ReferenceProcessor { +public final class ReferenceProcessor extends org.mmtk.vm.ReferenceProcessor { + private static Map<Semantics,ReferenceProcessor> processors = + new EnumMap<Semantics,ReferenceProcessor>(Semantics.class); + + static { + processors.put(Semantics.SOFT, new ReferenceProcessor(Semantics.SOFT)); + processors.put(Semantics.WEAK, new ReferenceProcessor(Semantics.WEAK)); + processors.put(Semantics.PHANTOM, new ReferenceProcessor(Semantics.PHANTOM)); + } + + static ReferenceProcessor getProcessorFor(Semantics semantics) { + return processors.get(semantics); + } + /** + * Discover a reference value while scanning stacks + * @param ref Reference value + */ + public static void discover(ReferenceValue ref) { + processors.get(ref.getSemantics()).add(ref); + } + + /** + * The set of reference objects of this semantics + */ + private final Set<ReferenceValue> oldRefs = new HashSet<ReferenceValue>(); + private final Set<ReferenceValue> currentRefs = Collections.synchronizedSet(new HashSet<ReferenceValue>()); + private final Set<ReferenceValue> newRefs = Collections.synchronizedSet(new HashSet<ReferenceValue>()); + + private final Semantics semantics; + + private ReferenceProcessor(Semantics semantics) { + this.semantics = semantics; + } + + /** + * Add a reference value to the set of references of this type. + * + * This method is thread-safe, to support concurrent collection of + * roots, by virtue of the synchronized collection types used for newRefs + * and currentRefs. + * + * @param ref The reference value + */ + private void add(ReferenceValue ref) { + Trace.trace(Item.REFERENCES, "Discovered reference %s", ref); + if (!oldRefs.contains(ref)) { + newRefs.add(ref); + } else { + currentRefs.add(ref); + } + } + + /** * Clear the contents of the table. This is called when reference types are * disabled to make it easier for VMs to change this setting at runtime. */ public void clear() { + Trace.trace(Item.REFERENCES, "Clearing %s references", semantics); + currentRefs.clear(); + newRefs.clear(); } /** * Scan through the list of references. * + * TODO support concurrent scans + * + * TODO the nursery/mature logic could be improved + * * @param trace the thread local trace element. * @param nursery true if it is safe to only scan new references. */ - public void scan(TraceLocal trace, boolean nursery) { - Assert.notImplemented(); + public synchronized void scan(TraceLocal trace, boolean nursery) { + Trace.trace(Item.REFERENCES, "Scanning %s references: current = %d, new = %d, %s", + semantics,currentRefs.size(), newRefs.size(), nursery ? "nursery" : "full-heap"); + if (!nursery) { + scanReferenceSet(trace, currentRefs); + } + scanReferenceSet(trace, newRefs); + oldRefs.clear(); + oldRefs.addAll(currentRefs); + oldRefs.addAll(newRefs); + currentRefs.clear(); + newRefs.clear(); } + private void scanReferenceSet(TraceLocal trace, Set<ReferenceValue> set) { + for (ReferenceValue value : set) { + ObjectReference referent = value.getObjectValue(); + if (trace.isReferentLive(referent)) { + value.traceObject(trace); + } else { + value.clear(); + } + } + } + /** * Iterate over all references and forward. + * @param trace The MMTk trace to forward to + * @param nursery The nursery collection hint */ public void forward(TraceLocal trace, boolean nursery) { Assert.notImplemented(); } /** - * Return the number of references objects on the queue - * - * @return + * @return the number of references objects on the queue */ public int countWaitingReferences() { - Assert.notImplemented(); - return 0; + return currentRefs.size() + newRefs.size(); } } Modified: rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Scanning.java =================================================================== --- rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Scanning.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/ext/vm/harness/org/mmtk/harness/vm/Scanning.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -12,21 +12,32 @@ */ package org.mmtk.harness.vm; +import java.util.concurrent.BlockingQueue; + import org.mmtk.harness.Mutator; +import org.mmtk.harness.Mutators; +import org.mmtk.harness.lang.Trace; +import org.mmtk.harness.lang.Trace.Item; import org.mmtk.plan.TraceLocal; import org.mmtk.plan.TransitiveClosure; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.*; +/** + * + * + */ @Uninterruptible public class Scanning extends org.mmtk.vm.Scanning { /** * Delegated scanning of a object, processing each pointer field * encountered. + * @param trace The trace * * @param object The object to be scanned. */ + @Override public void scanObject(TransitiveClosure trace, ObjectReference object) { int refs = ObjectModel.getRefs(object); @@ -44,6 +55,7 @@ * @param trace The trace the method has been specialized for * @param object The object to be scanned */ + @Override public void specializedScanObject(int id, TransitiveClosure trace, ObjectReference object) { scanObject(trace, object); } @@ -55,12 +67,12 @@ * @param trace The trace object to use for precopying. * @param object The object to be scanned. */ + @Override public void precopyChildren(TraceLocal trace, ObjectReference object) { scanObject(trace, object); } - /** Counter for computeThreadRoots **/ - private int threadCounter; + private BlockingQueue<Mutator> mutatorsToScan = null; /** * Prepares for using the <code>computeAllRoots</code> method. The @@ -69,8 +81,10 @@ * parallel GC threads were not important, the thread counter could * simply be replaced by a for loop). */ + @Override public synchronized void resetThreadCounter() { - threadCounter = 0; + assert mutatorsToScan.size() == 0; + mutatorsToScan = null; } /** @@ -83,7 +97,9 @@ * included in the set of roots. The existence of this method * allows the actions of calculating roots and forwarding GC * instances to be decoupled. + * @param trace The MMTk trace object */ + @Override public void preCopyGCInstances(TraceLocal trace) { /* None */ } @@ -103,6 +119,7 @@ * * @param trace The trace to use for computing roots. */ + @Override public void computeStaticRoots(TraceLocal trace) { /* None */ } @@ -122,6 +139,7 @@ * * @param trace The trace to use for computing roots. */ + @Override public void computeGlobalRoots(TraceLocal trace) { /* None */ } @@ -142,18 +160,21 @@ * * @param trace The trace to use for computing roots. */ + @Override public void computeThreadRoots(TraceLocal trace) { + Trace.trace(Item.COLLECT,"Computing roots for mutators"); + synchronized(this) { + if (mutatorsToScan == null) { + mutatorsToScan = Mutators.getAll(); + } + } while(true) { - int myIndex; - synchronized(this) { - myIndex = threadCounter++; - } - - if (myIndex >= Mutator.count()) { + Trace.trace(Item.COLLECT,"mutators to scan: %d",mutatorsToScan.size()); + Mutator m = mutatorsToScan.poll(); + if (m == null) break; - } - - Mutator.get(myIndex).computeThreadRoots(trace); + Trace.trace(Item.COLLECT,"Computing roots for mutator"); + m.computeThreadRoots(trace); } } @@ -169,6 +190,7 @@ * * @param trace The trace object to use to report root locations. */ + @Override public void computeBootImageRoots(TraceLocal trace) { /* None */ } Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Collector.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Collector.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Collector.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -200,6 +200,7 @@ synchronized (this) { while (!started) { try { + /* Wait for the timeout thread to start running */ wait(); } catch (InterruptedException e) { } @@ -214,10 +215,13 @@ public void run() { long startTime = System.currentTimeMillis(); synchronized (this) { + /* Inform the caller that the timeout thread has started */ + started = true; + notify(); + while (!cancelled) { try { - started = true; - notify(); + /* Sleep until woken by a cancel or the timer has expired */ long now = System.currentTimeMillis(); if (now - startTime >= timeout) { System.err.printf("Collection exceeded timeout %dms%n",timeout); @@ -252,18 +256,20 @@ */ private void collect() { boolean primary = context.getId() == 0; - Sanity sanity = new Sanity(); + Sanity sanity = null; TimeoutThread timeout = null; + rendezvous(5000); if (primary) { Plan.setCollectionTrigger(Scheduler.getTriggerReason()); + sanity = new Sanity(); sanity.snapshotBefore(); timeout = new TimeoutThread(Harness.timeout.getValue()); } + rendezvous(5001); long startTime = System.nanoTime(); boolean internalPhaseTriggered = (Scheduler.getTriggerReason() == Collection.INTERNAL_PHASE_GC_TRIGGER); boolean userTriggered = (Scheduler.getTriggerReason() == Collection.EXTERNAL_GC_TRIGGER); - rendezvous(5000); do { context.collect(); @@ -306,8 +312,7 @@ if (Plan.isEmergencyCollection()) { boolean gcFailed = ActivePlan.plan.lastCollectionFailed(); // Allocate OOMEs (some of which *may* not get used) - for(int m=0; m < Mutator.count(); m++) { - Mutator mutator = Mutator.get(m); + for (Mutator mutator : Mutators.getAll()) { if (mutator.getCollectionAttempts() > 0) { /* this thread was allocating */ if (gcFailed || mutator.isPhysicalAllocationFailure()) { @@ -318,6 +323,7 @@ } } + rendezvous(5202); if (primary) { sanity.snapshotAfter(); sanity.assertSanity(); @@ -328,12 +334,10 @@ Mutator.dumpHeap(); heapDumpRequested = false; } - } - rendezvous(5202); - if (primary) { Plan.collectionComplete(); timeout.cancel(); } + rendezvous(5203); } } Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Harness.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Harness.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Harness.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -16,12 +16,14 @@ import org.mmtk.harness.options.*; import org.mmtk.harness.scheduler.AbstractPolicy; +import org.mmtk.harness.scheduler.MMTkThread; import org.mmtk.harness.vm.*; import org.mmtk.utility.Log; import org.mmtk.utility.heap.HeapGrowthManager; import org.mmtk.utility.options.Options; -import org.vmmagic.unboxed.ArchitecturalWord; +import org.vmmagic.unboxed.harness.ArchitecturalWord; +import org.vmutil.options.BooleanOption; /** * This is the central class for the MMTk test harness. @@ -64,18 +66,27 @@ /** Interval for the fixed scheduler policies */ public static final YieldInterval yieldInterval = new YieldInterval(); - /** Parameters for the random scheduler policy */ + /* Parameters for the random scheduler policy */ + /** Length of the pseudo-random yield interval sequence */ public static final RandomPolicyLength randomPolicyLength = new RandomPolicyLength(); + /** Seed for the pseudo-random yield interval sequence */ public static final RandomPolicySeed randomPolicySeed = new RandomPolicySeed(); + /** Minimum value of each entry in the pseudo-random yield interval sequence */ public static final RandomPolicyMin randomPolicyMin = new RandomPolicyMin(); + /** Maximum value of each entry in the pseudo-random yield interval sequence */ public static final RandomPolicyMax randomPolicyMax = new RandomPolicyMax(); /** Print yield policy statistics on exit */ public static final PolicyStats policyStats = new PolicyStats(); + /** A set of objects to watch */ + public static final WatchObject watchObject = new WatchObject(); + /** Timeout on unreasonably long GC */ public static final Timeout timeout = new Timeout(); + public static final BooleanOption sanityUsesReadBarrier = new SanityUsesReadBarrier(); + private static boolean isInitialized = false; /** @@ -83,6 +94,7 @@ * and starting off the collector threads. * * After calling this it is possible to begin creating mutator threads. + * @param args Command-line arguments */ public static void init(String... args) { if (isInitialized) { @@ -102,7 +114,7 @@ options.process(arg); } } - ArchitecturalWord.init(); // Reads 'bits' + ArchitecturalWord.init(Harness.bits.getValue()); // Reads 'bits' for(String arg: args) { if (!options.process(arg)) newArgs.add(arg); } @@ -115,6 +127,7 @@ * give it a per-thread 'Log' object */ MMTkThread m = new MMTkThread() { + @Override public void run() { /* Get MMTk breathing */ @@ -125,7 +138,6 @@ /* Override some defaults */ Options.noFinalizer.setValue(true); - Options.noReferenceTypes.setValue(true); Options.variableSizeHeap.setValue(false); /* Process command line options */ @@ -137,7 +149,6 @@ /* Check options */ assert Options.noFinalizer.getValue(): "noFinalizer must be true"; - assert Options.noReferenceTypes.getValue(): "noReferenceTypes must be true"; /* Finish starting up MMTk */ ActivePlan.plan.postBoot(); @@ -153,9 +164,15 @@ org.mmtk.harness.scheduler.Scheduler.initCollectors(); + for (int value : watchObject.getValue()) { + System.out.printf("Setting watch for object %d%n", value); + org.mmtk.harness.vm.ObjectModel.watchObject(value); + } + /* Add exit handler to print yield stats */ if (policyStats.getValue()) { Runtime.getRuntime().addShutdownHook(new Thread() { + @Override public void run() { AbstractPolicy.printStats(); } Deleted: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/MMTkThread.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/MMTkThread.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/MMTkThread.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -1,55 +0,0 @@ -/* - * This file is part of the Jikes RVM project (http://jikesrvm.org). - * - * This file is licensed to You under the Eclipse Public License (EPL); - * You may not use this file except in compliance with the License. You - * may obtain a copy of the License at - * - * http://www.opensource.org/licenses/eclipse-1.0.php - * - * See the COPYRIGHT.txt file distributed with this work for information - * regarding copyright ownership. - */ -package org.mmtk.harness; - -import org.mmtk.utility.Log; - -public class MMTkThread extends Thread { - - /** The per-thread Log instance */ - protected final Log log = new Log(); - - public MMTkThread() { - super(); - trapUncaughtExceptions(); - } - - public MMTkThread(Runnable target, String name) { - super(target, name); - trapUncaughtExceptions(); - } - - public MMTkThread(Runnable target) { - super(target); - trapUncaughtExceptions(); - } - - public MMTkThread(String name) { - super(name); - trapUncaughtExceptions(); - } - - private void trapUncaughtExceptions() { - setUncaughtExceptionHandler(new UncaughtExceptionHandler() { - public void uncaughtException(Thread t, Throwable e) { - System.err.print("Unexpected exception: "); - e.printStackTrace(); - System.exit(1); - } - }); - } - - public final Log getLog() { - return log; - } -} Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutator.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutator.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutator.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -12,11 +12,11 @@ */ package org.mmtk.harness; -import java.util.ArrayList; +import java.util.ArrayDeque; import java.util.Collections; +import java.util.Deque; import java.util.HashSet; import java.util.Set; -import java.util.Stack; import org.mmtk.harness.lang.Trace; import org.mmtk.harness.lang.Trace.Item; @@ -32,6 +32,7 @@ import org.mmtk.vm.VM; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.ObjectReference; +import org.vmmagic.unboxed.Word; /** * This class represents a mutator thread that has memory managed by MMTk. @@ -46,6 +47,7 @@ * that a GC can not occur unless you execute commands on the mutator (or muEnd it). */ public abstract class Mutator { + private static boolean gcEveryWB = false; /** @@ -55,55 +57,48 @@ gcEveryWB = true; } - /** Registered mutators */ - protected static final ArrayList<Mutator> mutators = new ArrayList<Mutator>(); - /** - * @return The active mutators + * @return A mutator context for the current Plan */ - public static java.util.Collection<Mutator> getMutators() { - return Collections.unmodifiableCollection(mutators); + public static MutatorContext createMutatorContext() { + try { + String prefix = Harness.plan.getValue(); + return (MutatorContext)Class.forName(prefix + "Mutator").newInstance(); + } catch (Exception ex) { + throw new RuntimeException("Could not create Mutator", ex); + } } /** - * Get a mutator by id. - */ - public static Mutator get(int id) { - return mutators.get(id); - } - - /** * Get the currently executing mutator. + * @return the currently executing mutator. */ public static Mutator current() { return Scheduler.currentMutator(); } /** - * Return the number of mutators that have been created. - */ - public static int count() { - return mutators.size(); - } - - /** * Register a mutator, returning the allocated id. + * @param context The mutator context to register */ - public static synchronized void register(MutatorContext context) { - int id = mutators.size(); - mutators.add(null); - context.initMutator(id); + private static synchronized void register(MutatorContext context) { + context.initMutator(Mutators.registerMutator()); } /** Is this thread out of memory if the gc cannot free memory */ private boolean outOfMemory; - /** Get the out of memory status */ + /** Get the out of memory status + * @return True if we're subject to an out-of-memory condition + */ public boolean isOutOfMemory() { return outOfMemory; } - /** Set the out of memory status */ + /** + * Set the out of memory status + * @param value The status + */ public void setOutOfMemory(boolean value) { outOfMemory = value; } @@ -111,7 +106,9 @@ /** The number of collection attempts this thread has had since allocation succeeded */ private int collectionAttempts; - /** Get the number of collection attempts */ + /** + * @return the number of collection attempts + */ public int getCollectionAttempts() { return collectionAttempts; } @@ -129,12 +126,16 @@ /** Was the last failure a physical allocation failure (rather than a budget failure) */ private boolean physicalAllocationFailure; - /** Was the last failure a physical allocation failure */ + /** + * Was the last failure a physical allocation failure + * @return Was the last failure a physical allocation failure + */ public boolean isPhysicalAllocationFailure() { return physicalAllocationFailure; } - /** Set if last failure a physical allocation failure */ + /** Set if last failure a physical allocation failure + * @param value The new status */ public void setPhysicalAllocationFailure(boolean value) { physicalAllocationFailure = value; } @@ -143,50 +144,22 @@ protected final MutatorContext context; /** - * The type of exception that is expected at the end of execution. + * Constructor */ - private Class<?> expectedThrowable; - - /** - * Set an expectation that the execution will exit with a throw of this exception. - */ - public void setExpectedThrowable(Class<?> expectedThrowable) { - this.expectedThrowable = expectedThrowable; - } - public Mutator() { - try { - String prefix = Harness.plan.getValue(); - this.context = (MutatorContext)Class.forName(prefix + "Mutator").newInstance(); - register(this.context); - } catch (Exception ex) { - throw new RuntimeException("Could not create Mutator", ex); - } + this.context = createMutatorContext(); + register(this.context); } - public void begin() { - mutators.set(context.getId(), this); - } - /** - * Mutator-specific handling of uncaught exceptions. - * @param t - * @param e + * Initial processing of a mutator. Enters the mutator in the mutator table. */ - public void uncaughtException(Thread t, Throwable e) { - if (e.getClass() == expectedThrowable) { - System.err.println("Mutator " + context.getId() + " exiting due to expected exception of class " + expectedThrowable); - expectedThrowable = null; - end(); - } else { - System.err.print("Mutator " + context.getId() + " caused unexpected exception: "); - e.printStackTrace(); - System.exit(1); - } + public void begin() { + Mutators.set(this); } /** - * Return the MMTk MutatorContext for this mutator. + * @return the MMTk MutatorContext for this mutator. */ public MutatorContext getContext() { return context; @@ -194,6 +167,7 @@ /** * Compute the thread roots for this mutator. + * @param trace The MMTk TraceLocal to receive the roots */ public void computeThreadRoots(TraceLocal trace) { // Nothing to do for the default mutator @@ -201,14 +175,17 @@ /** * Return the roots + * @return The roots for this mutator */ public abstract Iterable<ObjectValue> getRoots(); /** - * Print the thread roots and add them to a stack for processing. + * Print the thread roots and return them for processing. + * @param width Output width + * @return The thread roots */ - public void dumpThreadRoots(int width, Stack<ObjectReference> roots) { - // Nothing to do for the default mutator + public java.util.Collection<ObjectReference> dumpThreadRoots(int width) { + return Collections.emptyList(); } /** @@ -216,24 +193,25 @@ */ public static void dumpHeap() { int width = Integer.toHexString(ObjectModel.nextObjectId()).length()+8; - Stack<ObjectReference> workStack = new Stack<ObjectReference>(); + Deque<ObjectReference> workStack = new ArrayDeque<ObjectReference>(); Set<ObjectReference> dumped = new HashSet<ObjectReference>(); - for(Mutator m: mutators) { + for(Mutator m: Mutators.getAll()) { System.err.println("Mutator " + m.context.getId()); - m.dumpThreadRoots(width, workStack); + workStack.addAll(m.dumpThreadRoots(width)); } System.err.println("Heap (Depth First)"); while(!workStack.isEmpty()) { ObjectReference object = workStack.pop(); if (!dumped.contains(object)) { dumped.add(object); - ObjectModel.dumpLogicalObject(width, object, workStack); + workStack.addAll(ObjectModel.dumpLogicalObject(width, object)); } } } -/** + /** * A gc safe point for the mutator. + * @return Whether a GC has occurred */ public boolean gcSafePoint() { if (Scheduler.gcTriggered()) { @@ -244,20 +222,10 @@ } /** - * An out of memory error originating from within MMTk. - * - * Tests that try to exercise out of memory conditions can catch this exception. - */ - public static class OutOfMemory extends RuntimeException { - public static final long serialVersionUID = 1; - } - - /** * Mark a mutator as no longer active. If a GC has been triggered we must ensure * that it proceeds before we deactivate. */ public void end() { - check(expectedThrowable == null, "Expected exception of class " + expectedThrowable + " not found"); } /** @@ -277,7 +245,7 @@ /** * Fail during execution. - * @param failMessage + * @param failMessage Message to write */ public void fail(String failMessage) { check(false, failMessage); @@ -292,6 +260,8 @@ /** * Assert that the given condition is true or print the failure message. + * @param condition The condition to check + * @param failMessage The message to exit with */ public void check(boolean condition, String failMessage) { if (!condition) throw new RuntimeException(failMessage); @@ -347,6 +317,7 @@ * * @param object The object to load the field of. * @param index The field index. + * @return The contents of the data field */ public int loadDataField(ObjectReference object, int index) { int limit = ObjectModel.getDataCount(object); @@ -365,6 +336,7 @@ * * @param object The object to load the field of. * @param index The field index. + * @return The object reference */ public ObjectReference loadReferenceField(ObjectReference object, int index) { int limit = ObjectModel.getRefs(object); @@ -375,16 +347,19 @@ Address referenceSlot = ObjectModel.getRefSlot(object, index); ObjectReference result; if (ActivePlan.constraints.needsReadBarrier()) { - result = context.readBarrier(object, referenceSlot, null, null, Plan.AASTORE_WRITE_BARRIER); + result = context.readBarrier(object, referenceSlot, null, null, Plan.GETFIELD_READ_BARRIER); } else { result = referenceSlot.loadObjectReference(); } + assert result.toAddress().toWord().and(Word.fromIntZeroExtend(0x3)).EQ(Word.zero()); Trace.trace(Item.LOAD,"[%s].object[%d] returned [%s]",ObjectModel.getString(object),index,result.toString()); return result; } /** * Get the hash code for the given object. + * @param object The object + * @return The hash code */ public int hash(ObjectReference object) { check(!object.isNull(), "Object can not be null"); @@ -415,8 +390,8 @@ /** * Return a string identifying the allocation site of an object - * @param object - * @return + * @param object The object + * @return Where in the script it was allocated */ public static String getSiteName(ObjectReference object) { return AllocationSite.getSite(ObjectModel.getSite(object)).toString(); Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutators.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutators.java (rev 0) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/Mutators.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -0,0 +1,61 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.mmtk.harness; + +import java.util.ArrayList; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +/** + * The collection of mutators + */ +public final class Mutators { + + /** Registered mutators */ + private static final ArrayList<Mutator> mutators = new ArrayList<Mutator>(); + + private static int nextId = 0; + + /** + * Register a mutator, reserving a slot in the list + * @return The reserved slot number + */ + static synchronized int registerMutator() { + return nextId++; + } + + /** + * Complete the registration of a mutator, by inserting the initialized + * object in the allocated slot. + * @param id + * @param m + */ + static synchronized void set(Mutator m) { + mutators.add(m); + } + + /** + * Return the collection of valid mutators, as a blocking queue + * (so that it's synchronized - don't call 'take' on an empty queue ...) + * @return The non-null mutators + */ + public static synchronized BlockingQueue<Mutator> getAll() { + BlockingQueue<Mutator> result = new ArrayBlockingQueue<Mutator>(mutators.size()+1); + for (Mutator m : mutators) { + if (m != null) { + result.add(m); + } + } + return result; + } +} Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/OutOfMemory.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/OutOfMemory.java (rev 0) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/exception/OutOfMemory.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -0,0 +1,22 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.mmtk.harness.exception; + +/** + * An out of memory error originating from within MMTk. + * + * Tests that try to exercise out of memory conditions can catch this exception. + */ +public class OutOfMemory extends RuntimeException { + private static final long serialVersionUID = 1; +} Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Env.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Env.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Env.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -16,7 +16,6 @@ import java.util.Collection; import java.util.List; import java.util.Random; -import java.util.Stack; import org.mmtk.harness.Mutator; import org.mmtk.harness.lang.Trace.Item; @@ -35,21 +34,29 @@ /** * The stack */ - private UnsyncStack<StackFrame> stack = new UnsyncStack<StackFrame>(); + private final UnsyncStack<StackFrame> stack = new UnsyncStack<StackFrame>(); /** * A source of random numbers (we have one per thread so that we can write * deterministic scripts). */ - private Random rng = new Random(); + private final Random rng = new Random(); + /** + * The type of exception that is expected at the end of execution. + */ + private Class<?> expectedThrowable; + + /** + * Enable a CG on every safepoint + */ public static void setGcEverySafepoint() { gcEverySafepoint = true; } /** * Enter a new procedure, pushing a new stack frame. - * @param frame + * @param frame Stack frame to push */ public void push(StackFrame frame) { stack.push(frame); @@ -90,6 +97,9 @@ Trace.trace(Item.ROOTS, "Locals: %d", localCount); } + /** + * @see org.mmtk.harness.Mutator#getRoots() + */ @Override public Collection<ObjectValue> getRoots() { List<ObjectValue> roots = new ArrayList<ObjectValue>(); @@ -103,17 +113,22 @@ * Print the thread roots and add them to a stack for processing. */ @Override - public void dumpThreadRoots(int width, Stack<ObjectReference> roots) { + public Collection<ObjectReference> dumpThreadRoots(int width) { int frameId = 0; + List<ObjectReference> roots = new ArrayList<ObjectReference>(); for (StackFrame frame : stack) { System.err.printf(" Frame %5d [", frameId++); - frame.dumpRoots(width, roots); + roots.addAll(frame.dumpRoots(width)); System.err.println(" ]"); } System.err.println(); + return roots; } + /** + * @see org.mmtk.harness.Mutator#gcSafePoint() + */ @Override public boolean gcSafePoint() { if (gcEverySafepoint) { @@ -123,6 +138,42 @@ } + /** + * @see org.mmtk.harness.Mutator#end() + */ + @Override + public void end() { + check(expectedThrowable == null, "Expected exception of class " + expectedThrowable + " not found"); + super.end(); + } + + /** + * Set an expectation that the execution will exit with a throw of this exception. + * @param expectedThrowable The expected exception class + */ + public void setExpectedThrowable(Class<?> expectedThrowable) { + Trace.trace(Item.EXCEPTION, "Setting expected exception %s", expectedThrowable.getCanonicalName()); + this.expectedThrowable = expectedThrowable; + } + + /** + * Mutator-specific handling of uncaught exceptions. The scheduler calls this when + * it catches an unhandled exception. + * @param t Thread object + * @param e Exception + */ + public void uncaughtException(Thread t, Throwable e) { + Trace.trace(Item.EXCEPTION, "Processing uncaught exception %s", e.getClass().getCanonicalName()); + if (e.getClass() == expectedThrowable) { + System.err.println("Mutator " + context.getId() + " exiting due to expected exception of class " + expectedThrowable); + System.exit(0); + } else { + System.err.print("Mutator " + context.getId() + " caused unexpected exception: "); + e.printStackTrace(); + System.exit(1); + } + } + /******************************************************************* * Utility methods */ @@ -133,4 +184,5 @@ public Random random() { return rng; } + } Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -12,8 +12,12 @@ */ package org.mmtk.harness.lang; +import org.mmtk.harness.Harness; import org.mmtk.harness.Mutator; import org.mmtk.harness.lang.runtime.ObjectValue; +import org.mmtk.harness.lang.runtime.PhantomReferenceValue; +import org.mmtk.harness.lang.runtime.SoftReferenceValue; +import org.mmtk.harness.lang.runtime.WeakReferenceValue; import org.mmtk.vm.Collection; import org.mmtk.vm.VM; @@ -25,8 +29,7 @@ public class Intrinsics { /** * Force GC - * @param env - * @return + * @param env Thread-local environment (language-dependent mutator context) */ public static void gc(Env env) { VM.collection.triggerCollection(Collection.EXTERNAL_GC_TRIGGER); @@ -34,8 +37,8 @@ /** * Return the thread ID - * @param env - * @return + * @param env Thread-local environment (language-dependent mutator context) + * @return the thread ID */ public static int threadId(Env env) { return Mutator.current().getContext().getId(); @@ -43,18 +46,18 @@ /** * Return the (identity) hash code - * @param env - * @param val - * @return + * @param env Thread-local environment (language-dependent mutator context) + * @param val The object to hash + * @return the (identity) hash code */ public static int hash(Env env, ObjectValue val) { return env.hash(val.getObjectValue()); } /** - * Set the random seed for this thread - * @param env - * @param seed + * Set the random number generator seed for this thread + * @param env Thread-local environment (language-dependent mutator context) + * @param seed Pseudo-random seed value */ public static void setRandomSeed(Env env, int seed) { env.random().setSeed(seed); @@ -62,10 +65,10 @@ /** * A random integer in the closed interval [low..high]. - * @param env - * @param low - * @param high - * @return + * @param env Thread-local environment (language-dependent mutator context) + * @param low Low bound (inclusive) + * @param high High bound (inclusive) + * @return A random integer in the closed interval [low..high] */ public static int random(Env env, int low, int high) { return env.random().nextInt(high-low+1) + low; @@ -73,6 +76,7 @@ /** * Dump the heap + * @param env Thread-local environment (language-dependent mutator context) */ public static void heapDump(Env env) { Mutator.dumpHeap(); @@ -80,9 +84,83 @@ /** * Unit test method for the Intrinsic method + * @param env Thread-local environment (language-dependent mutator context) + * @param x An int + * @param y A boolean + * @param string A string + * @param val An object + * @return The string representation of <code>val</code> */ public static String testMethod(Env env, int x, boolean y, String string, ObjectValue val) { return String.format("successfully called testMethod(%d,%b,%s,%s)", x,y,string,val.toString()); } + /** + * @param env Thread-local environment (language-dependent mutator context) + * @param referent The object to weakly refer to + * @return The created weak reference value + * + */ + public static WeakReferenceValue weakRef(Env env, ObjectValue referent) { + return new WeakReferenceValue(referent.getObjectValue()); + } + + /** + * @param env Thread-local environment (language-dependent mutator context) + * @param referent The object to weakly refer to + * @return The created weak reference value + * + */ + public static SoftReferenceValue softRef(Env env, ObjectValue referent) { + return new SoftReferenceValue(referent.getObjectValue()); + } + + /** + * @param env Thread-local environment (language-dependent mutator context) + * @param referent The object to weakly refer to + * @return The created weak reference value + * + */ + public static PhantomReferenceValue phantomRef(Env env, ObjectValue referent) { + return new PhantomReferenceValue(referent.getObjectValue()); + } + + /** + * Dereference a reference type + * @param env Thread-local environment (language-dependent mutator context) + * @param value The reference value + * @return The referent + */ + public static ObjectValue getReferent(Env env, WeakReferenceValue value) { + return new ObjectValue(value.getObjectValue()); + } + /** + * Dereference a reference type + * @param env Thread-local environment (language-dependent mutator context) + * @param value The reference value + * @return The referent + */ + public static ObjectValue getReferent(Env env, SoftReferenceValue value) { + return new ObjectValue(value.getObjectValue()); + } + /** + * Dereference a reference type + * @param env Thread-local environment (language-dependent mutator context) + * @param value The reference value + * @return The referent + */ + public static ObjectValue getReferent(Env env, PhantomReferenceValue value) { + return new ObjectValue(value.getObjectValue()); + } + + /** + * Set a command-line option from within a script + * @param env Thread-local environment (language-dependent mutator context) + * @param option The command-line option + */ + public static void setOption(Env env, String option) { + if (!Harness.options.process(option)) { + System.err.println("Error processing option "+option); + } + } } Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -18,6 +18,7 @@ import java.io.PrintStream; import java.util.Iterator; +import org.mmtk.harness.Harness; import org.mmtk.harness.lang.ast.AST; import org.mmtk.harness.lang.ast.Alloc; import org.mmtk.harness.lang.ast.AllocUserType; @@ -43,21 +44,37 @@ import org.mmtk.harness.lang.ast.WhileStatement; import org.mmtk.harness.lang.parser.MethodTable; import org.mmtk.harness.lang.parser.Parser; -import org.vmmagic.unboxed.ArchitecturalWord; +import org.vmmagic.unboxed.harness.ArchitecturalWord; +/** + * Format an AST back into Harness script-language code + * + * Implemented as a visitor over the AST + */ public class PrettyPrinter extends Visitor { private final OutputFormatter fmt; + /** + * Create a pretty printer that sends output to an internal buffer + */ public PrettyPrinter() { - fmt = new OutputFormatter(); + this(new OutputFormatter()); } + /** + * @param stream Where to send the output + */ public PrettyPrinter(PrintStream stream) { - fmt = new OutputFormatter(stream); + this(new OutputFormatter(stream)); } - private class OutputFormatter { + + private PrettyPrinter(OutputFormatter outputFormatter) { + fmt = outputFormatter; + } + + private static class OutputFormatter { private static final int INDENT = 2; private int indent = 0; private boolean pendingIndent = false; @@ -103,6 +120,11 @@ } + /** + * Visit a method definition + * + * @see org.mmtk.harness.lang.Visitor#visit(org.mmtk.harness.lang.ast.NormalMethod) + */ @Override public Object visit(NormalMethod method) { fmt.out("%s %s(",method.getReturnType(),method.getName()); @@ -123,6 +145,11 @@ return null; } + /** + * Visit a method-call + * + * @see org.mmtk.harness.lang.Visitor#visit(org.mmtk.harness.lang.ast.Call) + */ @Override public Object visit(Call call) { fmt.out("%s(",call.getMethod().getName()); @@ -159,27 +186,22 @@ public Object visit(IfStatement conditional) { String keyword = "if"; Iterator<Expression> condIter = conditional.getConds().iterator(); - Iterator<Statement> bodyIter = conditional.getStmts().iterator(); - while (condIter.hasNext() && bodyIter.hasNext()) { - Expression cond = condIter.next(); - Statement body = bodyIter.next(); - fmt.out("%s (", keyword); - cond.accept(this); - fmt.out(") {"); fmt.newline(); + for (Statement body : conditional.getStmts()) { + if (condIter.hasNext()) { + Expression cond = condIter.next(); + fmt.out("%s (", keyword); + cond.accept(this); + fmt.out(") {"); fmt.newline(); + keyword = "elif"; + } else { + fmt.out("else {"); fmt.newline(); + } fmt.increaseIndent(); body.accept(this); fmt.decreaseIndent(); fmt.out("} "); - keyword = "elif"; } - if (bodyIter.hasNext()) { - fmt.out("else {"); fmt.newline(); - fmt.increaseIndent(); - bodyIter.next().accept(this); - fmt.decreaseIndent(); - fmt.out("}"); - } return null; } @@ -376,7 +398,7 @@ } public static void main(String[] args) { - ArchitecturalWord.init(); + ArchitecturalWord.init(Harness.bits.getValue()); try { MethodTable methods = new Parser(new BufferedInputStream(new FileInputStream(args[0]))).script(); PrettyPrinter.printMethodTable(methods); Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Trace.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Trace.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/Trace.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -32,6 +32,7 @@ /** Harness language semantic checker */ CHECKER, /** Garbage collection */ COLLECT, /** P-code compiler */ COMPILER, + /** Expected exceptions */ EXCEPTION, /** Environment (stack frame) loads/stores */ ENV, /** P-code evaluation */ EVAL, /** Hashcode operations */ HASH, Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -23,21 +23,29 @@ /** * Constructor + * @param t The Parser token corresponding to this entity + * @param name The exception name */ public Expect(Token t, String name) { super(t); try { - expectedThrowable = Class.forName("org.mmtk.harness.Mutator$" + name); + expectedThrowable = Class.forName("org.mmtk.harness.exception." + name); } catch (ClassNotFoundException cnfe) { throw new RuntimeException(cnfe); } } + /** + * @see org.mmtk.harness.lang.ast.AbstractAST#accept(org.mmtk.harness.lang.Visitor) + */ @Override public Object accept(Visitor v) { return v.visit(this); } + /** + * @return The expected exception class + */ public Class<?> getExpected() { return expectedThrowable; } Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -22,8 +22,11 @@ import org.mmtk.harness.lang.runtime.BoolValue; import org.mmtk.harness.lang.runtime.IntValue; import org.mmtk.harness.lang.runtime.ObjectValue; +import org.mmtk.harness.lang.runtime.PhantomReferenceValue; +import org.mmtk.harness.lang.runtime.SoftReferenceValue; import org.mmtk.harness.lang.runtime.StringValue; import org.mmtk.harness.lang.runtime.Value; +import org.mmtk.harness.lang.runtime.WeakReferenceValue; import org.mmtk.harness.lang.type.Type; /** @@ -65,8 +68,14 @@ return Type.BOOLEAN; } else if (externalType.equals(void.class)) { return Type.VOID; + } else if (externalType.equals(WeakReferenceValue.class)) { + return Type.WEAKREF; + } else if (externalType.equals(SoftReferenceValue.class)) { + return Type.SOFTREF; + } else if (externalType.equals(PhantomReferenceValue.class)) { + return Type.PHANTOMREF; } - return null; + throw new RuntimeException("Invalid return type for intrinsic method, "+externalType.getCanonicalName()); } /** @@ -147,6 +156,10 @@ /** * Constructor + * @param name The name of the method in the scripting language + * @param className The class that implements the method + * @param methodName The name of the method in the implementing class + * @param params The types of the parameters */ public IntrinsicMethod(String name, String className, String methodName, List<String> params) { this(name,className, methodName,classesForParams(params)); @@ -231,6 +244,8 @@ } else if (obj instanceof Boolean) { assert returnType == Type.BOOLEAN : "mismatched return types"; return BoolValue.valueOf(((Boolean)obj).booleanValue()); + } else if (obj instanceof Value) { + return (Value)obj; } throw new RuntimeException("Can't unmarshall a "+obj.getClass().getCanonicalName()); } Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/parser/GlobalDefs.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/parser/GlobalDefs.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/parser/GlobalDefs.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -14,6 +14,9 @@ import org.mmtk.harness.lang.ast.IntrinsicMethod; import org.mmtk.harness.lang.runtime.ObjectValue; +import org.mmtk.harness.lang.runtime.PhantomReferenceValue; +import org.mmtk.harness.lang.runtime.SoftReferenceValue; +import org.mmtk.harness.lang.runtime.WeakReferenceValue; import org.mmtk.harness.lang.type.Type; /** @@ -27,7 +30,7 @@ * The types - predeclared ones are passed to the constructor */ public final TypeTable types = new TypeTable(Type.INT,Type.STRING,Type.BOOLEAN, - Type.OBJECT,Type.VOID); + Type.OBJECT,Type.VOID,Type.WEAKREF,Type.SOFTREF,Type.PHANTOMREF); private final String intrinsics = "org.mmtk.harness.lang.Intrinsics"; @@ -41,6 +44,20 @@ new IntrinsicMethod("random",intrinsics,"random", new Class<?>[] { int.class, int.class }), new IntrinsicMethod("setSeed",intrinsics,"setRandomSeed", new Class<?>[] { int.class }), - new IntrinsicMethod("heapDump",intrinsics,"heapDump") + new IntrinsicMethod("heapDump",intrinsics,"heapDump"), + new IntrinsicMethod("weakRef",intrinsics,"weakRef", + new Class<?>[] { ObjectValue.class }), + new IntrinsicMethod("getWeakReferent",intrinsics,"getReferent", + new Class<?>[] { WeakReferenceValue.class }), + new IntrinsicMethod("softRef",intrinsics,"softRef", + new Class<?>[] { ObjectValue.class }), + new IntrinsicMethod("getSoftReferent",intrinsics,"getReferent", + new Class<?>[] { SoftReferenceValue.class }), + new IntrinsicMethod("phantomRef",intrinsics,"phantomRef", + new Class<?>[] { ObjectValue.class }), + new IntrinsicMethod("getPhantomReferent",intrinsics,"getReferent", + new Class<?>[] { PhantomReferenceValue.class }), + new IntrinsicMethod("setOption",intrinsics,"setOption", new Class[] { String.class }) + ); } Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocOp.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocOp.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocOp.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -13,7 +13,7 @@ package org.mmtk.harness.lang.pcode; import org.mmtk.harness.Harness; -import org.mmtk.harness.Mutator.OutOfMemory; +import org.mmtk.harness.exception.OutOfMemory; import org.mmtk.harness.lang.Env; import org.mmtk.harness.lang.ast.AST; import org.mmtk.harness.lang.compiler.Register; Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocUserOp.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocUserOp.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/pcode/AllocUserOp.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -13,7 +13,7 @@ package org.mmtk.harness.lang.pcode; import org.mmtk.harness.Harness; -import org.mmtk.harness.Mutator.OutOfMemory; +import org.mmtk.harness.exception.OutOfMemory; import org.mmtk.harness.lang.Env; import org.mmtk.harness.lang.ast.AST; import org.mmtk.harness.lang.compiler.Register; Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -29,7 +29,7 @@ /** * The reference to the heap object * - * Not final because it may change during GC + * Not final because it may change during GC. */ private ObjectReference value; Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/PhantomReferenceValue.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/PhantomReferenceValue.java (rev 0) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/PhantomReferenceValue.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -0,0 +1,43 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.mmtk.harness.lang.runtime; + +import org.mmtk.harness.lang.type.Type; +import org.mmtk.vm.ReferenceProcessor.Semantics; +import org.vmmagic.unboxed.ObjectReference; + +/** + * A weak reference in the MMTk Harness language + */ +public class PhantomReferenceValue extends ReferenceValue { + + /** + * The NULL weak reference + */ + public static final ReferenceValue NULL = new PhantomReferenceValue(ObjectReference.nullReference()); + + /** + * @param ref The referent + */ + public PhantomReferenceValue(ObjectReference ref) { + super(ref,Semantics.PHANTOM); + } + + /** + * @see org.mmtk.harness.lang.runtime.Value#type() + */ + @Override + public Type type() { + return Type.PHANTOMREF; + } +} Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ReferenceValue.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ReferenceValue.java (rev 0) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/ReferenceValue.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -0,0 +1,84 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.mmtk.harness.lang.runtime; + +import org.mmtk.harness.lang.Trace; +import org.mmtk.harness.lang.Trace.Item; +import org.mmtk.harness.vm.ObjectModel; +import org.mmtk.plan.TraceLocal; +import org.mmtk.vm.ReferenceProcessor.Semantics; +import org.vmmagic.unboxed.ObjectReference; + +/** + * Moral equivalent of java.lang.ref.Reference + */ +public abstract class ReferenceValue extends Value { + + private ObjectReference ref; + private final Semantics semantics; + private boolean cleared = false; + + protected ReferenceValue(ObjectReference ref, Semantics semantics) { + this.ref = ref; + this.semantics = semantics; + } + + public void clear() { + Trace.trace(Item.REFERENCES, "Clearing reference %s", this); + cleared = true; + } + + /** + * @see org.mmtk.harness.lang.runtime.Value#getObjectValue() + */ + public ObjectReference getObjectValue() { + return cleared ? ObjectReference.nullReference() : ref; + } + + /** + * @return The reference semantics + */ + public Semantics getSemantics() { + return semantics; + } + + /** + * @see org.mmtk.harness.lang.runtime.Value#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + return this == o; + } + + /** + * GC-time processing of the contained object + * @param trace The MMTk trace + */ + public void traceObject(TraceLocal trace) { + String before = ObjectModel.getString(ref); + ref = trace.traceObject(ref, true); + Trace.trace(Item.REFERENCES, "Forwarded reference %x: %s reference (%s -> %s)", + System.identityHashCode(this), semantics, before, ObjectModel.getString(ref)); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public String toString() { + return String.format("%x: %s reference (-> %s)", System.identityHashCode(this), semantics, ObjectModel.getString(ref)); + } +} + Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/SoftReferenceValue.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/SoftReferenceValue.java (rev 0) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/SoftReferenceValue.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -0,0 +1,43 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.mmtk.harness.lang.runtime; + +import org.mmtk.harness.lang.type.Type; +import org.mmtk.vm.ReferenceProcessor.Semantics; +import org.vmmagic.unboxed.ObjectReference; + +/** + * A weak reference in the MMTk Harness language + */ +public class SoftReferenceValue extends ReferenceValue { + + /** + * The NULL weak reference + */ + public static final ReferenceValue NULL = new SoftReferenceValue(ObjectReference.nullReference()); + + /** + * @param ref The referent + */ + public SoftReferenceValue(ObjectReference ref) { + super(ref,Semantics.SOFT); + } + + /** + * @see org.mmtk.harness.lang.runtime.Value#type() + */ + @Override + public Type type() { + return Type.SOFTREF; + } +} Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -15,7 +15,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Stack; import org.mmtk.harness.lang.Declaration; import org.mmtk.harness.lang.Trace; @@ -23,6 +22,7 @@ import org.mmtk.harness.lang.pcode.PseudoOp; import org.mmtk.harness.lang.type.Type; import org.mmtk.harness.vm.ObjectModel; +import org.mmtk.harness.vm.ReferenceProcessor; import org.mmtk.plan.TraceLocal; import org.vmmagic.unboxed.ObjectReference; @@ -53,7 +53,11 @@ /** The slot for the return value of a method call */ private int resultSlot = NO_SUCH_SLOT; - /** Create a stack frame, given a list of declarations and a quantity of temporaries */ + /** + * Create a stack frame, given a list of declarations and a quantity of temporaries + * @param decls Variables declared in this stack frame + * @param nTemp Number of temporaries + */ public StackFrame(List<Declaration> decls, int nTemp) { int size = decls.size()+nTemp; this.values = new Value[size]; @@ -70,6 +74,7 @@ /** * Declare a variable in a given slot. Only used when tracing. + * @param d The variable declaration */ public void declare(Declaration d) { values[d.getSlot()] = d.getInitial(); @@ -78,6 +83,8 @@ /** * Return the variable at the given slot in the current stack frame + * @param slot The stack frame slot + * @return The value in the slot */ public Value get(int slot) { if (slot >= 0) { @@ -88,6 +95,8 @@ /** * Return the type of the variable at the given slot. + * @param slot The stack frame slot + * @return The type of the value in the slot */ public Type getType(int slot) { return values[slot].type(); @@ -95,6 +104,8 @@ /** * Assign a new value to the given slot + * @param slot Stack-frame slot to modify + * @param value New value */ public void set(int slot, Value value) { assert value != null : "Unexpected null value"; @@ -134,6 +145,10 @@ rootCount++; } } + Trace.trace(Item.REFERENCES, "Discovering references"); + for (ReferenceValue reference : getReferences()) { + ReferenceProcessor.discover(reference); + } return rootCount; } @@ -152,11 +167,26 @@ } /** + * + * @return The root ReferenceValues for this stack frame + */ + private Collection<ReferenceValue> getReferences() { + List<ReferenceValue> roots = new ArrayList<ReferenceValue>(); + for (Value value : values) { + if (value != null && value instanceof ReferenceValue) { + roots.add((ReferenceValue)value); + } + } + return roots; + } + + /** * Debug printing support: dump this stack frame and return roots. * @param width Output field width - * @param roots Root references + * @return The collection of roots in this frame */ - public void dumpRoots(int width, Stack<ObjectReference> roots) { + public Collection<ObjectReference> dumpRoots(int width) { + List<ObjectReference> roots = new ArrayList<ObjectReference>(); for (int i=0; i < values.length; i++) { Value value = values[i]; String name; @@ -168,45 +198,59 @@ if (value != null && value instanceof ObjectValue) { ObjectReference ref = ((ObjectValue)value).getObjectValue(); System.err.printf(" %s=%s", name, ObjectModel.formatObject(width, ref)); - if (!ref.isNull()) roots.push(ref); + if (!ref.isNull()) roots.add(ref); } } + return roots; } /** * Save a program counter value - * @param pc + * @param pc The program counter */ public void savePc(int pc) { savedPc = pc; } - /** Return the saved program counter */ + /** @return the saved program counter */ public int getSavedPc() { return savedPc; } - /** Save a method code array */ + /** + * Save a method code array + * @param code The code array + */ public void saveMethod(PseudoOp[] code) { savedCode = code; } - /** Return the saved code array */ + /** + * @return the saved code array + */ public PseudoOp[] getSavedMethod() { return savedCode; } - /** Set the slot for the return value */ + /** + * Set the slot for the return value + * @param slot The slot in which to store the return value + */ public void setResultSlot(int slot) { resultSlot = slot; } - /** Clear the return value slot */ + /** + * Clear the return value slot + */ public void clearResultSlot() { resultSlot = NO_SUCH_SLOT; } - /** Set the return value */ + /** + * Set the return value + * @param returnValue The procedure return value + */ public void setResult(Value returnValue) { assert resultSlot != NO_SUCH_SLOT : "Attempt to return a value to a method call with no result slot"; set(resultSlot,returnValue); Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -54,7 +54,15 @@ throw new RuntimeException("Invalid use of " + type() + " as a string"); } + /** + * Marshall a value of this type into the equivalent Java value + * @param klass The target class + * @return + */ public Object marshall(Class<?> klass) { + if (klass.isAssignableFrom(this.getClass())) { + return this; + } throw new RuntimeException(getClass()+" cannot be marshalled into a Java Object"); } Added: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/WeakReferenceValue.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/WeakReferenceValue.java (rev 0) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/runtime/WeakReferenceValue.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -0,0 +1,43 @@ +/* + * This file is part of the Jikes RVM project (http://jikesrvm.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. + */ +package org.mmtk.harness.lang.runtime; + +import org.mmtk.harness.lang.type.Type; +import org.mmtk.vm.ReferenceProcessor.Semantics; +import org.vmmagic.unboxed.ObjectReference; + +/** + * A weak reference in the MMTk Harness language + */ +public class WeakReferenceValue extends ReferenceValue { + + /** + * The NULL weak reference + */ + public static final ReferenceValue NULL = new WeakReferenceValue(ObjectReference.nullReference()); + + /** + * @param ref The referent + */ + public WeakReferenceValue(ObjectReference ref) { + super(ref,Semantics.WEAK); + } + + /** + * @see org.mmtk.harness.lang.runtime.Value#type() + */ + @Override + public Type type() { + return Type.WEAKREF; + } +} Modified: rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/AbstractType.java =================================================================== --- rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/AbstractType.java 2009-07-21 04:20:25 UTC (rev 15731) +++ rvmroot/trunk/MMTk/harness/src/org/mmtk/harness/lang/type/AbstractType.java 2009-07-22 07:44:58 UTC (rev 15732) @@ -12,8 +12,6 @@ */ package org.mmtk.harness.lang.type; -import org.mmtk.harness.lang.runtime.Value; - /** * Types in the scripting language. */ @@ -21,27 +19,41 @@ private final String name; + /** + * @param name Name of this type + */ public AbstractType(String name) { this.name = name; } + /** + * @see java.lang.Object#toString() + */ @Override public String toString() { return getName(); } + /** + * @see org.mmtk.harness.lang.type.Type#getName() + */ + @Override public String getName() { return name; } + /** + * @see org.mmtk.harness.lang.type.Type#isObject() + */ @Override public boolean isObject() { return false; } + /** + * @see org.mmtk.harness.lang.type.Type#isCompatibleWith(org.mmtk.harness.lang.type.Type) + */ public boolean isCompatibleWith(Type rhs) { @@ Diff output truncated at 100000 characters. @@ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ _______________________________________________ Jikesrvm-commits mailing list Jikesrvm-commits@... https://lists.sourceforge.net/lists/listinfo/jikesrvm-commits |
| Free embeddable forum powered by Nabble | Forum Help |