p1/machine/Lib.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();
}
}
}