diff --git a/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java b/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java index 772a09b5a..4399f496d 100644 --- a/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java +++ b/MMTk/ext/vm/harness/org/mmtk/harness/vm/Factory.java @@ -396,4 +396,9 @@ public ShortStream newGCspyShortStream( public org.mmtk.vm.MMTk_Events newEvents() { return new MMTkEvents(); } + + @Override + public Debug newDebug() { + return new Debug(); + } } diff --git a/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java b/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java index 5bf21dc6f..ac2d7b012 100644 --- a/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java +++ b/MMTk/ext/vm/harness/org/mmtk/harness/vm/ObjectModel.java @@ -13,6 +13,8 @@ package org.mmtk.harness.vm; import java.io.PrintStream; +import java.util.HashSet; +import java.util.Set; import java.util.Stack; import org.mmtk.harness.Collector; @@ -22,6 +24,7 @@ import org.mmtk.plan.CollectorContext; import org.mmtk.plan.MutatorContext; import org.mmtk.plan.Plan; +import org.mmtk.policy.Space; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.*; @@ -75,12 +78,9 @@ private static void printObjectLayout(PrintStream wr) { wr.flush(); } - static { - //printObjectLayout(System.out); - assert REFS_OFFSET.EQ(Offset.fromIntSignExtend(HEADER_SIZE)); - } - + /** Max data fields in an object */ public static final int MAX_DATA_FIELDS = Integer.MAX_VALUE; + /** Max pointer fields in an object */ public static final int MAX_REF_FIELDS = Integer.MAX_VALUE; /** Has this object been hashed? */ @@ -93,6 +93,10 @@ private static void printObjectLayout(PrintStream wr) { /** The value placed in alignment holes */ public static final int ALIGNMENT_VALUE = 1; + /* + * Object identifiers. Objects are allocated a sequential identifier. + */ + /** The next object id that will be allocated */ private static int nextObjectId = 1; @@ -106,6 +110,27 @@ public static int lastObjectId() { return nextObjectId; } + /* + * Watchpoints by object identifier. + */ + + private static final Set watchSet = new HashSet(); + + /** + * @param object The object + * @return True if this object is being watched + */ + public static boolean isWatched(ObjectReference object) { + return watchSet.contains(getId(object)); + } + + static { + //printObjectLayout(System.out); + assert REFS_OFFSET.EQ(Offset.fromIntSignExtend(HEADER_SIZE)); + //watchSet.add(4109); + //watchSet.add(8205); + } + /** * Allocate an object and return the ObjectReference. * @@ -133,13 +158,19 @@ public static ObjectReference allocateObject(MutatorContext context, int refCoun setRefCount(ref, refCount); setDataCount(ref, dataCount); + if (isWatched(ref)) { + System.err.printf("WATCH: Object %s created%n",objectIdString(ref)); + } + // Call MMTk postAlloc context.postAlloc(ref, null, bytes, allocator); return ref; } /** - * Get the number of references in the object. + * Get the number of references in an object. + * @param object The object + * @return number of reference fields in the object. */ public static int getRefs(ObjectReference object) { return object.toAddress().loadInt(REFCOUNT_OFFSET); @@ -147,18 +178,13 @@ public static int getRefs(ObjectReference object) { /** * Get the object identifier. + * @param object The object + * @return The object identifier */ public static int getId(ObjectReference object) { return object.toAddress().loadInt(ID_OFFSET) >>> 2; } - /** - * Get the object identifier as a string. - */ - public static String idString(ObjectReference object) { - return String.format("%08x", getId(object)); - } - /** * Set the object identifier. */ @@ -254,38 +280,6 @@ public static int getSize(int refs, int data) { } - /** - * Dump (logical) information for an object. - * - * @param object The object whose information is to be dumped - */ - public static void dumpLogicalObject(int width, ObjectReference object, Stack workStack) { - int refCount = getRefs(object); - int dataCount = getDataCount(object); - boolean hashed = (object.toAddress().loadInt(STATUS_OFFSET) & HASHED) == HASHED; - System.err.printf(" Object %s <%d %d %1s> [", Mutator.formatObject(width, object), refCount, dataCount, (hashed ? "H" : "")); - if (refCount > 0) { - for(int i=0; i < refCount; i++) { - ObjectReference ref = getRefSlot(object, i).loadObjectReference(); - System.err.print(" "); - System.err.print(Mutator.formatObject(width, ref)); - if (!ref.isNull()) { - workStack.push(ref); - } - } - } - System.err.println(" ]"); - } - - /** - * Print an object's header - */ - public static void dumpObjectHeader(ObjectReference object) { - int gcWord = object.toAddress().loadInt(GC_OFFSET); - int statusWord = object.toAddress().loadInt(STATUS_OFFSET); - System.err.printf("Object %s[%d@%s]<%x,%x>%n",object,getId(object),Mutator.getSiteName(object),gcWord,statusWord); - } - /** * Return the next object id to be allocated. */ @@ -327,14 +321,17 @@ public static int getHashCode(ObjectReference ref) { * @param allocator The allocator to use. * @return the address of the new object */ + @Override public ObjectReference copy(ObjectReference from, int allocator) { - Trace.trace(Item.COLLECT,"Copying object %s[%d@%s]",from,getId(from),Mutator.getSiteName(from)); int oldBytes = getSize(from); int newBytes = getCopiedSize(from); int align = getAlignWhenCopied(from); CollectorContext c = Collector.current().getContext(); allocator = c.copyCheckAllocator(from, newBytes, align, allocator); Address toRegion = c.allocCopy(from, newBytes, align, getAlignOffsetWhenCopied(from), allocator); + ObjectReference to = toRegion.toObjectReference(); + Trace.trace(Item.COLLECT,"Copying object %s from %s to %s", objectIdString(from), + addressAndSpaceString(from),addressAndSpaceString(to)); Address fromRegion = from.toAddress(); for(int i=0; i < oldBytes; i += SimulatedMemory.BYTES_IN_INT) { @@ -347,9 +344,13 @@ public ObjectReference copy(ObjectReference from, int allocator) { toRegion.store(getHashCode(from), Offset.fromIntZeroExtend(oldBytes)); } - ObjectReference to = toRegion.toObjectReference(); - c.postCopy(to, null, newBytes, allocator); + if (isWatched(from)) { + System.err.printf("WATCH: Object %d copied from %s to %s%n",getId(from), + addressAndSpaceString(from),addressAndSpaceString(to)); + dumpObject(to); + } + return to; } @@ -362,11 +363,14 @@ public ObjectReference copy(ObjectReference from, int allocator) { * * @param from the address of the object to be copied * @param to The target location. - * @param region The start of the region that was reserved for this object + * @param toRegion The start of the region that was reserved for this object * @return Address The address past the end of the copied object */ + @Override public Address copyTo(ObjectReference from, ObjectReference to, Address toRegion) { - Trace.trace(Item.COLLECT,"Copying object %s[%d@%s] to %s",from,getId(from),Mutator.getSiteName(from),to); + Trace.trace(Item.COLLECT,"Copying object %s from %s/%s to %s/%s", objectIdString(from), + from,Space.getSpaceForObject(from).getName(), + to,Space.getSpaceForObject(to).getName()); if (Trace.isEnabled(Item.COLLECT)) { dumpObjectHeader(from); } @@ -386,6 +390,10 @@ public Address copyTo(ObjectReference from, ObjectReference to, Address toRegion if (Trace.isEnabled(Item.COLLECT)) { dumpObjectHeader(to); } + if (isWatched(from)) { + System.err.printf("WATCH: Object %d copied from %s to %s%n",objectIdString(from), + addressAndSpaceString(from),addressAndSpaceString(to)); + } return toRegion.plus(bytes); } @@ -447,6 +455,7 @@ public int getCurrentSize(ObjectReference object) { /** * Return the next object in the heap under contiguous allocation */ + @Override public ObjectReference getNextObject(ObjectReference object) { Address nextAddress = object.toAddress().plus(getSize(object)); if (nextAddress.loadInt() == ALIGNMENT_VALUE) { @@ -461,6 +470,7 @@ public ObjectReference getNextObject(ObjectReference object) { /** * Return an object reference from knowledge of the low order word */ + @Override public ObjectReference getObjectFromStartAddress(Address start) { if ((start.loadInt() & ALIGNMENT_VALUE) != 0) { start = start.plus(SimulatedMemory.BYTES_IN_WORD); @@ -473,6 +483,7 @@ public ObjectReference getObjectFromStartAddress(Address start) { * * @param object The object. */ + @Override public Address getObjectEndAddress(ObjectReference object) { return object.toAddress().plus(getSize(object)); } @@ -483,28 +494,17 @@ public Address getObjectEndAddress(ObjectReference object) { * @param ref address of the object * @return byte array with the type descriptor */ + @Override public byte[] getTypeDescriptor(ObjectReference ref) { return getString(ref).getBytes(); } - /** - * Get the type descriptor for an object. - * - * @param ref address of the object - * @return byte array with the type descriptor - */ - public String getString(ObjectReference ref) { - int refs = getRefs(ref); - int data = getDataCount(ref); - int size = getSize(ref); - return ("Object[" + size + "bytes " + refs + "R / " + data + "D]"); - } - /** * Is the passed object an array? * * @param object address of the object */ + @Override public boolean isArray(ObjectReference object) { Assert.notImplemented(); return false; @@ -515,6 +515,7 @@ public boolean isArray(ObjectReference object) { * * @param object address of the object */ + @Override public boolean isPrimitiveArray(ObjectReference object) { Assert.notImplemented(); return false; @@ -526,6 +527,7 @@ public boolean isPrimitiveArray(ObjectReference object) { * @param object address of the object * @return The array length, in elements */ + @Override public int getArrayLength(ObjectReference object) { Assert.notImplemented(); return 0; @@ -544,7 +546,11 @@ public int getArrayLength(ObjectReference object) { * @return true if the bits were set, * false otherwise */ + @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); + } return object.toAddress().attempt(oldVal, newVal, STATUS_OFFSET); } @@ -555,6 +561,7 @@ public boolean attemptAvailableBits(ObjectReference object, Word oldVal, Word ne * @param object the address of the object * @return the value of the bits */ + @Override public Word prepareAvailableBits(ObjectReference object) { return object.toAddress().prepareWord(STATUS_OFFSET); } @@ -565,10 +572,11 @@ public Word prepareAvailableBits(ObjectReference object) { * @param object the address of the object * @param val the new value of the byte */ + @Override public void writeAvailableByte(ObjectReference object, byte val) { - if (Trace.isEnabled(Item.AVBYTE)) { + if (Trace.isEnabled(Item.AVBYTE) || isWatched(object)) { byte old = object.toAddress().loadByte(STATUS_OFFSET); - Trace.trace(Item.AVBYTE,"%s.gcbyte:%d->%d", object,old,val); + Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d", object,old,val); } object.toAddress().store(val, STATUS_OFFSET); } @@ -579,6 +587,7 @@ public void writeAvailableByte(ObjectReference object, byte val) { * @param object the address of the object * @return the value of the byte */ + @Override public byte readAvailableByte(ObjectReference object) { return object.toAddress().loadByte(STATUS_OFFSET); } @@ -589,10 +598,11 @@ public byte readAvailableByte(ObjectReference object) { * @param object the address of the object * @param val the new value of the bits */ + @Override public void writeAvailableBitsWord(ObjectReference object, Word val) { - if (Trace.isEnabled(Item.AVBYTE)) { + if (Trace.isEnabled(Item.AVBYTE) || isWatched(object)) { byte old = object.toAddress().loadByte(STATUS_OFFSET); - Trace.trace(Item.AVBYTE,"%s.gcbyte:%d->%d", object,old,val.and(Word.fromIntZeroExtend(0xFF)).toInt()); + Trace.printf(Item.AVBYTE,"%s.gcbyte:%d->%d", object,old,val.and(Word.fromIntZeroExtend(0xFF)).toInt()); } object.toAddress().store(val, STATUS_OFFSET); } @@ -603,6 +613,7 @@ public void writeAvailableBitsWord(ObjectReference object, Word val) { * @param object the address of the object * @return the value of the bits */ + @Override public Word readAvailableBitsWord(ObjectReference object) { return object.toAddress().loadWord(STATUS_OFFSET); } @@ -615,6 +626,7 @@ public Word readAvailableBitsWord(ObjectReference object) { * * @return the offset, relative the object reference address */ + @Override public Offset GC_HEADER_OFFSET() { return GC_OFFSET; } @@ -625,6 +637,7 @@ public Offset GC_HEADER_OFFSET() { * @param object the reference address of the object * @return the lowest address of the object */ + @Override public Address objectStartRef(ObjectReference object) { return object.toAddress(); } @@ -636,6 +649,7 @@ public Address objectStartRef(ObjectReference object) { * @param object the reference address of the object * @return an address inside the object */ + @Override public Address refToAddress(ObjectReference object) { return object.toAddress(); } @@ -647,25 +661,111 @@ public Address refToAddress(ObjectReference object) { * @return true if a reference of the type is * inherently acyclic */ + @Override public boolean isAcyclic(ObjectReference typeRef) { return false; } + /** @return The offset from array reference to element zero */ + @Override + protected Offset getArrayBaseOffset() { + return REFS_OFFSET; + } + + /* + * String representations of objects and logging/dump methods + */ + /** * Dump debugging information for an object. * * @param object The object whose information is to be dumped */ + @Override public void dumpObject(ObjectReference object) { System.err.println("==================================="); - System.err.println(getString(object) + " @" + object.toAddress()); + System.err.println(getString(object)); System.err.println("==================================="); SimulatedMemory.dumpMemory(object.toAddress(), 0, getSize(object)); System.err.println("==================================="); } - /** @return The offset from array reference to element zero */ - protected Offset getArrayBaseOffset() { - return REFS_OFFSET; + /** + * Format the object for dumping, and trim to a max width. + */ + public static String formatObject(int width, ObjectReference object) { + String base = getString(object); + return base.substring(base.length() - width); + } + + /** + * Print an object's header + */ + public static void dumpObjectHeader(ObjectReference object) { + int gcWord = object.toAddress().loadInt(GC_OFFSET); + int statusWord = object.toAddress().loadInt(STATUS_OFFSET); + System.err.printf("Object %s[%d@%s]<%x,%x>%n",object,getId(object),Mutator.getSiteName(object),gcWord,statusWord); + } + + /** + * Dump (logical) information for an object. + * @param width Output width + * @param object The object whose information is to be dumped + */ + public static void dumpLogicalObject(int width, ObjectReference object, Stack workStack) { + int refCount = getRefs(object); + int dataCount = getDataCount(object); + boolean hashed = (object.toAddress().loadInt(STATUS_OFFSET) & HASHED) == HASHED; + 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++) { + ObjectReference ref = getRefSlot(object, i).loadObjectReference(); + System.err.print(" "); + System.err.print(ObjectModel.formatObject(width, ref)); + if (!ref.isNull()) { + workStack.push(ref); + } + } + } + System.err.println(" ]"); + } + + /** + * String description of an object. + * + * @param ref address of the object + * @return "Object[size b nR/mD] + */ + public static String getString(ObjectReference ref) { + int refs = getRefs(ref); + int data = getDataCount(ref); + return addressAndSpaceString(ref)+objectIdString(ref)+refs + "R" + data + "D"; + } + + /** + * Brief string description of an object + * @param ref The object + * @return "[id@line:col]" + */ + private static String objectIdString(ObjectReference ref) { + return String.format("[%d@%s]", getId(ref),Mutator.getSiteName(ref)); + } + + /** + * Address and space name (eg 0x45678900/ms) + * @param ref The object + * @return "address/space" + */ + public static String addressAndSpaceString(ObjectReference ref) { + return String.format("%s/%s",ref, Space.getSpaceForObject(ref).getName()); + } + + /** + * Address and space name (eg 0x45678900/ms) + * @param ref The object + * @return "address/space" + */ + public static String addressAndSpaceString(Address addr) { + return addressAndSpaceString(addr.toObjectReference()); } } diff --git a/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Factory.java b/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Factory.java index d234d3d6a..b63af419a 100644 --- a/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Factory.java +++ b/MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Factory.java @@ -298,6 +298,10 @@ public org.mmtk.vm.MMTk_Events newEvents() { } } + public org.mmtk.vm.Debug newDebug() { + return new Debug(); + } + /********************************************************************** * GCspy methods */ diff --git a/MMTk/harness/src-generated/org/mmtk/harness/lang/parser/Parser.jj b/MMTk/harness/src-generated/org/mmtk/harness/lang/parser/Parser.jj index 06d508982..f9ca384d6 100644 --- a/MMTk/harness/src-generated/org/mmtk/harness/lang/parser/Parser.jj +++ b/MMTk/harness/src-generated/org/mmtk/harness/lang/parser/Parser.jj @@ -13,9 +13,10 @@ options { JDK_VERSION = "1.5"; - LOOKAHEAD = 10; + LOOKAHEAD = 2; FORCE_LA_CHECK=true; STATIC = false; +// DEBUG_PARSER=true; } PARSER_BEGIN(Parser) package org.mmtk.harness.lang.parser; @@ -23,6 +24,7 @@ package org.mmtk.harness.lang.parser; // CHECKSTYLE:OFF import org.mmtk.harness.lang.ast.*; import org.mmtk.harness.lang.runtime.*; +import org.mmtk.harness.lang.type.*; import java.util.*; import java.io.*; @@ -46,6 +48,13 @@ public class Parser { String.format("%d:%d - Variable %s is undefined",tok.beginLine,tok.beginColumn,id)); } } + + private static Type createTypeReference(TypeTable types, String name) { + if (types.isDefined(name)) { + return types.get(name); + } + return new TypeReference(types,name); + } } PARSER_END(Parser) @@ -86,25 +95,22 @@ MORE : { /* Reserved words */ TOKEN : { - < ALLOC : "alloc" > | - < ASSERT : "assert" > | - < BOOLEAN : "boolean" > | - < CLASS : "class" > | - < ELIF : "elif" > | - < ELSE : "else" > | - < EXPECT : "expect" > | - < IF : "if" > | - < INT : "int" > | - < INTRINSIC : "intrinsic" > | - < METHOD : "method" > | - < NULL : "null" > | - < OBJECT : "object" > | - < PRINT : "print" > | - < RETURN : "return" > | - < SIGNATURE : "signature" > | - < SPAWN : "spawn" > | - < STRING : "string" > | - < WHILE : "while" > + < ALLOC : "alloc" > + | < ASSERT : "assert" > + | < CLASS : "class" > + | < ELIF : "elif" > + | < ELSE : "else" > + | < EXPECT : "expect" > + | < IF : "if" > + | < INTRINSIC : "intrinsic" > + | < METHOD : "method" > + | < NULL : "null" > + | < PRINT : "print" > + | < RETURN : "return" > + | < SIGNATURE : "signature" > + | < SPAWN : "spawn" > + | < TYPE : "type" > + | < WHILE : "while" > } /* Literals */ @@ -156,45 +162,46 @@ TOKEN : { } MethodTable script() : { - MethodTable methods = new MethodTable(); - Method m; + GlobalDefs defs = new GlobalDefs(); final String intrinsics = "org.mmtk.harness.lang.Intrinsics"; - methods.add(new IntrinsicMethod("gc",intrinsics,"gc")); - methods.add(new IntrinsicMethod("tid",intrinsics,"threadId")); - methods.add(new IntrinsicMethod("hash",intrinsics,"hash", + defs.methods.add(new IntrinsicMethod("gc",intrinsics,"gc")); + defs.methods.add(new IntrinsicMethod("tid",intrinsics,"threadId")); + defs.methods.add(new IntrinsicMethod("hash",intrinsics,"hash", new Class[] { ObjectValue.class })); - methods.add(new IntrinsicMethod("random",intrinsics,"random", + defs.methods.add(new IntrinsicMethod("random",intrinsics,"random", new Class[] { int.class, int.class })); - methods.add(new IntrinsicMethod("setSeed",intrinsics,"setRandomSeed", + defs.methods.add(new IntrinsicMethod("setSeed",intrinsics,"setRandomSeed", new Class[] { int.class })); - methods.add(new IntrinsicMethod("heapDump",intrinsics,"heapDump")); + defs.methods.add(new IntrinsicMethod("heapDump",intrinsics,"heapDump")); } { - ( method(methods) )+ - { return methods; } + ( method(defs) + | typeDeclaration(defs) + )+ + { return defs.methods; } } /** * A program method with its own variable scope. */ -void method(MethodTable methods) : { +void method(GlobalDefs defs) : { SymbolTable symbols = new SymbolTable(); Statement stmt; String name; int params = 0; - Type retType = Type.VOID; + Type retType; String javaClass, javaMethod, javaParam; List signature = new ArrayList(); Token t; } { - (retType=type())? + retType=type(defs) t= { name = t.toString(); } - ( declaration1(methods, symbols) { params++; } ( declaration1(methods, symbols) { params++; } )* )? + ( declaration1(defs, symbols) { params++; } ( declaration1(defs, symbols) { params++; } )* )? - ( stmt=statements(methods, symbols) - { methods.add(new NormalMethod(t, name, params, retType, symbols.declarations(), stmt)); } + ( stmt=statements(defs, symbols) + { defs.methods.add(new NormalMethod(t, name, params, retType, symbols.declarations(), stmt)); } | javaClass=string() javaMethod=string() @@ -204,7 +211,7 @@ void method(MethodTable methods) : { )? )? - { methods.add(new IntrinsicMethod(name,javaClass,javaMethod,signature)); } + { defs.methods.add(new IntrinsicMethod(name,javaClass,javaMethod,signature)); } ) } @@ -218,12 +225,35 @@ void intrinsicParam(List signature) : { } signature.add(javaParam); } } + +/** + * A Type Declaration + */ +void typeDeclaration(GlobalDefs defs) : { + Token t; +} +{ + t= + { UserType type = new UserTypeImpl(t,t.toString()); + defs.types.add(type); + } + + ( typeField(defs,type) )+ + +} +void typeField(GlobalDefs defs, UserType type) : { + String fieldType, name; +} +{ + fieldType=ident() name=ident() + { type.defineField(name, createTypeReference(defs.types,fieldType)); } +} /** * A sequence of statements in braces, carrying an inner variable scope */ -Statement statements(MethodTable methods, SymbolTable symbols) : { +Statement statements(GlobalDefs defs, SymbolTable symbols) : { Statement stmt; List stmts = new ArrayList(); Token t; @@ -231,7 +261,7 @@ Statement statements(MethodTable methods, SymbolTable symbols) : { { t= { symbols.pushScope(); } - ( stmt=statement(methods, symbols) + ( stmt=statement(defs, symbols) { stmts.add(stmt); } )* { symbols.popScope(); } @@ -242,28 +272,32 @@ Statement statements(MethodTable methods, SymbolTable symbols) : { /** * A single statement */ -Statement statement(MethodTable methods, SymbolTable symbols) : { +Statement statement(GlobalDefs defs, SymbolTable symbols) : { Statement stmt; + Token t; } { - ( stmt=conditional(methods, symbols) | - stmt=declaration(methods, symbols) | - stmt=expect(methods, symbols) | - stmt=assignment(methods, symbols) | - stmt=spawn(methods, symbols) | - stmt=storeField(methods, symbols) | - stmt=whileLoop(methods, symbols) | - stmt=print(methods, symbols) | - stmt=assertTrue(methods, symbols) | - stmt=callMethod(methods, symbols) | - stmt=returnStmt(methods, symbols) ) + ( stmt=conditional(defs, symbols) + | stmt=expect(defs, symbols) + | stmt=spawn(defs, symbols) + | stmt=whileLoop(defs, symbols) + | stmt=print(defs, symbols) + | stmt=assertTrue(defs, symbols) + | t= + ( stmt=assignment(defs, symbols, t) + | stmt=declaration(defs, symbols, t) + | stmt=storeField(defs, symbols, t) + | stmt=callMethod(defs, symbols, t) + ) + | stmt=returnStmt(defs, symbols) + ) { return stmt; } } /** * if - then - else */ -Statement conditional(MethodTable methods, SymbolTable symbols) : { +Statement conditional(GlobalDefs defs, SymbolTable symbols) : { Expression cond; List conds = new ArrayList(); Statement stmt; @@ -271,11 +305,11 @@ Statement conditional(MethodTable methods, SymbolTable symbols) : { Token t; } { - t= cond=expression(methods,symbols) { conds.add(cond); } - stmt=statements(methods, symbols) { stmts.add(stmt); } - ( cond=expression(methods,symbols) { conds.add(cond); } - stmt=statements(methods, symbols) { stmts.add(stmt); })* - ( stmt=statements(methods, symbols) { stmts.add(stmt); } )? + t= cond=expression(defs,symbols) { conds.add(cond); } + stmt=statements(defs, symbols) { stmts.add(stmt); } + ( cond=expression(defs,symbols) { conds.add(cond); } + stmt=statements(defs, symbols) { stmts.add(stmt); })* + ( stmt=statements(defs, symbols) { stmts.add(stmt); } )? { return new IfStatement(t,conds,stmts); } } @@ -283,15 +317,15 @@ Statement conditional(MethodTable methods, SymbolTable symbols) : { * assert the expression in the first parameter, * and print the remaining parameters if the assertion fails */ -Statement assertTrue(MethodTable methods, SymbolTable symbols) : { +Statement assertTrue(GlobalDefs defs, SymbolTable symbols) : { Expression cond; List exprs = new ArrayList(); Expression expr; Token t; } { - t= cond=expression(methods,symbols) - ( expr=expression(methods,symbols) + t= cond=expression(defs,symbols) + ( expr=expression(defs,symbols) { exprs.add(expr); } )+ { return new Assert(t,cond, exprs); } @@ -300,14 +334,14 @@ Statement assertTrue(MethodTable methods, SymbolTable symbols) : { /** * while loop */ -Statement whileLoop(MethodTable methods, SymbolTable symbols) : { +Statement whileLoop(GlobalDefs defs, SymbolTable symbols) : { Expression cond; Statement body; Token t; } { - t= cond=expression(methods,symbols) - body=statements(methods, symbols) + t= cond=expression(defs,symbols) + body=statements(defs, symbols) { return new WhileStatement(t,cond,body); } } @@ -317,15 +351,15 @@ Statement whileLoop(MethodTable methods, SymbolTable symbols) : { * Adds a symbol to the symbol table, and returns either an * assignment statement or an empty sequence. */ -Statement declaration(MethodTable methods, SymbolTable symbols) : { +Statement declaration(GlobalDefs defs, SymbolTable symbols, Token id) : { String name; Expression expr; Statement stmt; Token t; } { - name=declaration1(methods, symbols) - ( ( t= expr=expression(methods,symbols) + name=declaration2(defs, symbols,id) + ( ( t= expr=expression(defs,symbols) { return new Assignment(t,symbols.getSymbol(name), expr); } ) )? @@ -337,30 +371,49 @@ Statement declaration(MethodTable methods, SymbolTable symbols) : { * * Adds a symbol to the symbol table and returns the name. */ -String declaration1(MethodTable methods, SymbolTable symbols) : { +String declaration1(GlobalDefs defs, SymbolTable symbols) : { String name; Type type; } { - type=type() name=ident() + type=type(defs) name=ident() { symbols.declare(name,type); return name; } } -Type type() : { +/** + * First part of variable declaration (without initialization), + * where the parent production has consumed the type identifier token. + * + * Adds a symbol to the symbol table and returns the name. + */ +String declaration2(GlobalDefs defs, SymbolTable symbols, Token id) : { + String name; + Type type = defs.types.get(id.toString()); } { - { return Type.INT; } -| { return Type.OBJECT; } -| { return Type.BOOLEAN; } -| { return Type.STRING; } + /* type - consumed by parent */ + name=ident() + { symbols.declare(name,type); + return name; + } +} + +Type type(GlobalDefs defs) : { + String type; +} +{ + type=ident() + { + return defs.types.get(type); + } } /* * Set up an expectation for an exception */ -Statement expect(MethodTable methods, SymbolTable symbols) : { +Statement expect(GlobalDefs defs, SymbolTable symbols) : { String name; Token t; } @@ -372,64 +425,69 @@ Statement expect(MethodTable methods, SymbolTable symbols) : { /* * Assign a value to a variable */ -Statement assignment(MethodTable methods, SymbolTable symbols) : { - String name; +Statement assignment(GlobalDefs defs, SymbolTable symbols, Token id) : { + String name = id.toString(); Expression expr; Token t; } { - name=ident() t= expr=expression(methods,symbols) + t= expr=expression(defs,symbols) { return new Assignment(t,symbols.getSymbol(name),expr); } } /* * Assign a value to a field of an object */ -Statement storeField(MethodTable methods, SymbolTable symbols) : { - String name; - Type type; +Statement storeField(GlobalDefs defs, SymbolTable symbols, Token id) : { + Symbol objectSym = symbols.getSymbol(id.toString()); Expression index, rVal; - Token t; + Token fieldId; } { - t= { name = t.toString(); } - type = type() - index=expression(methods,symbols) rVal=expression(methods,symbols) - { return new StoreField(t, symbols.getSymbol(name), type, index, rVal); } + { checkSymbol(symbols,id); } + fieldId = + ( index=expression(defs,symbols) + rVal=expression(defs,symbols) + { Type fieldType = defs.types.get(fieldId.toString()); + return new StoreField(id, objectSym, fieldType, index, rVal); + } + | rVal=expression(defs,symbols) + { String fieldName = fieldId.toString(); + return new StoreNamedField(id, objectSym, fieldName, rVal); + } + ) } /** * Procedure call, as a statement */ -Statement callMethod(MethodTable methods, SymbolTable symbols) : { - Token t; - String name; +Statement callMethod(GlobalDefs defs, SymbolTable symbols, Token id) : { + String name = id.toString(); List params = new ArrayList(); Expression p; } { - t= { name = t.toString(); } - ( p=expression(methods,symbols) + ( p=expression(defs,symbols) { params.add(p); } - ( p=expression(methods,symbols) + ( p=expression(defs,symbols) { params.add(p); } )* )? - { return new Call(t, new MethodProxy(methods, name, params.size()), params, false); } + { return new Call(id, new MethodProxy(defs.methods, name, params.size()), params, false); } } /** * Return a value from a method */ -Statement returnStmt(MethodTable methods, SymbolTable symbols) : { +Statement returnStmt(GlobalDefs defs, SymbolTable symbols) : { Expression e; Token t; } { t= - ( e=expression(methods,symbols) + ( e=expression(defs,symbols) { return new Return(t, e); } )? { return new Return(t); } @@ -438,7 +496,7 @@ Statement returnStmt(MethodTable methods, SymbolTable symbols) : { /* * Create a new thread */ -Statement spawn(MethodTable methods, SymbolTable symbols) : { +Statement spawn(GlobalDefs defs, SymbolTable symbols) : { String name; List params = new ArrayList(); Expression p; @@ -446,22 +504,22 @@ Statement spawn(MethodTable methods, SymbolTable symbols) : { } { t= name=ident() - ( p=expression(methods,symbols) + ( p=expression(defs,symbols) { params.add(p); } )* - { return new Spawn(t, methods, name, params); } + { return new Spawn(t, defs.methods, name, params); } } -Statement print(MethodTable methods, SymbolTable symbols) : { +Statement print(GlobalDefs defs, SymbolTable symbols) : { List exprs = new ArrayList(); Expression expr; Token t; } { - t= expr=expression(methods,symbols) + t= expr=expression(defs,symbols) { exprs.add(expr); } - ( expr=expression(methods,symbols) + ( expr=expression(defs,symbols) { exprs.add(expr); } )* { return new PrintStatement(t, exprs); } @@ -474,111 +532,115 @@ Statement print(MethodTable methods, SymbolTable symbols) : { * for enumerating temporaries at GC time. Therefore, method calls as expressions * can only occur at the top level of an expression. */ -Expression expression(MethodTable methods, SymbolTable symbols) : { +Expression expression(GlobalDefs defs, SymbolTable symbols) : { Expression e1,e2; Token t; } { - e1=expr1(methods,symbols) - ( t= e2=expression(methods,symbols) + e1=expr1(defs,symbols) + ( t= e2=expression(defs,symbols) { return new BinaryExpression(t, e1, Operator.OR, e2); } | - t= e2=expression(methods,symbols) + t= e2=expression(defs,symbols) { return new BinaryExpression(t, e1, Operator.AND, e2); } )? { return e1; } } -Expression expr1(MethodTable methods, SymbolTable symbols) : { +Expression expr1(GlobalDefs defs, SymbolTable symbols) : { Expression e; Token t; } { - t= e=expr1(methods,symbols) + t= e=expr1(defs,symbols) { return new UnaryExpression(t,Operator.NOT,e); } | - t= e=expr1(methods,symbols) + t= e=expr1(defs,symbols) { return new UnaryExpression(t,Operator.MINUS,e); } | - e=expr2(methods,symbols) { return e; } + e=expr2(defs,symbols) { return e; } } -Expression expr2(MethodTable methods, SymbolTable symbols) : { +Expression expr2(GlobalDefs defs, SymbolTable symbols) : { Expression e1,e2; Token t; } { - e1=expr3(methods,symbols) - ( t= e2=expr3(methods,symbols) + e1=expr3(defs,symbols) + ( t= e2=expr3(defs,symbols) { return new BinaryExpression(t, e1,Operator.LT,e2); } - | t= e2=expr3(methods,symbols) + | t= e2=expr3(defs,symbols) { return new BinaryExpression(t, e1,Operator.GT,e2); } - | t= e2=expr3(methods,symbols) + | t= e2=expr3(defs,symbols) { return new BinaryExpression(t, e1,Operator.LE,e2); } - | t= e2=expr3(methods,symbols) + | t= e2=expr3(defs,symbols) { return new BinaryExpression(t, e1,Operator.GE,e2); } - | t= e2=expr3(methods,symbols) + | t= e2=expr3(defs,symbols) { return new BinaryExpression(t, e1,Operator.EQ,e2); } - | t= e2=expr3(methods,symbols) + | t= e2=expr3(defs,symbols) { return new BinaryExpression(t, e1,Operator.NE,e2); } )? { return e1; } } -Expression expr3(MethodTable methods, SymbolTable symbols) : { +Expression expr3(GlobalDefs defs, SymbolTable symbols) : { Expression e1,e2; Token t; } { - e1=expr4(methods,symbols) - ( t= e2=expr3(methods,symbols) + e1=expr4(defs,symbols) + ( t= e2=expr3(defs,symbols) { return new BinaryExpression(t, e1,Operator.PLUS,e2); } - | t= e2=expr3(methods,symbols) + | t= e2=expr3(defs,symbols) { return new BinaryExpression(t, e1,Operator.MINUS,e2); } )? { return e1; } } -Expression expr4(MethodTable methods, SymbolTable symbols) : { +Expression expr4(GlobalDefs defs, SymbolTable symbols) : { Expression e1,e2; Token t; } { - e1=expr5(methods,symbols) - ( t= e2=expr4(methods,symbols) + e1=expr5(defs,symbols) + ( t= e2=expr4(defs,symbols) { return new BinaryExpression(t, e1, Operator.MULT, e2); } - | t= e2=expr4(methods,symbols) + | t= e2=expr4(defs,symbols) { return new BinaryExpression(t, e1, Operator.DIV, e2); } - | t= e2=expr4(methods,symbols) + | t= e2=expr4(defs,symbols) { return new BinaryExpression(t, e1, Operator.REM, e2); } )? { return e1; } } -Expression expr5(MethodTable methods, SymbolTable symbols) : { +Expression expr5(GlobalDefs defs, SymbolTable symbols) : { Expression e, index; String id; - Type type; - Token t; + Token t, field; } { /* constants of various types */ e=constant() { return e; } | /* intrinsic functions */ - e=alloc(methods,symbols) { return e; } | + e=alloc(defs,symbols) { return e; } | /* An expression in parentheses */ - e=expression(methods,symbols) + e=expression(defs,symbols) { return e; } | /* Field dereference */ ( t= { id=t.toString(); } - ( type = type() - index=expression(methods,symbols) + ( field= + { checkSymbol(symbols,t); } + ( index=expression(defs,symbols) { - checkSymbol(symbols,t); + Type type = defs.types.get(field.toString()); return new LoadField(t,symbols.getSymbol(id), type, index); } - - | e=callExpr(t,id,methods,symbols) { return e; } + | { + String fieldName = field.toString(); + return new LoadNamedField(t,symbols.getSymbol(id), fieldName); + } + ) + | e=callExpr(t,id,defs,symbols) { return e; } )? /* Variable substitution */ @@ -598,11 +660,11 @@ Expression constant() : { /* Integer constant */ | t= - { return new Constant(t, IntValue.valueOf(Integer.parseInt(t.toString()))); } + { return new Constant(t, IntValue.valueOf(Integer.valueOf(t.toString()))); } /* boolean constant */ | t= - { return new Constant(t, BoolValue.valueOf(Boolean.parseBoolean(t.toString()))); } + { return new Constant(t, BoolValue.valueOf(Boolean.valueOf(t.toString()))); } /* String constant */ | t= @@ -618,35 +680,41 @@ Expression constant() : { * Caller has matched the method name, which gets passed as the 'name' parameter. * 't' is the token of the method name (for error location). */ -Expression callExpr(Token t, String name, MethodTable methods, SymbolTable symbols) : { +Expression callExpr(Token t, String name, GlobalDefs defs, SymbolTable symbols) : { List params = new ArrayList(); Expression p; } { - ( p=expression(methods,symbols) + ( p=expression(defs,symbols) { params.add(p); } - ( p=expression(methods,symbols) + ( p=expression(defs,symbols) { params.add(p); } )* )? - { return new Call(t,new MethodProxy(methods, name, params.size()), params, true); } + { return new Call(t,new MethodProxy(defs.methods, name, params.size()), params, true); } } -Expression alloc(MethodTable methods, SymbolTable symbols) : { +Expression alloc(GlobalDefs defs, SymbolTable symbols) : { Expression e,refCount,dataCount,doubleAlign = new Constant(BoolValue.FALSE); AllocationSite site; Token t; + Type type; } { t= { site = new AllocationSite(t); } - refCount=expression(methods,symbols) - dataCount=expression(methods,symbols) - ( doubleAlign=expression(methods,symbols) )? - + ( refCount=expression(defs,symbols) + dataCount=expression(defs,symbols) + ( doubleAlign=expression(defs,symbols) )? + { return new Alloc(t, site.getId(), refCount, dataCount, doubleAlign); } + | + type=type(defs) + + { return new AllocUserType(t, site.getId(), type); } + ) } diff --git a/MMTk/harness/src/org/mmtk/harness/Collector.java b/MMTk/harness/src/org/mmtk/harness/Collector.java index cf9dc4197..6edc3a859 100644 --- a/MMTk/harness/src/org/mmtk/harness/Collector.java +++ b/MMTk/harness/src/org/mmtk/harness/Collector.java @@ -14,6 +14,7 @@ import java.util.ArrayList; +import org.mmtk.harness.sanity.Sanity; import org.mmtk.harness.scheduler.Scheduler; import org.mmtk.harness.vm.ActivePlan; import org.mmtk.plan.CollectorContext; @@ -32,13 +33,15 @@ public final class Collector implements Runnable { /** * Get a collector by id. + * @param id The ID of the collector + * @return The collector */ public static Collector get(int id) { return collectors.get(id); } /** - * Get the currently executing collector. + * @return the currently executing collector. */ public static Collector current() { Collector c = Scheduler.currentCollector(); @@ -47,14 +50,15 @@ public static Collector current() { } /** - * The number of collector threads that have been created. + * @return The number of collector threads that have been created. */ public static int count() { return collectors.size(); } /** - * Register a collector thread, returning the allocated id. + * Register a collector thread + * @return the allocated id. */ public static synchronized int allocateCollectorId() { int id = collectors.size(); @@ -64,6 +68,7 @@ public static synchronized int allocateCollectorId() { /** * Initialise numCollector collector threads. + * @param numCollectors # collectors */ public static void init(int numCollectors) { for(int i = 0; i < numCollectors; i++) { @@ -100,6 +105,9 @@ public void uncaughtException(Thread t, Throwable e) { /** The number of collections that have occurred */ private static int collectionCount; + /** + * @return The number of GCs commenced so far + */ public static int getCollectionCount() { return collectionCount; } @@ -107,6 +115,9 @@ public static int getCollectionCount() { /** The current base count of collection attempts */ private static int collectionAttemptBase; + /** + * @return The current base count of collection attempts + */ public static int getCollectionAttemptBase() { return collectionAttemptBase; } @@ -123,13 +134,14 @@ public static void requestHeapDump() { /** * Trigger a collection for the given reason + * @param why Reason (as defined by MMTk VM interface) */ public static void triggerGC(int why) { Scheduler.triggerGC(why); } /** - * Return the MMTk CollectorContext for this collector. + * @return the MMTk CollectorContext for this collector. */ public CollectorContext getContext() { return context; @@ -138,6 +150,8 @@ public CollectorContext getContext() { /** * Rendezvous with all other processors, returning the rank * (that is, the order this processor arrived at the barrier). + * @param where An identifier for the rendezvous point + * @return The order of arrival */ public static int rendezvous(int where) { return Scheduler.rendezvous(where); @@ -165,13 +179,85 @@ public void run() { } } + /** + * A timeout thread. Exit the harness if it isn't cancelled in time. + */ + private static final class TimeoutThread implements Runnable { + private static final boolean VERBOSE = false; + private static final int MILLIS_PER_SECOND = 1000; + private final long timeout; + private boolean cancelled = false; + private volatile boolean started = false; + + /** + * Create a timeout object and start it running in its own + * thread. + * @param seconds Timeout in seconds + */ + private TimeoutThread(int seconds) { + this.timeout = seconds * MILLIS_PER_SECOND; + new Thread(this).start(); + synchronized (this) { + while (!started) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + + /** + * @see java.lang.Thread#run() + */ + @Override + public void run() { + long startTime = System.currentTimeMillis(); + synchronized (this) { + while (!cancelled) { + try { + started = true; + notify(); + long now = System.currentTimeMillis(); + if (now - startTime >= timeout) { + System.err.printf("Collection exceeded timeout %dms%n",timeout); + System.exit(1); + } + long sleepTime = Math.max(1,timeout - (now - startTime)); + if (VERBOSE) { + System.err.printf("Collection timeout: sleeping for %dms%n",sleepTime); + } + wait(sleepTime); + } catch (InterruptedException e) { + // Ignore interruptions + } + } + } + } + + /** Cancel the timeout */ + public void cancel() { + synchronized (this) { + if (VERBOSE) { + System.err.printf("Collection timeout: cancelled%n"); + } + cancelled = true; + notify(); + } + } + } + /** * Perform a GC */ private void collect() { boolean primary = context.getId() == 0; + Sanity sanity = new Sanity(); + TimeoutThread timeout = null; if (primary) { Plan.setCollectionTrigger(Scheduler.getTriggerReason()); + sanity.snapshotBefore(); + timeout = new TimeoutThread(Harness.timeout.getValue()); } long startTime = System.nanoTime(); @@ -233,6 +319,8 @@ private void collect() { } if (primary) { + sanity.snapshotAfter(); + sanity.assertSanity(); collectionAttemptBase = 0; /* This is where we would schedule Finalization, if we supported it. */ @@ -244,6 +332,7 @@ private void collect() { rendezvous(5202); if (primary) { Plan.collectionComplete(); + timeout.cancel(); } } diff --git a/MMTk/harness/src/org/mmtk/harness/Harness.java b/MMTk/harness/src/org/mmtk/harness/Harness.java index ffaaf8a4b..7c1eb4611 100644 --- a/MMTk/harness/src/org/mmtk/harness/Harness.java +++ b/MMTk/harness/src/org/mmtk/harness/Harness.java @@ -73,6 +73,9 @@ public class Harness { /** Print yield policy statistics on exit */ public static final PolicyStats policyStats = new PolicyStats(); + /** Timeout on unreasonably long GC */ + public static final Timeout timeout = new Timeout(); + private static boolean isInitialized = false; /** diff --git a/MMTk/harness/src/org/mmtk/harness/Main.java b/MMTk/harness/src/org/mmtk/harness/Main.java index 3a840b45f..c384eb9d8 100644 --- a/MMTk/harness/src/org/mmtk/harness/Main.java +++ b/MMTk/harness/src/org/mmtk/harness/Main.java @@ -16,12 +16,16 @@ import java.io.FileNotFoundException; import org.mmtk.harness.lang.Checker; +import org.mmtk.harness.lang.CheckerException; import org.mmtk.harness.lang.Compiler; import org.mmtk.harness.lang.parser.MethodTable; import org.mmtk.harness.lang.parser.Parser; import org.mmtk.harness.lang.parser.ParseException; import org.mmtk.harness.scheduler.Scheduler; +/** + * Main class for the MMTk debugging harness. + */ public class Main { public static void main(String[] args) throws InterruptedException, ParseException, FileNotFoundException { /* Usage */ @@ -43,14 +47,22 @@ public static void main(String[] args) throws InterruptedException, ParseExcepti scriptFile += ".script"; } + /* Compile the script */ final MethodTable methods = new Parser(scriptFile).script(); - /* Type-check the script */ - Checker.typeCheck(methods); - + try { + /* Type-check the script */ + Checker.typeCheck(methods); + } catch (CheckerException e) { + System.err.println(e.getMessage()); + System.err.println("Exiting due to type-checker exceptions"); + return; + } + /* Schedule a thread to run the script */ Scheduler.scheduleMutator(Compiler.compile(methods)); + /* Start the thread scheduler */ Scheduler.schedule(); } } diff --git a/MMTk/harness/src/org/mmtk/harness/Mutator.java b/MMTk/harness/src/org/mmtk/harness/Mutator.java index aee489f12..23a85a2ee 100644 --- a/MMTk/harness/src/org/mmtk/harness/Mutator.java +++ b/MMTk/harness/src/org/mmtk/harness/Mutator.java @@ -13,6 +13,7 @@ package org.mmtk.harness; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.Stack; @@ -20,6 +21,7 @@ import org.mmtk.harness.lang.Trace; import org.mmtk.harness.lang.Trace.Item; import org.mmtk.harness.lang.runtime.AllocationSite; +import org.mmtk.harness.lang.runtime.ObjectValue; import org.mmtk.harness.scheduler.Scheduler; import org.mmtk.harness.vm.ActivePlan; import org.mmtk.harness.vm.ObjectModel; @@ -43,9 +45,12 @@ * Note that as soon as the mutator is created it is considered active. This means * that a GC can not occur unless you execute commands on the mutator (or muEnd it). */ -public class Mutator { +public abstract class Mutator { private static boolean gcEveryWB = false; + /** + * Force garbage collection on every write barrier invocation + */ public static void setGcEveryWB() { gcEveryWB = true; } @@ -53,6 +58,13 @@ public static void setGcEveryWB() { /** Registered mutators */ protected static final ArrayList mutators = new ArrayList(); + /** + * @return The active mutators + */ + public static java.util.Collection getMutators() { + return Collections.unmodifiableCollection(mutators); + } + /** * Get a mutator by id. */ @@ -188,25 +200,15 @@ public void computeThreadRoots(TraceLocal trace) { } /** - * Print the thread roots and add them to a stack for processing. + * Return the roots */ - public void dumpThreadRoots(int width, Stack roots) { - // Nothing to do for the default mutator - } - - /** - * Format the object for dumping. - */ - public static String formatObject(ObjectReference object) { - return String.format("%s[%d@%s]", object, ObjectModel.getId(object), getSiteName(object)); - } + public abstract Iterable getRoots(); /** - * Format the object for dumping, and trim to a max width. + * Print the thread roots and add them to a stack for processing. */ - public static String formatObject(int width, ObjectReference object) { - String base = formatObject(object); - return base.substring(base.length() - width); + public void dumpThreadRoots(int width, Stack roots) { + // Nothing to do for the default mutator } /** @@ -306,7 +308,7 @@ public void storeDataField(ObjectReference object, int index, int value) { int limit = ObjectModel.getDataCount(object); check(!object.isNull(), "Object can not be null"); check(index >= 0, "Index must be non-negative"); - check(index < limit, "Index out of bounds"); + check(index < limit, "Index "+index+" out of bounds "+limit); Address ref = ObjectModel.getDataSlot(object, index); ref.store(value); @@ -322,12 +324,12 @@ public void storeDataField(ObjectReference object, int index, int value) { */ public void storeReferenceField(ObjectReference object, int index, ObjectReference value) { int limit = ObjectModel.getRefs(object); - if (Trace.isEnabled(Item.STORE)) { - System.err.printf("[%s].object[%d/%d] = %s%n",object.toString(),index,limit,value.toString()); + if (Trace.isEnabled(Item.STORE) || ObjectModel.isWatched(object)) { + Trace.printf(Item.STORE,"[%s].object[%d/%d] = %s",ObjectModel.getString(object),index,limit,value.toString()); } check(!object.isNull(), "Object can not be null"); check(index >= 0, "Index must be non-negative"); - check(index < limit, "Index out of bounds"); + check(index < limit, "Index "+index+" out of bounds "+limit); Address referenceSlot = ObjectModel.getRefSlot(object, index); if (ActivePlan.constraints.needsWriteBarrier()) { @@ -350,11 +352,11 @@ public int loadDataField(ObjectReference object, int index) { int limit = ObjectModel.getDataCount(object); check(!object.isNull(), "Object can not be null"); check(index >= 0, "Index must be non-negative"); - check(index < limit, "Index out of bounds"); + check(index < limit, "Index "+index+" out of bounds "+limit); Address dataSlot = ObjectModel.getDataSlot(object, index); int result = dataSlot.loadInt(); - Trace.trace(Item.LOAD,"[%s].int[%d] returned [%d]",object.toString(),index,result); + Trace.trace(Item.LOAD,"[%s].int[%d] returned [%d]",ObjectModel.getString(object),index,result); return result; } @@ -368,7 +370,7 @@ public ObjectReference loadReferenceField(ObjectReference object, int index) { int limit = ObjectModel.getRefs(object); check(!object.isNull(), "Object can not be null"); check(index >= 0, "Index must be non-negative"); - check(index < limit, "Index out of bounds"); + check(index < limit, "Index "+index+" out of bounds "+limit); Address referenceSlot = ObjectModel.getRefSlot(object, index); ObjectReference result; @@ -377,7 +379,7 @@ public ObjectReference loadReferenceField(ObjectReference object, int index) { } else { result = referenceSlot.loadObjectReference(); } - Trace.trace(Item.LOAD,"[%s].object[%d] returned [%s]",object.toString(),index,result.toString()); + Trace.trace(Item.LOAD,"[%s].object[%d] returned [%s]",ObjectModel.getString(object),index,result.toString()); return result; } @@ -387,7 +389,7 @@ public ObjectReference loadReferenceField(ObjectReference object, int index) { public int hash(ObjectReference object) { check(!object.isNull(), "Object can not be null"); int result = ObjectModel.getHashCode(object); - Trace.trace(Item.HASH,"hash(%s) returned [%d]",object.toString(),result); + Trace.trace(Item.HASH,"hash(%s) returned [%d]",ObjectModel.getString(object),result); return result; } @@ -397,6 +399,7 @@ public int hash(ObjectReference object) { * @param refCount The number of reference fields. * @param dataCount The number of data fields. * @param doubleAlign Is this an 8 byte aligned object? + * @param allocSite Allocation site * @return The object reference. */ public ObjectReference alloc(int refCount, int dataCount, boolean doubleAlign, int allocSite) { @@ -406,6 +409,7 @@ public ObjectReference alloc(int refCount, int dataCount, boolean doubleAlign, i check(dataCount <= ObjectModel.MAX_DATA_FIELDS, "Maximum of "+ObjectModel.MAX_DATA_FIELDS+" data fields per object"); ObjectReference result = ObjectModel.allocateObject(context, refCount, dataCount, doubleAlign, allocSite); Trace.trace(Item.ALLOC,"alloc(" + refCount + ", " + dataCount + ", " + doubleAlign + ") returned [" + result + "]"); + check(result != null, "Allocation returned null"); return result; } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/Checker.java b/MMTk/harness/src/org/mmtk/harness/lang/Checker.java index 7e0648c87..06d95b43e 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/Checker.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/Checker.java @@ -19,6 +19,7 @@ import org.mmtk.harness.lang.Trace.Item; import org.mmtk.harness.lang.ast.AST; import org.mmtk.harness.lang.ast.Alloc; +import org.mmtk.harness.lang.ast.AllocUserType; import org.mmtk.harness.lang.ast.Assert; import org.mmtk.harness.lang.ast.Assignment; import org.mmtk.harness.lang.ast.BinaryExpression; @@ -29,6 +30,7 @@ import org.mmtk.harness.lang.ast.Expression; import org.mmtk.harness.lang.ast.IfStatement; import org.mmtk.harness.lang.ast.LoadField; +import org.mmtk.harness.lang.ast.LoadNamedField; import org.mmtk.harness.lang.ast.Method; import org.mmtk.harness.lang.ast.NormalMethod; import org.mmtk.harness.lang.ast.Operator; @@ -38,11 +40,14 @@ import org.mmtk.harness.lang.ast.Spawn; import org.mmtk.harness.lang.ast.Statement; import org.mmtk.harness.lang.ast.StoreField; -import org.mmtk.harness.lang.ast.Type; +import org.mmtk.harness.lang.ast.StoreNamedField; import org.mmtk.harness.lang.ast.UnaryExpression; import org.mmtk.harness.lang.ast.Variable; import org.mmtk.harness.lang.ast.WhileStatement; import org.mmtk.harness.lang.parser.MethodTable; +import org.mmtk.harness.lang.type.Field; +import org.mmtk.harness.lang.type.Type; +import org.mmtk.harness.lang.type.UserType; /** * A type-checker visitor for MMTk scripts @@ -60,11 +65,6 @@ public static void typeCheck(MethodTable methods) { } } - /** - * The type of the most recently visited expression. - */ - private Type type; - /** * The type of the current method */ @@ -75,18 +75,13 @@ public static void typeCheck(MethodTable methods) { */ private boolean[] isInitialized; - /** - * @return The type of the most recently visited expression. - */ - public Type getType() { return type; } - /** * Visit an expression and return its type. * @param expr * @return */ private Type getTypeOf(Expression expr) { - expr.accept(this); + Type type = (Type)expr.accept(this); Trace.trace(Item.CHECKER,"Type of %s is %s%n",PrettyPrinter.format(expr),type.toString()); return type; } @@ -99,7 +94,7 @@ private Type getTypeOf(Expression expr) { * @return */ private boolean checkType(Expression expr, Type...types) { - getTypeOf(expr); + Type type = getTypeOf(expr); for (Type t : types) { if (type == t) { return true; @@ -113,10 +108,11 @@ private boolean checkType(Expression expr, Type...types) { * @param ast * @param message */ - private static void fail(AST ast, String message) { - System.err.printf("Error at line %d: %s%n",ast.getLine(),message); + private static void fail(AST ast, String message, Object...params) { + String fullMessage = String.format(message,params); + System.err.printf("Error at line %d: %s%n",ast.getLine(),fullMessage); PrettyPrinter.print(System.err, ast); System.err.println(); - throw new RuntimeException(message); + throw new CheckerException(fullMessage); } private void checkParams(AST marker, List actualTypes, List formalTypes) { @@ -138,7 +134,7 @@ private void checkParams(AST marker, List actualTypes, List formalTy @Override - public void visit(Alloc alloc) { + public Object visit(Alloc alloc) { if (!checkType(alloc.getRefCount(),Type.INT)) { fail(alloc,"Allocation reference count must be integer"); } @@ -148,25 +144,33 @@ public void visit(Alloc alloc) { if (!checkType(alloc.getDoubleAlign(),Type.BOOLEAN)) { fail(alloc,"Allocation double align must be boolean"); } - type = Type.OBJECT; + return Type.OBJECT; } @Override - public void visit(Assert ass) { + public Object visit(AllocUserType alloc) { + if (!alloc.getType().isObject() || alloc.getType() == Type.OBJECT) { + fail(alloc,"Can't allocate a %s using alloc(type)",alloc.getType().toString()); + } + return alloc.getType(); + } + + @Override + public Object visit(Assert ass) { checkType(ass.getPredicate(),Type.BOOLEAN); - type = Type.VOID; + return Type.VOID; } @Override - public void visit(Assignment a) { + public Object visit(Assignment a) { isInitialized[a.getSlot()] = true; Type lhsType = a.getSymbol().getType(); checkType(a.getRhs(),lhsType); - type = Type.VOID; + return Type.VOID; } @Override - public void visit(BinaryExpression exp) { + public Object visit(BinaryExpression exp) { Type lhsType = getTypeOf(exp.getLhs()); Type rhsType = getTypeOf(exp.getRhs()); Operator op = exp.getOperator(); @@ -174,8 +178,10 @@ public void visit(BinaryExpression exp) { if (lhsType != rhsType) { // Allow boolean/object comparisons if (op == Operator.EQ || op == Operator.NE) { - if ((lhsType == Type.BOOLEAN && rhsType == Type.OBJECT) || - (lhsType == Type.OBJECT && rhsType == Type.BOOLEAN)) { + if ((lhsType == Type.BOOLEAN && rhsType.isObject()) || + (lhsType.isObject() && rhsType == Type.BOOLEAN)) { + ok = true; + } else if (lhsType.isObject() && rhsType.isObject()){ ok = true; } else { ok = false; @@ -184,18 +190,18 @@ public void visit(BinaryExpression exp) { ok = false; } if (!ok) { - fail(exp,"Type mismatch"); + fail(exp,"Type mismatch between "+lhsType+" and "+rhsType); } } if (Operator.booleanOperators.contains(op)) { - type = Type.BOOLEAN; + return Type.BOOLEAN; } else { - type = lhsType; + return lhsType; } } @Override - public void visit(Call call) { + public Object visit(Call call) { Method m = call.getMethod(); if (call.getParams().size() != m.getParamCount()) { fail(call,"Wrong number of parameters"); @@ -204,34 +210,32 @@ public void visit(Call call) { List actualTypes = new ArrayList(); /* Type-check the actual parameter expressions */ for (Expression param : call.getParams()) { - param.accept(this); - actualTypes.add(type); + actualTypes.add(getTypeOf(param)); } checkParams(call, actualTypes, m.getParamTypes()); if (call.isExpression()) { - type = call.getMethod().getReturnType(); - } else { - type = Type.VOID; + return call.getMethod().getReturnType(); } + return Type.VOID; } @Override - public void visit(Constant c) { - type = c.value.type(); + public Object visit(Constant c) { + return c.value.type(); } @Override - public void visit(Empty e) { - type = Type.VOID; + public Object visit(Empty e) { + return Type.VOID; } @Override - public void visit(Expect exc) { - type = Type.VOID; + public Object visit(Expect exc) { + return Type.VOID; } @Override - public void visit(IfStatement conditional) { + public Object visit(IfStatement conditional) { for (Expression e : conditional.getConds()) { if (!checkType(e,Type.BOOLEAN)) { fail(e,"Conditional must have type BOOLEAN"); @@ -240,38 +244,51 @@ public void visit(IfStatement conditional) { for (Statement s : conditional.getStmts()) { s.accept(this); } - type = Type.VOID; + return Type.VOID; } @Override - public void visit(LoadField load) { + public Object visit(LoadField load) { if (load.getObjectSymbol().getType() != Type.OBJECT) { fail(load,"Target of loadfield must be an Object"); } - load.getIndex().accept(this); - if (type != Type.INT) { + if (getTypeOf(load.getIndex()) != Type.INT) { fail(load,"Loadfield index must have type INTEGER"); } - type = load.getFieldType(); + return load.getFieldType(); } @Override - public void visit(NormalMethod method) { + public Object visit(LoadNamedField load) { + Type t = load.getObjectSymbol().getType(); + if (!t.isObject()) { + fail(load,"Target of loadfield must be an Object type"); + } + UserType objectType = (UserType)t; + Field field = objectType.getField(load.getFieldName()); + if (field == null) { + fail(load,"Type %s does not have a field called %s",t,load.getFieldName()); + } + return field.getType(); + } + + @Override + public Object visit(NormalMethod method) { isInitialized = new boolean[method.getDecls().size()]; for (Declaration decl : method.getParams()) { isInitialized[decl.getSlot()] = true; } returnType = method.getReturnType(); method.getBody().accept(this); - type = returnType; + return returnType; } @Override - public void visit(PrintStatement print) { + public Object visit(PrintStatement print) { for (Expression exp : print.getArgs()) { exp.accept(this); } - type = Type.VOID; + return Type.VOID; } /** @@ -281,22 +298,22 @@ public void visit(PrintStatement print) { * declared type of the method */ @Override - public void visit(Return ret) { + public Object visit(Return ret) { if (ret.hasReturnValue()) { - ret.getRhs().accept(this); + Type type = getTypeOf(ret.getRhs()); if (!returnType.isCompatibleWith(type)) { fail(ret,"Returning a "+type+" in a method declared as "+returnType); } + return type; } else if (returnType != Type.VOID) { - fail(ret,"Returning from a non-void method requires a return value"); - } else { - type = Type.VOID; + fail(ret,"Returning from a non-Object method requires a return value"); } + return Type.VOID; } @Override - public void visit(Sequence ass) { - super.visit(ass); + public Object visit(Sequence seq) { + return super.visit(seq); } /** @@ -305,55 +322,78 @@ public void visit(Sequence ass) { * - Actual parameters against method formal parameters */ @Override - public void visit(Spawn sp) { + public Object visit(Spawn sp) { List actualTypes = new ArrayList(); for (Expression expr : sp.getArgs()) { - expr.accept(this); - actualTypes.add(type); + actualTypes.add(getTypeOf(expr)); } checkParams(sp, actualTypes, sp.getMethod().getParamTypes()); - type = Type.VOID; + return Type.VOID; } @Override - public void visit(StoreField store) { + public Object visit(StoreField store) { if (store.getObjectSymbol().getType() != Type.OBJECT) { fail(store,"Target of storefield must be an Object"); } if (getTypeOf(store.getIndex()) != Type.INT) { fail(store,"Storefield index must have type INTEGER"); } - if (getTypeOf(store.getRhs()) != store.getFieldType()) { - fail(store,"Storefield to a "+store.getFieldType()+" must have type "+store.getFieldType()); + Type rhsType = getTypeOf(store.getRhs()); + Type fieldType = store.getFieldType(); + if (!fieldType.isCompatibleWith(rhsType)) { + fail(store,"Storefield to a "+fieldType+" must have type "+fieldType+", not "+rhsType); + } + return Type.VOID; + } + + @Override + public Object visit(StoreNamedField store) { + assert store.getObjectSymbol() != null; + assert store.getObjectSymbol().getType() != null; + Type t = store.getObjectSymbol().getType(); + if (!t.isObject()) { + fail(store,"Target of storefield.name (%s) must be an object type, not %s", + store.getObjectSymbol().getName(),t.getName()); } - type = Type.VOID; + UserType objectType = (UserType)t; + Field field = objectType.getField(store.getFieldName()); + if (field == null) { + fail(store,"The type "+objectType+" does not have a field called "+store.getFieldName()); + } + Type fieldType = field.getType(); + if (!fieldType.isCompatibleWith(getTypeOf(store.getRhs()))) { + fail(store,"Storefield to a "+fieldType+" must have type "+fieldType); + } + return Type.VOID; } @Override - public void visit(UnaryExpression exp) { + public Object visit(UnaryExpression exp) { /* Unary operators preserve type */ - exp.getOperand().accept(this); + Type type = getTypeOf(exp.getOperand()); /* With this one exception ... */ if (exp.getOperator() == Operator.NOT && type == Type.OBJECT) { - type = Type.BOOLEAN; + return Type.BOOLEAN; } + return type; } @Override - public void visit(Variable var) { + public Object visit(Variable var) { if (!isInitialized[var.getSlot()]) { fail(var,"Variable "+var.getSymbol().getName()+" is not initialized before use"); } - type = var.getSymbol().getType(); + return var.getSymbol().getType(); } @Override - public void visit(WhileStatement w) { + public Object visit(WhileStatement w) { if (!checkType(w.getCond(),Type.BOOLEAN,Type.OBJECT)) { fail(w,"While condition must have type BOOLEAN"); } w.getBody().accept(this); - type = Type.VOID; + return Type.VOID; } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/Compiler.java b/MMTk/harness/src/org/mmtk/harness/lang/Compiler.java index 00a206860..9bf33c86a 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/Compiler.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/Compiler.java @@ -17,7 +17,10 @@ import java.util.List; import org.mmtk.harness.Harness; +import org.mmtk.harness.lang.Trace.Item; +import org.mmtk.harness.lang.ast.AST; import org.mmtk.harness.lang.ast.Alloc; +import org.mmtk.harness.lang.ast.AllocUserType; import org.mmtk.harness.lang.ast.Assert; import org.mmtk.harness.lang.ast.Assignment; import org.mmtk.harness.lang.ast.BinaryExpression; @@ -29,6 +32,7 @@ import org.mmtk.harness.lang.ast.IfStatement; import org.mmtk.harness.lang.ast.IntrinsicMethod; import org.mmtk.harness.lang.ast.LoadField; +import org.mmtk.harness.lang.ast.LoadNamedField; import org.mmtk.harness.lang.ast.Method; import org.mmtk.harness.lang.ast.NormalMethod; import org.mmtk.harness.lang.ast.PrintStatement; @@ -37,7 +41,7 @@ import org.mmtk.harness.lang.ast.Statement; import org.mmtk.harness.lang.ast.Spawn; import org.mmtk.harness.lang.ast.StoreField; -import org.mmtk.harness.lang.ast.Type; +import org.mmtk.harness.lang.ast.StoreNamedField; import org.mmtk.harness.lang.ast.UnaryExpression; import org.mmtk.harness.lang.ast.Variable; import org.mmtk.harness.lang.ast.WhileStatement; @@ -48,6 +52,7 @@ import org.mmtk.harness.lang.compiler.Temporary; import org.mmtk.harness.lang.parser.MethodTable; import org.mmtk.harness.lang.pcode.AllocOp; +import org.mmtk.harness.lang.pcode.AllocUserOp; import org.mmtk.harness.lang.pcode.BinaryOperation; import org.mmtk.harness.lang.pcode.Branch; import org.mmtk.harness.lang.pcode.CallIntrinsicOp; @@ -56,14 +61,19 @@ import org.mmtk.harness.lang.pcode.ExpectOp; import org.mmtk.harness.lang.pcode.Goto; import org.mmtk.harness.lang.pcode.LoadFieldOp; +import org.mmtk.harness.lang.pcode.LoadFixedFieldOp; import org.mmtk.harness.lang.pcode.PrintOp; import org.mmtk.harness.lang.pcode.PseudoOp; import org.mmtk.harness.lang.pcode.ReturnOp; import org.mmtk.harness.lang.pcode.SpawnOp; import org.mmtk.harness.lang.pcode.StoreFieldOp; +import org.mmtk.harness.lang.pcode.StoreFixedFieldOp; import org.mmtk.harness.lang.pcode.StoreLocal; import org.mmtk.harness.lang.pcode.UnaryOperation; import org.mmtk.harness.lang.runtime.ConstantPool; +import org.mmtk.harness.lang.type.Field; +import org.mmtk.harness.lang.type.Type; +import org.mmtk.harness.lang.type.UserType; public final class Compiler extends Visitor { @@ -75,7 +85,6 @@ public final class Compiler extends Visitor { private final CompiledMethod current; private final CompiledMethodTable methodTable; private final Temporary temps; - private final UnsyncStack operands = new UnsyncStack(); private Compiler(NormalMethod method, CompiledMethodTable table) { this.current = new CompiledMethod(method); @@ -109,6 +118,7 @@ public CompiledMethod yield() { } private void emit(PseudoOp op) { + Trace.trace(Item.COMPILER, "emitting %s", op); current.append(op); } @@ -125,8 +135,7 @@ private void freeTemps(List actuals) { private List compileArgList(List args) { ArrayList actuals = new ArrayList(args.size()); for (Expression exp : args) { - exp.accept(this); - actuals.add(operands.pop()); + actuals.add(compile(exp)); } return actuals; } @@ -139,64 +148,73 @@ private CompiledMethod compiledMethodFor(Method method) { return compiledMethod; } + /** + * Visit a node and return its result as a Register + * @param ast + * @return + */ + private Register compile(AST ast) { + return (Register)ast.accept(this); + } @Override - public void visit(Alloc alloc) { - alloc.getDataCount().accept(this); - Register dataCount = operands.pop(); - alloc.getRefCount().accept(this); - Register refCount = operands.pop(); - alloc.getDoubleAlign().accept(this); - Register doubleAlign = operands.pop(); + public Object visit(Alloc alloc) { + Register dataCount = compile(alloc.getDataCount()); + Register refCount = compile(alloc.getRefCount()); + Register doubleAlign = compile(alloc.getDoubleAlign()); Register result = temps.acquire(); emit(new AllocOp(alloc,result,dataCount,refCount,doubleAlign,alloc.getSite())); - operands.push(result); temps.release(dataCount,refCount,doubleAlign); + return result; + } + + @Override + public Object visit(AllocUserType alloc) { + UserType type = (UserType)alloc.getType(); + Register result = temps.acquire(); + emit(new AllocUserOp(alloc,result,type,false,alloc.getSite())); + return result; } @Override - public void visit(Assert ass) { - ass.getPredicate().accept(this); // Compile the predicate - Register predicate = operands.pop(); + public Object visit(Assert ass) { + Register predicate = compile(ass.getPredicate()); Branch branch = new Branch(ass,predicate,true); emit(branch); temps.release(predicate); ArrayList actuals = new ArrayList(ass.getOutputs().size()); for (Expression expr : ass.getOutputs()) { - expr.accept(this); - actuals.add(operands.pop()); + actuals.add(compile(expr)); } emit(new PrintOp(ass,actuals.toArray(new Register[0]))); freeTemps(actuals); emit(new ExitOp(ass,ConstantPool.ONE)); branch.setBranchTarget(currentPc()); + return null; } @Override - public void visit(Assignment a) { - a.getRhs().accept(this); - Register rhs = operands.pop(); + public Object visit(Assignment a) { + Trace.trace(Item.COMPILER, "Compiling %s", PrettyPrinter.format(a)); + Register rhs = compile(a.getRhs()); emit(new StoreLocal(a,Register.createLocal(a.getSlot()),rhs)); temps.release(rhs); + return null; } @Override - public void visit(BinaryExpression exp) { - exp.getLhs().accept(this); - Register lhs = operands.pop(); - exp.getRhs().accept(this); - Register rhs = operands.pop(); + public Object visit(BinaryExpression exp) { + Register lhs = compile(exp.getLhs()); + Register rhs = compile(exp.getRhs()); Register result = temps.acquire(); emit(new BinaryOperation(exp,result,lhs,rhs,exp.getOperator())); temps.release(rhs,lhs); - operands.push(result); + return result; } @Override - public void visit(Call call) { + public Object visit(Call call) { Method method = call.getMethod(); - - List actuals = compileArgList(call.getParams()); Register returnVal = method.getReturnType() == Type.VOID ? Register.NULL : temps.acquire(); @@ -210,8 +228,7 @@ public void visit(Call call) { throw new RuntimeException("Unknown method class "+method.getClass().getCanonicalName()); } freeTemps(actuals); - if (returnVal != Register.NULL) - operands.push(returnVal); + return returnVal; } /** @@ -219,29 +236,29 @@ public void visit(Call call) { * global constant pool */ @Override - public void visit(Constant c) { - operands.push(ConstantPool.acquire(c.value)); + public Object visit(Constant c) { + return ConstantPool.acquire(c.value); } @Override - public void visit(Empty e) { - // Do nothing + public Object visit(Empty e) { + return null; } @Override - public void visit(Expect exp) { + public Object visit(Expect exp) { emit(new ExpectOp(exp,exp.getExpected())); + return null; } @Override - public void visit(IfStatement conditional) { + public Object visit(IfStatement conditional) { Iterator stmtIter = conditional.getStmts().iterator(); Branch branch = new Branch(conditional,Register.NULL,false); Goto gotoExit = new Goto(conditional); for (Expression cond : conditional.getConds()) { branch.setBranchTarget(currentPc()); - cond.accept(this); - Register conditionReg = operands.pop(); + Register conditionReg = compile(cond); branch = new Branch(conditional,conditionReg,false); temps.release(conditionReg); emit(branch); @@ -253,78 +270,106 @@ public void visit(IfStatement conditional) { stmtIter.next().accept(this); } gotoExit.setBranchTarget(currentPc()); + return null; } @Override - public void visit(IntrinsicMethod method) { + public Object visit(IntrinsicMethod method) { throw new RuntimeException("You can't compile an intrinsic method!!!"); } @Override - public void visit(LoadField load) { - load.getIndex().accept(this); - Register index = operands.pop(); + public Object visit(LoadField load) { + Register index = compile(load.getIndex()); Register object = Register.createLocal(load.getSlot()); Register result = temps.acquire(); emit(new LoadFieldOp(load,result,object,index,load.getFieldType())); temps.release(index); - operands.push(result); + return result; } @Override - public void visit(NormalMethod method) { - method.getBody().accept(this); + public Object visit(LoadNamedField load) { + UserType type = (UserType)load.getObjectSymbol().getType(); + Field field = type.getField(load.getFieldName()); + Register object = Register.createLocal(load.getSlot()); + Register result = temps.acquire(); + emit(new LoadFixedFieldOp(load,result,object,field.getOffset(), + load.getFieldName(), + field.getType().isObject() ? Type.OBJECT : Type.INT)); + return result; + } + + @Override + public Object visit(NormalMethod method) { + compile(method.getBody()); emit(new ReturnOp(method)); + return null; } @Override - public void visit(PrintStatement print) { + public Object visit(PrintStatement print) { List args = print.getArgs(); List actuals = compileArgList(args); emit(new PrintOp(print,actuals)); freeTemps(actuals); + return null; } @Override - public void visit(Return ret) { + public Object visit(Return ret) { if (ret.hasReturnValue()) { - ret.getRhs().accept(this); - emit(new ReturnOp(ret,operands.pop())); + emit(new ReturnOp(ret,compile(ret.getRhs()))); } else { emit(new ReturnOp(ret)); } + return null; } @Override - public void visit(Sequence ass) { + public Object visit(Sequence ass) { for (Statement stmt : ass) { - stmt.accept(this); + compile(stmt); } + return null; } @Override - public void visit(Spawn sp) { + public Object visit(Spawn sp) { List actuals = compileArgList(sp.getArgs()); emit(new SpawnOp(sp,compiledMethodFor(sp.getMethod()),actuals)); freeTemps(actuals); + return null; } @Override - public void visit(StoreField store) { - store.getIndex().accept(this); - Register index = operands.pop(); - store.getRhs().accept(this); - Register value = operands.pop(); + public Object visit(StoreField store) { + Register index = compile(store.getIndex()); + Register value = compile(store.getRhs()); Register object = Register.createLocal(store.getSlot()); emit(new StoreFieldOp(store,object,index,value,store.getFieldType())); temps.release(index,value); + return null; } @Override - public void visit(UnaryExpression exp) { - exp.getOperand().accept(this); - Register operand = operands.peek(); - emit(new UnaryOperation(exp,operand,operand,exp.getOperator())); + public Object visit(StoreNamedField store) { + Field field = store.getField(); + Register value = compile(store.getRhs()); + Register object = Register.createLocal(store.getSlot()); + emit(new StoreFixedFieldOp(store,object,field.getOffset(),store.getFieldName(),value, + field.getType().isObject() ? Type.OBJECT : Type.INT)); + temps.release(value); + return null; + } + + @Override + public Object visit(UnaryExpression exp) { + Register operand = compile(exp.getOperand()); + Register result = temps.acquire(); + emit(new UnaryOperation(exp,result,operand,exp.getOperator())); + temps.release(operand); + return result; } /** @@ -332,8 +377,8 @@ public void visit(UnaryExpression exp) { * the appropriate stack frame slot. */ @Override - public void visit(Variable var) { - operands.push(Register.createLocal(var.getSlot())); + public Object visit(Variable var) { + return Register.createLocal(var.getSlot()); } /** @@ -345,16 +390,16 @@ public void visit(Variable var) { * b: */ @Override - public void visit(WhileStatement w) { + public Object visit(WhileStatement w) { int top = currentPc(); - w.getCond().accept(this); // Compile the loop condition - Register cond = operands.pop(); + Register cond = compile(w.getCond()); Branch branchToExit = new Branch(w,cond,false); temps.release(cond); emit(branchToExit); - w.getBody().accept(this); + compile(w.getBody()); emit(new Goto(w,top)); branchToExit.setBranchTarget(currentPc()); + return null; } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/Declaration.java b/MMTk/harness/src/org/mmtk/harness/lang/Declaration.java index 8fdc71d4d..ac787924a 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/Declaration.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/Declaration.java @@ -12,9 +12,9 @@ */ package org.mmtk.harness.lang; -import org.mmtk.harness.lang.ast.Type; import org.mmtk.harness.lang.parser.Symbol; import org.mmtk.harness.lang.runtime.Value; +import org.mmtk.harness.lang.type.Type; /** * A variable declaration diff --git a/MMTk/harness/src/org/mmtk/harness/lang/Env.java b/MMTk/harness/src/org/mmtk/harness/lang/Env.java index b24e841ee..a8093d4dd 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/Env.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/Env.java @@ -12,11 +12,15 @@ */ package org.mmtk.harness.lang; +import java.util.ArrayList; +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; +import org.mmtk.harness.lang.runtime.ObjectValue; import org.mmtk.harness.lang.runtime.StackFrame; import org.mmtk.plan.TraceLocal; import org.vmmagic.unboxed.ObjectReference; @@ -61,14 +65,14 @@ public void pop() { } /** - * The frame at the top of the stack. + * @return The frame at the top of the stack. */ public StackFrame top() { return stack.peek(); } /** - * + * @return The current stack */ public Iterable stack() { return stack; @@ -86,6 +90,15 @@ public void computeThreadRoots(TraceLocal trace) { Trace.trace(Item.ROOTS, "Locals: %d", localCount); } + @Override + public Collection getRoots() { + List roots = new ArrayList(); + for (StackFrame frame : stack) { + roots.addAll(frame.getRoots()); + } + return roots; + } + /** * Print the thread roots and add them to a stack for processing. */ diff --git a/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java b/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java index bd859e575..a29b8d90c 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/Intrinsics.java @@ -68,7 +68,7 @@ public static void setRandomSeed(Env env, int seed) { * @return */ public static int random(Env env, int low, int high) { - return (int)(env.random().nextInt(high-low+1) + low); + return env.random().nextInt(high-low+1) + low; } /** diff --git a/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java b/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java index 68d5d2d89..727875fc0 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/PrettyPrinter.java @@ -20,6 +20,7 @@ import org.mmtk.harness.lang.ast.AST; import org.mmtk.harness.lang.ast.Alloc; +import org.mmtk.harness.lang.ast.AllocUserType; import org.mmtk.harness.lang.ast.Assert; import org.mmtk.harness.lang.ast.Assignment; import org.mmtk.harness.lang.ast.Call; @@ -27,6 +28,7 @@ import org.mmtk.harness.lang.ast.Expression; import org.mmtk.harness.lang.ast.IfStatement; import org.mmtk.harness.lang.ast.LoadField; +import org.mmtk.harness.lang.ast.LoadNamedField; import org.mmtk.harness.lang.ast.Method; import org.mmtk.harness.lang.ast.NormalMethod; import org.mmtk.harness.lang.ast.Operator; @@ -36,10 +38,12 @@ import org.mmtk.harness.lang.ast.Spawn; import org.mmtk.harness.lang.ast.Statement; import org.mmtk.harness.lang.ast.StoreField; +import org.mmtk.harness.lang.ast.StoreNamedField; import org.mmtk.harness.lang.ast.Variable; 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; public class PrettyPrinter extends Visitor { @@ -100,8 +104,8 @@ String read() { @Override - public void visit(NormalMethod method) { - fmt.out("%s(",method.getName()); + public Object visit(NormalMethod method) { + fmt.out("%s %s(",method.getReturnType(),method.getName()); boolean first = true; for (Declaration decl : method.getParams()) { if (first) { @@ -116,10 +120,11 @@ public void visit(NormalMethod method) { method.getBody().accept(this); fmt.decreaseIndent(); fmt.out("%s}",fmt.margin()); fmt.newline(); + return null; } @Override - public void visit(Call call) { + public Object visit(Call call) { fmt.out("%s(",call.getMethod().getName()); boolean first = true; for (Expression param : call.getParams()) { @@ -131,24 +136,27 @@ public void visit(Call call) { param.accept(this); } fmt.out(")"); + return null; } @Override - public void visit(Sequence ass) { + public Object visit(Sequence ass) { for (Statement stmt : ass) { stmt.accept(this); fmt.newline(); } + return null; } @Override - public void visit(Assignment a) { + public Object visit(Assignment a) { fmt.out("%s = ", a.getSymbol().getName()); a.getRhs().accept(this); fmt.out(";"); + return null; } @Override - public void visit(IfStatement conditional) { + public Object visit(IfStatement conditional) { String keyword = "if"; Iterator condIter = conditional.getConds().iterator(); Iterator bodyIter = conditional.getStmts().iterator(); @@ -172,11 +180,11 @@ public void visit(IfStatement conditional) { fmt.decreaseIndent(); fmt.out("}"); } -// fmt.newline(); + return null; } @Override - public void visit(WhileStatement w) { + public Object visit(WhileStatement w) { fmt.out("while ("); w.getCond().accept(this); fmt.out(") {"); fmt.newline(); @@ -184,52 +192,72 @@ public void visit(WhileStatement w) { w.getBody().accept(this); fmt.decreaseIndent(); fmt.out("}"); -// fmt.newline(); + return null; } @Override - public void visit(Operator op) { + public Object visit(Operator op) { fmt.out(" %s ", op.toString()); + return null; } @Override - public void visit(LoadField load) { + public Object visit(LoadField load) { fmt.out("%s.%s[", load.getObjectSymbol().getName(), load.getFieldType().toString()); load.getIndex().accept(this); fmt.out("]"); + return null; } @Override - public void visit(Constant c) { + public Object visit(LoadNamedField load) { + fmt.out("%s.%s", load.getObjectSymbol().getName(), load.getFieldName()); + return null; + } + + @Override + public Object visit(Constant c) { fmt.out(c.value.toString()); + return null; } @Override - public void visit(Variable var) { + public Object visit(Variable var) { fmt.out("%s", var.getSymbol().getName()); + return null; } @Override - public void visit(StoreField store) { + public Object visit(StoreField store) { fmt.out("%s.%s[",store.getObjectSymbol().getName(), store.getFieldType().toString()); store.getIndex().accept(this); fmt.out("] := "); store.getRhs().accept(this); fmt.out(";"); + return null; } @Override - public void visit(Return ret) { + public Object visit(StoreNamedField store) { + fmt.out("%s.%s := ",store.getObjectSymbol().getName(), store.getFieldName()); + store.getRhs().accept(this); + fmt.out(";"); + return null; + } + + @Override + public Object visit(Return ret) { fmt.out("return"); if (ret.hasReturnValue()) { fmt.out(" "); ret.getRhs().accept(this); } fmt.out(";"); + return null; } @Override - public void visit(Assert ass) { + public Object visit(Assert ass) { fmt.out("assert("); ass.getPredicate().accept(this); for (Expression expr : ass.getOutputs()) { @@ -237,17 +265,19 @@ public void visit(Assert ass) { expr.accept(this); } fmt.out(");"); + return null; } @Override - public void visit(Declaration decl) { + public Object visit(Declaration decl) { fmt.out("%s %s", decl.getType(), decl.getName()); + return null; } @Override - public void visit(PrintStatement print) { + public Object visit(PrintStatement print) { fmt.out("print"); String separator = "("; for (Expression expr : print.getArgs()) { @@ -256,10 +286,11 @@ public void visit(PrintStatement print) { expr.accept(this); } fmt.out(");"); + return null; } @Override - public void visit(Alloc alloc) { + public Object visit(Alloc alloc) { fmt.out("alloc("); alloc.getDataCount().accept(this); fmt.out(","); @@ -269,10 +300,17 @@ public void visit(Alloc alloc) { alloc.getDoubleAlign().accept(this); } fmt.out(")"); + return null; + } + + @Override + public Object visit(AllocUserType alloc) { + fmt.out("alloc(%s)",alloc.getType()); + return null; } @Override - public void visit(Spawn spawn) { + public Object visit(Spawn spawn) { fmt.out("spawn"); String separator = "("; for (Expression expr : spawn.getArgs()) { @@ -280,6 +318,7 @@ public void visit(Spawn spawn) { expr.accept(this); } fmt.out(");"); + return null; } @@ -337,6 +376,7 @@ private static void printMethodTable(MethodTable methods) { } public static void main(String[] args) { + ArchitecturalWord.init(); try { MethodTable methods = new Parser(new BufferedInputStream(new FileInputStream(args[0]))).script(); PrettyPrinter.printMethodTable(methods); diff --git a/MMTk/harness/src/org/mmtk/harness/lang/Trace.java b/MMTk/harness/src/org/mmtk/harness/lang/Trace.java index fe6ab8430..cc7dd5b5d 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/Trace.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/Trace.java @@ -14,16 +14,46 @@ import java.util.EnumSet; +/** + * Tracing of events in the harness, both for debugging MMTk + * and the harness itself. + * + * Tracing can be enabled using the command-line trace=ITEM parameter, + * or by setting Trace.enable(Item.xx) in the code. + */ public final class Trace { - public enum Item { ALLOC, CALL, OBJECT, INTRINSIC, LOAD, STORE, HASH, ENV, - ROOTS, COLLECT, AVBYTE, EVAL, COMPILER, CHECKER, SCHEDULER } + /** + * Items that can be traced. + */ + public enum Item { + /** Object allocation */ ALLOC, + /** Procedure calls in the harness language */ CALL, + /** Object reads and writes */ OBJECT, + /** Calls to intrinsic methods in the harness language */ INTRINSIC, + /** Load operations in the harness language */ LOAD, + /** Store operations in the harness language */ STORE, + /** Hashcode operations */ HASH, + /** Environment (stack frame) loads/stores */ ENV, + /** Tracing of roots */ ROOTS, + /** Garbage collection */ COLLECT, + /** Available byte operations */ AVBYTE, + /** P-code evaluation */ EVAL, + /** P-code compiler */ COMPILER, + /** Harness language semantic checker */ CHECKER, + /** Harness language thread scheduler */ SCHEDULER, + /** Harness language parser */ PARSER, + /** Harness language simplifier */ SIMPLIFIER + } private static EnumSet enabled = EnumSet.noneOf(Item.class); static { - //enable(Item.ALLOC); + //enable(Item.ENV); } + /** + * @return the names of the items in the Item enumeration + */ public static String[] itemNames() { String[] result = new String[Item.values().length+1]; result[0] = "NONE"; @@ -33,21 +63,34 @@ public static String[] itemNames() { return result; } + /** + * Enable tracing of the given item + * @param item Item to trace + */ public static void enable(String item) { enable(Item.valueOf(item)); } + /** + * Enable tracing of the given item + * @param item Item to trace + */ public static void enable(Item item) { enabled.add(item); } + /** + * Is the given item enabled for tracing ? + * @param item The trace item + * @return Is the given item enabled for tracing ? + */ public static boolean isEnabled(Item item) { return enabled.contains(item); } public static synchronized void trace(Item item, String pattern, Object...args) { if (isEnabled(item)) { - printf(prefix(item) + pattern + "%n",args); + printf(item, pattern, args); } } @@ -55,6 +98,10 @@ public static String prefix(Item item) { return "["+item+"] "; } + public static void printf(Item item, String pattern, Object... args) { + printf(prefix(item) + pattern + "%n",args); + } + public static void printf(String pattern, Object...args) { System.err.printf(pattern,args); } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/Visitor.java b/MMTk/harness/src/org/mmtk/harness/lang/Visitor.java index dc0e3cf15..885f0ba08 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/Visitor.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/Visitor.java @@ -14,6 +14,7 @@ import org.mmtk.harness.lang.ast.AST; import org.mmtk.harness.lang.ast.Alloc; +import org.mmtk.harness.lang.ast.AllocUserType; import org.mmtk.harness.lang.ast.Assert; import org.mmtk.harness.lang.ast.Assignment; import org.mmtk.harness.lang.ast.BinaryExpression; @@ -25,6 +26,7 @@ import org.mmtk.harness.lang.ast.IfStatement; import org.mmtk.harness.lang.ast.IntrinsicMethod; import org.mmtk.harness.lang.ast.LoadField; +import org.mmtk.harness.lang.ast.LoadNamedField; import org.mmtk.harness.lang.ast.Method; import org.mmtk.harness.lang.ast.MethodProxy; import org.mmtk.harness.lang.ast.NormalMethod; @@ -35,6 +37,7 @@ import org.mmtk.harness.lang.ast.Spawn; import org.mmtk.harness.lang.ast.Statement; import org.mmtk.harness.lang.ast.StoreField; +import org.mmtk.harness.lang.ast.StoreNamedField; import org.mmtk.harness.lang.ast.UnaryExpression; import org.mmtk.harness.lang.ast.Variable; import org.mmtk.harness.lang.ast.WhileStatement; @@ -45,96 +48,127 @@ */ public abstract class Visitor { - public void visit(AST ast) { } - public void visit(Alloc alloc) { + public Object visit(AST ast) { return ast; } + public Object visit(Alloc alloc) { alloc.getDataCount().accept(this); alloc.getRefCount().accept(this); alloc.getDoubleAlign().accept(this); + return alloc; } - public void visit(Assert ass) { + public Object visit(AllocUserType alloc) { + return alloc; + } + public Object visit(Assert ass) { ass.getPredicate().accept(this); for (AST a : ass.getOutputs()) { a.accept(this); } + return ass; } - public void visit(Assignment a) { + public Object visit(Assignment a) { a.getRhs().accept(this); + return a; } - public void visit(BinaryExpression exp) { + public Object visit(BinaryExpression exp) { exp.getLhs().accept(this); exp.getOperator().accept(this); exp.getRhs().accept(this); + return exp; } - public void visit(Call call) { + public Object visit(Call call) { for (Expression param : call.getParams()) { param.accept(this); } call.getMethod().accept(this); + return call; } - public void visit(Constant c) { } - public void visit(Declaration decl) { } - public void visit(Empty e) { } - public void visit(Expect exc) { } - public void visit(IfStatement conditional) { + public Object visit(Constant c) { return c; } + public Object visit(Declaration decl) { return decl; } + public Object visit(Empty e) { return e; } + public Object visit(Expect exc) { return exc; } + public Object visit(IfStatement conditional) { for (Expression cond : conditional.getConds()) { cond.accept(this); } for (Statement stmt: conditional.getStmts()) { stmt.accept(this); } + return conditional; } - public void visit(IntrinsicMethod method) { + public Object visit(IntrinsicMethod method) { + return method; } - public void visit(LoadField load) { + public Object visit(LoadField load) { load.getIndex().accept(this); + return load; + } + public Object visit(LoadNamedField load) { + return load; } - public void visit(Method method) { + public Object visit(Method method) { System.err.println("Fall-through to Method visitor"); + return method; } - public void visit(MethodProxy proxy) { + public Object visit(MethodProxy proxy) { proxy.getMethod().accept(this); + return proxy; } - public void visit(NormalMethod method) { + public Object visit(NormalMethod method) { for (Declaration decl : method.getDecls()) { decl.accept(this); } method.getBody().accept(this); + return method; } - public void visit(Operator op) { + public Object visit(Operator op) { op.accept(this); + return op; } - public void visit(PrintStatement print) { + public Object visit(PrintStatement print) { for (Expression e : print.getArgs()) { e.accept(this); } + return print; } - public void visit(Return ret) { + public Object visit(Return ret) { if (ret.hasReturnValue()) { ret.getRhs().accept(this); } + return ret; } - public void visit(Sequence ass) { + public Object visit(Sequence ass) { for (Statement stmt : ass) { stmt.accept(this); } + return ass; } - public void visit(Spawn sp) { + public Object visit(Spawn sp) { for (AST arg : sp.getArgs()) { arg.accept(this); } sp.getMethod().accept(this); + return sp; } - public void visit(StoreField store) { + public Object visit(StoreField store) { store.getIndex().accept(this); store.getRhs().accept(this); + return store; } - public void visit(UnaryExpression exp) { + public Object visit(StoreNamedField store) { + store.getRhs().accept(this); + return store; + } + public Object visit(UnaryExpression exp) { exp.getOperator().accept(this); exp.getOperand().accept(this); + return exp; + } + public Object visit(Variable var) { + return var; } - public void visit(Variable var) { } - public void visit(WhileStatement w) { + public Object visit(WhileStatement w) { w.getCond().accept(this); w.getBody().accept(this); + return w; } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/AST.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/AST.java index ebddb3f1c..ed8a90df0 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/AST.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/AST.java @@ -13,6 +13,7 @@ package org.mmtk.harness.lang.ast; import org.mmtk.harness.lang.Visitor; +import org.mmtk.harness.lang.parser.Token; /** * Abstract parent of all the components of an AST @@ -20,11 +21,13 @@ public interface AST { /** Accept visitors */ - void accept(Visitor v); + Object accept(Visitor v); int getLine(); int getColumn(); + Token getToken(); + String sourceLocation(String prefix); } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/AbstractAST.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/AbstractAST.java index a4fe0e7ff..97b581a84 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/AbstractAST.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/AbstractAST.java @@ -12,13 +12,14 @@ */ package org.mmtk.harness.lang.ast; +import org.mmtk.harness.lang.Visitor; import org.mmtk.harness.lang.parser.Source; import org.mmtk.harness.lang.parser.Token; /** * Abstract parent of all the components of an AST */ -public abstract class AbstractAST implements AST { +public class AbstractAST implements AST { /* * Track the current source file - assumes only one source file @@ -43,45 +44,59 @@ public static void clearCurrentSource() { /* The source file */ private Source source = currentSource; - /** Source code line corresponding to this syntax element */ - private final int line; - /** Source code column corresponding to this syntax element */ - private final int column; + /** Source code token corresponding to this syntax element */ + private final Token t; - protected AbstractAST(Token t) { - this(t.beginLine, t.beginColumn); + public AbstractAST(Token t) { + this.t = t; } + /** + * Constructor only for AST elements that don't have a direct correspondance + * to the source. + * @param line + * @param column + */ protected AbstractAST(int line, int column) { - this.line = line; - this.column = column; + Token tok = new Token(); + tok.beginLine = line; + tok.beginColumn = column; + this.t = tok; + } + + public Token getToken() { + return t; } @Override public int getLine() { - return line; + return t.beginLine; } @Override public int getColumn() { - return column; + return t.beginColumn; } @Override public String sourceLocation(String prefix) { if (source == null) { return prefix+""; - } else { - return prefix+source.getLine(line)+"\n"+ - spaces(prefix.length())+spaces(column-1)+"^"; } + return prefix+source.getLine(getLine())+"\n"+ + spaces(prefix.length())+spaces(getColumn()-1)+"^"; } - private String spaces(int n) { + private static String spaces(int n) { StringBuilder str = new StringBuilder(n); for (int i=0; i < n; i++) { str.append(' '); } return str.toString(); } + + @Override + public Object accept(Visitor v) { + throw new UnsupportedOperationException(); + } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Alloc.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Alloc.java index 2e1ae1cff..eff096cd9 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Alloc.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Alloc.java @@ -36,8 +36,8 @@ public Alloc(Token t, int site, Expression refCount, Expression dataCount, Expre this.doubleAlign = doubleAlign; } - public void accept(Visitor v) { - v.visit(this); + public Object accept(Visitor v) { + return v.visit(this); } public int getSite() { return site; } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Assert.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Assert.java index 2e251a537..1b3b2301a 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Assert.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Assert.java @@ -36,8 +36,8 @@ public Assert(Token t, Expression cond, List exprs) { this.exprs = exprs; } - public void accept(Visitor v) { - v.visit(this); + public Object accept(Visitor v) { + return v.visit(this); } public Expression getPredicate() { return cond; } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Assignment.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Assignment.java index 2976ab58f..b645834b3 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Assignment.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Assignment.java @@ -34,8 +34,8 @@ public Assignment(Token t, Symbol variable, Expression expr) { this.expr = expr; } - public void accept(Visitor v) { - v.visit(this); + public Object accept(Visitor v) { + return v.visit(this); } public int getSlot() { return symbol.getLocation(); } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/BinaryExpression.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/BinaryExpression.java index 3be9ddb2e..d7b5b70d7 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/BinaryExpression.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/BinaryExpression.java @@ -40,7 +40,7 @@ public BinaryExpression(Token t, Expression lhs, Operator op, Expression rhs) { public Expression getRhs() { return rhs; } public Operator getOperator() { return op; } - public void accept(Visitor v) { - v.visit(this); + public Object accept(Visitor v) { + return v.visit(this); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Call.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Call.java index 429b6290c..b6a22ca29 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Call.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Call.java @@ -53,7 +53,7 @@ public boolean isExpression() { return isExpression; } - public void accept(Visitor v) { - v.visit(this); + public Object accept(Visitor v) { + return v.visit(this); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Constant.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Constant.java index d319a6189..9348debef 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Constant.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Constant.java @@ -34,8 +34,8 @@ public Constant(Token t, Value value) { } @Override - public void accept(Visitor v) { - v.visit(this); + public Object accept(Visitor v) { + return v.visit(this); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Empty.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Empty.java index 38471db50..7c453c6b5 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Empty.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Empty.java @@ -23,7 +23,8 @@ public Empty() { super(0,0); } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java index b19e51de7..88b50c5c1 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Expect.java @@ -33,8 +33,9 @@ public Expect(Token t, String name) { } } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } public Class getExpected() { diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/IfStatement.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/IfStatement.java index 007f2d1d8..1b6e1a297 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/IfStatement.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/IfStatement.java @@ -46,7 +46,8 @@ public List getStmts() { return stmts; } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java index 176ce1488..978b8265d 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/IntrinsicMethod.java @@ -24,6 +24,7 @@ import org.mmtk.harness.lang.runtime.ObjectValue; import org.mmtk.harness.lang.runtime.StringValue; import org.mmtk.harness.lang.runtime.Value; +import org.mmtk.harness.lang.type.Type; /** * A method that is implemented directly in Java rather than in the scripting language. @@ -197,57 +198,18 @@ private IntrinsicMethod(String name, java.lang.reflect.Method method, Type retur this.signature = signature; } - /** - * Take a script-language value and return the corresponding Java value. - * This can only be done for a limited number of types ... - * - * @param v The script-language value - * @param klass The Java target type - * @return An object of type Class. - */ - private Object marshall(Value v, Class klass) { - switch (v.type()) { - case INT: - if (klass.isAssignableFrom(IntValue.class)) { - return v; - } else { - return Integer.valueOf(v.getIntValue()); - } - case BOOLEAN: - if (klass.isAssignableFrom(BoolValue.class)) { - return v; - } else { - return Boolean.valueOf(v.getBoolValue()); - } - case STRING: - if (klass.isAssignableFrom(StringValue.class)) { - return v; - } else { - return v.getStringValue(); - } - case OBJECT: - if (klass.isAssignableFrom(ObjectValue.class)) { - return v; - } else { - throw new RuntimeException("Can't marshall an object into a Java Object"); - } - default: - throw new RuntimeException("Unknown type in intrinsic call"); - } - } - /** * Marshall an array of values, adding the mandatory Env value. * @param env - * @param params + * @param values * @return */ - private Object[] marshall(Env env, Value[] params) { - assert params.length == signature.length : "Signature doesn't match params"; - Object[] marshalled = new Object[params.length+1]; + private Object[] marshall(Env env, Value[] values) { + assert values.length == signature.length : "Signature doesn't match params"; + Object[] marshalled = new Object[values.length+1]; marshalled[0] = env; - for (int i=0; i < params.length; i++) { - marshalled[i+1] = marshall(params[i], signature[i]); + for (int i=0; i < values.length; i++) { + marshalled[i+1] = values[i].marshall(signature[i]); } return marshalled; } @@ -318,8 +280,8 @@ public String toString() { * Accept visitors */ @Override - public void accept(Visitor v) { - v.visit(this); + public Object accept(Visitor v) { + return v.visit(this); } /** diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/LoadField.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/LoadField.java index 405731b4c..e20602e13 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/LoadField.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/LoadField.java @@ -15,6 +15,7 @@ import org.mmtk.harness.lang.Visitor; import org.mmtk.harness.lang.parser.Symbol; import org.mmtk.harness.lang.parser.Token; +import org.mmtk.harness.lang.type.Type; /** * An expression returning the value of a field in an object. @@ -39,10 +40,13 @@ public LoadField(Token t, Symbol symbol, Type fieldType, Expression index) { this.fieldType = fieldType; } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } - public Symbol getObjectSymbol() { return symbol; } + + /* Getters */ + public Symbol getObjectSymbol() { return symbol; } public Expression getIndex() { return index; } public Type getFieldType() { return fieldType; } public int getSlot() { return slot; } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Method.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Method.java index ab58d2f87..571aaf309 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Method.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Method.java @@ -16,6 +16,7 @@ import org.mmtk.harness.lang.Visitor; import org.mmtk.harness.lang.parser.Token; +import org.mmtk.harness.lang.type.Type; /** * Abstract superclass of methods implemented in a variety of ways @@ -56,8 +57,9 @@ public String getName() { return name; } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } public int getParamCount() { @@ -81,9 +83,8 @@ public int compareTo(Method m) { public boolean equals(Object o) { if (o instanceof Method) { return compareTo((Method)o) == 0; - } else { - return false; } + return false; } @Override diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/MethodProxy.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/MethodProxy.java index ce4e36619..741994931 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/MethodProxy.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/MethodProxy.java @@ -16,6 +16,7 @@ import org.mmtk.harness.lang.Visitor; import org.mmtk.harness.lang.parser.MethodTable; +import org.mmtk.harness.lang.type.Type; /** * A proxy for a method, used so that we can defer lookup of a method @@ -40,8 +41,8 @@ public MethodProxy(MethodTable methods, String name, int params) { } @Override - public void accept(Visitor v) { - getMethod().accept(v); + public Object accept(Visitor v) { + return v.visit(this); } @Override diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/NormalMethod.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/NormalMethod.java index 06acf2e6b..9ce6eebcf 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/NormalMethod.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/NormalMethod.java @@ -19,6 +19,7 @@ import org.mmtk.harness.lang.Declaration; import org.mmtk.harness.lang.Visitor; import org.mmtk.harness.lang.parser.Token; +import org.mmtk.harness.lang.type.Type; /** * A method is a set of variable declarations followed by a statement. @@ -27,7 +28,7 @@ public class NormalMethod extends Method { /** The variable declarations */ private final List decls; /** The statement this block will execute */ - private final Statement body; + private Statement body; /** * Create a new method. @@ -39,8 +40,9 @@ public NormalMethod(Token t, String name, int params, Type returnType, List getParamTypes() { List result = new ArrayList(); diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Operator.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Operator.java index b8d179a4d..ec4e6fefc 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Operator.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Operator.java @@ -19,6 +19,7 @@ import org.mmtk.harness.lang.runtime.BoolValue; import org.mmtk.harness.lang.runtime.IntValue; import org.mmtk.harness.lang.runtime.Value; +import org.mmtk.harness.lang.type.Type; /** * Arithmetic and logical operators @@ -133,10 +134,9 @@ private Operator(String image) { public final Type resultType(Type lhs, Type rhs) { if (booleanOperators.contains(this)) { return Type.BOOLEAN; - } else { - assert lhs == rhs; - return lhs; } + assert lhs == rhs; + return lhs; } /** diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/PrintStatement.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/PrintStatement.java index cda3cd9db..45bb53e78 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/PrintStatement.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/PrintStatement.java @@ -34,8 +34,9 @@ public PrintStatement(Token t, List exprs) { this.exprs = exprs; } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } public List getArgs() { return Collections.unmodifiableList(exprs); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Return.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Return.java index b2ea45720..db3017bba 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Return.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Return.java @@ -29,8 +29,9 @@ public Return(Token t) { this.expr = null; } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } public Expression getRhs() { return expr; } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Sequence.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Sequence.java index c7072e31f..565d861ce 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Sequence.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Sequence.java @@ -46,7 +46,8 @@ public Iterator iterator() { return stmts.iterator(); } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Spawn.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Spawn.java index 558c62728..ce752ea5d 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Spawn.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Spawn.java @@ -39,8 +39,9 @@ public Spawn(Token t, MethodTable methods, String methodName, List p this.params = params; } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } public List getArgs() { return params; } public Method getMethod() { return methods.get(methodName); } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/StoreField.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/StoreField.java index d65f88397..adb525c02 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/StoreField.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/StoreField.java @@ -15,6 +15,7 @@ import org.mmtk.harness.lang.Visitor; import org.mmtk.harness.lang.parser.Symbol; import org.mmtk.harness.lang.parser.Token; +import org.mmtk.harness.lang.type.Type; /** * Assign a field of an object. @@ -40,8 +41,9 @@ public StoreField(Token t, Symbol symbol, Type type, Expression index, Expressio this.value = value; } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } public Symbol getObjectSymbol() { return symbol; } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/UnaryExpression.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/UnaryExpression.java index f1996c74e..2fb907358 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/UnaryExpression.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/UnaryExpression.java @@ -38,8 +38,8 @@ public UnaryExpression(Token t, Operator op, Expression expr) { public Operator getOperator() { return op; } public Expression getOperand() { return expr; } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } - } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/Variable.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/Variable.java index d460ae40f..83e05e21f 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/Variable.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/Variable.java @@ -37,8 +37,9 @@ public Variable(Token t, Symbol symbol) { public int getSlot() { return symbol.getLocation(); } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } public Symbol getSymbol() { return symbol; } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/ast/WhileStatement.java b/MMTk/harness/src/org/mmtk/harness/lang/ast/WhileStatement.java index 7135e0c62..550f238ca 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/ast/WhileStatement.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/ast/WhileStatement.java @@ -36,7 +36,8 @@ public WhileStatement(Token t, Expression cond, Statement body) { public Expression getCond() { return cond; } public Statement getBody() { return body; } - public void accept(Visitor v) { - v.visit(this); + @Override + public Object accept(Visitor v) { + return v.visit(this); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/compiler/Register.java b/MMTk/harness/src/org/mmtk/harness/lang/compiler/Register.java index 3f3017299..bb6a6414c 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/compiler/Register.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/compiler/Register.java @@ -66,9 +66,8 @@ public int getIndex() { public static String nameOf(int index) { if (index >= 0) { return "t"+index; - } else { - return "c"+(-index-1); } + return "c"+(-index-1); } public String toString() { diff --git a/MMTk/harness/src/org/mmtk/harness/lang/compiler/Temporary.java b/MMTk/harness/src/org/mmtk/harness/lang/compiler/Temporary.java index e6eddcc35..764c148a4 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/compiler/Temporary.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/compiler/Temporary.java @@ -15,6 +15,9 @@ import java.util.ArrayList; import java.util.List; +import org.mmtk.harness.lang.Trace; +import org.mmtk.harness.lang.Trace.Item; + public class Temporary { private List freePool = new ArrayList(); @@ -28,14 +31,13 @@ public class Temporary { public Register acquire() { if (freePool.isEmpty()) { Register tmp = Register.createTemporary(nextIndex++); - //System.err.printf("Acquire *new* temporary, %s%n", tmp); + Trace.trace(Item.COMPILER,"Acquire new temporary, %s", tmp); return tmp; - } else { - Register result = freePool.remove(freePool.size()-1); - //System.err.printf("Acquire temporary, %s%n", result); - result.setUsed(); - return result; } + Register result = freePool.remove(freePool.size()-1); + Trace.trace(Item.COMPILER,"Acquire temporary, %s", result); + result.setUsed(); + return result; } public void release(Register...temp) { diff --git a/MMTk/harness/src/org/mmtk/harness/lang/parser/MethodTable.java b/MMTk/harness/src/org/mmtk/harness/lang/parser/MethodTable.java index a976cbca3..cf0410db1 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/parser/MethodTable.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/parser/MethodTable.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Map; +import org.mmtk.harness.lang.Trace; import org.mmtk.harness.lang.ast.Method; import org.mmtk.harness.lang.ast.NormalMethod; @@ -28,6 +29,7 @@ public class MethodTable { private Map table = new HashMap(); public void add(Method m) { + Trace.trace(Trace.Item.PARSER,"defining method %s", m.getName()); if (SymbolTable.reservedWords.contains(m.getName())) throw new RuntimeException(m.getName() + " is a reserved word"); if (table.containsKey(m.getName())) diff --git a/MMTk/harness/src/org/mmtk/harness/lang/parser/Source.java b/MMTk/harness/src/org/mmtk/harness/lang/parser/Source.java index b8954fc55..bcc24caf5 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/parser/Source.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/parser/Source.java @@ -35,7 +35,7 @@ public Source(String filename) { this.filename = filename; } - private void readSource(String filename) { + private void readSource() { try { BufferedReader source = new BufferedReader(new FileReader(filename)); for (String line = source.readLine(); line != null; line = source.readLine()) { @@ -50,7 +50,7 @@ private void readSource(String filename) { private void initialize() { if (!isInitialized) { isInitialized = true; - readSource(filename); + readSource(); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/parser/Symbol.java b/MMTk/harness/src/org/mmtk/harness/lang/parser/Symbol.java index 63c9b35f9..b9f0a3fdd 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/parser/Symbol.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/parser/Symbol.java @@ -12,7 +12,7 @@ */ package org.mmtk.harness.lang.parser; -import org.mmtk.harness.lang.ast.Type; +import org.mmtk.harness.lang.type.Type; /** * A symbol in the symbol table diff --git a/MMTk/harness/src/org/mmtk/harness/lang/parser/SymbolTable.java b/MMTk/harness/src/org/mmtk/harness/lang/parser/SymbolTable.java index 67afe626a..06147b2b6 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/parser/SymbolTable.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/parser/SymbolTable.java @@ -22,13 +22,7 @@ import java.util.Map.Entry; import org.mmtk.harness.lang.Declaration; -import org.mmtk.harness.lang.ast.Type; -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.StringValue; -import org.mmtk.harness.lang.runtime.Value; -import org.vmmagic.unboxed.ObjectReference; +import org.mmtk.harness.lang.type.Type; /** * Parser symbol table. @@ -86,7 +80,7 @@ void declare(String name, Type type) { throw new RuntimeException("Symbol "+name+" already defined"); Symbol symbol = new Symbol(this,name,type); table.put(name, symbol); - stackMap.add(new Declaration(symbol,initialValue(type))); + stackMap.add(new Declaration(symbol,type.initialValue())); } /** @@ -157,21 +151,4 @@ void popScope() { } currentScope--; } - - /** - * Initial value for a variable of a given type. Actually allocates - * the Value object that will hold the variables value. - * - * @param type - * @return - */ - private static Value initialValue(Type type) { - switch(type) { - case INT: return IntValue.ZERO; - case OBJECT: return new ObjectValue(ObjectReference.nullReference()); - case STRING: return new StringValue(""); - case BOOLEAN: return BoolValue.FALSE; - } - throw new RuntimeException("Invalid type"); - } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/pcode/BinaryOperation.java b/MMTk/harness/src/org/mmtk/harness/lang/pcode/BinaryOperation.java index 7deb0376e..84b73d132 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/pcode/BinaryOperation.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/pcode/BinaryOperation.java @@ -40,6 +40,7 @@ public void exec(Env env) { @Override public String toString() { - return String.format("t%d <- t%d %s t%d", getResult(), op1, name, op2); + return String.format("%s <- %s %s %s", Register.nameOf(getResult()), + Register.nameOf(op1), name, Register.nameOf(op2)); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/pcode/LoadFieldOp.java b/MMTk/harness/src/org/mmtk/harness/lang/pcode/LoadFieldOp.java index c94b40ecf..629464d5e 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/pcode/LoadFieldOp.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/pcode/LoadFieldOp.java @@ -14,11 +14,11 @@ import org.mmtk.harness.lang.Env; import org.mmtk.harness.lang.ast.AST; -import org.mmtk.harness.lang.ast.Type; import org.mmtk.harness.lang.compiler.Register; import org.mmtk.harness.lang.runtime.IntValue; import org.mmtk.harness.lang.runtime.ObjectValue; import org.mmtk.harness.lang.runtime.StackFrame; +import org.mmtk.harness.lang.type.Type; import org.vmmagic.unboxed.ObjectReference; public final class LoadFieldOp extends BinaryOp { @@ -65,20 +65,17 @@ public int getIndex(StackFrame frame) { } public String toString() { - return String.format("t%d <- t%d.%s[t%d]", getResult(), op1, - fieldType == Type.OBJECT ? "object" : "int", op2); + return String.format("%s <- %s.%s[%s]", Register.nameOf(getResult()), + Register.nameOf(op1), fieldType == Type.OBJECT ? "object" : "int", op2); } @Override public void exec(Env env) { StackFrame frame = env.top(); - switch (fieldType) { - case INT: - setResult(frame, new IntValue(env.loadDataField(getObject(frame), getIndex(frame)))); - break; - case OBJECT: - setResult(frame, new ObjectValue(env.loadReferenceField(getObject(frame), getIndex(frame)))); - break; + if (fieldType == Type.INT) { + setResult(frame, new IntValue(env.loadDataField(getObject(frame), getIndex(frame)))); + } else if (fieldType == Type.OBJECT) { + setResult(frame, new ObjectValue(env.loadReferenceField(getObject(frame), getIndex(frame)))); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/pcode/PseudoOp.java b/MMTk/harness/src/org/mmtk/harness/lang/pcode/PseudoOp.java index d955fb05f..c20dc1d19 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/pcode/PseudoOp.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/pcode/PseudoOp.java @@ -31,6 +31,7 @@ private PseudoOp(AST source, int arity, String name, boolean hasResult, int resu this.resultTemp = resultTemp; this.name = name; this.source = source; + assert (!hasResult) || resultTemp >= 0 : resultTemp; } public PseudoOp(AST source, int arity, String name, Register resultTemp) { @@ -65,9 +66,8 @@ public Value getResultValue(StackFrame frame) { public String toString() { if (hasResult) { return String.format("%s <- %s", Register.nameOf(resultTemp), name); - } else { - return name; } + return name; } /* diff --git a/MMTk/harness/src/org/mmtk/harness/lang/pcode/StoreFieldOp.java b/MMTk/harness/src/org/mmtk/harness/lang/pcode/StoreFieldOp.java index b30bebd96..19c58458c 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/pcode/StoreFieldOp.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/pcode/StoreFieldOp.java @@ -14,9 +14,9 @@ import org.mmtk.harness.lang.Env; import org.mmtk.harness.lang.ast.AST; -import org.mmtk.harness.lang.ast.Type; import org.mmtk.harness.lang.compiler.Register; import org.mmtk.harness.lang.runtime.StackFrame; +import org.mmtk.harness.lang.type.Type; import org.vmmagic.unboxed.ObjectReference; public final class StoreFieldOp extends TernaryOp { @@ -41,15 +41,10 @@ public void exec(Env env) { int fieldIndex = getIndex(frame); ObjectReference object = getObjectObj(frame); - switch (fieldType) { - case INT: { - env.storeDataField(object, fieldIndex, getValInt(frame)); - break; - } - case OBJECT: { - env.storeReferenceField(object, fieldIndex, getValObject(frame)); - break; - } + if (fieldType == Type.INT) { + env.storeDataField(object, fieldIndex, getValInt(frame)); + } else if (fieldType == Type.OBJECT) { + env.storeReferenceField(object, fieldIndex, getValObject(frame)); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/runtime/BoolValue.java b/MMTk/harness/src/org/mmtk/harness/lang/runtime/BoolValue.java index b3509b9c3..bcad5b3e4 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/runtime/BoolValue.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/runtime/BoolValue.java @@ -12,7 +12,7 @@ */ package org.mmtk.harness.lang.runtime; -import org.mmtk.harness.lang.ast.Type; +import org.mmtk.harness.lang.type.Type; /** * Expression consisting of a simple boolean value @@ -61,6 +61,14 @@ public Type type() { return Type.BOOLEAN; } + @Override + public Object marshall(Class klass) { + if (klass.isAssignableFrom(BoolValue.class)) { + return this; + } + return Boolean.valueOf(value); + } + /** * Object equality. */ diff --git a/MMTk/harness/src/org/mmtk/harness/lang/runtime/ConstantPool.java b/MMTk/harness/src/org/mmtk/harness/lang/runtime/ConstantPool.java index 20f3e7600..7d1beceb2 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/runtime/ConstantPool.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/runtime/ConstantPool.java @@ -16,22 +16,32 @@ import java.util.HashMap; import java.util.Map; +import org.mmtk.harness.lang.Trace; +import org.mmtk.harness.lang.Trace.Item; import org.mmtk.harness.lang.compiler.Register; -import org.vmmagic.unboxed.ObjectReference; +/** + * Execution-time constants + */ public class ConstantPool { private static int next = -1; private static final Map constants = new HashMap(); private static final ArrayList values = new ArrayList(); - public static final Register NULL = create(new ObjectValue(ObjectReference.nullReference())); + /** The null reference constant */ + public static final Register NULL = create(ObjectValue.NULL); + /** The int zero constant */ public static final Register ZERO = create(IntValue.ZERO); + /** The int one constant */ public static final Register ONE = create(IntValue.ONE); + /** The boolean TRUE constant */ public static final Register TRUE = create(BoolValue.TRUE); + /** The boolean false constant */ public static final Register FALSE = create(BoolValue.FALSE); public static Register acquire(Value constant) { + assert constant != null; Register result = constants.get(constant); if (result != null) { return result; @@ -43,6 +53,7 @@ private static Register create(Value constant) { Register result = Register.createConstant(next--); constants.put(constant, result); values.add(constant); + Trace.trace(Item.COMPILER,"Acquire new constant, %s = %s", result, constant); return result; } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/runtime/IntValue.java b/MMTk/harness/src/org/mmtk/harness/lang/runtime/IntValue.java index add1f7cd0..b1704734f 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/runtime/IntValue.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/runtime/IntValue.java @@ -12,7 +12,7 @@ */ package org.mmtk.harness.lang.runtime; -import org.mmtk.harness.lang.ast.Type; +import org.mmtk.harness.lang.type.Type; /** * Expression consisting of a simple integer value @@ -60,6 +60,14 @@ public int getIntValue() { return value; } + @Override + public Object marshall(Class klass) { + if (klass.isAssignableFrom(IntValue.class)) { + return this; + } + return Integer.valueOf(value); + } + @Override public boolean equals(Object other) { return (other instanceof IntValue && value == ((IntValue)other).value); diff --git a/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java b/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java index dd71b94f8..3457b1c65 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/runtime/ObjectValue.java @@ -12,7 +12,7 @@ */ package org.mmtk.harness.lang.runtime; -import org.mmtk.harness.lang.ast.Type; +import org.mmtk.harness.lang.type.Type; import org.mmtk.plan.TraceLocal; import org.vmmagic.unboxed.ObjectReference; @@ -21,7 +21,10 @@ */ public class ObjectValue extends Value { - public static final ObjectValue NULL = new ObjectValue(); + /** + * The null object - actually uses a subtype so that it can have type NULL + */ + public static final ObjectValue NULL = NullValue.NULL; /** * The reference to the heap object @@ -85,17 +88,25 @@ public void traceObject(TraceLocal trace) { value = trace.traceObject(value, true); } + @Override + public Object marshall(Class klass) { + if (klass.isAssignableFrom(ObjectValue.class)) { + return this; + } + throw new RuntimeException("Can't marshall an object into a Java Object"); + } + /** * Object equality. */ @Override public boolean equals(Object other) { - return (other instanceof ObjectValue && value.toAddress().EQ(((ObjectValue)other).value.toAddress())); + return (other instanceof ObjectValue && value.equals(((ObjectValue)other).value)); } @Override public int hashCode() { - return value.toAddress().hashCode(); + return value.hashCode(); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java b/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java index 4f132eb99..07a211b42 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/runtime/StackFrame.java @@ -12,15 +12,17 @@ */ package org.mmtk.harness.lang.runtime; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Stack; -import org.mmtk.harness.Mutator; import org.mmtk.harness.lang.Declaration; import org.mmtk.harness.lang.Trace; import org.mmtk.harness.lang.Trace.Item; -import org.mmtk.harness.lang.ast.Type; import org.mmtk.harness.lang.pcode.PseudoOp; +import org.mmtk.harness.lang.type.Type; +import org.mmtk.harness.vm.ObjectModel; import org.mmtk.plan.TraceLocal; import org.vmmagic.unboxed.ObjectReference; @@ -30,6 +32,13 @@ */ public class StackFrame { + /** + * Enable the assertion that objects won't move after being traced. + * This is notably not true for MC, but can be useful for debugging other + * collectors. + */ + private static final boolean ASSERT_WILL_NOT_MOVE = false; + /** A sentinel for slots that have no value */ public static final int NO_SUCH_SLOT = Integer.MAX_VALUE; @@ -73,9 +82,8 @@ public void declare(Declaration d) { public Value get(int slot) { if (slot >= 0) { return values[slot]; - } else { - return ConstantPool.get(slot); } + return ConstantPool.get(slot); } /** @@ -90,27 +98,38 @@ public Type getType(int slot) { */ public void set(int slot, Value value) { assert value != null : "Unexpected null value"; - if (Trace.isEnabled(Item.ENV)) { - Trace.trace(Item.ENV, "%s %s = %s",value.type().toString(),names[slot],value.toString()); + if (Trace.isEnabled(Item.EVAL)) { + Trace.printf(Item.EVAL, "%s %s = %s",value.type().toString(),getSlotName(slot),value.toString()); } values[slot] = value; } + private String getSlotName(int slot) { + if (names != null && names[slot] != null) { + return names[slot]; + } + return "t" + slot; + } + /** * GC support: trace this stack frame. + * @param trace The MMTk trace object to receive the roots + * @return The number of roots found */ public int computeRoots(TraceLocal trace) { int rootCount = 0; - for (int i=0; i < values.length; i++) { - Value value = values[i]; - if (value != null && value instanceof ObjectValue) { - ObjectValue object = (ObjectValue)value; + for (ObjectValue object : getRoots()) { + if (!object.getObjectValue().isNull()) { if (Trace.isEnabled(Item.ROOTS)) { - Trace.trace(Item.ROOTS, "Tracing root %s=%s", names[i], object.toString()); + Trace.trace(Item.ROOTS, "Tracing root %s", object.toString()); } object.traceObject(trace); + if (ASSERT_WILL_NOT_MOVE) { + assert trace.willNotMoveInCurrentCollection(object.getObjectValue()) : + object.getObjectValue()+" has been traced but willNotMoveInCurrentCollection is still false"; + } if (Trace.isEnabled(Item.ROOTS)) { - Trace.trace(Item.ROOTS, "new value of %s=%s", names[i], object.toString()); + Trace.trace(Item.ROOTS, "new value of %s", object.toString()); } rootCount++; } @@ -118,21 +137,37 @@ public int computeRoots(TraceLocal trace) { return rootCount; } + /** + * + * @return The root ObjectValues for this stack frame + */ + public Collection getRoots() { + List roots = new ArrayList(); + for (Value value : values) { + if (value != null && value instanceof ObjectValue) { + roots.add((ObjectValue)value); + } + } + return roots; + } + /** * Debug printing support: dump this stack frame and return roots. + * @param width Output field width + * @param roots Root references */ public void dumpRoots(int width, Stack roots) { for (int i=0; i < values.length; i++) { Value value = values[i]; String name; if (Trace.isEnabled(Item.ROOTS)) { - name = i < names.length ? names[i] : "t"+i; + name = names != null && i < names.length ? getSlotName(i) : "t"+i; } else { name = "slot["+i+"]"; } if (value != null && value instanceof ObjectValue) { ObjectReference ref = ((ObjectValue)value).getObjectValue(); - System.err.printf(" %s=%s", name, Mutator.formatObject(width, ref)); + System.err.printf(" %s=%s", name, ObjectModel.formatObject(width, ref)); if (!ref.isNull()) roots.push(ref); } } diff --git a/MMTk/harness/src/org/mmtk/harness/lang/runtime/StringValue.java b/MMTk/harness/src/org/mmtk/harness/lang/runtime/StringValue.java index f979de107..4956afcaa 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/runtime/StringValue.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/runtime/StringValue.java @@ -12,7 +12,7 @@ */ package org.mmtk.harness.lang.runtime; -import org.mmtk.harness.lang.ast.Type; +import org.mmtk.harness.lang.type.Type; /** * Expression consisting of a simple string value @@ -47,6 +47,14 @@ public String getStringValue() { return value; } + @Override + public Object marshall(Class klass) { + if (klass.isAssignableFrom(StringValue.class)) { + return this; + } + return value; + } + @Override public boolean equals(Object other) { return (other instanceof StringValue && value.equals(((StringValue)other).value)); diff --git a/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java b/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java index bafdb9f5e..d79329f6d 100644 --- a/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java +++ b/MMTk/harness/src/org/mmtk/harness/lang/runtime/Value.java @@ -12,7 +12,7 @@ */ package org.mmtk.harness.lang.runtime; -import org.mmtk.harness.lang.ast.Type; +import org.mmtk.harness.lang.type.Type; import org.vmmagic.unboxed.ObjectReference; /** @@ -54,9 +54,15 @@ public String getStringValue() { throw new RuntimeException("Invalid use of " + type() + " as a string"); } + public Object marshall(Class klass) { + throw new RuntimeException(getClass()+" cannot be marshalled into a Java Object"); + } + @Override public abstract int hashCode(); @Override public abstract boolean equals(Object o); + + } diff --git a/MMTk/harness/src/org/mmtk/harness/scheduler/AbstractPolicy.java b/MMTk/harness/src/org/mmtk/harness/scheduler/AbstractPolicy.java index 718074603..c8b3c3874 100644 --- a/MMTk/harness/src/org/mmtk/harness/scheduler/AbstractPolicy.java +++ b/MMTk/harness/src/org/mmtk/harness/scheduler/AbstractPolicy.java @@ -56,9 +56,8 @@ public final boolean yieldNow() { if (taken()) { yieldTaken(); return true; - } else { - return false; } + return false; } /** diff --git a/MMTk/harness/src/org/mmtk/harness/scheduler/Scheduler.java b/MMTk/harness/src/org/mmtk/harness/scheduler/Scheduler.java index abf02bbfd..e0a25b1fc 100644 --- a/MMTk/harness/src/org/mmtk/harness/scheduler/Scheduler.java +++ b/MMTk/harness/src/org/mmtk/harness/scheduler/Scheduler.java @@ -30,10 +30,12 @@ public class Scheduler { * Possible threading models */ public enum Model { + /** Schedule using the Java thread scheduler */ JAVA, + /** Schedule in the harness using deterministic algorithms */ DETERMINISTIC; - /** The values of this enum, converted to strings */ + /** @return The values of this enum, converted to strings */ public static String[] valueNames() { String[] result = new String[Scheduler.Model.values().length]; for (int i=0; i < Scheduler.Model.values().length; i++) { @@ -47,11 +49,14 @@ public static String[] valueNames() { * Possible thread-scheduling policies */ public enum SchedPolicy { + /** Reschedule every nth yield point */ FIXED, + /** Reschedule on a pseudo-random sequence of intervals */ RANDOM, + /** Only reschedule when the thread is blocked */ NEVER; - /** The values of this enum, converted to strings */ + /** @return The values of this enum, converted to strings */ public static String[] valueNames() { String[] result = new String[Scheduler.SchedPolicy.values().length]; for (int i=0; i < Scheduler.SchedPolicy.values().length; i++) { @@ -80,6 +85,8 @@ private static ThreadModel selectedThreadModel() { /** * Yield policy factory - return an instance of the the command-line * selected yield policy + * @param thread The Java thread + * @return A new policy for the given thread */ public static Policy yieldPolicy(Thread thread) { switch (Harness.policy.policy()) { @@ -87,9 +94,8 @@ public static Policy yieldPolicy(Thread thread) { int yieldInterval = Harness.yieldInterval.getValue(); if (yieldInterval == 1) { return new YieldAlways(thread); - } else { - return new YieldEvery(thread,yieldInterval); } + return new YieldEvery(thread,yieldInterval); case RANDOM: return new YieldRandomly(thread, Harness.randomPolicySeed.getValue(), @@ -142,30 +148,29 @@ public static void scheduleCollector() { /** * Create and start a new collector thread running a particular code * sequence. Used to schedule unit tests in collector context. + * @param item The schedulable object + * @return A java thread for the item */ public static Thread scheduleCollector(Schedulable item) { return model.scheduleCollector(item); } /** - * The current Log object. - * @return + * @return The current Log object. */ public static Log currentLog() { return ((MMTkThread)Thread.currentThread()).getLog(); } /** - * The current mutator object (if the current thread is a Mutator) - * @return + * @return The current mutator object (if the current thread is a Mutator) */ public static Mutator currentMutator() { return model.currentMutator(); } /** - * The current collector object (if the current thread is a Collector) - * @return + * @return The current collector object (if the current thread is a Collector) */ public static Collector currentCollector() { return model.currentCollector(); @@ -176,6 +181,7 @@ public static Collector currentCollector() { /** * Request a GC. Once requested, mutator threads block at * 'waitForGC' until a collection is performed. + * @param why Reason code */ public static void triggerGC(int why) { model.triggerGC(why); @@ -197,22 +203,22 @@ public static void waitForGCStart() { } /** - * Why was the current GC triggered ? - * @return + * @see #triggerGC(int) + * @return Why was the current GC triggered ? */ public static int getTriggerReason() { return model.getTriggerReason(); } /** - * Are there no threads currently in GC? + * @return Are there no threads currently in GC? */ public static boolean noThreadsInGC() { return model.noThreadsInGC(); } /** - * Has a GC been triggered? + * @return Has a GC been triggered? */ public static boolean gcTriggered() { return model.gcTriggered(); @@ -220,8 +226,8 @@ public static boolean gcTriggered() { /** * Collector thread synchronization barrier - * @param where - * @return + * @param where Rendezvous ID + * @return The order of arrival at the barrier */ public static int rendezvous(int where) { return model.rendezvous(where); @@ -251,6 +257,8 @@ public static void scheduleGcThreads() { /** * An MMTk lock - a factory method. + * @param name The name of the lock + * @return The newly created lock */ public static Lock newLock(String name) { return model.newLock(name); diff --git a/MMTk/harness/src/org/mmtk/harness/scheduler/ThreadModel.java b/MMTk/harness/src/org/mmtk/harness/scheduler/ThreadModel.java index beb17aa23..0966fd113 100644 --- a/MMTk/harness/src/org/mmtk/harness/scheduler/ThreadModel.java +++ b/MMTk/harness/src/org/mmtk/harness/scheduler/ThreadModel.java @@ -87,8 +87,8 @@ protected State getState() { return state; } - protected boolean isState(State state) { - return ThreadModel.state == state; + protected boolean isState(State s) { + return state == s; } protected boolean isRunning() { diff --git a/MMTk/harness/test-scripts/Alignment.script b/MMTk/harness/test-scripts/Alignment.script index caf015697..3cbe75bf8 100644 --- a/MMTk/harness/test-scripts/Alignment.script +++ b/MMTk/harness/test-scripts/Alignment.script @@ -14,7 +14,7 @@ /** * This is a simple test that allocates aligned and unaligned objects. */ -main() { +void main() { int listSize = 200; int alignEvery = 3; diff --git a/MMTk/harness/test-scripts/CyclicGarbage.script b/MMTk/harness/test-scripts/CyclicGarbage.script index 330e037e1..2284084c6 100644 --- a/MMTk/harness/test-scripts/CyclicGarbage.script +++ b/MMTk/harness/test-scripts/CyclicGarbage.script @@ -14,7 +14,7 @@ /** * This is a simple test that creates lots of cyclic garbage. */ -main() { +void main() { int cycles = 300; int cycleSize = 100; diff --git a/MMTk/harness/test-scripts/HashCode.script b/MMTk/harness/test-scripts/HashCode.script index 0c2e7cc5d..2259e34f5 100644 --- a/MMTk/harness/test-scripts/HashCode.script +++ b/MMTk/harness/test-scripts/HashCode.script @@ -14,7 +14,7 @@ /** * This is a simple test that checks hashCode values persist across a collection. */ -main() { +void main() { int listSize = 200; int hashEvery = 20; @@ -36,7 +36,7 @@ main() { verify(head); } -verify(object current) { +void verify(object current) { while (current) { if (current.int[0] != 0) { assert(current.int[0] == hash(current), "Hash code does not match remembered value ", current.int[0], " ", hash(current)); diff --git a/MMTk/harness/test-scripts/LargeObject.script b/MMTk/harness/test-scripts/LargeObject.script index 1893f9195..5218a0ddd 100644 --- a/MMTk/harness/test-scripts/LargeObject.script +++ b/MMTk/harness/test-scripts/LargeObject.script @@ -14,7 +14,7 @@ /** * This is a simple test that allocates large objects. */ -main() { +void main() { int limitPages = 32; // 128 int startPages = 2; int p = startPages; diff --git a/MMTk/harness/test-scripts/OutOfMemory.script b/MMTk/harness/test-scripts/OutOfMemory.script index 992194d50..844d4d139 100644 --- a/MMTk/harness/test-scripts/OutOfMemory.script +++ b/MMTk/harness/test-scripts/OutOfMemory.script @@ -14,7 +14,7 @@ /** * This is a simple test that forces an out of memory condition by creating an infinite linked list. */ -main() { +void main() { expect(OutOfMemory); object current = alloc(1, 8); object last; diff --git a/MMTk/harness/test-scripts/Quicksort.script b/MMTk/harness/test-scripts/Quicksort.script index 076bfc3d0..19cb2ff49 100644 --- a/MMTk/harness/test-scripts/Quicksort.script +++ b/MMTk/harness/test-scripts/Quicksort.script @@ -2,7 +2,7 @@ * Create a list of random integers, then sort the list using quicksort. * It's (java) stack intensive, run with -Xss4m or more. */ -main() { +void main() { runTest(1); runTest(10); runTest(100); @@ -10,14 +10,14 @@ main() { runTest(10000); } -runTest(int size) { +void runTest(int size) { print("=== Testing list of size ",size," ==="); test(size); print("=== test ",size," complete, heap should now be empty ==="); gc(); } -test(int size) { +void test(int size) { int n = 0; object list = null; while (n < size) { @@ -88,7 +88,7 @@ object partition(int pivot,object list) { * Perform a partition, putting the low elements into parts.object[0], * and the high elements into parts.object[1] */ -part2(object parts,int pivot, object list) { +void part2(object parts,int pivot, object list) { while (list != null) { int hd = head(list); if (hd < pivot) { @@ -103,7 +103,7 @@ part2(object parts,int pivot, object list) { /* * Print a list */ -printList(object list) { +void printList(object list) { if (list == null) { return; } else { @@ -116,7 +116,7 @@ printList(object list) { * Sanity check a list - ensure that the elements are in * monotonic order, and the list is the right length. */ -checkList(object list, int len) { +void checkList(object list, int len) { int count = 0; if (list != null) { int v1 = head(list); diff --git a/MMTk/harness/test-scripts/Spawn.script b/MMTk/harness/test-scripts/Spawn.script index 24eecdcfb..df8a3cfe5 100644 --- a/MMTk/harness/test-scripts/Spawn.script +++ b/MMTk/harness/test-scripts/Spawn.script @@ -1,8 +1,8 @@ -main() { +void main() { other(1); } -other(int x) { +void other(int x) { print (tid(), " executing other(", x, ")" ); object parent = alloc(5, 0); if (x < 30) { diff --git a/MMTk/harness/test-scripts/SpreadAlloc.script b/MMTk/harness/test-scripts/SpreadAlloc.script index 6cc0b894c..6131216f2 100644 --- a/MMTk/harness/test-scripts/SpreadAlloc.script +++ b/MMTk/harness/test-scripts/SpreadAlloc.script @@ -18,7 +18,7 @@ * * Highly non-generational :) Basic exercise of multi-class allocation. */ -main() { +void main() { int n = 10000; // Number of iterations int live = 200; // Number of live children int small = 5; // # scalars in the smallest object diff --git a/MMTk/harness/vmmagic/org/vmmagic/unboxed/Address.java b/MMTk/harness/vmmagic/org/vmmagic/unboxed/Address.java index e6fce673a..ecd3fddf8 100644 --- a/MMTk/harness/vmmagic/org/vmmagic/unboxed/Address.java +++ b/MMTk/harness/vmmagic/org/vmmagic/unboxed/Address.java @@ -597,105 +597,105 @@ public Word loadWord(Offset offset) { * Stores the address value in the memory location pointed to by the * current instance. * - * @param value The address value to store. + * @param val The address value to store. */ - public void store(ObjectReference value) { - SimulatedMemory.setWord(this, value.value); + public void store(ObjectReference val) { + SimulatedMemory.setWord(this, val.value); } /** * Stores the object reference value in the memory location pointed * to by the current instance. * - * @param value The object reference value to store. + * @param val The object reference value to store. * @param offset the offset to the value. */ - public void store(ObjectReference value, Offset offset) { - this.plus(offset).store(value); + public void store(ObjectReference val, Offset offset) { + this.plus(offset).store(val); } /** * Stores the address value in the memory location pointed to by the * current instance. * - * @param value The address value to store. + * @param val The address value to store. */ - public void store(Address value) { - SimulatedMemory.setWord(this, value.value); + public void store(Address val) { + SimulatedMemory.setWord(this, val.value); } /** * Stores the address value in the memory location pointed to by the * current instance. * - * @param value The address value to store. + * @param val The address value to store. * @param offset the offset to the value. */ - public void store(Address value, Offset offset) { - this.plus(offset).store(value); + public void store(Address val, Offset offset) { + this.plus(offset).store(val); } /** * Stores the float value in the memory location pointed to by the * current instance. * - * @param value The float value to store. + * @param val The float value to store. */ - public void store(float value) { - SimulatedMemory.setFloat(this, value); + public void store(float val) { + SimulatedMemory.setFloat(this, val); } /** * Stores the float value in the memory location pointed to by the * current instance. * - * @param value The float value to store. + * @param val The float value to store. * @param offset the offset to the value. */ - public void store(float value, Offset offset) { - this.plus(offset).store(value); + public void store(float val, Offset offset) { + this.plus(offset).store(val); } /** * Stores the word value in the memory location pointed to by the * current instance. * - * @param value The word value to store. + * @param val The word value to store. */ - public void store(Word value) { - SimulatedMemory.setWord(this, value.value); + public void store(Word val) { + SimulatedMemory.setWord(this, val.value); } /** * Stores the word value in the memory location pointed to by the * current instance. * - * @param value The word value to store. + * @param val The word value to store. * @param offset the offset to the value. */ - public void store(Word value, Offset offset) { - this.plus(offset).store(value); + public void store(Word val, Offset offset) { + this.plus(offset).store(val); } /** * Stores the byte value in the memory location pointed to by the * current instance. * - * @param value The byte value to store. + * @param val The byte value to store. */ - public void store(byte value) { - SimulatedMemory.setByte(this, value); + public void store(byte val) { + SimulatedMemory.setByte(this, val); } /** * Stores the byte value in the memory location pointed to by the * current instance. * - * @param value The byte value to store. + * @param val The byte value to store. * @param offset the offset to the value. */ - public void store(byte value, Offset offset) { - this.plus(offset).store(value); + public void store(byte val, Offset offset) { + this.plus(offset).store(val); } @@ -703,42 +703,42 @@ public void store(byte value, Offset offset) { * Stores an int value in memory location pointed to by the * current instance. * - * @param value The int value to store. + * @param val The int value to store. */ - public void store(int value) { - SimulatedMemory.setInt(this, value); + public void store(int val) { + SimulatedMemory.setInt(this, val); } /** * Stores an int value in memory location pointed to by the * current instance. * - * @param value The int value to store. + * @param val The int value to store. * @param offset the offset to the value. */ - public void store(int value, Offset offset) { - this.plus(offset).store(value); + public void store(int val, Offset offset) { + this.plus(offset).store(val); } /** * Stores a double value in memory location pointed to by the * current instance. * - * @param value The double value to store. + * @param val The double value to store. */ - public void store(double value) { - SimulatedMemory.setDouble(this, value); + public void store(double val) { + SimulatedMemory.setDouble(this, val); } /** * Stores a double value in memory location pointed to by the * current instance. * - * @param value The double value to store. + * @param val The double value to store. * @param offset the offset to the value. */ - public void store(double value, Offset offset) { - this.plus(offset).store(value); + public void store(double val, Offset offset) { + this.plus(offset).store(val); } @@ -746,63 +746,63 @@ public void store(double value, Offset offset) { * Stores a double value in memory location pointed to by the * current instance. * - * @param value The double value to store. + * @param val The double value to store. */ - public void store(long value) { - SimulatedMemory.setLong(this, value); + public void store(long val) { + SimulatedMemory.setLong(this, val); } /** * Stores a double value in memory location pointed to by the * current instance. * - * @param value The double value to store. + * @param val The double value to store. * @param offset the offset to the value. */ - public void store(long value, Offset offset) { - this.plus(offset).store(value); + public void store(long val, Offset offset) { + this.plus(offset).store(val); } /** * Stores a char value in the memory location pointed to by the * current instance. * - * @param value the char value to store. + * @param val the char value to store. */ - public void store(char value) { - SimulatedMemory.setChar(this, value); + public void store(char val) { + SimulatedMemory.setChar(this, val); } /** * Stores a char value in the memory location pointed to by the * current instance. * - * @param value the char value to store. + * @param val the char value to store. * @param offset the offset to the value. */ - public void store(char value, Offset offset) { - this.plus(offset).store(value); + public void store(char val, Offset offset) { + this.plus(offset).store(val); } /** * Stores a short value in the memory location pointed to by the * current instance. * - * @param value the short value to store. + * @param val the short value to store. */ - public void store(short value) { - SimulatedMemory.setShort(this, value); + public void store(short val) { + SimulatedMemory.setShort(this, val); } /** * Stores a short value in the memory location pointed to by the * current instance. * - * @param value the short value to store. + * @param val the short value to store. * @param offset the offset to the value. */ - public void store(short value, Offset offset) { - this.plus(offset).store(value); + public void store(short val, Offset offset) { + this.plus(offset).store(val); } /**************************************************************************** @@ -899,11 +899,11 @@ public int prepareInt(Offset offset) { * related call to prepare. * * @param old the old value. - * @param value the new value. + * @param val the new value. * @return true if the attempt was successful. */ - public boolean attempt(int old, int value) { - return SimulatedMemory.exchangeInt(this, old, value); + public boolean attempt(int old, int val) { + return SimulatedMemory.exchangeInt(this, old, val); } /** @@ -911,12 +911,12 @@ public boolean attempt(int old, int value) { * related call to prepare. * * @param old the old value. - * @param value the new value. + * @param val the new value. * @param offset the offset to the value. * @return true if the attempt was successful. */ - public boolean attempt(int old, int value, Offset offset) { - return this.plus(offset).attempt(old,value); + public boolean attempt(int old, int val, Offset offset) { + return this.plus(offset).attempt(old,val); } /** @@ -924,11 +924,11 @@ public boolean attempt(int old, int value, Offset offset) { * related call to prepare. * * @param old the old value. - * @param value the new value. + * @param val the new value. * @return true if the attempt was successful. */ - public boolean attempt(Word old, Word value) { - return SimulatedMemory.exchangeWord(this, old.value, value.value); + public boolean attempt(Word old, Word val) { + return SimulatedMemory.exchangeWord(this, old.value, val.value); } /** @@ -936,12 +936,12 @@ public boolean attempt(Word old, Word value) { * related call to prepare. * * @param old the old value. - * @param value the new value. + * @param val the new value. * @param offset the offset to the value. * @return true if the attempt was successful. */ - public boolean attempt(Word old, Word value, Offset offset) { - return this.plus(offset).attempt(old,value); + public boolean attempt(Word old, Word val, Offset offset) { + return this.plus(offset).attempt(old,val); } /** @@ -949,11 +949,11 @@ public boolean attempt(Word old, Word value, Offset offset) { * related call to prepare. * * @param old the old value. - * @param value the new value. + * @param val the new value. * @return true if the attempt was successful. */ - public boolean attempt(ObjectReference old, ObjectReference value) { - return SimulatedMemory.exchangeWord(this, old.value, value.value); + public boolean attempt(ObjectReference old, ObjectReference val) { + return SimulatedMemory.exchangeWord(this, old.value, val.value); } /** @@ -961,12 +961,12 @@ public boolean attempt(ObjectReference old, ObjectReference value) { * related call to prepare. * * @param old the old value. - * @param value the new value. + * @param val the new value. * @param offset the offset to the value. * @return true if the attempt was successful. */ - public boolean attempt(ObjectReference old, ObjectReference value, Offset offset) { - return this.plus(offset).attempt(old,value); + public boolean attempt(ObjectReference old, ObjectReference val, Offset offset) { + return this.plus(offset).attempt(old,val); } /** @@ -974,11 +974,11 @@ public boolean attempt(ObjectReference old, ObjectReference value, Offset offset * related call to prepare. * * @param old the old value. - * @param value the new value. + * @param val the new value. * @return true if the attempt was successful. */ - public boolean attempt(Address old, Address value) { - return SimulatedMemory.exchangeWord(this, old.value, value.value); + public boolean attempt(Address old, Address val) { + return SimulatedMemory.exchangeWord(this, old.value, val.value); } /** @@ -986,12 +986,12 @@ public boolean attempt(Address old, Address value) { * related call to prepare. * * @param old the old value. - * @param value the new value. + * @param val the new value. * @param offset the offset to the value. * @return true if the attempt was successful. */ - public boolean attempt(Address old, Address value, Offset offset) { - return this.plus(offset).attempt(old,value); + public boolean attempt(Address old, Address val, Offset offset) { + return this.plus(offset).attempt(old,val); } /** diff --git a/MMTk/harness/vmmagic/org/vmmagic/unboxed/Extent.java b/MMTk/harness/vmmagic/org/vmmagic/unboxed/Extent.java index 6da349c69..08f7c4917 100644 --- a/MMTk/harness/vmmagic/org/vmmagic/unboxed/Extent.java +++ b/MMTk/harness/vmmagic/org/vmmagic/unboxed/Extent.java @@ -25,11 +25,6 @@ public final class Extent { this.value = value; } - @Deprecated - private Extent(int value) { - this(ArchitecturalWord.fromIntSignExtend(value)); - } - public static Extent fromIntSignExtend(int value) { return new Extent(ArchitecturalWord.fromIntSignExtend(value)); } diff --git a/MMTk/harness/vmmagic/org/vmmagic/unboxed/SimulatedMemory.java b/MMTk/harness/vmmagic/org/vmmagic/unboxed/SimulatedMemory.java index bc6762f7d..f6f621813 100644 --- a/MMTk/harness/vmmagic/org/vmmagic/unboxed/SimulatedMemory.java +++ b/MMTk/harness/vmmagic/org/vmmagic/unboxed/SimulatedMemory.java @@ -125,7 +125,7 @@ private static void zeroPage(Address p) { /** * Watch mutations to an address (watches 4 byte values) - * @param watchAddress + * @param watchAddress Address to watch */ public static void addWatch(Address watchAddress) { watches.add(watchAddress); @@ -416,6 +416,7 @@ public void zero() { * @param low TODO * @return */ + @SuppressWarnings("cast") // Make cast explicit, because oddness can happen private long longFrom2Ints(int high, int low) { return (((long)high) << 32) |(((long)low & 0xFFFFFFFFL)); } @@ -468,6 +469,7 @@ public long getLong(Address address) { return longFrom2Ints(getInt(address), getInt(address.plus(BYTES_IN_CELL))); } + @SuppressWarnings("cast") public byte setByte(Address address, byte value) { int shift = ((address.toInt()) & ~WORD_MASK) << LOG_BITS_IN_BYTE; int mask = 0x000000FF << shift; @@ -479,6 +481,7 @@ public byte setByte(Address address, byte value) { return (byte)(oldValue >>> shift); } + @SuppressWarnings("cast") public char setChar(Address address, char value) { int shift = ((address.toInt()) & ~WORD_MASK) << LOG_BITS_IN_BYTE; assert shift == 0 || shift == 16: "misaligned 2b access"; @@ -536,6 +539,7 @@ private int read(int index) { int value = data[index]; if (isWatched(index)) { System.err.printf("%s = %08x%n", cellAddress(index), data[index]); + //new Throwable().printStackTrace(); } return value; } @@ -546,6 +550,7 @@ private int read(int index) { private void write(int index, int value) { if (isWatched(index)) { System.err.printf("%s: %08x -> %08x%n", cellAddress(index), data[index], value); + //new Throwable().printStackTrace(); } data[index] = value; } diff --git a/MMTk/harness/vmmagic/org/vmmagic/unboxed/Word.java b/MMTk/harness/vmmagic/org/vmmagic/unboxed/Word.java index 0fb927ebf..33109d44e 100644 --- a/MMTk/harness/vmmagic/org/vmmagic/unboxed/Word.java +++ b/MMTk/harness/vmmagic/org/vmmagic/unboxed/Word.java @@ -51,6 +51,7 @@ public static Word fromIntSignExtend(int val) { * @param val * @return */ + @SuppressWarnings("cast") public static Word fromIntZeroExtend(int val) { return new Word(((long)val) & 0xFFFFFFFFL); } diff --git a/MMTk/src/org/mmtk/plan/Phase.java b/MMTk/src/org/mmtk/plan/Phase.java index 871ebb852..dd9255ed3 100644 --- a/MMTk/src/org/mmtk/plan/Phase.java +++ b/MMTk/src/org/mmtk/plan/Phase.java @@ -414,14 +414,20 @@ private static boolean processPhaseStack(boolean resume) { /* Global phase */ case SCHEDULE_GLOBAL: { if (logDetails) Log.writeln(" as Global..."); - if (primary) plan.collectionPhase(phaseId); + if (primary) { + if (VM.DEBUG) VM.debugging.globalPhase(phaseId,true); + plan.collectionPhase(phaseId); + if (VM.DEBUG) VM.debugging.globalPhase(phaseId,false); + } break; } /* Collector phase */ case SCHEDULE_COLLECTOR: { if (logDetails) Log.writeln(" as Collector..."); + if (VM.DEBUG) VM.debugging.collectorPhase(phaseId,order,true); collector.collectionPhase(phaseId, primary); + if (VM.DEBUG) VM.debugging.collectorPhase(phaseId,order,false); break; } @@ -431,7 +437,9 @@ private static boolean processPhaseStack(boolean resume) { /* Iterate through all mutator contexts */ MutatorContext mutator; while ((mutator = VM.activePlan.getNextMutator()) != null) { + if (VM.DEBUG) VM.debugging.mutatorPhase(phaseId,mutator.getId(),true); mutator.collectionPhase(phaseId, primary); + if (VM.DEBUG) VM.debugging.mutatorPhase(phaseId,mutator.getId(),false); } break; } diff --git a/MMTk/src/org/mmtk/plan/generational/GenNurseryTraceLocal.java b/MMTk/src/org/mmtk/plan/generational/GenNurseryTraceLocal.java index fde171fff..785c0f839 100644 --- a/MMTk/src/org/mmtk/plan/generational/GenNurseryTraceLocal.java +++ b/MMTk/src/org/mmtk/plan/generational/GenNurseryTraceLocal.java @@ -94,12 +94,14 @@ protected void processRememberedSets() { logMessage(5, "processing modbuf"); ObjectReference obj; while (!(obj = modbuf.pop()).isNull()) { + if (VM.DEBUG) VM.debugging.modbufEntry(obj); Plan.markAsUnlogged(obj); scanObject(obj); } logMessage(5, "processing remset"); while (!remset.isEmpty()) { Address loc = remset.pop(); + if (VM.DEBUG) VM.debugging.remsetEntry(loc); processRootEdge(loc, false); } logMessage(5, "processing array remset"); @@ -107,6 +109,7 @@ protected void processRememberedSets() { while (!arrayRemset.isEmpty()) { Address start = arrayRemset.pop1(); Address guard = arrayRemset.pop2(); + if (VM.DEBUG) VM.debugging.arrayRemsetEntry(start,guard); while (start.LT(guard)) { processRootEdge(start, false); start = start.plus(BYTES_IN_ADDRESS); diff --git a/MMTk/src/org/mmtk/policy/CopySpace.java b/MMTk/src/org/mmtk/policy/CopySpace.java index 864fb196c..c315bbd1c 100644 --- a/MMTk/src/org/mmtk/policy/CopySpace.java +++ b/MMTk/src/org/mmtk/policy/CopySpace.java @@ -15,7 +15,9 @@ import org.mmtk.plan.TraceLocal; import org.mmtk.plan.TransitiveClosure; import org.mmtk.utility.heap.*; +import org.mmtk.utility.options.Options; import org.mmtk.utility.Constants; +import org.mmtk.utility.Log; import org.mmtk.vm.VM; @@ -62,6 +64,10 @@ */ private boolean fromSpace = true; + public boolean isFromSpace() { + return fromSpace; + } + /**************************************************************************** * * Initialization @@ -110,6 +116,7 @@ public CopySpace(String name, int pageBudget, boolean fromSpace, VMRequest vmReq public void release() { ((MonotonePageResource) pr).reset(); lastDiscontiguousRegion = Address.zero(); + fromSpace = false; } /** @@ -183,11 +190,17 @@ public ObjectReference traceObject(TransitiveClosure trace, ObjectReference obje return forwardingPtr.and(GC_FORWARDING_MASK.not()).toAddress().toObjectReference(); } else { /* We are the designated copier, so forward it and enqueue it */ - ObjectReference newObject = VM.objectModel.copy(object, allocator); setForwardingPointer(object, newObject); trace.processNode(newObject); // Scan it later + if (Options.verbose.getValue() >= 9) { + Log.write("C["); Log.write(object); Log.write("/"); + Log.write(getName()); Log.write("] -> "); + Log.write(newObject); Log.write("/"); + Log.write(Space.getSpaceForObject(newObject).getName()); + Log.writeln("]"); + } return newObject; } } diff --git a/MMTk/src/org/mmtk/vm/Factory.java b/MMTk/src/org/mmtk/vm/Factory.java index 214c74dba..238e4de6c 100644 --- a/MMTk/src/org/mmtk/vm/Factory.java +++ b/MMTk/src/org/mmtk/vm/Factory.java @@ -181,6 +181,11 @@ public abstract class Factory { */ public abstract MMTk_Events newEvents(); + /** + * Create a new debug object + */ + public abstract Debug newDebug(); + /********************************************************************** * GCspy methods */ diff --git a/MMTk/src/org/mmtk/vm/VM.java b/MMTk/src/org/mmtk/vm/VM.java index 3ea51a7a5..b37a65e80 100644 --- a/MMTk/src/org/mmtk/vm/VM.java +++ b/MMTk/src/org/mmtk/vm/VM.java @@ -78,6 +78,8 @@ public final class VM { public static final int ALIGNMENT_VALUE; /** The offset from an array reference to element zero */ public static final Offset ARRAY_BASE_OFFSET; + /** Global debugging switch */ + public static final boolean DEBUG; /* * VM-specific functionality captured in a series of singleton classs @@ -114,6 +116,8 @@ public final class VM { public static final TraceInterface traceInterface; @Untraced public static final MMTk_Events events; + @Untraced + public static final Debug debugging; /* * The remainder is does the static initialization of the @@ -159,6 +163,7 @@ public final class VM { strings = factory.newStrings(); traceInterface = factory.newTraceInterface(); events = factory.newEvents(); + debugging = factory.newDebug(); config = new Config(factory.newBuildTimeConfig()); /* Now initialize the constants using the vm-specific singletons */ @@ -175,6 +180,7 @@ public final class VM { MAX_BYTES_PADDING = Memory.maxBytesPaddingTrapdoor(memory); ALIGNMENT_VALUE = Memory.alignmentValueTrapdoor(memory); ARRAY_BASE_OFFSET = ObjectModel.arrayBaseOffsetTrapdoor(objectModel); + DEBUG = Debug.isEnabledTrapdoor(debugging); } /** diff --git a/bin/test-mmtk b/bin/test-mmtk index c5b3cfeff..4f4727c13 100755 --- a/bin/test-mmtk +++ b/bin/test-mmtk @@ -14,7 +14,7 @@ # Temporary script TEST_DIR=MMTk/harness/test-scripts -ant mmtk-harness +ant clean compile-mmtk mmtk-harness rm -rf results/mmtk mkdir -p results/mmtk diff --git a/build.xml b/build.xml index a877dfc75..cdcdca2c5 100644 --- a/build.xml +++ b/build.xml @@ -259,6 +259,14 @@ + + + + + + + + diff --git a/rvm/src-generated/vm-configuration/Configuration.template b/rvm/src-generated/vm-configuration/Configuration.template index 7ee06e7a6..efd5dfe8a 100644 --- a/rvm/src-generated/vm-configuration/Configuration.template +++ b/rvm/src-generated/vm-configuration/Configuration.template @@ -47,9 +47,6 @@ public abstract class Configuration { public static final boolean BuildForPowerOpenABI = BuildForAix || (BuildForLinux && BuildForPowerPC && BuildFor64Addr); public static final boolean BuildForSVR4ABI = !(BuildForPowerOpenABI || BuildForMachOABI); - /** Do we have the facilities to intercept blocking system calls? */ - public static final boolean withoutInterceptBlockingSystemCalls = BuildForAix || BuildForOsx || BuildForSolaris; - /** Are we using Classpath's portable native sync feature? */ public static final boolean PortableNativeSync = @_PORTABLE_NATIVE_SYNC_@; diff --git a/rvm/src/org/jikesrvm/classloader/ClassFileReader.java b/rvm/src/org/jikesrvm/classloader/ClassFileReader.java index 0314e0552..452c6626b 100644 --- a/rvm/src/org/jikesrvm/classloader/ClassFileReader.java +++ b/rvm/src/org/jikesrvm/classloader/ClassFileReader.java @@ -30,19 +30,11 @@ public class ClassFileReader implements Constants, ClassLoaderConstants { /** - * Create an instance of a RVMClass. - * @param typeRef the cannonical type reference for this type. + * Parse and return the constant pool in a class file + * @param typeRef the canonical type reference for this type. * @param input the data stream from which to read the class's description. */ - static RVMClass readClass(TypeReference typeRef, DataInputStream input) throws ClassFormatError, IOException { - - if (RVMClass.classLoadingDisabled) { - throw new RuntimeException("ClassLoading Disabled : " + typeRef); - } - - if (VM.TraceClassLoading && VM.runningVM) { - VM.sysWrite("RVMClass: (begin) load file " + typeRef.getName() + "\n"); - } + static int[] readConstantPool(TypeReference typeRef, DataInputStream input) throws ClassFormatError, IOException { int magic = input.readInt(); if (magic != 0xCAFEBABE) { @@ -204,8 +196,17 @@ static RVMClass readClass(TypeReference typeRef, DataInputStream input) throws C } // out: MemberReference id } } + return constantPool; + } - short modifiers = input.readShort(); + /** + * Read the class' TypeReference + * @param typeRef + * @param input + * @param constantPool + * @return the constantPool index of the typeRef of the class we are reading + */ + static int readTypeRef(TypeReference typeRef, DataInputStream input, int[] constantPool) throws IOException, ClassFormatError { int myTypeIndex = input.readUnsignedShort(); TypeReference myTypeRef = getTypeRef(constantPool, myTypeIndex); if (myTypeRef != typeRef) { @@ -225,13 +226,33 @@ static RVMClass readClass(TypeReference typeRef, DataInputStream input) throws C "\"\n" + typeRef + " != " + myTypeRef); } } + return myTypeIndex; + } + /** + * Read the super class name, load and resolve the super class + * @param input + * @param constantPool + * @param modifiers + * @return the super class of the class being read + */ + static RVMClass readSuperClass(DataInputStream input, int[] constantPool, + short modifiers) throws IOException, NoClassDefFoundError { TypeReference superType = getTypeRef(constantPool, input.readUnsignedShort()); // possibly null RVMClass superClass = null; if (((modifiers & ACC_INTERFACE) == 0) && (superType != null)) { superClass = superType.resolve().asClass(); } + return superClass; + } + /** + * Read the list of interfaces implemented by the class being read + * @param input + * @param constantPool + * @return the interfaces implemented by the class + */ + static RVMClass[] readDeclaredInterfaces(DataInputStream input, int[] constantPool) throws IOException, NoClassDefFoundError { int numInterfaces = input.readUnsignedShort(); RVMClass[] declaredInterfaces; if (numInterfaces == 0) { @@ -243,7 +264,17 @@ static RVMClass readClass(TypeReference typeRef, DataInputStream input) throws C declaredInterfaces[i] = inTR.resolve().asClass(); } } + return declaredInterfaces; + } + /** + * Read the declared fields of the class being read + * @param typeRef + * @param input + * @param constantPool + * @return the list of declared fields + */ + static RVMField[] readDeclaredFields(TypeReference typeRef, DataInputStream input, int[] constantPool) throws IOException { int numFields = input.readUnsignedShort(); RVMField[] declaredFields; if (numFields == 0) { @@ -263,10 +294,19 @@ static RVMClass readClass(TypeReference typeRef, DataInputStream input) throws C declaredFields[i] = RVMField.readField(typeRef, constantPool, memRef, fmodifiers, input); } } + return declaredFields; + } + /** + * Read the declared methods of the class being read + * @param typeRef + * @param input + * @param constantPool + * @return the declared methods of the class + */ + static RVMMethod[] readDeclaredMethods(TypeReference typeRef, DataInputStream input, int[] constantPool) throws IOException { int numMethods = input.readUnsignedShort(); RVMMethod[] declaredMethods; - RVMMethod classInitializerMethod = null; if (numMethods == 0) { declaredMethods = RVMType.emptyVMMethod; } else { @@ -278,11 +318,47 @@ static RVMClass readClass(TypeReference typeRef, DataInputStream input) throws C MemberReference memRef = MemberReference.findOrCreate(typeRef, methodName, methodDescriptor); RVMMethod method = RVMMethod.readMethod(typeRef, constantPool, memRef, mmodifiers, input); declaredMethods[i] = method; - if (method.isClassInitializer()) { - classInitializerMethod = method; - } } } + return declaredMethods; + } + + /** + * Return the class initializer method among the declared methods of the class + * @param declaredMethods + * @return the class initializer method of the class + */ + static RVMMethod getClassInitializerMethod(RVMMethod[] declaredMethods) { + for (RVMMethod method : declaredMethods) { + if (method.isClassInitializer()) return method; + } + return null; + } + + /** + * Create an instance of a RVMClass. + * @param typeRef the canonical type reference for this type. + * @param input the data stream from which to read the class's description. + */ + static RVMClass readClass(TypeReference typeRef, DataInputStream input) throws ClassFormatError, IOException { + + if (RVMClass.classLoadingDisabled) { + throw new RuntimeException("ClassLoading Disabled : " + typeRef); + } + + if (VM.TraceClassLoading && VM.runningVM) { + VM.sysWrite("RVMClass: (begin) load file " + typeRef.getName() + "\n"); + } + + int[] constantPool = readConstantPool(typeRef, input); + short modifiers = input.readShort(); + int myTypeIndex = readTypeRef(typeRef, input, constantPool); + RVMClass superClass = readSuperClass(input, constantPool, modifiers); + RVMClass[] declaredInterfaces = readDeclaredInterfaces(input, constantPool); + RVMField[] declaredFields = readDeclaredFields(typeRef, input, constantPool); + RVMMethod[] declaredMethods = readDeclaredMethods(typeRef, input, constantPool); + RVMMethod classInitializerMethod = getClassInitializerMethod(declaredMethods); + TypeReference[] declaredClasses = null; Atom sourceName = null; TypeReference declaringClass = null; diff --git a/rvm/src/org/jikesrvm/compilers/baseline/TemplateCompilerFramework.java b/rvm/src/org/jikesrvm/compilers/baseline/TemplateCompilerFramework.java index 6ed15b4e9..45a8fbeb1 100644 --- a/rvm/src/org/jikesrvm/compilers/baseline/TemplateCompilerFramework.java +++ b/rvm/src/org/jikesrvm/compilers/baseline/TemplateCompilerFramework.java @@ -1629,23 +1629,31 @@ protected final MachineCode genCode() { "You must use the 'create' function to create an array of this type"); } - // We can do early resolution of the array type if the element type - // is already initialized. RVMArray array = (RVMArray) arrayRef.peekType(); - if (array != null && - !(array.isInitialized() || array.isInBootImage()) && - RVMType.JavaLangObjectType.isInstantiated()) { - RVMType elementType = elementTypeRef.peekType(); - if (elementType != null && (elementType.isInitialized() || elementType.isInBootImage())) { - array.resolve(); - array.instantiate(); - } - if (array.isInitialized() || array.isInBootImage()) { - emit_resolved_newarray(array); - break; + if (RVMType.JavaLangObjectType.isInstantiated()) { + // If we've already instantiated java.lang.Object, then we can + // forcibly fully instantiate the array type as long as the element type is + // either already initialized or is in the bootimage. + // Note: The test against java.lang.Object is required only for the baseline compiler + // and is not present in the opt compiler version of anewarray (BC2IR) because of the way + // we handle recursive invocations of the compiler (can be caused by instantiate()). + // We need Object to be instantiated because we are going to mine it's TIB to get entries for array methods... + if (array == null || !(array.isInitialized() || array.isInBootImage())) { + RVMType elementType = elementTypeRef.peekType(); + if (elementType != null && (elementType.isInitialized() || elementType.isInBootImage())) { + if (array == null) { + array = (RVMArray)arrayRef.resolve(); + } + array.resolve(); + array.instantiate(); + } } } - emit_unresolved_newarray(arrayRef); + if (array != null && (array.isInitialized() || array.isInBootImage())) { + emit_resolved_newarray(array); + } else { + emit_unresolved_newarray(arrayRef); + } break; } diff --git a/testing/tests/basic/build.xml b/testing/tests/basic/build.xml index e5699351b..55cbb9623 100644 --- a/testing/tests/basic/build.xml +++ b/testing/tests/basic/build.xml @@ -148,6 +148,7 @@ +