Mega Code Archive

 
Categories / Java / Development Class
 

JVM Simulator

/*  * Copyright (c) 1996 Artima Software Company. All Rights Reserved.  *  * Permission to use, copy, modify, and distribute this software  * and its documentation for EVALUATION purposes only  * is hereby granted provided that this copyright notice  * appears in all copies. "Evaluation purposes" are any uses which  * do not constitute the sale, sharing, or redistribution of this  * software with or to any other persons in any medium.  *  * ARTIMA SOFTWARE COMPANY MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT  * THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING  * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS  * FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ARTIMA SOFTWARE COMPANY  * SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF  * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  *  */ /*  * LogicalResults.java  *  * This file contains all the code for the java virtual machine simulation  * applet, named Three Dimensional Array, that accompanies the JavaWorld Under The Hood  * article titled,"Objecs and Arrays".  *  * Bill Venners, October 1996  *  */ import java.awt.BorderLayout; import java.awt.Button; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Event; import java.awt.Font; import java.awt.GridLayout; import java.awt.Insets; import java.awt.Label; import java.awt.LayoutManager; import java.awt.Panel; /**  * An applet that simulates the Java virtual machine executing a  * sequence of bytecodes.  *  * @author      Bill Venners  */ public class JVMSimulator extends java.applet.Applet implements Runnable {     // Vars for the three outer panels that are contained inside the Applet's panel.     // twoParts contains the stack and the method area. simulationController     // contains the Step and Reset buttons and the hint label.     private ThreeParts threeParts;     private RegisterPanel registers;     private ControlPanel simulationController;     // Local reference to buttons on control panel allows for easy enabling and     // disabling of buttons.     private Button stepButton;     private Button resetButton;     private Button runButton;     private Button stopButton;     // If the "run" button is pushed, a separate thread will be invoked that     // will cause the JVM to execute until the "stop" button is pressed.     private Thread runner;     private final int millisecondDelayBetweenSteps = 250;     // Vars that implement the Java stack     private final int stackBase = 0x33330000;     private StackMemorySection stackMemorySection = new StackMemorySection(stackBase, SimData.stackMemorySectionSize);     private StackMemoryView stackMemoryView;     // Vars that implement the method area of the JVM     private final int methodAreaBase = 0x44440000;     private MemorySection methodAreaMemorySection = new MemorySection(methodAreaBase,         SimData.methodAreaMemorySectionSize);     private MemoryView methodAreaMemoryView;     // Vars that implement the Java registers     private int pcRegister;     private int optopRegister;     private int frameRegister;     private int varsRegister;     public void init() {         setBackground(SimData.appletBackgroundColor);         setLayout(new BorderLayout(5, 5));         threeParts = new ThreeParts(SimData.methodAreaMemorySectionSize);         simulationController = new ControlPanel();         stepButton = simulationController.getStepButton();         resetButton = simulationController.getResetButton();         runButton = simulationController.getRunButton();         stopButton = simulationController.getStopButton();         ColoredLabel title = new ColoredLabel(SimData.appletTitle, Label.CENTER, SimData.titleColor);         title.setFont(new Font("Helvetica", Font.BOLD, 12));         add("North", title);         add("South", simulationController);         add("Center", threeParts);         // Get a reference to the UI objects that are actually manipulated by         // the handlers of the Step and Reset buttons. These aren't available         // without this explicit get() because these objects are buried several         // levels down in embedded panels.         stackMemoryView = threeParts.getStackMemoryViewReference();         methodAreaMemoryView = threeParts.getMethodAreaMemoryViewReference();         registers = threeParts.getRegisterPanel();         // Place the bytecodes into the method area         for (int i = 0; i < SimData.methodAreaMemorySectionSize; ++i) {             methodAreaMemorySection.setAtAddress(methodAreaBase + i,                 SimData.theProgram[i]);             methodAreaMemorySection.setLogicalValueAtAddress(methodAreaBase + i,                 SimData.byteCodeMnemonics[i]);         }         ResetState();         UpdateStateDisplay();     }     public boolean action(Event evt, Object arg) {         if (evt.target instanceof Button) {             String bname = (String) arg;             if (bname.equals(StringTable.reset)) {                 stopButton.disable();                 runButton.enable();                 stepButton.enable();                 resetButton.disable();                 ResetState();                 UpdateStateDisplay();             }             else if (bname.equals(StringTable.step)) {                 resetButton.enable();                 ExecuteNextInstruction();                 UpdateStateDisplay();             }             else if (bname.equals(StringTable.run)) {                 stopButton.enable();                 runButton.disable();                 stepButton.disable();                 resetButton.disable();                 if (runner == null) {                     runner = new Thread(this);                     runner.start();                 }             }             else if (bname.equals(StringTable.stop)) {                 runButton.enable();                 stepButton.enable();                 resetButton.enable();                 stopButton.disable();                 if (runner != null) {                     runner.stop();                     runner = null;                 }             }         }         return true;     }     // ExecuteNextInstruction() grabs the instruction pointed to by the program     // counter, decodes it via the switch statement, and executes it by running the     // code under the appropriate case statement. The program counter is always     // set to the next instruction that should be executed, naturally. Only those     // bytecodes that appear in the short sequence presented in this simulation     // are interpreted here to save time (your time in downloading and my time     // in writing.)     void ExecuteNextInstruction() {         int a, b, result, i, operand0, operand1, operand2, offset;         float fa, fb, fresult;         Float f;         int nextOpCode = methodAreaMemorySection.getAtAddress(pcRegister);         switch (nextOpCode) {         case OpCode.AALOAD:             executeAaload();             break;         case OpCode.ALOAD_0:             executeAload_n(0);             break;         case OpCode.ASTORE_0:             executeAstore_n(0);             break;         case OpCode.BIPUSH:             operand0 = methodAreaMemorySection.getAtAddress(pcRegister + 1);             stackMemorySection.setAtAddress(optopRegister, operand0);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(operand0));             optopRegister += 4;             pcRegister += 2;             break;          // The BREAKPOINT opcode will serve as a stop sign for a running simulation.         case OpCode.BREAKPOINT:             stopButton.disable();             runButton.disable();             stepButton.disable();             resetButton.enable();             if (runner != null) {                 // If runner is not null, then this is probably the thread that                 // we want to stop. Therefore, as soon as stop has been executed,                 // nothing else will happen. So we must set runner to null before                 // we call runner.stop(). Therefore I copy runner to temp, assign                 // null to runner, and call stop() on temp.                 Thread temp = runner;                 runner = null;                 temp.stop();             }             break;         case OpCode.FCONST_0:             stackMemorySection.setAtAddress(optopRegister, Float.floatToIntBits((float) 0));             stackMemorySection.setLogicalValueAtAddress(optopRegister, "0");             optopRegister += 4;             ++pcRegister;             break;         case OpCode.FCONST_2:             stackMemorySection.setAtAddress(optopRegister, Float.floatToIntBits((float) 2));             stackMemorySection.setLogicalValueAtAddress(optopRegister, "2");             optopRegister += 4;             ++pcRegister;             break;         case OpCode.FLOAD_0:             a = stackMemorySection.getAtAddress(varsRegister);             stackMemorySection.setAtAddress(optopRegister, a);             fa = Float.intBitsToFloat(a);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Float.toString(fa));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.FMUL:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             fa = Float.intBitsToFloat(a);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             optopRegister -= 4;             b = stackMemorySection.getAtAddress(optopRegister);             fb = Float.intBitsToFloat(b);             fresult = fa * fb;             result = Float.floatToIntBits(fresult);             stackMemorySection.setAtAddress(optopRegister, result);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Float.toString(fresult));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.FSTORE_0:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             stackMemorySection.setAtAddress(varsRegister, a);             fa = Float.intBitsToFloat(a);             stackMemorySection.setLogicalValueAtAddress(varsRegister, Float.toString(fa));             ++pcRegister;             break;         case OpCode.FSUB:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             fa = Float.intBitsToFloat(a);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             optopRegister -= 4;             b = stackMemorySection.getAtAddress(optopRegister);             fb = Float.intBitsToFloat(b);             fresult = fb - fa;             result = Float.floatToIntBits(fresult);             stackMemorySection.setAtAddress(optopRegister, result);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Float.toString(fresult));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.GOTO:             operand1 = methodAreaMemorySection.getAtAddress(pcRegister + 1);             operand0 = methodAreaMemorySection.getAtAddress(pcRegister + 2);             offset = (operand1 << 8) | (operand0 & 0xff);             pcRegister += offset;             break;         case OpCode.IADD:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             optopRegister -= 4;             b = stackMemorySection.getAtAddress(optopRegister);             result = a + b;             stackMemorySection.setAtAddress(optopRegister, result);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(result));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.IAND:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             optopRegister -= 4;             b = stackMemorySection.getAtAddress(optopRegister);             result = a & b;             stackMemorySection.setAtAddress(optopRegister, result);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(result));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.IASTORE:             executeIastore();             break;         case OpCode.ICONST_M1:             stackMemorySection.setAtAddress(optopRegister, -1);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "-1");             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ICONST_0:             stackMemorySection.setAtAddress(optopRegister, 0);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "0");             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ICONST_1:             stackMemorySection.setAtAddress(optopRegister, 1);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "1");             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ICONST_2:             stackMemorySection.setAtAddress(optopRegister, 2);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "2");             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ICONST_3:             stackMemorySection.setAtAddress(optopRegister, 3);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "3");             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ICONST_4:             stackMemorySection.setAtAddress(optopRegister, 4);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "4");             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ICONST_5:             stackMemorySection.setAtAddress(optopRegister, 5);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "5");             optopRegister += 4;             ++pcRegister;             break;         case OpCode.IFNE:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             // If a != 0 jump, else go on             if (a != 0) {                 operand1 = methodAreaMemorySection.getAtAddress(pcRegister + 1);                 operand0 = methodAreaMemorySection.getAtAddress(pcRegister + 2);                 offset = (operand1 << 8) | (operand0 & 0xff);                 pcRegister += offset;             }             else {                 pcRegister += 3;             }             break;         case OpCode.IF_ICMPLT:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             optopRegister -= 4;             b = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             // If b < a jump, else go on             if (b < a) {                 operand1 = methodAreaMemorySection.getAtAddress(pcRegister + 1);                 operand0 = methodAreaMemorySection.getAtAddress(pcRegister + 2);                 offset = (operand1 << 8) | (operand0 & 0xff);                 pcRegister += offset;             }             else {                 pcRegister += 3;             }             break;         case OpCode.IINC:             operand0 = methodAreaMemorySection.getAtAddress(pcRegister + 1);             operand1 = methodAreaMemorySection.getAtAddress(pcRegister + 2);             a = stackMemorySection.getAtAddress(varsRegister + (operand0 * 4));             a += operand1;             stackMemorySection.setAtAddress(varsRegister + (operand0 * 4), a);             stackMemorySection.setLogicalValueAtAddress(varsRegister + (operand0 * 4), Integer.toString(a));             pcRegister += 3;             break;         case OpCode.ILOAD_0:             a = stackMemorySection.getAtAddress(varsRegister);             stackMemorySection.setAtAddress(optopRegister, a);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(a));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ILOAD_1:             a = stackMemorySection.getAtAddress(varsRegister + 4);             stackMemorySection.setAtAddress(optopRegister, a);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(a));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ILOAD_2:             a = stackMemorySection.getAtAddress(varsRegister + 8);             stackMemorySection.setAtAddress(optopRegister, a);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(a));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ILOAD_3:             a = stackMemorySection.getAtAddress(varsRegister + 12);             stackMemorySection.setAtAddress(optopRegister, a);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(a));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.IMUL:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             optopRegister -= 4;             b = stackMemorySection.getAtAddress(optopRegister);             result = a * b;             stackMemorySection.setAtAddress(optopRegister, result);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(result));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.INT2BYTE:             a = stackMemorySection.getAtAddress(optopRegister - 4);             a = (byte) a;             stackMemorySection.setAtAddress(optopRegister - 4, a);             stackMemorySection.setLogicalValueAtAddress(optopRegister - 4, Integer.toString(a));             ++pcRegister;             break;         case OpCode.IOR:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             optopRegister -= 4;             b = stackMemorySection.getAtAddress(optopRegister);             result = a | b;             stackMemorySection.setAtAddress(optopRegister, result);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(result));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ISHL:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             optopRegister -= 4;             b = stackMemorySection.getAtAddress(optopRegister);             result = b << (a & 0x1f);             stackMemorySection.setAtAddress(optopRegister, result);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(result));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.ISTORE_0:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             stackMemorySection.setAtAddress(varsRegister, a);             stackMemorySection.setLogicalValueAtAddress(varsRegister, Integer.toString(a));             ++pcRegister;             break;         case OpCode.ISTORE_1:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             stackMemorySection.setAtAddress(varsRegister + 4, a);             stackMemorySection.setLogicalValueAtAddress(varsRegister + 4, Integer.toString(a));             ++pcRegister;             break;         case OpCode.ISTORE_2:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             stackMemorySection.setAtAddress(varsRegister + 8, a);             stackMemorySection.setLogicalValueAtAddress(varsRegister + 8, Integer.toString(a));             ++pcRegister;             break;         case OpCode.ISTORE_3:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             stackMemorySection.setAtAddress(varsRegister + 12, a);             stackMemorySection.setLogicalValueAtAddress(varsRegister + 12, Integer.toString(a));             ++pcRegister;             break;         case OpCode.IXOR:             optopRegister -= 4;             a = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");             optopRegister -= 4;             b = stackMemorySection.getAtAddress(optopRegister);             result = a ^ b;             stackMemorySection.setAtAddress(optopRegister, result);             stackMemorySection.setLogicalValueAtAddress(optopRegister, Integer.toString(result));             optopRegister += 4;             ++pcRegister;             break;         case OpCode.MULTIANEWARRAY:             executeMultianewarray();             pcRegister += 4;             break;         }     }     // Pushing the Reset button will cause ResetState() to be executed, which will     // reset all the data to its initial values.     void ResetState() {         pcRegister = methodAreaBase;         optopRegister = stackBase + SimData.optopOffset;         frameRegister = stackBase + SimData.frameOffset;         varsRegister = stackBase;         int i;         for (i = 0; i < SimData.stackMemorySectionSize; ++i) {             stackMemorySection.setLogicalValueAtAddress(stackBase + (i * 4), "");             stackMemorySection.setAtAddress(stackBase + (i * 4), 0);         }         methodAreaMemoryView.update(methodAreaMemorySection, methodAreaBase);     }     // UpdateStateDisplay writes the current state of the JVM to the UI.     void UpdateStateDisplay() {         registers.setPcRegister(pcRegister);         registers.setOptopRegister(optopRegister);         registers.setFrameRegister(frameRegister);         registers.setVarsRegister(varsRegister);         stackMemoryView.update(stackMemorySection, stackBase);         methodAreaMemoryView.updateProgramCounter(pcRegister - methodAreaBase, methodAreaMemorySection);         stackMemoryView.clearPointers();         stackMemoryView.updatePointer((varsRegister - stackBase) / 4, StringTable.varsPointer);         stackMemoryView.updatePointer((frameRegister - stackBase) / 4, StringTable.framePointer);         stackMemoryView.updatePointer((optopRegister - stackBase) / 4, StringTable.optopPointer);         int nextOpCode = methodAreaMemorySection.getAtAddress(pcRegister);         switch (nextOpCode) {         case OpCode.AALOAD:             simulationController.setExplanationText(StringTable.aaloadText);             break;         case OpCode.ALOAD_0:             simulationController.setExplanationText(StringTable.aload_0Text);             break;         case OpCode.ASTORE_0:             simulationController.setExplanationText(StringTable.astore_0Text);             break;         case OpCode.BIPUSH:             simulationController.setExplanationText(StringTable.bipushText);             break;         case OpCode.BREAKPOINT:             simulationController.setExplanationText(StringTable.breakpointText);             break;         case OpCode.FCONST_0:             simulationController.setExplanationText(StringTable.fconst_0Text);             break;         case OpCode.FCONST_2:             simulationController.setExplanationText(StringTable.fconst_2Text);             break;         case OpCode.FLOAD_0:             simulationController.setExplanationText(StringTable.fload_0Text);             break;         case OpCode.FMUL:             simulationController.setExplanationText(StringTable.fmulText);             break;         case OpCode.FSTORE_0:             simulationController.setExplanationText(StringTable.fstore_0Text);             break;         case OpCode.FSUB:             simulationController.setExplanationText(StringTable.fsubText);             break;         case OpCode.GOTO:             simulationController.setExplanationText(StringTable.gotoText);             break;         case OpCode.IADD:             simulationController.setExplanationText(StringTable.iaddText);             break;         case OpCode.IAND:             simulationController.setExplanationText(StringTable.iandText);             break;         case OpCode.IASTORE:             simulationController.setExplanationText(StringTable.iastoreText);             break;         case OpCode.ICONST_M1:             simulationController.setExplanationText(StringTable.iconst_m1Text);             break;         case OpCode.ICONST_0:             simulationController.setExplanationText(StringTable.iconst_0Text);             break;         case OpCode.ICONST_1:             simulationController.setExplanationText(StringTable.iconst_1Text);             break;         case OpCode.ICONST_2:             simulationController.setExplanationText(StringTable.iconst_2Text);             break;         case OpCode.ICONST_3:             simulationController.setExplanationText(StringTable.iconst_3Text);             break;         case OpCode.ICONST_4:             simulationController.setExplanationText(StringTable.iconst_4Text);             break;         case OpCode.ICONST_5:             simulationController.setExplanationText(StringTable.iconst_5Text);             break;         case OpCode.IF_ICMPLT:             simulationController.setExplanationText(StringTable.if_icmpltText);             break;         case OpCode.IFNE:             simulationController.setExplanationText(StringTable.ifneText);             break;         case OpCode.IINC:             simulationController.setExplanationText(StringTable.iincText);             break;         case OpCode.ILOAD_0:             simulationController.setExplanationText(StringTable.iload_0Text);             break;         case OpCode.ILOAD_1:             simulationController.setExplanationText(StringTable.iload_1Text);             break;         case OpCode.ILOAD_2:             simulationController.setExplanationText(StringTable.iload_2Text);             break;         case OpCode.ILOAD_3:             simulationController.setExplanationText(StringTable.iload_3Text);             break;         case OpCode.IMUL:             simulationController.setExplanationText(StringTable.imulText);             break;         case OpCode.INT2BYTE:             simulationController.setExplanationText(StringTable.int2byteText);             break;         case OpCode.IOR:             simulationController.setExplanationText(StringTable.iorText);             break;         case OpCode.ISHL:             simulationController.setExplanationText(StringTable.ishlText);             break;         case OpCode.ISTORE_0:             simulationController.setExplanationText(StringTable.istore_0Text);             break;         case OpCode.ISTORE_1:             simulationController.setExplanationText(StringTable.istore_1Text);             break;         case OpCode.ISTORE_2:             simulationController.setExplanationText(StringTable.istore_2Text);             break;         case OpCode.ISTORE_3:             simulationController.setExplanationText(StringTable.istore_3Text);             break;         case OpCode.IXOR:             simulationController.setExplanationText(StringTable.ixorText);             break;         case OpCode.MULTIANEWARRAY:             simulationController.setExplanationText(StringTable.multianewarrayText);             break;         default:             simulationController.setExplanationText("");             break;         }     }     // Make pretty border around entire applet panel     public Insets insets() {         return new Insets(5, 5, 5, 5);     }     public void stop() {         if (runner != null) {             runner.stop();             runner = null;         }     }     public void run() {         while (true) {             ExecuteNextInstruction();             UpdateStateDisplay();             try {                 Thread.sleep(millisecondDelayBetweenSteps);             }             catch (InterruptedException e) {             }         }     }     void executeAaload() {         // Pop array index.         optopRegister -= 4;         int index = stackMemorySection.getAtAddress(optopRegister);         stackMemorySection.setLogicalValueAtAddress(optopRegister, "");         // Pop reference to array of object references.         // Cast generic object reference to a reference to an array of objects. This         // will cause the JVM to do a checkcast instruction to make sure this is a         // valid operation. An exception will be thrown if I've got any other kind         // of array or object reference. Once this succeeds, I can use the arrayRef         // as an array to get the index'th object reference and push it.         optopRegister -= 4;         Object objRef = stackMemorySection.getObjectAtAddress(optopRegister);         Object[] arrayRef = (Object[]) objRef;         // Push the object reference at arrayRef[index].         stackMemorySection.setObjectAtAddress(optopRegister, arrayRef[index]);         stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.objectReference);         optopRegister += 4;         ++pcRegister;     }     void executeAload_n(int locVar) {         Object objRef = stackMemorySection.getObjectAtAddress(varsRegister + (4 * locVar));         stackMemorySection.setObjectAtAddress(optopRegister, objRef);         stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.objectReference);         optopRegister += 4;         ++pcRegister;     }     void executeAstore_n(int locVar) {         optopRegister -= 4;         Object objRef = stackMemorySection.getObjectAtAddress(optopRegister);         stackMemorySection.setLogicalValueAtAddress(optopRegister, "");         stackMemorySection.setObjectAtAddress(varsRegister + (4 * locVar), objRef);         stackMemorySection.setLogicalValueAtAddress(varsRegister + (4 * locVar), StringTable.objectReference);         ++pcRegister;     }     void executeIastore() {         // Pop int value.         optopRegister -= 4;         int value = stackMemorySection.getAtAddress(optopRegister);         stackMemorySection.setLogicalValueAtAddress(optopRegister, "");         // Pop index.         optopRegister -= 4;         int index = stackMemorySection.getAtAddress(optopRegister);         stackMemorySection.setLogicalValueAtAddress(optopRegister, "");         // Pop reference to an array of integers. Must cast the generic object         // reference to a reference to an array of integers, then use that         // to assign arrayRef[index] = value.         optopRegister -= 4;         Object objRef = stackMemorySection.getObjectAtAddress(optopRegister);         stackMemorySection.setLogicalValueAtAddress(optopRegister, "");         int[] arrayRef = (int[]) objRef;         arrayRef[index] = value;         ++pcRegister;     }     void executeMultianewarray() {         int indexbyte1 = methodAreaMemorySection.getAtAddress(pcRegister + 1);         int indexbyte0 = methodAreaMemorySection.getAtAddress(pcRegister + 2);         int dim = methodAreaMemorySection.getAtAddress(pcRegister + 3);         if (dim < 1) {             // this is an exception             return;         }         // Fill an array with the sizes of the various arrays. The sizes go into the         // array in the order in which they appear in the declaration, left to right.         // This was the same order in which they were pushed onto the stack. Therefore,         // the first element is assigned the value most buried (furthest down) in the         // stack.         int[] size = new int[dim];         for (int i = dim - 1; i >= 0; --i) {             optopRegister -= 4;             size[i] = stackMemorySection.getAtAddress(optopRegister);             stackMemorySection.setLogicalValueAtAddress(optopRegister, "");         }         // This time around, I'll just assume it's an array of ints. In the future, I'll         // need to check the constant pool and pass down the type.         Object result = createMultiDimArray(size);         stackMemorySection.setObjectAtAddress(optopRegister, result);         stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.objectReference);         optopRegister += 4;     }     Object createMultiDimArray(int[] size) {         Object result;         if (size.length == 1) {             result = new int[size[0]];         }         else {             // Create and initialize an array of arrays             Object[] arrayOfArrays = new Object[size[0]];             result = arrayOfArrays;             // As soon as a size of zero is hit for the next array, we are done. This             // will be the case if some of the square brackets were left empty in             // the declaration, as in "new int[5][4][][]," in which the third and fourth             // sizes will be zero.             if (size[1] != 0) {                 // Create and initialize an array of sizes to be passed to a recursive call                 // to createMultiDimArray(). This array is identical to the array passed                 // to this function with the first element clipped off.                 int[] nextSize = new int[size.length - 1];                 for (int i = 1; i < size.length; ++i) {                     nextSize[i - 1] = size[i];                 }                 // Call this function recursively to create initialize this array                 // of array with the sub-arrays.                 for (int i = 0; i < size[0]; ++i) {                     arrayOfArrays[i] = createMultiDimArray(nextSize);                 }             }         }         return result;     } } // I used this class because I can't seem to set the background color of // a label.  I only want a label, but I want the backgound to be gray. class ColoredLabel extends Panel {     private Label theLabel;     ColoredLabel(String label, int alignment, Color color) {         setLayout(new GridLayout(1,1));         setBackground(color);         theLabel = new Label(label, alignment);         add(theLabel);     }     public void setLabelText(String s) {         theLabel.setText(s);     }     public Insets insets() {         return new Insets(0, 0, 0, 0);     } } class ControlPanel extends Panel {     private ColoredLabel explanationLabel;     private GrayButton stepButton = new GrayButton(StringTable.step);     private GrayButton resetButton = new GrayButton(StringTable.reset);     private GrayButton runButton = new GrayButton(StringTable.run);     private GrayButton stopButton = new GrayButton(StringTable.stop);     ControlPanel() {         setLayout(new BorderLayout(5, 5));         Panel leftButtonPanel = new Panel();         leftButtonPanel.setLayout(new GridLayout(2,2,5,5));         leftButtonPanel.add(stepButton);         resetButton.disable();         leftButtonPanel.add(runButton);         leftButtonPanel.add(resetButton);         leftButtonPanel.add(stopButton);         stopButton.disable();         explanationLabel = new ColoredLabel("This is where the explanation goes...",             Label.CENTER, Color.lightGray);         explanationLabel.setBackground(SimData.explanationLabel);         Font plainFont = new Font("TimesRoman", Font.ITALIC, 12);         explanationLabel.setFont(plainFont);         add("West", leftButtonPanel);         add("Center", explanationLabel);     }     public void setExplanationText(String explanation) {         explanationLabel.setLabelText(explanation);     }     public Button getStepButton() {         return stepButton;     }     public Button getResetButton() {         return resetButton;     }     public Button getRunButton() {         return runButton;     }     public Button getStopButton() {         return stopButton;     }     public Insets insets() {         // top, left, bottom, right         return new Insets(0, 0, 0, 0);     } } class GrayButton extends Button {     GrayButton(String label) {         super(label);         setBackground(Color.lightGray);     } } // GridSnapLayout lays out components in a grid that can have columns of // varying width. This is not a very general purpose layout manager. It // solves the specific problem of getting all the information I want to display about // the stack and method areas in a nice grid. Because some columns of info need // more room than others, and space is limited on a web page, I needed to be // able to specify varying widths of columns in a grid. class GridSnapLayout implements LayoutManager {     // rows and cols are the number of rows and columns of the grid upon     // which the components are placed. Components are always one row     // in height, but may be more than one column in width. The number     // of columns width of each component is stored in hComponentCellWidths.     // The array length of hComponentCellWidths indicates the number of     // components that will appear on each row.     private int rows;     private int cols;     private int[] hComponentCellWidths;     public GridSnapLayout(int rows, int cols, int[] hComponentCellWidths) {       this.rows = rows;       this.cols = cols;       this.hComponentCellWidths = hComponentCellWidths;     }     public void addLayoutComponent(String name, Component comp) {     }     public void removeLayoutComponent(Component comp) {     }     // Calculate preferred size as if each component were taking an equal     // share of the width of a row.     public Dimension preferredLayoutSize(Container parent) {       int rowCount = rows;       int colCount = cols;       Insets parentInsets = parent.insets();       int componentCount = parent.countComponents();       if (rowCount > 0) {           colCount = (componentCount + rowCount - 1) / rowCount;       } else {           rowCount = (componentCount + colCount - 1) / colCount;       }         // Find the maximum preferred width and the maximum preferred height         // of any component.       int w = 0;       int h = 0;       for (int i = 0; i < componentCount; i++) {           Component comp = parent.getComponent(i);           Dimension d = comp.preferredSize();           if (w < d.width) {             w = d.width;           }           if (h < d.height) {             h = d.height;           }       }       // Return the maximum preferred component width and height times the number       // of columns and rows, respectively, plus any insets in the parent.       return new Dimension(parentInsets.left + parentInsets.right + colCount*w,           parentInsets.top + parentInsets.bottom + rowCount*h);     }     // Calculate minimum size as if each component were taking an equal     // share of the width of a row.     public Dimension minimumLayoutSize(Container parent) {       Insets parentInsets = parent.insets();       int componentCount = parent.countComponents();       int rowCount = rows;       int colCount = cols;       if (rowCount > 0) {           colCount = (componentCount + rowCount - 1) / rowCount;       } else {           rowCount = (componentCount + colCount - 1) / colCount;       }         // Find the maximum "minimum width" and the maximum "minimum height"         // of any component.       int w = 0;       int h = 0;       for (int i = 0; i < componentCount; i++) {           Component comp = parent.getComponent(i);           Dimension d = comp.minimumSize();           if (w < d.width) {             w = d.width;           }           if (h < d.height) {             h = d.height;           }       }       // Return the maximum "minimum component width and height" times the number       // of columns and rows, respectively, plus any insets in the parent.       return new Dimension(parentInsets.left + parentInsets.right + colCount*w,           parentInsets.top + parentInsets.bottom + rowCount*h);     }     // Layout the container such that the widths of columns correspond     // to the number of columns in that components hComponentCellWidth     // array element. For example, if the     public void layoutContainer(Container parent) {       int rowCount = rows;       int colCount = hComponentCellWidths.length;       Insets parentInsets = parent.insets();       int componentCount = parent.countComponents();       if (componentCount == 0) {           return;       }         // Calculate the width and height of each grid cell. The height will         // be the height of each component, but the width may not. The width         // of a component will be some multiple of a grid cell width. The         // number of grid cells for each component is defined by the         // hComponentCellWidths array. w is width of each grid cell. h is         // height of each grid cell.       Dimension parentDim = parent.size();       int w = parentDim.width - (parentInsets.left + parentInsets.right);       int h = parentDim.height - (parentInsets.top + parentInsets.bottom);       w /= cols;       h /= rowCount;         // For each row and column of components (not grid cells) position         // the component.       for (int c = 0, x = parentInsets.left ; c < colCount ; c++) {           for (int r = 0, y = parentInsets.top ; r < rowCount ; r++) {             int i = r * colCount + c;             if (i < componentCount) {                 parent.getComponent(i).reshape(x, y, w * hComponentCellWidths[c], h);             }             y += h;           }           x += (w * hComponentCellWidths[c]);       }     } } class HexString {     private final String hexChar = "0123456789abcdef";     private StringBuffer buf = new StringBuffer();     void Convert(int val, int maxNibblesToConvert) {         buf.setLength(0);         int v = val;         for (int i = 0; i < maxNibblesToConvert; ++i) {             if (v == 0) {                 if (i == 0) {                     buf.insert(0, '0');                 }                 break;             }             // Get lowest nibble             int remainder = v & 0xf;             // Convert nibble to a character and insert it into the beginning of the string             buf.insert(0, hexChar.charAt(remainder));             // Shift the int to the right four bits             v >>>= 4;         }     }     HexString(int val, int minWidth) {         Convert(val, minWidth);         int charsNeeded = minWidth - buf.length();         for (int i = 0; i < charsNeeded; ++i) {             buf.insert(0, '0');         }     }     public String getString() {         return buf.toString();     } } class LabeledRegister extends Panel {     private ColoredLabel registerContents;     LabeledRegister(String labelText) {         setLayout(new BorderLayout(5,5));         registerContents = new ColoredLabel("00000000", Label.CENTER, Color.lightGray);         registerContents.setFont(new Font("TimesRoman", Font.PLAIN, 11));         Label title = new Label(labelText, Label.RIGHT);         title.setFont(new Font("Helvetica", Font.ITALIC, 11));         add("East", registerContents);         add("Center", title);     }     public void setRegister(int val) {         HexString hexString = new HexString(val, 8);         registerContents.setLabelText(hexString.getString());     }     public Insets insets() {         return new Insets(0, 0, 0, 0);     } } // MemorySection is just used for the method area in this applet. This implements // the functionality of the method area and has nothing to do with the UI. class MemorySection {     private int[] memory;     private int baseAddress;     private String[] logicalValueString;     MemorySection(int base, int size) {         baseAddress = base;         memory = new int[size];         logicalValueString = new String[size];         for (int i = 0; i < size; ++i) {             logicalValueString[i] = new String();         }     }     int getBaseAddress() {         return baseAddress;     }     public int getAtAddress(int address) {         return memory[address - baseAddress];     }     public String getLogicalValueAtAddress(int address) {         return logicalValueString[address - baseAddress];     }     public void setAtAddress(int address, int value) {         memory[address - baseAddress] = value;     }     public void setLogicalValueAtAddress(int address, String s) {         logicalValueString[address - baseAddress] = s;     }     int getSize() {         return memory.length;     } } // MemoryView is just used for the method area in this applet.  It implements the // UI of the method area. class MemoryView extends Panel {     private final int memoryLocationsVisibleCount = SimData.methodAreaMemoryLocationsVisibleCount;     private Label[] pointer = new Label[memoryLocationsVisibleCount];     private Label[] address = new Label[memoryLocationsVisibleCount];     private Label[] byteValue = new Label[memoryLocationsVisibleCount];     private Label[] logicalValue = new Label[memoryLocationsVisibleCount];     private int firstVisibleRow;     private int currentProgramCounterRow;     MemoryView(int methodAreaMemSectionSize) {         int[] hComponentCellWidths = new int[4];         hComponentCellWidths[0] = 2;         hComponentCellWidths[1] = 2;         hComponentCellWidths[2] = 2;         hComponentCellWidths[3] = 3;         setLayout(new GridSnapLayout(memoryLocationsVisibleCount, 9, hComponentCellWidths));         setBackground(Color.lightGray);         Font plainFont = new Font("TimesRoman", Font.PLAIN, 11);         setFont(plainFont);         Font italicFont = new Font("TimesRoman", Font.ITALIC, 11);         for (int i = 0; i < memoryLocationsVisibleCount; ++i) {             pointer[i] = new Label("", Label.RIGHT);             pointer[i].setFont(italicFont);             add(pointer[i]);             address[i] = new Label("", Label.CENTER);             add(address[i]);             byteValue[i] = new Label("", Label.CENTER);             add(byteValue[i]);             logicalValue[i] = new Label("", Label.LEFT);             add(logicalValue[i]);         }     }     public void setAt(int i, int addressValue, int value, String logicalValueStr) {         HexString addressValueHexString = new HexString(addressValue, 8);         HexString byteValueHexString = new HexString(value, 2);         address[i].setText(addressValueHexString.getString());         byteValue[i].setText(byteValueHexString.getString());         logicalValue[i].setText(logicalValueStr);     }     public void update(MemorySection memorySection, int initialAddress){         for (int i = 0; i < memoryLocationsVisibleCount; ++i) {             int theByte = memorySection.getAtAddress(initialAddress + i);             String logicalValue = memorySection.getLogicalValueAtAddress(                 initialAddress + i);             setAt(i, initialAddress + i, theByte, logicalValue);         }     }     public void clearPointers() {         for (int i = 0; i < memoryLocationsVisibleCount; ++i) {             pointer[i].setText("");         }     }     public void updateProgramCounter(int i, MemorySection memorySection) {         pointer[currentProgramCounterRow - firstVisibleRow].setText("");         if (i - firstVisibleRow >= memoryLocationsVisibleCount) {             firstVisibleRow = i;             if (firstVisibleRow > memorySection.getSize() - memoryLocationsVisibleCount) {                 firstVisibleRow = memorySection.getSize() - memoryLocationsVisibleCount;             }             update(memorySection, memorySection.getBaseAddress() + firstVisibleRow);         }         else if (i < firstVisibleRow) {             firstVisibleRow = i;             update(memorySection, memorySection.getBaseAddress() + firstVisibleRow);         }         pointer[i - firstVisibleRow].setText("pc >");         currentProgramCounterRow = i;     }     public Insets insets() {         // top, left, bottom, right         return new Insets(0, 0, 0, 0);     } } class MemoryViewTitlePanel extends Panel {     MemoryViewTitlePanel () {         int[] hComponentCellWidths = new int[4];         hComponentCellWidths[0] = 2;         hComponentCellWidths[1] = 2;         hComponentCellWidths[2] = 2;         hComponentCellWidths[3] = 3;         setLayout(new GridSnapLayout(1, 9, hComponentCellWidths));         setFont(new Font("Helvetica", Font.ITALIC, 11));         add(new Label("", Label.CENTER));         add(new Label(StringTable.address, Label.CENTER));         add(new Label(StringTable.bytecodes, Label.CENTER));         add(new Label(StringTable.mnemonics, Label.LEFT));     }     public Insets insets() {         // top, left, bottom, right         return new Insets(0, 0, 0, 0);     } } class MemoryViewWithTitles extends Panel {     private MemoryView memoryView;     MemoryViewWithTitles(int methodAreaMemorySectionSize) {         memoryView = new MemoryView(methodAreaMemorySectionSize);         setLayout(new BorderLayout());         add("North", new MemoryViewTitlePanel());         add("Center", memoryView);     }     public MemoryView getMemoryViewReference(){         return memoryView;     }     public Insets insets() {         // top, left, bottom, right         return new Insets(0, 0, 0, 0);     } } class MethodAreaPanel extends Panel {     private Label title;     private MemoryViewWithTitles memoryView;     MethodAreaPanel(int methodAreaMemorySectionSize) {         memoryView = new MemoryViewWithTitles(methodAreaMemorySectionSize);         setLayout(new BorderLayout());         title = new Label("Method Area", Label.CENTER);         title.setFont(new Font("Helvetica", Font.BOLD, 11));         add("North", title);         add("Center", memoryView);     }     public MemoryView getMemoryViewReference() {         return memoryView.getMemoryViewReference();     }     public Insets insets() {         return new Insets(5, 5, 5, 5);     } } class OpCode {     final static int NOP = 0;     final static int ACONST_NULL = 1;     final static int ICONST_M1 = 2;     final static int ICONST_0 = 3;     final static int ICONST_1 = 4;     final static int ICONST_2 = 5;     final static int ICONST_3 = 6;     final static int ICONST_4 = 7;     final static int ICONST_5 = 8;     final static int LCONST_0 = 9;     final static int LCONST_1 = 10;     final static int FCONST_0 = 11;     final static int FCONST_1 = 12;     final static int FCONST_2 = 13;     final static int DCONST_0 = 14;     final static int DCONST_1 = 15;     final static int BIPUSH = 16;     final static int SIPUSH = 17;     final static int LDC1 = 18;     final static int LDC2 = 19;     final static int LDC2W = 20;     final static int ILOAD = 21;     final static int LLOAD = 22;     final static int FLOAD = 23;     final static int DLOAD = 24;     final static int ALOAD = 25;     final static int ILOAD_0 = 26;     final static int ILOAD_1 = 27;     final static int ILOAD_2 = 28;     final static int ILOAD_3 = 29;     final static int LLOAD_0 = 30;     final static int LLOAD_1 = 31;     final static int LLOAD_2 = 32;     final static int LLOAD_3 = 33;     final static int FLOAD_0 = 34;     final static int FLOAD_1 = 35;     final static int FLOAD_2 = 36;     final static int FLOAD_3 = 37;     final static int DLOAD_0 = 38;     final static int DLOAD_1 = 39;     final static int DLOAD_2 = 40;     final static int DLOAD_3 = 41;     final static int ALOAD_0 = 42;     final static int ALOAD_1 = 43;     final static int ALOAD_2 = 44;     final static int ALOAD_3 = 45;     final static int IALOAD = 46;     final static int LALOAD = 47;     final static int FALOAD = 48;     final static int DALOAD = 49;     final static int AALOAD = 50;     final static int BALOAD = 51;     final static int CALOAD = 52;     final static int SALOAD = 53;     final static int ISTORE = 54;     final static int LSTORE = 55;     final static int FSTORE = 56;     final static int DSTORE = 57;     final static int ASTORE = 58;     final static int ISTORE_0 = 59;     final static int ISTORE_1 = 60;     final static int ISTORE_2 = 61;     final static int ISTORE_3 = 62;     final static int LSTORE_0 = 63;     final static int LSTORE_1 = 64;     final static int LSTORE_2 = 65;     final static int LSTORE_3 = 66;     final static int FSTORE_0 = 67;     final static int FSTORE_1 = 68;     final static int FSTORE_2 = 69;     final static int FSTORE_3 = 70;     final static int DSTORE_0 = 71;     final static int DSTORE_1 = 72;     final static int DSTORE_2 = 73;     final static int DSTORE_3 = 74;     final static int ASTORE_0 = 75;     final static int ASTORE_1 = 76;     final static int ASTORE_2 = 77;     final static int ASTORE_3 = 78;     final static int IASTORE = 79;     final static int LASTORE = 80;     final static int FASTORE = 81;     final static int DASTORE = 82;     final static int AASTORE = 83;     final static int BASTORE = 84;     final static int CASTORE = 85;     final static int SASTORE = 86;     final static int POP = 87;     final static int POP2 = 88;     final static int DUP = 89;     final static int DUP_X1 = 90;     final static int DUP_X2 = 91;     final static int DUP2 = 92;     final static int DUP2_X1 = 93;     final static int DUP2_X2 = 94;     final static int SWAP = 95;     final static int IADD = 96;     final static int LADD = 97;     final static int FADD = 98;     final static int DADD = 99;     final static int ISUB = 100;     final static int LSUB = 101;     final static int FSUB = 102;     final static int DSUB = 103;     final static int IMUL = 104;     final static int LMUL = 105;     final static int FMUL = 106;     final static int DMUL = 107;     final static int IDIV = 108;     final static int LDIV = 109;     final static int FDIV = 110;     final static int DDIV = 111;     final static int IREM = 112;     final static int LREM = 113;     final static int FREM = 114;     final static int DREM = 115;     final static int INEG = 116;     final static int LNEG = 117;     final static int FNEG = 118;     final static int DNEG = 119;     final static int ISHL = 120;     final static int LSHL = 121;     final static int ISHR = 122;     final static int LSHR = 123;     final static int IUSHR = 124;     final static int LUSHR = 125;     final static int IAND = 126;     final static int LAND = 127;     final static int IOR = 128;     final static int LOR = 129;     final static int IXOR = 130;     final static int LXOR = 131;     final static int IINC = 132;     final static int I2L = 133;     final static int I2F = 134;     final static int I2D = 135;     final static int L2I = 136;     final static int L2F = 137;     final static int L2D = 138;     final static int F2I = 139;     final static int F2L = 140;     final static int F2D = 141;     final static int D2I = 142;     final static int D2L = 143;     final static int D2F = 144;     final static int INT2BYTE = 145;     final static int INT2CHAR = 146;     final static int INT2SHORT = 147;     final static int LCMP = 148;     final static int FCMPL = 149;     final static int FCMPG = 150;     final static int DCMPL = 151;     final static int DCMPG = 152;     final static int IFEQ = 153;     final static int IFNE = 154;     final static int IFLT = 155;     final static int IFGE = 156;     final static int IFGT = 157;     final static int IFLE = 158;     final static int IF_ICMPEQ = 159;     final static int IF_ICMPNE = 160;     final static int IF_ICMPLT = 161;     final static int IF_ICMPGT = 163;     final static int IF_ICMPLE = 164;     final static int IF_ICMPGE = 162;     final static int IF_ACMPEQ = 165;     final static int IF_ACMPNE = 166;     final static int GOTO = 167;     final static int JSR = 168;     final static int RET = 169;     final static int TABLESWITCH = 170;     final static int LOOKUPSWITCH = 171;     final static int IRETURN = 172;     final static int LRETURN = 173;     final static int FRETURN = 174;     final static int DRETURN = 175;     final static int ARETURN = 176;     final static int RETURN = 177;     final static int INVOKEVIRTUAL = 182;     final static int INVOKENONVIRTUAL = 183;     final static int INVOKESTATIC = 184;     final static int INVOKEINTERFACE = 185;     final static int NEW = 187;     final static int NEWARRAY = 188;     final static int ANEWARRAY = 189;     final static int ARRAYLENGTH = 190;     final static int ATHROW = 191;     final static int CHECKCAST = 192;     final static int INSTANCEOF = 193;     final static int MONITORENTER = 194;     final static int MONITOREXIT = 195;     final static int WIDE = 196;     final static int MULTIANEWARRAY = 197;     final static int IFNULL = 198;     final static int IFNONNULL = 199;     final static int GOTO_W = 200;     final static int JSR_W = 201;     final static int BREAKPOINT = 202;     final static int RET_W = 209; } class RegisterPanel extends Panel {     private LabeledRegister pcRegister;     private LabeledRegister optopRegister;     private LabeledRegister frameRegister;     private LabeledRegister varsRegister;     RegisterPanel() {         setLayout(new BorderLayout(5,5));         pcRegister = new LabeledRegister(StringTable.pc);         optopRegister = new LabeledRegister(StringTable.optop);         frameRegister = new LabeledRegister(StringTable.frame);         varsRegister = new LabeledRegister(StringTable.vars);         setBackground(SimData.registersAreaColor);         Panel labeledRegisterPanel = new Panel();         labeledRegisterPanel.setLayout(new GridLayout(1, 4, 5, 5));         labeledRegisterPanel.add(pcRegister);         labeledRegisterPanel.add(optopRegister);         labeledRegisterPanel.add(frameRegister);         labeledRegisterPanel.add(varsRegister);         Label title = new Label(StringTable.Registers, Label.CENTER);         title.setFont(new Font("Helvetica", Font.BOLD, 11));         add("West", title);         add("Center", labeledRegisterPanel);     }     public void setPcRegister(int val) {         pcRegister.setRegister(val);     }     public void setOptopRegister(int val) {         optopRegister.setRegister(val);     }     public void setFrameRegister(int val) {         frameRegister.setRegister(val);     }     public void setVarsRegister(int val) {         varsRegister.setRegister(val);     }     public Insets insets() {         // top, left, bottom, right         return new Insets(5, 5, 5, 5);     } } class RepeaterButton extends GrayButton {     RepeaterButton(String label) {         super(label);     } } // SimData is like a personality module for the JVMSimulator. It contains all // the data that is unique to this particular simulation applet. class SimData {     public final static String appletTitle = "THREE DIMENSIONAL ARRAY";     // stackSize, localsSize, and argsSize define the size of the stack for     // one method, which each simulator executes. These three sizes vary for     // each method and can be found for a method by running javap -v on the     // class file. The execEnvSize is constant for every method and only     // depends on how the JVM was implemented.     static final int stackSize = 4;     static final int localsSize = 4;     static final int argsSize = 0;     static final int execEnvSize = 4;     // methodArea sizes are based on the length of the bytecode stream for     // this method.     static final int methodAreaMemorySectionSize = 60;     static final int methodAreaMemoryLocationsVisibleCount = 13;     // stack sizes are based on the sizes of each portion of the stack (local     // variables, execution environment, and operands) that are defined above     // for the method simulated by this applet. One is added to stackMemorySectionSize     // because this JVM implementation has the optop register pointing to the     // next available slot in the stack instead of the current top. This means     // that when the operand stack is full, I still need one more slot to show     // the location that is pointed to by the optop register, even though we     // know nothing will ever be pushed there by this method.     static final int stackMemorySectionSize = stackSize + localsSize + argsSize + execEnvSize + 1;     static final int stackMemoryLocationsVisibleCount = stackMemorySectionSize;     static final int frameOffset = (4 * localsSize) + (4 * argsSize); // 4 bytes for each local variable     static final int optopOffset = frameOffset + (4 * execEnvSize); // 4 bytes for each loc var & exec env slot     static int[] theProgram = {         OpCode.ICONST_5,         OpCode.ICONST_4,         OpCode.ICONST_3,         OpCode.MULTIANEWARRAY, (byte) 0x00, (byte) 0x02, (byte) 0x03,         OpCode.ASTORE_0,         OpCode.ICONST_0,         OpCode.ISTORE_1,         OpCode.GOTO, (byte) 0x00, (byte) 0x2c,         OpCode.ICONST_0,         OpCode.ISTORE_2,         OpCode.GOTO, (byte) 0x00, (byte) 0x1f,         OpCode.ICONST_0,         OpCode.ISTORE_3,         OpCode.GOTO, (byte) 0x00, (byte) 0x12,         OpCode.ALOAD_0,         OpCode.ILOAD_1,         OpCode.AALOAD,         OpCode.ILOAD_2,         OpCode.AALOAD,         OpCode.ILOAD_3,         OpCode.ILOAD_1,         OpCode.ILOAD_2,         OpCode.IADD,         OpCode.ILOAD_3,         OpCode.IADD,         OpCode.IASTORE,         OpCode.IINC, (byte) 0x03, (byte) 0x01,         OpCode.ILOAD_3,         OpCode.ICONST_3,         OpCode.IF_ICMPLT, (byte) 0xff, (byte) 0xef,         OpCode.IINC, (byte) 0x02, (byte) 0x01,         OpCode.ILOAD_2,         OpCode.ICONST_4,         OpCode.IF_ICMPLT, (byte) 0xff, (byte) 0xe2,         OpCode.IINC, (byte) 0x01, (byte) 0x01,         OpCode.ILOAD_1,         OpCode.ICONST_5,         OpCode.IF_ICMPLT, (byte) 0xff, (byte) 0xd5,         OpCode.BREAKPOINT     };     static String[] byteCodeMnemonics = {         "iconst_5",         "iconst_4",         "iconst_3",         "multianewarray 2 3", "", "", "",         "astore_0",         "iconst_0",         "istore_1",         "goto +44", "", "",         "iconst_0",         "istore_2",         "goto +31", "", "",         "iconst_0",         "istore_3",         "goto +18", "", "",         "aload_0",         "iload_1",         "aaload",         "iload_2",         "aaload",         "iload_3",         "iload_1",         "iload_2",         "iadd",         "iload_3",         "iadd",         "iastore",         "iinc 3 1", "", "",         "iload_3",         "iconst_3",         "if_icmplt -17", "", "",         "iinc 2 1", "", "",         "iload_2",         "iconst_4",         "if_icmplt -30", "", "",         "iinc 1 1", "", "",         "iload_1",         "iconst_5",         "if_icmplt -43", "", "",         "breakpoint"     };     static final Color appletBackgroundColor = Color.blue;     static final Color registersAreaColor = Color.cyan;     static final Color stackAreaColor = Color.cyan;     static final Color methodAreaColor = Color.cyan;     static final Color titleColor = Color.green;     static final Color explanationLabel = Color.green; } // StackMemorySection is just used for the stack in this applet. This implements // the functionality of the stack and has nothing to do with the UI. A separate // array is used for primitive types and object references because there is no // way to convert between an object reference and a primitive type (that would // be a pointer.) The int array (memory) is used to store types boolean, byte, // char, short, int, long, float, and double. The object reference array (objectMemory) // is used to store references to objects and arrays. class StackMemorySection {     private int[] memory;     private Object[] objectMemory;     private int baseAddress;     private String[] logicalValueString;     StackMemorySection(int base, int size) {         baseAddress = base;         memory = new int[size];         objectMemory = new Object[size];         logicalValueString = new String[size];         for (int i = 0; i < size; ++i) {             memory[i] = 0;             logicalValueString[i] = new String();         }     }     public int getAtAddress(int address) {         return memory[(address - baseAddress) / 4];     }     public Object getObjectAtAddress(int address) {         return objectMemory[(address - baseAddress) / 4];     }     public String getLogicalValueAtAddress(int address) {         return logicalValueString[(address - baseAddress) / 4];     }     public void setAtAddress(int address, int value) {         memory[(address - baseAddress) / 4] = value;     }     public void setObjectAtAddress(int address, Object value) {         objectMemory[(address - baseAddress) / 4] = value;     }     public void setLogicalValueAtAddress(int address, String s) {         logicalValueString[(address - baseAddress) / 4] = s;     } } // StackMemoryView is just used for the stack in this applet.  It implements the // UI of the stack. class StackMemoryView extends Panel {     private final int memoryLocationsVisibleCount = SimData.stackMemoryLocationsVisibleCount;     private Label[] pointer = new Label[memoryLocationsVisibleCount];     private Label[] address = new Label[memoryLocationsVisibleCount];     private Label[] wordValue = new Label[memoryLocationsVisibleCount];     private Label[] logicalValue = new Label[memoryLocationsVisibleCount];     StackMemoryView () {         int[] hComponentCellWidths = new int[4];         hComponentCellWidths[0] = 2;         hComponentCellWidths[1] = 2;         hComponentCellWidths[2] = 2;         hComponentCellWidths[3] = 3;         setLayout(new GridSnapLayout(memoryLocationsVisibleCount, 9, hComponentCellWidths));         setBackground(Color.lightGray);         Font plainFont = new Font("TimesRoman", Font.PLAIN, 11);         setFont(plainFont);         Font italicFont = new Font("TimesRoman", Font.ITALIC, 11);         for (int i = memoryLocationsVisibleCount - 1; i >= 0; --i) {             pointer[i] = new Label("", Label.RIGHT);             pointer[i].setFont(italicFont);             add(pointer[i]);             address[i] = new Label("", Label.CENTER);             add(address[i]);             wordValue[i] = new Label("", Label.CENTER);             add(wordValue[i]);             logicalValue[i] = new Label("", Label.CENTER);             add(logicalValue[i]);         }     }     public void setAt(int i, int addressValue, int value, String logicalValueString) {         HexString addressValueString = new HexString(addressValue, 8);         HexString wordValueString = new HexString(value, 8);         address[memoryLocationsVisibleCount - 1 - i].setText(addressValueString.getString());         wordValue[memoryLocationsVisibleCount - 1 - i].setText(wordValueString.getString());         logicalValue[memoryLocationsVisibleCount - 1 - i].setText(logicalValueString);     }     public void update(StackMemorySection memorySection, int initialAddress){         for (int i = 0; i < memoryLocationsVisibleCount; ++i) {             int theWord = memorySection.getAtAddress(initialAddress + (i * 4));             String logicalValue = memorySection.getLogicalValueAtAddress(                 initialAddress + (i * 4));             setAt(i, initialAddress + (i * 4), theWord, logicalValue);         }     }     public void clearPointers() {         for (int i = 0; i < memoryLocationsVisibleCount; ++i) {             pointer[i].setText("");         }     }     public void updatePointer(int i, String pointerString) {         pointer[memoryLocationsVisibleCount - 1 - i].setText(pointerString);     }     public Insets insets() {         // top, left, bottom, right         return new Insets(0, 0, 0, 0);     } } class StackMemoryViewTitlePanel extends Panel {     StackMemoryViewTitlePanel () {         int[] hComponentCellWidths = new int[4];         hComponentCellWidths[0] = 2;         hComponentCellWidths[1] = 2;         hComponentCellWidths[2] = 2;         hComponentCellWidths[3] = 3;         setLayout(new GridSnapLayout(1, 9, hComponentCellWidths));         setFont(new Font("Helvetica", Font.ITALIC, 11));         add(new Label("", Label.CENTER));         add(new Label(StringTable.address, Label.CENTER));         add(new Label(StringTable.hexValue, Label.CENTER));         add(new Label(StringTable.value, Label.CENTER));     }     public Insets insets() {         // top, left, bottom, right         return new Insets(0, 0, 0, 0);     } } class StackMemoryViewWithTitles extends Panel {     private StackMemoryView memoryView = new StackMemoryView();     StackMemoryViewWithTitles () {         setLayout(new BorderLayout());         add("North", new StackMemoryViewTitlePanel());         add("Center", memoryView);     }     public StackMemoryView getMemoryViewReference(){         return memoryView;     }     public Insets insets() {         // top, left, bottom, right         return new Insets(0, 0, 0, 0);     } } class StackPanel extends Panel {     private Label title;     private StackMemoryViewWithTitles memoryView = new StackMemoryViewWithTitles();     StackPanel() {         setLayout(new BorderLayout());         title = new Label("Stack", Label.CENTER);         title.setFont(new Font("Helvetica", Font.BOLD, 11));         add("North", title);         add("Center", memoryView);     }     public StackMemoryView getMemoryViewReference() {         return memoryView.getMemoryViewReference();     }     public Insets insets() {         return new Insets(5, 5, 5, 5);     } } class StringTable {     public final static String step = "Step";     public final static String reset = "Reset";     public final static String run = "Run";     public final static String stop = "Stop";     public final static String operand = "operand";     public final static String execEnv = "exec env";     public final static String localVars = "local vars";     public final static String varsPointer = "vars >";     public final static String framePointer = "frame >";     public final static String optopPointer = "optop >";     public final static String address = "address";     public final static String bytecodes = "bytecode";     public final static String mnemonics = "mnemonic";     public final static String hexValue = "hex value";     public final static String value = "value";     public final static String Registers = "Registers";     public final static String pc = "pc";     public final static String optop = "optop";     public final static String frame = "frame";     public final static String vars = "vars";     public final static String objectReference = "object";     public final static String objectRefHexRepresentation = "OBJ REF";     public final static String aaloadText = "aaload will pop an index and array reference and push the object ref at that index of the array.";     public final static String aload_0Text = "aload_0 will push the object ref at local variable 0 onto the stack.";     public final static String astore_0Text = "astore_0 will pop the object ref off the top of the stack and store it in local variable 0.";     public final static String bipushText = "bipush will expand the next byte to an int and push it onto the stack.";     public final static String breakpointText = "breakpoint will stop the simulation.";     public final static String fconst_0Text = "fconst_0 will push float 0.0 onto the stack.";     public final static String fconst_2Text = "fconst_2 will push float 2.0 onto the stack.";     public final static String fload_0Text = "fload_0 will push the float at local variable 0 onto the stack.";     public final static String fmulText = "fmul will pop two floats, multiply them, and push the result.";     public final static String fstore_0Text = "fstore_0 will pop the float off the top of the stack and store it in local variable 0.";     public final static String fsubText = "fsub will pop two floats, subtract them, and push the result.";     public final static String gotoText = "goto will cause a jump to the specified offset.";     public final static String iaddText = "iadd will pop the top two ints off the stack, add them, and push the result back onto the stack.";     public final static String iandText = "iand will pop the top two ints off the stack, bitwise-and them, and push the result back onto the stack.";     public final static String iastoreText = "iastore will pop an int value, an index, and an arrayref and assign arrayref[index] = value.";     public final static String iconst_m1Text = "iconst_m1 will push -1 onto the stack.";     public final static String iconst_0Text = "iconst_0 will push 0 onto the stack.";     public final static String iconst_1Text = "iconst_1 will push 1 onto the stack.";     public final static String iconst_2Text = "iconst_2 will push 2 onto the stack.";     public final static String iconst_3Text = "iconst_3 will push 3 onto the stack.";     public final static String iconst_4Text = "iconst_4 will push 4 onto the stack.";     public final static String iconst_5Text = "iconst_5 will push 5 onto the stack.";     public final static String if_icmpltText = "if_icmplt will branch if the next to topmost int is less than the topmost int.";     public final static String ifneText = "ifne will branch if the topmost int is not equal to zero.";     public final static String iincText = "iinc will increment the specified local variable by the specified amount.";     public final static String iload_0Text = "iload_0 will push the integer at local variable 0 onto the stack.";     public final static String iload_1Text = "iload_1 will push the integer at local variable 1 onto the stack.";     public final static String iload_2Text = "iload_2 will push the integer at local variable 2 onto the stack.";     public final static String iload_3Text = "iload_3 will push the integer at local variable 3 onto the stack.";     public final static String imulText = "imul will pop two integers, multiply them, and push the result.";     public final static String int2byteText = "int2byte will convert the topmost int on the stack to a value valid for the byte type.";     public final static String iorText = "ior will pop the top two ints off the stack, bitwise-or them, and push the result back onto the stack.";     public final static String ishlText = "ishl will shift the next to topmost int to the left by amount indicated by topmost int.";     public final static String istore_0Text = "istore_0 will pop the integer off the top of the stack and store it in local variable 0.";     public final static String istore_1Text = "istore_1 will pop the integer off the top of the stack and store it in local variable 1.";     public final static String istore_2Text = "istore_2 will pop the integer off the top of the stack and store it in local variable 2.";     public final static String istore_3Text = "istore_3 will pop the integer off the top of the stack and store it in local variable 3.";     public final static String ixorText = "ixor will pop the top two ints off the stack, biwise-xor them, and push the result back onto the stack.";     public final static String multianewarrayText = "multianewarray will allocate memory for a new multi-dim array and push reference."; } class ThreeParts extends Panel {     private RegisterPanel registers;     private TwoParts twoParts;     ThreeParts(int methodAreaMemorySectionSize) {         setLayout(new BorderLayout(5, 5));         registers = new RegisterPanel();         twoParts = new TwoParts(methodAreaMemorySectionSize);         add("North", registers);         add("Center", twoParts);     }     StackMemoryView getStackMemoryViewReference() {         return twoParts.getStackMemoryViewReference();     }     MemoryView getMethodAreaMemoryViewReference() {         return twoParts.getMethodAreaMemoryViewReference();     }     RegisterPanel getRegisterPanel() {         return registers;     } } // TwoParts is the panel that contains the Stack and Method Area panels class TwoParts extends Panel {     private StackPanel stack;     private MethodAreaPanel methodArea;     TwoParts(int methodAreaMemorySectionSize) {         setLayout(new GridLayout(1, 2, 5, 5));         stack = new StackPanel();         methodArea = new MethodAreaPanel(methodAreaMemorySectionSize);         stack.setBackground(SimData.stackAreaColor);         methodArea.setBackground(SimData.methodAreaColor);         add(stack);         add(methodArea);     }     public StackMemoryView getStackMemoryViewReference() {         return stack.getMemoryViewReference();     }     public MemoryView getMethodAreaMemoryViewReference() {         return methodArea.getMemoryViewReference();     }     // top, left, bottom, right     // Want a 10 pixel separation between the twoparts and the register panel     // above and the control panel below.     public Insets insets() {         return new Insets(0, 0, 0, 0);     } }