639 lines
20 KiB
Java
639 lines
20 KiB
Java
// PART OF THE MACHINE SIMULATION. DO NOT CHANGE.
|
|
|
|
package nachos.machine;
|
|
|
|
import java.lang.reflect.Constructor;
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Modifier;
|
|
import java.security.PrivilegedAction;
|
|
import java.util.Random;
|
|
|
|
/**
|
|
* Thrown when an assertion fails.
|
|
*/
|
|
class AssertionFailureError extends Error {
|
|
AssertionFailureError() {
|
|
super();
|
|
}
|
|
|
|
AssertionFailureError(String message) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Provides miscellaneous library routines.
|
|
*/
|
|
public final class Lib {
|
|
/**
|
|
* Prevent instantiation.
|
|
*/
|
|
private Lib() {
|
|
}
|
|
|
|
private static Random random = null;
|
|
|
|
/**
|
|
* Seed the random number generater. May only be called once.
|
|
*
|
|
* @param randomSeed the seed for the random number generator.
|
|
*/
|
|
public static void seedRandom(long randomSeed) {
|
|
assertTrue(random == null);
|
|
random = new Random(randomSeed);
|
|
}
|
|
|
|
/**
|
|
* Return a random integer between 0 and <i>range - 1</i>. Must not be
|
|
* called before <tt>seedRandom()</tt> seeds the random number generator.
|
|
*
|
|
* @param range a positive value specifying the number of possible
|
|
* return values.
|
|
* @return a random integer in the specified range.
|
|
*/
|
|
public static int random(int range) {
|
|
assertTrue(range > 0);
|
|
return random.nextInt(range);
|
|
}
|
|
|
|
/**
|
|
* Return a random double between 0.0 (inclusive) and 1.0 (exclusive).
|
|
*
|
|
* @return a random double between 0.0 and 1.0.
|
|
*/
|
|
public static double random() {
|
|
return random.nextDouble();
|
|
}
|
|
|
|
/**
|
|
* Asserts that <i>expression</i> is <tt>true</tt>. If not, then Nachos
|
|
* exits with an error message.
|
|
*
|
|
* @param expression the expression to assert.
|
|
*/
|
|
public static void assertTrue(boolean expression) {
|
|
if (!expression)
|
|
throw new AssertionFailureError();
|
|
}
|
|
|
|
/**
|
|
* Asserts that <i>expression</i> is <tt>true</tt>. If not, then Nachos
|
|
* exits with the specified error message.
|
|
*
|
|
* @param expression the expression to assert.
|
|
* @param message the error message.
|
|
*/
|
|
public static void assertTrue(boolean expression, String message) {
|
|
if (!expression)
|
|
throw new AssertionFailureError(message);
|
|
}
|
|
|
|
/**
|
|
* Asserts that this call is never made. Same as <tt>assertTrue(false)</tt>.
|
|
*/
|
|
public static void assertNotReached() {
|
|
assertTrue(false);
|
|
}
|
|
|
|
/**
|
|
* Asserts that this call is never made, with the specified error messsage.
|
|
* Same as <tt>assertTrue(false, message)</tt>.
|
|
*
|
|
* @param message the error message.
|
|
*/
|
|
public static void assertNotReached(String message) {
|
|
assertTrue(false, message);
|
|
}
|
|
|
|
/**
|
|
* Print <i>message</i> if <i>flag</i> was enabled on the command line. To
|
|
* specify which flags to enable, use the -d command line option. For
|
|
* example, to enable flags a, c, and e, do the following:
|
|
*
|
|
* <p>
|
|
* <pre>nachos -d ace</pre>
|
|
*
|
|
* <p>
|
|
* Nachos uses several debugging flags already, but you are encouraged to
|
|
* add your own.
|
|
*
|
|
* @param flag the debug flag that must be set to print this message.
|
|
* @param message the debug message.
|
|
*/
|
|
public static void debug(char flag, String message) {
|
|
if (test(flag))
|
|
System.out.println(message);
|
|
}
|
|
|
|
/**
|
|
* Tests if <i>flag</i> was enabled on the command line.
|
|
*
|
|
* @param flag the debug flag to test.
|
|
*
|
|
* @return <tt>true</tt> if this flag was enabled on the command line.
|
|
*/
|
|
public static boolean test(char flag) {
|
|
if (debugFlags == null)
|
|
return false;
|
|
else if (debugFlags[(int) '+'])
|
|
return true;
|
|
else if (flag >= 0 && flag < 0x80 && debugFlags[(int) flag])
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Enable all the debug flags in <i>flagsString</i>.
|
|
*
|
|
* @param flagsString the flags to enable.
|
|
*/
|
|
public static void enableDebugFlags(String flagsString) {
|
|
if (debugFlags == null)
|
|
debugFlags = new boolean[0x80];
|
|
|
|
char[] newFlags = flagsString.toCharArray();
|
|
for (int i=0; i<newFlags.length; i++) {
|
|
char c = newFlags[i];
|
|
if (c >= 0 && c < 0x80)
|
|
debugFlags[(int) c] = true;
|
|
}
|
|
}
|
|
|
|
/** Debug flags specified on the command line. */
|
|
private static boolean debugFlags[];
|
|
|
|
/**
|
|
* Read a file, verifying that the requested number of bytes is read, and
|
|
* verifying that the read operation took a non-zero amount of time.
|
|
*
|
|
* @param file the file to read.
|
|
* @param position the file offset at which to start reading.
|
|
* @param buf the buffer in which to store the data.
|
|
* @param offset the buffer offset at which storing begins.
|
|
* @param length the number of bytes to read.
|
|
*/
|
|
public static void strictReadFile(OpenFile file, int position,
|
|
byte[] buf, int offset, int length) {
|
|
long startTime = Machine.timer().getTime();
|
|
assertTrue(file.read(position, buf, offset, length) == length);
|
|
long finishTime = Machine.timer().getTime();
|
|
assertTrue(finishTime>startTime);
|
|
}
|
|
|
|
/**
|
|
* Load an entire file into memory.
|
|
*
|
|
* @param file the file to load.
|
|
* @return an array containing the contents of the entire file, or
|
|
* <tt>null</tt> if an error occurred.
|
|
*/
|
|
public static byte[] loadFile(OpenFile file) {
|
|
int startOffset = file.tell();
|
|
|
|
int length = file.length();
|
|
if (length < 0)
|
|
return null;
|
|
|
|
byte[] data = new byte[length];
|
|
|
|
file.seek(0);
|
|
int amount = file.read(data, 0, length);
|
|
file.seek(startOffset);
|
|
|
|
if (amount == length)
|
|
return data;
|
|
else
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Take a read-only snapshot of a file.
|
|
*
|
|
* @param file the file to take a snapshot of.
|
|
* @return a read-only snapshot of the file.
|
|
*/
|
|
public static OpenFile cloneFile(OpenFile file) {
|
|
OpenFile clone = new ArrayFile(loadFile(file));
|
|
|
|
clone.seek(file.tell());
|
|
|
|
return clone;
|
|
}
|
|
|
|
/**
|
|
* Convert a short into its little-endian byte string representation.
|
|
*
|
|
* @param array the array in which to store the byte string.
|
|
* @param offset the offset in the array where the string will start.
|
|
* @param value the value to convert.
|
|
*/
|
|
public static void bytesFromShort(byte[] array, int offset, short value) {
|
|
array[offset+0] = (byte) ((value>>0)&0xFF);
|
|
array[offset+1] = (byte) ((value>>8)&0xFF);
|
|
}
|
|
|
|
/**
|
|
* Convert an int into its little-endian byte string representation.
|
|
*
|
|
* @param array the array in which to store the byte string.
|
|
* @param offset the offset in the array where the string will start.
|
|
* @param value the value to convert.
|
|
*/
|
|
public static void bytesFromInt(byte[] array, int offset, int value) {
|
|
array[offset+0] = (byte) ((value>>0) &0xFF);
|
|
array[offset+1] = (byte) ((value>>8) &0xFF);
|
|
array[offset+2] = (byte) ((value>>16)&0xFF);
|
|
array[offset+3] = (byte) ((value>>24)&0xFF);
|
|
}
|
|
|
|
/**
|
|
* Convert an int into its little-endian byte string representation, and
|
|
* return an array containing it.
|
|
*
|
|
* @param value the value to convert.
|
|
* @return an array containing the byte string.
|
|
*/
|
|
public static byte[] bytesFromInt(int value) {
|
|
byte[] array = new byte[4];
|
|
bytesFromInt(array, 0, value);
|
|
return array;
|
|
}
|
|
|
|
/**
|
|
* Convert an int into a little-endian byte string representation of the
|
|
* specified length.
|
|
*
|
|
* @param array the array in which to store the byte string.
|
|
* @param offset the offset in the array where the string will start.
|
|
* @param length the number of bytes to store (must be 1, 2, or 4).
|
|
* @param value the value to convert.
|
|
*/
|
|
public static void bytesFromInt(byte[] array, int offset,
|
|
int length, int value) {
|
|
assertTrue(length==1 || length==2 || length==4);
|
|
|
|
switch (length) {
|
|
case 1:
|
|
array[offset] = (byte) value;
|
|
break;
|
|
case 2:
|
|
bytesFromShort(array, offset, (short) value);
|
|
break;
|
|
case 4:
|
|
bytesFromInt(array, offset, value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert to a short from its little-endian byte string representation.
|
|
*
|
|
* @param array the array containing the byte string.
|
|
* @param offset the offset of the byte string in the array.
|
|
* @return the corresponding short value.
|
|
*/
|
|
public static short bytesToShort(byte[] array, int offset) {
|
|
return (short) ((((short) array[offset+0] & 0xFF) << 0) |
|
|
(((short) array[offset+1] & 0xFF) << 8));
|
|
}
|
|
|
|
/**
|
|
* Convert to an unsigned short from its little-endian byte string
|
|
* representation.
|
|
*
|
|
* @param array the array containing the byte string.
|
|
* @param offset the offset of the byte string in the array.
|
|
* @return the corresponding short value.
|
|
*/
|
|
public static int bytesToUnsignedShort(byte[] array, int offset) {
|
|
return (((int) bytesToShort(array, offset)) & 0xFFFF);
|
|
}
|
|
|
|
/**
|
|
* Convert to an int from its little-endian byte string representation.
|
|
*
|
|
* @param array the array containing the byte string.
|
|
* @param offset the offset of the byte string in the array.
|
|
* @return the corresponding int value.
|
|
*/
|
|
public static int bytesToInt(byte[] array, int offset) {
|
|
return (int) ((((int) array[offset+0] & 0xFF) << 0) |
|
|
(((int) array[offset+1] & 0xFF) << 8) |
|
|
(((int) array[offset+2] & 0xFF) << 16) |
|
|
(((int) array[offset+3] & 0xFF) << 24));
|
|
}
|
|
|
|
/**
|
|
* Convert to an int from a little-endian byte string representation of the
|
|
* specified length.
|
|
*
|
|
* @param array the array containing the byte string.
|
|
* @param offset the offset of the byte string in the array.
|
|
* @param length the length of the byte string.
|
|
* @return the corresponding value.
|
|
*/
|
|
public static int bytesToInt(byte[] array, int offset, int length) {
|
|
assertTrue(length==1 || length==2 || length==4);
|
|
|
|
switch (length) {
|
|
case 1:
|
|
return array[offset];
|
|
case 2:
|
|
return bytesToShort(array, offset);
|
|
case 4:
|
|
return bytesToInt(array, offset);
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert to a string from a possibly null-terminated array of bytes.
|
|
*
|
|
* @param array the array containing the byte string.
|
|
* @param offset the offset of the byte string in the array.
|
|
* @param length the maximum length of the byte string.
|
|
* @return a string containing the specified bytes, up to and not
|
|
* including the null-terminator (if present).
|
|
*/
|
|
public static String bytesToString(byte[] array, int offset, int length) {
|
|
int i;
|
|
for (i=0; i<length; i++) {
|
|
if (array[offset+i] == 0)
|
|
break;
|
|
}
|
|
|
|
return new String(array, offset, i);
|
|
}
|
|
|
|
/** Mask out and shift a bit substring.
|
|
*
|
|
* @param bits the bit string.
|
|
* @param lowest the first bit of the substring within the string.
|
|
* @param size the number of bits in the substring.
|
|
* @return the substring.
|
|
*/
|
|
public static int extract(int bits, int lowest, int size) {
|
|
if (size == 32)
|
|
return (bits >> lowest);
|
|
else
|
|
return ((bits >> lowest) & ((1<<size)-1));
|
|
}
|
|
|
|
/** Mask out and shift a bit substring.
|
|
*
|
|
* @param bits the bit string.
|
|
* @param lowest the first bit of the substring within the string.
|
|
* @param size the number of bits in the substring.
|
|
* @return the substring.
|
|
*/
|
|
public static long extract(long bits, int lowest, int size) {
|
|
if (size == 64)
|
|
return (bits >> lowest);
|
|
else
|
|
return ((bits >> lowest) & ((1L<<size)-1));
|
|
}
|
|
|
|
/** Mask out and shift a bit substring; then sign extend the substring.
|
|
*
|
|
* @param bits the bit string.
|
|
* @param lowest the first bit of the substring within the string.
|
|
* @param size the number of bits in the substring.
|
|
* @return the substring, sign-extended.
|
|
*/
|
|
public static int extend(int bits, int lowest, int size) {
|
|
int extra = 32 - (lowest+size);
|
|
return ((extract(bits, lowest, size) << extra) >> extra);
|
|
}
|
|
|
|
/** Test if a bit is set in a bit string.
|
|
*
|
|
* @param flag the flag to test.
|
|
* @param bits the bit string.
|
|
* @return <tt>true</tt> if <tt>(bits & flag)</tt> is non-zero.
|
|
*/
|
|
public static boolean test(long flag, long bits) {
|
|
return ((bits & flag) != 0);
|
|
}
|
|
|
|
/**
|
|
* Creates a padded upper-case string representation of the integer
|
|
* argument in base 16.
|
|
*
|
|
* @param i an integer.
|
|
* @return a padded upper-case string representation in base 16.
|
|
*/
|
|
public static String toHexString(int i) {
|
|
return toHexString(i, 8);
|
|
}
|
|
|
|
/**
|
|
* Creates a padded upper-case string representation of the integer
|
|
* argument in base 16, padding to at most the specified number of digits.
|
|
*
|
|
* @param i an integer.
|
|
* @param pad the minimum number of hex digits to pad to.
|
|
* @return a padded upper-case string representation in base 16.
|
|
*/
|
|
public static String toHexString(int i, int pad) {
|
|
String result = Integer.toHexString(i).toUpperCase();
|
|
while (result.length() < pad)
|
|
result = "0" + result;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Divide two non-negative integers, round the quotient up to the nearest
|
|
* integer, and return it.
|
|
*
|
|
* @param a the numerator.
|
|
* @param b the denominator.
|
|
* @return <tt>ceiling(a / b)</tt>.
|
|
*/
|
|
public static int divRoundUp(int a, int b) {
|
|
assertTrue(a >= 0 && b > 0);
|
|
|
|
return ((a + (b-1)) / b);
|
|
}
|
|
|
|
/**
|
|
* Load and return the named class, or return <tt>null</tt> if the class
|
|
* could not be loaded.
|
|
*
|
|
* @param className the name of the class to load.
|
|
* @return the loaded class, or <tt>null</tt> if an error occurred.
|
|
*/
|
|
public static Class tryLoadClass(String className) {
|
|
try {
|
|
return ClassLoader.getSystemClassLoader().loadClass(className);
|
|
}
|
|
catch (Throwable e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load and return the named class, terminating Nachos on any error.
|
|
*
|
|
* @param className the name of the class to load.
|
|
* @return the loaded class.
|
|
*/
|
|
public static Class loadClass(String className) {
|
|
try {
|
|
return ClassLoader.getSystemClassLoader().loadClass(className);
|
|
}
|
|
catch (Throwable e) {
|
|
Machine.terminate(e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create and return a new instance of the named class, using the
|
|
* constructor that takes no arguments.
|
|
*
|
|
* @param className the name of the class to instantiate.
|
|
* @return a new instance of the class.
|
|
*/
|
|
public static Object constructObject(String className) {
|
|
try {
|
|
// kamil - workaround for Java 1.4
|
|
// Thanks to Ka-Hing Cheung for the suggestion.
|
|
// Fixed for Java 1.5 by geels
|
|
Class[] param_types = new Class[0];
|
|
Object[] params = new Object[0];
|
|
return loadClass(className).getConstructor(param_types).newInstance(params);
|
|
}
|
|
catch (Throwable e) {
|
|
Machine.terminate(e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verify that the specified class extends or implements the specified
|
|
* superclass.
|
|
*
|
|
* @param cls the descendant class.
|
|
* @param superCls the ancestor class.
|
|
*/
|
|
public static void checkDerivation(Class<?> cls, Class<?> superCls) {
|
|
Lib.assertTrue(superCls.isAssignableFrom(cls));
|
|
}
|
|
|
|
/**
|
|
* Verifies that the specified class is public and not abstract, and that a
|
|
* constructor with the specified signature exists and is public.
|
|
*
|
|
* @param cls the class containing the constructor.
|
|
* @param parameterTypes the list of parameters.
|
|
*/
|
|
public static void checkConstructor(Class cls, Class[] parameterTypes) {
|
|
try {
|
|
Lib.assertTrue(Modifier.isPublic(cls.getModifiers()) &&
|
|
!Modifier.isAbstract(cls.getModifiers()));
|
|
Constructor constructor = cls.getConstructor(parameterTypes);
|
|
Lib.assertTrue(Modifier.isPublic(constructor.getModifiers()));
|
|
}
|
|
catch (Exception e) {
|
|
Lib.assertNotReached();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verifies that the specified class is public, and that a non-static
|
|
* method with the specified name and signature exists, is public, and
|
|
* returns the specified type.
|
|
*
|
|
* @param cls the class containing the non-static method.
|
|
* @param methodName the name of the non-static method.
|
|
* @param parameterTypes the list of parameters.
|
|
* @param returnType the required return type.
|
|
*/
|
|
public static void checkMethod(Class cls, String methodName,
|
|
Class[] parameterTypes, Class returnType) {
|
|
try {
|
|
Lib.assertTrue(Modifier.isPublic(cls.getModifiers()));
|
|
Method method = cls.getMethod(methodName, parameterTypes);
|
|
Lib.assertTrue(Modifier.isPublic(method.getModifiers()) &&
|
|
!Modifier.isStatic(method.getModifiers()));
|
|
Lib.assertTrue(method.getReturnType() == returnType);
|
|
}
|
|
catch (Exception e) {
|
|
Lib.assertNotReached();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verifies that the specified class is public, and that a static method
|
|
* with the specified name and signature exists, is public, and returns the
|
|
* specified type.
|
|
*
|
|
* @param cls the class containing the static method.
|
|
* @param methodName the name of the static method.
|
|
* @param parameterTypes the list of parameters.
|
|
* @param returnType the required return type.
|
|
*/
|
|
public static void checkStaticMethod(Class cls, String methodName,
|
|
Class[] parameterTypes,
|
|
Class returnType) {
|
|
try {
|
|
Lib.assertTrue(Modifier.isPublic(cls.getModifiers()));
|
|
Method method = cls.getMethod(methodName, parameterTypes);
|
|
Lib.assertTrue(Modifier.isPublic(method.getModifiers()) &&
|
|
Modifier.isStatic(method.getModifiers()));
|
|
Lib.assertTrue(method.getReturnType() == returnType);
|
|
}
|
|
catch (Exception e) {
|
|
Lib.assertNotReached();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verifies that the specified class is public, and that a non-static field
|
|
* with the specified name and type exists, is public, and is not final.
|
|
*
|
|
* @param cls the class containing the field.
|
|
* @param fieldName the name of the field.
|
|
* @param fieldType the required type.
|
|
*/
|
|
public static void checkField(Class cls, String fieldName,
|
|
Class fieldType) {
|
|
try {
|
|
Lib.assertTrue(Modifier.isPublic(cls.getModifiers()));
|
|
Field field = cls.getField(fieldName);
|
|
Lib.assertTrue(field.getType() == fieldType);
|
|
Lib.assertTrue(Modifier.isPublic(field.getModifiers()) &&
|
|
!Modifier.isStatic(field.getModifiers()) &&
|
|
!Modifier.isFinal(field.getModifiers()));
|
|
}
|
|
catch (Exception e) {
|
|
Lib.assertNotReached();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verifies that the specified class is public, and that a static field
|
|
* with the specified name and type exists and is public.
|
|
*
|
|
* @param cls the class containing the static field.
|
|
* @param fieldName the name of the static field.
|
|
* @param fieldType the required type.
|
|
*/
|
|
public static void checkStaticField(Class cls, String fieldName,
|
|
Class fieldType) {
|
|
try {
|
|
Lib.assertTrue(Modifier.isPublic(cls.getModifiers()));
|
|
Field field = cls.getField(fieldName);
|
|
Lib.assertTrue(field.getType() == fieldType);
|
|
Lib.assertTrue(Modifier.isPublic(field.getModifiers()) &&
|
|
Modifier.isStatic(field.getModifiers()));
|
|
}
|
|
catch (Exception e) {
|
|
Lib.assertNotReached();
|
|
}
|
|
}
|
|
}
|