/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.mmtk.harness.lang; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Random; import org.mmtk.harness.Main; 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; /** * An execution environment */ public class Env extends Mutator { private static boolean gcEverySafepoint = false; /** * The stack */ private final UnsyncStack<StackFrame> stack = new UnsyncStack<StackFrame>(); /** * A source of random numbers (we have one per thread so that we can write * deterministic scripts). */ private final Random rng = new Random(); /** * The type of exception that is expected at the end of execution. */ private Class<?> expectedThrowable; /** * Enable a CG on every safepoint */ public static void setGcEverySafepoint() { gcEverySafepoint = true; } /** * Enter a new procedure, pushing a new stack frame. * @param frame Stack frame to push */ public void push(StackFrame frame) { stack.push(frame); Trace.trace(Item.ENV,"push()"); } /** * Exit from a procedure, popping the top stack frame. */ public void pop() { stack.pop(); Trace.trace(Item.ENV,"pop()"); } /** * @return The frame at the top of the stack. */ public StackFrame top() { return stack.peek(); } /** * @return The current stack */ public Iterable<StackFrame> stack() { return stack; } /** * Compute the thread roots for this mutator. */ @Override public void computeThreadRoots(TraceLocal trace) { int localCount = 0; for (StackFrame frame : stack) { localCount += frame.computeRoots(trace); } Trace.trace(Item.ROOTS, "Locals: %d", localCount); } /** * @see org.mmtk.harness.Mutator#getRoots() */ @Override public Collection<ObjectValue> getRoots() { List<ObjectValue> roots = new ArrayList<ObjectValue>(); for (StackFrame frame : stack) { roots.addAll(frame.getRoots()); } return roots; } /** * Print the thread roots and add them to a stack for processing. */ @Override public Collection<ObjectReference> dumpThreadRoots(int width) { int frameId = 0; List<ObjectReference> roots = new ArrayList<ObjectReference>(); for (StackFrame frame : stack) { System.err.printf(" Frame %5d [", frameId++); roots.addAll(frame.dumpRoots(width)); System.err.println(" ]"); } System.err.println(); return roots; } /** * @see org.mmtk.harness.Mutator#gcSafePoint() */ @Override public boolean gcSafePoint() { if (gcEverySafepoint) { gc(); } return super.gcSafePoint(); } /** * @see org.mmtk.harness.Mutator#end() */ @Override public void end() { if (!(expectedThrowable == null)) fail(("Expected exception of class " + expectedThrowable + " not found")); super.end(); } /** * Set an expectation that the execution will exit with a throw of this exception. * @param expectedThrowable The expected exception class */ public void setExpectedThrowable(Class<?> expectedThrowable) { Trace.trace(Item.EXCEPTION, "Setting expected exception %s", expectedThrowable.getCanonicalName()); this.expectedThrowable = expectedThrowable; } /** * Mutator-specific handling of uncaught exceptions. The scheduler calls this when * it catches an unhandled exception. * @param t Thread object * @param e Exception */ public void uncaughtException(Thread t, Throwable e) { Trace.trace(Item.EXCEPTION, "Processing uncaught exception %s", e.getClass().getCanonicalName()); if (e.getClass() == expectedThrowable) { System.err.println("Mutator " + context.getId() + " exiting due to expected exception of class " + expectedThrowable); Main.exitWithSuccess(); } else { System.err.print("Mutator " + context.getId() + " caused unexpected exception: "); e.printStackTrace(); Main.exitWithFailure(); } } /** * @return The per-thread random number generator */ public Random random() { return rng; } }