Added: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/BCMethod.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/BCMethod.java?rev=417860&view=auto ============================================================================== --- incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/BCMethod.java (added) +++ incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/BCMethod.java Wed Jun 28 12:46:13 2006 @@ -0,0 +1,498 @@ +/* + * Copyright 2006 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 serp.bytecode; + +import serp.bytecode.visitor.*; + +import serp.util.*; + + +/** + * <p>A method of a class.</p> + * + * @author Abe White + */ +public class BCMethod extends BCMember implements VisitAcceptor { + BCMethod(BCClass owner) { + super(owner); + } + + ///////////////////// + // Access operations + ///////////////////// + + /** + * Manipulate the method access flags. + */ + public boolean isSynchronized() { + return (getAccessFlags() & Constants.ACCESS_SYNCHRONIZED) > 0; + } + + /** + * Manipulate the method access flags. + */ + public void setSynchronized(boolean on) { + if (on) { + setAccessFlags(getAccessFlags() | Constants.ACCESS_SYNCHRONIZED); + } else { + setAccessFlags(getAccessFlags() & ~Constants.ACCESS_SYNCHRONIZED); + } + } + + /** + * Manipulate the method access flags. + */ + public boolean isNative() { + return (getAccessFlags() & Constants.ACCESS_NATIVE) > 0; + } + + /** + * Manipulate the method access flags. + */ + public void setNative(boolean on) { + if (on) { + setAccessFlags(getAccessFlags() | Constants.ACCESS_NATIVE); + } else { + setAccessFlags(getAccessFlags() & ~Constants.ACCESS_NATIVE); + } + } + + /** + * Manipulate the method access flags. + */ + public boolean isAbstract() { + return (getAccessFlags() & Constants.ACCESS_ABSTRACT) > 0; + } + + /** + * Manipulate the method access flags. + */ + public void setAbstract(boolean on) { + if (on) { + setAccessFlags(getAccessFlags() | Constants.ACCESS_ABSTRACT); + } else { + setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ABSTRACT); + } + } + + /** + * Manipulate the method access flags. + */ + public boolean isStrict() { + return (getAccessFlags() & Constants.ACCESS_STRICT) > 0; + } + + /** + * Manipulate the method access flags. + */ + public void setStrict(boolean on) { + if (on) { + setAccessFlags(getAccessFlags() | Constants.ACCESS_STRICT); + } else { + setAccessFlags(getAccessFlags() & ~Constants.ACCESS_STRICT); + } + } + + ///////////////////// + // Return operations + ///////////////////// + + /** + * Return the name of the type returned by this method. The name + * will be given in a form suitable for a [EMAIL PROTECTED] Class#forName} call. + * + * @see BCMember#getDescriptor + */ + public String getReturnName() { + return getProject().getNameCache() + .getExternalForm(getProject().getNameCache() + .getDescriptorReturnName(getDescriptor()), + false); + } + + /** + * Return the [EMAIL PROTECTED] Class} object for the return type of this method. + * + * @see BCMember#getDescriptor + */ + public Class getReturnType() { + return Strings.toClass(getReturnName(), getClassLoader()); + } + + /** + * Return the bytecode for the return type of this method. + * + * @see BCMember#getDescriptor + */ + public BCClass getReturnBC() { + return getProject().loadClass(getReturnName(), getClassLoader()); + } + + /** + * Set the return type of this method. + */ + public void setReturn(String name) { + setDescriptor(getProject().getNameCache() + .getDescriptor(name, getParamNames())); + } + + /** + * Set the return type of this method. + */ + public void setReturn(Class type) { + setReturn(type.getName()); + } + + /** + * Set the return type of this method. + */ + public void setReturn(BCClass type) { + setReturn(type.getName()); + } + + //////////////////////// + // Parameter operations + //////////////////////// + + /** + * Return the names of all the parameter types for this method. The names + * will be returned in a form suitable for a [EMAIL PROTECTED] Class#forName} call. + * + * @see BCMember#getDescriptor + */ + public String[] getParamNames() { + // get the parameter types from the descriptor + String[] params = getProject().getNameCache() + .getDescriptorParamNames(getDescriptor()); + + // convert them to external form + for (int i = 0; i < params.length; i++) + params[i] = getProject().getNameCache() + .getExternalForm(params[i], false); + + return params; + } + + /** + * Return the [EMAIL PROTECTED] Class} objects for all the parameter types for this + * method. + * + * @see BCMember#getDescriptor + */ + public Class[] getParamTypes() { + String[] paramNames = getParamNames(); + Class[] params = new Class[paramNames.length]; + + for (int i = 0; i < paramNames.length; i++) + params[i] = Strings.toClass(paramNames[i], getClassLoader()); + + return params; + } + + /** + * Return the bytecode for all the parameter types for this + * method. + * + * @see BCMember#getDescriptor + */ + public BCClass[] getParamBCs() { + String[] paramNames = getParamNames(); + BCClass[] params = new BCClass[paramNames.length]; + + for (int i = 0; i < paramNames.length; i++) + params[i] = getProject().loadClass(paramNames[i], getClassLoader()); + + return params; + } + + /** + * Set the parameter types of this method. + * + * @see BCMember#setDescriptor + */ + public void setParams(String[] names) { + if (names == null) { + names = new String[0]; + } + + setDescriptor(getProject().getNameCache() + .getDescriptor(getReturnName(), names)); + } + + /** + * Set the parameter type of this method. + * + * @see BCMember#setDescriptor + */ + public void setParams(Class[] types) { + if (types == null) { + setParams((String[]) null); + } else { + String[] names = new String[types.length]; + + for (int i = 0; i < types.length; i++) + names[i] = types[i].getName(); + + setParams(names); + } + } + + /** + * Set the parameter type of this method. + * + * @see BCMember#setDescriptor + */ + public void setParams(BCClass[] types) { + if (types == null) { + setParams((String[]) null); + } else { + String[] names = new String[types.length]; + + for (int i = 0; i < types.length; i++) + names[i] = types[i].getName(); + + setParams(names); + } + } + + /** + * Add a parameter type to this method. + */ + public void addParam(String type) { + String[] origParams = getParamNames(); + String[] params = new String[origParams.length + 1]; + + for (int i = 0; i < origParams.length; i++) + params[i] = origParams[i]; + + params[origParams.length] = type; + setParams(params); + } + + /** + * Add a parameter type to this method. + */ + public void addParam(Class type) { + addParam(type.getName()); + } + + /** + * Add a parameter type to this method. + */ + public void addParam(BCClass type) { + addParam(type.getName()); + } + + /** + * Add a parameter type to this method. + * + * @see java.util.List#add(int,Object) + */ + public void addParam(int pos, String type) { + String[] origParams = getParamNames(); + + if ((pos < 0) || (pos >= origParams.length)) { + throw new IndexOutOfBoundsException("pos = " + pos); + } + + String[] params = new String[origParams.length + 1]; + + for (int i = 0, index = 0; i < params.length; i++) { + if (i == pos) { + params[i] = type; + } else { + params[i] = origParams[index++]; + } + } + + setParams(params); + } + + /** + * Add a parameter type to this method. + * + * @see java.util.List#add(int,Object) + */ + public void addParam(int pos, Class type) { + addParam(pos, type.getName()); + } + + /** + * Add a parameter type to this method. + * + * @see java.util.List#add(int,Object) + */ + public void addParam(int pos, BCClass type) { + addParam(pos, type.getName()); + } + + /** + * Change a parameter type of this method. + * + * @see java.util.List#set(int,Object) + */ + public void setParam(int pos, String type) { + String[] origParams = getParamNames(); + + if ((pos < 0) || (pos >= origParams.length)) { + throw new IndexOutOfBoundsException("pos = " + pos); + } + + String[] params = new String[origParams.length]; + + for (int i = 0; i < params.length; i++) { + if (i == pos) { + params[i] = type; + } else { + params[i] = origParams[i]; + } + } + + setParams(params); + } + + /** + * Change a parameter type of this method. + * + * @see java.util.List#set(int,Object) + */ + public void setParam(int pos, Class type) { + setParam(pos, type.getName()); + } + + /** + * Change a parameter type of this method. + * + * @see java.util.List#set(int,Object) + */ + public void setParam(int pos, BCClass type) { + setParam(pos, type.getName()); + } + + /** + * Clear all parameters from this method. + */ + public void clearParams() { + setParams((String[]) null); + } + + /** + * Remove a parameter from this method. + */ + public void removeParam(int pos) { + String[] origParams = getParamNames(); + + if ((pos < 0) || (pos >= origParams.length)) { + throw new IndexOutOfBoundsException("pos = " + pos); + } + + String[] params = new String[origParams.length - 1]; + + for (int i = 0, index = 0; i < origParams.length; i++) + if (i != pos) { + params[index++] = origParams[i]; + } + + setParams(params); + } + + /////////////////////// + // Convenience methods + /////////////////////// + + /** + * Return the checked exceptions information for the method. + * Acts internally through the [EMAIL PROTECTED] Attributes} interface. + * + * @param add if true, a new exceptions attribute will be added + * if not already present + * @return the exceptions information, or null if none and the + * <code>add</code> param is set to false + */ + public Exceptions getExceptions(boolean add) { + Exceptions exceptions = (Exceptions) getAttribute(Constants.ATTR_EXCEPTIONS); + + if (!add || (exceptions != null)) { + return exceptions; + } + + if (exceptions == null) { + exceptions = (Exceptions) addAttribute(Constants.ATTR_EXCEPTIONS); + } + + return exceptions; + } + + /** + * Remove the exceptions attribute for the method. + * Acts internally through the [EMAIL PROTECTED] Attributes} interface. + * + * @return true if there was a value to remove + */ + public boolean removeExceptions() { + return removeAttribute(Constants.ATTR_EXCEPTIONS); + } + + /** + * Return the code for the method. If the code already exists, its + * iterator will be reset to the first instruction. + * Acts internally through the [EMAIL PROTECTED] Attributes} interface. + * + * @param add if true, a new code attribute will be added + * if not already present + * @return the code for the metohd, or null if none and the + * <code>add</code> param is set to false + */ + public Code getCode(boolean add) { + Code code = (Code) getAttribute(Constants.ATTR_CODE); + + if (code != null) { + code.beforeFirst(); + + return code; + } + + if (!add) { + return null; + } + + return (Code) addAttribute(Constants.ATTR_CODE); + } + + /** + * Remove the code attribute from the method. + * Acts internally through the [EMAIL PROTECTED] Attributes} interface. + * + * @return true if there was a value to remove + */ + public boolean removeCode() { + return removeAttribute(Constants.ATTR_CODE); + } + + //////////////////////////////// + // VisitAcceptor implementation + //////////////////////////////// + public void acceptVisit(BCVisitor visit) { + visit.enterBCMethod(this); + visitAttributes(visit); + visit.exitBCMethod(this); + } + + void initialize(String name, String descriptor) { + super.initialize(name, descriptor); + makePublic(); + } +}
Propchange: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/BCMethod.java ------------------------------------------------------------------------------ svn:executable = * Added: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassConstantInstruction.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassConstantInstruction.java?rev=417860&view=auto ============================================================================== --- incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassConstantInstruction.java (added) +++ incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassConstantInstruction.java Wed Jun 28 12:46:13 2006 @@ -0,0 +1,223 @@ +/* + * Copyright 2006 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 serp.bytecode; + +import serp.bytecode.lowlevel.*; + +import java.util.*; + + +/** + * <p>Pseudo-instruction used to place [EMAIL PROTECTED] Class} objects onto the stack. + * This logical instruction may actually involve a large chunk of code, and + * may even add static synthetic fields and methods to the owning class. + * Therefore, once the type of class being loaded is set, it cannot + * be changed. Also, this instruction is invalid as the target of + * any jump instruction or exception handler.</p> + * + * @author Abe White + */ +public class ClassConstantInstruction { + private static final Class[] _params = new Class[] { String.class }; + private static final Map _wrappers = new HashMap(); + + static { + _wrappers.put(byte.class.getName(), Byte.class); + _wrappers.put(boolean.class.getName(), Boolean.class); + _wrappers.put(char.class.getName(), Character.class); + _wrappers.put(double.class.getName(), Double.class); + _wrappers.put(float.class.getName(), Float.class); + _wrappers.put(int.class.getName(), Integer.class); + _wrappers.put(long.class.getName(), Long.class); + _wrappers.put(short.class.getName(), Short.class); + } + + private Instruction _ins = null; + private Code _code = null; + private BCClass _class = null; + private boolean _invalid = false; + + ClassConstantInstruction(BCClass bc, Code code, Instruction nop) { + _class = bc; + _code = code; + _ins = nop; + } + + /** + * Set the type of class being loaded. + * + * @return the first Instruction of the block added by setting + * the type + * @throws IllegalStateException if type has already been set + */ + public Instruction setClass(String name) { + name = _class.getProject().getNameCache().getExternalForm(name, false); + setClassName(name, getWrapperClass(name)); + + return _ins; + } + + /** + * Set the type of class being loaded. + * + * @return the first Instruction of the block added by setting + * the type + * @throws IllegalStateException if type has already been set + */ + public Instruction setClass(Class type) { + return setClass(type.getName()); + } + + /** + * Set the type of class being loaded. + * + * @return the first Instruction of the block added by setting + * the type + * @throws IllegalStateException if type has already been set + */ + public Instruction setClass(BCClass type) { + return setClass(type.getName()); + } + + /** + * Set the name of the class to load. + */ + private void setClassName(String name, Class wrapper) { + if (_invalid) { + throw new IllegalStateException(); + } + + // remember the position of the code iterator + Instruction before = (_code.hasNext()) ? _code.next() : null; + _code.before(_ins); + _code.next(); + + if (wrapper != null) { + _code.getstatic().setField(wrapper, "TYPE", Class.class); + } else { + setObject(name); + } + + // move to the old position + if (before != null) { + _code.before(before); + } else { + _code.afterLast(); + } + + _invalid = true; + } + + /** + * Adds fields and methods as necessary to load a class constant of + * an object type. + */ + private void setObject(String name) { + BCField field = addClassField(name); + BCMethod method = addClassLoadMethod(); + + // copied from the way jikes loads classes + _code.getstatic().setField(field); + + JumpInstruction ifnull = _code.ifnull(); + + _code.getstatic().setField(field); + + JumpInstruction go2 = _code.go2(); + + ifnull.setTarget(_code.constant().setValue(name)); + _code.invokestatic().setMethod(method); + _code.dup(); + _code.putstatic().setField(field); + + go2.setTarget(_code.nop()); + } + + /** + * Adds a static field to hold the loaded class constant. + */ + private BCField addClassField(String name) { + String fieldName = "class$L" + + name.replace('.', '$').replace('[', '$').replace(';', '$'); + + BCField field = _class.getDeclaredField(fieldName); + + if (field == null) { + field = _class.declareField(fieldName, Class.class); + field.makePackage(); + field.setStatic(true); + field.setSynthetic(true); + } + + return field; + } + + /** + * Adds the standard <code>class$<code> method used inernally by classes + * to load class constants for object types. + */ + private BCMethod addClassLoadMethod() { + BCMethod method = _class.getDeclaredMethod("class$", _params); + + if (method != null) { + return method; + } + + // add the special synthetic method + method = _class.declareMethod("class$", Class.class, _params); + method.setStatic(true); + method.makePackage(); + method.setSynthetic(true); + + // copied directly from the output of the jikes compiler + Code code = method.getCode(true); + code.setMaxStack(3); + code.setMaxLocals(2); + + Instruction tryStart = code.aload().setLocal(0); + code.invokestatic() + .setMethod(Class.class, "forName", Class.class, _params); + + Instruction tryEnd = code.areturn(); + Instruction handlerStart = code.astore().setLocal(1); + code.anew().setType(NoClassDefFoundError.class); + code.dup(); + code.aload().setLocal(1); + code.invokevirtual() + .setMethod(Throwable.class, "getMessage", String.class, null); + code.invokespecial() + .setMethod(NoClassDefFoundError.class, "<init>", void.class, _params); + code.athrow(); + + code.addExceptionHandler(tryStart, tryEnd, handlerStart, + ClassNotFoundException.class); + + return method; + } + + /** + * Return the wrapper type for the given primitive class, or null + * if the given name is not a primitive type. The given name should + * be in external form. + */ + private static Class getWrapperClass(String name) { + if (name == null) { + return null; + } + + return (Class) _wrappers.get(name); + } +} Propchange: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassConstantInstruction.java ------------------------------------------------------------------------------ svn:executable = * Added: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassInstruction.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassInstruction.java?rev=417860&view=auto ============================================================================== --- incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassInstruction.java (added) +++ incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassInstruction.java Wed Jun 28 12:46:13 2006 @@ -0,0 +1,135 @@ +/* + * Copyright 2006 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 serp.bytecode; + +import serp.bytecode.lowlevel.*; + +import serp.bytecode.visitor.*; + +import java.io.*; + + +/** + * <p>An instruction that takes as an argument a class to operate + * on. Examples include <code>anewarray, checkcast, instance, anew</code>, + * etc.</p> + * + * @author Abe White + */ +public class ClassInstruction extends TypedInstruction { + private int _index = 0; + + ClassInstruction(Code owner, int opcode) { + super(owner, opcode); + } + + public int getLogicalStackChange() { + return getStackChange(); + } + + public int getStackChange() { + if (getOpcode() == Constants.NEW) { + return 1; + } + + return 0; + } + + int getLength() { + return super.getLength() + 2; + } + + /** + * Return the [EMAIL PROTECTED] ConstantPool} index of the + * [EMAIL PROTECTED] ClassEntry} describing the class for this instruction. + */ + public int getTypeIndex() { + return _index; + } + + /** + * Set the [EMAIL PROTECTED] ConstantPool} index of the + * [EMAIL PROTECTED] ClassEntry} describing the class for this instruction. + * + * @return this instruction, for method chaining + */ + public ClassInstruction setTypeIndex(int index) { + _index = index; + + return this; + } + + public String getTypeName() { + if (_index == 0) { + return null; + } + + ClassEntry entry = (ClassEntry) getPool().getEntry(_index); + + return getProject().getNameCache() + .getExternalForm(entry.getNameEntry().getValue(), false); + } + + public TypedInstruction setType(String type) { + if (type == null) { + setTypeIndex(0); + } else { + type = getProject().getNameCache().getInternalForm(type, false); + setTypeIndex(getPool().findClassEntry(type, true)); + } + + return this; + } + + /** + * ClassInstructions are equal if the type they reference is the same or + * unset and if their opcodes are equal. + */ + public boolean equalsInstruction(Instruction other) { + if (other == this) { + return true; + } + + if (!super.equalsInstruction(other)) { + return false; + } + + String type = getTypeName(); + String otherType = ((ClassInstruction) other).getTypeName(); + + return (type == null) || (otherType == null) || type.equals(otherType); + } + + public void acceptVisit(BCVisitor visit) { + visit.enterClassInstruction(this); + visit.exitClassInstruction(this); + } + + void read(Instruction other) { + super.read(other); + setType(((ClassInstruction) other).getTypeName()); + } + + void read(DataInput in) throws IOException { + super.read(in); + setTypeIndex(in.readUnsignedShort()); + } + + void write(DataOutput out) throws IOException { + super.write(out); + out.writeShort(getTypeIndex()); + } +} Propchange: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/ClassInstruction.java ------------------------------------------------------------------------------ svn:executable = * Added: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CmpInstruction.java URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CmpInstruction.java?rev=417860&view=auto ============================================================================== --- incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CmpInstruction.java (added) +++ incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CmpInstruction.java Wed Jun 28 12:46:13 2006 @@ -0,0 +1,190 @@ +/* + * Copyright 2006 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 serp.bytecode; + +import serp.bytecode.visitor.*; + + +/** + * <p>An instruction comparing two stack values. Examples include + * <code>lcmp, fcmpl</code>, etc.</p> + * + * @author Abe White + */ +public class CmpInstruction extends TypedInstruction { + private static Class[][] _mappings = new Class[][] { + { int.class, long.class }, + { byte.class, long.class }, + { char.class, long.class }, + { short.class, long.class }, + { boolean.class, long.class }, + { void.class, long.class }, + { Object.class, long.class }, + }; + + CmpInstruction(Code owner) { + super(owner); + } + + CmpInstruction(Code owner, int opcode) { + super(owner, opcode); + } + + public int getLogicalStackChange() { + switch (getOpcode()) { + case Constants.NOP: + return 0; + + default: + return -1; + } + } + + public int getStackChange() { + switch (getOpcode()) { + case Constants.LCMP: + case Constants.DCMPL: + case Constants.DCMPG: + return -3; + + case Constants.NOP: + return 0; + + default: + return -1; + } + } + + public String getTypeName() { + switch (getOpcode()) { + case Constants.LCMP: + return long.class.getName(); + + case Constants.FCMPL: + case Constants.FCMPG: + return float.class.getName(); + + case Constants.DCMPL: + case Constants.DCMPG: + return double.class.getName(); + + default: + return null; + } + } + + public TypedInstruction setType(String type) { + type = mapType(type, _mappings, true); + + if (type == null) { + return (TypedInstruction) setOpcode(Constants.NOP); + } + + int opcode = getOpcode(); + + switch (type.charAt(0)) { + case 'l': + return (TypedInstruction) setOpcode(Constants.LCMP); + + case 'f': + + if ((opcode == Constants.FCMPL) || (opcode == Constants.DCMPL)) { + return (TypedInstruction) setOpcode(Constants.FCMPL); + } + + return (TypedInstruction) setOpcode(Constants.FCMPG); + + case 'd': + + if ((opcode == Constants.FCMPL) || (opcode == Constants.DCMPL)) { + return (TypedInstruction) setOpcode(Constants.DCMPL); + } + + return (TypedInstruction) setOpcode(Constants.DCMPG); + + default: + throw new IllegalStateException(); + } + } + + /** + * Return the number that will be placed on the stack if this instruction + * is of type float or double and one of the operands is NaN. For + * FCMPG or DCMPG, this value will be 1; for FCMPL or DCMPL this value + * will be -1. For LCMP or if the type is unset, this value will be 0. + */ + public int getNaNValue() { + switch (getOpcode()) { + case Constants.FCMPL: + case Constants.DCMPL: + return -1; + + case Constants.FCMPG: + case Constants.DCMPG: + return 1; + + default: + return 0; + } + } + + /** + * Set the number that will be placed on the stack if this instruction + * is of type float or double and one of the operands is NaN. For + * FCMPG or DCMPG, this value should be 1; for FCMPL or DCMPL this value + * should be -1. For LCMP, this value should be 0. + * + * @return this instruction, for method chaining + */ + public CmpInstruction setNaNValue(int nan) { + switch (getOpcode()) { + case Constants.FCMPL: + case Constants.FCMPG: + + if (nan == 1) { + setOpcode(Constants.FCMPG); + } else if (nan == -1) { + setOpcode(Constants.FCMPL); + } else { + throw new IllegalArgumentException("Invalid nan for type"); + } + + case Constants.DCMPL: + case Constants.DCMPG: + + if (nan == 1) { + setOpcode(Constants.DCMPG); + } else if (nan == -1) { + setOpcode(Constants.DCMPL); + } else { + throw new IllegalArgumentException("Invalid nan for type"); + } + + default: + + if (nan != 0) { + throw new IllegalArgumentException("Invalid nan for type"); + } + } + + return this; + } + + public void acceptVisit(BCVisitor visit) { + visit.enterCmpInstruction(this); + visit.exitCmpInstruction(this); + } +} Propchange: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CmpInstruction.java ------------------------------------------------------------------------------ svn:executable = *