summaryrefslogtreecommitdiff
path: root/src/fjbg
diff options
context:
space:
mode:
authorGilles Dubochet <gilles.dubochet@epfl.ch>2009-09-21 19:24:41 +0000
committerGilles Dubochet <gilles.dubochet@epfl.ch>2009-09-21 19:24:41 +0000
commit0f10ffedc8d0cdf8410cc6fc143a08a9333c9832 (patch)
treee933f41b1faa1d1c53c357c7664b4714daccefab /src/fjbg
parent4c29e778f1c95d60f24310c1898fa2fdf295db0f (diff)
downloadscala-0f10ffedc8d0cdf8410cc6fc143a08a9333c9832.tar.gz
scala-0f10ffedc8d0cdf8410cc6fc143a08a9333c9832.tar.bz2
scala-0f10ffedc8d0cdf8410cc6fc143a08a9333c9832.zip
SABBUS now builds FJBG, which sources are now p...
SABBUS now builds FJBG, which sources are now part of the Scala module.
Diffstat (limited to 'src/fjbg')
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/FJBGContext.java170
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JAccessFlags.java32
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JArrayType.java59
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JAttribute.java75
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JAttributeFactory.java91
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JBootstrapInvokeDynamic.java35
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JClass.java320
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JCode.java1131
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JCodeAttribute.java89
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JCodeIterator.java374
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JConstantPool.java608
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java614
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JField.java30
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JFieldOrMethod.java122
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java89
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JLabel.java27
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JLineNumberTableAttribute.java99
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JLocalVariable.java35
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JMember.java99
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JMethod.java133
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JMethodType.java72
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JObjectType.java53
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JOpcode.java1264
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JOtherAttribute.java54
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JReferenceType.java16
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JSourceFileAttribute.java53
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JType.java289
-rw-r--r--src/fjbg/ch/epfl/lamp/util/ByteArray.java140
28 files changed, 6173 insertions, 0 deletions
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/FJBGContext.java b/src/fjbg/ch/epfl/lamp/fjbg/FJBGContext.java
new file mode 100644
index 0000000000..a2eb6e7fa1
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/FJBGContext.java
@@ -0,0 +1,170 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Context in which FJBG executes. Used both as a factory for most
+ * FJBG classes and as a repository for other factories.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public class FJBGContext {
+ /** Class file major version */
+ final int MAJOR_VERSION;
+
+ /** Class file minor version */
+ final int MINOR_VERSION;
+
+ public FJBGContext() {
+ this(45, 3);
+ }
+
+ public FJBGContext(int major, int minor) {
+ MAJOR_VERSION = major;
+ MINOR_VERSION = minor;
+ }
+
+ // Factory methods
+ //////////////////////////////////////////////////////////////////////
+
+ public JClass JClass(int accessFlags,
+ String name,
+ String superclassName,
+ String[] interfaceNames,
+ String sourceFileName) {
+ return new JClass(this,
+ accessFlags,
+ name,
+ superclassName,
+ interfaceNames,
+ sourceFileName);
+ }
+
+ public JClass JClass(DataInputStream stream)
+ throws IOException {
+ return new JClass(this, stream);
+ }
+
+ public JConstantPool JConstantPool() {
+ return new JConstantPool(this);
+ }
+
+ public JConstantPool JConstantPool(DataInputStream stream)
+ throws IOException {
+ return new JConstantPool(this, stream);
+ }
+
+ public JField JField(JClass owner,
+ int accessFlags,
+ String name,
+ JType type) {
+ return new JField(this,
+ owner,
+ accessFlags,
+ name,
+ type);
+ }
+
+ public JField JField(JClass owner, DataInputStream stream)
+ throws IOException {
+ return new JField(this, owner, stream);
+ }
+
+ public JMethod JMethod(JClass owner,
+ int accessFlags,
+ String name,
+ JType returnType,
+ JType[] argTypes,
+ String[] argNames) {
+ return new JMethod(this,
+ owner,
+ accessFlags,
+ name,
+ returnType,
+ argTypes,
+ argNames);
+ }
+
+ public JMethod JMethod(JClass owner,
+ int accessFlags,
+ String name,
+ JMethodType type,
+ String[] argNames) {
+ return JMethod(owner,
+ accessFlags,
+ name,
+ type.getReturnType(),
+ type.getArgumentTypes(),
+ argNames);
+ }
+
+ public JMethod JMethod(JClass owner, DataInputStream stream)
+ throws IOException {
+ return new JMethod(this, owner, stream);
+ }
+
+ public JLocalVariable JLocalVariable(JMethod owner,
+ JType type,
+ String name,
+ int index) {
+ return new JLocalVariable(this, owner, type, name, index);
+ }
+
+ public JCode JCode(JClass clazz, JMethod owner) {
+ return new JExtendedCode(this, clazz, owner);
+ }
+
+ public JCode JCode(JClass clazz, JMethod owner, DataInputStream stream)
+ throws IOException {
+ return new JCode(this, clazz, owner, stream);
+ }
+
+ public JAttributeFactory JAttributeFactory() {
+ return new JAttributeFactory(this);
+ }
+
+ // Attributes
+ public JCodeAttribute JCodeAttribute(JClass clazz, JMethod owner) {
+ return new JCodeAttribute(this, clazz, owner);
+ }
+
+ public JLineNumberTableAttribute JLineNumberTableAttribute(JClass clazz,
+ JCode owner) {
+ return new JLineNumberTableAttribute(this, clazz, owner);
+ }
+
+ public JOtherAttribute JOtherAttribute(JClass clazz,
+ Object owner,
+ String name,
+ byte[] contents,
+ int length) {
+ return new JOtherAttribute(this, clazz, owner, name, contents, length);
+ }
+
+ public JOtherAttribute JOtherAttribute(JClass clazz,
+ Object owner,
+ String name,
+ byte[] contents) {
+ return JOtherAttribute(clazz, owner, name, contents, contents.length);
+ }
+
+ public JSourceFileAttribute JSourceFileAttribute(JClass clazz,
+ String sourceFileName) {
+ return new JSourceFileAttribute(this, clazz, sourceFileName);
+ }
+
+ /// Repository
+ //////////////////////////////////////////////////////////////////////
+
+ protected JAttributeFactory jAttributeFactory = null;
+ public JAttributeFactory getJAttributeFactory() {
+ if (jAttributeFactory == null)
+ jAttributeFactory = JAttributeFactory();
+ return jAttributeFactory;
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JAccessFlags.java b/src/fjbg/ch/epfl/lamp/fjbg/JAccessFlags.java
new file mode 100644
index 0000000000..8df4f9350e
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JAccessFlags.java
@@ -0,0 +1,32 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Definition of access flags for fields, methods and classes.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public interface JAccessFlags {
+ public static int ACC_PUBLIC = 0x0001;
+ public static int ACC_PRIVATE = 0x0002;
+ public static int ACC_PROTECTED = 0x0004;
+ public static int ACC_STATIC = 0x0008;
+ public static int ACC_FINAL = 0x0010;
+ public static int ACC_SUPER = 0x0020;
+ public static int ACC_VOLATILE = 0x0040;
+ public static int ACC_TRANSIENT = 0x0080;
+ public static int ACC_NATIVE = 0x0100;
+ public static int ACC_INTERFACE = 0x0200;
+ public static int ACC_ABSTRACT = 0x0400;
+ public static int ACC_STRICT = 0x0800;
+ public static int ACC_SYNTHETIC = 0x1000;
+ public static int ACC_ANNOTATION= 0x2000;
+ public static int ACC_ENUM = 0x4000;
+
+ // 1.5 specifics
+ public static int ACC_BRIDGE = 0x0040;
+ public static int ACC_VARARGS = 0x0080;
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JArrayType.java b/src/fjbg/ch/epfl/lamp/fjbg/JArrayType.java
new file mode 100644
index 0000000000..85662428b6
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JArrayType.java
@@ -0,0 +1,59 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Types for Java arrays.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public class JArrayType extends JReferenceType {
+ protected final JType elementType;
+ protected String signature = null;
+
+ public JArrayType(JType elementType) {
+ this.elementType = elementType;
+ }
+
+ public int getSize() { return 1; }
+
+ public String getSignature() {
+ if (signature == null)
+ signature = "[" + elementType.getSignature();
+ return signature;
+ }
+
+ public String getDescriptor() {
+ return getSignature();
+ }
+
+ public int getTag() { return T_ARRAY; }
+
+ public JType getElementType() { return elementType; }
+
+ public String toString() {
+ return elementType.toString() + "[]";
+ }
+
+ public boolean isArrayType() { return true; }
+
+ public boolean isCompatibleWith(JType other) {
+ if (other instanceof JObjectType)
+ return (JObjectType)other == JObjectType.JAVA_LANG_OBJECT;
+ else if (other instanceof JArrayType)
+ return elementType.isCompatibleWith(((JArrayType)other).elementType);
+ else return other == JType.REFERENCE;
+ }
+
+ public static JArrayType BOOLEAN = new JArrayType(JType.BOOLEAN);
+ public static JArrayType BYTE = new JArrayType(JType.BYTE);
+ public static JArrayType CHAR = new JArrayType(JType.CHAR);
+ public static JArrayType SHORT = new JArrayType(JType.SHORT);
+ public static JArrayType INT = new JArrayType(JType.INT);
+ public static JArrayType FLOAT = new JArrayType(JType.FLOAT);
+ public static JArrayType LONG = new JArrayType(JType.LONG);
+ public static JArrayType DOUBLE = new JArrayType(JType.DOUBLE);
+ public static JArrayType REFERENCE = new JArrayType(JType.REFERENCE);
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JAttribute.java b/src/fjbg/ch/epfl/lamp/fjbg/JAttribute.java
new file mode 100644
index 0000000000..981fbfc645
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JAttribute.java
@@ -0,0 +1,75 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Abstract superclass for attributes which can be attached to various
+ * parts of a class file.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public abstract class JAttribute {
+ protected final int nameIdx;
+
+ static public void writeTo(List/*<JAttribute>*/ attrs, DataOutputStream stream)
+ throws IOException {
+ stream.writeShort(attrs.size());
+ Iterator attrsIt = attrs.iterator();
+ while (attrsIt.hasNext()) {
+ JAttribute attr = (JAttribute)attrsIt.next();
+ attr.writeTo(stream);
+ }
+ }
+
+ static public List/*<JAttribute>*/ readFrom(FJBGContext context,
+ JClass clazz,
+ Object owner,
+ DataInputStream stream)
+ throws IOException {
+ JAttributeFactory factory = context.getJAttributeFactory();
+ int count = stream.readShort();
+ ArrayList list = new ArrayList(count);
+ for (int i = 0; i < count; ++i)
+ list.add(factory.newInstance(clazz, owner, stream));
+ return list;
+ }
+
+ public JAttribute(FJBGContext context, JClass clazz) {
+ this.nameIdx = clazz.getConstantPool().addUtf8(getName());
+ }
+
+ public JAttribute(FJBGContext context, JClass clazz, String name) {
+ this.nameIdx = clazz.getConstantPool().addUtf8(name);
+ }
+
+ abstract public String getName();
+
+ /**
+ * Write the attribute to a stream.
+ */
+ public void writeTo(DataOutputStream stream) throws IOException {
+ int contentsSize = getSize();
+
+ stream.writeShort(nameIdx);
+ stream.writeInt(contentsSize);
+ int streamSizeBefore = stream.size();
+ writeContentsTo(stream);
+ int streamSizeDiff = stream.size() - streamSizeBefore;
+
+ assert contentsSize == streamSizeDiff
+ : "invalid size for attribute " + getName()
+ + " given: " + contentsSize
+ + " actual: " + streamSizeDiff;
+ }
+
+ // Note: it is not legal to add data to the constant pool during
+ // the execution of any of the following two methods.
+ protected abstract int getSize();
+ protected abstract void writeContentsTo(DataOutputStream stream)
+ throws IOException;
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JAttributeFactory.java b/src/fjbg/ch/epfl/lamp/fjbg/JAttributeFactory.java
new file mode 100644
index 0000000000..a0f575e7d0
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JAttributeFactory.java
@@ -0,0 +1,91 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.io.*;
+import java.util.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Extensible factory to build subclasses of JAttribute based on an
+ * attribute name.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public class JAttributeFactory {
+ protected FJBGContext context;
+ protected HashMap/*<String, Constructor>*/ constructors = new HashMap();
+
+ protected final static Class[] CONSTRUCTOR_ARGS = new Class[] {
+ FJBGContext.class,
+ JClass.class,
+ Object.class,
+ String.class,
+ int.class,
+ DataInputStream.class
+ };
+
+ protected final static Constructor defaultDefaultConstructor;
+ static {
+ try {
+ defaultDefaultConstructor =
+ JOtherAttribute.class.getConstructor(CONSTRUCTOR_ARGS);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected final Constructor defaultConstructor;
+
+ public JAttributeFactory(FJBGContext context,
+ Constructor defaultConstructor) {
+ this.context = context;
+ this.defaultConstructor = defaultConstructor;
+ registerClass("Code", JCodeAttribute.class);
+ registerClass("LineNumberTable", JLineNumberTableAttribute.class);
+ registerClass("SourceFile", JSourceFileAttribute.class);
+ }
+
+ public JAttributeFactory(FJBGContext context) {
+ this(context, defaultDefaultConstructor);
+ }
+
+ public void registerClass(String attributeName,
+ Class clazz) {
+ if (! JAttribute.class.isAssignableFrom(clazz))
+ throw new IllegalArgumentException("Not a subclass of JAttribute: "
+ + clazz);
+
+ try {
+ Constructor constr = clazz.getConstructor(CONSTRUCTOR_ARGS);
+ constructors.put(attributeName, constr);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("No appropriate constructor for "
+ + clazz);
+ }
+ }
+
+ public JAttribute newInstance(JClass clazz,
+ Object owner,
+ DataInputStream stream)
+ throws IOException {
+ String name = clazz.getConstantPool().lookupUtf8(stream.readShort());
+ Integer size = new Integer(stream.readInt());
+ Constructor constr = (Constructor)constructors.get(name);
+ if (constr == null) constr = defaultConstructor;
+
+ Object[] args = new Object[] { context, clazz, owner, name, size, stream };
+ try {
+ return (JAttribute)constr.newInstance(args);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JBootstrapInvokeDynamic.java b/src/fjbg/ch/epfl/lamp/fjbg/JBootstrapInvokeDynamic.java
new file mode 100644
index 0000000000..ad4acfc329
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JBootstrapInvokeDynamic.java
@@ -0,0 +1,35 @@
+package ch.epfl.lamp.fjbg;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * BootstrapInvokeDynamic entry, as described by JSR 292 (invoke dynamic)
+ *
+ * @author Iulian Dragos
+ *
+ */
+public class JBootstrapInvokeDynamic extends JAttribute {
+ /** Constant pool of the current classfile. */
+ private JConstantPool pool;
+
+ private int classIndex = -1;
+
+ public JBootstrapInvokeDynamic(FJBGContext context,
+ JClass clazz, String className) {
+ super(context, clazz);
+ this.pool = clazz.pool;
+ this.classIndex = pool.addClass(className);
+ }
+
+ public String getName() { return "BootstrapInvokeDynamic"; }
+
+ protected int getSize() {
+ return 2;
+ }
+
+ protected void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeShort(classIndex);
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JClass.java b/src/fjbg/ch/epfl/lamp/fjbg/JClass.java
new file mode 100644
index 0000000000..1542bb1104
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JClass.java
@@ -0,0 +1,320 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Representation of a Java class.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+public class JClass extends JMember {
+
+ /** Magic number for Java class files. */
+ public final static int MAGIC_NUMBER = 0xCAFEBABE;
+
+ protected final JAttributeFactory attributeFactory;
+
+ protected final String superclassName;
+ protected final String[] interfaceNames;
+ protected final String sourceFileName;
+ protected final JConstantPool pool;
+
+ protected JBootstrapInvokeDynamic bootstrapClassAttr = null;
+
+ public final static String[] NO_INTERFACES = new String[0];
+
+ protected final LinkedList/*<JMethod>*/ methods = new LinkedList();
+ protected final LinkedList/*<JField>*/ fields = new LinkedList();
+
+ protected JInnerClassesAttribute innerClasses;
+
+ protected int major;
+ protected int minor;
+
+ /**
+ * Creates a new class with its access flags, name, superclass name,
+ * interfaces names and source file name initialized to a given value.
+ * The constructor also initializes the pool and adds a sourceFileName
+ * attribute to the class.
+ * @param accessFlags the int representing the access flags of the class.
+ * @param name the string representing the name of the class.
+ * @param superclassName the string representing the name of the class'
+ * superclass.
+ * @param interfaceNames the list of strings representing the names of the
+ * interfaces implemented by the class.
+ * @param sourceFileName name of the file from which the class was compiled.
+ */
+ protected JClass(FJBGContext context,
+ int accessFlags,
+ String name,
+ String superclassName,
+ String[] interfaceNames,
+ String sourceFileName) {
+ super(context, accessFlags, name);
+ this.attributeFactory = context.getJAttributeFactory();
+
+ this.major = context.MAJOR_VERSION;
+ this.minor = context.MINOR_VERSION;
+
+ this.superclassName = superclassName;
+ this.interfaceNames = interfaceNames;
+ this.sourceFileName = sourceFileName;
+ this.pool = context.JConstantPool();
+ if (sourceFileName != null)
+ addAttribute(context.JSourceFileAttribute(this, sourceFileName));
+ }
+
+ protected JClass(FJBGContext context, DataInputStream stream)
+ throws IOException {
+ super(context);
+ this.attributeFactory = context.getJAttributeFactory();
+
+ int magic = stream.readInt();
+ if (magic != MAGIC_NUMBER)
+ throw new IllegalArgumentException("invalid magic number: "+magic);
+
+ minor = stream.readShort();
+ major = stream.readShort();
+ pool = context.JConstantPool(stream);
+ accessFlags = stream.readShort();
+
+ // This class, super class and interfaces
+ name = pool.lookupClass(stream.readShort());
+ superclassName = pool.lookupClass(stream.readShort());
+ interfaceNames = new String[stream.readShort()];
+ for (int i = 0; i < interfaceNames.length; ++i)
+ interfaceNames[i] = pool.lookupClass(stream.readShort());
+
+ // Fields, methods and attributes
+ int fieldsCount = stream.readShort();
+ for (int i = 0; i < fieldsCount; ++i)
+ addField(context.JField(this, stream));
+
+ int methodsCount = stream.readShort();
+ for (int i = 0; i < methodsCount; ++i)
+ addMethod(context.JMethod(this, stream));
+
+ int attributesCount = stream.readShort();
+ for (int i = 0; i < attributesCount; ++i)
+ addAttribute(attributeFactory.newInstance(this, this, stream));
+
+ sourceFileName = null;
+ }
+
+ /**
+ * Gets the name of the class' superclass.
+ * @return The string representing the name of the class' superclass.
+ */
+ public String getSuperclassName() { return superclassName; }
+
+ /**
+ * Gets the names of the interfaces implemented by the class.
+ * @return The array containing the string representations of the
+ * names of the interfaces implemented by the class.
+ */
+ public String[] getInterfaceNames() { return interfaceNames; }
+
+ /**
+ * Gets the type of the objects that are instances of the class.
+ * @return The type of the instances of the class.
+ */
+ public JType getType() { return new JObjectType(name); }
+
+ public JClass getJClass() { return this; }
+
+ /**
+ * Gets the version number of the class.
+ * @param major The int representing the major part of the version number
+ * of the class.
+ * @param minor The int representing the minor part of the version number
+ * of the class.
+ */
+ public void setVersion(int major, int minor) {
+ assert !frozen;
+ this.major = major;
+ this.minor = minor;
+ }
+
+ /**
+ * Gets the major part of the number describing the version of the class.
+ * @return The int representing the major part of the version number of
+ * the class.
+ */
+ public int getMajorVersion() { return major; }
+
+ /**
+ * Gets the minor part of the number describing the version of the class.
+ * @return The int representing the minor part of the version number of
+ * the class.
+ */
+ public int getMinorVersion() { return minor; }
+
+ /**
+ * Gets the constant pool of the class.
+ * @return The constant pool of the class.
+ */
+ public JConstantPool getConstantPool() { return pool; }
+
+ public JInnerClassesAttribute getInnerClasses() {
+ if (innerClasses == null) {
+ innerClasses = new JInnerClassesAttribute(context, this);
+ addAttribute(innerClasses);
+ }
+ return innerClasses;
+ }
+
+ /**
+ * Decides if the class is an interface.
+ * @return The boolean representing if the class is an interface or not.
+ */
+ public boolean isInterface() {
+ return (accessFlags & JAccessFlags.ACC_INTERFACE) != 0;
+ }
+
+ public void addField(JField field) {
+ assert !frozen;
+ fields.add(field);
+ }
+
+ /**
+ * Create and add a new field to the class.
+ */
+ public JField addNewField(int accessFlags, String name, JType type) {
+ assert !frozen;
+ JField f = context.JField(this, accessFlags, name, type);
+ addField(f);
+ return f;
+ }
+
+ protected void addMethod(JMethod method) {
+ assert !frozen;
+ methods.add(method);
+ }
+
+ /**
+ * Create and add a new method to the class.
+ */
+ public JMethod addNewMethod(int accessFlags,
+ String name,
+ JType returnType,
+ JType[] argTypes,
+ String[] argNames) {
+ assert !frozen;
+ JMethod m = context.JMethod(this,
+ accessFlags,
+ name,
+ returnType,
+ argTypes,
+ argNames);
+ addMethod(m);
+ return m;
+ }
+
+ /**
+ * Remove a previously-added method. This makes no attempt at
+ * minimising the constant pool by removing all constants which
+ * were used only by this method.
+ */
+ public void removeMethod(JMethod m) {
+ assert !frozen;
+ methods.remove(m);
+ }
+
+ public JMethod[] getMethods() {
+ return (JMethod[])methods.toArray(new JMethod[methods.size()]);
+ }
+
+ /**
+ * Freeze the contents of this class so that it can be written to
+ * a file.
+ */
+ public void freeze() {
+ assert !frozen;
+ frozen = true;
+ }
+
+ /**
+ * Writes the contents of the class to a file referenced by its name.
+ * @param fileName The name of the file in which the class must be written.
+ */
+ public void writeTo(String fileName) throws IOException {
+ writeTo(new File(fileName));
+ }
+
+ /**
+ * Writes the contents of the class to a file.
+ * @param file The file in which the class must be written.
+ */
+ public void writeTo(File file) throws IOException {
+ File parent = file.getParentFile();
+ if (parent != null && !parent.isDirectory())
+ if (!parent.mkdirs())
+ throw new IOException("cannot create directory " + parent);
+
+ FileOutputStream fStream = new FileOutputStream(file);
+ BufferedOutputStream bStream = new BufferedOutputStream(fStream);
+ DataOutputStream dStream = new DataOutputStream(bStream);
+ writeTo(dStream);
+ dStream.close();
+ bStream.close();
+ fStream.close();
+ }
+
+ public void setBootstrapClass(String bootstrapClass) {
+ assert bootstrapClassAttr == null;
+ bootstrapClassAttr = new JBootstrapInvokeDynamic(context, this, bootstrapClass);
+ addAttribute(bootstrapClassAttr);
+ }
+
+ /**
+ * Writes the contents of the class to a data stream.
+ * @param stream The data stream in which the class must be written.
+ */
+ public void writeTo(DataOutputStream stream) throws IOException {
+ if (!frozen) freeze();
+
+ int thisClassIdx = pool.addClass(name);
+ int superClassIdx = pool.addClass(superclassName);
+ int[] interfacesIdx = new int[interfaceNames.length];
+
+ for (int i = 0; i < interfaceNames.length; ++i)
+ interfacesIdx[i] = pool.addClass(interfaceNames[i]);
+
+ pool.freeze();
+
+ // Magic number.
+ stream.writeInt(MAGIC_NUMBER);
+ // Version
+ stream.writeShort(minor);
+ stream.writeShort(major);
+ // Constant pool
+ pool.writeTo(stream);
+ // Access flags
+ stream.writeShort(accessFlags);
+
+ // This class, super class and interfaces
+ stream.writeShort(thisClassIdx);
+ stream.writeShort(superClassIdx);
+ stream.writeShort(interfacesIdx.length);
+ for (int i = 0; i < interfacesIdx.length; ++i)
+ stream.writeShort(interfacesIdx[i]);
+
+ // Fields and methods
+ stream.writeShort(fields.size());
+ Iterator fieldsIt = fields.iterator();
+ while (fieldsIt.hasNext())
+ ((JField)fieldsIt.next()).writeTo(stream);
+
+ stream.writeShort(methods.size());
+ Iterator methodsIt = methods.iterator();
+ while (methodsIt.hasNext())
+ ((JMethod)methodsIt.next()).writeTo(stream);
+
+ // Attributes
+ JAttribute.writeTo(attributes, stream);
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JCode.java b/src/fjbg/ch/epfl/lamp/fjbg/JCode.java
new file mode 100644
index 0000000000..252186a18e
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JCode.java
@@ -0,0 +1,1131 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.util.*;
+import java.io.*;
+
+import ch.epfl.lamp.util.*;
+
+/**
+ * List of instructions, to which Java byte-code instructions can be
+ * added.
+ *
+ * @author Michel Schinz, Thomas Friedli
+ * @version 1.0
+ */
+
+public class JCode {
+ protected boolean frozen = false;
+
+ protected final FJBGContext context;
+ protected final JMethod owner;
+
+ protected final ByteArray codeArray;
+
+ protected final LinkedList/*<ExceptionHandler>*/ exceptionHandlers =
+ new LinkedList();
+
+ protected final JConstantPool pool;
+
+ protected final ArrayList/*<OffsetToPatch>*/ offsetToPatch =
+ new ArrayList();
+
+ protected static int UNKNOWN_STACK_SIZE = Integer.MIN_VALUE;
+ protected int maxStackSize = UNKNOWN_STACK_SIZE;
+ protected int[] stackProduction = null;
+ protected int[] stackSizes;
+
+ protected JCode(FJBGContext context, JClass clazz, JMethod owner) {
+ this.context = context;
+ this.pool = clazz.getConstantPool();
+ this.owner = owner;
+ this.codeArray = new ByteArray();
+ }
+
+ protected JCode(FJBGContext context,
+ JClass clazz,
+ JMethod owner,
+ DataInputStream stream)
+ throws IOException {
+ this.context = context;
+ this.pool = clazz.getConstantPool();
+ this.owner = owner;
+ int size = stream.readInt();
+ this.codeArray = new ByteArray(stream, size);
+ }
+
+ /**
+ * Gets the program counter, which is defined as the address of the
+ * next instruction.
+ * @return The int representing the value of the program counter
+ */
+ public int getPC() {
+ return codeArray.getSize();
+ }
+
+ /**
+ * Gets the size of the code
+ * @return The number of bytes of the code
+ */
+ public int getSize() {
+ return codeArray.getSize();
+ }
+
+ /**
+ * Gets the method to which the code belongs
+ * @return The method to which the code belongs
+ */
+ public JMethod getOwner() {
+ return owner;
+ }
+
+ // Stack size
+ public int getMaxStackSize() {
+ if (maxStackSize == UNKNOWN_STACK_SIZE)
+ maxStackSize = computeMaxStackSize();
+ return maxStackSize;
+ }
+
+ // Freezing
+ //////////////////////////////////////////////////////////////////////
+
+ public void freeze() throws OffsetTooBigException {
+ assert !frozen;
+ patchAllOffset();
+ codeArray.freeze();
+ frozen = true;
+ }
+
+ // Attributes
+ //////////////////////////////////////////////////////////////////////
+
+ protected final LinkedList/*<JAttribute>*/ attributes = new LinkedList();
+
+ public void addAttribute(JAttribute attr) {
+ attributes.add(attr);
+ }
+
+ public List/*<JAttribute>*/ getAttributes() {
+ return attributes;
+ }
+
+ // Emitting code
+ //////////////////////////////////////////////////////////////////////
+
+ public void emit(JOpcode opcode) {
+ setStackProduction(getPC(), opcode);
+ codeArray.addU1(opcode.code);
+ }
+
+ public void emitNOP() { emit(JOpcode.NOP); }
+
+ // Constant loading.
+ public void emitACONST_NULL() { emit(JOpcode.ACONST_NULL); }
+ public void emitICONST_M1() { emit(JOpcode.ICONST_M1); }
+ public void emitICONST_0() { emit(JOpcode.ICONST_0); }
+ public void emitICONST_1() { emit(JOpcode.ICONST_1); }
+ public void emitICONST_2() { emit(JOpcode.ICONST_2); }
+ public void emitICONST_3() { emit(JOpcode.ICONST_3); }
+ public void emitICONST_4() { emit(JOpcode.ICONST_4); }
+ public void emitICONST_5() { emit(JOpcode.ICONST_5); }
+ public void emitLCONST_0() { emit(JOpcode.LCONST_0); }
+ public void emitLCONST_1() { emit(JOpcode.LCONST_1); }
+ public void emitFCONST_0() { emit(JOpcode.FCONST_0); }
+ public void emitFCONST_1() { emit(JOpcode.FCONST_1); }
+ public void emitFCONST_2() { emit(JOpcode.FCONST_2); }
+ public void emitDCONST_0() { emit(JOpcode.DCONST_0); }
+ public void emitDCONST_1() { emit(JOpcode.DCONST_1); }
+
+ public void emitBIPUSH(int b) { emitU1(JOpcode.BIPUSH, b); }
+ public void emitSIPUSH(int s) { emitU2(JOpcode.SIPUSH, s); }
+ public void emitLDC(int value) {
+ emitU1(JOpcode.LDC, pool.addInteger(value));
+ }
+ public void emitLDC(float value) {
+ emitU1(JOpcode.LDC, pool.addFloat(value));
+ }
+ public void emitLDC(String value) {
+ emitU1(JOpcode.LDC, pool.addString(value));
+ }
+ public void emitLDC_W(int value) {
+ emitU1(JOpcode.LDC_W, pool.addInteger(value));
+ }
+ public void emitLDC_W(float value) {
+ emitU1(JOpcode.LDC_W, pool.addFloat(value));
+ }
+ public void emitLDC_W(String value) {
+ emitU1(JOpcode.LDC_W, pool.addString(value));
+ }
+ public void emitLDC2_W(long value) {
+ emitU2(JOpcode.LDC2_W, pool.addLong(value));
+ }
+ public void emitLDC2_W(double value) {
+ emitU2(JOpcode.LDC2_W, pool.addDouble(value));
+ }
+
+ // Loading variables.
+ public void emitILOAD(int index) { emitU1(JOpcode.ILOAD, index); }
+ public void emitLLOAD(int index) { emitU1(JOpcode.LLOAD, index); }
+ public void emitFLOAD(int index) { emitU1(JOpcode.FLOAD, index); }
+ public void emitDLOAD(int index) { emitU1(JOpcode.DLOAD, index); }
+ public void emitALOAD(int index) { emitU1(JOpcode.ALOAD, index); }
+
+ public void emitILOAD_0() { emit(JOpcode.ILOAD_0); }
+ public void emitILOAD_1() { emit(JOpcode.ILOAD_1); }
+ public void emitILOAD_2() { emit(JOpcode.ILOAD_2); }
+ public void emitILOAD_3() { emit(JOpcode.ILOAD_3); }
+ public void emitLLOAD_0() { emit(JOpcode.LLOAD_0); }
+ public void emitLLOAD_1() { emit(JOpcode.LLOAD_1); }
+ public void emitLLOAD_2() { emit(JOpcode.LLOAD_2); }
+ public void emitLLOAD_3() { emit(JOpcode.LLOAD_3); }
+ public void emitFLOAD_0() { emit(JOpcode.FLOAD_0); }
+ public void emitFLOAD_1() { emit(JOpcode.FLOAD_1); }
+ public void emitFLOAD_2() { emit(JOpcode.FLOAD_2); }
+ public void emitFLOAD_3() { emit(JOpcode.FLOAD_3); }
+ public void emitDLOAD_0() { emit(JOpcode.DLOAD_0); }
+ public void emitDLOAD_1() { emit(JOpcode.DLOAD_1); }
+ public void emitDLOAD_2() { emit(JOpcode.DLOAD_2); }
+ public void emitDLOAD_3() { emit(JOpcode.DLOAD_3); }
+ public void emitALOAD_0() { emit(JOpcode.ALOAD_0); }
+ public void emitALOAD_1() { emit(JOpcode.ALOAD_1); }
+ public void emitALOAD_2() { emit(JOpcode.ALOAD_2); }
+ public void emitALOAD_3() { emit(JOpcode.ALOAD_3); }
+
+ public void emitIALOAD() { emit(JOpcode.IALOAD); }
+ public void emitLALOAD() { emit(JOpcode.LALOAD); }
+ public void emitFALOAD() { emit(JOpcode.FALOAD); }
+ public void emitDALOAD() { emit(JOpcode.DALOAD); }
+ public void emitAALOAD() { emit(JOpcode.AALOAD); }
+ public void emitBALOAD() { emit(JOpcode.BALOAD); }
+ public void emitCALOAD() { emit(JOpcode.CALOAD); }
+ public void emitSALOAD() { emit(JOpcode.SALOAD); }
+
+ // Storing variables.
+ public void emitISTORE(int index) { emitU1(JOpcode.ISTORE, index); }
+ public void emitLSTORE(int index) { emitU1(JOpcode.LSTORE, index); }
+ public void emitFSTORE(int index) { emitU1(JOpcode.FSTORE, index); }
+ public void emitDSTORE(int index) { emitU1(JOpcode.DSTORE, index); }
+ public void emitASTORE(int index) { emitU1(JOpcode.ASTORE, index); }
+
+ public void emitISTORE_0() { emit(JOpcode.ISTORE_0); }
+ public void emitISTORE_1() { emit(JOpcode.ISTORE_1); }
+ public void emitISTORE_2() { emit(JOpcode.ISTORE_2); }
+ public void emitISTORE_3() { emit(JOpcode.ISTORE_3); }
+ public void emitLSTORE_0() { emit(JOpcode.LSTORE_0); }
+ public void emitLSTORE_1() { emit(JOpcode.LSTORE_1); }
+ public void emitLSTORE_2() { emit(JOpcode.LSTORE_2); }
+ public void emitLSTORE_3() { emit(JOpcode.LSTORE_3); }
+ public void emitFSTORE_0() { emit(JOpcode.FSTORE_0); }
+ public void emitFSTORE_1() { emit(JOpcode.FSTORE_1); }
+ public void emitFSTORE_2() { emit(JOpcode.FSTORE_2); }
+ public void emitFSTORE_3() { emit(JOpcode.FSTORE_3); }
+ public void emitDSTORE_0() { emit(JOpcode.DSTORE_0); }
+ public void emitDSTORE_1() { emit(JOpcode.DSTORE_1); }
+ public void emitDSTORE_2() { emit(JOpcode.DSTORE_2); }
+ public void emitDSTORE_3() { emit(JOpcode.DSTORE_3); }
+ public void emitASTORE_0() { emit(JOpcode.ASTORE_0); }
+ public void emitASTORE_1() { emit(JOpcode.ASTORE_1); }
+ public void emitASTORE_2() { emit(JOpcode.ASTORE_2); }
+ public void emitASTORE_3() { emit(JOpcode.ASTORE_3); }
+
+ public void emitIASTORE() { emit(JOpcode.IASTORE); }
+ public void emitLASTORE() { emit(JOpcode.LASTORE); }
+ public void emitFASTORE() { emit(JOpcode.FASTORE); }
+ public void emitDASTORE() { emit(JOpcode.DASTORE); }
+ public void emitAASTORE() { emit(JOpcode.AASTORE); }
+ public void emitBASTORE() { emit(JOpcode.BASTORE); }
+ public void emitCASTORE() { emit(JOpcode.CASTORE); }
+ public void emitSASTORE() { emit(JOpcode.SASTORE); }
+
+ // Stack manipulation.
+ public void emitPOP() { emit(JOpcode.POP); }
+ public void emitPOP2() { emit(JOpcode.POP2); }
+ public void emitDUP() { emit(JOpcode.DUP); }
+ public void emitDUP_X1() { emit(JOpcode.DUP_X1); }
+ public void emitDUP_X2() { emit(JOpcode.DUP_X2); }
+ public void emitDUP2() { emit(JOpcode.DUP2); }
+ public void emitDUP2_X1() { emit(JOpcode.DUP2_X1); }
+ public void emitDUP2_X2() { emit(JOpcode.DUP2_X2); }
+ public void emitSWAP() { emit(JOpcode.SWAP); }
+
+ // Artithmetic and logic operations.
+ public void emitIADD() { emit(JOpcode.IADD); }
+ public void emitLADD() { emit(JOpcode.LADD); }
+ public void emitFADD() { emit(JOpcode.FADD); }
+ public void emitDADD() { emit(JOpcode.DADD); }
+
+ public void emitISUB() { emit(JOpcode.ISUB); }
+ public void emitLSUB() { emit(JOpcode.LSUB); }
+ public void emitFSUB() { emit(JOpcode.FSUB); }
+ public void emitDSUB() { emit(JOpcode.DSUB); }
+
+ public void emitIMUL() { emit(JOpcode.IMUL); }
+ public void emitLMUL() { emit(JOpcode.LMUL); }
+ public void emitFMUL() { emit(JOpcode.FMUL); }
+ public void emitDMUL() { emit(JOpcode.DMUL); }
+
+ public void emitIDIV() { emit(JOpcode.IDIV); }
+ public void emitLDIV() { emit(JOpcode.LDIV); }
+ public void emitFDIV() { emit(JOpcode.FDIV); }
+ public void emitDDIV() { emit(JOpcode.DDIV); }
+
+ public void emitIREM() { emit(JOpcode.IREM); }
+ public void emitLREM() { emit(JOpcode.LREM); }
+ public void emitFREM() { emit(JOpcode.FREM); }
+ public void emitDREM() { emit(JOpcode.DREM); }
+
+ public void emitINEG() { emit(JOpcode.INEG); }
+ public void emitLNEG() { emit(JOpcode.LNEG); }
+ public void emitFNEG() { emit(JOpcode.FNEG); }
+ public void emitDNEG() { emit(JOpcode.DNEG); }
+
+ public void emitISHL() { emit(JOpcode.ISHL); }
+ public void emitLSHL() { emit(JOpcode.LSHL); }
+
+ public void emitISHR() { emit(JOpcode.ISHR); }
+ public void emitLSHR() { emit(JOpcode.LSHR); }
+
+ public void emitIUSHR() { emit(JOpcode.IUSHR); }
+ public void emitLUSHR() { emit(JOpcode.LUSHR); }
+
+ public void emitIAND() { emit(JOpcode.IAND); }
+ public void emitLAND() { emit(JOpcode.LAND); }
+
+ public void emitIOR() { emit(JOpcode.IOR); }
+ public void emitLOR() { emit(JOpcode.LOR); }
+
+ public void emitIXOR() { emit(JOpcode.IXOR); }
+ public void emitLXOR() { emit(JOpcode.LXOR); }
+
+ public void emitIINC(int index, int increment) {
+ emitU1U1(JOpcode.IINC, index, increment);
+ }
+
+ // (Numeric) type conversions.
+ public void emitI2L() { emit(JOpcode.I2L); }
+ public void emitI2F() { emit(JOpcode.I2F); }
+ public void emitI2D() { emit(JOpcode.I2D); }
+ public void emitL2I() { emit(JOpcode.L2I); }
+ public void emitL2F() { emit(JOpcode.L2F); }
+ public void emitL2D() { emit(JOpcode.L2D); }
+ public void emitF2I() { emit(JOpcode.F2I); }
+ public void emitF2L() { emit(JOpcode.F2L); }
+ public void emitF2D() { emit(JOpcode.F2D); }
+ public void emitD2I() { emit(JOpcode.D2I); }
+ public void emitD2L() { emit(JOpcode.D2L); }
+ public void emitD2F() { emit(JOpcode.D2F); }
+ public void emitI2B() { emit(JOpcode.I2B); }
+ public void emitI2C() { emit(JOpcode.I2C); }
+ public void emitI2S() { emit(JOpcode.I2S); }
+
+ // Comparisons and tests.
+ public void emitLCMP() { emit(JOpcode.LCMP); }
+ public void emitFCMPL() { emit(JOpcode.FCMPL); }
+ public void emitFCMPG() { emit(JOpcode.FCMPG); }
+ public void emitDCMPL() { emit(JOpcode.DCMPL); }
+ public void emitDCMPG() { emit(JOpcode.DCMPG); }
+
+ protected void emitGenericIF(JOpcode opcode, Label label)
+ throws OffsetTooBigException {
+ emitU2(opcode, label.getOffset16(getPC() + 1, getPC()));
+ }
+
+ public void emitIFEQ(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IFEQ, label);
+ }
+ public void emitIFEQ(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IFEQ, targetPC - getPC());
+ }
+ public void emitIFEQ() {
+ emitU2(JOpcode.IFEQ, 0);
+ }
+
+ public void emitIFNE(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IFNE, label);
+ }
+ public void emitIFNE(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IFNE, targetPC - getPC());
+ }
+ public void emitIFNE() {
+ emitU2(JOpcode.IFNE, 0);
+ }
+
+ public void emitIFLT(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IFLT, label);
+ }
+ public void emitIFLT(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IFLT, targetPC - getPC());
+ }
+ public void emitIFLT() {
+ emitU2(JOpcode.IFLT, 0);
+ }
+
+ public void emitIFGE(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IFGE, label);
+ }
+ public void emitIFGE(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IFGE, targetPC - getPC());
+ }
+ public void emitIFGE() {
+ emitU2(JOpcode.IFGE, 0);
+ }
+
+ public void emitIFGT(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IFGT, label);
+ }
+ public void emitIFGT(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IFGT, targetPC - getPC());
+ }
+ public void emitIFGT() {
+ emitU2(JOpcode.IFGT, 0);
+ }
+
+ public void emitIFLE(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IFLE, label);
+ }
+ public void emitIFLE(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IFLE, targetPC - getPC());
+ }
+ public void emitIFLE() {
+ emitU2(JOpcode.IFLE, 0);
+ }
+
+ public void emitIF_ICMPEQ(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IF_ICMPEQ, label);
+ }
+ public void emitIF_ICMPEQ(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IF_ICMPEQ, targetPC - getPC());
+ }
+ public void emitIF_ICMPEQ() {
+ emitU2(JOpcode.IF_ICMPEQ, 0);
+ }
+
+ public void emitIF_ICMPNE(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IF_ICMPNE, label);
+ }
+ public void emitIF_ICMPNE(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IF_ICMPNE, targetPC - getPC());
+ }
+ public void emitIF_ICMPNE() {
+ emitU2(JOpcode.IF_ICMPNE, 0);
+ }
+
+ public void emitIF_ICMPLT(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IF_ICMPLT, label);
+ }
+ public void emitIF_ICMPLT(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IF_ICMPLT, targetPC - getPC());
+ }
+ public void emitIF_ICMPLT() {
+ emitU2(JOpcode.IF_ICMPLT, 0);
+ }
+
+ public void emitIF_ICMPGE(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IF_ICMPGE, label);
+ }
+ public void emitIF_ICMPGE(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IF_ICMPGE, targetPC - getPC());
+ }
+ public void emitIF_ICMPGE() {
+ emitU2(JOpcode.IF_ICMPGE, 0);
+ }
+
+ public void emitIF_ICMPGT(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IF_ICMPGT, label);
+ }
+ public void emitIF_ICMPGT(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IF_ICMPGT, targetPC - getPC());
+ }
+ public void emitIF_ICMPGT() {
+ emitU2(JOpcode.IF_ICMPGT, 0);
+ }
+
+ public void emitIF_ICMPLE(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IF_ICMPLE, label);
+ }
+ public void emitIF_ICMPLE(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IF_ICMPLE, targetPC - getPC());
+ }
+ public void emitIF_ICMPLE() {
+ emitU2(JOpcode.IF_ICMPLE, 0);
+ }
+
+ public void emitIF_ACMPEQ(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IF_ACMPEQ, label);
+ }
+ public void emitIF_ACMPEQ(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IF_ACMPEQ, targetPC - getPC());
+ }
+ public void emitIF_ACMPEQ() {
+ emitU2(JOpcode.IF_ACMPEQ, 0);
+ }
+
+ public void emitIF_ACMPNE(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IF_ACMPNE, label);
+ }
+ public void emitIF_ACMPNE(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IF_ACMPNE, targetPC - getPC());
+ }
+ public void emitIF_ACMPNE() {
+ emitU2(JOpcode.IF_ACMPNE, 0);
+ }
+
+ public void emitIFNULL(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IFNULL, label);
+ }
+ public void emitIFNULL(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IFNULL, targetPC - getPC());
+ }
+ public void emitIFNULL() {
+ emitU2(JOpcode.IFNULL, 0);
+ }
+
+ public void emitIFNONNULL(Label label) throws OffsetTooBigException {
+ emitGenericIF(JOpcode.IFNONNULL, label);
+ }
+ public void emitIFNONNULL(int targetPC) throws OffsetTooBigException {
+ emitU2(JOpcode.IFNONNULL, targetPC - getPC());
+ }
+ public void emitIFNONNULL() {
+ emitU2(JOpcode.IFNONNULL, 0);
+ }
+
+ public void emitGOTO(Label label) throws OffsetTooBigException {
+ emitU2(JOpcode.GOTO, label.getOffset16(getPC() + 1, getPC()));
+ }
+ public void emitGOTO(int targetPC) throws OffsetTooBigException {
+ int offset = targetPC - getPC();
+ checkOffset16(offset);
+ emitU2(JOpcode.GOTO, offset);
+ }
+ public void emitGOTO() {
+ emitU2(JOpcode.GOTO, 0);
+ }
+
+ public void emitGOTO_W(Label label) {
+ emitU4(JOpcode.GOTO_W, label.getOffset32(getPC() + 1, getPC()));
+ }
+ public void emitGOTO_W(int targetPC) {
+ emitU4(JOpcode.GOTO_W, targetPC - getPC());
+ }
+ public void emitGOTO_W() {
+ emitU4(JOpcode.GOTO_W, 0);
+ }
+
+ public void emitJSR(Label label) throws OffsetTooBigException {
+ emitU2(JOpcode.JSR, label.getOffset16(getPC() + 1, getPC()));
+ }
+ public void emitJSR(int targetPC) {
+ emitU2(JOpcode.JSR, targetPC - getPC());
+ }
+ public void emitJSR() {
+ emitU2(JOpcode.JSR, 0);
+ }
+
+ public void emitJSR_W(Label label) {
+ emitU4(JOpcode.JSR_W, label.getOffset32(getPC() + 1, getPC()));
+ }
+ public void emitJSR_W(int targetPC) {
+ emitU4(JOpcode.JSR_W, targetPC - getPC());
+ }
+ public void emitJSR_W() {
+ emitU4(JOpcode.JSR_W, 0);
+ }
+
+ /*
+ public void emitRET(Label label) throws OffsetTooBigException {
+ emitU2(JOpcode.RET, label.getOffset16(getPC() + 1, getPC()));
+ }
+ public void emitRET(int targetPC) {
+ emitU1(JOpcode.RET, targetPC);
+ }
+ public void emitRET() {
+ emitU1(JOpcode.RET, 0);
+ }
+ */
+
+ public void emitRET(int index) {
+ emitU1(JOpcode.RET, index);
+ }
+
+ public void emitRET(JLocalVariable var) {
+ emitRET(var.getIndex());
+ }
+
+ public void emitTABLESWITCH(int[] keys,
+ Label[] branches,
+ Label defaultBranch) {
+ assert keys.length == branches.length;
+
+ int low = keys[0], high = keys[keys.length - 1];
+ int instrPC = getPC();
+
+ setStackProduction(instrPC, JOpcode.TABLESWITCH);
+ codeArray.addU1(JOpcode.cTABLESWITCH);
+ while (getPC() % 4 != 0) codeArray.addU1(0);
+
+ codeArray.addU4(defaultBranch.getOffset32(getPC(), instrPC));
+ codeArray.addU4(low);
+ codeArray.addU4(high);
+ for (int i = 0; i < branches.length; i++) {
+ assert keys[i] == low + i;
+ codeArray.addU4(branches[i].getOffset32(getPC(), instrPC));
+ }
+ }
+
+ public void emitLOOKUPSWITCH(int[] keys,
+ Label[] branches,
+ Label defaultBranch) {
+ assert keys.length == branches.length;
+
+ int instrPC = getPC();
+ setStackProduction(getPC(), JOpcode.LOOKUPSWITCH);
+ codeArray.addU1(JOpcode.cLOOKUPSWITCH);
+ while (getPC() % 4 != 0) codeArray.addU1(0);
+
+ codeArray.addU4(defaultBranch.getOffset32(getPC(), instrPC));
+ codeArray.addU4(branches.length);
+ for (int i = 0; i < branches.length; i++) {
+ codeArray.addU4(keys[i]);
+ codeArray.addU4(branches[i].getOffset32(getPC(), instrPC));
+ }
+ }
+
+ public void emitIRETURN() { emit(JOpcode.IRETURN); }
+ public void emitLRETURN() { emit(JOpcode.LRETURN); }
+ public void emitFRETURN() { emit(JOpcode.FRETURN); }
+ public void emitDRETURN() { emit(JOpcode.DRETURN); }
+ public void emitARETURN() { emit(JOpcode.ARETURN); }
+ public void emitRETURN() { emit(JOpcode.RETURN); }
+
+ // Field access
+ public void emitGETSTATIC(String className, String name, JType type) {
+ setStackProduction(getPC(), type.getSize());
+ int index = pool.addFieldRef(className, name, type.getSignature());
+ emitU2(JOpcode.GETSTATIC, index);
+ }
+ public void emitPUTSTATIC(String className, String name, JType type) {
+ setStackProduction(getPC(), -type.getSize());
+ int index = pool.addFieldRef(className, name, type.getSignature());
+ emitU2(JOpcode.PUTSTATIC, index);
+ }
+ public void emitGETFIELD(String className, String name, JType type) {
+ setStackProduction(getPC(), type.getSize() - 1);
+ int index = pool.addFieldRef(className, name, type.getSignature());
+ emitU2(JOpcode.GETFIELD, index);
+ }
+ public void emitPUTFIELD(String className, String name, JType type) {
+ setStackProduction(getPC(), -(type.getSize() + 1));
+ int index = pool.addFieldRef(className, name, type.getSignature());
+ emitU2(JOpcode.PUTFIELD, index);
+ }
+
+ // Method invocation
+ public void emitINVOKEVIRTUAL(String className,
+ String name,
+ JMethodType type) {
+ setStackProduction(getPC(), type.getProducedStack() - 1);
+ int index =
+ pool.addClassMethodRef(className, name, type.getSignature());
+ emitU2(JOpcode.INVOKEVIRTUAL, index);
+ }
+ public void emitINVOKESPECIAL(String className,
+ String name,
+ JMethodType type) {
+ setStackProduction(getPC(), type.getProducedStack() - 1);
+ int index =
+ pool.addClassMethodRef(className, name, type.getSignature());
+ emitU2(JOpcode.INVOKESPECIAL, index);
+ }
+ public void emitINVOKESTATIC(String className,
+ String name,
+ JMethodType type) {
+ setStackProduction(getPC(), type.getProducedStack());
+ int index =
+ pool.addClassMethodRef(className, name, type.getSignature());
+ emitU2(JOpcode.INVOKESTATIC, index);
+ }
+ public void emitINVOKEINTERFACE(String className,
+ String name,
+ JMethodType type) {
+ setStackProduction(getPC(), type.getProducedStack() - 1);
+ int index =
+ pool.addInterfaceMethodRef(className, name, type.getSignature());
+ emitU2U1U1(JOpcode.INVOKEINTERFACE, index, type.getArgsSize() + 1, 0);
+ }
+
+ // Object creation
+ public void emitNEW(String className) {
+ emitU2(JOpcode.NEW, pool.addClass(className));
+ }
+ public void emitNEWARRAY(JType elemType) {
+ emitU1(JOpcode.NEWARRAY, elemType.getTag());
+ }
+ public void emitANEWARRAY(JReferenceType elemType) {
+ emitU2(JOpcode.ANEWARRAY, pool.addDescriptor(elemType));
+ }
+ public void emitMULTIANEWARRAY(JReferenceType elemType, int dimensions) {
+ setStackProduction(getPC(), -dimensions + 1);
+ emitU2U1(JOpcode.MULTIANEWARRAY,
+ pool.addDescriptor(elemType),
+ dimensions);
+ }
+ public void emitARRAYLENGTH() { emit(JOpcode.ARRAYLENGTH); }
+
+ // Exception throwing
+ public void emitATHROW() { emit(JOpcode.ATHROW); }
+
+ // Dynamic typing
+ public void emitCHECKCAST(JReferenceType type) {
+ emitU2(JOpcode.CHECKCAST, pool.addDescriptor(type));
+ }
+ public void emitINSTANCEOF(JReferenceType type) {
+ emitU2(JOpcode.INSTANCEOF, pool.addDescriptor(type));
+ }
+
+ // Monitors
+ public void emitMONITORENTER() { emit(JOpcode.MONITORENTER); }
+ public void emitMONITOREXIT() { emit(JOpcode.MONITOREXIT); }
+
+ // Wide variants
+ // FIXME setStackProd. will here raise an exception
+ public void emitWIDE(JOpcode opcode, int index) {
+ assert (opcode.code == JOpcode.cILOAD)
+ || (opcode.code == JOpcode.cLLOAD)
+ || (opcode.code == JOpcode.cFLOAD)
+ || (opcode.code == JOpcode.cDLOAD)
+ || (opcode.code == JOpcode.cALOAD)
+ || (opcode.code == JOpcode.cISTORE)
+ || (opcode.code == JOpcode.cLSTORE)
+ || (opcode.code == JOpcode.cFSTORE)
+ || (opcode.code == JOpcode.cDSTORE)
+ || (opcode.code == JOpcode.cASTORE)
+ || (opcode.code == JOpcode.cRET)
+ : "invalide opcode for WIDE: " + opcode;
+
+ setStackProduction(getPC(), opcode);
+ codeArray.addU1(JOpcode.WIDE.code);
+ codeArray.addU1(opcode.code);
+ codeArray.addU2(index);
+ }
+ public void emitWIDE(JOpcode opcode, int index, int constant) {
+ assert opcode.code == JOpcode.cIINC
+ : "invalid opcode for WIDE: " + opcode;
+
+ setStackProduction(getPC(), opcode);
+ codeArray.addU1(JOpcode.cWIDE);
+ codeArray.addU1(opcode.code);
+ codeArray.addU2(index);
+ codeArray.addU2(constant);
+ }
+
+ protected void emitU1(JOpcode opcode, int i1) {
+ setStackProduction(getPC(), opcode);
+ codeArray.addU1(opcode.code);
+ codeArray.addU1(i1);
+ }
+
+ protected void emitU1U1(JOpcode opcode, int i1, int i2) {
+ setStackProduction(getPC(), opcode);
+ codeArray.addU1(opcode.code);
+ codeArray.addU1(i1);
+ codeArray.addU1(i2);
+ }
+
+ protected void emitU2(JOpcode opcode, int i1) {
+ setStackProduction(getPC(), opcode);
+ codeArray.addU1(opcode.code);
+ codeArray.addU2(i1);
+ }
+
+ protected void emitU2U1(JOpcode opcode, int i1, int i2) {
+ setStackProduction(getPC(), opcode);
+ codeArray.addU1(opcode.code);
+ codeArray.addU2(i1);
+ codeArray.addU1(i2);
+ }
+
+ protected void emitU2U1U1(JOpcode opcode, int i1, int i2, int i3) {
+ setStackProduction(getPC(), opcode);
+ codeArray.addU1(opcode.code);
+ codeArray.addU2(i1);
+ codeArray.addU1(i2);
+ codeArray.addU1(i3);
+ }
+
+ protected void emitU4(JOpcode opcode, int i1) {
+ setStackProduction(getPC(), opcode);
+ codeArray.addU1(opcode.code);
+ codeArray.addU4(i1);
+ }
+
+ protected int getU1(int sourcePos) {
+ return codeArray.getU1(sourcePos);
+ }
+
+ protected int getU2(int sourcePos) {
+ return codeArray.getU2(sourcePos);
+ }
+
+ protected int getU4(int sourcePos) {
+ return codeArray.getU4(sourcePos);
+ }
+
+ protected int getS1(int sourcePos) {
+ return codeArray.getS1(sourcePos);
+ }
+
+ protected int getS2(int sourcePos) {
+ return codeArray.getS2(sourcePos);
+ }
+
+ protected int getS4(int sourcePos) {
+ return codeArray.getS4(sourcePos);
+ }
+
+ // Stack size computation
+ //////////////////////////////////////////////////////////////////////
+
+ protected int getStackProduction(int pc) {
+ if (stackProduction == null || pc >= stackProduction.length)
+ return UNKNOWN_STACK_SIZE;
+ else
+ return stackProduction[pc];
+ }
+
+ protected void setStackProduction(int pc, int production) {
+ if (stackProduction == null) {
+ stackProduction = new int[256];
+ Arrays.fill(stackProduction, UNKNOWN_STACK_SIZE);
+ } else {
+ while (pc >= stackProduction.length) {
+ int[] newStackProduction = new int[stackProduction.length * 2];
+ System.arraycopy(stackProduction, 0,
+ newStackProduction, 0,
+ stackProduction.length);
+ Arrays.fill(newStackProduction,
+ stackProduction.length,
+ newStackProduction.length,
+ UNKNOWN_STACK_SIZE);
+ stackProduction = newStackProduction;
+ }
+ }
+ stackProduction[pc] = production;
+ }
+
+ protected void setStackProduction(int pc, JOpcode opcode) {
+ // TODO we should instead check whether the opcode has known
+ // stack consumption/production.
+ if (getStackProduction(pc) == UNKNOWN_STACK_SIZE)
+// && opcode.hasKnownProducedDataSize()
+// && opcode.hasKnownConsumedDataSize())
+ setStackProduction(pc,
+ opcode.getProducedDataSize()
+ - opcode.getConsumedDataSize());
+ }
+
+ protected int computeMaxStackSize() {
+ if (stackSizes == null) {
+ stackSizes = new int[getSize()];
+ Arrays.fill(stackSizes, UNKNOWN_STACK_SIZE);
+ stackSizes[0] = 0;
+ }
+ int size = computeMaxStackSize(0, 0, 0);
+
+ // compute stack sizes for exception handlers too
+ ExceptionHandler exh = null;
+ for (Iterator it = exceptionHandlers.iterator();
+ it.hasNext();) {
+ exh = (ExceptionHandler)it.next();
+ int exhSize = computeMaxStackSize(exh.getHandlerPC(), 1, 1);
+ if (size < exhSize)
+ size = exhSize;
+ }
+
+ return size;
+ }
+
+ protected int computeMaxStackSize(int pc, int stackSize, int maxStackSize) {
+ JCodeIterator iterator = new JCodeIterator(this, pc);
+ for (;;) {
+ int successors = iterator.getSuccessorCount();
+ if (successors == 0)
+ return maxStackSize;
+ else {
+ assert stackProduction[iterator.getPC()] != UNKNOWN_STACK_SIZE
+ : "unknown stack production, pc=" + iterator.getPC()
+ + " in method " + owner.getName();
+ stackSize += stackProduction[iterator.getPC()];
+ if (stackSize > maxStackSize)
+ maxStackSize = stackSize;
+ int nextPC = -1;
+ for (int i = 0; i < successors; ++i) {
+ int succPC = iterator.getSuccessorPC(i);
+ assert succPC >= 0 && succPC < stackSizes.length
+ : iterator.getPC() + ": invalid pc: " + succPC
+ + " op: " + iterator.getOpcode();
+ if (stackSizes[succPC] == UNKNOWN_STACK_SIZE) {
+ stackSizes[succPC] = stackSize;
+ if (nextPC == -1)
+ nextPC = succPC;
+ else
+ maxStackSize = computeMaxStackSize(succPC,
+ stackSize,
+ maxStackSize);
+ }
+ }
+ if (nextPC == -1)
+ return maxStackSize;
+ else
+ iterator.moveTo(nextPC);
+ }
+ }
+ }
+
+ // Labels
+ //////////////////////////////////////////////////////////////////////
+
+ public static class OffsetTooBigException extends Exception {
+ public OffsetTooBigException() { super(); }
+ public OffsetTooBigException(String message) { super(message); }
+ }
+
+ protected void checkOffset16(int offset) throws OffsetTooBigException {
+ if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE)
+ throw new OffsetTooBigException("offset too big to fit"
+ + " in 16 bits: " + offset);
+ }
+
+ public class Label {
+ protected boolean anchored = false;
+ protected int targetPC = 0;
+
+ public void anchorToNext() {
+ assert !anchored;
+ this.targetPC = getPC();
+ anchored = true;
+ }
+
+ public int getAnchor() {
+ assert anchored;
+ return targetPC;
+ }
+
+ protected int getOffset16(int pc, int instrPC)
+ throws OffsetTooBigException {
+ if (anchored) {
+ int offset = targetPC - instrPC;
+ checkOffset16(offset);
+ return offset;
+ } else {
+ recordOffsetToPatch(pc, 16, instrPC, this);
+ return 0;
+ }
+ }
+
+ protected int getOffset32(int pc, int instrPC) {
+ if (anchored)
+ return targetPC - instrPC;
+ else {
+ recordOffsetToPatch(pc, 32, instrPC, this);
+ return 0;
+ }
+ }
+ }
+
+ public Label newLabel() {
+ return new Label();
+ }
+
+ public Label[] newLabels(int count) {
+ Label[] labels = new Label[count];
+ for (int i = 0; i < labels.length; ++i)
+ labels[i] = newLabel();
+ return labels;
+ }
+
+ protected static class OffsetToPatch {
+ public final int pc;
+ public final int size;
+ public final int instrPC;
+ public final Label label;
+
+ public OffsetToPatch(int pc, int size, int instrPC, Label label) {
+ this.pc = pc;
+ this.size = size;
+ this.instrPC = instrPC;
+ this.label = label;
+ }
+ }
+
+ protected void recordOffsetToPatch(int offsetPC,
+ int size,
+ int instrPC,
+ Label label) {
+ offsetToPatch.add(new OffsetToPatch(offsetPC, size, instrPC, label));
+ }
+
+ protected void patchAllOffset() throws OffsetTooBigException {
+ Iterator offsetIt = offsetToPatch.iterator();
+ while (offsetIt.hasNext()) {
+ OffsetToPatch offset = (OffsetToPatch)offsetIt.next();
+ int offsetValue = offset.label.getAnchor() - offset.instrPC;
+ if (offset.size == 16) {
+ checkOffset16(offsetValue);
+ codeArray.putU2(offset.pc, offsetValue);
+ } else
+ codeArray.putU4(offset.pc, offsetValue);
+ }
+ }
+
+ // Exception handling
+ //////////////////////////////////////////////////////////////////////
+
+ public class ExceptionHandler {
+ protected int startPC, endPC, handlerPC;
+ protected final String catchType;
+ protected final int catchTypeIndex;
+
+ public void setStartPC(int pc) {
+ this.startPC = pc;
+ }
+
+ public int getStartPC() {
+ return this.startPC;
+ }
+
+ public void setEndPC(int pc) {
+ this.endPC = pc;
+ }
+
+ public int getEndPC() {
+ return this.endPC;
+ }
+
+ public void setHandlerPC(int pc) {
+ this.handlerPC = pc;
+ }
+
+ public int getHandlerPC() {
+ return this.handlerPC;
+ }
+
+ public ExceptionHandler(String catchType) {
+ this(0, 0, 0, catchType);
+ }
+
+ public ExceptionHandler(int startPC,
+ int endPC,
+ int handlerPC,
+ String catchType) {
+ this.startPC = startPC;
+ this.endPC = endPC;
+ this.handlerPC = handlerPC;
+ this.catchType = catchType;
+ this.catchTypeIndex = (catchType == null
+ ? 0
+ : pool.addClass(catchType));
+ }
+
+ public ExceptionHandler(DataInputStream stream) throws IOException {
+ this.startPC = stream.readShort();
+ this.endPC = stream.readShort();
+ this.handlerPC = stream.readShort();
+ this.catchTypeIndex = stream.readShort();
+ this.catchType = (catchTypeIndex == 0
+ ? null
+ : pool.lookupClass(catchTypeIndex));
+ }
+
+ public void writeTo(DataOutputStream stream) throws IOException {
+ stream.writeShort(startPC);
+ stream.writeShort(endPC);
+ stream.writeShort(handlerPC);
+ stream.writeShort(catchTypeIndex);
+ }
+ }
+
+ public void addExceptionHandler(ExceptionHandler handler) {
+ assert !frozen;
+ exceptionHandlers.add(handler);
+ }
+
+ public void addExceptionHandler(int startPC,
+ int endPC,
+ int handlerPC,
+ String catchType) {
+ addExceptionHandler(new ExceptionHandler(startPC,
+ endPC,
+ handlerPC,
+ catchType));
+ }
+
+ public void addFinallyHandler(int startPC, int endPC, int handlerPC) {
+ assert !frozen;
+ addExceptionHandler(startPC, endPC, handlerPC, null);
+ }
+
+ public List/*<JExceptionHandler>*/ getExceptionHandlers() {
+ return exceptionHandlers;
+ }
+
+ // Line numbers
+ //////////////////////////////////////////////////////////////////////
+
+ protected int[] lineNumbers = null;
+ protected void ensureLineNumberCapacity(int endPC) {
+ assert !frozen;
+ if (lineNumbers == null) {
+ lineNumbers = new int[endPC];
+ addAttribute(context.JLineNumberTableAttribute(owner.getOwner(),
+ this));
+ } else if (lineNumbers.length < endPC) {
+ int[] newLN = new int[Math.max(endPC, lineNumbers.length * 2)];
+ System.arraycopy(lineNumbers, 0, newLN, 0, lineNumbers.length);
+ lineNumbers = newLN;
+ }
+ }
+
+ /**
+ * Set all line numbers in the interval [startPC, endPC) to
+ * line, overwriting existing line numbers.
+ */
+ public void setLineNumber(int startPC, int endPC, int line) {
+ ensureLineNumberCapacity(endPC);
+ Arrays.fill(lineNumbers, startPC, endPC, line);
+ }
+
+ public void setLineNumber(int instrPC, int line) {
+ setLineNumber(instrPC, instrPC + 1, line);
+ }
+
+ /** Sets all non-filled line numbers in the interval [startPC, endPC)
+ * to 'line'.
+ */
+ public void completeLineNumber(int startPC, int endPC, int line) {
+ ensureLineNumberCapacity(endPC);
+ for (int pc = startPC; pc < endPC; ++pc)
+ if (lineNumbers[pc] == 0) lineNumbers[pc] = line;
+ }
+
+ public int[] getLineNumbers() {
+ assert frozen;
+ if (lineNumbers == null) return new int[0];
+ else if (lineNumbers.length == getPC()) return lineNumbers;
+ else {
+ int[] trimmedLN = new int[getPC()];
+ System.arraycopy(lineNumbers, 0,
+ trimmedLN, 0,
+ Math.min(lineNumbers.length, trimmedLN.length));
+ return trimmedLN;
+ }
+ }
+
+ // Output
+ public void writeTo(DataOutputStream stream) throws IOException {
+ assert frozen;
+ stream.writeInt(getSize());
+ codeArray.writeTo(stream);
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JCodeAttribute.java b/src/fjbg/ch/epfl/lamp/fjbg/JCodeAttribute.java
new file mode 100644
index 0000000000..79afaded44
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JCodeAttribute.java
@@ -0,0 +1,89 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Code attribute, containing code of methods.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public class JCodeAttribute extends JAttribute {
+ protected final JCode code;
+
+ public JCodeAttribute(FJBGContext context, JClass clazz, JMethod owner) {
+ super(context, clazz);
+ this.code = owner.getCode();
+
+ assert clazz == owner.getOwner();
+ }
+
+ public JCodeAttribute(FJBGContext context,
+ JClass clazz,
+ Object owner,
+ String name,
+ int size,
+ DataInputStream stream)
+ throws IOException {
+ super(context, clazz);
+
+ stream.readShort(); // skip max stack size
+ stream.readShort(); // skip max locals
+
+ this.code = context.JCode(clazz, (JMethod)owner, stream);
+
+ int handlersCount = stream.readShort();
+ for (int i = 0; i < handlersCount; ++i)
+ code.addExceptionHandler(code.new ExceptionHandler(stream));
+
+ List/*<JAttribute>*/ attributes =
+ JAttribute.readFrom(context, clazz, owner, stream);
+ Iterator attrIt = attributes.iterator();
+ while (attrIt.hasNext())
+ code.addAttribute((JAttribute)attrIt.next());
+
+ assert name.equals(getName());
+ }
+
+ public String getName() { return "Code"; }
+
+ protected int getSize() {
+ int handlersNum = code.getExceptionHandlers().size();
+
+ int attrsSize = 0;
+ Iterator attrsIt = code.getAttributes().iterator();
+ while (attrsIt.hasNext()) {
+ JAttribute attr = (JAttribute)attrsIt.next();
+ attrsSize += attr.getSize() + 6;
+ }
+
+ return 2 // max stack
+ + 2 // max locals
+ + 4 // code size
+ + code.getSize() // code
+ + 2 // exception table size
+ + 8 * handlersNum // exception table
+ + 2 // attributes count
+ + attrsSize; // attributes
+ }
+
+ protected void writeContentsTo(DataOutputStream stream) throws IOException {
+ List/*<JExceptionHandler>*/ handlers = code.getExceptionHandlers();
+
+ stream.writeShort(code.getMaxStackSize());
+ stream.writeShort(code.getOwner().getMaxLocals());
+
+ code.writeTo(stream);
+
+ stream.writeShort(handlers.size());
+ Iterator handlerIt = handlers.iterator();
+ while (handlerIt.hasNext())
+ ((JCode.ExceptionHandler)handlerIt.next()).writeTo(stream);
+
+ JAttribute.writeTo(code.getAttributes(), stream);
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JCodeIterator.java b/src/fjbg/ch/epfl/lamp/fjbg/JCodeIterator.java
new file mode 100644
index 0000000000..d4effed412
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JCodeIterator.java
@@ -0,0 +1,374 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import ch.epfl.lamp.util.ByteArray;
+
+/**
+ * Iterator used to examine the contents of an instruction list.
+ *
+ * @version 1.0
+ * @author Michel Schinz, Thomas Friedli
+ */
+
+public class JCodeIterator {
+ protected final JCode code;
+ protected final JConstantPool pool;
+ protected final ByteArray codeArray;
+
+ protected int pc;
+ protected JOpcode opcode;
+
+ /**
+ * Creates a new code iterator with its instruction list
+ * and its pc initialized to a given value.
+ */
+ public JCodeIterator(JCode code, int pc) {
+ this.code = code;
+ this.pool = code.getOwner().getOwner().getConstantPool();
+ this.codeArray = code.codeArray;
+ this.pc = pc;
+ setOpcode();
+ }
+
+ public JCodeIterator(JCode code) {
+ this(code, 0);
+ }
+
+ /**
+ * Get the current program counter.
+ * @return The current program counter.
+ */
+ public int getPC() { return pc; }
+
+ /**
+ * Searches the type of the instruction positionned at the
+ * current address and updates the current instruction.
+ */
+ protected void setOpcode() {
+ // TODO : check if the current pc is the beginning
+ // of an instruction
+ opcode = isValid() ? JOpcode.OPCODES[codeArray.getU1(pc)] : null;
+ }
+
+ /**
+ * Returns the opcode of the current instruction.
+ * @return The opcode of the current instruction.
+ */
+ public JOpcode getOpcode() {
+ return opcode;
+ }
+
+ /**
+ * Updates the program counter to an given value.
+ * @param pc The new value of the program counter.
+ */
+ public void moveTo(int pc) {
+ this.pc = pc;
+ setOpcode();
+ }
+
+ /**
+ * Check the validity of the iterator.
+ * @return true iff the iterator points to a valid address.
+ */
+ public boolean isValid() {
+ return pc < codeArray.getSize();
+ }
+
+ /**
+ * Updates the current instruction with the next one in the
+ * sense of their position in the code.
+ */
+ public void moveToNext() {
+ moveTo(pc + getInstructionSize());
+ }
+
+ /**
+ * Updates the current instruction with a specific successor
+ * of it.
+ * @param succ The index of the wanted successor in the list of
+ * the successors of the current instruction.
+ */
+ public void moveToSuccessor(int succ) {
+ moveTo(getSuccessorPC(succ));
+ }
+
+ /**
+ * Updates the current instruction with the one positionned
+ * at a given index relatively to the actual program counter
+ * @param offset The relative position of the instruction
+ * compared with the position of the current one
+ */
+ public void moveRelatively(int offset) {
+ moveTo(pc + offset);
+ }
+
+ /**
+ * Returns the size in bytes of the current instruction.
+ * @return The size in bytes of the current instruction.
+ */
+ public int getInstructionSize() {
+ if (opcode.size != JOpcode.UNKNOWN) {
+ return opcode.size;
+ } else if (opcode == JOpcode.TABLESWITCH) {
+ int lowOffset = 1 + pad4(pc + 1) + 4;
+ int low = codeArray.getS4(pc + lowOffset);
+ int high = codeArray.getS4(pc + lowOffset + 4);
+ return lowOffset + 8 + 4 * (high - low + 1);
+ } else if (opcode == JOpcode.LOOKUPSWITCH) {
+ int npairsOffset = 1 + pad4(pc + 1) + 4;
+ int npairs = codeArray.getS4(pc + npairsOffset);
+ return npairsOffset + 4 + 8 * npairs;
+ } else if (opcode == JOpcode.WIDE) {
+ if (codeArray.getU1(pc + 1) == JOpcode.cIINC)
+ return 6;
+ else
+ return 4;
+ } else
+ throw new Error("Unknown size for instruction " + opcode);
+ }
+
+ /**
+ * Returns the number of successors of the current instruction.
+ * @return The number of successors of the current instruction.
+ */
+ public int getSuccessorCount() {
+ if (opcode.successorCount != JOpcode.UNKNOWN) {
+ return opcode.successorCount;
+ } else if (opcode == JOpcode.TABLESWITCH) {
+ int lowPos = pc + 1 + pad4(pc + 1) + 4;
+ return 1 // default case
+ + codeArray.getS4(lowPos + 4) // value of HIGH field
+ - codeArray.getS4(lowPos) + 1; // value of LOW field
+ } else if (opcode == JOpcode.LOOKUPSWITCH) {
+ int npairsPos = pc + 1 + pad4(pc + 1) + 4;
+ return 1 + codeArray.getS4(npairsPos);
+ } else
+ throw new Error("Unknown successors for instruction " + opcode);
+ }
+
+ /**
+ * Returns the address of the successor of the current instruction
+ * given its index in the list of successors of the current
+ * instruction.
+ * @param index The index of the wanted successor in the list of
+ * the successors of the current instruction.
+ * @return The address of the specific successor.
+ */
+ public int getSuccessorPC(int index) {
+ assert (index >= 0) && (index < getSuccessorCount()) : index;
+
+ switch (opcode.jumpKind) {
+ case JOpcode.JMP_NEXT:
+ return pc + getInstructionSize();
+ case JOpcode.JMP_ALWAYS_S2_OFFSET:
+ return pc + codeArray.getS2(pc + 1);
+ case JOpcode.JMP_ALWAYS_S4_OFFSET:
+ return pc + codeArray.getS4(pc + 1);
+ case JOpcode.JMP_MAYBE_S2_OFFSET:
+ if (index == 0)
+ return pc + getInstructionSize();
+ else
+ return pc + codeArray.getS2(pc + 1);
+ case JOpcode.JMP_TABLE: {
+ int defaultPos = pc + 1 + pad4(pc + 1);
+ if (index == 0)
+ return pc + codeArray.getS4(defaultPos);
+ else
+ return pc + codeArray.getS4(defaultPos + 3*4 + 4 * (index - 1));
+ }
+ case JOpcode.JMP_LOOKUP: {
+ int defaultPos = pc + 1 + pad4(pc + 1);
+ if (index == 0)
+ return pc + codeArray.getS4(defaultPos);
+ else
+ return pc + codeArray.getS4(defaultPos + 2*4 + 4 + 8 * (index - 1));
+ }
+ default:
+ throw new Error();
+ }
+ }
+
+ /**
+ * Returns the total size of data words put on the stack by the current
+ * instruction.
+ * @return The total size of data words put on the stack by the current
+ * instruction.
+ */
+ public int getProducedDataSize() {
+ if (opcode.getProducedDataTypes() == JOpcode.UNKNOWN_TYPE) {
+ switch (opcode.code) {
+ case JOpcode.cLDC: case JOpcode.cLDC_W: case JOpcode.cBALOAD:
+ return 1;
+ case JOpcode.cLDC2_W: case JOpcode.cDUP: case JOpcode.cSWAP:
+ return 2;
+ case JOpcode.cDUP_X1:
+ return 3;
+ case JOpcode.cDUP_X2: case JOpcode.cDUP2:
+ return 4;
+ case JOpcode.cDUP2_X1:
+ return 5;
+ case JOpcode.cDUP2_X2:
+ return 6;
+ case JOpcode.cGETSTATIC: case JOpcode.cGETFIELD: {
+ JConstantPool.FieldOrMethodRefEntry entry =
+ (JConstantPool.FieldOrMethodRefEntry)
+ pool.lookupEntry(codeArray.getU2(pc + 1));
+ return JType.parseSignature(entry.getSignature()).getSize();
+ }
+ case JOpcode.cWIDE : {
+ int op = codeArray.getU1(pc + 1);
+ if (op >= JOpcode.cILOAD && op <= JOpcode.cALOAD) {
+ JOpcode opcode2 = JOpcode.OPCODES[op];
+ return JType.getTotalSize(opcode2.getProducedDataTypes());
+ } else if (op >= JOpcode.cISTORE && op <= JOpcode.cASTORE)
+ return 0;
+ else return 0; // (IINC)
+ }
+ default :
+ throw new Error(opcode.toString());
+ }
+ } else
+ return JType.getTotalSize(opcode.getProducedDataTypes());
+ }
+
+ /**
+ * Returns the total size of data words taken from the stack by the current
+ * instruction.
+ * @return The total size of data words taken from the stack by the current
+ * instruction.
+ */
+ public int getConsumedDataSize() {
+ if (opcode.getConsumedDataTypes() != JOpcode.UNKNOWN_TYPE)
+ return JType.getTotalSize(opcode.getConsumedDataTypes());
+ else {
+ switch (opcode.code) {
+ case JOpcode.cPOP: case JOpcode.cDUP:
+ return 1;
+ case JOpcode.cPOP2: case JOpcode.cSWAP:
+ case JOpcode.cDUP_X1: case JOpcode.cDUP2:
+ return 2;
+ case JOpcode.cDUP_X2: case JOpcode.cDUP2_X1:
+ return 3;
+ case JOpcode.cDUP2_X2:
+ return 4;
+ case JOpcode.cPUTSTATIC: case JOpcode.cPUTFIELD: {
+ JConstantPool.FieldOrMethodRefEntry entry =
+ (JConstantPool.FieldOrMethodRefEntry)
+ pool.lookupEntry(codeArray.getU2(pc + 1));
+ return JType.parseSignature(entry.getSignature()).getSize();
+ }
+ case JOpcode.cINVOKEVIRTUAL: case JOpcode.cINVOKESPECIAL:
+ case JOpcode.cINVOKESTATIC: case JOpcode.cINVOKEINTERFACE : {
+ JConstantPool.FieldOrMethodRefEntry entry =
+ (JConstantPool.FieldOrMethodRefEntry)
+ pool.lookupEntry(codeArray.getU2(pc + 1));
+ JMethodType tp = (JMethodType)
+ JType.parseSignature(entry.getSignature());
+ return tp.getArgsSize()
+ + (opcode == JOpcode.INVOKESTATIC ? 0 : 1);
+ }
+ case JOpcode.cWIDE : {
+ int op = codeArray.getU1(pc + 1);
+ if (op >= JOpcode.cILOAD && op <= JOpcode.cALOAD)
+ return 0;
+ else if (op >= JOpcode.cISTORE && op <= JOpcode.cASTORE) {
+ JOpcode opcode2 = JOpcode.OPCODES[op];
+ return JType.getTotalSize(opcode2.getConsumedDataTypes());
+ } else
+ return 0; // (IINC)
+ }
+ case JOpcode.cMULTIANEWARRAY :
+ return codeArray.getU1(pc + 3);
+ default:
+ throw new Error(opcode.toString());
+ }
+ }
+ }
+
+ /**
+ * Returns the number of data types put on the stack by the current
+ * instruction.
+ * @return The number of data types put on the stack by the current
+ * instruction.
+ */
+ public int getProducedDataTypesNumber() {
+ if (opcode.getProducedDataTypes() != JOpcode.UNKNOWN_TYPE)
+ return opcode.getProducedDataTypes().length;
+ else {
+ switch (opcode.code) {
+ case JOpcode.cLDC: case JOpcode.cLDC_W: case JOpcode.cLDC2_W:
+ case JOpcode.cBALOAD: case JOpcode.cGETSTATIC:
+ case JOpcode.cGETFIELD:
+ return 1;
+ case JOpcode.cDUP: case JOpcode.cSWAP:
+ return 2;
+ case JOpcode.cDUP_X1:
+ return 3;
+ case JOpcode.cWIDE: {
+ int op = codeArray.getU1(pc + 1);
+ if (op >= JOpcode.cILOAD && op <= JOpcode.cALOAD)
+ return 1;
+ else if (op >= JOpcode.cISTORE && op <= JOpcode.cASTORE)
+ return 0;
+ else
+ return 0; // (IINC)
+ }
+ default:
+ throw new Error("JOpcode implementation error");
+ }
+ }
+ }
+
+ /**
+ * Returns the number of data types taken from the stack by the current
+ * instruction.
+ * @return The number of data types taken from the stack by the current
+ * instruction.
+ */
+// public int getConsumedDataTypesNumber() {
+// if (opcode.getConsumedDataTypes() == JOpcode.UNKNOWN_TYPE) {
+// switch (opcode.code) {
+// case 87 : return 1; // POP
+// case 88 : return 2; // POP2
+// case 89 : return 1; // DUP
+// case 90 : return 2; // DUP_X1
+// case 91 : // DUP_X2
+// case 92 : // DUP2
+// case 93 : // DUP2_X1
+// case 94 : // DUP2_X2
+// throw new UnsupportedOperationException("Opcode " + opcode.name
+// + " has a stack-dependant"
+// + " data types consumption");
+// case 95 : return 2; // SWAP
+// case 179 : return 1; // PUTSTATIC
+// case 181 : return 1; // PUTFIELD
+// case 182 : // INVOKEVIRTUAL
+// case 183 : // INVOKESPECIAL
+// case 185 : // INVOKEINTERFACE
+// s = epool.getClassMethodRef(codeArray.getU2(pc + 1)).split(" ")[3];
+// return ((JMethodType)JType.parseSignature(s)).argTypes.length + 1;
+// case 184 : // INVOKESTATIC
+// s = epool.getClassMethodRef(codeArray.getU2(pc + 1)).split(" ")[3];
+// return ((JMethodType)JType.parseSignature(s)).argTypes.length;
+// case 196 : // WIDE
+// int op = codeArray.getU1(pc + 1);
+// if (op >= 21 && op <= 25) return 0; // (xLOAD)
+// else if (op >= 54 && op <= 58) // (xSTORE)
+// return JOpcode.OPCODES[op].getConsumedDataTypes().length;
+// else return 0; // (IINC)
+// case 197 : return codeArray.getU1(pc + 3); // MULTIANEWARRAY
+// default : throw new Error("JOpcode implementation error");
+// }
+// } else return opcode.getConsumedDataTypes().length;
+// }
+
+
+ // Return the number between 0 and 3 which, if added to the given
+ // value, would yield a multiple of 4.
+ protected int[] padding = { 0, 3, 2, 1 };
+ protected int pad4(int value) {
+ return padding[value % 4];
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JConstantPool.java b/src/fjbg/ch/epfl/lamp/fjbg/JConstantPool.java
new file mode 100644
index 0000000000..911acd18da
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JConstantPool.java
@@ -0,0 +1,608 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Constant pool, holding constants for a Java class file.
+ *
+ * @author Michel Schinz
+ * @version 2.0
+ */
+
+public class JConstantPool {
+ protected boolean frozen = false;
+
+ protected HashMap/*<Entry,Integer>*/ entryToIndex = new HashMap();
+ protected Entry[] indexToEntry;
+ protected int currIndex;
+
+ public static final short CONSTANT_Utf8 = 1;
+ public static final short CONSTANT_Integer = 3;
+ public static final short CONSTANT_Float = 4;
+ public static final short CONSTANT_Long = 5;
+ public static final short CONSTANT_Double = 6;
+ public static final short CONSTANT_Class = 7;
+ public static final short CONSTANT_String = 8;
+ public static final short CONSTANT_Fieldref = 9;
+ public static final short CONSTANT_Methodref = 10;
+ public static final short CONSTANT_InterfaceMethodref = 11;
+ public static final short CONSTANT_NameAndType = 12;
+
+ protected JConstantPool(FJBGContext context) {
+ indexToEntry = new Entry[8];
+ currIndex = 1;
+ }
+
+ protected JConstantPool(FJBGContext context, DataInputStream stream)
+ throws IOException {
+ int count = stream.readShort();
+ indexToEntry = new EntryIndex[count];
+
+ currIndex = 1;
+ while (currIndex < count) {
+ EntryIndex e;
+ int tag = stream.readByte();
+
+ switch (tag) {
+ case CONSTANT_Utf8:
+ e = new Utf8Entry(stream);
+ break;
+ case CONSTANT_Integer:
+ e = new IntegerEntry(stream);
+ break;
+ case CONSTANT_Float:
+ e = new FloatEntry(stream);
+ break;
+ case CONSTANT_Long:
+ e = new LongEntry(stream);
+ break;
+ case CONSTANT_Double:
+ e = new DoubleEntry(stream);
+ break;
+ case CONSTANT_Class:
+ e = new DescriptorEntryIndex(stream);
+ break;
+ case CONSTANT_String:
+ e = new StringEntryIndex(stream);
+ break;
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ e = new FieldOrMethodRefEntryIndex(tag, stream);
+ break;
+ case CONSTANT_NameAndType:
+ e = new NameAndTypeEntryIndex(stream);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown entry in pool: " + tag);
+ }
+ indexToEntry[currIndex] = e;
+ currIndex += e.getSize();
+ }
+ }
+
+ public void freeze() { frozen = true; }
+
+ /**
+ * Returns a string representing the type of an entry
+ * knowing its tag
+ * @param tag The tag representing the type of the
+ * constant pool entry
+ */
+ public String getEntryType(int tag) {
+ switch (tag) {
+ case 4 : return "Utf8";
+ case 5 : return "Integer";
+ case 6 : return "Float";
+ case 7 : return "Long";
+ case 8 : return "Double";
+ case 9 : return "Class";
+ case 10 : return "String";
+ case 11 : return "Fieldref";
+ case 12 : return "Methodref";
+ case 13 : return "InterfaceMethodref";
+ case 14 : return "NameAndType";
+ default : throw new Error("invalid constant pool tag : " + tag);
+ }
+ }
+
+ public int addClass(String className) {
+ return addDescriptor(className.replace('.', '/'));
+ }
+
+ public String lookupClass(int index) {
+ DescriptorEntry entry = (DescriptorEntry)lookupEntry(index);
+ return entry.getValue().replace('/', '.');
+ }
+
+ public int addDescriptor(JReferenceType type) {
+ return addDescriptor(type.getDescriptor());
+ }
+
+ protected int addDescriptor(String name) {
+ return addEntry(new DescriptorEntryValue(name));
+ }
+
+ public int addClassMethodRef(String className,
+ String methodName,
+ String signature) {
+ return addMethodRef(true, className, methodName, signature);
+ }
+
+ public int addInterfaceMethodRef(String className,
+ String methodName,
+ String signature) {
+ return addMethodRef(false, className, methodName, signature);
+ }
+
+ public int addMethodRef(boolean isClass,
+ String className,
+ String methodName,
+ String signature) {
+ return addEntry(new FieldOrMethodRefEntryValue(isClass
+ ? CONSTANT_Methodref
+ : CONSTANT_InterfaceMethodref,
+ className,
+ methodName,
+ signature));
+ }
+
+ public int addFieldRef(String className,
+ String fieldName,
+ String signature) {
+ return addEntry(new FieldOrMethodRefEntryValue(CONSTANT_Fieldref,
+ className,
+ fieldName,
+ signature));
+ }
+
+ public int addInteger(int value) {
+ return addEntry(new IntegerEntry(value));
+ }
+
+ public int addFloat(float value) {
+ return addEntry(new FloatEntry(value));
+ }
+
+ public int addLong(long value) {
+ return addEntry(new LongEntry(value));
+ }
+
+ public int addDouble(double value) {
+ return addEntry(new DoubleEntry(value));
+ }
+
+ public int addString(String value) {
+ return addEntry(new StringEntryValue(value));
+ }
+
+ public int addNameAndType(String name, String descriptor) {
+ return addEntry(new NameAndTypeEntryValue(name, descriptor));
+ }
+
+ public int addUtf8(String value) {
+ return addEntry(new Utf8Entry(value));
+ }
+
+ public String lookupUtf8(int index) {
+ Utf8Entry entry = (Utf8Entry)lookupEntry(index);
+ return entry.getValue();
+ }
+
+ protected int addEntry(EntryValue e) {
+ assert !frozen;
+
+ Integer idx = (Integer)entryToIndex.get(e);
+ if (idx != null)
+ return idx.intValue();
+
+ e.addChildren();
+
+ int index = currIndex;
+ currIndex += e.getSize();
+
+ entryToIndex.put(e, new Integer(index));
+ if (index >= indexToEntry.length) {
+ Entry[] newI2E = new Entry[indexToEntry.length * 2];
+ System.arraycopy(indexToEntry, 0, newI2E, 0, indexToEntry.length);
+ indexToEntry = newI2E;
+ }
+ indexToEntry[index] = e;
+ return index;
+ }
+
+ public Entry lookupEntry(int index) {
+ assert index > 0 && index < currIndex
+ : "invalid index: " + index;
+ assert indexToEntry[index] != null
+ : "invalid index (null contents): " + index;
+ return indexToEntry[index];
+ }
+
+ public void writeTo(DataOutputStream stream) throws IOException {
+ if (! frozen) freeze();
+
+ stream.writeShort(currIndex);
+ for (int i = 0; i < currIndex; ++i) {
+ Entry entry = indexToEntry[i];
+ if (entry != null) {
+ stream.writeByte(entry.getTag());
+ entry.writeContentsTo(stream);
+ }
+ }
+ }
+
+ /// Classes for the various kinds of entries
+ //////////////////////////////////////////////////////////////////////
+
+ public interface Entry {
+ public int getTag();
+
+ int getSize();
+ void writeContentsTo(DataOutputStream stream) throws IOException;
+ }
+
+ protected interface EntryValue extends Entry {
+ abstract void addChildren();
+ }
+
+ protected interface EntryIndex extends Entry {
+ abstract void fetchChildren();
+ }
+
+ abstract protected class ChildlessEntry implements EntryValue, EntryIndex {
+ public void addChildren() {}
+ public void fetchChildren() {}
+ }
+
+ public class IntegerEntry extends ChildlessEntry implements Entry {
+ private final int value;
+ public IntegerEntry(int value) { this.value = value; }
+ public IntegerEntry(DataInputStream stream) throws IOException {
+ this(stream.readInt());
+ }
+
+ public int hashCode() { return value; }
+ public boolean equals(Object o) {
+ return o instanceof IntegerEntry && ((IntegerEntry)o).value == value;
+ }
+
+ public int getTag() { return CONSTANT_Integer; }
+ public int getValue() { return value; }
+
+ public int getSize() { return 1; }
+ public void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeInt(value);
+ }
+ }
+
+ public class FloatEntry extends ChildlessEntry implements Entry {
+ private final float value;
+ public FloatEntry(float value) { this.value = value; }
+ public FloatEntry(DataInputStream stream) throws IOException {
+ this(stream.readFloat());
+ }
+
+ public int hashCode() { return (int)value; }
+ public boolean equals(Object o) {
+ return o instanceof FloatEntry && ((FloatEntry)o).value == value;
+ }
+
+ public int getTag() { return CONSTANT_Float; }
+ public float getValue() { return value; }
+
+ public int getSize() { return 1; }
+ public void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeFloat(value);
+ }
+ }
+
+ public class LongEntry extends ChildlessEntry implements Entry {
+ private final long value;
+ public LongEntry(long value) { this.value = value; }
+ public LongEntry(DataInputStream stream) throws IOException {
+ this(stream.readLong());
+ }
+
+ public int hashCode() { return (int)value; }
+ public boolean equals(Object o) {
+ return o instanceof LongEntry && ((LongEntry)o).value == value;
+ }
+
+ public int getTag() { return CONSTANT_Long; }
+ public long getValue() { return value; }
+
+ public int getSize() { return 2; }
+ public void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeLong(value);
+ }
+ }
+
+ public class DoubleEntry extends ChildlessEntry implements Entry {
+ private final double value;
+ public DoubleEntry(double value) { this.value = value; }
+ public DoubleEntry(DataInputStream stream) throws IOException {
+ this(stream.readDouble());
+ }
+
+ public int hashCode() { return (int)value; }
+ public boolean equals(Object o) {
+ return o instanceof DoubleEntry && ((DoubleEntry)o).value == value;
+ }
+
+ public int getTag() { return CONSTANT_Double; }
+ public double getValue() { return value; }
+
+ public int getSize() { return 2; }
+ public void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeDouble(value);
+ }
+ }
+
+ public class Utf8Entry extends ChildlessEntry implements Entry {
+ private final String value;
+ public Utf8Entry(String value) { this.value = value.intern(); }
+ public Utf8Entry(DataInputStream stream) throws IOException {
+ this(stream.readUTF());
+ }
+
+ public int hashCode() { return value.hashCode(); }
+ public boolean equals(Object o) {
+ return o instanceof Utf8Entry && ((Utf8Entry)o).value == value;
+ }
+
+ public int getTag() { return CONSTANT_Utf8; }
+ public String getValue() { return value; }
+
+ public int getSize() { return 1; }
+ public void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeUTF(value);
+ }
+ }
+
+ abstract public class StringEntry implements Entry {
+ protected String value;
+ protected int valueIndex;
+
+ public int hashCode() {
+ assert value != null;
+ return value.hashCode();
+ }
+ public boolean equals(Object o) {
+ return o instanceof StringEntry && ((StringEntry)o).value == value;
+ }
+
+ public int getTag() { return CONSTANT_String; }
+ public String getValue() { return value; }
+
+ public int getSize() { return 1; }
+ public void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeShort(valueIndex);
+ }
+ }
+
+ public class StringEntryValue extends StringEntry implements EntryValue {
+ public StringEntryValue(String value) {
+ this.value = value.intern();
+ }
+ public void addChildren() {
+ valueIndex = addUtf8(value);
+ }
+ }
+
+ public class StringEntryIndex extends StringEntry implements EntryIndex {
+ public StringEntryIndex(int valueIndex) {
+ this.valueIndex = valueIndex;
+ }
+ public StringEntryIndex(DataInputStream stream) throws IOException {
+ this(stream.readShort());
+ }
+ public String getValue() {
+ if (value == null) fetchChildren();
+ return super.getValue();
+ }
+ public void fetchChildren() {
+ value = lookupUtf8(valueIndex);
+ }
+ }
+
+ abstract public class DescriptorEntry implements Entry {
+ protected String name;
+ protected int nameIndex;
+
+ public int hashCode() {
+ assert name != null;
+ return name.hashCode();
+ }
+ public boolean equals(Object o) {
+ return o instanceof DescriptorEntry && ((DescriptorEntry)o).name == name;
+ }
+
+ public int getTag() { return CONSTANT_Class; }
+ public String getValue() { return name; }
+
+ public int getSize() { return 1; }
+ public void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeShort(nameIndex);
+ }
+ }
+
+ protected class DescriptorEntryValue
+ extends DescriptorEntry
+ implements EntryValue {
+ public DescriptorEntryValue(String name) { this.name = name.intern(); }
+ public void addChildren() {
+ nameIndex = addUtf8(name);
+ }
+ }
+
+ protected class DescriptorEntryIndex
+ extends DescriptorEntry
+ implements EntryIndex {
+ public DescriptorEntryIndex(int nameIndex) { this.nameIndex = nameIndex; }
+ public DescriptorEntryIndex(DataInputStream stream) throws IOException {
+ this(stream.readShort());
+ }
+ public String getValue() {
+ if (name == null) fetchChildren();
+ return super.getValue();
+ }
+ public void fetchChildren() {
+ name = lookupUtf8(nameIndex);
+ }
+ }
+
+ abstract public class FieldOrMethodRefEntry implements Entry {
+ private final int tag;
+ protected String className, thingName, signature;
+ protected int classIndex, nameAndTypeIndex;
+
+ public FieldOrMethodRefEntry(int tag) {
+ assert tag == CONSTANT_Fieldref
+ || tag == CONSTANT_Methodref
+ || tag == CONSTANT_InterfaceMethodref;
+
+ this.tag = tag;
+ }
+
+ public int hashCode() {
+ return tag
+ + className.hashCode()
+ + thingName.hashCode()
+ + signature.hashCode();
+ }
+ public boolean equals(Object o) {
+ return o instanceof FieldOrMethodRefEntry
+ && ((FieldOrMethodRefEntry)o).tag == tag
+ && ((FieldOrMethodRefEntry)o).className == className
+ && ((FieldOrMethodRefEntry)o).thingName == thingName
+ && ((FieldOrMethodRefEntry)o).signature == signature;
+ }
+
+ public int getTag() { return tag; }
+ public String getClassName() { return className; }
+ public String getFieldOrMethodName() { return thingName; }
+ public String getSignature() { return signature; }
+
+ public int getSize() { return 1; }
+ public void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeShort(classIndex);
+ stream.writeShort(nameAndTypeIndex);
+ }
+ }
+
+ protected class FieldOrMethodRefEntryValue
+ extends FieldOrMethodRefEntry
+ implements EntryValue {
+ public FieldOrMethodRefEntryValue(int tag,
+ String className,
+ String thingName,
+ String signature) {
+ super(tag);
+ this.className = className.intern();
+ this.thingName = thingName.intern();
+ this.signature = signature.intern();
+ }
+
+ public void addChildren() {
+ classIndex = addClass(className);
+ nameAndTypeIndex = addNameAndType(thingName, signature);
+ }
+ }
+
+ protected class FieldOrMethodRefEntryIndex
+ extends FieldOrMethodRefEntry
+ implements EntryIndex {
+ public FieldOrMethodRefEntryIndex(int tag,
+ int classIndex,
+ int nameAndTypeIndex) {
+ super(tag);
+ this.classIndex = classIndex;
+ this.nameAndTypeIndex = nameAndTypeIndex;
+ }
+ public FieldOrMethodRefEntryIndex(int tag, DataInputStream stream)
+ throws IOException {
+ this(tag, stream.readShort(), stream.readShort());
+ }
+ public String getClassName() {
+ if (className == null) fetchChildren();
+ return super.getClassName();
+ }
+ public String getFieldOrMethodName() {
+ if (thingName == null) fetchChildren();
+ return super.getFieldOrMethodName();
+ }
+ public String getSignature() {
+ if (signature == null) fetchChildren();
+ return super.getSignature();
+ }
+ public void fetchChildren() {
+ className = lookupClass(classIndex);
+ NameAndTypeEntry nat = (NameAndTypeEntry)lookupEntry(nameAndTypeIndex);
+ thingName = nat.getName();
+ signature = nat.getDescriptor();
+ }
+ }
+
+ abstract public class NameAndTypeEntry implements Entry {
+ protected String name, descriptor;
+ protected int nameIndex, descriptorIndex;
+
+ public int hashCode() { return name.hashCode() + descriptor.hashCode(); }
+ public boolean equals(Object o) {
+ return o instanceof NameAndTypeEntry
+ && ((NameAndTypeEntry)o).name == name
+ && ((NameAndTypeEntry)o).descriptor == descriptor;
+ }
+
+ public int getTag() { return CONSTANT_NameAndType; }
+ public String getName() { return name; }
+ public String getDescriptor() { return descriptor; }
+
+ public int getSize() { return 1; }
+ public void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeShort(nameIndex);
+ stream.writeShort(descriptorIndex);
+ }
+ }
+
+ protected class NameAndTypeEntryValue
+ extends NameAndTypeEntry
+ implements EntryValue {
+ public NameAndTypeEntryValue(String name, String descriptor) {
+ this.name = name.intern();
+ this.descriptor = descriptor.intern();
+ }
+ public void addChildren() {
+ nameIndex = addUtf8(name);
+ descriptorIndex = addUtf8(descriptor);
+ }
+ }
+
+ protected class NameAndTypeEntryIndex
+ extends NameAndTypeEntry
+ implements EntryIndex {
+ public NameAndTypeEntryIndex(int nameIndex, int descriptorIndex) {
+ this.nameIndex = nameIndex;
+ this.descriptorIndex = descriptorIndex;
+ }
+ public NameAndTypeEntryIndex(DataInputStream stream) throws IOException {
+ this(stream.readShort(), stream.readShort());
+ }
+ public String getName() {
+ if (name == null) fetchChildren();
+ return super.getName();
+ }
+ public String getDescriptor() {
+ if (descriptor == null) fetchChildren();
+ return super.getDescriptor();
+ }
+ public void fetchChildren() {
+ name = lookupUtf8(nameIndex);
+ descriptor = lookupUtf8(descriptorIndex);
+ }
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java b/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java
new file mode 100644
index 0000000000..b8f29a6a2b
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java
@@ -0,0 +1,614 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Extended list of instructions, providing pseudo-instructions which
+ * are easier to use than the standard ones.
+ *
+ * @author Michel Schinz, Thomas Friedli
+ * @version 1.0
+ */
+
+public class JExtendedCode extends JCode {
+ public final static int COND_EQ = 0;
+ public final static int COND_NE = 1;
+ public final static int COND_LT = 2;
+ public final static int COND_GE = 3;
+ public final static int COND_GT = 4;
+ public final static int COND_LE = 5;
+
+ private final JOpcode[] forbidden = new JOpcode[0];
+ private final JOpcode[] nothingToDo = new JOpcode[0];
+
+ private final JOpcode[][][] typeConversions = {
+ {
+ /* T_BOOLEAN -> T_BOOLEAN */ nothingToDo,
+ /* T_BOOLEAN -> T_CHAR */ forbidden,
+ /* T_BOOLEAN -> T_FLOAT */ forbidden,
+ /* T_BOOLEAN -> T_DOUBLE */ forbidden,
+ /* T_BOOLEAN -> T_BYTE */ forbidden,
+ /* T_BOOLEAN -> T_SHORT */ forbidden,
+ /* T_BOOLEAN -> T_INT */ forbidden,
+ /* T_BOOLEAN -> T_LONG */ forbidden
+ },
+ {
+ /* T_CHAR -> T_BOOLEAN */ forbidden,
+ /* T_CHAR -> T_CHAR */ nothingToDo,
+ /* T_CHAR -> T_FLOAT */ {JOpcode.I2F},
+ /* T_CHAR -> T_DOUBLE */ {JOpcode.I2D},
+ /* T_CHAR -> T_BYTE */ {JOpcode.I2B},
+ /* T_CHAR -> T_SHORT */ {JOpcode.I2S},
+ /* T_CHAR -> T_INT */ nothingToDo,
+ /* T_CHAR -> T_LONG */ {JOpcode.I2L}
+ },
+ {
+ /* T_FLOAT -> T_BOOLEAN */ forbidden,
+ /* T_FLOAT -> T_CHAR */ {JOpcode.F2I, JOpcode.I2C},
+ /* T_FLOAT -> T_FLOAT */ nothingToDo,
+ /* T_FLOAT -> T_DOUBLE */ {JOpcode.F2D},
+ /* T_FLOAT -> T_BYTE */ {JOpcode.F2I, JOpcode.I2B},
+ /* T_FLOAT -> T_SHORT */ {JOpcode.F2I, JOpcode.I2S},
+ /* T_FLOAT -> T_INT */ {JOpcode.F2I},
+ /* T_FLOAT -> T_LONG */ {JOpcode.F2L}
+ },
+ {
+ /* T_DOUBLE -> T_BOOLEAN */ forbidden,
+ /* T_DOUBLE -> T_CHAR */ {JOpcode.D2I, JOpcode.I2C},
+ /* T_DOUBLE -> T_FLOAT */ {JOpcode.D2F},
+ /* T_DOUBLE -> T_DOUBLE */ nothingToDo,
+ /* T_DOUBLE -> T_BYTE */ {JOpcode.D2I, JOpcode.I2B},
+ /* T_DOUBLE -> T_SHORT */ {JOpcode.D2I, JOpcode.I2S},
+ /* T_DOUBLE -> T_INT */ {JOpcode.D2I},
+ /* T_DOUBLE -> T_LONG */ {JOpcode.D2L}
+ },
+ {
+ /* T_BYTE -> T_BOOLEAN */ forbidden,
+ /* T_BYTE -> T_CHAR */ {JOpcode.I2C},
+ /* T_BYTE -> T_FLOAT */ {JOpcode.I2F},
+ /* T_BYTE -> T_DOUBLE */ {JOpcode.I2D},
+ /* T_BYTE -> T_BYTE */ nothingToDo,
+ /* T_BYTE -> T_SHORT */ nothingToDo,
+ /* T_BYTE -> T_INT */ nothingToDo,
+ /* T_BYTE -> T_LONG */ {JOpcode.I2L}
+ },
+ {
+ /* T_SHORT -> T_BOOLEAN */ forbidden,
+ /* T_SHORT -> T_CHAR */ nothingToDo,
+ /* T_SHORT -> T_FLOAT */ {JOpcode.I2F},
+ /* T_SHORT -> T_DOUBLE */ {JOpcode.I2D},
+ /* T_SHORT -> T_BYTE */ {JOpcode.I2B},
+ /* T_SHORT -> T_SHORT */ nothingToDo,
+ /* T_SHORT -> T_INT */ nothingToDo,
+ /* T_SHORT -> T_LONG */ {JOpcode.I2L}
+ },
+ {
+ /* T_INT -> T_BOOLEAN */ forbidden,
+ /* T_INT -> T_CHAR */ {JOpcode.I2C},
+ /* T_INT -> T_FLOAT */ {JOpcode.I2F},
+ /* T_INT -> T_DOUBLE */ {JOpcode.I2D},
+ /* T_INT -> T_BYTE */ {JOpcode.I2B},
+ /* T_INT -> T_SHORT */ {JOpcode.I2S},
+ /* T_INT -> T_INT */ nothingToDo,
+ /* T_INT -> T_LONG */ {JOpcode.I2L}
+ },
+ {
+ /* T_LONG -> T_BOOLEAN */ forbidden,
+ /* T_LONG -> T_CHAR */ {JOpcode.L2I, JOpcode.I2C},
+ /* T_LONG -> T_FLOAT */ {JOpcode.L2F},
+ /* T_LONG -> T_DOUBLE */ {JOpcode.L2D},
+ /* T_LONG -> T_BYTE */ {JOpcode.L2I, JOpcode.I2B},
+ /* T_LONG -> T_SHORT */ {JOpcode.L2I, JOpcode.I2S},
+ /* T_LONG -> T_INT */ {JOpcode.L2I},
+ /* T_LONG -> T_LONG */ nothingToDo
+ }
+ };
+
+ public JExtendedCode(FJBGContext context,
+ JClass clazz,
+ JMethod owner) {
+ super(context, clazz, owner);
+ }
+
+ public void emitPUSH(boolean value) { emitPUSH(value ? 1 : 0); }
+ public void emitPUSH(Boolean value) { emitPUSH(value.booleanValue()); }
+
+ public void emitPUSH(byte value) { emitBIPUSH(value); }
+ public void emitPUSH(Byte value) { emitPUSH(value.byteValue()); }
+
+ public void emitPUSH(short value) { emitSIPUSH(value); }
+ public void emitPUSH(Short value) { emitPUSH(value.shortValue()); }
+
+ // TODO check that we do the right thing here
+ public void emitPUSH(char value) { emitPUSH((int)value); }
+ public void emitPUSH(Character value) { emitPUSH(value.charValue()); }
+
+ public void emitPUSH(int value) {
+ switch (value) {
+ case -1: emitICONST_M1(); break;
+ case 0: emitICONST_0(); break;
+ case 1: emitICONST_1(); break;
+ case 2: emitICONST_2(); break;
+ case 3: emitICONST_3(); break;
+ case 4: emitICONST_4(); break;
+ case 5: emitICONST_5(); break;
+ default: emitPUSH_index(pool.addInteger(value)); break;
+ }
+ }
+ public void emitPUSH(Integer value) { emitPUSH(value.intValue()); }
+
+ public void emitPUSH(long value) {
+ if (value == 0L)
+ emitLCONST_0();
+ else if (value == 1L)
+ emitLCONST_1();
+ else
+ emitLDC2_W(value);
+ }
+ public void emitPUSH(Long value) { emitPUSH(value.longValue()); }
+
+ public void emitPUSH(float value) {
+ if (value == 0.0F)
+ emitFCONST_0();
+ else if (value == 1.0F)
+ emitFCONST_1();
+ else if (value == 2.0F)
+ emitFCONST_2();
+ else
+ emitPUSH_index(pool.addFloat(value));
+ }
+ public void emitPUSH(Float value) { emitPUSH(value.floatValue()); }
+
+ public void emitPUSH(double value) {
+ if (value == 0.0)
+ emitDCONST_0();
+ else if (value == 1.0)
+ emitDCONST_1();
+ else
+ emitLDC2_W(value);
+ }
+ public void emitPUSH(Double value) { emitPUSH(value.doubleValue()); }
+
+ public void emitPUSH(String s) {
+ emitPUSH_index(pool.addString(s));
+ }
+
+ /** Pushes a class literal on the stack */
+ public void emitPUSH(JReferenceType type) {
+ assert owner.owner.major >= 49;
+ emitPUSH_index(pool.addClass(type.getDescriptor()));
+ }
+
+ protected void emitPUSH_index(int index) {
+ if (index <= 0xFF)
+ emitU1(JOpcode.LDC, index);
+ else
+ emitU2(JOpcode.LDC_W, index);
+ }
+
+ public void emitLOAD(int index, JType type) {
+ JOpcode opcode;
+
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN: case JType.T_BYTE: case JType.T_CHAR:
+ case JType.T_SHORT: case JType.T_INT:
+ switch (index) {
+ case 0: emitILOAD_0(); return;
+ case 1: emitILOAD_1(); return;
+ case 2: emitILOAD_2(); return;
+ case 3: emitILOAD_3(); return;
+ default: opcode = JOpcode.ILOAD;
+ } break;
+ case JType.T_FLOAT:
+ switch (index) {
+ case 0: emitFLOAD_0(); return;
+ case 1: emitFLOAD_1(); return;
+ case 2: emitFLOAD_2(); return;
+ case 3: emitFLOAD_3(); return;
+ default: opcode = JOpcode.FLOAD;
+ } break;
+ case JType.T_LONG:
+ switch (index) {
+ case 0: emitLLOAD_0(); return;
+ case 1: emitLLOAD_1(); return;
+ case 2: emitLLOAD_2(); return;
+ case 3: emitLLOAD_3(); return;
+ default: opcode = JOpcode.LLOAD;
+ } break;
+ case JType.T_DOUBLE:
+ switch (index) {
+ case 0: emitDLOAD_0(); return;
+ case 1: emitDLOAD_1(); return;
+ case 2: emitDLOAD_2(); return;
+ case 3: emitDLOAD_3(); return;
+ default: opcode = JOpcode.DLOAD;
+ } break;
+ case JType.T_ARRAY: case JType.T_OBJECT:
+ switch (index) {
+ case 0: emitALOAD_0(); return;
+ case 1: emitALOAD_1(); return;
+ case 2: emitALOAD_2(); return;
+ case 3: emitALOAD_3(); return;
+ default: opcode = JOpcode.ALOAD;
+ } break;
+ default:
+ throw new IllegalArgumentException("invalid type for load "+type);
+ }
+
+ if (index > 0xFF)
+ emitWIDE(opcode, index);
+ else
+ emitU1(opcode, index);
+ }
+ public void emitLOAD(JLocalVariable var) {
+ emitLOAD(var.index, var.type);
+ }
+
+ public void emitSTORE(int index, JType type) {
+ JOpcode opcode;
+
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN: case JType.T_BYTE: case JType.T_CHAR:
+ case JType.T_SHORT: case JType.T_INT:
+ switch (index) {
+ case 0: emitISTORE_0(); return;
+ case 1: emitISTORE_1(); return;
+ case 2: emitISTORE_2(); return;
+ case 3: emitISTORE_3(); return;
+ default: opcode = JOpcode.ISTORE;
+ } break;
+ case JType.T_FLOAT:
+ switch (index) {
+ case 0: emitFSTORE_0(); return;
+ case 1: emitFSTORE_1(); return;
+ case 2: emitFSTORE_2(); return;
+ case 3: emitFSTORE_3(); return;
+ default: opcode = JOpcode.FSTORE;
+ } break;
+ case JType.T_LONG:
+ switch (index) {
+ case 0: emitLSTORE_0(); return;
+ case 1: emitLSTORE_1(); return;
+ case 2: emitLSTORE_2(); return;
+ case 3: emitLSTORE_3(); return;
+ default: opcode = JOpcode.LSTORE;
+ } break;
+ case JType.T_DOUBLE:
+ switch (index) {
+ case 0: emitDSTORE_0(); return;
+ case 1: emitDSTORE_1(); return;
+ case 2: emitDSTORE_2(); return;
+ case 3: emitDSTORE_3(); return;
+ default: opcode = JOpcode.DSTORE;
+ } break;
+ case JType.T_ARRAY: case JType.T_OBJECT: case JType.T_ADDRESS:
+ switch (index) {
+ case 0: emitASTORE_0(); return;
+ case 1: emitASTORE_1(); return;
+ case 2: emitASTORE_2(); return;
+ case 3: emitASTORE_3(); return;
+ default: opcode = JOpcode.ASTORE;
+ } break;
+ default:
+ throw new IllegalArgumentException("invalid type for store "+type);
+ }
+
+ if (index > 0xFF)
+ emitWIDE(opcode, index);
+ else
+ emitU1(opcode, index);
+ }
+ public void emitSTORE(JLocalVariable var) {
+ emitSTORE(var.index, var.type);
+ }
+
+ public void emitALOAD(JType type) {
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN:
+ case JType.T_BYTE:
+ emitBALOAD();
+ break;
+ case JType.T_CHAR:
+ emitCALOAD();
+ break;
+ case JType.T_SHORT:
+ emitSALOAD();
+ break;
+ case JType.T_INT:
+ emitIALOAD();
+ break;
+ case JType.T_FLOAT:
+ emitFALOAD();
+ break;
+ case JType.T_LONG:
+ emitLALOAD();
+ break;
+ case JType.T_DOUBLE:
+ emitDALOAD();
+ break;
+ case JType.T_ARRAY:
+ case JType.T_OBJECT:
+ emitAALOAD();
+ break;
+ default:
+ throw new IllegalArgumentException("invalid type for aload " + type);
+ }
+ }
+
+ public void emitASTORE(JType type) {
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN:
+ case JType.T_BYTE:
+ emitBASTORE();
+ break;
+ case JType.T_CHAR:
+ emitCASTORE();
+ break;
+ case JType.T_SHORT:
+ emitSASTORE();
+ break;
+ case JType.T_INT:
+ emitIASTORE();
+ break;
+ case JType.T_FLOAT:
+ emitFASTORE();
+ break;
+ case JType.T_LONG:
+ emitLASTORE();
+ break;
+ case JType.T_DOUBLE:
+ emitDASTORE();
+ break;
+ case JType.T_ARRAY:
+ case JType.T_OBJECT:
+ emitAASTORE();
+ break;
+ default:
+ throw new IllegalArgumentException("invalid type for astore " + type);
+ }
+ }
+
+ public void emitRETURN(JType type) {
+ if (type.isValueType()) {
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN:
+ case JType.T_BYTE:
+ case JType.T_CHAR:
+ case JType.T_SHORT:
+ case JType.T_INT:
+ emitIRETURN();
+ break;
+ case JType.T_FLOAT:
+ emitFRETURN();
+ break;
+ case JType.T_LONG:
+ emitLRETURN();
+ break;
+ case JType.T_DOUBLE:
+ emitDRETURN();
+ break;
+ }
+ } else if (type.isArrayType() || type.isObjectType())
+ emitARETURN();
+ else if (type == JType.VOID)
+ emitRETURN();
+ else
+ throw new IllegalArgumentException("invalid type for RETURN " + type);
+ }
+
+ public void emitADD(JType type) {
+ switch (type.getTag()) {
+ case JType.T_BOOLEAN: case JType.T_BYTE: case JType.T_CHAR:
+ case JType.T_SHORT: case JType.T_INT:
+ emitIADD(); break;
+ case JType.T_FLOAT:
+ emitFADD(); break;
+ case JType.T_LONG:
+ emitLADD(); break;
+ case JType.T_DOUBLE:
+ emitDADD(); break;
+ }
+ }
+
+ /**
+ * Emits a basic type conversion instruction choosen according to the
+ * types given in parameter.
+ *
+ * @param fromType The type of the value to be cast into another type.
+ * @param toType The type the value will be cast into.
+ */
+ public void emitT2T(JType fromType, JType toType) {
+ assert fromType.getTag() >= JType.T_BOOLEAN
+ && fromType.getTag() <= JType.T_LONG
+ && toType.getTag() >= JType.T_BOOLEAN
+ && toType.getTag() <= JType.T_LONG;
+
+ JOpcode[] conv = typeConversions[fromType.getTag() - 4][toType.getTag() - 4];
+ if (conv == forbidden) {
+ throw new Error("inconvertible types : " + fromType.toString()
+ + " -> " + toType.toString());
+ } else if (conv != nothingToDo) {
+ for (int i = 0; i < conv.length; i++) {
+ emit(conv[i]);
+ }
+ }
+ }
+
+ public void emitIF(int cond, Label label) throws OffsetTooBigException {
+ assert cond >= COND_EQ && cond <= COND_LE;
+ emitU2(JOpcode.OPCODES[153 + cond], label.getOffset16(getPC() + 1, getPC()));
+ }
+ public void emitIF(int cond, int targetPC) throws OffsetTooBigException {
+ int offset = targetPC - getPC();
+ emitU2(JOpcode.OPCODES[153 + cond], offset);
+ }
+ public void emitIF(int cond) throws OffsetTooBigException {
+ emitIF(cond, 0);
+ }
+
+ public void emitIF_ICMP(int cond, Label label) throws OffsetTooBigException {
+ assert cond >= COND_EQ && cond <= COND_LE;
+ emitU2(JOpcode.OPCODES[159 + cond], label.getOffset16(getPC() + 1, getPC()));
+ }
+ public void emitIF_ICMP(int cond, int targetPC) throws OffsetTooBigException {
+ int offset = targetPC - getPC();
+ emitU2(JOpcode.OPCODES[159 + cond], offset);
+ }
+ public void emitIF_ICMP(int cond) throws OffsetTooBigException {
+ emitIF_ICMP(cond, 0);
+ }
+
+ public void emitIF_ACMP(int cond, Label label) throws OffsetTooBigException {
+ assert cond == COND_EQ || cond == COND_NE;
+ emitU2(JOpcode.OPCODES[165 + cond], label.getOffset16(getPC() + 1, getPC()));
+ }
+ public void emitIF_ACMP(int cond, int targetPC) throws OffsetTooBigException {
+ int offset = targetPC - getPC();
+ emitU2(JOpcode.OPCODES[165 + cond], offset);
+ }
+ public void emitIF_ACMP(int cond) throws OffsetTooBigException {
+ emitIF_ACMP(cond, 0);
+ }
+
+ public void emitGOTO_maybe_W(Label label, boolean defaultToWide) {
+ if (label.anchored)
+ emitGOTO_maybe_W(label.targetPC);
+ else {
+ if (defaultToWide)
+ emitGOTO_W(label);
+ else {
+ try {
+ emitGOTO(label);
+ } catch (OffsetTooBigException e) {
+ throw new Error(e);
+ }
+ }
+ }
+ }
+
+ public void emitGOTO_maybe_W(int targetPC) {
+ int offset = targetPC - (getPC() + 1);
+ if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE)
+ emitGOTO_W(targetPC);
+ else {
+ try {
+ emitGOTO(targetPC);
+ } catch (OffsetTooBigException e) {
+ throw new Error(e);
+ }
+ }
+ }
+
+ /**
+ * Emits a switch instruction choosen according to the caracteristics
+ * of the given list of keys and a default maxRate.
+ *
+ * @param keySets The array of all keys that must be compared to the
+ * value on stack.
+ * @param branches The labels representing the jump addresses linked
+ * with the corresponding keys.
+ * @param defaultBranch The label representing the default branch
+ * address.
+ */
+ public void emitSWITCH(int[][] keySets,
+ Label[] branches,
+ Label defaultBranch,
+ double minDensity) {
+ assert keySets.length == branches.length;
+
+ int flatSize = 0;
+ for (int i = 0; i < keySets.length; ++i)
+ flatSize += keySets[i].length;
+
+ int[] flatKeys = new int[flatSize];
+ Label[] flatBranches = new Label[flatSize];
+ int flatI = 0;
+ for (int i = 0; i < keySets.length; ++i) {
+ Label branch = branches[i];
+ int[] keys = keySets[i];
+ for (int j = 0; j < keys.length; ++j) {
+ flatKeys[flatI] = keys[j];
+ flatBranches[flatI] = branch;
+ }
+ ++flatI;
+ }
+ assert flatI == flatSize;
+ emitSWITCH(flatKeys, flatBranches, defaultBranch, minDensity);
+ }
+
+ /**
+ * Emits a switch instruction choosen according to the caracteristics
+ * of the given list of keys and a given maxRate.
+ *
+ * @param keys The array of all keys that must be compared to the
+ * value on stack.
+ * @param branches The labels representing the jump addresses linked
+ * with the corresponding keys.
+ * @param defaultBranch The label representing the default branch
+ * address.
+ * @param minDensity The minimum density to use for TABLESWITCH.
+ */
+ public void emitSWITCH(int[] keys,
+ Label[] branches,
+ Label defaultBranch,
+ double minDensity) {
+ assert keys.length == branches.length;
+
+ // sorting the tables
+ // FIXME use quicksort
+ for (int i = 1; i < keys.length; i++) {
+ for (int j = 1; j <= keys.length - i; j++) {
+ if (keys[j] < keys[j - 1]) {
+ int tmp = keys[j];
+ keys[j] = keys[j - 1];
+ keys[j - 1] = tmp;
+
+ Label tmp_l = branches[j];
+ branches[j] = branches[j - 1];
+ branches[j - 1] = tmp_l;
+ }
+ }
+ }
+
+ int keyMin = keys[0], keyMax = keys[keys.length - 1];
+ int keyRange = keyMax - keyMin + 1;
+ if ((double)keys.length / (double)keyRange >= minDensity) {
+ // Keys are dense enough, use a table in which holes are
+ // filled with defaultBranch.
+ int[] newKeys = new int[keyRange];
+ Label[] newBranches = new Label[keyRange];
+ int oldPos = 0;
+ for (int i = 0; i < keyRange; ++i) {
+ int key = keyMin + i;
+ newKeys[i] = key;
+ if (keys[oldPos] == key) {
+ newBranches[i] = branches[oldPos];
+ ++oldPos;
+ } else
+ newBranches[i] = defaultBranch;
+ }
+ assert oldPos == keys.length;
+ emitTABLESWITCH(newKeys, newBranches, defaultBranch);
+ } else
+ emitLOOKUPSWITCH(keys, branches, defaultBranch);
+ }
+
+ /**
+ * Emits a method invocation instruction choosen according to
+ * the caracteristics of the given method.
+ *
+ * @param method The method to be invoked.
+ */
+ public void emitINVOKE(JMethod method) {
+ String mName = method.getName();
+ String cName = method.getOwner().getName();
+ JMethodType mType = (JMethodType)method.getType();
+ if (method.isStatic())
+ emitINVOKESTATIC(cName, mName, mType);
+ else if (method.getOwner().isInterface())
+ emitINVOKEINTERFACE(cName, mName, mType);
+ else
+ emitINVOKEVIRTUAL(cName, mName, mType);
+ }
+
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JField.java b/src/fjbg/ch/epfl/lamp/fjbg/JField.java
new file mode 100644
index 0000000000..d94bf8c64f
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JField.java
@@ -0,0 +1,30 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Java class field.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public class JField extends JFieldOrMethod {
+ protected JField(FJBGContext context,
+ JClass owner,
+ int accessFlags,
+ String name,
+ JType type) {
+ super(context, owner, accessFlags, name, type);
+ }
+
+ protected JField(FJBGContext context,
+ JClass owner,
+ DataInputStream stream)
+ throws IOException {
+ super(context, owner, stream);
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JFieldOrMethod.java b/src/fjbg/ch/epfl/lamp/fjbg/JFieldOrMethod.java
new file mode 100644
index 0000000000..bf82015c42
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JFieldOrMethod.java
@@ -0,0 +1,122 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.io.*;
+
+/**
+ * Abstract superclass for a Java field or method.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+abstract public class JFieldOrMethod extends JMember {
+
+ protected final JClass owner;
+ protected final JType type;
+
+ protected final int nameIndex, signatureIndex;
+
+ protected JFieldOrMethod(FJBGContext context,
+ JClass owner,
+ int accessFlags,
+ String name,
+ JType type) {
+ super(context, accessFlags, name);
+ this.owner = owner;
+ this.type = type;
+
+ JConstantPool pool = owner.getConstantPool();
+ nameIndex = pool.addUtf8(name);
+ signatureIndex = pool.addUtf8(type.getSignature());
+ }
+
+ protected JFieldOrMethod(FJBGContext context,
+ JClass owner,
+ DataInputStream stream)
+ throws IOException {
+ super(context);
+ this.owner = owner;
+ this.accessFlags = stream.readShort();
+ this.nameIndex = stream.readShort();
+ this.name = owner.pool.lookupUtf8(nameIndex);
+ this.signatureIndex = stream.readShort();
+ this.type = JType.parseSignature(owner.pool.lookupUtf8(signatureIndex));
+ this.attributes.addAll(JAttribute.readFrom(context, owner, this, stream));
+ }
+
+ public void freeze() throws JCode.OffsetTooBigException {
+ assert !frozen;
+ frozen = true;
+ }
+
+ public JClass getOwner() { return owner; }
+
+ public JType getType() { return type; }
+
+ public JClass getJClass() { return owner; }
+
+ public boolean isPublic() {
+ return (accessFlags & JAccessFlags.ACC_PUBLIC) != 0;
+ }
+
+ public boolean isPrivate() {
+ return (accessFlags & JAccessFlags.ACC_PRIVATE) != 0;
+ }
+
+ public boolean isProtected() {
+ return (accessFlags & JAccessFlags.ACC_PROTECTED) != 0;
+ }
+
+ public boolean isStatic() {
+ return (accessFlags & JAccessFlags.ACC_STATIC) != 0;
+ }
+
+ public boolean isFinal() {
+ return (accessFlags & JAccessFlags.ACC_FINAL) != 0;
+ }
+
+ public boolean isSuper() {
+ return (accessFlags & JAccessFlags.ACC_SUPER) != 0;
+ }
+
+ public boolean isVolatile() {
+ return (accessFlags & JAccessFlags.ACC_VOLATILE) != 0;
+ }
+
+ public boolean isTransient() {
+ return (accessFlags & JAccessFlags.ACC_TRANSIENT) != 0;
+ }
+
+ public boolean isNative() {
+ return (accessFlags & JAccessFlags.ACC_NATIVE) != 0;
+ }
+
+ public boolean isInterface() {
+ return (accessFlags & JAccessFlags.ACC_INTERFACE) != 0;
+ }
+
+ public boolean isAbstract() {
+ return (accessFlags & JAccessFlags.ACC_ABSTRACT) != 0;
+ }
+
+ public boolean isStrict() {
+ return (accessFlags & JAccessFlags.ACC_STRICT) != 0;
+ }
+
+ public void writeTo(DataOutputStream stream) throws IOException {
+ if (! frozen) {
+ try {
+ freeze();
+ }
+ catch (JCode.OffsetTooBigException e) {
+ throw new Error(e);
+ }
+ }
+ stream.writeShort(accessFlags);
+ stream.writeShort(nameIndex);
+ stream.writeShort(signatureIndex);
+ JAttribute.writeTo(getAttributes(), stream);
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java b/src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java
new file mode 100644
index 0000000000..81a7db7488
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java
@@ -0,0 +1,89 @@
+package ch.epfl.lamp.fjbg;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * InnerClasses attribute. See section 4.7.5 of the JVM
+ * Specification.
+ *
+ * @author Iulian Dragos
+ */
+public class JInnerClassesAttribute extends JAttribute {
+ /** InnerClass entries */
+ private Map/*<InnerClassEntry>*/ entries = new LinkedHashMap();
+
+ /** Constant pool of the current classfile. */
+ private JConstantPool pool;
+
+ public JInnerClassesAttribute(FJBGContext context,
+ JClass clazz) {
+ super(context, clazz);
+ this.pool = clazz.pool;
+ }
+
+ public void addEntry(String inner, String outer, String name, int flags) {
+ Entry e = new Entry(inner, outer, name, flags);
+ if (entries.containsKey(inner)) {
+ Entry other = (Entry) entries.get(inner);
+ assert other.outerInfo == e.outerInfo && other.originalName == e.originalName && other.innerFlags == e.innerFlags
+ : inner + "already declared as " + other;
+ } else
+ entries.put(inner, e);
+ }
+
+ public String getName() { return "InnerClasses"; }
+
+ protected int getSize() {
+ return 2 + entries.size() * 8;
+ }
+
+ protected void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeShort(entries.size());
+ for (Iterator it = entries.values().iterator(); it.hasNext(); ) {
+ Entry e = (Entry)it.next();
+ stream.writeShort(e.innerInfo);
+ stream.writeShort(e.outerInfo);
+ stream.writeShort(e.originalName);
+ stream.writeShort(e.innerFlags);
+ }
+ }
+
+ /** An entry in the InnerClasses attribute, as defined by the JVM Spec. */
+ private class Entry {
+ /** CONSTANT_Class_info index in the pool for the inner class (mangled). */
+ int innerInfo;
+
+ /** CONSTANT_Class_info index in the pool for the outer class (mangled). */
+ int outerInfo;
+
+ /** CONSTANT_Utf8_info index in the pool for the original name of the inner class. */
+ int originalName;
+
+ /** Short int for modifier flags. */
+ int innerFlags;
+
+ public Entry(int iI, int oI, int oN, int f) {
+ this.innerInfo = iI;
+ this.outerInfo = oI;
+ this.originalName = oN;
+ this.innerFlags = f;
+ }
+
+ public Entry(String innerClass, String outerClass, String name, int flags) {
+ this(pool.addClass(innerClass),pool.addClass(outerClass), pool.addUtf8(name), flags);
+ }
+
+ /** Two entries are equal if they refer to the same inner class.
+ * innerInfo represents a unique name (mangled).
+ */
+ public boolean equals(Object other) {
+ if (other instanceof Entry) {
+ Entry otherEntry = (Entry) other;
+ return otherEntry.innerInfo == this.innerInfo;
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JLabel.java b/src/fjbg/ch/epfl/lamp/fjbg/JLabel.java
new file mode 100644
index 0000000000..a8ba479c7b
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JLabel.java
@@ -0,0 +1,27 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Labels which can be attached to instructions.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+public class JLabel {
+ public final static int UNDEFINED_ANCHOR = -1;
+ protected int anchor = UNDEFINED_ANCHOR;
+
+ public boolean isAnchored() { return anchor != UNDEFINED_ANCHOR; }
+
+ public int getAnchor() {
+ assert isAnchored();
+ return anchor;
+ }
+
+ public void setAnchor(int anchor) {
+ assert !isAnchored();
+ this.anchor = anchor;
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JLineNumberTableAttribute.java b/src/fjbg/ch/epfl/lamp/fjbg/JLineNumberTableAttribute.java
new file mode 100644
index 0000000000..2ca4a73252
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JLineNumberTableAttribute.java
@@ -0,0 +1,99 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.io.DataOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Attribute storing correspondance between instructions and source
+ * line numbers.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+public class JLineNumberTableAttribute extends JAttribute {
+ protected final JCode code;
+
+ public JLineNumberTableAttribute(FJBGContext context,
+ JClass clazz,
+ JCode owner) {
+ super(context, clazz);
+ this.code = owner;
+
+ assert owner.getOwner().getOwner() == clazz;
+ }
+
+ public JLineNumberTableAttribute(FJBGContext context,
+ JClass clazz,
+ Object owner,
+ String name,
+ int size,
+ DataInputStream stream)
+ throws IOException {
+ super(context, clazz);
+ code = (JCode)owner;
+
+ int[] mapping = new int[code.getSize()];
+
+ int count = stream.readShort();
+ for (int i = 0; i < count; ++i) {
+ int startPC = stream.readShort();
+ int lineNum = stream.readShort();
+ mapping[startPC] = lineNum;
+ }
+
+ int lineNum = 0;
+ for (int pc = 0; pc < mapping.length; ++pc) {
+ if (mapping[pc] != 0) lineNum = mapping[pc];
+ if (lineNum != 0) code.setLineNumber(pc, lineNum);
+ }
+
+ assert name.equals(getName());
+ }
+
+ public String getName() { return "LineNumberTable"; }
+
+ protected int[] encoding;
+ protected int[] encode() {
+ if (encoding == null) {
+ int[] lineNumbers = code.getLineNumbers();
+ int[] preEncoding = new int[lineNumbers.length * 2];
+ int prevLineNum = 0;
+
+ int i = 0;
+ for (int pc = 0; pc < lineNumbers.length; ++pc) {
+ int lineNum = lineNumbers[pc];
+ if (lineNum != 0 & lineNum != prevLineNum) {
+ preEncoding[i++] = pc;
+ preEncoding[i++] = lineNum;
+ prevLineNum = lineNum;
+ }
+ }
+ if (i == preEncoding.length)
+ encoding = preEncoding;
+ else {
+ encoding = new int[i];
+ System.arraycopy(preEncoding, 0, encoding, 0, i);
+ }
+ }
+ return encoding;
+ }
+
+ protected int getSize() {
+ int[] encoding = encode();
+ return 2 + encoding.length * 2;
+ }
+
+ protected void writeContentsTo(DataOutputStream stream) throws IOException {
+ int[] encoding = encode();
+ int entries = encoding.length / 2;
+ stream.writeShort(entries);
+ for (int i = 0; i < entries; ++i) {
+ stream.writeShort(encoding[i * 2]);
+ stream.writeShort(encoding[i * 2 + 1]);
+ }
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JLocalVariable.java b/src/fjbg/ch/epfl/lamp/fjbg/JLocalVariable.java
new file mode 100644
index 0000000000..b708a37e3c
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JLocalVariable.java
@@ -0,0 +1,35 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Representation of a local variable or method argument.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+public class JLocalVariable {
+ protected final JMethod owner;
+ protected final JType type;
+ protected final String name;
+ protected final int index;
+
+ protected JLocalVariable(FJBGContext context,
+ JMethod owner,
+ JType type,
+ String name,
+ int index) {
+ this.owner = owner;
+ this.type = type;
+ this.name = name;
+ this.index = index;
+
+ assert index < 0xFFFF : "index too big for local variable: " + index;
+ }
+
+ public JMethod getOwner() { return owner; }
+ public int getIndex() { return index; }
+ public String getName() { return name; }
+ public JType getType() { return type; }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JMember.java b/src/fjbg/ch/epfl/lamp/fjbg/JMember.java
new file mode 100644
index 0000000000..f2378cf473
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JMember.java
@@ -0,0 +1,99 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Iterator;
+
+/**
+ * Abstract superclass for a Java class, field or method.
+ *
+ * @author Nikolay Mihaylov
+ * @version 1.0
+ */
+
+abstract public class JMember {
+
+ protected boolean frozen = false;
+
+ protected final FJBGContext context;
+
+ protected String name;
+
+ protected int accessFlags;
+
+ protected final List/*<JAttribute>*/ attributes = new LinkedList();
+
+ protected JMember(FJBGContext context) { this.context = context; }
+
+ protected JMember(FJBGContext context, int accessFlags, String name) {
+ this(context);
+ this.name = name;
+ this.accessFlags = accessFlags;
+ }
+
+ /**
+ * Gets the access flags of the class.
+ * @return The int representing the access flags of the class.
+ */
+ public int getAccessFlags() { return accessFlags; }
+
+ /**
+ * Gets the name of the member.
+ * @return The string representing the name of the member.
+ */
+ public String getName() { return name; }
+
+ /**
+ * Gets the type of the objects that are instances of the class.
+ * @return The type of the instances of the class.
+ */
+ public abstract JType getType();
+
+ /**
+ * Gets the class corresponding to/owning this member
+ * @return The class owning this member or the class itself.
+ */
+ public abstract JClass getJClass();
+
+ /**
+ * Gets the constant pool of the class.
+ * @return The constant pool of the class.
+ */
+ public JConstantPool getConstantPool() { return getJClass().getConstantPool(); }
+
+ public FJBGContext getContext() { return context; }
+
+ /**
+ * Adds an attribute to the class.
+ * @param attr The attribute to be added.
+ */
+ public void addAttribute(JAttribute attr) {
+ assert !frozen;
+ attributes.add(attr);
+ }
+
+ /**
+ * Gets the list of all attributes of the class.
+ * @return The list of the attributes of the class representation.
+ */
+ public List/*<JAttribute>*/ getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * Get the attribute with the given name, or null if it doesn't
+ * exist.
+ */
+ public JAttribute getAttribute(String name) {
+ Iterator attrIt = getAttributes().iterator();
+ while (attrIt.hasNext()) {
+ JAttribute attr = (JAttribute)attrIt.next();
+ if (attr.getName().equals(name))
+ return attr;
+ }
+ return null;
+ }
+
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JMethod.java b/src/fjbg/ch/epfl/lamp/fjbg/JMethod.java
new file mode 100644
index 0000000000..dbddf6547d
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JMethod.java
@@ -0,0 +1,133 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Representation of a Java method.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+public class JMethod extends JFieldOrMethod {
+ public final static String CLASS_CONSTRUCTOR_NAME = "<clinit>";
+ public final static String INSTANCE_CONSTRUCTOR_NAME = "<init>";
+
+ protected final JCode code;
+ protected final String[] argNames;
+
+ protected final LinkedList/*<JLocalVariable>*/ localVariables =
+ new LinkedList();
+ protected int localVariableIndex = 0;
+
+ protected JMethod(FJBGContext context,
+ JClass owner,
+ int accessFlags,
+ String name,
+ JType returnType,
+ JType[] argTypes,
+ String[] argNames) {
+ super(context,
+ owner,
+ accessFlags,
+ name,
+ new JMethodType(returnType, argTypes));
+ this.argNames = argNames;
+
+ assert argTypes.length == argNames.length;
+
+ if (isAbstract() || isNative()) {
+ code = null;
+ } else {
+ JConstantPool pool = owner.getConstantPool();
+ code = context.JCode(owner, this);
+ addAttribute(context.JCodeAttribute(owner, this));
+
+ if (!isStatic())
+ addNewLocalVariable(owner.getType(), "this");
+
+ for (int i = 0; i < argTypes.length; ++i)
+ addNewLocalVariable(argTypes[i], argNames[i]);
+ }
+ }
+
+ protected JMethod(FJBGContext context,
+ JClass owner,
+ DataInputStream stream)
+ throws IOException {
+ super(context, owner, stream);
+
+ // Fetch code from the attributes.
+ setCode: {
+ Iterator attrIt = attributes.iterator();
+ while (attrIt.hasNext()) {
+ Object attr = attrIt.next();
+ if (attr instanceof JCodeAttribute) {
+ code = ((JCodeAttribute)attr).code;
+ break setCode;
+ }
+ }
+ code = null;
+ }
+ argNames = null; // TODO get from attribute
+ }
+
+ public void freeze() throws JCode.OffsetTooBigException {
+ if (code != null) code.freeze();
+ super.freeze();
+ }
+
+ public JType getReturnType() {
+ return ((JMethodType)type).getReturnType();
+ }
+
+ public JType[] getArgumentTypes() {
+ return ((JMethodType)type).getArgumentTypes();
+ }
+
+ public String[] getArgumentNames() {
+ return argNames;
+ }
+
+ public JCode getCode() {
+ assert !isAbstract();
+ return code;
+ }
+
+ public JCodeIterator codeIterator() {
+ return new JCodeIterator(code);
+ }
+
+ // Local variables
+ // FIXME : find a better management method for local variables
+ public JLocalVariable addNewLocalVariable(JType type, String name) {
+ assert !frozen;
+ JLocalVariable var =
+ context.JLocalVariable(this, type, name, localVariableIndex);
+ localVariableIndex += type.getSize();
+ localVariables.add(var);
+ return var;
+ }
+
+ public JLocalVariable getLocalVariable(int index) {
+ for (int i = 0; i < localVariables.size(); i++) {
+ if (((JLocalVariable)localVariables.get(i)).index == index)
+ return (JLocalVariable)localVariables.get(i);
+ }
+ return null;
+ }
+
+ public JLocalVariable[] getLocalVariables() {
+ return (JLocalVariable[])localVariables
+ .toArray(new JLocalVariable[localVariables.size()]);
+ }
+
+ public int getMaxLocals() {
+ return localVariableIndex;
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JMethodType.java b/src/fjbg/ch/epfl/lamp/fjbg/JMethodType.java
new file mode 100644
index 0000000000..de136bf53d
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JMethodType.java
@@ -0,0 +1,72 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Type for Java methods. These types do not really exist in Java, but
+ * are provided here because they are useful in several places.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+public class JMethodType extends JType {
+ protected final JType returnType;
+ protected final JType[] argTypes;
+ protected String signature = null;
+
+ public final static JMethodType ARGLESS_VOID_FUNCTION =
+ new JMethodType(JType.VOID, JType.EMPTY_ARRAY);
+
+ public JMethodType(JType returnType, JType[] argTypes) {
+ this.returnType = returnType;
+ this.argTypes = argTypes;
+ }
+
+ public JType getReturnType() { return returnType; }
+ public JType[] getArgumentTypes() { return argTypes; }
+
+ public int getSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getSignature() {
+ if (signature == null) {
+ StringBuffer buf = new StringBuffer();
+ buf.append('(');
+ for (int i = 0; i < argTypes.length; ++i)
+ buf.append(argTypes[i].getSignature());
+ buf.append(')');
+ buf.append(returnType.getSignature());
+ signature = buf.toString();
+ }
+ return signature;
+ }
+
+ public int getTag() { return T_UNKNOWN; }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append('(');
+ for (int i = 0; i < argTypes.length; ++i)
+ buf.append(argTypes[i].toString());
+ buf.append(')');
+ buf.append(returnType.toString());
+ return buf.toString();
+ }
+
+ public int getArgsSize() {
+ int size = 0;
+ for (int i = 0; i < argTypes.length; ++i)
+ size += argTypes[i].getSize();
+ return size;
+ }
+
+ public int getProducedStack() {
+ return returnType.getSize() - getArgsSize();
+ }
+
+ public boolean isCompatibleWith(JType other) {
+ return false;
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JObjectType.java b/src/fjbg/ch/epfl/lamp/fjbg/JObjectType.java
new file mode 100644
index 0000000000..a1930f77ef
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JObjectType.java
@@ -0,0 +1,53 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Types for Java objects.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+public class JObjectType extends JReferenceType {
+ protected final String name;
+ protected String signature = null;
+
+ public final static JObjectType JAVA_LANG_OBJECT =
+ new JObjectType("java.lang.Object");
+ public final static JObjectType JAVA_LANG_STRING =
+ new JObjectType("java.lang.String");
+ public final static JObjectType CLONEABLE =
+ new JObjectType("Cloneable");
+ public final static JObjectType JAVA_IO_SERIALIZABLE =
+ new JObjectType("java.io.Serializable");
+
+ public JObjectType(String name) {
+ this.name = name;
+ }
+
+ public int getSize() { return 1; }
+
+ public String getName() { return name; }
+
+ public String getSignature() {
+ if (signature == null)
+ signature = "L" + name.replace('.','/') + ";";
+ return signature;
+ }
+
+ public String getDescriptor() {
+ return name.replace('.','/');
+ }
+
+ public int getTag() { return T_OBJECT; }
+
+ public String toString() { return name; }
+
+ public boolean isObjectType() { return true; }
+
+ public boolean isCompatibleWith(JType other) {
+ return other instanceof JObjectType
+ || other == JType.REFERENCE;
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JOpcode.java b/src/fjbg/ch/epfl/lamp/fjbg/JOpcode.java
new file mode 100644
index 0000000000..6b6d3b6a74
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JOpcode.java
@@ -0,0 +1,1264 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Definition of opcodes for the JVM.
+ *
+ * @author Michel Schinz, Thomas Friedli
+ * @version 1.0
+ */
+
+public class JOpcode {
+ public final String name;
+ public final int code;
+
+ // The following attributes can be (statically) unknown for some
+ // instructions, and are therefore not public. To know their value,
+ // functions have to be used (see JCodeIterator).
+ protected final int size;
+ protected final JType[] producedDataTypes;
+ protected final JType[] consumedDataTypes;
+ protected final int jumpKind;
+ protected final int successorCount;
+
+ protected final static int UNKNOWN = Integer.MIN_VALUE;
+
+ protected final static int JMP_NONE = 0;
+ protected final static int JMP_NEXT = 1;
+ protected final static int JMP_ALWAYS_S2_OFFSET = 2;
+ protected final static int JMP_ALWAYS_S4_OFFSET = 3;
+ protected final static int JMP_MAYBE_S2_OFFSET = 4;
+ protected final static int JMP_TABLE = 5;
+ protected final static int JMP_LOOKUP = 6;
+
+ protected final static JType[] NO_DATA = new JType[0];
+
+ protected final static JType[] INT_TYPE =
+ new JType[] { JType.INT };
+ protected final static JType[] FLOAT_TYPE =
+ new JType[] { JType.FLOAT };
+ protected final static JType[] LONG_TYPE =
+ new JType[] { JType.LONG };
+ protected final static JType[] DOUBLE_TYPE =
+ new JType[] { JType.DOUBLE };
+ protected final static JType[] OBJECT_REF_TYPE =
+ new JType[] { JObjectType.JAVA_LANG_OBJECT };
+ protected final static JType[] ARRAY_REF_TYPE =
+ new JType[] { new JArrayType(JType.VOID) };
+ protected final static JType[] REFERENCE_TYPE =
+ new JType[] { JType.REFERENCE };
+ protected final static JType[] ADDRESS_TYPE =
+ new JType[] { JType.ADDRESS };
+ protected final static JType[] UNKNOWN_TYPE =
+ new JType[] { JType.UNKNOWN };
+
+ /// Instruction codes
+ public final static int cNOP = 0;
+ public final static int cACONST_NULL = 1;
+ public final static int cICONST_M1 = 2;
+ public final static int cICONST_0 = 3;
+ public final static int cICONST_1 = 4;
+ public final static int cICONST_2 = 5;
+ public final static int cICONST_3 = 6;
+ public final static int cICONST_4 = 7;
+ public final static int cICONST_5 = 8;
+ public final static int cLCONST_0 = 9;
+ public final static int cLCONST_1 = 10;
+ public final static int cFCONST_0 = 11;
+ public final static int cFCONST_1 = 12;
+ public final static int cFCONST_2 = 13;
+ public final static int cDCONST_0 = 14;
+ public final static int cDCONST_1 = 15;
+ public final static int cBIPUSH = 16;
+ public final static int cSIPUSH = 17;
+ public final static int cLDC = 18;
+ public final static int cLDC_W = 19;
+ public final static int cLDC2_W = 20;
+ public final static int cILOAD = 21;
+ public final static int cLLOAD = 22;
+ public final static int cFLOAD = 23;
+ public final static int cDLOAD = 24;
+ public final static int cALOAD = 25;
+ public final static int cILOAD_0 = 26;
+ public final static int cILOAD_1 = 27;
+ public final static int cILOAD_2 = 28;
+ public final static int cILOAD_3 = 29;
+ public final static int cLLOAD_0 = 30;
+ public final static int cLLOAD_1 = 31;
+ public final static int cLLOAD_2 = 32;
+ public final static int cLLOAD_3 = 33;
+ public final static int cFLOAD_0 = 34;
+ public final static int cFLOAD_1 = 35;
+ public final static int cFLOAD_2 = 36;
+ public final static int cFLOAD_3 = 37;
+ public final static int cDLOAD_0 = 38;
+ public final static int cDLOAD_1 = 39;
+ public final static int cDLOAD_2 = 40;
+ public final static int cDLOAD_3 = 41;
+ public final static int cALOAD_0 = 42;
+ public final static int cALOAD_1 = 43;
+ public final static int cALOAD_2 = 44;
+ public final static int cALOAD_3 = 45;
+ public final static int cIALOAD = 46;
+ public final static int cLALOAD = 47;
+ public final static int cFALOAD = 48;
+ public final static int cDALOAD = 49;
+ public final static int cAALOAD = 50;
+ public final static int cBALOAD = 51;
+ public final static int cCALOAD = 52;
+ public final static int cSALOAD = 53;
+ public final static int cISTORE = 54;
+ public final static int cLSTORE = 55;
+ public final static int cFSTORE = 56;
+ public final static int cDSTORE = 57;
+ public final static int cASTORE = 58;
+ public final static int cISTORE_0 = 59;
+ public final static int cISTORE_1 = 60;
+ public final static int cISTORE_2 = 61;
+ public final static int cISTORE_3 = 62;
+ public final static int cLSTORE_0 = 63;
+ public final static int cLSTORE_1 = 64;
+ public final static int cLSTORE_2 = 65;
+ public final static int cLSTORE_3 = 66;
+ public final static int cFSTORE_0 = 67;
+ public final static int cFSTORE_1 = 68;
+ public final static int cFSTORE_2 = 69;
+ public final static int cFSTORE_3 = 70;
+ public final static int cDSTORE_0 = 71;
+ public final static int cDSTORE_1 = 72;
+ public final static int cDSTORE_2 = 73;
+ public final static int cDSTORE_3 = 74;
+ public final static int cASTORE_0 = 75;
+ public final static int cASTORE_1 = 76;
+ public final static int cASTORE_2 = 77;
+ public final static int cASTORE_3 = 78;
+ public final static int cIASTORE = 79;
+ public final static int cLASTORE = 80;
+ public final static int cFASTORE = 81;
+ public final static int cDASTORE = 82;
+ public final static int cAASTORE = 83;
+ public final static int cBASTORE = 84;
+ public final static int cCASTORE = 85;
+ public final static int cSASTORE = 86;
+ public final static int cPOP = 87;
+ public final static int cPOP2 = 88;
+ public final static int cDUP = 89;
+ public final static int cDUP_X1 = 90;
+ public final static int cDUP_X2 = 91;
+ public final static int cDUP2 = 92;
+ public final static int cDUP2_X1 = 93;
+ public final static int cDUP2_X2 = 94;
+ public final static int cSWAP = 95;
+ public final static int cIADD = 96;
+ public final static int cLADD = 97;
+ public final static int cFADD = 98;
+ public final static int cDADD = 99;
+ public final static int cISUB = 100;
+ public final static int cLSUB = 101;
+ public final static int cFSUB = 102;
+ public final static int cDSUB = 103;
+ public final static int cIMUL = 104;
+ public final static int cLMUL = 105;
+ public final static int cFMUL = 106;
+ public final static int cDMUL = 107;
+ public final static int cIDIV = 108;
+ public final static int cLDIV = 109;
+ public final static int cFDIV = 110;
+ public final static int cDDIV = 111;
+ public final static int cIREM = 112;
+ public final static int cLREM = 113;
+ public final static int cFREM = 114;
+ public final static int cDREM = 115;
+ public final static int cINEG = 116;
+ public final static int cLNEG = 117;
+ public final static int cFNEG = 118;
+ public final static int cDNEG = 119;
+ public final static int cISHL = 120;
+ public final static int cLSHL = 121;
+ public final static int cISHR = 122;
+ public final static int cLSHR = 123;
+ public final static int cIUSHR = 124;
+ public final static int cLUSHR = 125;
+ public final static int cIAND = 126;
+ public final static int cLAND = 127;
+ public final static int cIOR = 128;
+ public final static int cLOR = 129;
+ public final static int cIXOR = 130;
+ public final static int cLXOR = 131;
+ public final static int cIINC = 132;
+ public final static int cI2L = 133;
+ public final static int cI2F = 134;
+ public final static int cI2D = 135;
+ public final static int cL2I = 136;
+ public final static int cL2F = 137;
+ public final static int cL2D = 138;
+ public final static int cF2I = 139;
+ public final static int cF2L = 140;
+ public final static int cF2D = 141;
+ public final static int cD2I = 142;
+ public final static int cD2L = 143;
+ public final static int cD2F = 144;
+ public final static int cI2B = 145;
+ public final static int cI2C = 146;
+ public final static int cI2S = 147;
+ public final static int cLCMP = 148;
+ public final static int cFCMPL = 149;
+ public final static int cFCMPG = 150;
+ public final static int cDCMPL = 151;
+ public final static int cDCMPG = 152;
+ public final static int cIFEQ = 153;
+ public final static int cIFNE = 154;
+ public final static int cIFLT = 155;
+ public final static int cIFGE = 156;
+ public final static int cIFGT = 157;
+ public final static int cIFLE = 158;
+ public final static int cIF_ICMPEQ = 159;
+ public final static int cIF_ICMPNE = 160;
+ public final static int cIF_ICMPLT = 161;
+ public final static int cIF_ICMPGE = 162;
+ public final static int cIF_ICMPGT = 163;
+ public final static int cIF_ICMPLE = 164;
+ public final static int cIF_ACMPEQ = 165;
+ public final static int cIF_ACMPNE = 166;
+ public final static int cGOTO = 167;
+ public final static int cJSR = 168;
+ public final static int cRET = 169;
+ public final static int cTABLESWITCH = 170;
+ public final static int cLOOKUPSWITCH = 171;
+ public final static int cIRETURN = 172;
+ public final static int cLRETURN = 173;
+ public final static int cFRETURN = 174;
+ public final static int cDRETURN = 175;
+ public final static int cARETURN = 176;
+ public final static int cRETURN = 177;
+ public final static int cGETSTATIC = 178;
+ public final static int cPUTSTATIC = 179;
+ public final static int cGETFIELD = 180;
+ public final static int cPUTFIELD = 181;
+ public final static int cINVOKEVIRTUAL = 182;
+ public final static int cINVOKESPECIAL = 183;
+ public final static int cINVOKESTATIC = 184;
+ public final static int cINVOKEINTERFACE = 185;
+ public final static int cNEW = 187;
+ public final static int cNEWARRAY = 188;
+ public final static int cANEWARRAY = 189;
+ public final static int cARRAYLENGTH = 190;
+ public final static int cATHROW = 191;
+ public final static int cCHECKCAST = 192;
+ public final static int cINSTANCEOF = 193;
+ public final static int cMONITORENTER = 194;
+ public final static int cMONITOREXIT = 195;
+ public final static int cWIDE = 196;
+ public final static int cMULTIANEWARRAY = 197;
+ public final static int cIFNULL = 198;
+ public final static int cIFNONNULL = 199;
+ public final static int cGOTO_W = 200;
+ public final static int cJSR_W = 201;
+
+ // Objects representing instructions
+ public final static JOpcode NOP =
+ new JOpcode("NOP", cNOP, 1, NO_DATA, NO_DATA, JMP_NEXT);
+ public final static JOpcode ACONST_NULL = new JOpcode("ACONST_NULL",
+ cACONST_NULL,
+ 1,
+ REFERENCE_TYPE,
+ NO_DATA,
+ JMP_NEXT);
+ public final static JOpcode ICONST_M1 =
+ new JOpcode("ICONST_M1", cICONST_M1, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ICONST_0 =
+ new JOpcode("ICONST_0", cICONST_0, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ICONST_1 =
+ new JOpcode("ICONST_1", cICONST_1, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ICONST_2 =
+ new JOpcode("ICONST_2", cICONST_2, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ICONST_3 =
+ new JOpcode("ICONST_3", cICONST_3, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ICONST_4 =
+ new JOpcode("ICONST_4", cICONST_4, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ICONST_5 =
+ new JOpcode("ICONST_5", cICONST_5, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LCONST_0 =
+ new JOpcode("LCONST_0", cLCONST_0, 1, LONG_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LCONST_1 =
+ new JOpcode("LCONST_1", cLCONST_1, 1, LONG_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode FCONST_0 =
+ new JOpcode("FCONST_0", cFCONST_0, 1, FLOAT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode FCONST_1 =
+ new JOpcode("FCONST_1", cFCONST_1, 1, FLOAT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode FCONST_2 =
+ new JOpcode("FCONST_2", cFCONST_2, 1, FLOAT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode DCONST_0 =
+ new JOpcode("DCONST_0", cDCONST_0, 1, DOUBLE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode DCONST_1 =
+ new JOpcode("DCONST_1", cDCONST_1, 1, DOUBLE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode BIPUSH =
+ new JOpcode("BIPUSH", cBIPUSH, 2, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode SIPUSH =
+ new JOpcode("SIPUSH", cSIPUSH, 3, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LDC =
+ new JOpcode("LDC", cLDC, 2, UNKNOWN_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LDC_W =
+ new JOpcode("LDC_W", cLDC_W, 3, UNKNOWN_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LDC2_W =
+ new JOpcode("LDC2_W", cLDC2_W, 3, UNKNOWN_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ILOAD =
+ new JOpcode("ILOAD", cILOAD, 2, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LLOAD =
+ new JOpcode("LLOAD", cLLOAD, 2, LONG_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode FLOAD =
+ new JOpcode("FLOAD", cFLOAD, 2, FLOAT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode DLOAD =
+ new JOpcode("DLOAD", cDLOAD, 2, DOUBLE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ALOAD =
+ new JOpcode("ALOAD", cALOAD, 2, REFERENCE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ILOAD_0 =
+ new JOpcode("ILOAD_0", cILOAD_0, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ILOAD_1 =
+ new JOpcode("ILOAD_1", cILOAD_1, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ILOAD_2 =
+ new JOpcode("ILOAD_2", cILOAD_2, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ILOAD_3 =
+ new JOpcode("ILOAD_3", cILOAD_3, 1, INT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LLOAD_0 =
+ new JOpcode("LLOAD_0", cLLOAD_0, 1, LONG_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LLOAD_1 =
+ new JOpcode("LLOAD_1", cLLOAD_1, 1, LONG_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LLOAD_2 =
+ new JOpcode("LLOAD_2", cLLOAD_2, 1, LONG_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode LLOAD_3 =
+ new JOpcode("LLOAD_3", cLLOAD_3, 1, LONG_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode FLOAD_0 =
+ new JOpcode("FLOAD_0", cFLOAD_0, 1, FLOAT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode FLOAD_1 =
+ new JOpcode("FLOAD_1", cFLOAD_1, 1, FLOAT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode FLOAD_2 =
+ new JOpcode("FLOAD_2", cFLOAD_2, 1, FLOAT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode FLOAD_3 =
+ new JOpcode("FLOAD_3", cFLOAD_3, 1, FLOAT_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode DLOAD_0 =
+ new JOpcode("DLOAD_0", cDLOAD_0, 1, DOUBLE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode DLOAD_1 =
+ new JOpcode("DLOAD_1", cDLOAD_1, 1, DOUBLE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode DLOAD_2 =
+ new JOpcode("DLOAD_2", cDLOAD_2, 1, DOUBLE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode DLOAD_3 =
+ new JOpcode("DLOAD_3", cDLOAD_3, 1, DOUBLE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ALOAD_0 =
+ new JOpcode("ALOAD_0", cALOAD_0, 1, REFERENCE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ALOAD_1 =
+ new JOpcode("ALOAD_1", cALOAD_1, 1, REFERENCE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ALOAD_2 =
+ new JOpcode("ALOAD_2", cALOAD_2, 1, REFERENCE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode ALOAD_3 =
+ new JOpcode("ALOAD_3", cALOAD_3, 1, REFERENCE_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode IALOAD =
+ new JOpcode("IALOAD",
+ cIALOAD,
+ 1,
+ INT_TYPE,
+ new JType[] {JType.INT, JArrayType.INT},
+ JMP_NEXT);
+ public final static JOpcode LALOAD =
+ new JOpcode("LALOAD",
+ cLALOAD,
+ 1,
+ LONG_TYPE,
+ new JType[] {JType.INT, JArrayType.LONG},
+ JMP_NEXT);
+ public final static JOpcode FALOAD =
+ new JOpcode("FALOAD",
+ cFALOAD,
+ 1,
+ FLOAT_TYPE,
+ new JType[] {JType.INT, JArrayType.FLOAT},
+ JMP_NEXT);
+ public final static JOpcode DALOAD =
+ new JOpcode("DALOAD",
+ cDALOAD,
+ 1,
+ DOUBLE_TYPE,
+ new JType[] {JType.INT, JArrayType.DOUBLE},
+ JMP_NEXT);
+ public final static JOpcode AALOAD =
+ new JOpcode("AALOAD",
+ cAALOAD,
+ 1,
+ REFERENCE_TYPE,
+ new JType[] {JType.INT, JArrayType.REFERENCE},
+ JMP_NEXT);
+ public final static JOpcode BALOAD =
+ new JOpcode("BALOAD",
+ cBALOAD,
+ 1,
+ INT_TYPE,
+ new JType[] {JType.INT, new JArrayType(JType.UNKNOWN)},
+ JMP_NEXT);
+ public final static JOpcode CALOAD =
+ new JOpcode("CALOAD",
+ cCALOAD,
+ 1,
+ INT_TYPE,
+ new JType[] {JType.INT, JArrayType.CHAR},
+ JMP_NEXT);
+ public final static JOpcode SALOAD =
+ new JOpcode("SALOAD",
+ cSALOAD,
+ 1,
+ INT_TYPE,
+ new JType[] {JType.INT, JArrayType.SHORT},
+ JMP_NEXT);
+ public final static JOpcode ISTORE =
+ new JOpcode("ISTORE", cISTORE, 2, NO_DATA, INT_TYPE, JMP_NEXT);
+ public final static JOpcode LSTORE =
+ new JOpcode("LSTORE", cLSTORE, 2, NO_DATA, LONG_TYPE, JMP_NEXT);
+ public final static JOpcode FSTORE =
+ new JOpcode("FSTORE", cFSTORE, 2, NO_DATA, FLOAT_TYPE, JMP_NEXT);
+ public final static JOpcode DSTORE =
+ new JOpcode("DSTORE", cDSTORE, 2, NO_DATA, DOUBLE_TYPE, JMP_NEXT);
+ public final static JOpcode ASTORE =
+ new JOpcode("ASTORE", cASTORE, 2, NO_DATA, REFERENCE_TYPE, JMP_NEXT);
+ public final static JOpcode ISTORE_0 =
+ new JOpcode("ISTORE_0", cISTORE_0, 1, NO_DATA, INT_TYPE, JMP_NEXT);
+ public final static JOpcode ISTORE_1 =
+ new JOpcode("ISTORE_1", cISTORE_1, 1, NO_DATA, INT_TYPE, JMP_NEXT);
+ public final static JOpcode ISTORE_2 =
+ new JOpcode("ISTORE_2", cISTORE_2, 1, NO_DATA, INT_TYPE, JMP_NEXT);
+ public final static JOpcode ISTORE_3 =
+ new JOpcode("ISTORE_3", cISTORE_3, 1, NO_DATA, INT_TYPE, JMP_NEXT);
+ public final static JOpcode LSTORE_0 =
+ new JOpcode("LSTORE_0", cLSTORE_0, 1, NO_DATA, LONG_TYPE, JMP_NEXT);
+ public final static JOpcode LSTORE_1 =
+ new JOpcode("LSTORE_1", cLSTORE_1, 1, NO_DATA, LONG_TYPE, JMP_NEXT);
+ public final static JOpcode LSTORE_2 =
+ new JOpcode("LSTORE_2", cLSTORE_2, 1, NO_DATA, LONG_TYPE, JMP_NEXT);
+ public final static JOpcode LSTORE_3 =
+ new JOpcode("LSTORE_3", cLSTORE_3, 1, NO_DATA, LONG_TYPE, JMP_NEXT);
+ public final static JOpcode FSTORE_0 =
+ new JOpcode("FSTORE_0", cFSTORE_0, 1, NO_DATA, FLOAT_TYPE, JMP_NEXT);
+ public final static JOpcode FSTORE_1 =
+ new JOpcode("FSTORE_1", cFSTORE_1, 1, NO_DATA, FLOAT_TYPE, JMP_NEXT);
+ public final static JOpcode FSTORE_2 =
+ new JOpcode("FSTORE_2", cFSTORE_2, 1, NO_DATA, FLOAT_TYPE, JMP_NEXT);
+ public final static JOpcode FSTORE_3 =
+ new JOpcode("FSTORE_3", cFSTORE_3, 1, NO_DATA, FLOAT_TYPE, JMP_NEXT);
+ public final static JOpcode DSTORE_0 =
+ new JOpcode("DSTORE_0", cDSTORE_0, 1, NO_DATA, DOUBLE_TYPE, JMP_NEXT);
+ public final static JOpcode DSTORE_1 =
+ new JOpcode("DSTORE_1", cDSTORE_1, 1, NO_DATA, DOUBLE_TYPE, JMP_NEXT);
+ public final static JOpcode DSTORE_2 =
+ new JOpcode("DSTORE_2", cDSTORE_2, 1, NO_DATA, DOUBLE_TYPE, JMP_NEXT);
+ public final static JOpcode DSTORE_3 =
+ new JOpcode("DSTORE_3", cDSTORE_3, 1, NO_DATA, DOUBLE_TYPE, JMP_NEXT);
+ public final static JOpcode ASTORE_0 = new JOpcode("ASTORE_0",
+ cASTORE_0,
+ 1,
+ NO_DATA,
+ REFERENCE_TYPE,
+ JMP_NEXT);
+ public final static JOpcode ASTORE_1 = new JOpcode("ASTORE_1",
+ cASTORE_1,
+ 1,
+ NO_DATA,
+ REFERENCE_TYPE,
+ JMP_NEXT);
+ public final static JOpcode ASTORE_2 = new JOpcode("ASTORE_2",
+ cASTORE_2,
+ 1,
+ NO_DATA,
+ REFERENCE_TYPE,
+ JMP_NEXT);
+ public final static JOpcode ASTORE_3 = new JOpcode("ASTORE_3",
+ cASTORE_3,
+ 1,
+ NO_DATA,
+ REFERENCE_TYPE,
+ JMP_NEXT);
+ public final static JOpcode IASTORE =
+ new JOpcode("IASTORE",
+ cIASTORE,
+ 1,
+ NO_DATA,
+ new JType[] { JType.INT,
+ JType.INT,
+ JArrayType.INT},
+ JMP_NEXT);
+ public final static JOpcode LASTORE =
+ new JOpcode("LASTORE",
+ cLASTORE,
+ 1,
+ NO_DATA,
+ new JType[] { JType.LONG,
+ JType.INT,
+ JArrayType.LONG},
+ JMP_NEXT);
+ public final static JOpcode FASTORE =
+ new JOpcode("FASTORE",
+ cFASTORE,
+ 1,
+ NO_DATA,
+ new JType[] { JType.FLOAT,
+ JType.INT,
+ JArrayType.FLOAT},
+ JMP_NEXT);
+ public final static JOpcode DASTORE =
+ new JOpcode("DASTORE",
+ cDASTORE,
+ 1,
+ NO_DATA,
+ new JType[] { JType.DOUBLE,
+ JType.INT,
+ JArrayType.DOUBLE},
+ JMP_NEXT);
+ public final static JOpcode AASTORE =
+ new JOpcode("AASTORE",
+ cAASTORE,
+ 1,
+ NO_DATA,
+ new JType[] { JType.REFERENCE,
+ JType.INT,
+ JArrayType.REFERENCE},
+ JMP_NEXT);
+ public final static JOpcode BASTORE =
+ new JOpcode("BASTORE",
+ cBASTORE,
+ 1,
+ NO_DATA,
+ new JType[] { JType.INT,
+ JType.INT,
+ new JArrayType(JType.UNKNOWN)},
+ JMP_NEXT);
+ public final static JOpcode CASTORE =
+ new JOpcode("CASTORE",
+ cCASTORE,
+ 1,
+ NO_DATA,
+ new JType[] { JType.INT,
+ JType.INT,
+ JArrayType.CHAR},
+ JMP_NEXT);
+ public final static JOpcode SASTORE =
+ new JOpcode("SASTORE",
+ cSASTORE,
+ 1,
+ NO_DATA,
+ new JType[] { JType.INT,
+ JType.INT,
+ JArrayType.SHORT},
+ JMP_NEXT);
+ public final static JOpcode POP =
+ new JOpcode("POP", cPOP, 1, NO_DATA, UNKNOWN_TYPE, JMP_NEXT);
+ public final static JOpcode POP2 =
+ new JOpcode("POP2", cPOP2, 1, NO_DATA, UNKNOWN_TYPE, JMP_NEXT);
+ public final static JOpcode DUP =
+ new JOpcode("DUP", cDUP, 1, UNKNOWN_TYPE, UNKNOWN_TYPE, JMP_NEXT);
+ public final static JOpcode DUP_X1 = new JOpcode("DUP_X1",
+ cDUP_X1,
+ 1,
+ UNKNOWN_TYPE,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode DUP_X2 = new JOpcode("DUP_X2",
+ cDUP_X2,
+ 1,
+ UNKNOWN_TYPE,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode DUP2 =
+ new JOpcode("DUP2", cDUP2, 1, UNKNOWN_TYPE, UNKNOWN_TYPE, JMP_NEXT);
+ public final static JOpcode DUP2_X1 = new JOpcode("DUP2_X1",
+ cDUP2_X1,
+ 1,
+ UNKNOWN_TYPE,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode DUP2_X2 = new JOpcode("DUP2_X2",
+ cDUP2_X2,
+ 1,
+ UNKNOWN_TYPE,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode SWAP =
+ new JOpcode("SWAP", cSWAP, 1, UNKNOWN_TYPE, UNKNOWN_TYPE, JMP_NEXT);
+ public final static JOpcode IADD =
+ new JOpcode("IADD",
+ cIADD,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LADD =
+ new JOpcode("LADD",
+ cLADD,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode FADD =
+ new JOpcode("FADD",
+ cFADD,
+ 1,
+ FLOAT_TYPE,
+ new JType[] { JType.FLOAT, JType.FLOAT },
+ JMP_NEXT);
+ public final static JOpcode DADD =
+ new JOpcode("DADD",
+ cDADD,
+ 1,
+ DOUBLE_TYPE,
+ new JType[] { JType.DOUBLE, JType.DOUBLE },
+ JMP_NEXT);
+ public final static JOpcode ISUB =
+ new JOpcode("ISUB",
+ cISUB,
+ 1,
+ INT_TYPE,
+ new JType[] {JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LSUB =
+ new JOpcode("LSUB",
+ cLSUB,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode FSUB =
+ new JOpcode("FSUB",
+ cFSUB,
+ 1,
+ FLOAT_TYPE,
+ new JType[] { JType.FLOAT, JType.FLOAT },
+ JMP_NEXT);
+ public final static JOpcode DSUB =
+ new JOpcode("DSUB",
+ cDSUB,
+ 1,
+ DOUBLE_TYPE,
+ new JType[] { JType.DOUBLE, JType.DOUBLE },
+ JMP_NEXT);
+ public final static JOpcode IMUL =
+ new JOpcode("IMUL",
+ cIMUL,
+ 1,
+ INT_TYPE,
+ new JType[] {JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LMUL =
+ new JOpcode("LMUL",
+ cLMUL,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode FMUL =
+ new JOpcode("FMUL",
+ cFMUL,
+ 1,
+ FLOAT_TYPE,
+ new JType[] { JType.FLOAT, JType.FLOAT },
+ JMP_NEXT);
+ public final static JOpcode DMUL =
+ new JOpcode("DMUL",
+ cDMUL,
+ 1,
+ DOUBLE_TYPE,
+ new JType[] { JType.DOUBLE, JType.DOUBLE },
+ JMP_NEXT);
+ public final static JOpcode IDIV =
+ new JOpcode("IDIV",
+ cIDIV,
+ 1,
+ INT_TYPE,
+ new JType[] {JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LDIV =
+ new JOpcode("LDIV",
+ cLDIV,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode FDIV =
+ new JOpcode("FDIV",
+ cFDIV,
+ 1,
+ FLOAT_TYPE,
+ new JType[] { JType.FLOAT, JType.FLOAT },
+ JMP_NEXT);
+ public final static JOpcode DDIV =
+ new JOpcode("DDIV",
+ cDDIV,
+ 1,
+ DOUBLE_TYPE,
+ new JType[] { JType.DOUBLE, JType.DOUBLE },
+ JMP_NEXT);
+ public final static JOpcode IREM =
+ new JOpcode("IREM",
+ cIREM,
+ 1,
+ INT_TYPE,
+ new JType[] {JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LREM =
+ new JOpcode("LREM",
+ cLREM,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode FREM =
+ new JOpcode("FREM",
+ cFREM,
+ 1,
+ FLOAT_TYPE,
+ new JType[] { JType.FLOAT, JType.FLOAT },
+ JMP_NEXT);
+ public final static JOpcode DREM =
+ new JOpcode("DREM",
+ cDREM,
+ 1,
+ DOUBLE_TYPE,
+ new JType[] { JType.DOUBLE, JType.DOUBLE },
+ JMP_NEXT);
+ public final static JOpcode INEG =
+ new JOpcode("INEG", cINEG, 1, INT_TYPE, INT_TYPE, JMP_NEXT);
+ public final static JOpcode LNEG =
+ new JOpcode("LNEG", cLNEG, 1, LONG_TYPE, LONG_TYPE, JMP_NEXT);
+ public final static JOpcode FNEG =
+ new JOpcode("FNEG", cFNEG, 1, FLOAT_TYPE, FLOAT_TYPE, JMP_NEXT);
+ public final static JOpcode DNEG =
+ new JOpcode("DNEG", cDNEG, 1, DOUBLE_TYPE, DOUBLE_TYPE, JMP_NEXT);
+ public final static JOpcode ISHL =
+ new JOpcode("ISHL", cISHL,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LSHL =
+ new JOpcode("LSHL",
+ cLSHL,
+ 1,
+ LONG_TYPE,
+ new JType [] { JType.INT, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode ISHR =
+ new JOpcode("ISHR",
+ cISHR,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LSHR =
+ new JOpcode("LSHR",
+ cLSHR,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.INT, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode IUSHR =
+ new JOpcode("IUSHR",
+ cIUSHR,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LUSHR =
+ new JOpcode("LUSHR",
+ cLUSHR,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.INT, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode IAND =
+ new JOpcode("IAND",
+ cIAND,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LAND =
+ new JOpcode("LAND",
+ cLAND,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode IOR =
+ new JOpcode("IOR",
+ cIOR,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LOR =
+ new JOpcode("LOR",
+ cLOR,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode IXOR =
+ new JOpcode("IXOR",
+ cIXOR,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.INT, JType.INT },
+ JMP_NEXT);
+ public final static JOpcode LXOR =
+ new JOpcode("LXOR",
+ cLXOR,
+ 1,
+ LONG_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode IINC =
+ new JOpcode("IINC", cIINC, 3, NO_DATA, NO_DATA, JMP_NEXT);
+ public final static JOpcode I2L =
+ new JOpcode("I2L", cI2L, 1, LONG_TYPE, INT_TYPE, JMP_NEXT);
+ public final static JOpcode I2F =
+ new JOpcode("I2F", cI2F, 1, FLOAT_TYPE, INT_TYPE, JMP_NEXT);
+ public final static JOpcode I2D =
+ new JOpcode("I2D", cI2D, 1, DOUBLE_TYPE, INT_TYPE, JMP_NEXT);
+ public final static JOpcode L2I =
+ new JOpcode("L2I", cL2I, 1, INT_TYPE, LONG_TYPE, JMP_NEXT);
+ public final static JOpcode L2F =
+ new JOpcode("L2F", cL2F, 1, FLOAT_TYPE, LONG_TYPE, JMP_NEXT);
+ public final static JOpcode L2D =
+ new JOpcode("L2D", cL2D, 1, DOUBLE_TYPE, LONG_TYPE, JMP_NEXT);
+ public final static JOpcode F2I =
+ new JOpcode("F2I", cF2I, 1, INT_TYPE, FLOAT_TYPE, JMP_NEXT);
+ public final static JOpcode F2L =
+ new JOpcode("F2L", cF2L, 1, LONG_TYPE, FLOAT_TYPE, JMP_NEXT);
+ public final static JOpcode F2D =
+ new JOpcode("F2D", cF2D, 1, DOUBLE_TYPE, FLOAT_TYPE, JMP_NEXT);
+ public final static JOpcode D2I =
+ new JOpcode("D2I", cD2I, 1, INT_TYPE, DOUBLE_TYPE, JMP_NEXT);
+ public final static JOpcode D2L =
+ new JOpcode("D2L", cD2L, 1, LONG_TYPE, DOUBLE_TYPE, JMP_NEXT);
+ public final static JOpcode D2F =
+ new JOpcode("D2F", cD2F, 1, FLOAT_TYPE, DOUBLE_TYPE, JMP_NEXT);
+ public final static JOpcode I2B =
+ new JOpcode("I2B", cI2B, 1, INT_TYPE, INT_TYPE, JMP_NEXT);
+ public final static JOpcode I2C =
+ new JOpcode("I2C", cI2C, 1, INT_TYPE, INT_TYPE, JMP_NEXT);
+ public final static JOpcode I2S =
+ new JOpcode("I2S", cI2S, 1, INT_TYPE, INT_TYPE, JMP_NEXT);
+ public final static JOpcode LCMP =
+ new JOpcode("LCMP",
+ cLCMP,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode FCMPL =
+ new JOpcode("FCMPL",
+ cFCMPL,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.FLOAT, JType.FLOAT },
+ JMP_NEXT);
+ public final static JOpcode FCMPG =
+ new JOpcode("FCMPG",
+ cFCMPG,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.FLOAT, JType.FLOAT },
+ JMP_NEXT);
+ public final static JOpcode DCMPL =
+ new JOpcode("DCMPL",
+ cDCMPL,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.LONG, JType.LONG },
+ JMP_NEXT);
+ public final static JOpcode DCMPG =
+ new JOpcode("DCMPG",
+ cDCMPG,
+ 1,
+ INT_TYPE,
+ new JType[] { JType.DOUBLE, JType.DOUBLE },
+ JMP_NEXT);
+ public final static JOpcode IFEQ =
+ new JOpcode("IFEQ", cIFEQ, 3, NO_DATA, INT_TYPE, JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IFNE =
+ new JOpcode("IFNE", cIFNE, 3, NO_DATA, INT_TYPE, JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IFLT =
+ new JOpcode("IFLT", cIFLT, 3, NO_DATA, INT_TYPE, JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IFGE =
+ new JOpcode("IFGE", cIFGE, 3, NO_DATA, INT_TYPE, JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IFGT =
+ new JOpcode("IFGT", cIFGT, 3, NO_DATA, INT_TYPE, JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IFLE =
+ new JOpcode("IFLE", cIFLE, 3, NO_DATA, INT_TYPE, JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IF_ICMPEQ =
+ new JOpcode("IF_ICMPEQ",
+ cIF_ICMPEQ,
+ 3,
+ NO_DATA,
+ new JType[] { JType.INT, JType.INT },
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IF_ICMPNE =
+ new JOpcode("IF_ICMPNE",
+ cIF_ICMPNE,
+ 3,
+ NO_DATA,
+ new JType[] { JType.INT, JType.INT },
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IF_ICMPLT =
+ new JOpcode("IF_ICMPLT",
+ cIF_ICMPLT,
+ 3,
+ NO_DATA,
+ new JType[] { JType.INT, JType.INT },
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IF_ICMPGE =
+ new JOpcode("IF_ICMPGE",
+ cIF_ICMPGE,
+ 3,
+ NO_DATA,
+ new JType[] { JType.INT, JType.INT },
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IF_ICMPGT =
+ new JOpcode("IF_ICMPGT",
+ cIF_ICMPGT,
+ 3,
+ NO_DATA,
+ new JType[] { JType.INT, JType.INT },
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IF_ICMPLE =
+ new JOpcode("IF_ICMPLE",
+ cIF_ICMPLE,
+ 3,
+ NO_DATA,
+ new JType[] { JType.INT, JType.INT },
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IF_ACMPEQ =
+ new JOpcode("IF_ACMPEQ",
+ cIF_ACMPEQ,
+ 3,
+ NO_DATA,
+ new JType[] { JType.REFERENCE, JType.REFERENCE },
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IF_ACMPNE =
+ new JOpcode("IF_ACMPNE",
+ cIF_ACMPNE,
+ 3,
+ NO_DATA,
+ new JType[] { JType.REFERENCE, JType.REFERENCE },
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode GOTO =
+ new JOpcode("GOTO", cGOTO, 3, NO_DATA, NO_DATA, JMP_ALWAYS_S2_OFFSET);
+ public final static JOpcode JSR =
+ new JOpcode("JSR", cJSR, 3, ADDRESS_TYPE, NO_DATA, JMP_ALWAYS_S2_OFFSET);
+ public final static JOpcode RET =
+ new JOpcode("RET", cRET, 2, NO_DATA, NO_DATA, JMP_NONE);
+ public final static JOpcode TABLESWITCH = new JOpcode("TABLESWITCH",
+ cTABLESWITCH,
+ UNKNOWN,
+ NO_DATA,
+ INT_TYPE,
+ JMP_TABLE);
+ public final static JOpcode LOOKUPSWITCH = new JOpcode("LOOKUPSWITCH",
+ cLOOKUPSWITCH,
+ UNKNOWN,
+ NO_DATA,
+ INT_TYPE,
+ JMP_LOOKUP);
+ public final static JOpcode IRETURN =
+ new JOpcode("IRETURN", cIRETURN, 1, NO_DATA, INT_TYPE, JMP_NONE);
+ public final static JOpcode LRETURN =
+ new JOpcode("LRETURN", cLRETURN, 1, NO_DATA, LONG_TYPE, JMP_NONE);
+ public final static JOpcode FRETURN =
+ new JOpcode("FRETURN", cFRETURN, 1, NO_DATA, FLOAT_TYPE, JMP_NONE);
+ public final static JOpcode DRETURN =
+ new JOpcode("DRETURN", cDRETURN, 1, NO_DATA, DOUBLE_TYPE, JMP_NONE);
+ public final static JOpcode ARETURN = new JOpcode("ARETURN",
+ cARETURN,
+ 1,
+ NO_DATA,
+ OBJECT_REF_TYPE,
+ JMP_NONE);
+ public final static JOpcode RETURN =
+ new JOpcode("RETURN", cRETURN, 1, NO_DATA, NO_DATA, JMP_NONE);
+ public final static JOpcode GETSTATIC = new JOpcode("GETSTATIC",
+ cGETSTATIC,
+ 3,
+ UNKNOWN_TYPE,
+ NO_DATA,
+ JMP_NEXT);
+ public final static JOpcode PUTSTATIC = new JOpcode("PUTSTATIC",
+ cPUTSTATIC,
+ 3,
+ NO_DATA,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode GETFIELD = new JOpcode("GETFIELD",
+ cGETFIELD,
+ 3,
+ UNKNOWN_TYPE,
+ OBJECT_REF_TYPE,
+ JMP_NEXT);
+ public final static JOpcode PUTFIELD =
+ new JOpcode("PUTFIELD", cPUTFIELD, 3, NO_DATA, UNKNOWN_TYPE, JMP_NEXT);
+ public final static JOpcode INVOKEVIRTUAL = new JOpcode("INVOKEVIRTUAL",
+ cINVOKEVIRTUAL,
+ 3,
+ NO_DATA,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode INVOKESPECIAL = new JOpcode("INVOKESPECIAL",
+ cINVOKESPECIAL,
+ 3,
+ NO_DATA,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode INVOKESTATIC = new JOpcode("INVOKESTATIC",
+ cINVOKESTATIC,
+ 3,
+ NO_DATA,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode INVOKEINTERFACE =
+ new JOpcode("INVOKEINTERFACE",
+ cINVOKEINTERFACE,
+ 5,
+ NO_DATA,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode NEW =
+ new JOpcode("NEW", cNEW, 3, OBJECT_REF_TYPE, NO_DATA, JMP_NEXT);
+ public final static JOpcode NEWARRAY =
+ new JOpcode("NEWARRAY",
+ cNEWARRAY,
+ 2,
+ ARRAY_REF_TYPE,
+ INT_TYPE,
+ JMP_NEXT);
+ public final static JOpcode ANEWARRAY =
+ new JOpcode("ANEWARRAY",
+ cANEWARRAY,
+ 3,
+ ARRAY_REF_TYPE,
+ INT_TYPE,
+ JMP_NEXT);
+ public final static JOpcode ARRAYLENGTH = new JOpcode("ARRAYLENGTH",
+ cARRAYLENGTH,
+ 1,
+ INT_TYPE,
+ ARRAY_REF_TYPE,
+ JMP_NEXT);
+ public final static JOpcode ATHROW = new JOpcode("ATHROW",
+ cATHROW,
+ 1,
+ OBJECT_REF_TYPE,
+ OBJECT_REF_TYPE,
+ JMP_NONE);
+ public final static JOpcode CHECKCAST = new JOpcode("CHECKCAST",
+ cCHECKCAST,
+ 3,
+ OBJECT_REF_TYPE,
+ OBJECT_REF_TYPE,
+ JMP_NEXT);
+ public final static JOpcode INSTANCEOF = new JOpcode("INSTANCEOF",
+ cINSTANCEOF,
+ 3,
+ INT_TYPE,
+ OBJECT_REF_TYPE,
+ JMP_NEXT);
+ public final static JOpcode MONITORENTER = new JOpcode("MONITORENTER",
+ cMONITORENTER,
+ 1,
+ NO_DATA,
+ OBJECT_REF_TYPE,
+ JMP_NEXT);
+ public final static JOpcode MONITOREXIT = new JOpcode("MONITOREXIT",
+ cMONITOREXIT,
+ 1,
+ NO_DATA,
+ OBJECT_REF_TYPE,
+ JMP_NEXT);
+ public final static JOpcode WIDE = new JOpcode("WIDE",
+ cWIDE,
+ UNKNOWN,
+ UNKNOWN_TYPE,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode MULTIANEWARRAY = new JOpcode("MULTIANEWARRAY",
+ cMULTIANEWARRAY,
+ 4,
+ ARRAY_REF_TYPE,
+ UNKNOWN_TYPE,
+ JMP_NEXT);
+ public final static JOpcode IFNULL = new JOpcode("IFNULL",
+ cIFNULL,
+ 3,
+ NO_DATA,
+ REFERENCE_TYPE,
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode IFNONNULL = new JOpcode("IFNONNULL",
+ cIFNONNULL,
+ 3,
+ NO_DATA,
+ REFERENCE_TYPE,
+ JMP_MAYBE_S2_OFFSET);
+ public final static JOpcode GOTO_W = new JOpcode("GOTO_W",
+ cGOTO_W,
+ 5,
+ NO_DATA,
+ NO_DATA,
+ JMP_ALWAYS_S4_OFFSET);
+ public final static JOpcode JSR_W =
+ new JOpcode("JSR_W", cJSR_W, 5, ADDRESS_TYPE, NO_DATA, JMP_NEXT);
+
+ public final static JOpcode[] OPCODES = {
+ NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
+ ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0,
+ LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0,
+ DCONST_1, BIPUSH, SIPUSH, LDC, LDC_W,
+ LDC2_W, ILOAD, LLOAD, FLOAD, DLOAD,
+ ALOAD, ILOAD_0, ILOAD_1, ILOAD_2, ILOAD_3,
+ LLOAD_0, LLOAD_1, LLOAD_2, LLOAD_3, FLOAD_0,
+ FLOAD_1, FLOAD_2, FLOAD_3, DLOAD_0, DLOAD_1,
+ DLOAD_2, DLOAD_3, ALOAD_0, ALOAD_1, ALOAD_2,
+ ALOAD_3, IALOAD, LALOAD, FALOAD, DALOAD,
+ AALOAD, BALOAD, CALOAD, SALOAD, ISTORE,
+ LSTORE, FSTORE, DSTORE, ASTORE, ISTORE_0,
+ ISTORE_1, ISTORE_2, ISTORE_3, LSTORE_0, LSTORE_1,
+ LSTORE_2, LSTORE_3, FSTORE_0, FSTORE_1, FSTORE_2,
+ FSTORE_3, DSTORE_0, DSTORE_1, DSTORE_2, DSTORE_3,
+ ASTORE_0, ASTORE_1, ASTORE_2, ASTORE_3, IASTORE,
+ LASTORE, FASTORE, DASTORE, AASTORE, BASTORE,
+ CASTORE, SASTORE, POP, POP2, DUP,
+ DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2,
+ SWAP, IADD, LADD, FADD, DADD,
+ ISUB, LSUB, FSUB, DSUB, IMUL,
+ LMUL, FMUL, DMUL, IDIV, LDIV,
+ FDIV, DDIV, IREM, LREM, FREM,
+ DREM, INEG, LNEG, FNEG, DNEG,
+ ISHL, LSHL, ISHR, LSHR, IUSHR,
+ LUSHR, IAND, LAND, IOR, LOR,
+ IXOR, LXOR, IINC, I2L, I2F,
+ I2D, L2I, L2F, L2D, F2I,
+ F2L, F2D, D2I, D2L, D2F,
+ I2B, I2C, I2S, LCMP, FCMPL,
+ FCMPG, DCMPL, DCMPG, IFEQ, IFNE,
+ IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
+ IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
+ IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, RET,
+ TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN,
+ DRETURN, ARETURN, RETURN, GETSTATIC, PUTSTATIC,
+ GETFIELD, PUTFIELD, INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC,
+ INVOKEINTERFACE, null, NEW, NEWARRAY, ANEWARRAY,
+ ARRAYLENGTH, ATHROW, CHECKCAST, INSTANCEOF, MONITORENTER,
+ MONITOREXIT, WIDE, MULTIANEWARRAY, IFNULL, IFNONNULL,
+ GOTO_W, JSR_W
+ };
+
+ protected JOpcode(String name,
+ int code,
+ int size,
+ JType[] producedDataTypes,
+ JType[] consumedDataTypes,
+ int jumpKind) {
+ this.name = name;
+ this.code = code;
+ this.size = size;
+ this.producedDataTypes = producedDataTypes;
+ this.consumedDataTypes = consumedDataTypes;
+ this.jumpKind = jumpKind;
+ switch (jumpKind) {
+ case JMP_NONE: successorCount = 0; break;
+ case JMP_NEXT: successorCount = 1; break;
+ case JMP_ALWAYS_S2_OFFSET: successorCount = 1; break;
+ case JMP_ALWAYS_S4_OFFSET: successorCount = 1; break;
+ case JMP_MAYBE_S2_OFFSET: successorCount = 2; break;
+ case JMP_TABLE: successorCount = UNKNOWN; break;
+ case JMP_LOOKUP: successorCount = UNKNOWN; break;
+ default: successorCount = UNKNOWN; break;
+ }
+ }
+
+ public String toString() { return name; }
+ protected int getSize() { return size; }
+ protected JType[] getProducedDataTypes() { return producedDataTypes; }
+ protected JType[] getConsumedDataTypes() { return consumedDataTypes; }
+
+ protected int getProducedDataSize() {
+ if (producedDataTypes != UNKNOWN_TYPE)
+ return JType.getTotalSize(producedDataTypes);
+ else {
+ switch (code) {
+ case cLDC: case cLDC_W: case cBALOAD:
+ return 1;
+ case cLDC2_W: case cDUP: case cSWAP:
+ return 2;
+ case cDUP_X1:
+ return 3;
+ case cDUP_X2: case cDUP2:
+ return 4;
+ case cDUP2_X1:
+ return 5;
+ case cDUP2_X2:
+ return 6;
+ default:
+ throw new Error(this.toString());
+ }
+ }
+ }
+
+ protected int getConsumedDataSize() {
+ if (consumedDataTypes != UNKNOWN_TYPE)
+ return JType.getTotalSize(consumedDataTypes);
+ else {
+ switch (code) {
+ case cPOP: case cDUP:
+ return 1;
+ case cPOP2: case cDUP_X1: case cDUP2: case cSWAP:
+ return 2;
+ case cDUP_X2: case cDUP2_X1:
+ return 3;
+ case cDUP2_X2:
+ return 4;
+ default:
+ throw new Error(this.toString());
+ }
+ }
+ }
+
+ protected int getProducedDataTypesNumber() {
+ if (producedDataTypes != UNKNOWN_TYPE)
+ return producedDataTypes.length;
+ else {
+ switch (code) {
+ case cLDC: case cLDC_W: case cLDC2_W: case cBALOAD:
+ case cGETSTATIC: case cGETFIELD:
+ return 1;
+ case cDUP: case cSWAP:
+ return 2;
+ case cDUP_X2: case cDUP2: case cDUP2_X1: case cDUP2_X2:
+ return 2;
+ case cDUP_X1:
+ return 3;
+ default:
+ throw new Error(this.toString());
+ }
+ }
+ }
+
+ protected int getConsumedDataTypesNumber() {
+ if (consumedDataTypes != UNKNOWN_TYPE)
+ return consumedDataTypes.length;
+ else {
+ switch (code) {
+ case cPOP: case cDUP: case cPUTSTATIC:
+ return 1;
+ case cPUTFIELD: case cDUP_X1: case cDUP_X2:
+ case cDUP2: case cDUP2_X1: case cPOP2: case cSWAP:
+ return 2;
+ default:
+ throw new Error(this.toString());
+ }
+ }
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JOtherAttribute.java b/src/fjbg/ch/epfl/lamp/fjbg/JOtherAttribute.java
new file mode 100644
index 0000000000..ad73540940
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JOtherAttribute.java
@@ -0,0 +1,54 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.io.*;
+
+/**
+ * Attributes which are unknown to the JVM (or at least to this
+ * library).
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public class JOtherAttribute extends JAttribute {
+ protected final String name;
+ protected final byte[] contents;
+ protected final int length;
+
+ public JOtherAttribute(FJBGContext context,
+ JClass clazz,
+ Object owner,
+ String name,
+ byte[] contents,
+ int length) {
+ super(context, clazz, name);
+ this.name = name;
+ this.contents = contents;
+ this.length = length;
+ }
+
+ public JOtherAttribute(FJBGContext context,
+ JClass clazz,
+ Object owner,
+ String name,
+ int size,
+ DataInputStream stream)
+ throws IOException {
+ super(context, clazz, name);
+ this.name = name;
+ this.contents = new byte[size];
+ this.length = size;
+
+ stream.read(contents, 0, length);
+ }
+
+ public String getName() { return name; }
+
+ protected int getSize() { return length; }
+
+ protected void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.write(contents, 0, length);
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JReferenceType.java b/src/fjbg/ch/epfl/lamp/fjbg/JReferenceType.java
new file mode 100644
index 0000000000..99c6acff71
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JReferenceType.java
@@ -0,0 +1,16 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+/**
+ * Types for Java references, i.e. arrays and objects.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+abstract public class JReferenceType extends JType {
+ public boolean isReferenceType() { return true; }
+
+ abstract public String getDescriptor();
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JSourceFileAttribute.java b/src/fjbg/ch/epfl/lamp/fjbg/JSourceFileAttribute.java
new file mode 100644
index 0000000000..77d6783c87
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JSourceFileAttribute.java
@@ -0,0 +1,53 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Sourcefile attribute, which can be attached to class files to
+ * associate them with their source file.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+public class JSourceFileAttribute extends JAttribute {
+ protected final String sourceFileName;
+ protected final int sourceFileIndex;
+
+ public JSourceFileAttribute(FJBGContext context,
+ JClass clazz,
+ String sourceFileName) {
+ super(context, clazz);
+ this.sourceFileName = sourceFileName;
+ this.sourceFileIndex = clazz.getConstantPool().addUtf8(sourceFileName);
+ }
+
+ public JSourceFileAttribute(FJBGContext context,
+ JClass clazz,
+ Object owner,
+ String name,
+ int size,
+ DataInputStream stream)
+ throws IOException {
+ super(context, clazz);
+ stream.readInt(); // ignore size
+ this.sourceFileIndex = stream.readShort();
+ this.sourceFileName = clazz.getConstantPool().lookupUtf8(sourceFileIndex);
+
+ assert name.equals(getName());
+ }
+
+ public String getName() { return "SourceFile"; }
+
+ protected int getSize() {
+ return 2;
+ }
+
+ protected void writeContentsTo(DataOutputStream stream) throws IOException {
+ stream.writeShort(sourceFileIndex);
+ }
+}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JType.java b/src/fjbg/ch/epfl/lamp/fjbg/JType.java
new file mode 100644
index 0000000000..2557d45b83
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JType.java
@@ -0,0 +1,289 @@
+// $Id$
+
+package ch.epfl.lamp.fjbg;
+
+import java.util.*;
+import java.io.StringReader;
+import java.io.IOException;
+
+/**
+ * Representation of Java types.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+abstract public class JType {
+ abstract public int getSize();
+ abstract public String getSignature();
+ abstract public int getTag();
+ abstract public String toString();
+ abstract public boolean isCompatibleWith(JType other);
+
+ public boolean isValueType() { return false; }
+ public boolean isObjectType() { return false; }
+ public boolean isArrayType() { return false; }
+ public boolean isReferenceType() { return false; }
+
+ // Tags for types. Taken from BCEL.
+ public static final int T_BOOLEAN = 4;
+ public static final int T_CHAR = 5;
+ public static final int T_FLOAT = 6;
+ public static final int T_DOUBLE = 7;
+ public static final int T_BYTE = 8;
+ public static final int T_SHORT = 9;
+ public static final int T_INT = 10;
+ public static final int T_LONG = 11;
+ public static final int T_VOID = 12; // Non-standard
+ public static final int T_ARRAY = 13;
+ public static final int T_OBJECT = 14;
+ public static final int T_UNKNOWN = 15;
+ public static final int T_ADDRESS = 16;
+
+ public static final int T_REFERENCE = 17; // type compatible with references
+
+ public static final JType[] EMPTY_ARRAY = new JType[0];
+
+ protected static JType parseSig(StringReader s) throws IOException {
+ int nextChar = s.read();
+ if (nextChar == -1) throw new IllegalArgumentException();
+
+ switch ((char)nextChar) {
+ case 'V' : return VOID;
+ case 'Z' : return BOOLEAN;
+ case 'B' : return BYTE;
+ case 'C' : return CHAR;
+ case 'S' : return SHORT;
+ case 'I' : return INT;
+ case 'F' : return FLOAT;
+ case 'J' : return LONG;
+ case 'D' : return DOUBLE;
+ case 'L': {
+ StringBuffer className = new StringBuffer();
+ for (;;) {
+ nextChar = s.read();
+ if (nextChar == -1 || nextChar == ';') break;
+ className.append(nextChar == '/' ? ':' : ((char)nextChar));
+ }
+ if (nextChar != ';') throw new IllegalArgumentException();
+ return new JObjectType(className.toString());
+ }
+ case '[': {
+ JType elemType = parseSig(s);
+ return new JArrayType(elemType);
+ }
+ case '(': {
+ ArrayList argTps = new ArrayList();
+ for (;;) {
+ s.mark(1);
+ nextChar = s.read();
+ if (nextChar == -1 || nextChar == ')') break;
+ s.reset();
+ argTps.add(parseSig(s));
+ }
+ if (nextChar != ')') throw new IllegalArgumentException("a");
+ JType[] argTpsA = (JType[])argTps.toArray(new JType[argTps.size()]);
+ JType returnType = parseSig(s);
+ return new JMethodType(returnType, argTpsA);
+ }
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public static JType parseSignature(String signature) {
+ try {
+ StringReader sigReader = new StringReader(signature);
+ JType parsed = parseSig(sigReader);
+ if (sigReader.read() != -1)
+ throw new IllegalArgumentException();
+ return parsed;
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("invalid signature " + signature);
+ } catch (IOException e) {
+ throw new Error(e);
+ }
+ }
+
+ public static int getTotalSize(JType[] types) {
+ int size = 0;
+ for (int i = 0; i < types.length; ++i)
+ size += types[i].getSize();
+ return size;
+ }
+
+ protected JType() {}
+
+ public static JType VOID = new JType() {
+ public int getSize() { return 0; }
+ public String getSignature() { return "V"; }
+ public int getTag() { return T_VOID; }
+ public String toString() { return "void"; }
+ public boolean isCompatibleWith(JType other) {
+ throw new UnsupportedOperationException("type VOID is no real "
+ + "data type therefore "
+ + "cannot be assigned to "
+ + other.toString());
+ }
+ };
+
+ public static JType BOOLEAN = new JType() {
+ public int getSize() { return 1; }
+ public String getSignature() { return "Z"; }
+ public int getTag() { return T_BOOLEAN; }
+ public String toString() { return "boolean"; }
+ public boolean isValueType() { return true; }
+ public boolean isCompatibleWith(JType other) {
+ return other == BOOLEAN
+ || other == INT
+ || other == BYTE
+ || other == CHAR
+ || other == SHORT;
+ }
+ };
+
+ public static JType BYTE = new JType() {
+ public int getSize() { return 1; }
+ public String getSignature() { return "B"; }
+ public int getTag() { return T_BYTE; }
+ public String toString() { return "byte"; }
+ public boolean isValueType() { return true; }
+ public boolean isCompatibleWith(JType other) {
+ return other == BOOLEAN
+ || other == INT
+ || other == BYTE
+ || other == CHAR
+ || other == SHORT;
+ }
+ };
+
+ public static JType CHAR = new JType() {
+ public int getSize() { return 1; }
+ public String getSignature() { return "C"; }
+ public int getTag() { return T_CHAR; }
+ public String toString() { return "char"; }
+ public boolean isValueType() { return true; }
+ public boolean isCompatibleWith(JType other) {
+ return other == BOOLEAN
+ || other == INT
+ || other == BYTE
+ || other == CHAR
+ || other == SHORT;
+ }
+ };
+
+ public static JType SHORT = new JType() {
+ public int getSize() { return 1; }
+ public String getSignature() { return "S"; }
+ public int getTag() { return T_SHORT; }
+ public String toString() { return "short"; }
+ public boolean isValueType() { return true; }
+ public boolean isCompatibleWith(JType other) {
+ return other == BOOLEAN
+ || other == INT
+ || other == BYTE
+ || other == CHAR
+ || other == SHORT;
+ }
+ };
+
+ public static JType INT = new JType() {
+ public int getSize() { return 1; }
+ public String getSignature() { return "I"; }
+ public int getTag() { return T_INT; }
+ public String toString() { return "int"; }
+ public boolean isValueType() { return true; }
+ public boolean isCompatibleWith(JType other) {
+ return other == BOOLEAN
+ || other == INT
+ || other == BYTE
+ || other == CHAR
+ || other == SHORT;
+ }
+ };
+
+ public static JType FLOAT = new JType() {
+ public int getSize() { return 1; }
+ public String getSignature() { return "F"; }
+ public int getTag() { return T_FLOAT; }
+ public String toString() { return "float"; }
+ public boolean isValueType() { return true; }
+ public boolean isCompatibleWith(JType other) {
+ return other == FLOAT;
+ }
+ };
+
+ public static JType LONG = new JType() {
+ public int getSize() { return 2; }
+ public String getSignature() { return "J"; }
+ public int getTag() { return T_LONG; }
+ public String toString() { return "long"; }
+ public boolean isValueType() { return true; }
+ public boolean isCompatibleWith(JType other) {
+ return other == LONG;
+ }
+ };
+
+ public static JType DOUBLE = new JType() {
+ public int getSize() { return 2; }
+ public String getSignature() { return "D"; }
+ public int getTag() { return T_DOUBLE; }
+ public String toString() { return "double"; }
+ public boolean isValueType() { return true; }
+ public boolean isCompatibleWith(JType other) {
+ return other == DOUBLE;
+ }
+ };
+
+ public static JType REFERENCE = new JType() {
+ public int getSize() { return 1; }
+ public String getSignature() {
+ throw new UnsupportedOperationException("type REFERENCE is no real "
+ + "data type and therefore "
+ + "has no signature");
+ }
+ public int getTag() { return T_REFERENCE; }
+ public String toString() { return "<reference>"; }
+ public boolean isCompatibleWith(JType other) {
+ throw new UnsupportedOperationException("type REFERENCE is no real "
+ + "data type and therefore "
+ + "cannot be assigned to "
+ + other.toString());
+ }
+ };
+
+ public static JType ADDRESS = new JType() {
+ public int getSize() { return 1; }
+ public String getSignature() {
+ throw new UnsupportedOperationException("type ADDRESS is no usable "
+ + "data type and therefore "
+ + "has no signature");
+ }
+ public int getTag() { return T_ADDRESS; }
+ public String toString() { return "<address>"; }
+ public boolean isCompatibleWith(JType other) {
+ return other == ADDRESS;
+ }
+ };
+
+ public static JType UNKNOWN = new JType() {
+ public int getSize() {
+ throw new UnsupportedOperationException("type UNKNOWN is no real "
+ + "data type and therefore "
+ + "has no size");
+ }
+ public String getSignature() {
+ throw new UnsupportedOperationException("type UNKNOWN is no real "
+ + "data type and therefore "
+ + "has no signature");
+ }
+ public int getTag() { return T_UNKNOWN; }
+ public String toString() { return "<unknown>"; }
+ public boolean isCompatibleWith(JType other) {
+ throw new UnsupportedOperationException("type UNKNOWN is no real "
+ + "data type and therefore "
+ + "cannot be assigned to "
+ + other.toString());
+ }
+ };
+}
diff --git a/src/fjbg/ch/epfl/lamp/util/ByteArray.java b/src/fjbg/ch/epfl/lamp/util/ByteArray.java
new file mode 100644
index 0000000000..800fc9d0d8
--- /dev/null
+++ b/src/fjbg/ch/epfl/lamp/util/ByteArray.java
@@ -0,0 +1,140 @@
+// $Id$
+
+package ch.epfl.lamp.util;
+
+import java.io.*;
+
+/**
+ * Array of bytes.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public class ByteArray {
+ protected final static int BYTE_BLOCK_BITS = 8;
+ protected final static int BYTE_BLOCK_SIZE = 1 << BYTE_BLOCK_BITS;
+ protected final static int BYTE_BLOCK_MASK = BYTE_BLOCK_SIZE - 1;
+
+ protected byte[][] data = new byte[][] { new byte[BYTE_BLOCK_SIZE] };
+ protected int pos = 0; // The next free position.
+
+ protected boolean frozen = false;
+
+ public ByteArray() { }
+
+ public ByteArray(InputStream stream, int size) throws IOException {
+ size = pos;
+ for (int block = 0; size > 0; ++block) {
+ int sizeToRead = Math.min(BYTE_BLOCK_SIZE, size);
+ stream.read(data[block], 0, sizeToRead);
+
+ size -= sizeToRead;
+ if (size > 0) addNewBlock();
+ }
+ }
+
+ public void freeze() { frozen = true; }
+
+ public int nextBytePosition() {
+ return pos;
+ }
+
+ public int getSize() {
+ return pos;
+ }
+
+ protected void addNewBlock() {
+ int nextBlockPos = pos >>> BYTE_BLOCK_BITS;
+ if (nextBlockPos == data.length) {
+ byte[][] newData = new byte[data.length * 2][];
+ System.arraycopy(data, 0, newData, 0, data.length);
+ data = newData;
+ }
+ assert data[nextBlockPos] == null : pos + " " + nextBlockPos;
+ data[nextBlockPos] = new byte[BYTE_BLOCK_SIZE];
+ }
+
+ protected void addByte(int b) {
+ assert !frozen;
+
+ if ((pos & BYTE_BLOCK_MASK) == 0 && pos > 0)
+ addNewBlock();
+ int currPos = pos++;
+ data[currPos >>> BYTE_BLOCK_BITS][currPos & BYTE_BLOCK_MASK] = (byte)b;
+ }
+
+ public void addU1(int i) {
+ assert i <= 0xFF : i;
+ addByte(i);
+ }
+
+ public void addU2(int i) {
+ assert i <= 0xFFFF : i;
+
+ addByte(i >>> 8);
+ addByte(i & 0xFF);
+ }
+
+ public void addU4(int i) {
+ addByte(i >>> 24);
+ addByte((i >>> 16) & 0xFF);
+ addByte((i >>> 8) & 0xFF);
+ addByte(i & 0xFF);
+ }
+
+ public void putByte(int targetPos, int b) {
+ assert !frozen;
+ assert targetPos < pos : targetPos + " >= " + pos;
+
+ data[targetPos >>> BYTE_BLOCK_BITS][targetPos & BYTE_BLOCK_MASK] = (byte)b;
+ }
+
+ public void putU2(int targetPos, int i) {
+ assert i < 0xFFFF : i;
+ putByte(targetPos, i >>> 8);
+ putByte(targetPos + 1, i & 0xFF);
+ }
+
+ public void putU4(int targetPos, int i) {
+ putByte(targetPos, i >>> 24);
+ putByte(targetPos + 1, (i >>> 16) & 0xFF);
+ putByte(targetPos + 2, (i >>> 8) & 0xFF);
+ putByte(targetPos + 3, i & 0xFF);
+ }
+
+ public int getU1(int sourcePos) {
+ assert sourcePos < pos : sourcePos + " >= " + pos;
+ return data[sourcePos >>> BYTE_BLOCK_BITS][sourcePos & BYTE_BLOCK_MASK] & 0xFF;
+ }
+
+ public int getU2(int sourcePos) {
+ return (getU1(sourcePos) << 8) | getU1(sourcePos + 1);
+ }
+
+ public int getU4(int sourcePos) {
+ return (getU2(sourcePos) << 16) | getU2(sourcePos + 2);
+ }
+
+ public int getS1(int sourcePos) {
+ assert sourcePos < pos : sourcePos + " >= " + pos;
+ return data[sourcePos >>> BYTE_BLOCK_BITS][sourcePos & BYTE_BLOCK_MASK];
+ }
+
+ public int getS2(int sourcePos) {
+ return (getS1(sourcePos) << 8) | getU1(sourcePos + 1);
+ }
+
+ public int getS4(int sourcePos) {
+ return (getS2(sourcePos) << 16) | getU2(sourcePos + 2);
+ }
+
+ public void writeTo(OutputStream stream) throws IOException {
+ if (!frozen) freeze();
+
+ for (int i = 0; i < data.length && data[i] != null; ++i) {
+ int len = Math.min(BYTE_BLOCK_SIZE, pos - (i << BYTE_BLOCK_BITS));
+ stream.write(data[i], 0, len);
+ }
+ }
+}