Java tutorial
/******************************************************************** 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. PROJECT: JavaWorld MODULE: Under The Hood FILE: CircleOfSquares.java AUTHOR: Bill Venners, August 1996 DESCRIPTION: This file contains all the code for the java virtual machine simulation applet, named Circle Of Squares, that accompanies the Under The Hood article titled, "Floating Point Arithmetic". As I developed this applet I had every class in a separate file. I combined them in one file here to make it easier to download. *********************************************************************/ 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; public class CircleOfSquares extends java.applet.Applet { // 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 reset button on control panel allows for easy enabling // and // disabling of this button. private Button resetButton; // Vars that implement the Java stack private final int stackBase = 0x33330000; private final int stackMemorySectionSize = 8; private StackMemorySection stackMemorySection = new StackMemorySection(stackBase, 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(ColorTable.appletBackgroundColor); setLayout(new BorderLayout(5, 5)); threeParts = new ThreeParts(SimData.methodAreaMemorySectionSize); simulationController = new ControlPanel(); resetButton = simulationController.getResetButton(); ColoredLabel title = new ColoredLabel(StringTable.appletTitle, Label.CENTER, ColorTable.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)) { resetButton.disable(); ResetState(); UpdateStateDisplay(); } else if (bname.equals(StringTable.step)) { if (!resetButton.isEnabled()) { resetButton.enable(); } ExecuteNextInstruction(); UpdateStateDisplay(); } } 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; float fa, fb, fresult; Float f; int operand0, operand1; int nextOpCode = methodAreaMemorySection.getAtAddress(pcRegister); switch (nextOpCode) { case OpCode.BIPUSH: operand0 = methodAreaMemorySection.getAtAddress(pcRegister + 1); stackMemorySection.setAtAddress(optopRegister, operand0); stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.operand); optopRegister += 4; pcRegister += 2; 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); int 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); optopRegister += 4; ++pcRegister; break; case OpCode.ICONST_M1: stackMemorySection.setAtAddress(optopRegister, -1); stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.operand); optopRegister += 4; ++pcRegister; break; case OpCode.ICONST_0: stackMemorySection.setAtAddress(optopRegister, 0); stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.operand); optopRegister += 4; ++pcRegister; break; case OpCode.ICONST_1: stackMemorySection.setAtAddress(optopRegister, 1); stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.operand); optopRegister += 4; ++pcRegister; break; case OpCode.ICONST_2: stackMemorySection.setAtAddress(optopRegister, 2); stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.operand); optopRegister += 4; ++pcRegister; 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); pcRegister += 3; break; case OpCode.ILOAD_0: a = stackMemorySection.getAtAddress(varsRegister); stackMemorySection.setAtAddress(optopRegister, a); stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.operand); optopRegister += 4; ++pcRegister; break; case OpCode.ILOAD_1: a = stackMemorySection.getAtAddress(varsRegister + 4); stackMemorySection.setAtAddress(optopRegister, a); stackMemorySection.setLogicalValueAtAddress(optopRegister, StringTable.operand); 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); optopRegister += 4; ++pcRegister; break; case OpCode.INT2BYTE: a = stackMemorySection.getAtAddress(optopRegister - 4); a = (byte) a; stackMemorySection.setAtAddress(optopRegister - 4, a); stackMemorySection.setLogicalValueAtAddress(optopRegister - 4, StringTable.operand); ++pcRegister; break; case OpCode.ISTORE_0: optopRegister -= 4; a = stackMemorySection.getAtAddress(optopRegister); stackMemorySection.setLogicalValueAtAddress(optopRegister, ""); stackMemorySection.setAtAddress(varsRegister, a); ++pcRegister; break; case OpCode.ISTORE_1: optopRegister -= 4; a = stackMemorySection.getAtAddress(optopRegister); stackMemorySection.setLogicalValueAtAddress(optopRegister + 4, ""); stackMemorySection.setAtAddress(varsRegister + 4, a); ++pcRegister; 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 < 7; ++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.BIPUSH: simulationController.setExplanationText(StringTable.bipushText); 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.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.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.IMUL: simulationController.setExplanationText(StringTable.imulText); break; case OpCode.INT2BYTE: simulationController.setExplanationText(StringTable.int2byteText); break; case OpCode.ISTORE_0: simulationController.setExplanationText(StringTable.istore_0Text); break; case OpCode.ISTORE_1: simulationController.setExplanationText(StringTable.istore_1Text); break; default: simulationController.setExplanationText(""); break; } } // Make pretty border around entire applet panel public Insets insets() { return new Insets(5, 5, 5, 5); } } // 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 ColorTable { static final Color appletBackgroundColor = Color.blue; static final Color registersAreaColor = Color.magenta; static final Color stackAreaColor = Color.magenta; static final Color methodAreaColor = Color.magenta; static final Color titleColor = Color.cyan; static final Color explanationLabel = Color.cyan; } class ControlPanel extends Panel { private ColoredLabel explanationLabel; private GrayButton resetButton = new GrayButton(StringTable.reset); ControlPanel() { setLayout(new BorderLayout(5, 5)); Panel leftButtonPanel = new Panel(); leftButtonPanel.setLayout(new GridLayout(2, 1, 0, 5)); leftButtonPanel.add(new GrayButton(StringTable.step)); resetButton.disable(); leftButtonPanel.add(resetButton); explanationLabel = new ColoredLabel("This is where the explanation goes...", Label.CENTER, Color.lightGray); explanationLabel.setBackground(ColorTable.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 getResetButton() { return resetButton; } 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) { setLayout(new GridLayout(memoryLocationsVisibleCount, 4)); 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 += 5; 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() { setLayout(new GridLayout(1, 4)); 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.CENTER)); } 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 PanelWithInsets extends Panel { private int top; private int left; private int bottom; private int right; PanelWithInsets(int t, int l, int b, int r) { top = t; left = l; bottom = b; right = r; } PanelWithInsets() { top = 5; left = 5; bottom = 5; right = 5; } public Insets insets() { return new Insets(top, left, bottom, right); } } 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(ColorTable.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); } } class SimData { static final int methodAreaMemorySectionSize = 13; static final int methodAreaMemoryLocationsVisibleCount = 13; static final int frameOffset = 4; static final int optopOffset = 16; static int[] theProgram = { OpCode.FCONST_2, OpCode.FSTORE_0, OpCode.FLOAD_0, OpCode.FLOAD_0, OpCode.FMUL, OpCode.FSTORE_0, OpCode.FCONST_0, OpCode.FLOAD_0, OpCode.FSUB, OpCode.FSTORE_0, OpCode.GOTO, (byte) 0xff, (byte) 0xf8 }; static String[] byteCodeMnemonics = { "fconst_2", "fstore_0", "fload_0", "fload_0", "fmul", "fstore_0", "fconst_0", "fload_0", "fsub", "fstore_0", "goto -17", "", "" }; } // 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. class StackMemorySection { private int[] memory; private int baseAddress; private String[] logicalValueString; StackMemorySection(int base, int size) { baseAddress = base; memory = new int[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 String getLogicalValueAtAddress(int address) { return logicalValueString[(address - baseAddress) / 4]; } public void setAtAddress(int address, int value) { memory[(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 = 8; 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() { // setLayout(new GridLayout(1, 4)); 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 appletTitle = "CIRCLE OF SQUARES"; public final static String step = "Step"; public final static String reset = "Reset"; 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 = "bytecodes"; public final static String mnemonics = "mnemonics"; 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 bipushText = "bipush will expand the next byte to an int and push it onto the stack."; 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 integers off the stack, add them, and push the result back onto the stack."; 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 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 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 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."; } 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(ColorTable.stackAreaColor); methodArea.setBackground(ColorTable.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); } }