Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/Descriptor.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/Descriptor.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/Descriptor.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/Descriptor.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,556 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.util.Stack; +import java.util.Map; + +//@olsen: subst: Hashtable -> Map, HashMap + + +/** + * A collection of static methods which manipulate type descriptors + */ +public class Descriptor implements VMConstants { + /** + * Return the number of words of arguments to the method + * based on the method signature + */ + public static int countMethodArgWords(String sig) { + if (sig.charAt(0) != '(') + throw new InsnError ("not a method signature"); + int count = 0; + for (int idx = 1; sig.charAt(idx) != ')'; idx++) { + switch (sig.charAt(idx)) { + case 'B': /* byte */ + case 'C': /* char */ + case 'S': /* short */ + case 'I': /* int */ + case 'F': /* float */ + case 'Z': /* boolean */ + count++; + break; + case 'J': /* long */ + case 'D': /* double */ + count += 2; + break; + case 'L': + count++; + idx = sig.indexOf(';', idx); + break; + case '[': + count++; + while (sig.charAt(idx) == '[' || sig.charAt(idx) == ']') + idx++; + if (sig.charAt(idx) == 'L') + idx = sig.indexOf(';', idx); + /* else, let idx++ at loop iteration skip primitive descriptor */ + break; + default: + throw new InsnError("missing case"); + } + } + return count; + } + + /** + * Return the number of words of return value for the method + * based on the method signature + */ + public static int countMethodReturnWords(String sig) { + int idx = sig.lastIndexOf(')') + 1; + if (idx == 0) + throw new InsnError ("not a method signature"); + switch (sig.charAt(idx)) { + case 'J': /* long */ + case 'D': /* double */ + return 2; + case 'B': /* byte */ + case 'C': /* char */ + case 'S': /* short */ + case 'I': /* int */ + case 'F': /* float */ + case 'Z': /* boolean */ + case 'L': /* object */ + case '[': /* array */ + return 1; + case 'V': /* void */ + return 0; + default: + throw new InsnError("missing case"); + } + } + + /** + * Return the stack descriptor for the result of a method + * invocation. Void return values yield "V". + */ + public static String extractResultSig(String methodSig) { + return methodSig.substring(methodSig.indexOf(')')+1); + } + + /** + * Return the stack descriptor for the arguments to a method + * invocation (not including any "this" argument) + */ + public static String extractArgSig(String methodSig) { + return methodSig.substring(1, methodSig.indexOf(')')); + } + + /** + * Return the reversed stack descriptor for the arguments to a method + * invocation (not including any "this" argument). The top of stack + * element will be first. + */ + public static String extractReversedArgSig(String methodSig) { + StringBuffer buf = new StringBuffer();; + reverseArgSig(buf, methodSig, 1); + return buf.toString(); + } + + /** + * Given a StringBuffer, a method descriptor, and a index to the + * start of an argument descriptor, append the arguments to the + * string buffer in reverse order. + */ + private static void reverseArgSig(StringBuffer buf, String methodSig, + int idx) { + char c = methodSig.charAt(idx); + if (c == ')') + return; + int startIdx = idx; + + switch(c) { + case 'B': + case 'C': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + case 'Z': + idx = idx+1; + break; + case '[': + while (methodSig.charAt(idx) == '[' || methodSig.charAt(idx) == ']') + idx++; + if (methodSig.charAt(idx) != 'L') { + idx++; + break; + } + /* fall through */ + case 'L': + idx = methodSig.indexOf(';', idx) + 1; + break; + default: + throw new InsnError("bad signature char"); + } + + reverseArgSig(buf, methodSig, idx); + while (startIdx < idx) + buf.append(methodSig.charAt(startIdx++)); + } + + /** + * Return the number of words of a field based on its signature. + */ + //@olsen: added method + public static int countFieldWords(String sig) { + if (sig == null || sig.length() < 1) + throw new InsnError ("not a field signature"); + switch (sig.charAt(0)) { + case 'J': /* long */ + case 'D': /* double */ + return 2; + case 'B': /* byte */ + case 'C': /* char */ + case 'S': /* short */ + case 'I': /* int */ + case 'F': /* float */ + case 'Z': /* boolean */ + case 'L': /* object */ + case '[': /* array */ + return 1; + default: + throw new InsnError("missing case"); + } + } + + /** + * Return the element type for the first char in the type descriptor string. + */ + //@olsen: added method + public static int elementType(String sig) { + if (sig == null || sig.length() < 1) + throw new InsnError ("not a value signature"); + switch(sig.charAt(0)) { + case 'B': + return T_BOOLEAN; + case 'C': + return T_CHAR; + case 'Z': + return T_BYTE; + case 'S': + return T_SHORT; + case 'I': + return T_INT; + case 'J': + return T_LONG; + case 'F': + return T_FLOAT; + case 'D': + return T_DOUBLE; + case '[': + return TC_OBJECT; + case 'L': + return TC_OBJECT; + default: + throw new InsnError("bad signature char"); + } + } + + /** + * Return the element type descriptor char for the element type. + * The element type must be one of the T_ or TC_OBJECT. + */ + public static String elementSig(int valueType) { + switch(valueType) { + case T_BYTE: + return "B"; + case T_CHAR: + return "C"; + case T_BOOLEAN: + return "Z"; + case T_SHORT: + return "S"; + case T_INT: + return "I"; + case T_LONG: + return "J"; + case T_FLOAT: + return "F"; + case T_DOUBLE: + return "D"; + case TC_OBJECT: + return "Ljava/lang/Object;"; + default: + throw new InsnError("bad element type"); + } + } + + /** + * Return the number of stack words required for a value of the specified + * type on the operand stack. + */ + public static int elementSize(int elementType) { + switch(elementType) { + case T_LONG: + case T_DOUBLE: + case T_TWOWORD: + return 2; + default: + return 1; + } + } + + /** + * stackSig is a signature for a list of types on the JVM stack with the + * last type in the signature intended to be on the top of JVM stack. + * For each type in the signature, pushes an Integer objects identifying + * the types on top of the input Stack object. + */ + public static void computeStackTypes(String stackSig, Stack stack) { + for (int idx = 0; idx < stackSig.length(); idx++) { + int tp = 0; + switch(stackSig.charAt(idx)) { + case 'B': + case 'C': + case 'Z': + case 'S': + case 'I': + tp = T_INT; + break; + case 'F': + tp = T_FLOAT; + break; + case 'J': + tp = T_LONG; + break; + case 'D': + tp = T_DOUBLE; + break; + case '?': + tp = T_UNKNOWN; + break; + case 'W': + tp = T_WORD; + break; + case 'X': + tp = T_TWOWORD; + break; + case 'A': + /* This isn't a real type, but any object refrence */ + tp = TC_OBJECT; + break; + case '[': + tp = TC_OBJECT; + while (stackSig.charAt(idx) == '[' || stackSig.charAt(idx) == ']') + idx++; + if (stackSig.charAt(idx) != 'L') + break; + /* fall through */ + case 'L': + tp = TC_OBJECT; + idx = stackSig.indexOf(';', idx); + break; + default: + throw new InsnError("bad signature char"); + } + stack.push(new Integer(tp)); + } + } + + /** + * stackSig is a signature for the types on the stack with the last + * type in the signature on the top of stack. idx is the index of + * the start of a valid signature type element. Return the index of + * the next element (which may be past the end of the string). + */ + public static int nextSigElement(String stackSig, int idx) { + switch(stackSig.charAt(idx)) { + case 'B': + case 'C': + case 'Z': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + break; + case '[': + while (stackSig.charAt(idx) == '[' || stackSig.charAt(idx) == ']') + idx++; + if (stackSig.charAt(idx) != 'L') + break; + /* fall through */ + case 'L': + idx = stackSig.indexOf(';', idx); + break; + default: + throw new InsnError("bad signature char"); + } + + idx++; + return idx; + } + + /** + * classTranslations contains a set of mappings of class names. + * For any types within the input signature which appear as keys + * in the translation table, change the signature to replace the + * original type with the translation. Return a string containing + * the original signature with any translations applied. + */ + public static String remapTypes(String sig, Map classTranslations) { + /* Defer allocation of the string buffer until it's needed */ + StringBuffer buf = null; + + for (int idx = 0; idx < sig.length(); idx++) { + char c; + switch(c = sig.charAt(idx)) { + case '[': + /* An array - skip through the [] pairs, copying to buf if not null */ + while ((c = sig.charAt(idx)) == '[' || c == ']') { + idx++; + if (buf != null) + buf.append(c); + } + + /* If the next char isnt 'L', the next char is a simple type and + will be handled by the default 1 char translation */ + if (sig.charAt(idx) != 'L') + break; + /* fall through to type name translation */ + case 'L': + /* This is a type name */ + idx++; + int endIdx = sig.indexOf(';', idx); + String typeName = sig.substring(idx, endIdx); + String mapTo = (String) classTranslations.get(typeName); + if (mapTo != null) { + /* This type needs translation - allocate the string buffer + now if needed and copy in all up to this type name. */ + if (buf == null) { + buf = new StringBuffer(sig.length() + 20); + buf.append(sig.substring(0,idx-1)); + } + typeName = mapTo; + } + + if (buf != null) { + buf.append('L'); + buf.append(typeName); + } + idx = endIdx; + c = ';'; + break; + } + + if (buf != null) + buf.append(c); + } + return (buf == null) ? sig : (buf.toString()); + } + + /** + * classTranslations contains a set of mappings of class names. + * Translate the class name (which may be an array class) according + * to the entries in the translation table. + * Return either the original string if no translation applies or + * else the translated string. + */ + public static String translateClass( + String cls, Map classTranslations) { + if (cls.charAt(0) == '[') + return remapTypes(cls, classTranslations); + else { + String mapTo = (String) classTranslations.get(cls); + if (mapTo != null) + return mapTo; + return cls; + } + } + + /** + * Translates a VM type field signature into a user-format signature. + * Just a front for the two argument overload of this method. + */ + public static String userFieldSig(String vmSig) { + return userFieldSig(vmSig, 0); + } + + /** + * Translates a VM type field signature into a user-format signature. + */ + public static String userFieldSig(String vmSig, int idx) { + String sigElement = ""; + int arrayDims = 0; + boolean moreSig = true; + while (moreSig) { + moreSig = false; + char c = vmSig.charAt(idx); + switch (c) { + case 'B': + sigElement = "byte"; + break; + case 'C': + sigElement = "char"; + break; + case 'Z': + sigElement = "boolean"; + break; + case 'S': + sigElement = "short"; + break; + case 'I': + sigElement = "int"; + break; + case 'F': + sigElement = "float"; + break; + case 'J': + sigElement = "long"; + break; + case 'D': + sigElement = "double"; + break; + case 'V': + /* void isn't really valid as a field signature but this method + might be useful in implementing method signature conversion and + void is a valid return type. */ + sigElement = "void"; + break; + case '[': + idx++; + arrayDims++; + moreSig = true; + break; + case 'L': + int nextIdx = vmSig.indexOf(';', idx); + sigElement = vmSig.substring(idx+1,nextIdx).replace('/','.'); + break; + default: + throw new InsnError("bad signature char"); + } + } + + /* If a non-array type, we already have the answer */ + if (arrayDims == 0) + return sigElement; + + /* array types need a little more work */ + StringBuffer buf = new StringBuffer(sigElement.length() + + 2 * arrayDims); + buf.append(sigElement); + while (arrayDims-- > 0) + buf.append("[]"); + + return buf.toString(); + } + + /** + * Produce a user consumable representation of a method argument list + * from the method signature. The return value is ignored. + */ + public static String userMethodArgs(String methodSig) { + /* This better be a method signature */ + if (methodSig.charAt(0) != '(') + throw new InsnError("Invalid method signature"); + + StringBuffer buf = new StringBuffer(); + + buf.append('('); + + int idx = 1; + boolean firstArg = true; + while (methodSig.charAt(idx) != ')') { + if (firstArg) + firstArg = false; + else + buf.append(", "); + + buf.append(userFieldSig(methodSig, idx)); + idx = nextSigElement(methodSig, idx); + } + + buf.append(')'); + return buf.toString(); + } + + /** + * Produce a user consumable representation of a method result type + * from the method signature. The argument list is ignored. + */ + //@olsen: added method + public static String userMethodResult(String methodSig) { + /* This better be a method signature */ + if (methodSig.charAt(0) != '(') + throw new InsnError("Invalid method signature"); + return userFieldSig(extractResultSig(methodSig)); + } +}
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionRange.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionRange.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionRange.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionRange.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,157 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; +import java.util.Stack; + +/** + * ExceptionRange represents a range an exception handler within + * a method in class file. + */ +public class ExceptionRange { + /* The start of the exception hander (inclusive) */ + private InsnTarget excStartPC; + + /* The end of the exception hander (exclusive) */ + private InsnTarget excEndPC; + + /* The exception handler code */ + private InsnTarget excHandlerPC; + + /* The exception specification */ + private ConstClass excCatchType; + + /* public accessors */ + + /** + * return the start of the exception hander (inclusive) + */ + public InsnTarget startPC() { + return excStartPC; + } + + /** + * return the end of the exception hander (exclusive) + */ + public InsnTarget endPC() { + return excEndPC; + } + + /** + * return the exception handler code + */ + public InsnTarget handlerPC() { + return excHandlerPC; + } + + /** + * return the exception specification + * a null return value means a catch of any (try/finally) + */ + public ConstClass catchType() { + return excCatchType; + } + + /** + * constructor + */ + public ExceptionRange(InsnTarget startPC, InsnTarget endPC, + InsnTarget handlerPC, ConstClass catchType) { + excStartPC = startPC; + excEndPC = endPC; + excHandlerPC = handlerPC; + excCatchType = catchType; + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof ExceptionRange)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + ExceptionRange other = (ExceptionRange)obj; + + if (!this.excStartPC.isEqual(msg, other.excStartPC)) { + msg.push(String.valueOf("excStartPC = " + + other.excStartPC)); + msg.push(String.valueOf("excStartPC = " + + this.excStartPC)); + return false; + } + if (!this.excEndPC.isEqual(msg, other.excEndPC)) { + msg.push(String.valueOf("excEndPC = " + + other.excEndPC)); + msg.push(String.valueOf("excEndPC = " + + this.excEndPC)); + return false; + } + if (!this.excHandlerPC.isEqual(msg, other.excHandlerPC)) { + msg.push(String.valueOf("excHandlerPC = " + + other.excHandlerPC)); + msg.push(String.valueOf("excHandlerPC = " + + this.excHandlerPC)); + return false; + } + if (!this.excCatchType.isEqual(msg, other.excCatchType)) { + msg.push(String.valueOf("excCatchType = " + + other.excCatchType)); + msg.push(String.valueOf("excCatchType = " + + this.excCatchType)); + return false; + } + return true; + } + + /* package local methods */ + + static ExceptionRange read(DataInputStream data, CodeEnv env) + throws IOException { + InsnTarget startPC = env.getTarget(data.readUnsignedShort()); + InsnTarget endPC = env.getTarget(data.readUnsignedShort()); + InsnTarget handlerPC = env.getTarget(data.readUnsignedShort()); + ConstClass catchType = + (ConstClass) env.pool().constantAt(data.readUnsignedShort()); + return new ExceptionRange(startPC, endPC, handlerPC, catchType); + } + + void write(DataOutputStream out) throws IOException { + out.writeShort(excStartPC.offset()); + out.writeShort(excEndPC.offset()); + out.writeShort(excHandlerPC.offset()); + out.writeShort(excCatchType == null ? 0 : excCatchType.getIndex()); + } + + void print(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.print("Exc Range:"); + if (excCatchType == null) + out.print("any"); + else + out.print("'" + excCatchType.asString() + "'"); + out.print(" start = " + Integer.toString(excStartPC.offset())); + out.print(" end = " + Integer.toString(excEndPC.offset())); + out.println(" handle = " + Integer.toString(excHandlerPC.offset())); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionTable.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionTable.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionTable.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionTable.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,113 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; +import java.util.Stack; +import java.util.Vector; +import java.util.Enumeration; + +/** + * ExceptionTable represents the exception handlers within the code + * of a method. + */ +public class ExceptionTable { + /* A variable length list of ExceptionRange objects */ + //@olsen: renamed theVector -> handlers + private Vector handlers = new Vector(); + + /* public accessors */ + + /** + * Return an enumeration of the exception handlers + * Each element in the enumeration is an ExceptionRange + */ + public Enumeration handlers() { + return handlers.elements(); + } + + /** + * Add an exception handler to the list + */ + public void addElement(ExceptionRange range) { + handlers.addElement(range); + } + + public ExceptionTable() { } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof ExceptionTable)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + ExceptionTable other = (ExceptionTable)obj; + + if (this.handlers.size() != other.handlers.size()) { + msg.push("handlers.size() " + + String.valueOf(other.handlers.size())); + msg.push("handlers.size() " + + String.valueOf(this.handlers.size())); + return false; + } + + for (int i = 0; i < handlers.size(); i++) { + ClassAttribute h1 = (ClassAttribute)this.handlers.get(i); + ClassAttribute h2 = (ClassAttribute)other.handlers.get(i); + if (!h1.isEqual(msg, h2)) { + msg.push("handlers[" + i + "] = " + + String.valueOf(h2)); + msg.push("handlers[" + i + "] = " + + String.valueOf(h1)); + return false; + } + } + return true; + } + + /* package local methods */ + + static ExceptionTable read(DataInputStream data, CodeEnv env) + throws IOException { + ExceptionTable excTable = new ExceptionTable(); + int nExcepts = data.readUnsignedShort(); + while (nExcepts-- > 0) { + excTable.addElement(ExceptionRange.read(data, env)); + } + return excTable; + } + + void write(DataOutputStream out) throws IOException { + out.writeShort(handlers.size()); + for (int i=0; i<handlers.size(); i++) + ((ExceptionRange) handlers.elementAt(i)).write(out); + } + + void print(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.println("Exception Table: "); + for (int i=0; i<handlers.size(); i++) + ((ExceptionRange) handlers.elementAt(i)).print(out, indent+2); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionsAttribute.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionsAttribute.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionsAttribute.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/ExceptionsAttribute.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,160 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; +import java.util.Stack; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Vector; +import java.util.Enumeration; + +/** + * ExceptionsAttribute represents a method attribute in a class file + * listing the checked exceptions for the method. + */ +public class ExceptionsAttribute extends ClassAttribute { + public final static String expectedAttrName = "Exceptions"; + + /* The list of checked exceptions */ + private Vector exceptionTable; + + /* public accessors */ + + /** + * Return an enumeration of the checked exceptions + */ + public Enumeration exceptions() { + return exceptionTable.elements(); + } + + /** + * Returns the vector of the checked exceptions. + */ + //@olsen: added method + public Vector getExceptions() { + return exceptionTable; + } + + /** + * Constructor + */ + public ExceptionsAttribute(ConstUtf8 attrName, Vector excTable) { + super(attrName); + exceptionTable = excTable; + } + + /** + * Convenience Constructor - for single exception + */ + public ExceptionsAttribute(ConstUtf8 attrName, ConstClass exc) { + super(attrName); + exceptionTable = new Vector(1); + exceptionTable.addElement(exc); + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof ExceptionsAttribute)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + ExceptionsAttribute other = (ExceptionsAttribute)obj; + + if (!super.isEqual(msg, other)) { + return false; + } + + if (this.exceptionTable.size() != other.exceptionTable.size()) { + msg.push("exceptionTable.size() " + + String.valueOf(other.exceptionTable.size())); + msg.push("exceptionTable.size() " + + String.valueOf(this.exceptionTable.size())); + return false; + } + + // sort exceptions by name + class ConstClassComparator implements Comparator { + public int compare(Object o1, Object o2) { + ConstClass c1 = (ConstClass)o1; + ConstClass c2 = (ConstClass)o2; + String s1 = c1.className().asString(); + String s2 = c2.className().asString(); + return s1.compareTo(s2); + } + } + ConstClassComparator comparator = new ConstClassComparator(); + ConstClass[] thisExceptionTable + = (ConstClass[])this.exceptionTable.toArray(new ConstClass[0]); + ConstClass[] otherExceptionTable + = (ConstClass[])other.exceptionTable.toArray(new ConstClass[0]); + Arrays.sort(thisExceptionTable, comparator); + Arrays.sort(otherExceptionTable, comparator); + for (int i = 0; i < exceptionTable.size(); i++) { + ConstClass c1 = thisExceptionTable[i]; + ConstClass c2 = otherExceptionTable[i]; + if (!c1.isEqual(msg, c2)) { + msg.push("exceptionTable[i] = " + String.valueOf(c2)); + msg.push("exceptionTable[i] = " + String.valueOf(c1)); + return false; + } + } + return true; + } + + /* package local methods */ + + static ExceptionsAttribute read(ConstUtf8 attrName, + DataInputStream data, ConstantPool pool) + throws IOException { + int nExcepts = data.readUnsignedShort(); + Vector excTable = new Vector(); + while (nExcepts-- > 0) { + int excIndex = data.readUnsignedShort(); + ConstClass exc_class = null; + if (excIndex != 0) + exc_class = (ConstClass) pool.constantAt(excIndex); + excTable.addElement(exc_class); + } + + return new ExceptionsAttribute(attrName, excTable); + } + + void write(DataOutputStream out) throws IOException { + out.writeShort(attrName().getIndex()); + out.writeInt(2+2*exceptionTable.size()); + out.writeShort(exceptionTable.size()); + for (int i=0; i<exceptionTable.size(); i++) + out.writeShort(((ConstClass) exceptionTable.elementAt(i)).getIndex()); + } + + void print(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.print("Exceptions:"); + for (int i=0; i<exceptionTable.size(); i++) + out.print(" " + ((ConstClass) exceptionTable.elementAt(i)).asString()); + out.println(); + } + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/GenericAttribute.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/GenericAttribute.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/GenericAttribute.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/GenericAttribute.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,106 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.*; +import java.util.Stack; + +/** + * GenericAttribute represents a class attribute in a class file which + * is not recognized as any supported attribute type. These attributes + * are maintained, and are not modified in any way. + */ + +public class GenericAttribute extends ClassAttribute { + + /* The bytes of the attribute following the name */ + byte attributeBytes[]; + + /* public accessors */ + + /** + * constructor + */ + public GenericAttribute(ConstUtf8 attrName, byte attrBytes[]) { + super(attrName); + attributeBytes = attrBytes; + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof GenericAttribute)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + GenericAttribute other = (GenericAttribute)obj; + + if (!super.isEqual(msg, other)) { + return false; + } + + if (this.attributeBytes.length != other.attributeBytes.length) { + msg.push("attributeBytes.length " + + String.valueOf(other.attributeBytes.length)); + msg.push("attributeBytes.length " + + String.valueOf(this.attributeBytes.length)); + return false; + } + + for (int i = 0; i < attributeBytes.length; i++) { + byte b1 = this.attributeBytes[i]; + byte b2 = other.attributeBytes[i]; + if (b1 != b2) { + msg.push("attributeBytes[" + i + "] = " + + String.valueOf(b2)); + msg.push("attributeBytes[" + i + "] = " + + String.valueOf(b1)); + return false; + } + } + return true; + } + + void write(DataOutputStream out) throws IOException { + out.writeShort(attrName().getIndex()); + out.writeInt(attributeBytes.length); + out.write(attributeBytes, 0, attributeBytes.length); + } + + void print(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.println("Generic Attribute(" + attrName().asString() + "): " + + Integer.toString(attributeBytes.length) + + " in length"); + for (int i=0; i<attributeBytes.length; i++) { + if ((i % 16) == 0) { + if (i != 0) + out.println(); + out.print(i + " :"); + } + out.print(" " + Integer.toString((attributeBytes[i] & 0xff), 16)); + } + out.println(); + } +} + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/Insn.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/Insn.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/Insn.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/Insn.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,660 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.PrintStream; +import java.util.Stack; + +/** + * Insn is an abstract class which represents a java VM instruction in a + * sequence of instructions. + */ +abstract public class Insn implements VMConstants { + /* An instruction with no pc defined yet */ + final static int NO_OFFSET = -1; + + /* A special magic opcode for branch target pseudo instructions */ + final public static int opc_target = -1; + + /* The opcode of this instruction */ + private int insnOpcode; + + /* The pc of this instruction within the containing code sequence */ + private int insnOffset = NO_OFFSET; + + /* The next instruction in the code sequence */ + private Insn nextInsn = null; + + /* The previous instruction in the code sequence */ + private Insn prevInsn = null; + + /* public accessors */ + + /** + * Returns the next instruction in the code sequence + */ + public Insn next() { + return nextInsn; + } + + /** + * Returns the previous instruction in the code sequence + */ + public Insn prev() { + return prevInsn; + } + + /** + * Removes the current instruction from it's embedding sequence. + */ + //@olsen: added method + public void remove() { + if (nextInsn != null) + nextInsn.prevInsn = prevInsn; + + if (prevInsn != null) + prevInsn.nextInsn = nextInsn; + + prevInsn = null; + nextInsn = null; + } + + /** + * Insert the single instruction in the code sequence after this + * instruction. + * Returns the inserted instruction. + */ + public Insn setNext(Insn i) { + if (nextInsn != null) + nextInsn.prevInsn = i; + + if (i != null) { + i.nextInsn = nextInsn; + i.prevInsn = this; + } + nextInsn = i; + return i; + } + + /** + * Insert an instruction sequence in the code sequence after this + * instruction. + * Returns the final instruction. + */ + public Insn insert(Insn i) { + if (i == null) + return this; + + Insn theNextInsn = nextInsn; + nextInsn = i; + i.prevInsn = this; + + while (i.nextInsn != null) + i = i.nextInsn; + i.nextInsn = theNextInsn; + if (theNextInsn != null) + theNextInsn.prevInsn = i; + return i; + } + + /** + * Append an instruction sequence at the end of this instruction + * sequence. + * Returns the final instruction. + */ + public Insn append(Insn i) { + Insn thisInsn = this; + while (thisInsn.nextInsn != null) + thisInsn = thisInsn.nextInsn; + return thisInsn.insert(i); + } + + /** + * Return the opcode for this instruction + */ + public int opcode() { + return insnOpcode; + } + + /** + * Return the offset of this instruction in the containing code sequence + */ + public int offset() { + return insnOffset; + } + + /** + * How many words of stack operands does this instruction take? + */ + abstract public int nStackArgs(); + + /** + * How many words of stack results does this instruction deposit? + */ + abstract public int nStackResults(); + + /** + * What are the types of the stack operands ? + */ + abstract public String argTypes(); + + /** + * What are the types of the stack results? + */ + abstract public String resultTypes(); + + /** + * Does this instruction branch? + */ + abstract public boolean branches(); + + /** + * Mark possible branch targets + */ + public void markTargets() { + } + + /** + * Return the name of the operation for a given opcode + */ + public static String opName(int opcode) { + if (opcode == opc_target) + return "target:"; + if (opcode >=0 && opcode <= VMOp.ops.length) + return VMOp.ops[opcode].name(); + else + throw new InsnError("invalid opcode for opName: " + opcode); + } + + /* Instruction creation interfaces - these should be used for all + * instructions except opc_iinc, opc_tableswitch, opc_lookupswitch, + * opc_multidimarraynew, and opc_invokeinterface. + */ + + /** + * Create an instruction which requires no immediate operands + */ + public static Insn create(int theOpCode) { + return new InsnSingle(theOpCode); + } + + /** + * Create an instruction which requires a single constant from the + * constant pool as an immediate operand. + */ + public static Insn create(int theOpCode, ConstBasic constValue) { + return new InsnConstOp(theOpCode, constValue); + } + + /** + * Create an instruction which requires a single integral constant + * as an immediate operand. + */ + public static Insn create(int theOpCode, int intValue) { + return new InsnIntOp(theOpCode, intValue); + } + + /** + * Create an instruction which requires a single branch offset + * as an immediate operand. + */ + public static Insn create(int theOpCode, InsnTarget target) { + return new InsnTargetOp(theOpCode, target); + } + + /** + * Print the sequence of instructions to the output stream + */ + public void printList(PrintStream out) { + Insn insn = this; + while (insn != null) { + insn.print(out, 0); + insn = insn.next(); + } + } + + /** + * Print this instruction to the output stream + */ + public void printInsn(PrintStream out) { + print(out, 0); + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof Insn)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + Insn other = (Insn)obj; + + if (this.insnOpcode != other.insnOpcode) { + // be tolerant against opc_ldc vs. opc_ldc_w + if (!((this.insnOpcode == opc_ldc + || this.insnOpcode == opc_ldc_w) + && (other.insnOpcode == opc_ldc + || other.insnOpcode == opc_ldc_w))) { + msg.push(String.valueOf("insnOpcode = " + + other.insnOpcode)); + msg.push(String.valueOf("insnOpcode = " + + this.insnOpcode)); + return false; + } + } + // offsets may differ due to different byte length + // (e.g. opc_ldc vs. opc_ldc_w) + //if (this.insnOffset != other.insnOffset) { + // msg.push(String.valueOf("insnOffset = " + // + other.insnOffset)); + // msg.push(String.valueOf("insnOffset = " + // + this.insnOffset)); + // return false; + //} + return true; + } + + /** + * A printable representation + */ + public String toString() { + return ("Insn: " + "insnOpcode(" + opName(insnOpcode) + ")" + + " insnOffset(" + insnOffset + ")"); + } + + /* package local methods */ + + abstract void print(PrintStream out, int indent); + + abstract int store(byte[] buf, int index); + + /* return the size of the instruction in bytes + * Note: some instructions are unable to answer correctly until their + * start offset is known + */ + abstract int size(); + + /* Set the offset of the instruction and return the offset of the + following instruction */ + + final int resolveOffset(int pc) { + insnOffset = pc; + return pc + size(); + } + + Insn(int theOpcode, int theOffset) { + insnOpcode = theOpcode; + insnOffset = theOffset; + } + + static int storeInt(byte buf[], int index, int v) { + buf[index++] = (byte) (v >> 24); + buf[index++] = (byte) ((v >> 16) & 0xff); + buf[index++] = (byte) ((v >> 8) & 0xff); + buf[index++] = (byte) (v & 0xff); + return index; + } + + + static int storeShort(byte buf[], int index, short v) { + buf[index++] = (byte) ((v >> 8) & 0xff); + buf[index++] = (byte) (v & 0xff); + return index; + } + + static Insn read(InsnReadEnv insnEnv) { + boolean widen = false; + int pc = insnEnv.currentPC(); + + int op = insnEnv.getUByte(); + if (op == opc_wide) { + widen = true; + op = insnEnv.getUByte(); + } + + switch (op) { + case opc_nop: + case opc_aconst_null: + case opc_iconst_m1: + case opc_iconst_0: + case opc_iconst_1: + case opc_iconst_2: + case opc_iconst_3: + case opc_iconst_4: + case opc_iconst_5: + case opc_lconst_0: + case opc_lconst_1: + case opc_fconst_0: + case opc_fconst_1: + case opc_fconst_2: + case opc_dconst_0: + case opc_dconst_1: + case opc_iload_0: + case opc_iload_1: + case opc_iload_2: + case opc_iload_3: + case opc_lload_0: + case opc_lload_1: + case opc_lload_2: + case opc_lload_3: + case opc_fload_0: + case opc_fload_1: + case opc_fload_2: + case opc_fload_3: + case opc_dload_0: + case opc_dload_1: + case opc_dload_2: + case opc_dload_3: + case opc_aload_0: + case opc_aload_1: + case opc_aload_2: + case opc_aload_3: + case opc_iaload: + case opc_laload: + case opc_faload: + case opc_daload: + case opc_aaload: + case opc_baload: + case opc_caload: + case opc_saload: + case opc_istore_0: + case opc_istore_1: + case opc_istore_2: + case opc_istore_3: + case opc_lstore_0: + case opc_lstore_1: + case opc_lstore_2: + case opc_lstore_3: + case opc_fstore_0: + case opc_fstore_1: + case opc_fstore_2: + case opc_fstore_3: + case opc_dstore_0: + case opc_dstore_1: + case opc_dstore_2: + case opc_dstore_3: + case opc_astore_0: + case opc_astore_1: + case opc_astore_2: + case opc_astore_3: + case opc_iastore: + case opc_lastore: + case opc_fastore: + case opc_dastore: + case opc_aastore: + case opc_bastore: + case opc_castore: + case opc_sastore: + case opc_pop: + case opc_pop2: + case opc_dup: + case opc_dup_x1: + case opc_dup_x2: + case opc_dup2: + case opc_dup2_x1: + case opc_dup2_x2: + case opc_swap: + case opc_iadd: + case opc_ladd: + case opc_fadd: + case opc_dadd: + case opc_isub: + case opc_lsub: + case opc_fsub: + case opc_dsub: + case opc_imul: + case opc_lmul: + case opc_fmul: + case opc_dmul: + case opc_idiv: + case opc_ldiv: + case opc_fdiv: + case opc_ddiv: + case opc_irem: + case opc_lrem: + case opc_frem: + case opc_drem: + case opc_ineg: + case opc_lneg: + case opc_fneg: + case opc_dneg: + case opc_ishl: + case opc_lshl: + case opc_ishr: + case opc_lshr: + case opc_iushr: + case opc_lushr: + case opc_iand: + case opc_land: + case opc_ior: + case opc_lor: + case opc_ixor: + case opc_lxor: + case opc_i2l: + case opc_i2f: + case opc_i2d: + case opc_l2i: + case opc_l2f: + case opc_l2d: + case opc_f2i: + case opc_f2l: + case opc_f2d: + case opc_d2i: + case opc_d2l: + case opc_d2f: + case opc_i2b: + case opc_i2c: + case opc_i2s: + case opc_lcmp: + case opc_fcmpl: + case opc_fcmpg: + case opc_dcmpl: + case opc_dcmpg: + case opc_ireturn: + case opc_lreturn: + case opc_freturn: + case opc_dreturn: + case opc_areturn: + case opc_return: + case opc_xxxunusedxxx: + case opc_arraylength: + case opc_athrow: + case opc_monitorenter: + case opc_monitorexit: + return new InsnSingle(op, pc); + + case opc_ldc: + return new InsnConstOp(op, insnEnv.pool().constantAt(insnEnv.getUByte()), + pc); + + case opc_ldc_w: + case opc_ldc2_w: + case opc_getstatic: + case opc_putstatic: + case opc_getfield: + case opc_putfield: + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + case opc_new: + case opc_anewarray: + case opc_checkcast: + case opc_instanceof: + return new InsnConstOp(op, + insnEnv.pool().constantAt(insnEnv.getUShort()), + pc); + + case opc_iload: + case opc_lload: + case opc_fload: + case opc_dload: + case opc_aload: + case opc_istore: + case opc_lstore: + case opc_fstore: + case opc_dstore: + case opc_astore: + case opc_ret: + if (widen) + return new InsnIntOp(op, insnEnv.getShort(), pc); + else + return new InsnIntOp(op, insnEnv.getByte(), pc); + + case opc_bipush: /* a byte constant */ + case opc_newarray: + return new InsnIntOp(op, insnEnv.getByte(), pc); + + case opc_sipush: /* a short constant */ + return new InsnIntOp(op, insnEnv.getShort(), pc); + + case opc_iinc: + if (widen) + return new InsnIInc(insnEnv.getUShort(), insnEnv.getShort(), pc); + else + return new InsnIInc(insnEnv.getUByte(), insnEnv.getByte(), pc); + + case opc_ifeq: + case opc_ifne: + case opc_iflt: + case opc_ifge: + case opc_ifgt: + case opc_ifle: + case opc_if_icmpeq: + case opc_if_icmpne: + case opc_if_icmplt: + case opc_if_icmpge: + case opc_if_icmpgt: + case opc_if_icmple: + case opc_if_acmpeq: + case opc_if_acmpne: + case opc_goto: + case opc_jsr: + case opc_ifnull: + case opc_ifnonnull: + return new InsnTargetOp(op, insnEnv.getTarget(insnEnv.getShort()+pc), pc); + + case opc_goto_w: + case opc_jsr_w: + return new InsnTargetOp(op, insnEnv.getTarget(insnEnv.getInt()+pc), pc); + + case opc_tableswitch: + return InsnTableSwitch.read(insnEnv, pc); + + case opc_lookupswitch: + return InsnLookupSwitch.read(insnEnv, pc); + + case opc_invokeinterface: + return InsnInterfaceInvoke.read(insnEnv, pc); + + case opc_multianewarray: + return InsnMultiDimArrayNew.read(insnEnv, pc); + } + throw new InsnError("Invalid byte code (" + op + ")"); + } + + /** + * Return the type of value manipulated by the load/store instruction + */ + public static final int loadStoreDataType(int opcode) { + switch(opcode) { + case opc_iload: + case opc_iload_0: + case opc_iload_1: + case opc_iload_2: + case opc_iload_3: + case opc_istore: + case opc_istore_0: + case opc_istore_1: + case opc_istore_2: + case opc_istore_3: + case opc_iaload: + case opc_baload: + case opc_caload: + case opc_saload: + case opc_iastore: + case opc_bastore: + case opc_castore: + case opc_sastore: + return T_INT; + + case opc_lload: + case opc_lload_0: + case opc_lload_1: + case opc_lload_2: + case opc_lload_3: + case opc_lstore: + case opc_lstore_0: + case opc_lstore_1: + case opc_lstore_2: + case opc_lstore_3: + case opc_laload: + case opc_lastore: + return T_LONG; + + case opc_fload: + case opc_fload_0: + case opc_fload_1: + case opc_fload_2: + case opc_fload_3: + case opc_fstore: + case opc_fstore_0: + case opc_fstore_1: + case opc_fstore_2: + case opc_fstore_3: + case opc_faload: + case opc_fastore: + return T_FLOAT; + + case opc_dload: + case opc_dload_0: + case opc_dload_1: + case opc_dload_2: + case opc_dload_3: + case opc_dstore: + case opc_dstore_0: + case opc_dstore_1: + case opc_dstore_2: + case opc_dstore_3: + case opc_daload: + case opc_dastore: + return T_DOUBLE; + + case opc_aload: + case opc_aload_0: + case opc_aload_1: + case opc_aload_2: + case opc_aload_3: + case opc_astore: + case opc_astore_0: + case opc_astore_1: + case opc_astore_2: + case opc_astore_3: + case opc_aaload: + case opc_aastore: + return TC_OBJECT; + + default: + throw new InsnError("not a load/store"); + } + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnConstOp.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnConstOp.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnConstOp.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnConstOp.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,318 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + + +import java.io.PrintStream; +import java.util.Stack; + +/** + * An instruction which requires a single constant from the constant + * pool as an immediate operand + */ +public class InsnConstOp extends Insn { + /* The constant from the constant pool */ + private ConstBasic constValue; + + /* public accessors */ + + public int nStackArgs() { + int n = VMOp.ops[opcode()].nStackArgs(); + if (n >= 0) + return n; + switch (opcode()) { + case opc_putstatic: + case opc_putfield: + { + ConstFieldRef fld = (ConstFieldRef) constValue; + String sig = fld.nameAndType().signature().asString(); + if (sig.equals("J") || sig.equals("D")) + return (opcode() == opc_putfield) ? 3 : 2; + return (opcode() == opc_putfield) ? 2 : 1; + } + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + /* handle interface invoke too */ + case opc_invokeinterface: + { + ConstBasicMemberRef meth = (ConstBasicMemberRef) constValue; + String sig = meth.nameAndType().signature().asString(); + int nMethodArgWords = Descriptor.countMethodArgWords(sig); + return nMethodArgWords + + ((opcode() == opc_invokestatic) ? 0 : 1); + } + default: + throw new InsnError("unexpected variable opcode"); + } + } + + public int nStackResults() { + int n = VMOp.ops[opcode()].nStackResults(); + if (n >= 0) + return n; + switch (opcode()) { + case opc_getstatic: + case opc_getfield: + { + ConstFieldRef fld = (ConstFieldRef) constValue; + String sig = fld.nameAndType().signature().asString(); + if (sig.equals("J") || sig.equals("D")) + return 2; + return 1; + } + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + /* handle interface invoke too */ + case opc_invokeinterface: + { + ConstBasicMemberRef meth = (ConstBasicMemberRef) constValue; + return Descriptor.countMethodReturnWords( + meth.nameAndType().signature().asString()); + } + default: + throw new InsnError("unexpected variable opcode"); + } + } + + public String argTypes() { + switch (opcode()) { + case opc_putstatic: + case opc_putfield: + { + ConstFieldRef fld = (ConstFieldRef) constValue; + String sig = fld.nameAndType().signature().asString(); + if (opcode() == opc_putstatic) + return sig; + else + return descriptorTypeOfObject(fld) + sig; + } + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + /* handle interface invoke too */ + case opc_invokeinterface: + { + ConstBasicMemberRef meth = (ConstBasicMemberRef) constValue; + String argSig = + Descriptor.extractArgSig(meth.nameAndType().signature().asString()); + if (opcode() == opc_invokestatic) + return argSig; + else + return descriptorTypeOfObject(meth) + argSig; + } + default: + return VMOp.ops[opcode()].argTypes(); + } + } + + public String resultTypes() { + switch (opcode()) { + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + /* handle interface invoke too */ + case opc_invokeinterface: + { + ConstBasicMemberRef meth = (ConstBasicMemberRef) constValue; + String resultSig = Descriptor.extractResultSig( + meth.nameAndType().signature().asString()); + if (resultSig.equals("V")) + return ""; + return resultSig; + } + case opc_getstatic: + case opc_getfield: + { + ConstFieldRef fld = (ConstFieldRef) constValue; + return fld.nameAndType().signature().asString(); + } + case opc_ldc: + case opc_ldc_w: + case opc_ldc2_w: + { + ConstValue constVal = (ConstValue) constValue; + return constVal.descriptor(); + } + default: + return VMOp.ops[opcode()].resultTypes(); + } + } + + public boolean branches() { + /* invokes don't count as a branch */ + return false; + } + + /** + * Return the constant pool entry which is the immediate operand + */ + public ConstBasic value() { + return constValue; + } + + /** + * Modify the referenced constant + */ + public void setValue(ConstBasic newValue) { + checkConstant(newValue); + constValue = newValue; + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof InsnConstOp)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + InsnConstOp other = (InsnConstOp)obj; + + if (!super.isEqual(msg, other)) { + return false; + } + + if (!this.constValue.isEqual(msg, other.constValue)) { + msg.push(String.valueOf("constValue = " + + other.constValue)); + msg.push(String.valueOf("constValue = " + + this.constValue)); + return false; + } + return true; + } + + /* package local methods */ + + void print(PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.println(offset() + " " + opName(opcode()) + " pool(" + + constValue.getIndex() + ")"); + } + + int store(byte[] buf, int index) { + if (opcode() == opc_ldc && !isNarrowldc()) + buf[index++] = (byte) opc_ldc_w; + else + buf[index++] = (byte) opcode(); + int constIndex = constValue.getIndex(); + if (size() == 3) + buf[index++] = (byte) (constIndex >> 8); + buf[index++] = (byte)(constIndex & 0xff); + return index; + } + + int size() { + return isNarrowldc() ? 2 : 3; + } + + private boolean isNarrowldc() { + return (opcode() == opc_ldc && constValue.getIndex() < 256); + } + + + InsnConstOp(int theOpcode, ConstBasic theOperand) { + this(theOpcode, theOperand, NO_OFFSET); + } + + InsnConstOp(int theOpcode, ConstBasic theOperand, int pc) { + super(theOpcode, pc); + constValue = theOperand; + checkConstant(theOperand); + if (theOpcode == opc_invokeinterface) + throw new InsnError("attempt to create an " + opName(theOpcode) + + " as an InsnConstOp instead of InsnInterfaceInvoke"); + } + + /* used only by InsnInterfaceInvoke, to make sure that opc_invokeinterface cannot + * come through the wrong path and miss its extra nArgsOp */ + InsnConstOp(int theOpcode, ConstInterfaceMethodRef theOperand, int pc) { + super(theOpcode, pc); + constValue = theOperand; + checkConstant(theOperand); + } + + private void checkConstant(ConstBasic operand) { + switch(opcode()) { + case opc_ldc: + case opc_ldc_w: + case opc_ldc2_w: + /* ConstValue */ + if (operand == null || + (! (operand instanceof ConstValue))) + throw new InsnError ("attempt to create an " + opName(opcode()) + + " without a ConstValue operand"); + break; + + case opc_getstatic: + case opc_putstatic: + case opc_getfield: + case opc_putfield: + /* ConstFieldRef */ + if (operand == null || + (! (operand instanceof ConstFieldRef))) + throw new InsnError ("attempt to create an " + opName(opcode()) + + " without a ConstFieldRef operand"); + break; + + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + /* ConstMethodRef */ + if (operand == null || + (! (operand instanceof ConstMethodRef))) + throw new InsnError ("attempt to create an " + opName(opcode()) + + " without a ConstMethodRef operand"); + break; + + case opc_invokeinterface: + /* ConstInterfaceMethodRef */ + if (operand == null || + (! (operand instanceof ConstInterfaceMethodRef))) + throw new InsnError("Attempt to create an " + opName(opcode()) + + " without a ConstInterfaceMethodRef operand"); + break; + + case opc_new: + case opc_anewarray: + case opc_checkcast: + case opc_instanceof: + /* ConstClass */ + if (operand == null || + (! (operand instanceof ConstClass))) + throw new InsnError ("attempt to create an " + opName(opcode()) + + " without a ConstClass operand"); + break; + + default: + throw new InsnError ("attempt to create an " + opName(opcode()) + + " with a constant operand"); + } + } + + private final String descriptorTypeOfObject(ConstBasicMemberRef memRef) { + String cname = memRef.className().className().asString(); + return "L" + cname + ";"; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnError.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnError.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnError.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnError.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,28 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +/** + * An exception thrown when an error occurs in encoding or decoding + * instruction sequences + */ +public class InsnError extends RuntimeException { + public InsnError(String s) { + super(s); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnIInc.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnIInc.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnIInc.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnIInc.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,156 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + + +import java.io.PrintStream; +import java.util.Stack; + +/** + * Special instruction form for the opc_iinc instruction + */ +public class InsnIInc extends Insn { + + /* The local variable slot to be incremented */ + private int localVarIndex; + + /* The amount by which the slot is to be incremented */ + private int value; + + /* public accessors */ + + public int nStackArgs() { + return 0; + } + + public int nStackResults() { + return 0; + } + + /** + * What are the types of the stack operands ? + */ + public String argTypes() { + return ""; + } + + /** + * What are the types of the stack results? + */ + public String resultTypes() { + return ""; + } + + public boolean branches() { + return false; + } + + /** + * The local variable slot to be incremented + */ + public int varIndex() { + return localVarIndex; + } + + /** + * The amount by which the slot is to be incremented + */ + public int incrValue() { + return value; + } + + /** + * Constructor for opc_iinc instruction + */ + public InsnIInc (int localVarIndex, int value) { + this(localVarIndex, value, NO_OFFSET); + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof InsnIInc)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + InsnIInc other = (InsnIInc)obj; + + if (!super.isEqual(msg, other)) { + return false; + } + + if (this.localVarIndex != other.localVarIndex) { + msg.push(String.valueOf("localVarIndex = " + + other.localVarIndex)); + msg.push(String.valueOf("localVarIndex = " + + this.localVarIndex)); + return false; + } + if (this.value != other.value) { + msg.push(String.valueOf("value = " + + other.value)); + msg.push(String.valueOf("value = " + + this.value)); + return false; + } + return true; + } + + /* package local methods */ + + InsnIInc (int localVarIndex, int value, int pc) { + super(opc_iinc, pc); + + this.localVarIndex = localVarIndex; + this.value =value; + } + + void print (PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.println(offset() + " opc_iinc " + + localVarIndex + "," + value); + } + + int store(byte[] buf, int index) { + if (isWide()) + buf[index++] = (byte) opc_wide; + buf[index++] = (byte) opcode(); + if (isWide()) { + index = storeShort(buf, index, (short) localVarIndex); + index = storeShort(buf, index, (short) value); + } else { + buf[index++] = (byte)localVarIndex; + buf[index++] = (byte)value; + } + return index; + } + + int size() { + return isWide() ? 6 : 3; + } + + private boolean isWide() { + return (value > 127 || value < -128 || localVarIndex > 255); + } + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnIntOp.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnIntOp.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnIntOp.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnIntOp.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,209 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.PrintStream; +import java.util.Stack; + +/** + * An instruction which requires a integral constant as an immediate operand + */ + +public class InsnIntOp extends Insn { + /* The operand */ + private int operandValue; + + /* public accessors */ + + public int nStackArgs() { + return VMOp.ops[opcode()].nStackArgs(); + } + + public int nStackResults() { + return VMOp.ops[opcode()].nStackResults(); + } + + public String argTypes() { + return VMOp.ops[opcode()].argTypes(); + } + + public String resultTypes() { + return VMOp.ops[opcode()].resultTypes(); + } + + public boolean branches() { + return opcode() == opc_ret; + } + + public int value() { + return operandValue; + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof InsnIntOp)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + InsnIntOp other = (InsnIntOp)obj; + + if (!super.isEqual(msg, other)) { + return false; + } + + if (this.operandValue != other.operandValue) { + msg.push(String.valueOf("operandValue = " + + other.operandValue)); + msg.push(String.valueOf("operandValue = " + + this.operandValue)); + return false; + } + return true; + } + + /* package local methods */ + + static String primType(int primIndex) { + switch (primIndex) { + case T_BOOLEAN: + return "boolean"; + case T_CHAR: + return "char"; + case T_FLOAT: + return "float"; + case T_DOUBLE: + return "double"; + case T_BYTE: + return "byte"; + case T_SHORT: + return "short"; + case T_INT: + return "int"; + case T_LONG: + return "long"; + default: + throw new InsnError ("Invalid primitive type(" + primIndex + ")"); + } + } + + void print (PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + if (opcode() == opc_newarray) + out.println(offset() + " opc_newarray " + primType(operandValue)); + else + out.println(offset() + " " + opName(opcode()) + " " + operandValue); + } + + int store(byte[] buf, int index) { + if (size() == 4) { + /* prefix with an opc_wide */ + buf[index++] = (byte) opc_wide; + } + + buf[index++] = (byte) opcode(); + if (size() > 2) + buf[index++] = (byte)(operandValue >> 8); + buf[index++] = (byte)(operandValue & 0xff); + return index; + } + + + /* return the size of the instruction in bytes */ + + int size() { + switch(opcode()) { + case opc_bipush: + case opc_newarray: + /* These are always 1 byte constants */ + return 2; + + case opc_sipush: /* a short constant */ + /* This is always a 2 byte constant */ + return 3; + + case opc_iload: + case opc_lload: + case opc_fload: + case opc_dload: + case opc_aload: + case opc_istore: + case opc_lstore: + case opc_fstore: + case opc_dstore: + case opc_astore: + case opc_ret: + /* These can be one or two byte constants specifying a local var. + * If a two byte constant, the constant is prefixed by a wide + * instruction */ + if (operandValue < 256) + return 2; + else + return 4; + + default: + throw new InsnError ("invalid instruction " + opName(opcode()) + + " with an integer operand"); + } + } + + + InsnIntOp (int theOpcode, int theOperand, int pc) { + super(theOpcode, pc); + + operandValue = theOperand; + } + + + InsnIntOp (int theOpcode, int theOperand) { + super(theOpcode, NO_OFFSET); + + operandValue = theOperand; + switch(theOpcode) { + case opc_bipush: + case opc_newarray: + /* These are always 1 byte constants */ + + case opc_sipush: /* a short constant */ + /* This is always a 2 byte constant */ + + case opc_dload: + case opc_lload: + case opc_iload: + case opc_fload: + case opc_aload: + case opc_istore: + case opc_lstore: + case opc_fstore: + case opc_dstore: + case opc_astore: + case opc_ret: + /* These can be one or two byte constants specifying a local var */ + break; + + default: + throw new InsnError ("attempt to create an " + opName(theOpcode) + + " with an integer operand"); + } + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnInterfaceInvoke.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnInterfaceInvoke.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnInterfaceInvoke.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/InsnInterfaceInvoke.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,146 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +import java.io.PrintStream; +import java.util.Stack; + +/** + * Special instruction form for the opc_invokeinterface instruction + */ +public class InsnInterfaceInvoke extends InsnConstOp { + /* The number of arguments to the interface method */ + private int nArgsOp; + + /* public accessors */ + + public int nStackArgs() { + return super.nStackArgs(); + } + + public int nStackResults() { + return super.nStackResults(); + } + + /** + * What are the types of the stack operands ? + */ + public String argTypes() { + return super.argTypes(); + } + + /** + * What are the types of the stack results? + */ + public String resultTypes() { + return super.resultTypes(); + } + + public boolean branches() { + return false; + } + + /** + * Return the interface to be invoked + */ + public ConstInterfaceMethodRef method() { + return (ConstInterfaceMethodRef) value(); + } + + /** + * Return the number of arguments to the interface + */ + public int nArgs() { + return nArgsOp; + } + + /** + * constructor for opc_invokeinterface + */ + public InsnInterfaceInvoke (ConstInterfaceMethodRef methodRefOp, + int nArgsOp) { + this(methodRefOp, nArgsOp, NO_OFFSET); + } + + /** + * Compares this instance with another for structural equality. + */ + //@olsen: added method + public boolean isEqual(Stack msg, Object obj) { + if (!(obj instanceof InsnInterfaceInvoke)) { + msg.push("obj/obj.getClass() = " + + (obj == null ? null : obj.getClass())); + msg.push("this.getClass() = " + + this.getClass()); + return false; + } + InsnInterfaceInvoke other = (InsnInterfaceInvoke)obj; + + if (!super.isEqual(msg, other)) { + return false; + } + + if (this.nArgsOp != other.nArgsOp) { + msg.push(String.valueOf("nArgsOp = " + + other.nArgsOp)); + msg.push(String.valueOf("nArgsOp = " + + this.nArgsOp)); + return false; + } + return true; + } + + /* package local methods */ + + InsnInterfaceInvoke (ConstInterfaceMethodRef methodRefOp, int nArgsOp, + int offset) { + super(opc_invokeinterface, methodRefOp, offset); + + this.nArgsOp = nArgsOp; + + if (methodRefOp == null || nArgsOp < 0) + throw new InsnError ("attempt to create an opc_invokeinterface" + + " with invalid operands"); + } + + void print (PrintStream out, int indent) { + ClassPrint.spaces(out, indent); + out.println(offset() + " opc_invokeinterface " + + "pool(" + method().getIndex() + ")," + nArgsOp); + } + + int store(byte[] buf, int index) { + buf[index++] = (byte) opcode(); + index = storeShort(buf, index, (short)method().getIndex()); + buf[index++] = (byte) nArgsOp; + buf[index++] = (byte) 0; + return index; + } + + int size() { + return 5; + } + + static InsnInterfaceInvoke read(InsnReadEnv insnEnv, int myPC) { + ConstInterfaceMethodRef iface = (ConstInterfaceMethodRef) + insnEnv.pool().constantAt(insnEnv.getUShort()); + int nArgs = insnEnv.getUByte(); + insnEnv.getByte(); // eat reserved arg + return new InsnInterfaceInvoke(iface, nArgs, myPC); + } +}