serp-1.14.1.orig/0000755000000000000000000000000011401260236010367 5ustar serp-1.14.1.orig/LICENSE.txt0000644000000000000000000000272010455015657012230 0ustar Copyright (c) 2002, A. Abram White All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of 'serp' nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. serp-1.14.1.orig/README.txt0000644000000000000000000000011110455015657012073 0ustar See to comments in the header of pom.xml for instructions on building. serp-1.14.1.orig/src/0000755000000000000000000000000011401260237011157 5ustar serp-1.14.1.orig/src/test/0000755000000000000000000000000011401260237012136 5ustar serp-1.14.1.orig/src/test/java/0000755000000000000000000000000011401260237013057 5ustar serp-1.14.1.orig/src/test/java/serp/0000755000000000000000000000000011401260237014030 5ustar serp-1.14.1.orig/src/test/java/serp/bytecode/0000755000000000000000000000000011401260237015626 5ustar serp-1.14.1.orig/src/test/java/serp/bytecode/TestNameCache.java0000755000000000000000000002070610460270415021150 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link NameCache} utility type. * * @author Abe White */ public class TestNameCache extends TestCase { private NameCache _cache = null; public TestNameCache(String test) { super(test); } public void setUp() { _cache = new Project().getNameCache(); } /** * Tests that class names are correctly converted to internal form. */ public void testInternalForm() { assertEquals("I", _cache.getInternalForm("int", true)); assertEquals("I", _cache.getInternalForm("int", false)); assertEquals("I", _cache.getInternalForm("I", true)); assertEquals("I", _cache.getInternalForm("I", false)); assertEquals("B", _cache.getInternalForm("byte", true)); assertEquals("C", _cache.getInternalForm("char", true)); assertEquals("D", _cache.getInternalForm("double", true)); assertEquals("F", _cache.getInternalForm("float", true)); assertEquals("J", _cache.getInternalForm("long", true)); assertEquals("S", _cache.getInternalForm("short", true)); assertEquals("Z", _cache.getInternalForm("boolean", true)); assertEquals("V", _cache.getInternalForm("void", true)); assertEquals("Ljava/lang/Object;", _cache.getInternalForm(Object.class.getName(), true)); assertEquals("java/lang/Object", _cache.getInternalForm(Object.class.getName(), false)); assertEquals("Ljava/lang/Object;", _cache.getInternalForm("Ljava/lang/Object;", true)); assertEquals("java/lang/Object", _cache.getInternalForm("Ljava/lang/Object;", false)); } /** * Tests that array class names are correctly converted to internal form. */ public void testArrayInternalForm() { assertEquals("[B", _cache.getInternalForm(byte[].class.getName(), false)); assertEquals("[B", _cache.getInternalForm(byte[].class.getName(), true)); assertEquals("[B", _cache.getInternalForm("byte[]", false)); assertEquals("[B", _cache.getInternalForm("byte[]", true)); assertEquals("[[Ljava/lang/Object;", _cache.getInternalForm(Object[][].class.getName(), false)); assertEquals("[[Ljava/lang/Object;", _cache.getInternalForm(Object[][].class.getName(), true)); assertEquals("[[Ljava/lang/Object;", _cache.getInternalForm("java.lang.Object[][]", false)); assertEquals("[[Ljava/lang/Object;", _cache.getInternalForm("java.lang.Object[][]", true)); } /** * Tests that class names are correctly converted to external form. */ public void testExternalForm() { assertEquals("byte", _cache.getExternalForm("B", true)); assertEquals("byte", _cache.getExternalForm("byte", true)); assertEquals("byte", _cache.getExternalForm("B", false)); assertEquals("byte", _cache.getExternalForm("byte", false)); assertEquals("byte", _cache.getExternalForm("byte", false)); assertEquals("byte", _cache.getExternalForm("B", true)); assertEquals("char", _cache.getExternalForm("char", false)); assertEquals("char", _cache.getExternalForm("C", true)); assertEquals("double", _cache.getExternalForm("double", false)); assertEquals("double", _cache.getExternalForm("D", true)); assertEquals("float", _cache.getExternalForm("float", false)); assertEquals("float", _cache.getExternalForm("F", true)); assertEquals("int", _cache.getExternalForm("int", false)); assertEquals("int", _cache.getExternalForm("I", true)); assertEquals("long", _cache.getExternalForm("long", false)); assertEquals("long", _cache.getExternalForm("J", true)); assertEquals("short", _cache.getExternalForm("short", false)); assertEquals("short", _cache.getExternalForm("S", true)); assertEquals("boolean", _cache.getExternalForm("boolean", false)); assertEquals("boolean", _cache.getExternalForm("Z", true)); assertEquals("void", _cache.getExternalForm("void", false)); assertEquals("void", _cache.getExternalForm("V", true)); assertEquals("[B", _cache.getExternalForm("byte[]", false)); assertEquals("[C", _cache.getExternalForm("char[]", false)); assertEquals("[D", _cache.getExternalForm("double[]", false)); assertEquals("[F", _cache.getExternalForm("float[]", false)); assertEquals("[I", _cache.getExternalForm("int[]", false)); assertEquals("[J", _cache.getExternalForm("long[]", false)); assertEquals("[S", _cache.getExternalForm("short[]", false)); assertEquals("[Z", _cache.getExternalForm("boolean[]", false)); assertEquals("java.lang.Object", _cache.getExternalForm("java.lang.Object", true)); assertEquals("java.lang.Object", _cache.getExternalForm("java/lang/Object", true)); assertEquals("java.lang.Object", _cache.getExternalForm("java/lang/Object", false)); assertEquals("java.lang.Object", _cache.getExternalForm("Ljava/lang/Object;", false)); } /** * Tests that array class names are correctly converted to external form. */ public void testArrayExternalForm() { assertEquals("byte[]", _cache.getExternalForm("byte[]", true)); assertEquals("byte[]", _cache.getExternalForm(byte[].class.getName(), true)); assertEquals("[B", _cache.getExternalForm("byte[]", false)); assertEquals("[B", _cache.getExternalForm(byte[].class.getName(), false)); assertEquals("java.lang.Object[][]", _cache.getExternalForm("java.lang.Object[][]", true)); assertEquals("java.lang.Object[][]", _cache.getExternalForm(Object[][].class.getName(), true)); assertEquals("[[Ljava.lang.Object;", _cache.getExternalForm("java.lang.Object[][]", false)); assertEquals("[[Ljava.lang.Object;", _cache.getExternalForm(Object[][].class.getName(), false)); } /** * Tests that method descriptors are correctly formed. */ public void testDescriptors() { assertEquals("()V", _cache.getDescriptor("V", new String[0])); assertEquals("()V", _cache.getDescriptor("void", null)); assertEquals("()Ljava/lang/Object;", _cache.getDescriptor("java.lang.Object", null)); assertEquals("(Z)V", _cache.getDescriptor("void", new String[] { "boolean" })); assertEquals("([ZLjava/lang/Object;I)[I", _cache.getDescriptor("int[]", new String[] { "[Z", "Ljava/lang/Object;", "int" })); } /** * Test that return types are extracted from method descriptors. */ public void testDescriptorReturnName() { assertEquals("", _cache.getDescriptorReturnName("foo")); assertEquals("V", _cache.getDescriptorReturnName("()V")); assertEquals("[Ljava/lang/Object;", _cache.getDescriptorReturnName( "(IZLjava/lang/String;)[Ljava/lang/Object;")); } /** * Test that param types are extracted from method descriptors. */ public void testDescriptorParamNames() { assertEquals(0, _cache.getDescriptorParamNames("foo").length); String[] params = _cache.getDescriptorParamNames( "([ZLjava/lang/Object;I)[I"); assertEquals(3, params.length); assertEquals("[Z", params[0]); assertEquals("Ljava/lang/Object;", params[1]); assertEquals("I", params[2]); } /** * Test {@link NameCache#getComponentTypeName}. */ public void testComponentTypes() { assertNull(_cache.getComponentName(null)); assertNull(_cache.getComponentName(int.class.getName())); assertNull(_cache.getComponentName(String.class.getName())); assertEquals(int.class.getName(), _cache.getComponentName(int[].class.getName())); assertEquals(int[][].class.getName(), _cache.getComponentName(int[][][].class.getName())); assertEquals(String.class.getName(), _cache.getComponentName(String[].class.getName())); assertEquals(String[][].class.getName(), _cache.getComponentName(String[][][].class.getName())); } public static Test suite() { return new TestSuite(TestNameCache.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestArray.java0000755000000000000000000000375110460270415020423 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the handling of array {@link BCClass}es. * * @author Abe White */ public class TestArray extends AbstractStateTest { private BCClass _bc2 = null; public TestArray(String test) { super(test); } public void setUp() { _bc = _project.loadClass(String[].class); _bc2 = _project.loadClass(int[][].class); } public void testType() { assertEquals(String[].class.getName(), _bc.getName()); assertEquals("java.lang", _bc.getPackageName()); assertEquals("String[]", _bc.getClassName()); assertEquals(String[].class, _bc.getType()); try { _bc.setName("Foo[]"); fail("Allowed set name"); } catch (UnsupportedOperationException uoe) { } assertTrue(!_bc.isPrimitive()); assertTrue(_bc.isArray()); assertEquals(int[][].class.getName(), _bc2.getName()); assertNull(_bc2.getPackageName()); assertEquals("int[][]", _bc2.getClassName()); assertEquals(int[][].class, _bc2.getType()); } public void testSuperclass() { assertEquals(Object.class.getName(), _bc.getSuperclassName()); try { _bc.setSuperclass("Foo"); fail("Allowed set superclass"); } catch (UnsupportedOperationException uoe) { } } public void testComponent() { assertEquals(String.class.getName(), _bc.getComponentName()); assertEquals(String.class, _bc.getComponentType()); assertEquals(String.class, _bc.getComponentBC().getType()); assertEquals(int[].class.getName(), _bc2.getComponentName()); assertEquals(int[].class, _bc2.getComponentType()); assertEquals(int[].class, _bc2.getComponentBC().getType()); } public static Test suite() { return new TestSuite(TestArray.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestMathInstruction.java0000755000000000000000000003600310460270415022474 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link MathInstruction} type. * * @author Abe White */ public class TestMathInstruction extends TestCase { private Code _code = new Code(); public TestMathInstruction(String test) { super(test); } /** * Test that the instruction intitializes correctly when generated. */ public void testInitialize() { assertEquals(Constants.NOP, _code.math().getOpcode()); assertEquals(Constants.NOP, _code.xadd().getOpcode()); assertEquals(Constants.IADD, _code.iadd().getOpcode()); assertEquals(Constants.LADD, _code.ladd().getOpcode()); assertEquals(Constants.FADD, _code.fadd().getOpcode()); assertEquals(Constants.DADD, _code.dadd().getOpcode()); assertEquals(Constants.NOP, _code.xsub().getOpcode()); assertEquals(Constants.ISUB, _code.isub().getOpcode()); assertEquals(Constants.LSUB, _code.lsub().getOpcode()); assertEquals(Constants.FSUB, _code.fsub().getOpcode()); assertEquals(Constants.DSUB, _code.dsub().getOpcode()); assertEquals(Constants.NOP, _code.xmul().getOpcode()); assertEquals(Constants.IMUL, _code.imul().getOpcode()); assertEquals(Constants.LMUL, _code.lmul().getOpcode()); assertEquals(Constants.FMUL, _code.fmul().getOpcode()); assertEquals(Constants.DMUL, _code.dmul().getOpcode()); assertEquals(Constants.NOP, _code.xdiv().getOpcode()); assertEquals(Constants.IDIV, _code.idiv().getOpcode()); assertEquals(Constants.LDIV, _code.ldiv().getOpcode()); assertEquals(Constants.FDIV, _code.fdiv().getOpcode()); assertEquals(Constants.DDIV, _code.ddiv().getOpcode()); assertEquals(Constants.NOP, _code.xrem().getOpcode()); assertEquals(Constants.IREM, _code.irem().getOpcode()); assertEquals(Constants.LREM, _code.lrem().getOpcode()); assertEquals(Constants.FREM, _code.frem().getOpcode()); assertEquals(Constants.DREM, _code.drem().getOpcode()); assertEquals(Constants.NOP, _code.xneg().getOpcode()); assertEquals(Constants.INEG, _code.ineg().getOpcode()); assertEquals(Constants.LNEG, _code.lneg().getOpcode()); assertEquals(Constants.FNEG, _code.fneg().getOpcode()); assertEquals(Constants.DNEG, _code.dneg().getOpcode()); assertEquals(Constants.NOP, _code.xshl().getOpcode()); assertEquals(Constants.ISHL, _code.ishl().getOpcode()); assertEquals(Constants.LSHL, _code.lshl().getOpcode()); assertEquals(Constants.NOP, _code.xshr().getOpcode()); assertEquals(Constants.ISHR, _code.ishr().getOpcode()); assertEquals(Constants.LSHR, _code.lshr().getOpcode()); assertEquals(Constants.NOP, _code.xushr().getOpcode()); assertEquals(Constants.IUSHR, _code.iushr().getOpcode()); assertEquals(Constants.LUSHR, _code.lushr().getOpcode()); assertEquals(Constants.NOP, _code.xand().getOpcode()); assertEquals(Constants.IAND, _code.iand().getOpcode()); assertEquals(Constants.LAND, _code.land().getOpcode()); assertEquals(Constants.NOP, _code.xor().getOpcode()); assertEquals(Constants.IOR, _code.ior().getOpcode()); assertEquals(Constants.LOR, _code.lor().getOpcode()); assertEquals(Constants.NOP, _code.xxor().getOpcode()); assertEquals(Constants.IXOR, _code.ixor().getOpcode()); assertEquals(Constants.LXOR, _code.lxor().getOpcode()); } /** * Test that the instruction returns its type correctly. */ public void testGetType() { MathInstruction ins = _code.math(); assertNull(ins.getType()); assertEquals(-1, ins.getOperation()); ins = _code.xadd(); assertNull(ins.getType()); assertEquals(Constants.MATH_ADD, ins.getOperation()); ins = _code.iadd(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_ADD, ins.getOperation()); ins = _code.ladd(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_ADD, ins.getOperation()); ins = _code.fadd(); assertEquals(float.class, ins.getType()); assertEquals(Constants.MATH_ADD, ins.getOperation()); ins = _code.dadd(); assertEquals(double.class, ins.getType()); assertEquals(Constants.MATH_ADD, ins.getOperation()); ins = _code.xsub(); assertNull(ins.getType()); assertEquals(Constants.MATH_SUB, ins.getOperation()); ins = _code.isub(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_SUB, ins.getOperation()); ins = _code.lsub(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_SUB, ins.getOperation()); ins = _code.fsub(); assertEquals(float.class, ins.getType()); assertEquals(Constants.MATH_SUB, ins.getOperation()); ins = _code.dsub(); assertEquals(double.class, ins.getType()); assertEquals(Constants.MATH_SUB, ins.getOperation()); ins = _code.xmul(); assertNull(ins.getType()); assertEquals(Constants.MATH_MUL, ins.getOperation()); ins = _code.imul(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_MUL, ins.getOperation()); ins = _code.lmul(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_MUL, ins.getOperation()); ins = _code.fmul(); assertEquals(float.class, ins.getType()); assertEquals(Constants.MATH_MUL, ins.getOperation()); ins = _code.dmul(); assertEquals(double.class, ins.getType()); assertEquals(Constants.MATH_MUL, ins.getOperation()); ins = _code.xdiv(); assertNull(ins.getType()); assertEquals(Constants.MATH_DIV, ins.getOperation()); ins = _code.idiv(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_DIV, ins.getOperation()); ins = _code.ldiv(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_DIV, ins.getOperation()); ins = _code.fdiv(); assertEquals(float.class, ins.getType()); assertEquals(Constants.MATH_DIV, ins.getOperation()); ins = _code.ddiv(); assertEquals(double.class, ins.getType()); assertEquals(Constants.MATH_DIV, ins.getOperation()); ins = _code.xrem(); assertNull(ins.getType()); assertEquals(Constants.MATH_REM, ins.getOperation()); ins = _code.irem(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_REM, ins.getOperation()); ins = _code.lrem(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_REM, ins.getOperation()); ins = _code.frem(); assertEquals(float.class, ins.getType()); assertEquals(Constants.MATH_REM, ins.getOperation()); ins = _code.drem(); assertEquals(double.class, ins.getType()); assertEquals(Constants.MATH_REM, ins.getOperation()); ins = _code.xneg(); assertNull(ins.getType()); assertEquals(Constants.MATH_NEG, ins.getOperation()); ins = _code.ineg(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_NEG, ins.getOperation()); ins = _code.lneg(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_NEG, ins.getOperation()); ins = _code.fneg(); assertEquals(float.class, ins.getType()); assertEquals(Constants.MATH_NEG, ins.getOperation()); ins = _code.dneg(); assertEquals(double.class, ins.getType()); assertEquals(Constants.MATH_NEG, ins.getOperation()); ins = _code.xshl(); assertNull(ins.getType()); assertEquals(Constants.MATH_SHL, ins.getOperation()); ins = _code.ishl(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_SHL, ins.getOperation()); ins = _code.lshl(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_SHL, ins.getOperation()); ins = _code.xshr(); assertNull(ins.getType()); assertEquals(Constants.MATH_SHR, ins.getOperation()); ins = _code.ishr(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_SHR, ins.getOperation()); ins = _code.lshr(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_SHR, ins.getOperation()); ins = _code.xushr(); assertNull(ins.getType()); assertEquals(Constants.MATH_USHR, ins.getOperation()); ins = _code.iushr(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_USHR, ins.getOperation()); ins = _code.lushr(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_USHR, ins.getOperation()); ins = _code.xand(); assertNull(ins.getType()); assertEquals(Constants.MATH_AND, ins.getOperation()); ins = _code.iand(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_AND, ins.getOperation()); ins = _code.land(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_AND, ins.getOperation()); ins = _code.xor(); assertNull(ins.getType()); assertEquals(Constants.MATH_OR, ins.getOperation()); ins = _code.ior(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_OR, ins.getOperation()); ins = _code.lor(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_OR, ins.getOperation()); ins = _code.xxor(); assertNull(ins.getType()); assertEquals(Constants.MATH_XOR, ins.getOperation()); ins = _code.ixor(); assertEquals(int.class, ins.getType()); assertEquals(Constants.MATH_XOR, ins.getOperation()); ins = _code.lxor(); assertEquals(long.class, ins.getType()); assertEquals(Constants.MATH_XOR, ins.getOperation()); } /** * Test that the opcode is morphed correctly when the type and operation * of the instruction are changed. */ public void testOpcodeMorph() { MathInstruction math = _code.math(); math.setOperation(Constants.MATH_ADD); assertEquals(Constants.NOP, math.setType((String) null).getOpcode()); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.NOP, math.setType((BCClass) null).getOpcode()); assertEquals(Constants.IADD, math.setType(int.class).getOpcode()); assertEquals(Constants.LADD, math.setType(long.class).getOpcode()); assertEquals(Constants.FADD, math.setType(float.class).getOpcode()); assertEquals(Constants.DADD, math.setType(double.class).getOpcode()); assertEquals(Constants.IADD, math.setType(boolean.class).getOpcode()); assertEquals(Constants.IADD, math.setType(short.class).getOpcode()); assertEquals(Constants.IADD, math.setType(char.class).getOpcode()); math.setOperation(Constants.MATH_SUB); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.ISUB, math.setType(int.class).getOpcode()); assertEquals(Constants.LSUB, math.setType(long.class).getOpcode()); assertEquals(Constants.FSUB, math.setType(float.class).getOpcode()); assertEquals(Constants.DSUB, math.setType(double.class).getOpcode()); math.setOperation(Constants.MATH_MUL); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.IMUL, math.setType(int.class).getOpcode()); assertEquals(Constants.LMUL, math.setType(long.class).getOpcode()); assertEquals(Constants.FMUL, math.setType(float.class).getOpcode()); assertEquals(Constants.DMUL, math.setType(double.class).getOpcode()); math.setOperation(Constants.MATH_DIV); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.IDIV, math.setType(int.class).getOpcode()); assertEquals(Constants.LDIV, math.setType(long.class).getOpcode()); assertEquals(Constants.FDIV, math.setType(float.class).getOpcode()); assertEquals(Constants.DDIV, math.setType(double.class).getOpcode()); math.setOperation(Constants.MATH_REM); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.IREM, math.setType(int.class).getOpcode()); assertEquals(Constants.LREM, math.setType(long.class).getOpcode()); assertEquals(Constants.FREM, math.setType(float.class).getOpcode()); assertEquals(Constants.DREM, math.setType(double.class).getOpcode()); math.setOperation(Constants.MATH_NEG); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.INEG, math.setType(int.class).getOpcode()); assertEquals(Constants.LNEG, math.setType(long.class).getOpcode()); assertEquals(Constants.FNEG, math.setType(float.class).getOpcode()); assertEquals(Constants.DNEG, math.setType(double.class).getOpcode()); math.setOperation(Constants.MATH_SHL); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.ISHL, math.setType(int.class).getOpcode()); assertEquals(Constants.LSHL, math.setType(long.class).getOpcode()); math.setOperation(Constants.MATH_SHR); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.ISHR, math.setType(int.class).getOpcode()); assertEquals(Constants.LSHR, math.setType(long.class).getOpcode()); math.setOperation(Constants.MATH_USHR); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.IUSHR, math.setType(int.class).getOpcode()); assertEquals(Constants.LUSHR, math.setType(long.class).getOpcode()); math.setOperation(Constants.MATH_AND); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.IAND, math.setType(int.class).getOpcode()); assertEquals(Constants.LAND, math.setType(long.class).getOpcode()); math.setOperation(Constants.MATH_OR); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.IOR, math.setType(int.class).getOpcode()); assertEquals(Constants.LOR, math.setType(long.class).getOpcode()); math.setOperation(Constants.MATH_XOR); assertEquals(Constants.NOP, math.setType((Class) null).getOpcode()); assertEquals(Constants.IXOR, math.setType(int.class).getOpcode()); assertEquals(Constants.LXOR, math.setType(long.class).getOpcode()); } public static Test suite() { return new TestSuite(TestMathInstruction.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestStoreInstruction.java0000755000000000000000000001576210460270415022710 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link StoreInstruction} type. * * @author Abe White */ public class TestStoreInstruction extends TestCase { private Code _code = new Code(); public TestStoreInstruction(String test) { super(test); } /** * Test that the instruction intitializes correctly when generated. */ public void testInitialize() { assertEquals(Constants.NOP, _code.xstore().getOpcode()); assertNull(_code.xstore().getType()); assertEquals(Constants.NOP, _code.istore().getOpcode()); assertEquals(int.class, _code.istore().getType()); assertEquals(Constants.NOP, _code.lstore().getOpcode()); assertEquals(long.class, _code.lstore().getType()); assertEquals(Constants.NOP, _code.fstore().getOpcode()); assertEquals(float.class, _code.fstore().getType()); assertEquals(Constants.NOP, _code.dstore().getOpcode()); assertEquals(double.class, _code.dstore().getType()); assertEquals(Constants.NOP, _code.astore().getOpcode()); assertEquals(Object.class, _code.astore().getType()); } /** * Test that the instruction returns its type correctly. */ public void testGetType() { StoreInstruction ins = _code.xstore(); assertNull(ins.getType()); assertEquals(-1, ins.getLocal()); ins = _code.istore(); assertEquals(int.class, ins.getType()); assertEquals(int.class, ins.setLocal(1).getType()); assertEquals(int.class, ins.setLocal(2).getType()); assertEquals(int.class, ins.setLocal(3).getType()); assertEquals(int.class, ins.setLocal(100).getType()); ins = _code.lstore(); assertEquals(long.class, ins.getType()); assertEquals(long.class, ins.setLocal(1).getType()); assertEquals(long.class, ins.setLocal(2).getType()); assertEquals(long.class, ins.setLocal(3).getType()); assertEquals(long.class, ins.setLocal(100).getType()); ins = _code.fstore(); assertEquals(float.class, ins.getType()); assertEquals(float.class, ins.setLocal(1).getType()); assertEquals(float.class, ins.setLocal(2).getType()); assertEquals(float.class, ins.setLocal(3).getType()); assertEquals(float.class, ins.setLocal(100).getType()); ins = _code.dstore(); assertEquals(double.class, ins.getType()); assertEquals(double.class, ins.setLocal(1).getType()); assertEquals(double.class, ins.setLocal(2).getType()); assertEquals(double.class, ins.setLocal(3).getType()); assertEquals(double.class, ins.setLocal(100).getType()); ins = _code.astore(); assertEquals(Object.class, ins.getType()); assertEquals(Object.class, ins.setLocal(1).getType()); assertEquals(Object.class, ins.setLocal(2).getType()); assertEquals(Object.class, ins.setLocal(3).getType()); assertEquals(Object.class, ins.setLocal(100).getType()); } /** * Test that the opcode is morphed correctly when the type and local * of the instruction are changed. */ public void testOpcodeMorph() { StoreInstruction ins = _code.xstore(); assertEquals(Constants.NOP, ins.getOpcode()); assertEquals(Constants.NOP, ins.setType(int.class).getOpcode()); assertEquals(Constants.ISTORE, ins.setLocal(10).getOpcode()); assertEquals(Constants.ISTORE, ins.setType(boolean.class).getOpcode()); assertEquals(Constants.ISTORE, ins.setType(byte.class).getOpcode()); assertEquals(Constants.ISTORE, ins.setType(char.class).getOpcode()); assertEquals(Constants.ISTORE, ins.setType(short.class).getOpcode()); assertEquals(Constants.ISTORE0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.ISTORE1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.ISTORE2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.ISTORE3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.ISTORE, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); assertEquals(Constants.LSTORE, ins.setType(long.class).getOpcode()); assertEquals(Constants.LSTORE0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.LSTORE1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.LSTORE2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.LSTORE3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.LSTORE, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); assertEquals(Constants.FSTORE, ins.setType(float.class).getOpcode()); assertEquals(Constants.FSTORE0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.FSTORE1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.FSTORE2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.FSTORE3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.FSTORE, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); assertEquals(Constants.DSTORE, ins.setType(double.class).getOpcode()); assertEquals(Constants.DSTORE0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.DSTORE1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.DSTORE2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.DSTORE3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.DSTORE, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); assertEquals(Constants.ASTORE, ins.setType(Object.class).getOpcode()); assertEquals(Constants.ASTORE, ins.setType(String.class).getOpcode()); assertEquals(Constants.ASTORE0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.ASTORE1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.ASTORE2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.ASTORE3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.ASTORE, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); } public static Test suite() { return new TestSuite(TestStoreInstruction.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestPrimitive.java0000755000000000000000000000244410460270415021313 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the handling of primitive {@link BCClass}es. * * @author Abe White */ public class TestPrimitive extends AbstractStateTest { public TestPrimitive(String test) { super(test); } public void setUp() { _bc = _project.loadClass(int.class); } public void testType() { assertEquals("int", _bc.getName()); assertNull(_bc.getPackageName()); assertEquals("int", _bc.getClassName()); assertEquals(int.class, _bc.getType()); try { _bc.setName("long"); fail("Allowed set name"); } catch (UnsupportedOperationException uoe) { } assertTrue(_bc.isPrimitive()); assertTrue(!_bc.isArray()); } public void testSuperclass() { assertNull(_bc.getSuperclassName()); try { _bc.setSuperclass("long"); fail("Allowed set superclass"); } catch (UnsupportedOperationException uoe) { } } public void testComponent() { assertNull(_bc.getComponentName()); } public static Test suite() { return new TestSuite(TestPrimitive.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestConvertInstruction.java0000755000000000000000000000473510460270415023232 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link ConvertInstruction} type. * * @author Abe White */ public class TestConvertInstruction extends TestCase { private Code _code = new Code(); public TestConvertInstruction(String test) { super(test); } /** * Test that the opcode is morphed correctly when the types are set. */ public void testOpcodeMorph() { ConvertInstruction ins = _code.convert(); assertEquals(Constants.NOP, ins.getOpcode()); ins.setFromType(int.class); assertEquals(Constants.NOP, ins.getOpcode()); assertEquals(int.class, ins.getFromType()); assertNull(ins.getType()); ins.setType(int.class); assertEquals(Constants.NOP, ins.getOpcode()); assertEquals(int.class, ins.getFromType()); assertEquals(int.class, ins.getType()); ins.setType(long.class); assertEquals(Constants.I2L, ins.getOpcode()); assertEquals(int.class, ins.getFromType()); assertEquals(long.class, ins.getType()); ins.setType(float.class); assertEquals(Constants.I2F, ins.getOpcode()); assertEquals(int.class, ins.getFromType()); assertEquals(float.class, ins.getType()); ins.setType(double.class); assertEquals(Constants.I2D, ins.getOpcode()); assertEquals(int.class, ins.getFromType()); assertEquals(double.class, ins.getType()); ins.setFromType(long.class); assertEquals(Constants.L2D, ins.getOpcode()); assertEquals(long.class, ins.getFromType()); assertEquals(double.class, ins.getType()); ins.setType(long.class); assertEquals(Constants.NOP, ins.getOpcode()); assertEquals(long.class, ins.getFromType()); assertEquals(long.class, ins.getType()); ins.setType(int.class); assertEquals(Constants.L2I, ins.getOpcode()); assertEquals(long.class, ins.getFromType()); assertEquals(int.class, ins.getType()); ins.setType(String.class); assertEquals(Constants.L2I, ins.getOpcode()); ins.setType((Class) null); assertEquals(Constants.NOP, ins.getOpcode()); ins.setType(float.class); assertEquals(Constants.L2F, ins.getOpcode()); } public static Test suite() { return new TestSuite(TestConvertInstruction.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestConstantInstruction.java0000755000000000000000000001235410460270415023377 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link ConstantInstruction} type. * * @author Abe White */ public class TestConstantInstruction extends TestCase { private ConstantInstruction _const = new Code().constant(); public TestConstantInstruction(String test) { super(test); } /** * Test that the type instruction returns its type correctly. */ public void testGetType() { assertNull(_const.getType()); assertEquals(int.class, _const.setValue(0).getType()); assertEquals(int.class, _const.setValue(2 << 3).getType()); assertEquals(int.class, _const.setValue(2 << 7).getType()); assertEquals(int.class, _const.setValue(2 << 15).getType()); assertEquals(long.class, _const.setValue(0L).getType()); assertEquals(long.class, _const.setValue(1000L).getType()); assertEquals(float.class, _const.setValue(0F).getType()); assertEquals(float.class, _const.setValue(1000F).getType()); assertEquals(double.class, _const.setValue(0D).getType()); assertEquals(double.class, _const.setValue(1000D).getType()); assertEquals(Object.class, _const.setValue((Object) null).getType()); assertEquals(String.class, _const.setValue("foo").getType()); assertEquals(int.class, _const.setValue(true).getType()); assertEquals(int.class, _const.setValue((short) 0).getType()); assertEquals(int.class, _const.setValue('a').getType()); assertEquals(Class.class, _const.setValue(String.class).getType()); } /** * Test that the value is stored correctly. */ public void testGetValue() { assertNull(_const.getValue()); assertEquals(0, _const.setValue(0).getIntValue()); assertEquals(-1, _const.setValue(-1).getIntValue()); assertEquals(2 << 3, _const.setValue(2 << 3).getIntValue()); assertEquals(2 << 7, _const.setValue(2 << 7).getIntValue()); assertEquals(2 << 15, _const.setValue(2 << 15).getIntValue()); assertEquals(0L, _const.setValue(0L).getLongValue()); assertEquals(1000L, _const.setValue(1000L).getLongValue()); assertEquals(0F, _const.setValue(0F).getFloatValue(), .001); assertEquals(1000F, _const.setValue(1000F).getFloatValue(), .001); assertEquals(0D, _const.setValue(0D).getDoubleValue(), .001); assertEquals(1000D, _const.setValue(1000D).getDoubleValue(), .001); assertNull(_const.setValue((Object) null).getValue()); assertEquals("foo", _const.setValue("foo").getStringValue()); assertEquals(1, _const.setValue(true).getIntValue()); assertEquals(0, _const.setValue((short) 0).getIntValue()); assertEquals((int) 'a', _const.setValue('a').getIntValue()); assertEquals(String.class.getName(), _const.setValue(String.class).getClassNameValue()); } /** * Test the the opcode is morphed correctly when the value is set. */ public void testOpcodeMorph() { assertEquals(Constants.NOP, _const.getOpcode()); assertEquals(Constants.ICONSTM1, _const.setValue(-1).getOpcode()); assertEquals(Constants.ICONST0, _const.setValue(0).getOpcode()); assertEquals(Constants.ICONST1, _const.setValue(1).getOpcode()); assertEquals(Constants.ICONST2, _const.setValue(2).getOpcode()); assertEquals(Constants.ICONST3, _const.setValue(3).getOpcode()); assertEquals(Constants.ICONST4, _const.setValue(4).getOpcode()); assertEquals(Constants.ICONST5, _const.setValue(5).getOpcode()); assertEquals(Constants.BIPUSH, _const.setValue(2 << 3).getOpcode()); assertEquals(Constants.SIPUSH, _const.setValue(2 << 7).getOpcode()); assertEquals(Constants.LDC, _const.setValue(2 << 15).getOpcode()); assertEquals(Constants.LCONST0, _const.setValue(0L).getOpcode()); assertEquals(Constants.LCONST1, _const.setValue(1L).getOpcode()); assertEquals(Constants.LDC2W, _const.setValue(1000L).getOpcode()); assertEquals(Constants.FCONST2, _const.setValue(2F).getOpcode()); assertEquals(Constants.FCONST1, _const.setValue(1F).getOpcode()); assertEquals(Constants.FCONST0, _const.setValue(0F).getOpcode()); assertEquals(Constants.LDC, _const.setValue(1000F).getOpcode()); assertEquals(Constants.DCONST0, _const.setValue(0D).getOpcode()); assertEquals(Constants.DCONST1, _const.setValue(1D).getOpcode()); assertEquals(Constants.LDC2W, _const.setValue(2D).getOpcode()); assertEquals(Constants.LDC2W, _const.setValue(1000D).getOpcode()); assertEquals(Constants.LDC, _const.setValue("foo").getOpcode()); assertEquals(Constants.ICONST1, _const.setValue(true).getOpcode()); assertEquals(Constants.BIPUSH, _const.setValue('a').getOpcode()); assertEquals(Constants.ICONST0, _const.setValue((short) 0).getOpcode()); assertEquals(Constants.ACONSTNULL, _const.setValue((Object) null).getOpcode()); assertEquals(Constants.LDCW, _const.setValue(String.class).getOpcode()); } public static Test suite() { return new TestSuite(TestConstantInstruction.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestAttributes.java0000755000000000000000000001206210460270415021466 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link Attributes} type. * * @author Abe White */ public class TestAttributes extends TestCase { private Project _project = new Project(); private Attributes _attrs = _project.loadClass("serp.Attrs"); private Attributes _attrs2 = _project.loadClass("serp.Attrs2"); public TestAttributes(String test) { super(test); } /** * Test getting attributes. */ public void testGetAttributes() { assertEquals(0, _attrs.getAttributes().length); assertNull(_attrs.getAttribute(Constants.ATTR_SYNTHETIC)); Attribute attr1 = _attrs.addAttribute(Constants.ATTR_DEPRECATED); Attribute attr2 = _attrs.addAttribute(Constants.ATTR_SYNTHETIC); assertEquals(2, _attrs.getAttributes().length); assertNull(_attrs.getAttribute(Constants.ATTR_CODE)); assertTrue(attr1 == _attrs.getAttribute(Constants.ATTR_DEPRECATED)); assertTrue(attr2 == _attrs.getAttribute(Constants.ATTR_SYNTHETIC)); assertEquals(0, _attrs.getAttributes(Constants.ATTR_CODE).length); assertEquals(1, _attrs.getAttributes(Constants.ATTR_DEPRECATED).length); assertEquals(1, _attrs.getAttributes(Constants.ATTR_SYNTHETIC).length); assertTrue(attr1 == _attrs.getAttributes(Constants.ATTR_DEPRECATED)[0]); assertTrue(attr2 == _attrs.getAttributes(Constants.ATTR_SYNTHETIC)[0]); Attribute attr3 = _attrs.addAttribute(Constants.ATTR_DEPRECATED); assertEquals(3, _attrs.getAttributes().length); assertEquals(2, _attrs.getAttributes(Constants.ATTR_DEPRECATED).length); } /** * Test setting attributes. */ public void testSetAttributes() { Attribute attr1 = _attrs.addAttribute(Constants.ATTR_DEPRECATED); Attribute attr2 = _attrs.addAttribute(Constants.ATTR_SYNTHETIC); _attrs2.setAttributes(_attrs.getAttributes()); assertEquals(2, _attrs2.getAttributes().length); assertEquals(Constants.ATTR_DEPRECATED, _attrs2.getAttribute(Constants.ATTR_DEPRECATED).getName()); assertEquals(Constants.ATTR_SYNTHETIC, _attrs2.getAttribute(Constants.ATTR_SYNTHETIC).getName()); assertTrue(attr1 != _attrs2.getAttribute(Constants.ATTR_DEPRECATED)); assertTrue(attr2 != _attrs2.getAttribute(Constants.ATTR_SYNTHETIC)); Attribute attr3 = _attrs.addAttribute(Constants.ATTR_SOURCE); _attrs2.setAttributes(new Attribute[] { attr3 }); assertEquals(1, _attrs2.getAttributes().length); assertEquals(Constants.ATTR_SOURCE, _attrs2.getAttributes()[0]. getName()); } /** * Test adding attributs. */ public void testAddAttributes() { SourceFile attr1 = (SourceFile) _attrs.addAttribute (Constants.ATTR_SOURCE); assertEquals(attr1.getName(), Constants.ATTR_SOURCE); assertTrue(attr1 != _attrs.addAttribute(Constants.ATTR_SOURCE)); assertEquals(2, _attrs.getAttributes(Constants.ATTR_SOURCE).length); attr1.setFile("foo"); SourceFile attr2 = (SourceFile) _attrs2.addAttribute(attr1); assertTrue(attr1 != attr2); assertEquals("foo", attr2.getFileName()); } /** * Test clearing attributes. */ public void testClear() { _attrs.clearAttributes(); Attribute attr1 = _attrs.addAttribute(Constants.ATTR_SYNTHETIC); Attribute attr2 = _attrs.addAttribute(Constants.ATTR_DEPRECATED); assertTrue(attr1.isValid()); assertTrue(attr2.isValid()); assertEquals(2, _attrs.getAttributes().length); _attrs.clearAttributes(); assertEquals(0, _attrs.getAttributes().length); // cleared classes should be invalid assertTrue(!attr1.isValid()); assertTrue(!attr2.isValid()); } /** * Test removing a class. */ public void testRemoveAttribute() { assertTrue(!_attrs.removeAttribute((String) null)); assertTrue(!_attrs.removeAttribute((Attribute) null)); assertTrue(!_attrs.removeAttribute(Constants.ATTR_SYNTHETIC)); assertTrue(!_attrs.removeAttribute(_attrs2.addAttribute( Constants.ATTR_SYNTHETIC))); Attribute attr1 = _attrs.addAttribute(Constants.ATTR_SYNTHETIC); Attribute attr2 = _attrs.addAttribute(Constants.ATTR_DEPRECATED); assertTrue(attr1.isValid()); assertTrue(attr2.isValid()); assertEquals(2, _attrs.getAttributes().length); assertTrue(_attrs.removeAttribute(attr1.getName())); assertEquals(1, _attrs.getAttributes().length); assertTrue(!_attrs.removeAttribute(_attrs2.addAttribute (attr2.getName()))); assertTrue(_attrs.removeAttribute(attr2)); assertEquals(0, _attrs.getAttributes().length); assertTrue(!attr1.isValid()); assertTrue(!attr2.isValid()); } public static Test suite() { return new TestSuite(TestAttributes.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestLoadInstruction.java0000755000000000000000000001566610460270415022476 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link LoadInstruction} type. * * @author Abe White */ public class TestLoadInstruction extends TestCase { private Code _code = new Code(); public TestLoadInstruction(String test) { super(test); } /** * Test that the instruction intitializes correctly when generated. */ public void testInitialize() { assertEquals(Constants.NOP, _code.xload().getOpcode()); assertNull(_code.xload().getType()); assertEquals(Constants.NOP, _code.iload().getOpcode()); assertEquals(int.class, _code.iload().getType()); assertEquals(Constants.NOP, _code.lload().getOpcode()); assertEquals(long.class, _code.lload().getType()); assertEquals(Constants.NOP, _code.fload().getOpcode()); assertEquals(float.class, _code.fload().getType()); assertEquals(Constants.NOP, _code.dload().getOpcode()); assertEquals(double.class, _code.dload().getType()); assertEquals(Constants.NOP, _code.aload().getOpcode()); assertEquals(Object.class, _code.aload().getType()); } /** * Test that the instruction returns its type correctly. */ public void testGetType() { LoadInstruction ins = _code.xload(); assertNull(ins.getType()); assertEquals(-1, ins.getLocal()); ins = _code.iload(); assertEquals(int.class, ins.getType()); assertEquals(int.class, ins.setLocal(1).getType()); assertEquals(int.class, ins.setLocal(2).getType()); assertEquals(int.class, ins.setLocal(3).getType()); assertEquals(int.class, ins.setLocal(100).getType()); ins = _code.lload(); assertEquals(long.class, ins.getType()); assertEquals(long.class, ins.setLocal(1).getType()); assertEquals(long.class, ins.setLocal(2).getType()); assertEquals(long.class, ins.setLocal(3).getType()); assertEquals(long.class, ins.setLocal(100).getType()); ins = _code.fload(); assertEquals(float.class, ins.getType()); assertEquals(float.class, ins.setLocal(1).getType()); assertEquals(float.class, ins.setLocal(2).getType()); assertEquals(float.class, ins.setLocal(3).getType()); assertEquals(float.class, ins.setLocal(100).getType()); ins = _code.dload(); assertEquals(double.class, ins.getType()); assertEquals(double.class, ins.setLocal(1).getType()); assertEquals(double.class, ins.setLocal(2).getType()); assertEquals(double.class, ins.setLocal(3).getType()); assertEquals(double.class, ins.setLocal(100).getType()); ins = _code.aload(); assertEquals(Object.class, ins.getType()); assertEquals(Object.class, ins.setLocal(1).getType()); assertEquals(Object.class, ins.setLocal(2).getType()); assertEquals(Object.class, ins.setLocal(3).getType()); assertEquals(Object.class, ins.setLocal(100).getType()); } /** * Test that the opcode is morphed correctly when the type and local * of the instruction are changed. */ public void testOpcodeMorph() { LoadInstruction ins = _code.xload(); assertEquals(Constants.NOP, ins.getOpcode()); assertEquals(Constants.NOP, ins.setType(int.class).getOpcode()); assertEquals(Constants.ILOAD, ins.setLocal(10).getOpcode()); assertEquals(Constants.ILOAD, ins.setType(boolean.class).getOpcode()); assertEquals(Constants.ILOAD, ins.setType(byte.class).getOpcode()); assertEquals(Constants.ILOAD, ins.setType(char.class).getOpcode()); assertEquals(Constants.ILOAD, ins.setType(short.class).getOpcode()); assertEquals(Constants.ILOAD0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.ILOAD1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.ILOAD2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.ILOAD3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.ILOAD, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); assertEquals(Constants.LLOAD, ins.setType(long.class).getOpcode()); assertEquals(Constants.LLOAD0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.LLOAD1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.LLOAD2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.LLOAD3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.LLOAD, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); assertEquals(Constants.FLOAD, ins.setType(float.class).getOpcode()); assertEquals(Constants.FLOAD0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.FLOAD1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.FLOAD2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.FLOAD3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.FLOAD, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); assertEquals(Constants.DLOAD, ins.setType(double.class).getOpcode()); assertEquals(Constants.DLOAD0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.DLOAD1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.DLOAD2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.DLOAD3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.DLOAD, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); assertEquals(Constants.ALOAD, ins.setType(Object.class).getOpcode()); assertEquals(Constants.ALOAD, ins.setType(String.class).getOpcode()); assertEquals(Constants.ALOAD0, ins.setLocal(0).getOpcode()); assertEquals(0, ins.getLocal()); assertEquals(Constants.ALOAD1, ins.setLocal(1).getOpcode()); assertEquals(1, ins.getLocal()); assertEquals(Constants.ALOAD2, ins.setLocal(2).getOpcode()); assertEquals(2, ins.getLocal()); assertEquals(Constants.ALOAD3, ins.setLocal(3).getOpcode()); assertEquals(3, ins.getLocal()); assertEquals(Constants.ALOAD, ins.setLocal(4).getOpcode()); assertEquals(4, ins.getLocal()); } public static Test suite() { return new TestSuite(TestLoadInstruction.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/AbstractStateTest.java0000755000000000000000000001171210460270415022105 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Base class for testing the handling of the {@link PrimitiveState} and * {@link ArrayState}. Subclasses should set the {@link #_bc} member in * their {@link TestCase#setUp} method. * * @author Abe White */ public abstract class AbstractStateTest extends TestCase { protected Project _project = new Project(); protected BCClass _bc = null; public AbstractStateTest(String test) { super(test); } /** * Test the name and type operations. */ public abstract void testType(); /** * Test operations on the superclass. */ public abstract void testSuperclass(); /** * Test operations on the component type. */ public abstract void testComponent(); /** * Test the basics -- magic number, etc. */ public void testBasics() { assertEquals(Constants.VALID_MAGIC, _bc.getMagic()); try { _bc.setMagic(1); fail("Allowed set magic"); } catch (UnsupportedOperationException uoe) { } assertEquals(Constants.MAJOR_VERSION, _bc.getMajorVersion()); try { _bc.setMajorVersion(1); fail("Allowed set major version"); } catch (UnsupportedOperationException uoe) { } assertEquals(Constants.MINOR_VERSION, _bc.getMinorVersion()); try { _bc.setMinorVersion(1); fail("Allowed set minor version"); } catch (UnsupportedOperationException uoe) { } assertEquals(Constants.ACCESS_PUBLIC | Constants.ACCESS_FINAL, _bc.getAccessFlags()); try { _bc.setAccessFlags(1); fail("Allowed set access flags"); } catch (UnsupportedOperationException uoe) { } try { _bc.getPool(); fail("Allowed access constant pool"); } catch (UnsupportedOperationException uoe) { } } /** * Test operations on interfaces. */ public void testInterfaces() { assertEquals(0, _bc.getDeclaredInterfaceNames().length); assertEquals(0, _bc.getInterfaceNames().length); try { _bc.declareInterface("foo"); fail("Allowed declare interface"); } catch (UnsupportedOperationException uoe) { } _bc.clearDeclaredInterfaces(); assertTrue(!_bc.removeDeclaredInterface((String) null)); assertTrue(!_bc.removeDeclaredInterface("foo")); assertTrue(_bc.isInstanceOf(_bc.getName())); assertTrue(!_bc.isInstanceOf("foo")); } /** * Test operations on fields. */ public void testFields() { assertEquals(0, _bc.getDeclaredFields().length); assertEquals(0, _bc.getFields().length); try { _bc.declareField("foo", int.class); fail("Allowed declare field"); } catch (UnsupportedOperationException uoe) { } _bc.clearDeclaredFields(); assertTrue(!_bc.removeDeclaredField((String) null)); assertTrue(!_bc.removeDeclaredField("foo")); } /** * Test operations on methods. */ public void testMethods() { assertEquals(0, _bc.getDeclaredMethods().length); try { _bc.declareMethod("foo", int.class, null); fail("Allowed declare method"); } catch (UnsupportedOperationException uoe) { } _bc.clearDeclaredMethods(); assertTrue(!_bc.removeDeclaredMethod((String) null)); assertTrue(!_bc.removeDeclaredMethod("foo")); try { _bc.addDefaultConstructor(); fail("Allowed add default constructor"); } catch (UnsupportedOperationException uoe) { } } /** * Test operations on attributes. */ public void testAttributes() { assertNull(_bc.getSourceFile(false)); try { _bc.getSourceFile(true); fail("Allowed add source file"); } catch (UnsupportedOperationException uoe) { } assertNull(_bc.getInnerClasses(false)); try { _bc.getInnerClasses(true); fail("Allowed add inner classes"); } catch (UnsupportedOperationException uoe) { } assertTrue(!_bc.isDeprecated()); try { _bc.setDeprecated(true); fail("Allowed set deprecated"); } catch (UnsupportedOperationException uoe) { } assertEquals(0, _bc.getAttributes().length); _bc.clearAttributes(); assertTrue(!_bc.removeAttribute(Constants.ATTR_SYNTHETIC)); try { _bc.addAttribute(Constants.ATTR_SYNTHETIC); fail("Allowed add attribute"); } catch (UnsupportedOperationException uoe) { } } /** * Tests that these types cannot be written. */ public void testWrite() { try { _bc.toByteArray(); } catch (UnsupportedOperationException uoe) { } } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestBCClass.java0000755000000000000000000002054510460270415020617 0ustar package serp.bytecode; import java.io.*; import junit.framework.*; import junit.textui.*; /** * Tests the {@link BCClass} type. * * @author Abe White */ public class TestBCClass extends TestCase { private Project _project = new Project(); private BCClass _bc = _project.loadClass(Integer.class); public TestBCClass(String test) { super(test); } /** * Test accessing the class project. */ public void testProject() { assertTrue(_project == _bc.getProject()); assertTrue(_bc.isValid()); assertTrue(_project.removeClass(_bc)); assertTrue(!_bc.isValid()); } /** * Test read/write. */ public void testReadWrite() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); InputStream in = Integer.class.getResourceAsStream("Integer.class"); int ch; while ((ch = in.read()) != -1) out.write(ch); byte[] origBytes = out.toByteArray(); byte[] bytes = _bc.toByteArray(); assertEquals(origBytes.length, bytes.length); for (int i = 0; i < origBytes.length; i++) assertEquals(origBytes[i], bytes[i]); // also test copying one class to another BCClass bc2 = new Project().loadClass(_bc); bytes = bc2.toByteArray(); assertEquals(origBytes.length, bytes.length); for (int i = 0; i < origBytes.length; i++) assertEquals(origBytes[i], bytes[i]); } /** * Test basics -- magic number, major version, minor version. */ public void testBasics() { assertEquals(Constants.VALID_MAGIC, _bc.getMagic()); _bc.setMagic(1); assertEquals(1, _bc.getMagic()); assertTrue(Constants.MAJOR_VERSION <= _bc.getMajorVersion()); _bc.setMajorVersion(1); assertEquals(1, _bc.getMajorVersion()); _bc.setMinorVersion(1); assertEquals(1, _bc.getMinorVersion()); assertTrue(!_bc.isPrimitive()); assertTrue(!_bc.isArray()); assertNull(_bc.getComponentName()); assertNull(_bc.getComponentType()); assertNull(_bc.getComponentBC()); } /** * Test access flags. */ public void testAccessFlags() { assertEquals(Constants.ACCESS_PUBLIC | Constants.ACCESS_SUPER | Constants.ACCESS_FINAL, _bc.getAccessFlags()); assertTrue(_bc.isPublic()); assertTrue(!_bc.isPackage()); assertTrue(_bc.isFinal()); assertTrue(!_bc.isInterface()); assertTrue(!_bc.isAbstract()); _bc.setAccessFlags(Constants.ACCESS_ABSTRACT | Constants.ACCESS_INTERFACE); assertTrue(!_bc.isPublic()); assertTrue(_bc.isPackage()); assertTrue(!_bc.isFinal()); assertTrue(_bc.isInterface()); assertTrue(_bc.isAbstract()); _bc.setAccessFlags(Constants.ACCESS_PUBLIC | Constants.ACCESS_SUPER | Constants.ACCESS_FINAL); _bc.makePackage(); assertTrue(!_bc.isPublic()); assertTrue(_bc.isPackage()); _bc.makePublic(); assertTrue(_bc.isPublic()); assertTrue(!_bc.isPackage()); _bc.setFinal(false); assertTrue(!_bc.isFinal()); _bc.setFinal(true); assertTrue(_bc.isFinal()); _bc.setAbstract(true); assertTrue(_bc.isAbstract()); _bc.setAbstract(false); assertTrue(!_bc.isAbstract()); _bc.setInterface(true); assertTrue(_bc.isInterface()); assertTrue(_bc.isAbstract()); _bc.setInterface(false); assertTrue(!_bc.isInterface()); } /** * Test class type operations. */ public void testType() { assertEquals(Integer.class.getName(), _bc.getName()); assertEquals("java.lang", _bc.getPackageName()); assertEquals("Integer", _bc.getClassName()); assertEquals(Integer.class, _bc.getType()); _bc.setName("serp.Foo"); assertEquals("serp.Foo", _bc.getName()); } /** * Test superclass operations. */ public void testSuperclass() { assertEquals(Number.class.getName(), _bc.getSuperclassName()); assertEquals(Number.class, _bc.getSuperclassType()); assertEquals(Number.class.getName(), _bc.getSuperclassBC().getName()); assertEquals(null, _bc.getSuperclassBC().getSuperclassBC().getSuperclassBC()); _bc.setSuperclass(String.class); assertEquals(String.class.getName(), _bc.getSuperclassName()); _bc.setSuperclass((BCClass) null); _bc.setSuperclass((Class) null); _bc.setSuperclass((String) null); assertNull(_bc.getSuperclassName()); assertNull(_bc.getSuperclassType()); assertNull(_bc.getSuperclassBC()); assertEquals(0, _bc.getSuperclassIndex()); } /** * Test operations on interfaces. */ public void testInterfaces() { Object[] interfaces = _bc.getInterfaceNames(); assertEquals(2, interfaces.length); assertEquals(Comparable.class.getName(), interfaces[0]); assertEquals(Serializable.class.getName(), interfaces[1]); interfaces = _bc.getInterfaceTypes(); assertEquals(2, interfaces.length); assertEquals(Comparable.class, interfaces[0]); assertEquals(Serializable.class, interfaces[1]); interfaces = _bc.getInterfaceBCs(); assertEquals(2, interfaces.length); assertEquals(Comparable.class, ((BCClass) interfaces[0]).getType()); assertEquals(Serializable.class, ((BCClass) interfaces[1]).getType()); interfaces = _bc.getDeclaredInterfaceNames(); assertEquals(1, interfaces.length); assertEquals(Comparable.class.getName(), interfaces[0]); interfaces = _bc.getDeclaredInterfaceTypes(); assertEquals(1, interfaces.length); assertEquals(Comparable.class, interfaces[0]); interfaces = _bc.getDeclaredInterfaceBCs(); assertEquals(1, interfaces.length); assertEquals(Comparable.class, ((BCClass) interfaces[0]).getType()); assertTrue(_bc.isInstanceOf(Comparable.class.getName())); assertTrue(_bc.isInstanceOf(Comparable.class)); assertTrue(_bc.isInstanceOf(_project.loadClass(Comparable.class))); assertTrue(_bc.isInstanceOf(Serializable.class)); assertTrue(!_bc.isInstanceOf(Cloneable.class.getName())); assertTrue(!_bc.isInstanceOf(Cloneable.class)); assertTrue(!_bc.isInstanceOf(_project.loadClass(Cloneable.class))); _bc.clearDeclaredInterfaces(); interfaces = _bc.getInterfaceNames(); assertEquals(1, interfaces.length); assertEquals(Serializable.class.getName(), interfaces[0]); interfaces = _bc.getDeclaredInterfaceNames(); assertEquals(0, interfaces.length); _bc.declareInterface(Comparable.class.getName()); assertTrue(_bc.isInstanceOf(Comparable.class.getName())); interfaces = _bc.getDeclaredInterfaceNames(); assertEquals(1, interfaces.length); assertEquals(Comparable.class.getName(), interfaces[0]); assertTrue(!_bc.removeDeclaredInterface(Serializable.class)); assertTrue(_bc.removeDeclaredInterface(Comparable.class.getName())); interfaces = _bc.getDeclaredInterfaceNames(); assertEquals(0, interfaces.length); _bc.declareInterface(Comparable.class); assertTrue(_bc.isInstanceOf(Comparable.class)); interfaces = _bc.getDeclaredInterfaceTypes(); assertEquals(1, interfaces.length); assertEquals(Comparable.class, interfaces[0]); assertTrue(_bc.removeDeclaredInterface(Comparable.class)); interfaces = _bc.getDeclaredInterfaceNames(); assertEquals(0, interfaces.length); _bc.declareInterface(_project.loadClass(Comparable.class)); assertTrue(_bc.isInstanceOf(_project.loadClass(Comparable.class))); interfaces = _bc.getDeclaredInterfaceBCs(); assertEquals(1, interfaces.length); assertEquals(Comparable.class, ((BCClass) interfaces[0]).getType()); assertTrue(_bc.removeDeclaredInterface(_project.loadClass( Comparable.class))); interfaces = _bc.getDeclaredInterfaceNames(); assertEquals(0, interfaces.length); } public static Test suite() { return new TestSuite(TestBCClass.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestProject.java0000755000000000000000000002335510460270415020755 0ustar package serp.bytecode; import java.io.*; import junit.framework.*; import junit.textui.*; /** * Tests the {@link Project} type. * * @author Abe White */ public class TestProject extends TestCase { private Project _project = new Project(); public TestProject(String test) { super(test); } /** * Test the project name. */ public void testName() { assertNull(_project.getName()); assertNull(new Project(null).getName()); assertEquals("foo", new Project("foo").getName()); } /** * Test loading classes by name. */ public void testLoadByName() { BCClass bc; BCClass bc2; String[] names; String[] names2; // test primitive types names = new String[] { "boolean", "byte", "char", "double", "float", "int", "long", "short", "void" }; names2 = new String[] { "Z", "B", "C", "D", "F", "I", "J", "S", "V" }; for (int i = 0; i < names.length; i++) { bc = _project.loadClass(names[i]); bc2 = _project.loadClass(names2[i]); assertTrue(names[i], bc == bc2); assertTrue(names[i], bc.isPrimitive()); assertEquals(names[i], bc.getName()); } // test primitive array types names = new String[] { "boolean[]", "byte[]", "char[]", "double[]", "float[]", "int[]", "long[]", "short[]" }; names2 = new String[] {"[Z", "[B", "[C", "[D", "[F", "[I", "[J", "[S" }; for (int i = 0; i < names.length; i++) { bc = _project.loadClass(names[i]); bc2 = _project.loadClass(names2[i]); assertTrue(names[i], bc == bc2); assertTrue(names[i], bc.isArray()); assertEquals(names2[i], bc.getName()); } // test new object type bc = _project.loadClass("serp.Foo"); bc2 = _project.loadClass("serp.Foo"); assertTrue(bc == bc2); assertTrue(!bc.isPrimitive()); assertTrue(!bc.isArray()); assertEquals("serp.Foo", bc.getName()); // test new object array type bc = _project.loadClass("serp.Foo[]"); bc2 = _project.loadClass("[Lserp.Foo;"); assertTrue(bc == bc2); assertTrue(bc.isArray()); assertEquals("[Lserp.Foo;", bc.getName()); // test existing object type bc = _project.loadClass(String.class.getName()); bc2 = _project.loadClass(String.class); assertTrue(bc == bc2); assertTrue(!bc.isPrimitive()); assertTrue(!bc.isArray()); assertEquals(String.class.getName(), bc.getName()); assertEquals("length", bc.getDeclaredMethod("length").getName()); // test new object array type bc = _project.loadClass(String.class.getName() + "[]"); bc2 = _project.loadClass(String[].class); assertTrue(bc == bc2); assertTrue(bc.isArray()); assertEquals(String[].class.getName(), bc.getName()); } /** * Test loading classes by type. */ public void testLoadByType() { BCClass bc; BCClass bc2; Class[] types; String[] names; // test primitive types types = new Class[] { boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class, void.class }; names = new String[] { "Z", "B", "C", "D", "F", "I", "J", "S", "V" }; for (int i = 0; i < names.length; i++) { bc = _project.loadClass(types[i]); bc2 = _project.loadClass(names[i]); assertTrue(types[i].getName(), bc == bc2); assertTrue(types[i].getName(), bc.isPrimitive()); assertEquals(types[i].getName(), bc.getName()); } // test primitive array types types = new Class[] { boolean[].class, byte[].class, char[].class, double[].class, float[].class, int[].class, long[].class, short[].class, }; names = new String[] { "[Z", "[B", "[C", "[D", "[F", "[I", "[J", "[S" }; for (int i = 0; i < names.length; i++) { bc = _project.loadClass(types[i]); bc2 = _project.loadClass(names[i]); assertTrue(types[i].getName(), bc == bc2); assertTrue(types[i].getName(), bc.isArray()); assertEquals(types[i].getName(), bc.getName()); } // test existing object type bc = _project.loadClass(String.class); bc2 = _project.loadClass(String.class.getName()); assertTrue(bc == bc2); assertTrue(!bc.isPrimitive()); assertTrue(!bc.isArray()); assertEquals(String.class.getName(), bc.getName()); assertEquals("length", bc.getDeclaredMethod("length").getName()); // test new object array type bc = _project.loadClass(String[].class); bc2 = _project.loadClass(String.class.getName() + "[]"); assertTrue(bc == bc2); assertTrue(bc.isArray()); assertEquals(String[].class.getName(), bc.getName()); } /** * Test loading classes by file. */ public void testLoadByFile() { File file = new File(getClass().getResource("TestProject.class"). getFile()); BCClass bc = _project.loadClass(file); BCClass bc2 = _project.loadClass(file); assertTrue(bc == bc2); assertTrue(!bc.isPrimitive()); assertTrue(!bc.isArray()); assertEquals(getClass().getName(), bc.getName()); assertEquals("main", bc.getDeclaredMethod("main").getName()); } /** * Test loading classes by stream. */ public void testLoadByStream() { InputStream in = getClass().getResourceAsStream("TestProject.class"); InputStream in2 = getClass().getResourceAsStream("TestProject.class"); BCClass bc = _project.loadClass(in); BCClass bc2 = _project.loadClass(in2); assertTrue(bc == bc2); assertTrue(!bc.isPrimitive()); assertTrue(!bc.isArray()); assertEquals(getClass().getName(), bc.getName()); assertEquals("main", bc.getDeclaredMethod("main").getName()); } /** * Test retrieving all loaded classes. */ public void testGetClasses() { BCClass[] bcs = _project.getClasses(); assertEquals(0, bcs.length); BCClass[] added = new BCClass[3]; added[0] = _project.loadClass("int"); added[1] = _project.loadClass("serp.Foo"); added[2] = _project.loadClass(String[].class); bcs = _project.getClasses(); assertEquals(3, bcs.length); int matches; for (int i = 0; i < added.length; i++) { matches = 0; for (int j = 0; j < bcs.length; j++) if (added[i] == bcs[j]) matches++; assertEquals(1, matches); } } /** * Test renaming classes within the project. */ public void testRename() { BCClass str = _project.loadClass(String.class); BCClass foo = _project.loadClass("serp.Foo"); str.setName("java.lang.String2"); assertEquals("java.lang.String2", str.getName()); foo.setName("serp.Foo2"); assertEquals("serp.Foo2", foo.getName()); try { str.setName("serp.Foo2"); fail("Set to existing name"); } catch (IllegalStateException ise) { } assertEquals("java.lang.String2", str.getName()); try { foo.setName("java.lang.String2"); fail("Set to existing name"); } catch (IllegalStateException ise) { } assertEquals("serp.Foo2", foo.getName()); str.setName("serp.Foo"); assertEquals("serp.Foo", str.getName()); foo.setName("java.lang.String"); assertEquals("java.lang.String", foo.getName()); assertTrue(foo == _project.loadClass(String.class)); assertTrue(str == _project.loadClass("serp.Foo")); } /** * Test clearing classes. */ public void testClear() { _project.clear(); BCClass bc1 = _project.loadClass("int"); BCClass bc2 = _project.loadClass("serp.Foo"); BCClass bc3 = _project.loadClass(String[].class); assertTrue(bc1.isValid()); assertTrue(bc2.isValid()); assertTrue(bc3.isValid()); assertEquals(3, _project.getClasses().length); _project.clear(); assertEquals(0, _project.getClasses().length); // cleared classes should be invalid assertTrue(!bc1.isValid()); assertTrue(!bc2.isValid()); assertTrue(!bc3.isValid()); } /** * Test removing a class. */ public void testRemove() { assertTrue(!_project.removeClass((String) null)); assertTrue(!_project.removeClass((Class) null)); assertTrue(!_project.removeClass((BCClass) null)); BCClass bc1 = _project.loadClass("int"); BCClass bc2 = _project.loadClass("serp.Foo"); BCClass bc3 = _project.loadClass(String[].class); assertTrue(bc1.isValid()); assertTrue(bc2.isValid()); assertTrue(bc3.isValid()); assertTrue(!_project.removeClass(new Project().loadClass("int"))); assertTrue(_project.removeClass(bc1)); assertTrue(!bc1.isValid()); assertEquals(2, _project.getClasses().length); assertTrue(_project.removeClass("serp.Foo")); assertTrue(!bc1.isValid()); assertEquals(1, _project.getClasses().length); assertTrue(_project.removeClass(String[].class)); assertTrue(!bc1.isValid()); assertEquals(0, _project.getClasses().length); } public static Test suite() { return new TestSuite(TestProject.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestArrayStoreInstruction.java0000755000000000000000000000641110460270415023676 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link ArrayStoreInstruction} type. * * @author Abe White */ public class TestArrayStoreInstruction extends TestCase { private Code _code = new Code(); public TestArrayStoreInstruction(String test) { super(test); } /** * Test that the instruction initializes correctly when generated. */ public void testIniitalize() { assertEquals(Constants.NOP, _code.xastore().getOpcode()); assertEquals(Constants.IASTORE, _code.iastore().getOpcode()); assertEquals(Constants.LASTORE, _code.lastore().getOpcode()); assertEquals(Constants.FASTORE, _code.fastore().getOpcode()); assertEquals(Constants.DASTORE, _code.dastore().getOpcode()); assertEquals(Constants.AASTORE, _code.aastore().getOpcode()); assertEquals(Constants.BASTORE, _code.bastore().getOpcode()); assertEquals(Constants.CASTORE, _code.castore().getOpcode()); assertEquals(Constants.SASTORE, _code.sastore().getOpcode()); } /** * Test the the instruction returns its type correctly. */ public void testGetType() { assertNull(_code.xastore().getType()); assertEquals(int.class, _code.iastore().getType()); assertEquals(long.class, _code.lastore().getType()); assertEquals(float.class, _code.fastore().getType()); assertEquals(double.class, _code.dastore().getType()); assertEquals(Object.class, _code.aastore().getType()); assertEquals(byte.class, _code.bastore().getType()); assertEquals(char.class, _code.castore().getType()); assertEquals(short.class, _code.sastore().getType()); } /** * Test that the opcode morphs correctly with type changes. */ public void testOpcodeMorph() { ArrayStoreInstruction ins = _code.xastore(); assertEquals(Constants.NOP, ins.getOpcode()); assertEquals(Constants.NOP, ins.setType((String) null).getOpcode()); assertEquals(Constants.NOP, ins.setType((BCClass) null).getOpcode()); assertEquals(Constants.NOP, ins.setType((Class) null).getOpcode()); assertEquals(Constants.IASTORE, ins.setType(int.class).getOpcode()); assertEquals(Constants.NOP, ins.setType((String) null).getOpcode()); assertEquals(Constants.LASTORE, ins.setType(long.class).getOpcode()); assertEquals(Constants.FASTORE, ins.setType(float.class).getOpcode()); assertEquals(Constants.DASTORE, ins.setType(double.class).getOpcode()); assertEquals(Constants.AASTORE, ins.setType(Object.class).getOpcode()); assertEquals(Constants.BASTORE, ins.setType(byte.class).getOpcode()); assertEquals(Constants.CASTORE, ins.setType(char.class).getOpcode()); assertEquals(Constants.SASTORE, ins.setType(short.class).getOpcode()); assertEquals(Constants.IASTORE, ins.setType(void.class).getOpcode()); assertEquals(Constants.AASTORE, ins.setType(String.class).getOpcode()); assertEquals(Constants.IASTORE, ins.setType(boolean.class).getOpcode()); } public static Test suite() { return new TestSuite(TestArrayStoreInstruction.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestArrayLoadInstruction.java0000755000000000000000000000633610460270415023467 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link ArrayLoadInstruction} type. * * @author Abe White */ public class TestArrayLoadInstruction extends TestCase { private Code _code = new Code(); public TestArrayLoadInstruction(String test) { super(test); } /** * Test that the instruction initializes correctly when generated. */ public void testIniitalize() { assertEquals(Constants.NOP, _code.xaload().getOpcode()); assertEquals(Constants.IALOAD, _code.iaload().getOpcode()); assertEquals(Constants.LALOAD, _code.laload().getOpcode()); assertEquals(Constants.FALOAD, _code.faload().getOpcode()); assertEquals(Constants.DALOAD, _code.daload().getOpcode()); assertEquals(Constants.AALOAD, _code.aaload().getOpcode()); assertEquals(Constants.BALOAD, _code.baload().getOpcode()); assertEquals(Constants.CALOAD, _code.caload().getOpcode()); assertEquals(Constants.SALOAD, _code.saload().getOpcode()); } /** * Test the the instruction returns its type correctly. */ public void testGetType() { assertNull(_code.xaload().getType()); assertEquals(int.class, _code.iaload().getType()); assertEquals(long.class, _code.laload().getType()); assertEquals(float.class, _code.faload().getType()); assertEquals(double.class, _code.daload().getType()); assertEquals(Object.class, _code.aaload().getType()); assertEquals(byte.class, _code.baload().getType()); assertEquals(char.class, _code.caload().getType()); assertEquals(short.class, _code.saload().getType()); } /** * Test that the opcode morphs correctly with type changes. */ public void testOpcodeMorph() { ArrayLoadInstruction ins = _code.xaload(); assertEquals(Constants.NOP, ins.getOpcode()); assertEquals(Constants.NOP, ins.setType((String) null).getOpcode()); assertEquals(Constants.NOP, ins.setType((BCClass) null).getOpcode()); assertEquals(Constants.NOP, ins.setType((Class) null).getOpcode()); assertEquals(Constants.IALOAD, ins.setType(int.class).getOpcode()); assertEquals(Constants.NOP, ins.setType((String) null).getOpcode()); assertEquals(Constants.LALOAD, ins.setType(long.class).getOpcode()); assertEquals(Constants.FALOAD, ins.setType(float.class).getOpcode()); assertEquals(Constants.DALOAD, ins.setType(double.class).getOpcode()); assertEquals(Constants.AALOAD, ins.setType(Object.class).getOpcode()); assertEquals(Constants.BALOAD, ins.setType(byte.class).getOpcode()); assertEquals(Constants.CALOAD, ins.setType(char.class).getOpcode()); assertEquals(Constants.SALOAD, ins.setType(short.class).getOpcode()); assertEquals(Constants.IALOAD, ins.setType(void.class).getOpcode()); assertEquals(Constants.AALOAD, ins.setType(String.class).getOpcode()); assertEquals(Constants.IALOAD, ins.setType(boolean.class).getOpcode()); } public static Test suite() { return new TestSuite(TestArrayLoadInstruction.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/TestCode.java0000755000000000000000000000707310460270415020220 0ustar package serp.bytecode; import junit.framework.*; import junit.textui.*; /** * Tests the {@link Code} class. * * @author Eric Lindauer */ public class TestCode extends TestCase { public TestCode(String test) { super(test); } /** * Test that removing Instructions from a Code block * removes the correct Instructions. */ public void testRemove() { Code code = new Code(); JumpInstruction go2 = code.go2(); Instruction first = code.nop(); Instruction second = code.nop(); Instruction third = code.nop(); Instruction fourth = code.nop(); go2.setTarget(second); // remove 'second' after a next() call code.beforeFirst(); code.next(); code.next(); code.next(); code.remove(); assertEquals(third, code.next()); assertEquals(third, go2.getTarget()); code.beforeFirst(); assertEquals(go2, code.next()); assertEquals(first, code.next()); assertEquals(third, code.next()); assertEquals(fourth, code.next()); // remove 'third' after a previous() call code.beforeFirst(); code.next(); code.next(); code.next(); code.next(); code.previous(); code.previous(); code.remove(); assertEquals(fourth, go2.getTarget()); assertEquals(fourth, code.next()); assertTrue(!code.hasNext()); assertEquals(fourth, code.previous()); code.remove(); code.afterLast(); assertEquals(code.previous(), go2.getTarget()); assertEquals(first, code.previous()); } /** * Test that instruction indexes work correctly. */ public void testIndexes() { Code code = new Code(); assertEquals(0, code.nextIndex()); assertEquals(-1, code.previousIndex()); Instruction first = code.nop(); assertEquals(1, code.nextIndex()); assertEquals(0, code.previousIndex()); Instruction second = code.nop(); assertEquals(2, code.nextIndex()); assertEquals(1, code.previousIndex()); code.previous(); assertEquals(1, code.nextIndex()); assertEquals(0, code.previousIndex()); code.next(); assertEquals(2, code.nextIndex()); assertEquals(1, code.previousIndex()); Instruction third = code.nop(); assertEquals(3, code.nextIndex()); assertEquals(2, code.previousIndex()); code.afterLast(); assertEquals(3, code.nextIndex()); assertEquals(2, code.previousIndex()); code.beforeFirst(); assertEquals(0, code.nextIndex()); assertEquals(-1, code.previousIndex()); code.before(first); assertEquals(0, code.nextIndex()); assertEquals(-1, code.previousIndex()); code.before(second); assertEquals(1, code.nextIndex()); assertEquals(0, code.previousIndex()); code.before(third); assertEquals(2, code.nextIndex()); assertEquals(1, code.previousIndex()); code.after(first); assertEquals(1, code.nextIndex()); assertEquals(0, code.previousIndex()); code.after(second); assertEquals(2, code.nextIndex()); assertEquals(1, code.previousIndex()); code.after(third); assertEquals(3, code.nextIndex()); assertEquals(2, code.previousIndex()); } public static Test suite() { return new TestSuite(TestCode.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/bytecode/lowlevel/0000755000000000000000000000000011401260237017457 5ustar serp-1.14.1.orig/src/test/java/serp/bytecode/lowlevel/TestConstantPool.java0000755000000000000000000003173110460270415023620 0ustar package serp.bytecode.lowlevel; import junit.framework.*; import junit.textui.*; /** * Tests the {@link ConstantPool} type. * * @author Abe White */ public class TestConstantPool extends TestCase { private ConstantPool _pool = new ConstantPool(); private IntEntry _intEntry = new IntEntry(1); private LongEntry _longEntry = new LongEntry(2L); private UTF8Entry _utf8Entry = new UTF8Entry("4"); public TestConstantPool(String test) { super(test); } /** * Tests adding entries. */ public void testAdd() { assertEquals(0, _pool.size()); assertEquals(1, _pool.addEntry(_intEntry)); assertEquals(1, _pool.size()); assertEquals(2, _pool.addEntry(_longEntry)); assertEquals(3, _pool.size()); assertEquals(4, _pool.addEntry(_utf8Entry)); assertEquals(4, _pool.size()); assertEquals(_intEntry, _pool.getEntry(1)); assertEquals(_longEntry, _pool.getEntry(2)); assertEquals(_utf8Entry, _pool.getEntry(4)); assertEquals(1, _pool.findIntEntry(1, false)); assertEquals(2, _pool.findLongEntry(2L, false)); assertEquals(4, _pool.findUTF8Entry("4", false)); // add an entry multiple times assertEquals(4, _pool.addEntry(_utf8Entry)); assertEquals(5, _pool.addEntry(new UTF8Entry("4"))); // cannot add to another pool ConstantPool pool = new ConstantPool(); try { pool.addEntry(_intEntry); fail("Entry already in another pool"); } catch (IllegalStateException ise) { } assertEquals(0, pool.size()); _pool.removeEntry(_intEntry); assertEquals(0, _pool.indexOf(_intEntry)); pool.addEntry(_intEntry); assertEquals(1, pool.size()); assertEquals(_intEntry, pool.getEntry(1)); } /** * Tests removing entries. */ public void testRemove() { _pool.addEntry(_intEntry); _pool.addEntry(_longEntry); _pool.addEntry(_utf8Entry); assertEquals(4, _pool.size()); assertTrue(_pool.removeEntry(_longEntry)); assertEquals(2, _pool.size()); assertEquals(_intEntry, _pool.getEntry(1)); assertEquals(_utf8Entry, _pool.getEntry(2)); assertEquals(1, _pool.findIntEntry(1, false)); assertEquals(2, _pool.findUTF8Entry("4", false)); assertEquals(0, _pool.findLongEntry(2L, false)); assertTrue(!_pool.removeEntry(_longEntry)); assertTrue(_pool.removeEntry(_intEntry)); assertEquals(1, _pool.size()); assertEquals(_utf8Entry, _pool.getEntry(1)); assertEquals(0, _pool.findIntEntry(1, false)); assertEquals(1, _pool.findUTF8Entry("4", false)); assertTrue(_pool.removeEntry(_utf8Entry)); assertEquals(0, _pool.size()); try { _pool.getEntry(1); fail("Invalid index"); } catch (IndexOutOfBoundsException ioobe) { } assertEquals(0, _pool.findUTF8Entry("4", false)); } /** * Tests mutating entries. */ public void testMutate() { _intEntry.setValue(2); _pool.addEntry(_intEntry); _pool.addEntry(_longEntry); _pool.addEntry(_utf8Entry); assertEquals(1, _pool.findIntEntry(2, false)); assertEquals(2, _pool.findLongEntry(2L, false)); assertEquals(4, _pool.findUTF8Entry("4", false)); _intEntry.setValue(1); _longEntry.setValue(3L); _utf8Entry.setValue("foo"); assertEquals(1, _pool.findIntEntry(1, false)); assertEquals(2, _pool.findLongEntry(3L, false)); assertEquals(4, _pool.findUTF8Entry("foo", false)); } /** * Tests finding the index of entries. */ public void testIndexOf() { _pool.addEntry(_intEntry); _pool.addEntry(_longEntry); _pool.addEntry(_utf8Entry); assertEquals(1, _pool.indexOf(_intEntry)); assertEquals(2, _pool.indexOf(_longEntry)); assertEquals(4, _pool.indexOf(_utf8Entry)); _pool.removeEntry(_longEntry); assertEquals(1, _pool.indexOf(_intEntry)); assertEquals(0, _pool.indexOf(_longEntry)); assertEquals(2, _pool.indexOf(_utf8Entry)); } /** * Tests getting all entries. */ public void testGetEntries() { _pool.addEntry(_intEntry); _pool.addEntry(_longEntry); _pool.addEntry(_utf8Entry); Entry[] entries = _pool.getEntries(); assertEquals(3, entries.length); assertEquals(_intEntry, entries[0]); assertEquals(_longEntry, entries[1]); assertEquals(_utf8Entry, entries[2]); _pool.clear(); assertEquals(0, _pool.getEntries().length); } /** * Tests getting entries by index. */ public void testGetEntry() { _pool.addEntry(_intEntry); _pool.addEntry(_longEntry); _pool.addEntry(_utf8Entry); assertEquals(_intEntry, _pool.getEntry(1)); assertEquals(_longEntry, _pool.getEntry(2)); assertEquals(_utf8Entry, _pool.getEntry(4)); try { _pool.getEntry(0); fail("0 index"); } catch (IndexOutOfBoundsException ioobe) { } try { _pool.getEntry(_pool.size() + 1); fail("size() + 1 index"); } catch (IndexOutOfBoundsException ioobe) { } try { _pool.getEntry(3); fail("Wide index"); } catch (IndexOutOfBoundsException ioobe) { } } /** * Test clearing the pool. */ public void testClear() { // make sure clearing empty pool OK _pool.clear(); assertEquals(0, _pool.size()); _pool.addEntry(_intEntry); _pool.addEntry(_longEntry); _pool.addEntry(_utf8Entry); _pool.clear(); assertEquals(0, _pool.size()); assertEquals(0, _pool.findIntEntry(1, false)); assertEquals(0, _pool.findUTF8Entry("4", false)); } /** * Test finding entry indexes. */ public void testFind() { int double1 = _pool.addEntry(new DoubleEntry(1D)); int double2 = _pool.addEntry(new DoubleEntry(2D)); int float1 = _pool.addEntry(new FloatEntry(1F)); int float2 = _pool.addEntry(new FloatEntry(2F)); int int1 = _pool.addEntry(new IntEntry(1)); int int2 = _pool.addEntry(new IntEntry(2)); int long1 = _pool.addEntry(new LongEntry(1L)); int long2 = _pool.addEntry(new LongEntry(2L)); int utf1 = _pool.addEntry(new UTF8Entry("1")); int utf2 = _pool.addEntry(new UTF8Entry("2")); int string1 = _pool.addEntry(new StringEntry(utf1)); int string2 = _pool.addEntry(new StringEntry(utf2)); int class1 = _pool.addEntry(new ClassEntry(utf1)); int class2 = _pool.addEntry(new ClassEntry(utf2)); int name1 = _pool.addEntry(new NameAndTypeEntry(utf1, utf2)); int name2 = _pool.addEntry(new NameAndTypeEntry(utf2, utf1)); int field1 = _pool.addEntry(new FieldEntry(class1, name1)); int field2 = _pool.addEntry(new FieldEntry(class2, name2)); int method1 = _pool.addEntry(new MethodEntry(class1, name1)); int method2 = _pool.addEntry(new MethodEntry(class2, name2)); int imethod1 = _pool.addEntry(new InterfaceMethodEntry(class1, name1)); int imethod2 = _pool.addEntry(new InterfaceMethodEntry(class2, name2)); assertEquals(0, _pool.findDoubleEntry(0D, false)); assertEquals(double1, _pool.findDoubleEntry(1D, false)); assertEquals(double2, _pool.findDoubleEntry(2D, false)); assertEquals(double1, _pool.findDoubleEntry(1D, true)); assertEquals(double2, _pool.findDoubleEntry(2D, true)); assertEquals(_pool.size() + 1, _pool.findDoubleEntry(0D, true)); assertEquals(0, _pool.findFloatEntry(0F, false)); assertEquals(float1, _pool.findFloatEntry(1F, false)); assertEquals(float2, _pool.findFloatEntry(2F, false)); assertEquals(float1, _pool.findFloatEntry(1F, true)); assertEquals(float2, _pool.findFloatEntry(2F, true)); assertEquals(_pool.size() + 1, _pool.findFloatEntry(0F, true)); assertEquals(0, _pool.findIntEntry(0, false)); assertEquals(int1, _pool.findIntEntry(1, false)); assertEquals(int2, _pool.findIntEntry(2, false)); assertEquals(int1, _pool.findIntEntry(1, true)); assertEquals(int2, _pool.findIntEntry(2, true)); assertEquals(_pool.size() + 1, _pool.findIntEntry(0, true)); assertEquals(0, _pool.findLongEntry(0L, false)); assertEquals(long1, _pool.findLongEntry(1L, false)); assertEquals(long2, _pool.findLongEntry(2L, false)); assertEquals(long1, _pool.findLongEntry(1L, true)); assertEquals(long2, _pool.findLongEntry(2L, true)); assertEquals(_pool.size() + 1, _pool.findLongEntry(0L, true)); assertEquals(0, _pool.findUTF8Entry("0", false)); assertEquals(utf1, _pool.findUTF8Entry("1", false)); assertEquals(utf2, _pool.findUTF8Entry("2", false)); assertEquals(utf1, _pool.findUTF8Entry("1", true)); assertEquals(utf2, _pool.findUTF8Entry("2", true)); assertEquals(_pool.size() + 1, _pool.findUTF8Entry("0", true)); assertEquals(0, _pool.findStringEntry("0", false)); assertEquals(string1, _pool.findStringEntry("1", false)); assertEquals(string2, _pool.findStringEntry("2", false)); assertEquals(string1, _pool.findStringEntry("1", true)); assertEquals(string2, _pool.findStringEntry("2", true)); assertEquals(_pool.size() + 1, _pool.findStringEntry("0", true)); assertEquals(_pool.size() + 2, _pool.findStringEntry("aaa", true)); assertEquals(0, _pool.findClassEntry("0", false)); assertEquals(class1, _pool.findClassEntry("1", false)); assertEquals(class2, _pool.findClassEntry("2", false)); assertEquals(class1, _pool.findClassEntry("1", true)); assertEquals(class2, _pool.findClassEntry("2", true)); assertEquals(_pool.size() + 1, _pool.findClassEntry("0", true)); assertEquals(_pool.size() + 2, _pool.findStringEntry("bbb", true)); assertEquals(0, _pool.findNameAndTypeEntry("0", "1", false)); assertEquals(name1, _pool.findNameAndTypeEntry("1", "2", false)); assertEquals(name2, _pool.findNameAndTypeEntry("2", "1", false)); assertEquals(name1, _pool.findNameAndTypeEntry("1", "2", true)); assertEquals(name2, _pool.findNameAndTypeEntry("2", "1", true)); assertEquals(_pool.size() + 1, _pool.findNameAndTypeEntry("0", "1", true)); assertEquals(_pool.size() + 2, _pool.findNameAndTypeEntry("2", "3", true)); assertEquals(_pool.size() + 3, _pool.findNameAndTypeEntry("ccc", "ddd", true)); assertEquals(0, _pool.findFieldEntry("0", "1", "2", false)); assertEquals(field1, _pool.findFieldEntry("1", "1", "2", false)); assertEquals(field2, _pool.findFieldEntry("2", "2", "1", false)); assertEquals(field1, _pool.findFieldEntry("1", "1", "2", true)); assertEquals(field2, _pool.findFieldEntry("2", "2", "1", true)); assertEquals(_pool.size() + 1, _pool.findFieldEntry("1", "2", "1", true)); assertEquals(_pool.size() + 3, _pool.findFieldEntry("1", "3", "4", true)); assertEquals(_pool.size() + 6, _pool.findFieldEntry("eee", "fff", "ggg", true)); assertEquals(0, _pool.findMethodEntry("0", "1", "2", false)); assertEquals(method1, _pool.findMethodEntry("1", "1", "2", false)); assertEquals(method2, _pool.findMethodEntry("2", "2", "1", false)); assertEquals(method1, _pool.findMethodEntry("1", "1", "2", true)); assertEquals(method2, _pool.findMethodEntry("2", "2", "1", true)); assertEquals(_pool.size() + 1, _pool.findMethodEntry("1", "2", "1", true)); assertEquals(_pool.size() + 3, _pool.findMethodEntry("1", "3", "5", true)); assertEquals(_pool.size() + 6, _pool.findMethodEntry("hhh", "iii", "jjj", true)); assertEquals(0, _pool.findInterfaceMethodEntry("0", "1", "2", false)); assertEquals(imethod1, _pool.findInterfaceMethodEntry("1", "1", "2", false)); assertEquals(imethod2, _pool.findInterfaceMethodEntry("2", "2", "1", false)); assertEquals(imethod1, _pool.findInterfaceMethodEntry("1", "1", "2", true)); assertEquals(imethod2, _pool.findInterfaceMethodEntry("2", "2", "1", true)); assertEquals(_pool.size() + 1, _pool.findInterfaceMethodEntry("1", "2", "1", true)); assertEquals(_pool.size() + 3, _pool.findInterfaceMethodEntry("1", "3", "6", true)); assertEquals(_pool.size() + 6, _pool.findInterfaceMethodEntry("kkk", "lll", "mmm", true)); } public static Test suite() { return new TestSuite(TestConstantPool.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/test/java/serp/util/0000755000000000000000000000000011401260237015005 5ustar serp-1.14.1.orig/src/test/java/serp/util/TestStrings.java0000755000000000000000000001034010460270415020145 0ustar package serp.util; import junit.framework.*; import junit.textui.*; /** * Tests the {@link Strings} type. * * @author Abe White */ public class TestStrings extends TestCase { public TestStrings(String test) { super(test); } /** * Test {@link Strings#split}. */ public void testSplit() { String str = "boo:and:foo"; assertEquals(new String[] { "boo", "and:foo" }, Strings.split(str, ":", 2)); assertEquals(new String[] { "boo:and:foo" }, Strings.split(str, ":", 1)); assertEquals(new String[] { "boo", "and", "foo" }, Strings.split(str, ":", 0)); assertEquals(new String[] { "boo", "and", "foo" }, Strings.split(str, ":", -2)); assertEquals(new String[] { "b", "", ":and:f", "", "" }, Strings.split(str, "o", 5)); assertEquals(new String[] { "b", "", ":and:f", "o" }, Strings.split(str, "o", 4)); assertEquals(new String[] { "b", "", ":and:f", "", "" }, Strings.split(str, "o", -2)); assertEquals(new String[] { "b", "", ":and:f" }, Strings.split(str, "o", 0)); assertEquals(new String[] { "", "b", "", ":and:f" }, Strings.split("o" + str, "o", 0)); } /** * Test {@link Strings#classForName}. */ public void testClassForName() { // test primitives assertEquals(boolean.class, Strings.toClass("boolean", null)); assertEquals(byte.class, Strings.toClass("byte", null)); assertEquals(char.class, Strings.toClass("char", null)); assertEquals(double.class, Strings.toClass("double", null)); assertEquals(float.class, Strings.toClass("float", null)); assertEquals(int.class, Strings.toClass("int", null)); assertEquals(long.class, Strings.toClass("long", null)); assertEquals(short.class, Strings.toClass("short", null)); assertEquals(void.class, Strings.toClass("void", null)); // test objects assertEquals(String.class, Strings.toClass(String.class.getName(), null)); // test arrays assertEquals(boolean[].class, Strings.toClass("[Z", null)); assertEquals(byte[].class, Strings.toClass("[B", null)); assertEquals(char[].class, Strings.toClass("[C", null)); assertEquals(double[].class, Strings.toClass("[D", null)); assertEquals(float[].class, Strings.toClass("[F", null)); assertEquals(int[].class, Strings.toClass("[I", null)); assertEquals(long[].class, Strings.toClass("[J", null)); assertEquals(short[].class, Strings.toClass("[S", null)); assertEquals(String[].class, Strings.toClass(String[].class.getName(), null)); assertEquals(boolean[][].class, Strings.toClass("[[Z", null)); assertEquals(String[][].class, Strings.toClass(String[][].class.getName(), null)); assertEquals(boolean[].class, Strings.toClass("boolean[]", null)); assertEquals(byte[].class, Strings.toClass("byte[]", null)); assertEquals(char[].class, Strings.toClass("char[]", null)); assertEquals(double[].class, Strings.toClass("double[]", null)); assertEquals(float[].class, Strings.toClass("float[]", null)); assertEquals(int[].class, Strings.toClass("int[]", null)); assertEquals(long[].class, Strings.toClass("long[]", null)); assertEquals(short[].class, Strings.toClass("short[]", null)); assertEquals(String[].class, Strings.toClass("java.lang.String[]", null)); try { Strings.toClass("[V", null); fail("Allowed invalid class name"); } catch (RuntimeException re) { } try { Strings.toClass("java.lang.Foo", null); fail("Allowed invalid class name"); } catch (RuntimeException re) { } } private void assertEquals(String[] arr1, String[] arr2) { assertEquals(arr1.length, arr2.length); for (int i = 0; i < arr1.length; i++) assertEquals(arr1[i], arr2[i]); } public static Test suite() { return new TestSuite(TestStrings.class); } public static void main(String[] args) { TestRunner.run(suite()); } } serp-1.14.1.orig/src/main/0000755000000000000000000000000011401260236012102 5ustar serp-1.14.1.orig/src/main/java/0000755000000000000000000000000011401260236013023 5ustar serp-1.14.1.orig/src/main/java/serp/0000755000000000000000000000000011401260237013775 5ustar serp-1.14.1.orig/src/main/java/serp/bytecode/0000755000000000000000000000000011401260237015573 5ustar serp-1.14.1.orig/src/main/java/serp/bytecode/LocalVariableTable.java0000755000000000000000000000552210460270414022117 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * Code blocks compiled from source have local variable tables mapping * locals used in opcodes to their names and descriptions. * * @author Abe White */ public class LocalVariableTable extends LocalTable { LocalVariableTable(int nameIndex, Attributes owner) { super(nameIndex, owner); } /** * Return all the locals of this method. */ public LocalVariable[] getLocalVariables() { return (LocalVariable[]) getLocals(); } /** * Return the local with the given locals index, or null if none. */ public LocalVariable getLocalVariable(int local) { return (LocalVariable) getLocal(local); } /** * Return the local with the given name, or null if none. If multiple * locals have the given name, which is returned is undefined. */ public LocalVariable getLocalVariable(String name) { return (LocalVariable) getLocal(name); } /** * Return all locals with the given name, or empty array if none. */ public LocalVariable[] getLocalVariables(String name) { return (LocalVariable[]) getLocals(name); } /** * Import a local from another method/class. Note that * the program counter and length from the given local is copied * directly, and thus will be incorrect unless this method is the same * as the one the local is copied from, or the pc and length are reset. */ public LocalVariable addLocalVariable(LocalVariable local) { return (LocalVariable) addLocal(local); } /** * Add a local to this table. */ public LocalVariable addLocalVariable() { return (LocalVariable) addLocal(); } /** * Add a local to this table. */ public LocalVariable addLocalVariable(String name, String type) { return (LocalVariable) addLocal(name, type); } /** * Add a local to this table. */ public LocalVariable addLocalVariable(String name, Class type) { String typeName = (type == null) ? null : type.getName(); return addLocalVariable(name, typeName); } /** * Add a local to this table. */ public LocalVariable addLocalVariable(String name, BCClass type) { String typeName = (type == null) ? null : type.getName(); return addLocalVariable(name, typeName); } public void acceptVisit(BCVisitor visit) { visit.enterLocalVariableTable(this); LocalVariable[] locals = (LocalVariable[]) getLocals(); for (int i = 0; i < locals.length; i++) locals[i].acceptVisit(visit); visit.exitLocalVariableTable(this); } protected Local newLocal() { return new LocalVariable(this); } protected Local[] newLocalArray(int size) { return new LocalVariable[size]; } } serp-1.14.1.orig/src/main/java/serp/bytecode/BCField.java0000755000000000000000000001035010517502266017700 0ustar package serp.bytecode; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * A field of a class. * * @author Abe White */ public class BCField extends BCMember implements VisitAcceptor { BCField(BCClass owner) { super(owner); if (owner.isEnum()) setEnum(true); } /** * Manipulate the field access flags. */ public boolean isVolatile() { return (getAccessFlags() & Constants.ACCESS_VOLATILE) > 0; } /** * Manipulate the field access flags. */ public void setVolatile(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_VOLATILE); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_VOLATILE); } /** * Manipulate the field access flags. */ public boolean isTransient() { return (getAccessFlags() & Constants.ACCESS_TRANSIENT) > 0; } /** * Manipulate the field access flags. */ public void setTransient(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_TRANSIENT); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_TRANSIENT); } /** * Manipulate the field access flags. Defaults to true for fields added * to enum classes. */ public boolean isEnum() { return (getAccessFlags() & Constants.ACCESS_ENUM) > 0; } /** * Manipulate the field access flags. Defaults to true for fields added * to enum classes. */ public void setEnum(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_ENUM); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ENUM); } /** * Return the name of the type of this field. The name will be given in * a form suitable for a {@link Class#forName} call. * * @see BCMember#getDescriptor */ public String getTypeName() { return getProject().getNameCache().getExternalForm (getDescriptor(), false); } /** * Return the {@link Class} object for the type of this field. */ public Class getType() { return Strings.toClass(getTypeName(), getClassLoader()); } /** * Return the bytecode for the type of this field. */ public BCClass getTypeBC() { return getProject().loadClass(getTypeName(), getClassLoader()); } /** * Set the name of the type of this field. * * @see BCMember#setDescriptor */ public void setType(String type) { setDescriptor(type); } /** * Set the type of this field. * * @see BCMember#setDescriptor */ public void setType(Class type) { setType(type.getName()); } /** * Set the type of this field. * * @see BCMember#setDescriptor */ public void setType(BCClass type) { setType(type.getName()); } /** * Return the constant value information for the field. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new constant value attribute will be added * if not already present * @return the constant value information, or null if none and the * add param is set to false */ public ConstantValue getConstantValue(boolean add) { ConstantValue constant = (ConstantValue) getAttribute (Constants.ATTR_CONST); if (!add || (constant != null)) return constant; if (constant == null) constant = (ConstantValue) addAttribute(Constants.ATTR_CONST); return constant; } /** * Remove the constant value attribute for the field. * Acts internally through the {@link Attributes} interface. * * @return true if there was a value to remove */ public boolean removeConstantValue() { return removeAttribute(Constants.ATTR_CONST); } public void acceptVisit(BCVisitor visit) { visit.enterBCField(this); visitAttributes(visit); visit.exitBCField(this); } void initialize(String name, String descriptor) { super.initialize(name, descriptor); makePrivate(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/Annotated.java0000755000000000000000000000524610620672122020367 0ustar package serp.bytecode; /** * An annotated entity. * * @author Abe White */ public abstract class Annotated extends Attributes { /** * Return runtime invisible annotation information for the entity. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new annotations attribute will be added if not * already present * @return the annotation information, or null if none and the * add param is set to false */ public Annotations getDeclaredAnnotations(boolean add) { Annotations ann = (Annotations) getAttribute (Constants.ATTR_ANNOTATIONS); if (!add || ann != null) return ann; ensureBytecodeVersion(); return (Annotations) addAttribute(Constants.ATTR_ANNOTATIONS); } /** * Remove the runtime invisible annotations attribute for the entity. * Acts internally through the {@link Attributes} interface. * * @return true if there was an attribute to remove */ public boolean removeDeclaredAnnotations() { return removeAttribute(Constants.ATTR_ANNOTATIONS); } /** * Return runtime visible annotation information for the entity. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new runtime annotations attribute will be * added if not already present * @return the annotation information, or null if none and the * add param is set to false */ public Annotations getDeclaredRuntimeAnnotations(boolean add) { Annotations ann = (Annotations) getAttribute (Constants.ATTR_RUNTIME_ANNOTATIONS); if (!add || ann != null) return ann; ensureBytecodeVersion(); return (Annotations) addAttribute(Constants.ATTR_RUNTIME_ANNOTATIONS); } /** * Remove the runtime visible annotations attribute for the entity. * Acts internally through the {@link Attributes} interface. * * @return true if there was an attribute to remove */ public boolean removeDeclaredRuntimeAnnotations() { return removeAttribute(Constants.ATTR_RUNTIME_ANNOTATIONS); } /** * When adding annotations, make sure the bytecode spec supports them. */ private void ensureBytecodeVersion() { BCClass bc = getBCClass(); if (bc.getMajorVersion() < Constants.MAJOR_VERSION_JAVA5) { bc.setMajorVersion(Constants.MAJOR_VERSION_JAVA5); bc.setMinorVersion(Constants.MINOR_VERSION_JAVA5); } } /** * Internal access to the owning class. */ abstract BCClass getBCClass(); } serp-1.14.1.orig/src/main/java/serp/bytecode/LineNumberTable.java0000755000000000000000000001223210460270414021453 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * Code blocks compiled from source have line number tables mapping * opcodes to source lines. This table automatically maintains line * numbers in ascending order by their start program counter position * at all times. * * @author Abe White */ public class LineNumberTable extends Attribute implements InstructionPtr { private List _lineNumbers = new ArrayList(); LineNumberTable(int nameIndex, Attributes owner) { super(nameIndex, owner); } /** * Return the line numbers held in this table. */ public LineNumber[] getLineNumbers() { Collections.sort(_lineNumbers); return (LineNumber[]) _lineNumbers.toArray (new LineNumber[_lineNumbers.size()]); } /** * Return the line number for the given program counter, or null if none. */ public LineNumber getLineNumber(int pc) { for (int i = _lineNumbers.size() - 1; i >= 0; i--) if (((LineNumber) _lineNumbers.get(i))._target.getByteIndex() <= pc) return (LineNumber) _lineNumbers.get(i); return null; } /** * Return the line number for the given instruction, or null if none. */ public LineNumber getLineNumber(Instruction ins) { if (ins == null) return null; return getLineNumber(ins.getByteIndex()); } /** * Set the line numbers for the table. This method is useful when * importing line numbers from another method. */ public void setLineNumbers(LineNumber[] lines) { clear(); if (lines != null) for (int i = 0; i < lines.length; i++) addLineNumber(lines[i]); } /** * Import a line number from another method. * * @return the newly added line number */ public LineNumber addLineNumber(LineNumber ln) { LineNumber line = addLineNumber(); line.setStartPc(ln.getStartPc()); line.setLine(ln.getLine()); return line; } /** * Add a new line number to this table. */ public LineNumber addLineNumber() { LineNumber ln = new LineNumber(this); _lineNumbers.add(ln); return ln; } /** * Add a new line number to this table. */ public LineNumber addLineNumber(int startPc, int line) { LineNumber ln = addLineNumber(); ln.setStartPc(startPc); ln.setLine(line); return ln; } /** * Add a new line number to this table. */ public LineNumber addLineNumber(Instruction start, int line) { LineNumber ln = addLineNumber(); ln.setStart(start); ln.setLine(line); return ln; } /** * Clear the line numbers. */ public void clear() { for (int i = 0; i < _lineNumbers.size(); i++) ((LineNumber) _lineNumbers.get(i)).invalidate(); _lineNumbers.clear(); } /** * Remove the given line. * * @return true if the line was removed, false otherwise */ public boolean removeLineNumber(LineNumber ln) { if (ln == null || !_lineNumbers.remove(ln)) return false; ln.invalidate(); return true; } /** * Remove the line number for the given program counter. * * @return true if the line was removed, false otherwise */ public boolean removeLineNumber(int pc) { return removeLineNumber(getLineNumber(pc)); } /** * Remove the line number for the given instruction. * * @return true if the line was removed, false otherwise */ public boolean removeLineNumber(Instruction ins) { return removeLineNumber(getLineNumber(ins)); } public void updateTargets() { for (int i = 0; i < _lineNumbers.size(); i++) ((LineNumber) _lineNumbers.get(i)).updateTargets(); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { for (int i = 0; i < _lineNumbers.size(); i++) ((LineNumber) _lineNumbers.get(i)).replaceTarget(oldTarget, newTarget); } public void acceptVisit(BCVisitor visit) { visit.enterLineNumberTable(this); LineNumber[] lines = getLineNumbers(); for (int i = 0; i < lines.length; i++) lines[i].acceptVisit(visit); visit.exitLineNumberTable(this); } int getLength() { return 2 + (4 * _lineNumbers.size()); } void read(Attribute other) { setLineNumbers(((LineNumberTable) other).getLineNumbers()); } void read(DataInput in, int length) throws IOException { clear(); int numLines = in.readUnsignedShort(); LineNumber lineNumber; for (int i = 0; i < numLines; i++) { lineNumber = addLineNumber(); lineNumber.read(in); } } void write(DataOutput out, int length) throws IOException { LineNumber[] lines = getLineNumbers(); out.writeShort(lines.length); for (int i = 0; i < lines.length; i++) lines[i].write(out); } public Code getCode() { return (Code) getOwner(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/ConstantInstruction.java0000755000000000000000000003450310677227261022517 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * An instruction that that loads a constant onto the stack. * The opcode represented by this instruction may change depending on the * type and value of the constant set. For example, if the constant value * is initially set to 5, the opcode will be iconst5; if later * incremented to 6, the opcode will be changed to bipush(6). * * @author Abe White */ public class ConstantInstruction extends TypedInstruction { private int _arg = -1; ConstantInstruction(Code owner) { super(owner); } ConstantInstruction(Code owner, int opcode) { super(owner, opcode); } int getLength() { switch (getOpcode()) { case Constants.BIPUSH: case Constants.LDC: return super.getLength() + 1; case Constants.SIPUSH: case Constants.LDCW: case Constants.LDC2W: return super.getLength() + 2; default: return super.getLength(); } } public int getStackChange() { String type = getTypeName(); if (double.class.getName().equals(type) || long.class.getName().equals(type)) return 2; return 1; } public int getLogicalStackChange() { return 1; } public String getTypeName() { int opcode = getOpcode(); switch (opcode) { case Constants.NOP: return null; case Constants.ACONSTNULL: return Object.class.getName(); case Constants.ICONSTM1: case Constants.ICONST0: case Constants.ICONST1: case Constants.ICONST2: case Constants.ICONST3: case Constants.ICONST4: case Constants.ICONST5: case Constants.BIPUSH: case Constants.SIPUSH: return int.class.getName(); case Constants.LCONST0: case Constants.LCONST1: return long.class.getName(); case Constants.FCONST0: case Constants.FCONST1: case Constants.FCONST2: return float.class.getName(); case Constants.DCONST0: case Constants.DCONST1: return double.class.getName(); } Entry entry = getPool().getEntry(_arg); switch (entry.getType()) { case Entry.UTF8: case Entry.STRING: return String.class.getName(); case Entry.INT: return int.class.getName(); case Entry.FLOAT: return float.class.getName(); case Entry.LONG: return long.class.getName(); case Entry.DOUBLE: return double.class.getName(); case Entry.CLASS: return Class.class.getName(); default: return null; } } public TypedInstruction setType(String type) { throw new UnsupportedOperationException("Use setValue"); } /** * Return the value of the constant as its wrapper type, or null if * not set. Returns class values as the class name. */ public Object getValue() { int opcode = getOpcode(); switch (opcode) { case Constants.NOP: case Constants.ACONSTNULL: return null; case Constants.ICONSTM1: case Constants.ICONST0: case Constants.ICONST1: case Constants.ICONST2: case Constants.ICONST3: case Constants.ICONST4: case Constants.ICONST5: return Numbers.valueOf(opcode - Constants.ICONST0); case Constants.LCONST0: case Constants.LCONST1: return Numbers.valueOf((long) (opcode - Constants.LCONST0)); case Constants.FCONST0: case Constants.FCONST1: case Constants.FCONST2: return new Float(opcode - Constants.FCONST0); case Constants.DCONST0: case Constants.DCONST1: return new Double(opcode - Constants.DCONST0); case Constants.BIPUSH: case Constants.SIPUSH: return Numbers.valueOf(_arg); default: Entry entry = getPool().getEntry(_arg); Object val = ((ConstantEntry) entry).getConstant(); if (entry.getType() == Entry.CLASS) return getProject().getNameCache().getExternalForm((String) val, false); return val; } } /** * Set the constant to the given value. The value should be * an instance of String, Integer, Long, Double, Float, Class, BCClass, or * null depending on the constant type. If the given value is not * supported directly, it will be converted accordingly. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(Object value) { boolean clsName = false; if (value instanceof Boolean) value = Numbers.valueOf((((Boolean) value).booleanValue()) ? 1 : 0); else if (value instanceof Character) value = Numbers.valueOf((int) ((Character) value).charValue()); else if (value instanceof Byte) value = Numbers.valueOf(((Byte) value).intValue()); else if (value instanceof Short) value = Numbers.valueOf(((Short) value).intValue()); else if (value instanceof Class) { value = ((Class) value).getName(); clsName = true; } else if (value instanceof BCClass) { value = ((BCClass) value).getName(); clsName = true; } else if (value != null && !(value instanceof Number) && !(value instanceof String)) throw new IllegalArgumentException("value = " + value); calculateOpcode(value, clsName, false); return this; } /** * Return the string value of this constant, or null if not set. */ public String getStringValue() { return (String) getValue(); } /** * Return the int value of this constant, or 0 if not set. */ public int getIntValue() { Object value = getValue(); return (value == null) ? 0 : ((Number) value).intValue(); } /** * Return the long value of this constant, or 0 if not set. */ public long getLongValue() { Object value = getValue(); return (value == null) ? 0L : ((Number) value).longValue(); } /** * Return the float value of this constant, or 0 if not set. */ public float getFloatValue() { Object value = getValue(); return (value == null) ? 0F : ((Number) value).floatValue(); } /** * Return the double value of this constant, or 0 if not set. */ public double getDoubleValue() { Object value = getValue(); return (value == null) ? 0D : ((Number) value).doubleValue(); } /** * Return the class value of this constant, or null if not set. */ public String getClassNameValue() { return (String) getValue(); } /** * Set this constant to null. * * @return this instruction, for method chaining */ public ConstantInstruction setNull() { calculateOpcode(null, false, false); return this; } /** * Set the value of this constant. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(String value) { return setValue(value, false); } public ConstantInstruction setValue(String value, boolean clsName) { calculateOpcode(value, clsName, false); return this; } /** * Set the value of this constant. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(Class value) { if (value == null) return setNull(); calculateOpcode(value.getName(), true, false); return this; } /** * Set the value of this constant. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(BCClass value) { if (value == null) return setNull(); calculateOpcode(value.getName(), true, false); return this; } /** * Set the value of this constant. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(int value) { calculateOpcode(Numbers.valueOf(value), false, false); return this; } /** * Set the value of this constant. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(long value) { calculateOpcode(Numbers.valueOf(value), false, false); return this; } /** * Set the value of this constant. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(float value) { calculateOpcode(new Float(value), false, false); return this; } /** * Set the value of this constant. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(double value) { calculateOpcode(new Double(value), false, false); return this; } /** * Set the value of this constant; note that this type is converted to int. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(boolean value) { return setValue((value) ? 1 : 0); } /** * Set the value of this constant; note that this type is converted to int. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(short value) { return setValue((int) value); } /** * Set the value of this constant; note that this type is converted to int. * * @return this instruction, for method chaining */ public ConstantInstruction setValue(char value) { return setValue((int) value); } /** * ConstantInstructions are equal if the const they reference is the same, * or if the const of either is unset. */ public boolean equalsInstruction(Instruction other) { if (this == other) return true; if (!(other instanceof ConstantInstruction)) return false; ConstantInstruction ci = (ConstantInstruction) other; Object value = getValue(); Object otherValue = ci.getValue(); if (value == null || otherValue == null) return true; if (getTypeName() == null || ci.getTypeName() == null) return true; return value.equals(otherValue) && getTypeName().equals(ci.getTypeName()); } public void acceptVisit(BCVisitor visit) { visit.enterConstantInstruction(this); visit.exitConstantInstruction(this); } void read(Instruction orig) { super.read(orig); ConstantInstruction ci = (ConstantInstruction) orig; calculateOpcode(ci.getValue(), Class.class.getName().equals(ci.getTypeName()), ci.getOpcode() == Constants.LDCW); } void read(DataInput in) throws IOException { super.read(in); switch (getOpcode()) { case Constants.BIPUSH: case Constants.LDC: _arg = in.readUnsignedByte(); break; case Constants.SIPUSH: case Constants.LDCW: case Constants.LDC2W: _arg = in.readUnsignedShort(); } } void write(DataOutput out) throws IOException { super.write(out); switch (getOpcode()) { case Constants.BIPUSH: case Constants.LDC: out.writeByte(_arg); break; case Constants.SIPUSH: case Constants.LDCW: case Constants.LDC2W: out.writeShort(_arg); break; } } private void calculateOpcode(Object value, boolean clsName, boolean wide) { int len = getLength(); _arg = -1; if (value == null) setOpcode(Constants.ACONSTNULL); else if (clsName) { String name = getProject().getNameCache().getInternalForm((String) value, false); _arg = getPool().findClassEntry(name, true); setOpcode(Constants.LDCW); } else if (value instanceof Float) { float floatVal = ((Float) value).floatValue(); if ((floatVal == 0) || (floatVal == 1) || (floatVal == 2)) setOpcode(Constants.FCONST0 + (int) floatVal); else { _arg = getPool().findFloatEntry((float) floatVal, true); setOpcode((_arg > 255 || wide) ? Constants.LDCW : Constants.LDC); } } else if (value instanceof Long) { long longVal = ((Long) value).longValue(); if (longVal == 0 || longVal == 1) setOpcode(Constants.LCONST0 + (int) longVal); else { _arg = getPool().findLongEntry(longVal, true); setOpcode(Constants.LDC2W); } } else if (value instanceof Double) { double doubleVal = ((Double) value).doubleValue(); if (doubleVal == 0 || doubleVal == 1) setOpcode(Constants.DCONST0 + (int) doubleVal); else { _arg = getPool().findDoubleEntry(doubleVal, true); setOpcode(Constants.LDC2W); } } else if (value instanceof Integer) { int intVal = ((Integer) value).intValue(); if (intVal >= -1 && intVal <= 5) setOpcode(Constants.ICONST0 + intVal); else if ((intVal >= -(2 << 6)) && (intVal < (2 << 6))) { setOpcode(Constants.BIPUSH); _arg = intVal; } else if (intVal >= -(2 << 14) && intVal < (2 << 14)) { setOpcode(Constants.SIPUSH); _arg = intVal; } else { _arg = getPool().findIntEntry(intVal, true); setOpcode((_arg > 255 || wide) ? Constants.LDCW : Constants.LDC); } } else if (value instanceof String) { _arg = getPool().findStringEntry((String) value, true); setOpcode((_arg > 255 || wide) ? Constants.LDCW : Constants.LDC); } else throw new IllegalArgumentException(String.valueOf(value)); if (len != getLength()) invalidateByteIndexes(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/JumpInstruction.java0000755000000000000000000000556410637750727021652 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * An instruction that specifies a position in the code block to jump to. * Examples include go2, jsr, etc. * * @author Abe White */ public abstract class JumpInstruction extends Instruction implements InstructionPtr { private InstructionPtrStrategy _target = new InstructionPtrStrategy(this); JumpInstruction(Code owner, int opcode) { super(owner, opcode); } /** * Get the current target instruction to jump to, if it has been set. */ public Instruction getTarget() { return _target.getTargetInstruction(); } /** * Set the instruction to jump to; the instruction must already be * added to the code block. * * @return this instruction, for method chaining */ public JumpInstruction setTarget(Instruction instruction) { _target.setTargetInstruction(instruction); return this; } /** * JumpInstructions are equal if they represent the same operation and * the instruction they jump to is the * same, or if the jump Instruction of either is unset. */ public boolean equalsInstruction(Instruction other) { if (this == other) return true; if (!super.equalsInstruction(other)) return false; Instruction target = ((JumpInstruction) other).getTarget(); return target == null || getTarget() == null || target == getTarget(); } public void updateTargets() { _target.updateTargets(); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { _target.replaceTarget(oldTarget, newTarget); } public void acceptVisit(BCVisitor visit) { visit.enterJumpInstruction(this); visit.exitJumpInstruction(this); } void read(Instruction orig) { super.read(orig); _target.setByteIndex(((JumpInstruction) orig)._target.getByteIndex()); } void read(DataInput in) throws IOException { super.read(in); switch (getOpcode()) { case Constants.GOTOW: case Constants.JSRW: _target.setByteIndex(getByteIndex() + in.readInt()); break; default: _target.setByteIndex(getByteIndex() + in.readShort()); } } void write(DataOutput out) throws IOException { super.write(out); switch (getOpcode()) { case Constants.GOTOW: case Constants.JSRW: out.writeInt(_target.getByteIndex() - getByteIndex()); break; default: out.writeShort(_target.getByteIndex() - getByteIndex()); } } public void setOffset(int offset) { _target.setByteIndex(getByteIndex() + offset); } public int getOffset() { return _target.getByteIndex() - getByteIndex(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/ReturnInstruction.java0000755000000000000000000000473510460270414022175 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * Returns a value (or void) from a method. * * @author Abe White */ public class ReturnInstruction extends TypedInstruction { private static final Class[][] _mappings = new Class[][] { { byte.class, int.class }, { char.class, int.class }, { short.class, int.class }, { boolean.class, int.class }, }; ReturnInstruction(Code owner) { super(owner); } ReturnInstruction(Code owner, int opcode) { super(owner, opcode); } public String getTypeName() { switch (getOpcode()) { case Constants.IRETURN: return int.class.getName(); case Constants.LRETURN: return long.class.getName(); case Constants.FRETURN: return float.class.getName(); case Constants.DRETURN: return double.class.getName(); case Constants.ARETURN: return Object.class.getName(); case Constants.RETURN: return void.class.getName(); default: return null; } } public TypedInstruction setType(String type) { type = mapType(type, _mappings, true); if (type == null) return (TypedInstruction) setOpcode(Constants.NOP); switch (type.charAt(0)) { case 'i': return (TypedInstruction) setOpcode(Constants.IRETURN); case 'l': return (TypedInstruction) setOpcode(Constants.LRETURN); case 'f': return (TypedInstruction) setOpcode(Constants.FRETURN); case 'd': return (TypedInstruction) setOpcode(Constants.DRETURN); case 'v': return (TypedInstruction) setOpcode(Constants.RETURN); default: return (TypedInstruction) setOpcode(Constants.ARETURN); } } public int getLogicalStackChange() { switch (getOpcode()) { case Constants.NOP: return 0; default: return -1; } } public int getStackChange() { switch (getOpcode()) { case Constants.RETURN: case Constants.NOP: return 0; case Constants.LRETURN: case Constants.DRETURN: return -2; default: return -1; } } public void acceptVisit(BCVisitor visit) { visit.enterReturnInstruction(this); visit.exitReturnInstruction(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/MonitorEnterInstruction.java0000755000000000000000000000072510460270414023336 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.visitor.*; /** * The monitorenter instruction. * * @author Abe White */ public class MonitorEnterInstruction extends MonitorInstruction { MonitorEnterInstruction(Code owner) { super(owner, Constants.MONITORENTER); } public void acceptVisit(BCVisitor visit) { visit.enterMonitorEnterInstruction(this); visit.exitMonitorEnterInstruction(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/LineNumber.java0000755000000000000000000000616610460270414020514 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; /** * A line number corresponds to a sequence of opcodes that map logically * to a line of source code. * * @author Abe White */ public class LineNumber implements Comparable, InstructionPtr, BCEntity, VisitAcceptor { private int _line = 0; private LineNumberTable _owner = null; InstructionPtrStrategy _target = new InstructionPtrStrategy(this); LineNumber(LineNumberTable owner) { _owner = owner; } LineNumber(LineNumberTable owner, int startPc) { this(owner); setStartPc(startPc); } /** * Line numbers are stored in a {@link LineNumberTable}. */ public LineNumberTable getTable() { return _owner; } void invalidate() { _owner = null; } /** * Return source line number. */ public int getLine() { return _line; } /** * Set the source line number. */ public void setLine(int lineNumber) { _line = lineNumber; } /** * Return the instruction marking the beginning of this line. */ public Instruction getStart() { return _target.getTargetInstruction(); } /** * Return the index into the code byte array at which this line starts. */ public int getStartPc() { return _target.getByteIndex(); } /** * Set the index into the code byte array at which this line starts. */ public void setStartPc(int startPc) { _target.setByteIndex(startPc); } /** * Set the {@link Instruction} marking the beginning this line. * The instruction must already be a part of the method. */ public void setStart(Instruction instruction) { _target.setTargetInstruction(instruction); } public void updateTargets() { _target.updateTargets(); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { _target.replaceTarget(oldTarget, newTarget); } public Project getProject() { return _owner.getProject(); } public ConstantPool getPool() { return _owner.getPool(); } public ClassLoader getClassLoader() { return _owner.getClassLoader(); } public boolean isValid() { return _owner != null; } public void acceptVisit(BCVisitor visit) { visit.enterLineNumber(this); visit.exitLineNumber(this); } public int compareTo(Object other) { if (!(other instanceof LineNumber)) return -1; LineNumber ln = (LineNumber) other; if (getStartPc() == ln.getStartPc()) return 0; if (getStartPc() < ln.getStartPc()) return -1; return 1; } void read(DataInput in) throws IOException { setStartPc(in.readUnsignedShort()); setLine(in.readUnsignedShort()); } void write(DataOutput out) throws IOException { out.writeShort(getStartPc()); out.writeShort(getLine()); } public Code getCode() { return _owner.getCode(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/LocalVariable.java0000755000000000000000000000315310460270414021145 0ustar package serp.bytecode; import serp.bytecode.visitor.*; import serp.util.*; /** * A local variable contains the name, description, index and scope * of a local used in opcodes. * * @author Abe White */ public class LocalVariable extends Local { LocalVariable(LocalVariableTable owner) { super(owner); } /** * The owning table. */ public LocalVariableTable getLocalVariableTable() { return (LocalVariableTable) getTable(); } /** * Return the type of this local. * If the type has not been set, this method will return null. */ public Class getType() { String type = getTypeName(); if (type == null) return null; return Strings.toClass(type, getClassLoader()); } /** * Return the type of this local. * If the type has not been set, this method will return null. */ public BCClass getTypeBC() { String type = getTypeName(); if (type == null) return null; return getProject().loadClass(type, getClassLoader()); } /** * Set the type of this local. */ public void setType(Class type) { if (type == null) setType((String) null); else setType(type.getName()); } /** * Set the type of this local. */ public void setType(BCClass type) { if (type == null) setType((String) null); else setType(type.getName()); } public void acceptVisit(BCVisitor visit) { visit.enterLocalVariable(this); visit.exitLocalVariable(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/State.java0000755000000000000000000001212310660077275017536 0ustar package serp.bytecode; import java.util.*; import serp.bytecode.lowlevel.*; /** * The State type is extended by various concrete types to change * the behavior of a {@link BCClass}. All methods in this base * implementation throw an {@link UnsupportedOperationException} * * @author Abe White */ class State { /** * A singleton instance of this type that can be used to make a * class invalid. */ public static final State INVALID = new State(); /** * Return the magic number of the bytecode class. */ public int getMagic() { throw new UnsupportedOperationException(); } /** * Set the magic number of the bytecode class. */ public void setMagic(int magic) { throw new UnsupportedOperationException(); } /** * Return the major number of the bytecode class. */ public int getMajorVersion() { throw new UnsupportedOperationException(); } /** * Set the major version of the bytecode class. */ public void setMajorVersion(int major) { throw new UnsupportedOperationException(); } /** * Return the minor number of the bytecode class. */ public int getMinorVersion() { throw new UnsupportedOperationException(); } /** * Set the minor version of the bytecode class. */ public void setMinorVersion(int minor) { throw new UnsupportedOperationException(); } /** * Return the access flags of the bytecode class. */ public int getAccessFlags() { throw new UnsupportedOperationException(); } /** * Set the access flags of the bytecode class. */ public void setAccessFlags(int access) { throw new UnsupportedOperationException(); } /** * Return the {@link ConstantPool} index of the {@link ClassEntry} * for this class, or 0 if none. */ public int getIndex() { throw new UnsupportedOperationException(); } /** * Set the {@link ConstantPool} index of the {@link ClassEntry} * for this class. */ public void setIndex(int index) { throw new UnsupportedOperationException(); } /** * Return the {@link ConstantPool} index of the {@link ClassEntry} * for the superclass of this class, or 0 if none. */ public int getSuperclassIndex() { throw new UnsupportedOperationException(); } /** * Set the {@link ConstantPool} index of the {@link ClassEntry} * for the superclass of this class. Throws * {@link UnsupportedOperationException} by default. */ public void setSuperclassIndex(int index) { throw new UnsupportedOperationException(); } /** * Return the {@link ConstantPool} indexes of the {@link ClassEntry}s * for the indexes of this class, or empty list if none. If the * state does not support changing the interfaces, the returned * list should be immutable. */ public List getInterfacesHolder() { throw new UnsupportedOperationException(); } /** * Return the {@link BCField}s of this class, or empty list if none. * If the state does not support changing the fields, the returned * list should be immutable. */ public List getFieldsHolder() { throw new UnsupportedOperationException(); } /** * Return the {@link BCMethod}s of this class, or empty list if none. * If the state does not support changing the methods, the returned * list should be immutable. */ public List getMethodsHolder() { throw new UnsupportedOperationException(); } /** * Return the {@link Attribute}s of this class, or empty list if * none. If the state does not support changing the attributes, the * returned list should be immutable. */ public Collection getAttributesHolder() { throw new UnsupportedOperationException(); } /** * Return the constant pool of the class. */ public ConstantPool getPool() { throw new UnsupportedOperationException(); } /** * Return the name of the class. The name should be in a form suitable * for a {@link Class#forName} call. */ public String getName() { throw new UnsupportedOperationException(); } /** * Return the name of the superclass. The name should be in a form * suitable for a {@link Class#forName} call, or null if none. */ public String getSuperclassName() { throw new UnsupportedOperationException(); } /** * Return the name of the component type of this array, or null if not * an array. The name should be in a form suitable for a * {@link Class#forName} call. */ public String getComponentName() { throw new UnsupportedOperationException(); } /** * Return true if this class is a primitive. */ public boolean isPrimitive() { throw new UnsupportedOperationException(); } /** * Return true if this class is an array. */ public boolean isArray() { throw new UnsupportedOperationException(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/GetFieldInstruction.java0000755000000000000000000000164210460270414022373 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * Loads a value from a field onto the stack. * * @author Abe White */ public class GetFieldInstruction extends FieldInstruction { GetFieldInstruction(Code owner, int opcode) { super(owner, opcode); } public int getLogicalStackChange() { if (getOpcode() == Constants.GETSTATIC) return 1; return 0; } public int getStackChange() { String type = getFieldTypeName(); if (type == null) return 0; int stack = 0; if (long.class.getName().equals(type) || double.class.getName().equals(type)) stack++; if (getOpcode() == Constants.GETSTATIC) stack++; return stack; } public void acceptVisit(BCVisitor visit) { visit.enterGetFieldInstruction(this); visit.exitGetFieldInstruction(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/LocalVariableInstruction.java0000755000000000000000000001022310460270414023403 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * An instruction that has an argument of an index into the * local variable table of the current frame. This includes most of the * load and store instructions. * *

The local variable table size is fixed by the maxLocals * property of the code block. Long and double types take up 2 local variable * indexes.

* *

Parameter values to methods are loaded into the local variable table * prior to the execution of the first instruction. The 0 index of the * table is set to the instance of the class the method is being invoked on.

* * @author Abe White */ public abstract class LocalVariableInstruction extends TypedInstruction { private int _index = -1; LocalVariableInstruction(Code owner) { super(owner); } LocalVariableInstruction(Code owner, int opcode) { super(owner, opcode); calculateLocal(); } public String getTypeName() { return null; } public TypedInstruction setType(String type) { throw new UnsupportedOperationException(); } /** * Return the index of the local variable that this instruction operates on. */ public int getLocal() { return _index; } /** * Set the index of the local variable that this instruction operates on. * * @return this instruction, for method chaining */ public LocalVariableInstruction setLocal(int index) { _index = index; calculateOpcode(); return this; } /** * Return the parameter that this instruction operates on, or -1 if none. */ public int getParam() { return getCode().getParamsIndex(getLocal()); } /** * Set the method parameter that this instruction operates on. This * will set both the local index and the type of the instruction based * on the current method parameters. */ public LocalVariableInstruction setParam(int param) { int local = getCode().getLocalsIndex(param); if (local != -1) { BCMethod method = getCode().getMethod(); setType(method.getParamNames()[param]); } return setLocal(local); } /** * Return the local variable object this instruction * operates on, or null if none. * * @see LocalVariableTable#getLocalVariable(int) */ public LocalVariable getLocalVariable() { LocalVariableTable table = getCode().getLocalVariableTable(false); if (table == null) return null; return table.getLocalVariable(getLocal()); } /** * Set the local variable object this instruction * operates on. This method will set both the type and local index * of this instruction from the given local variable. * * @return this instruction, for method chaining */ public LocalVariableInstruction setLocalVariable(LocalVariable local) { if (local == null) return setLocal(-1); String type = local.getTypeName(); if (type != null) setType(type); return setLocal(local.getLocal()); } /** * Two local variable instructions are equal if the local index they * reference is equal or if either index is 0/unset. */ public boolean equalsInstruction(Instruction other) { if (this == other) return true; if (!getClass().equals(other.getClass())) return false; LocalVariableInstruction ins = (LocalVariableInstruction) other; int index = getLocal(); int insIndex = ins.getLocal(); return index == -1 || insIndex == -1 || index == insIndex; } void read(Instruction orig) { super.read(orig); setLocal(((LocalVariableInstruction) orig).getLocal()); } /** * Subclasses with variable opcodes can use this method to be * notified that information possibly affecting the opcode has been changed. */ void calculateOpcode() { } /** * Subclasses can use this method to calculate * the locals index based on their opcode. */ void calculateLocal() { } } serp-1.14.1.orig/src/main/java/serp/bytecode/BCMethod.java0000755000000000000000000003147710517502266020112 0ustar package serp.bytecode; import serp.bytecode.visitor.*; import serp.util.*; /** * A method of a class. * * @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); } /** * Manipulate the method access flags. */ public boolean isVarArgs() { return (getAccessFlags() & Constants.ACCESS_VARARGS) > 0; } /** * Manipulate the method access flags. */ public void setVarArgs(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_VARARGS); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_VARARGS); } /** * Manipulate the method access flags. */ public boolean isBridge() { return (getAccessFlags() & Constants.ACCESS_BRIDGE) > 0; } /** * Manipulate the method access flags. */ public void setBridge(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_BRIDGE); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_BRIDGE); } ///////////////////// // Return operations ///////////////////// /** * Return the name of the type returned by this method. The name * will be given in a form suitable for a {@link Class#forName} call. * * @see BCMember#getDescriptor */ public String getReturnName() { return getProject().getNameCache().getExternalForm(getProject(). getNameCache().getDescriptorReturnName(getDescriptor()), false); } /** * Return the {@link 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 {@link 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 {@link 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 {@link 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 * add 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 {@link 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 {@link 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 * add 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 {@link 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(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/InstructionPtrStrategy.java0000755000000000000000000000606710640272105023205 0ustar package serp.bytecode; /** * InstructionPtrStrategy handles the different strategies for finding the * Instructions that InstructionPtrs point to. These strategies include, * from least desirable to most desirable, using byte indexes, * and storing a reference to the target Instruction proper. * * @author Eric Lindauer * @date 2002.7.26 */ class InstructionPtrStrategy implements InstructionPtr { // the Instruction doing the targetting private InstructionPtr _pointer; // two different ways to find the target from the pointer. // _target is used first, then _byteIndex private Instruction _target = null; private int _byteIndex = -1; public InstructionPtrStrategy(InstructionPtr pointer) { _pointer = pointer; } public InstructionPtrStrategy(InstructionPtr pointer, Instruction target) { this(pointer); setTargetInstruction(target); } /** * Sets the byteIndex where the target Instruction can be found. * This target will now be using byte indices as its target finding * strategy, which is the least robust option. Changing the Code block * or importing it into another Method may result in an invalid target. */ public void setByteIndex(int index) { if (index < -1) throw new IllegalArgumentException(String.valueOf(index)); _byteIndex = index; _target = null; } /** * Changes the target Instruction. The target is in the best state * possible and should maintain this information even in the face * of Code imports and Code changes. */ public void setTargetInstruction(Instruction ins) { if (ins.getCode() != getCode()) throw new IllegalArgumentException("Instruction pointers and " + "targets must be part of the same code block."); _target = ins; _byteIndex = -1; } /** * Returns the Instruction this Target is targetting. This request * does not change the targetting strategy for this Target. */ public Instruction getTargetInstruction() { if (_target != null) return _target; return getCode().getInstruction(_byteIndex); } /** * Returns the byteIndex at which the target instruction can be found. * This call does not change the Target strategy. */ public int getByteIndex() { if (_target == null) return _byteIndex; return _target.getByteIndex(); } /** * Same as getInstruction, but this method alters the Target strategy * to use the returned Instruction. This method alters the Target * strategy (and Instruction) iff it was previously using byte indexes. */ public void updateTargets() { if (_target == null) _target = getCode().getInstruction(_byteIndex); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { if (getTargetInstruction() == oldTarget) setTargetInstruction(newTarget); } public Code getCode() { return _pointer.getCode(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/MultiANewArrayInstruction.java0000755000000000000000000000405210637750727023572 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.visitor.*; /** * The multianewarray instruction, which creates a new * multi-dimensional array. * * @author Abe White */ public class MultiANewArrayInstruction extends ClassInstruction { private int _dims = -1; MultiANewArrayInstruction(Code owner) { super(owner, Constants.MULTIANEWARRAY); } int getLength() { return super.getLength() + 1; } public int getStackChange() { return -_dims + 1; } /** * Return the dimensions of the array, or -1 if not set. */ public int getDimensions() { return _dims; } /** * Set the dimensions of the array. * * @return this instruction, for method chaining */ public MultiANewArrayInstruction setDimensions(int dims) { _dims = dims; return this; } /** * Two MultiANewArray instructions are equal if they have the same * type and dimensions, or if the type and dimensions of either is unset. */ public boolean equalsInstruction(Instruction other) { if (other == this) return true; if (!(other instanceof MultiANewArrayInstruction)) return false; if (!super.equalsInstruction(other)) return false; MultiANewArrayInstruction ins = (MultiANewArrayInstruction) other; int dims = getDimensions(); int otherDims = ins.getDimensions(); return dims == -1 || otherDims == -1 || dims == otherDims; } public void acceptVisit(BCVisitor visit) { visit.enterMultiANewArrayInstruction(this); visit.exitMultiANewArrayInstruction(this); } void read(Instruction orig) { super.read(orig); _dims = ((MultiANewArrayInstruction) orig).getDimensions(); } void read(DataInput in) throws IOException { super.read(in); _dims = in.readUnsignedByte(); } void write(DataOutput out) throws IOException { super.write(out); out.writeByte(_dims); } } serp-1.14.1.orig/src/main/java/serp/bytecode/NewArrayInstruction.java0000755000000000000000000000715410637750727022464 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * The newarray instruction, which is used to create new * arrays of primitive types. * * @author Abe White */ public class NewArrayInstruction extends TypedInstruction { private static final Class[][] _mappings = new Class[][] { { void.class, int.class }, { Object.class, int.class }, }; private int _code = -1; NewArrayInstruction(Code owner) { super(owner, Constants.NEWARRAY); } int getLength() { return super.getLength() + 1; } public String getTypeName() { switch (getTypeCode()) { case Constants.ARRAY_BOOLEAN: return boolean.class.getName(); case Constants.ARRAY_CHAR: return char.class.getName(); case Constants.ARRAY_FLOAT: return float.class.getName(); case Constants.ARRAY_DOUBLE: return double.class.getName(); case Constants.ARRAY_BYTE: return byte.class.getName(); case Constants.ARRAY_SHORT: return short.class.getName(); case Constants.ARRAY_INT: return int.class.getName(); case Constants.ARRAY_LONG: return long.class.getName(); default: return null; } } public TypedInstruction setType(String type) { type = mapType(type, _mappings, true); if (type == null) return setTypeCode(-1); switch (type.charAt(0)) { case 'b': if (boolean.class.getName().equals(type)) return setTypeCode(Constants.ARRAY_BOOLEAN); return setTypeCode(Constants.ARRAY_BYTE); case 'c': return setTypeCode(Constants.ARRAY_CHAR); case 'f': return setTypeCode(Constants.ARRAY_FLOAT); case 'd': return setTypeCode(Constants.ARRAY_DOUBLE); case 's': return setTypeCode(Constants.ARRAY_SHORT); case 'i': return setTypeCode(Constants.ARRAY_INT); case 'l': return setTypeCode(Constants.ARRAY_LONG); default: throw new IllegalStateException(); } } /** * Return the array code used in the lowlevel bytecode, or -1 if unset. */ public int getTypeCode() { return _code; } /** * Set the array code used in the lowlevel bytecode. * * @return this instruction, for method chaining */ public NewArrayInstruction setTypeCode(int code) { _code = code; return this; } /** * NewArray instructions are equal if the array type is the same, * of if the array type of either is unset. */ public boolean equalsInstruction(Instruction other) { if (this == other) return true; if (!(other instanceof NewArrayInstruction)) return false; NewArrayInstruction ins = (NewArrayInstruction) other; int code = getTypeCode(); int otherCode = ins.getTypeCode(); return code == -1 || otherCode == -1 || code == otherCode; } public void acceptVisit(BCVisitor visit) { visit.enterNewArrayInstruction(this); visit.exitNewArrayInstruction(this); } void read(Instruction orig) { super.read(orig); _code = ((NewArrayInstruction) orig).getTypeCode(); } void read(DataInput in) throws IOException { super.read(in); _code = in.readUnsignedByte(); } void write(DataOutput out) throws IOException { super.write(out); out.writeByte(_code); } } serp-1.14.1.orig/src/main/java/serp/bytecode/CmpInstruction.java0000755000000000000000000001042310460270414021424 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * An instruction comparing two stack values. Examples include * lcmp, fcmpl, etc. * * @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); } } serp-1.14.1.orig/src/main/java/serp/bytecode/ObjectState.java0000755000000000000000000000523210660077275020670 0ustar package serp.bytecode; import java.util.*; import serp.bytecode.lowlevel.*; /** * State implementing the behavior of an object type. * * @author Abe White */ class ObjectState extends State { private final ConstantPool _pool = new ConstantPool(); private final NameCache _names; private int _index = 0; private int _superclassIndex = 0; private int _magic = Constants.VALID_MAGIC; private int _major = Constants.MAJOR_VERSION; private int _minor = Constants.MINOR_VERSION; private int _access = Constants.ACCESS_PUBLIC | Constants.ACCESS_SUPER; private final List _interfaces = new ArrayList(); private final List _fields = new ArrayList(); private final List _methods = new ArrayList(); private final List _attributes = new ArrayList(); public ObjectState(NameCache names) { _names = names; } public int getMagic() { return _magic; } public void setMagic(int magic) { _magic = magic; } public int getMajorVersion() { return _major; } public void setMajorVersion(int major) { _major = major; } public int getMinorVersion() { return _minor; } public void setMinorVersion(int minor) { _minor = minor; } public int getAccessFlags() { return _access; } public void setAccessFlags(int access) { _access = access; } public int getIndex() { return _index; } public void setIndex(int index) { _index = index; } public int getSuperclassIndex() { return _superclassIndex; } public void setSuperclassIndex(int index) { _superclassIndex = index; } public List getInterfacesHolder() { return _interfaces; } public List getFieldsHolder() { return _fields; } public List getMethodsHolder() { return _methods; } public Collection getAttributesHolder() { return _attributes; } public ConstantPool getPool() { return _pool; } public String getName() { if (_index == 0) return null; return _names.getExternalForm(((ClassEntry) _pool.getEntry(_index)). getNameEntry().getValue(), false); } public String getSuperclassName() { if (_superclassIndex == 0) return null; return _names.getExternalForm(((ClassEntry) _pool.getEntry (_superclassIndex)).getNameEntry().getValue(), false); } public String getComponentName() { return null; } public boolean isPrimitive() { return false; } public boolean isArray() { return false; } } serp-1.14.1.orig/src/main/java/serp/bytecode/ExceptionHandler.java0000755000000000000000000001735610460270414021713 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * Represents a try {} catch() {} statement in bytecode. * * @author Abe White */ public class ExceptionHandler implements InstructionPtr, BCEntity, VisitAcceptor { private int _catchIndex = 0; private Code _owner = null; private InstructionPtrStrategy _tryStart = new InstructionPtrStrategy(this); private InstructionPtrStrategy _tryEnd = new InstructionPtrStrategy(this); private InstructionPtrStrategy _tryHandler = new InstructionPtrStrategy (this); ExceptionHandler(Code owner) { _owner = owner; } /** * Return the owning code block. */ public Code getCode() { return _owner; } /////////////////// // Body operations /////////////////// /** * Return the instruction marking the beginning of the try {} block. */ public Instruction getTryStart() { return _tryStart.getTargetInstruction(); } /** * Set the {@link Instruction} marking the beginning of the try block. * The instruction must already be a part of the method. */ public void setTryStart(Instruction instruction) { _tryStart.setTargetInstruction(instruction); } /** * Return the instruction at the end of the try {} block. */ public Instruction getTryEnd() { return _tryEnd.getTargetInstruction(); } /** * Set the Instruction at the end of the try block. The * Instruction must already be a part of the method. */ public void setTryEnd(Instruction instruction) { _tryEnd.setTargetInstruction(instruction); } ////////////////////// // Handler operations ////////////////////// /** * Return the instruction marking the beginning of the catch {} block. */ public Instruction getHandlerStart() { return _tryHandler.getTargetInstruction(); } /** * Set the {@link Instruction} marking the beginning of the catch block. * The instruction must already be a part of the method. * WARNING: if this instruction is deleted, the results are undefined. */ public void setHandlerStart(Instruction instruction) { _tryHandler.setTargetInstruction(instruction); } //////////////////// // Catch operations //////////////////// /** * Return the index into the class {@link ConstantPool} of the * {@link ClassEntry} describing the exception type this handler catches. */ public int getCatchIndex() { return _catchIndex; } /** * Set the index into the class {@link ConstantPool} of the * {@link ClassEntry} describing the exception type this handler catches. */ public void setCatchIndex(int catchTypeIndex) { _catchIndex = catchTypeIndex; } /** * Return the name of the exception type; returns null for catch-all * clauses used to implement finally blocks. The name will be returned * in a forum suitable for a {@link Class#forName} call. */ public String getCatchName() { if (_catchIndex == 0) return null; ClassEntry entry = (ClassEntry) getPool().getEntry(_catchIndex); return getProject().getNameCache().getExternalForm(entry.getNameEntry(). getValue(), false); } /** * Return the {@link Class} of the exception type; returns null for * catch-all clauses used to implement finally blocks. */ public Class getCatchType() { String name = getCatchName(); if (name == null) return null; return Strings.toClass(name, getClassLoader()); } /** * Return the bytecode of the exception type; returns null for * catch-all clauses used to implement finally blocks. */ public BCClass getCatchBC() { String name = getCatchName(); if (name == null) return null; return getProject().loadClass(name, getClassLoader()); } /** * Set the class of the exception type, or null for catch-all clauses used * with finally blocks. */ public void setCatch(String name) { if (name == null) _catchIndex = 0; else _catchIndex = getPool().findClassEntry(getProject().getNameCache(). getInternalForm(name, false), true); } /** * Set the class of the exception type, or null for catch-all clauses used * for finally blocks. */ public void setCatch(Class type) { if (type == null) setCatch((String) null); else setCatch(type.getName()); } /** * Set the class of the exception type, or null for catch-all clauses used * for finally blocks. */ public void setCatch(BCClass type) { if (type == null) setCatch((String) null); else setCatch(type.getName()); } ///////////////////////////////// // InstructionPtr implementation ///////////////////////////////// public void updateTargets() { _tryStart.updateTargets(); _tryEnd.updateTargets(); _tryHandler.updateTargets(); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { _tryStart.replaceTarget(oldTarget, newTarget); _tryEnd.replaceTarget(oldTarget, newTarget); _tryHandler.replaceTarget(oldTarget, newTarget); } /////////////////////////// // BCEntity implementation /////////////////////////// public Project getProject() { return _owner.getProject(); } public ConstantPool getPool() { return _owner.getPool(); } public ClassLoader getClassLoader() { return _owner.getClassLoader(); } public boolean isValid() { return _owner != null; } //////////////////////////////// // VisitAcceptor implementation //////////////////////////////// public void acceptVisit(BCVisitor visit) { visit.enterExceptionHandler(this); visit.exitExceptionHandler(this); } ////////////////// // I/O operations ////////////////// void read(ExceptionHandler orig) { _tryStart.setByteIndex(orig._tryStart.getByteIndex()); _tryEnd.setByteIndex(orig._tryEnd.getByteIndex()); _tryHandler.setByteIndex(orig._tryHandler.getByteIndex()); // done at a high level so that if the name isn't in our constant pool, // it will be added setCatch(orig.getCatchName()); } void read(DataInput in) throws IOException { setTryStart(in.readUnsignedShort()); setTryEnd(in.readUnsignedShort()); setHandlerStart(in.readUnsignedShort()); setCatchIndex(in.readUnsignedShort()); } void write(DataOutput out) throws IOException { out.writeShort(getTryStartPc()); out.writeShort(getTryEndPc()); out.writeShort(getHandlerStartPc()); out.writeShort(getCatchIndex()); } public void setTryStart(int start) { _tryStart.setByteIndex(start); } public int getTryStartPc() { return _tryStart.getByteIndex(); } public void setTryEnd(int end) { setTryEnd((Instruction) _owner.getInstruction(end).prev); } /** * Return the program counter end position for this exception handler. * This represents an index into the code byte array. */ public int getTryEndPc() { return _tryEnd.getByteIndex() + getTryEnd().getLength(); } public void setHandlerStart(int handler) { _tryHandler.setByteIndex(handler); } public int getHandlerStartPc() { return _tryHandler.getByteIndex(); } void invalidate() { _owner = null; } } serp-1.14.1.orig/src/main/java/serp/bytecode/PutFieldInstruction.java0000755000000000000000000000174410460270414022427 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * Stores a value from the stack into a field. * * @author Abe White */ public class PutFieldInstruction extends FieldInstruction { PutFieldInstruction(Code owner, int opcode) { super(owner, opcode); } public int getLogicalStackChange() { if (getFieldTypeName() == null) return 0; if (getOpcode() == Constants.PUTSTATIC) return -1; return -2; } public int getStackChange() { String type = getFieldTypeName(); if (type == null) return 0; int stack = -2; if (long.class.getName().equals(type) || double.class.getName().equals(type)) stack++; if (getOpcode() == Constants.PUTSTATIC) stack++; return stack; } public void acceptVisit(BCVisitor visit) { visit.enterPutFieldInstruction(this); visit.exitPutFieldInstruction(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/CodeEntry.java0000755000000000000000000000026710637750727020364 0ustar package serp.bytecode; /** * An entry in a code block. * * @author Abe White */ class CodeEntry { CodeEntry next = null; CodeEntry prev = null; int byteIndex = -1; } serp-1.14.1.orig/src/main/java/serp/bytecode/ArrayInstruction.java0000755000000000000000000000073210460270414021765 0ustar package serp.bytecode; /** * Any array load or store instruction. This class has * no functionality beyond the {@link TypedInstruction} but is provided * so that users can easily identify array instructions in code if need be. * * @author Abe White */ public abstract class ArrayInstruction extends TypedInstruction { ArrayInstruction(Code owner) { super(owner); } ArrayInstruction(Code owner, int opcode) { super(owner, opcode); } } serp-1.14.1.orig/src/main/java/serp/bytecode/InnerClasses.java0000755000000000000000000001452110460270414021037 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * Attribute describing all referenced classes that are not package * members. This includes all member interfaces and classes. * * @author Abe White */ public class InnerClasses extends Attribute { private List _innerClasses = new LinkedList(); InnerClasses(int nameIndex, Attributes owner) { super(nameIndex, owner); } /** * Return all referenced inner classes, or empty array if none. */ public InnerClass[] getInnerClasses() { return (InnerClass[]) _innerClasses.toArray (new InnerClass[_innerClasses.size()]); } /** * Return the inner class with the given name. If multiple inner classes * share the name, which is returned is undefined. Use null to retrieve * anonymous classes. */ public InnerClass getInnerClass(String name) { InnerClass[] inners = getInnerClasses(); String inner; for (int i = 0; i < inners.length; i++) { inner = inners[i].getName(); if ((inner == null && name == null) || (inner != null && inner.equals(name))) return inners[i]; } return null; } /** * Return all inner classes with the given name, or empty array if none. * Use null to retrieve anonymous classes. */ public InnerClass[] getInnerClasses(String name) { List matches = new LinkedList(); InnerClass[] inners = getInnerClasses(); String inner; for (int i = 0; i < inners.length; i++) { inner = inners[i].getName(); if ((inner == null && name == null) || (inner != null && inner.equals(name))) matches.add(inners[i]); } return (InnerClass[]) matches.toArray(new InnerClass[matches.size()]); } /** * Set the inner class references for this class. This method is * useful when importing inner class references from another class. */ public void setInnerClasses(InnerClass[] inners) { clear(); if (inners != null) for (int i = 0; i < inners.length; i++) addInnerClass(inners[i]); } /** * Import an inner class from another entity, or make a copy of one * on this entity. * * @return the newly added inner class */ public InnerClass addInnerClass(InnerClass inner) { InnerClass newInner = addInnerClass(inner.getName(), inner.getTypeName(), inner.getDeclarerName()); newInner.setAccessFlags(inner.getAccessFlags()); return newInner; } /** * Add an inner class. */ public InnerClass addInnerClass() { InnerClass inner = new InnerClass(this); _innerClasses.add(inner); return inner; } /** * Add an inner class. * * @param name the simple name of the class, or null if anonymous * @param type the full class name of the inner class * @param owner the declaring class, or null if not a member class */ public InnerClass addInnerClass(String name, String type, String owner) { InnerClass inner = addInnerClass(); inner.setName(name); inner.setType(type); inner.setDeclarer(owner); return inner; } /** * Add an inner class. * * @param name the simple name of the class, or null if anonymous * @param type the class of the inner class * @param owner the declaring class, or null if not a member class */ public InnerClass addInnerClass(String name, Class type, Class owner) { String typeName = (type == null) ? null : type.getName(); String ownerName = (owner == null) ? null : owner.getName(); return addInnerClass(name, typeName, ownerName); } /** * Add an inner class. * * @param name the simple name of the class, or null if anonymous * @param type the class of the inner class * @param owner the declaring class, or null if not a member class */ public InnerClass addInnerClass(String name, BCClass type, BCClass owner) { String typeName = (type == null) ? null : type.getName(); String ownerName = (owner == null) ? null : owner.getName(); return addInnerClass(name, typeName, ownerName); } /** * Clear all inner classes from this entity. */ public void clear() { InnerClass inner; for (Iterator itr = _innerClasses.iterator(); itr.hasNext();) { inner = (InnerClass) itr.next(); itr.remove(); inner.invalidate(); } } /** * Remove the inner class with the given name. Use null for anonymous * classes. * * @return true if an inner class was removed, false otherwise */ public boolean removeInnerClass(String name) { return removeInnerClass(getInnerClass(name)); } /** * Remove the given inner class. After being removed, the given inner * class is invalid, and the result of any operations on it are undefined. * * @return true if the inner class was removed, false otherwise */ public boolean removeInnerClass(InnerClass innerClass) { if (innerClass == null || !_innerClasses.remove(innerClass)) return false; innerClass.invalidate(); return true; } public void acceptVisit(BCVisitor visit) { visit.enterInnerClasses(this); InnerClass[] inners = getInnerClasses(); for (int i = 0; i < inners.length; i++) inners[i].acceptVisit(visit); visit.exitInnerClasses(this); } int getLength() { return 2 + (8 * _innerClasses.size()); } void read(Attribute other) { setInnerClasses(((InnerClasses) other).getInnerClasses()); } void read(DataInput in, int length) throws IOException { clear(); int numInnerClasses = in.readUnsignedShort(); InnerClass innerClass; for (int i = 0; i < numInnerClasses; i++) { innerClass = addInnerClass(); innerClass.read(in); } } void write(DataOutput out, int length) throws IOException { InnerClass[] inners = getInnerClasses(); out.writeShort(inners.length); for (int i = 0; i < inners.length; i++) inners[i].write(out); } } serp-1.14.1.orig/src/main/java/serp/bytecode/ArrayLoadInstruction.java0000755000000000000000000000517210460270414022570 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * Loads a value from an array onto the stack. * * @author Abe White */ public class ArrayLoadInstruction extends ArrayInstruction { private static final Class[][] _mappings = new Class[][] { { boolean.class, int.class }, { void.class, int.class }, }; ArrayLoadInstruction(Code owner) { super(owner); } ArrayLoadInstruction(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.DALOAD: case Constants.LALOAD: case Constants.NOP: return 0; default: return -1; } } public String getTypeName() { switch (getOpcode()) { case Constants.IALOAD: return int.class.getName(); case Constants.LALOAD: return long.class.getName(); case Constants.FALOAD: return float.class.getName(); case Constants.DALOAD: return double.class.getName(); case Constants.AALOAD: return Object.class.getName(); case Constants.BALOAD: return byte.class.getName(); case Constants.CALOAD: return char.class.getName(); case Constants.SALOAD: return short.class.getName(); default: return null; } } public TypedInstruction setType(String type) { type = mapType(type, _mappings, true); if (type == null) return (TypedInstruction) setOpcode(Constants.NOP); switch (type.charAt(0)) { case 'i': return (TypedInstruction) setOpcode(Constants.IALOAD); case 'l': return (TypedInstruction) setOpcode(Constants.LALOAD); case 'f': return (TypedInstruction) setOpcode(Constants.FALOAD); case 'd': return (TypedInstruction) setOpcode(Constants.DALOAD); case 'b': return (TypedInstruction) setOpcode(Constants.BALOAD); case 'c': return (TypedInstruction) setOpcode(Constants.CALOAD); case 's': return (TypedInstruction) setOpcode(Constants.SALOAD); default: return (TypedInstruction) setOpcode(Constants.AALOAD); } } public void acceptVisit(BCVisitor visit) { visit.enterArrayLoadInstruction(this); visit.exitArrayLoadInstruction(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/Constants.java0000755000000000000000000003357710620672122020436 0ustar package serp.bytecode; /** * Interface to track constants used in bytecode. Entities can access these * constants using the static Constants. field prefix, * or implement this interface themselves to conveniently import the * constants into their own namespace. * * @author Abe White */ public interface Constants { // class magic number public static final int VALID_MAGIC = 0xcafebabe; // standard major, minor versions public static final int MAJOR_VERSION = 45; public static final int MINOR_VERSION = 3; public static final int MAJOR_VERSION_JAVA5 = 49; public static final int MINOR_VERSION_JAVA5 = 0; // access constants for classes, fields, methods public static final int ACCESS_PUBLIC = 0x0001; public static final int ACCESS_PRIVATE = 0x0002; public static final int ACCESS_PROTECTED = 0x0004; public static final int ACCESS_STATIC = 0x0008; public static final int ACCESS_FINAL = 0x0010; public static final int ACCESS_SUPER = 0x0020; public static final int ACCESS_SYNCHRONIZED = 0x0020; public static final int ACCESS_VOLATILE = 0x0040; public static final int ACCESS_BRIDGE = 0x0040; public static final int ACCESS_TRANSIENT = 0x0080; public static final int ACCESS_VARARGS = 0x0080; public static final int ACCESS_NATIVE = 0x0100; public static final int ACCESS_INTERFACE = 0x0200; public static final int ACCESS_ABSTRACT = 0x0400; public static final int ACCESS_STRICT = 0x0800; public static final int ACCESS_SYNTHETIC = 0x1000; public static final int ACCESS_ANNOTATION = 0x2000; public static final int ACCESS_ENUM = 0x4000; // attribute types the compiler must support public static final String ATTR_CODE = "Code"; public static final String ATTR_CONST = "ConstantValue"; public static final String ATTR_DEPRECATED = "Deprecated"; public static final String ATTR_EXCEPTIONS = "Exceptions"; public static final String ATTR_INNERCLASS = "InnerClasses"; public static final String ATTR_LINENUMBERS = "LineNumberTable"; public static final String ATTR_LOCALS = "LocalVariableTable"; public static final String ATTR_LOCAL_TYPES = "LocalVariableTypeTable"; public static final String ATTR_SOURCE = "SourceFile"; public static final String ATTR_SYNTHETIC = "Synthetic"; public static final String ATTR_UNKNOWN = "Unknown"; public static final String ATTR_ANNOTATIONS = "RuntimeInvisibleAnnotations"; public static final String ATTR_RUNTIME_ANNOTATIONS = "RuntimeVisibleAnnotations"; // opcodes public static final int NOP = 0; public static final int ACONSTNULL = 1; public static final int ICONSTM1 = 2; public static final int ICONST0 = 3; public static final int ICONST1 = 4; public static final int ICONST2 = 5; public static final int ICONST3 = 6; public static final int ICONST4 = 7; public static final int ICONST5 = 8; public static final int LCONST0 = 9; public static final int LCONST1 = 10; public static final int FCONST0 = 11; public static final int FCONST1 = 12; public static final int FCONST2 = 13; public static final int DCONST0 = 14; public static final int DCONST1 = 15; public static final int BIPUSH = 16; public static final int SIPUSH = 17; public static final int LDC = 18; public static final int LDCW = 19; public static final int LDC2W = 20; public static final int ILOAD = 21; public static final int LLOAD = 22; public static final int FLOAD = 23; public static final int DLOAD = 24; public static final int ALOAD = 25; public static final int ILOAD0 = 26; public static final int ILOAD1 = 27; public static final int ILOAD2 = 28; public static final int ILOAD3 = 29; public static final int LLOAD0 = 30; public static final int LLOAD1 = 31; public static final int LLOAD2 = 32; public static final int LLOAD3 = 33; public static final int FLOAD0 = 34; public static final int FLOAD1 = 35; public static final int FLOAD2 = 36; public static final int FLOAD3 = 37; public static final int DLOAD0 = 38; public static final int DLOAD1 = 39; public static final int DLOAD2 = 40; public static final int DLOAD3 = 41; public static final int ALOAD0 = 42; public static final int ALOAD1 = 43; public static final int ALOAD2 = 44; public static final int ALOAD3 = 45; public static final int IALOAD = 46; public static final int LALOAD = 47; public static final int FALOAD = 48; public static final int DALOAD = 49; public static final int AALOAD = 50; public static final int BALOAD = 51; public static final int CALOAD = 52; public static final int SALOAD = 53; public static final int ISTORE = 54; public static final int LSTORE = 55; public static final int FSTORE = 56; public static final int DSTORE = 57; public static final int ASTORE = 58; public static final int ISTORE0 = 59; public static final int ISTORE1 = 60; public static final int ISTORE2 = 61; public static final int ISTORE3 = 62; public static final int LSTORE0 = 63; public static final int LSTORE1 = 64; public static final int LSTORE2 = 65; public static final int LSTORE3 = 66; public static final int FSTORE0 = 67; public static final int FSTORE1 = 68; public static final int FSTORE2 = 69; public static final int FSTORE3 = 70; public static final int DSTORE0 = 71; public static final int DSTORE1 = 72; public static final int DSTORE2 = 73; public static final int DSTORE3 = 74; public static final int ASTORE0 = 75; public static final int ASTORE1 = 76; public static final int ASTORE2 = 77; public static final int ASTORE3 = 78; public static final int IASTORE = 79; public static final int LASTORE = 80; public static final int FASTORE = 81; public static final int DASTORE = 82; public static final int AASTORE = 83; public static final int BASTORE = 84; public static final int CASTORE = 85; public static final int SASTORE = 86; public static final int POP = 87; public static final int POP2 = 88; public static final int DUP = 89; public static final int DUPX1 = 90; public static final int DUPX2 = 91; public static final int DUP2 = 92; public static final int DUP2X1 = 93; public static final int DUP2X2 = 94; public static final int SWAP = 95; public static final int IADD = 96; public static final int LADD = 97; public static final int FADD = 98; public static final int DADD = 99; public static final int ISUB = 100; public static final int LSUB = 101; public static final int FSUB = 102; public static final int DSUB = 103; public static final int IMUL = 104; public static final int LMUL = 105; public static final int FMUL = 106; public static final int DMUL = 107; public static final int IDIV = 108; public static final int LDIV = 109; public static final int FDIV = 110; public static final int DDIV = 111; public static final int IREM = 112; public static final int LREM = 113; public static final int FREM = 114; public static final int DREM = 115; public static final int INEG = 116; public static final int LNEG = 117; public static final int FNEG = 118; public static final int DNEG = 119; public static final int ISHL = 120; public static final int LSHL = 121; public static final int ISHR = 122; public static final int LSHR = 123; public static final int IUSHR = 124; public static final int LUSHR = 125; public static final int IAND = 126; public static final int LAND = 127; public static final int IOR = 128; public static final int LOR = 129; public static final int IXOR = 130; public static final int LXOR = 131; public static final int IINC = 132; public static final int I2L = 133; public static final int I2F = 134; public static final int I2D = 135; public static final int L2I = 136; public static final int L2F = 137; public static final int L2D = 138; public static final int F2I = 139; public static final int F2L = 140; public static final int F2D = 141; public static final int D2I = 142; public static final int D2L = 143; public static final int D2F = 144; public static final int I2B = 145; public static final int I2C = 146; public static final int I2S = 147; public static final int LCMP = 148; public static final int FCMPL = 149; public static final int FCMPG = 150; public static final int DCMPL = 151; public static final int DCMPG = 152; public static final int IFEQ = 153; public static final int IFNE = 154; public static final int IFLT = 155; public static final int IFGE = 156; public static final int IFGT = 157; public static final int IFLE = 158; public static final int IFICMPEQ = 159; public static final int IFICMPNE = 160; public static final int IFICMPLT = 161; public static final int IFICMPGE = 162; public static final int IFICMPGT = 163; public static final int IFICMPLE = 164; public static final int IFACMPEQ = 165; public static final int IFACMPNE = 166; public static final int GOTO = 167; public static final int JSR = 168; public static final int RET = 169; public static final int TABLESWITCH = 170; public static final int LOOKUPSWITCH = 171; public static final int IRETURN = 172; public static final int LRETURN = 173; public static final int FRETURN = 174; public static final int DRETURN = 175; public static final int ARETURN = 176; public static final int RETURN = 177; public static final int GETSTATIC = 178; public static final int PUTSTATIC = 179; public static final int GETFIELD = 180; public static final int PUTFIELD = 181; public static final int INVOKEVIRTUAL = 182; public static final int INVOKESPECIAL = 183; public static final int INVOKESTATIC = 184; public static final int INVOKEINTERFACE = 185; public static final int NEW = 187; public static final int NEWARRAY = 188; public static final int ANEWARRAY = 189; public static final int ARRAYLENGTH = 190; public static final int ATHROW = 191; public static final int CHECKCAST = 192; public static final int INSTANCEOF = 193; public static final int MONITORENTER = 194; public static final int MONITOREXIT = 195; public static final int WIDE = 196; public static final int MULTIANEWARRAY = 197; public static final int IFNULL = 198; public static final int IFNONNULL = 199; public static final int GOTOW = 200; public static final int JSRW = 201; // array types public static final int ARRAY_BOOLEAN = 4; public static final int ARRAY_CHAR = 5; public static final int ARRAY_FLOAT = 6; public static final int ARRAY_DOUBLE = 7; public static final int ARRAY_BYTE = 8; public static final int ARRAY_SHORT = 9; public static final int ARRAY_INT = 10; public static final int ARRAY_LONG = 11; // math operations public static final int MATH_ADD = IADD; public static final int MATH_SUB = ISUB; public static final int MATH_MUL = IMUL; public static final int MATH_DIV = IDIV; public static final int MATH_REM = IREM; public static final int MATH_NEG = INEG; public static final int MATH_SHL = ISHL; public static final int MATH_SHR = ISHR; public static final int MATH_USHR = IUSHR; public static final int MATH_AND = IAND; public static final int MATH_OR = IOR; public static final int MATH_XOR = IXOR; // human-readable opcode names public static final String[] OPCODE_NAMES = new String[] { "nop", "aconstnull", "iconstm1", "iconst0", "iconst1", "iconst2", "iconst3", "iconst4", "iconst5", "lconst0", "lconst1", "fconst0", "fconst1", "fconst2", "dconst0", "dconst1", "bipush", "sipush", "ldc", "ldcw", "ldc2w", "iload", "lload", "fload", "dload", "aload", "iload0", "iload1", "iload2", "iload3", "lload0", "lload1", "lload2", "lload3", "fload0", "fload1", "fload2", "fload3", "dload0", "dload1", "dload2", "dload3", "aload0", "aload1", "aload2", "aload3", "iaload", "laload", "faload", "daload", "aaload", "baload", "caload", "saload", "istore", "lstore", "fstore", "dstore", "astore", "istore0", "istore1", "istore2", "istore3", "lstore0", "lstore1", "lstore2", "lstore3", "fstore0", "fstore1", "fstore2", "fstore3", "dstore0", "dstore1", "dstore2", "dstore3", "astore0", "astore1", "astore2", "astore3", "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", "pop2", "dup", "dupx1", "dupx2", "dup2", "dup2x1", "dup2x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", "ldiv", "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", "iand", "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s", "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "ificmpeq", "ificmpne", "ificmplt", "ificmpge", "ificmpgt", "ificmple", "ifacmpeq", "ifacmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", "dreturn", "areturn", "return", "getstatic", "putstatic", "getfield", "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface", "??", "new", "newarray", "anewarray", "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", "monitorexit", "wide", "multianewarray", "ifnull", "ifnonnull", "gotow", "jsrw", }; } serp-1.14.1.orig/src/main/java/serp/bytecode/LoadInstruction.java0000755000000000000000000001565410637750727021617 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.visitor.*; /** * Loads a value from the locals table to the stack. * * @author Abe White */ public class LoadInstruction extends LocalVariableInstruction { private static final Class[][] _mappings = new Class[][] { { byte.class, int.class }, { boolean.class, int.class }, { char.class, int.class }, { short.class, int.class }, { void.class, int.class }, }; String _type = null; LoadInstruction(Code owner) { super(owner); } LoadInstruction(Code owner, int opcode) { super(owner, opcode); } int getLength() { switch (getOpcode()) { case Constants.ILOAD: case Constants.LLOAD: case Constants.FLOAD: case Constants.DLOAD: case Constants.ALOAD: return super.getLength() + 1; default: return super.getLength(); } } public int getStackChange() { switch (getOpcode()) { case Constants.LLOAD: case Constants.LLOAD0: case Constants.LLOAD1: case Constants.LLOAD2: case Constants.LLOAD3: case Constants.DLOAD: case Constants.DLOAD0: case Constants.DLOAD1: case Constants.DLOAD2: case Constants.DLOAD3: return 2; case Constants.NOP: return 0; default: return 1; } } public int getLogicalStackChange() { switch (getOpcode()) { case Constants.NOP: return 0; default: return 1; } } public String getTypeName() { switch (getOpcode()) { case Constants.ILOAD: case Constants.ILOAD0: case Constants.ILOAD1: case Constants.ILOAD2: case Constants.ILOAD3: return int.class.getName(); case Constants.LLOAD: case Constants.LLOAD0: case Constants.LLOAD1: case Constants.LLOAD2: case Constants.LLOAD3: return long.class.getName(); case Constants.FLOAD: case Constants.FLOAD0: case Constants.FLOAD1: case Constants.FLOAD2: case Constants.FLOAD3: return float.class.getName(); case Constants.DLOAD: case Constants.DLOAD0: case Constants.DLOAD1: case Constants.DLOAD2: case Constants.DLOAD3: return double.class.getName(); case Constants.ALOAD: case Constants.ALOAD0: case Constants.ALOAD1: case Constants.ALOAD2: case Constants.ALOAD3: return Object.class.getName(); default: return _type; } } public TypedInstruction setType(String type) { type = mapType(type, _mappings, true); int local = getLocal(); int len = getLength(); // if an invalid type or local, revert to nop if (type == null || local < 0) { _type = type; setOpcode(Constants.NOP); } else { // valid opcode, unset saved type _type = null; switch (type.charAt(0)) { case 'i': setOpcode((local > 3) ? Constants.ILOAD : (Constants.ILOAD0 + local)); break; case 'l': setOpcode((local > 3) ? Constants.LLOAD : (Constants.LLOAD0 + local)); break; case 'f': setOpcode((local > 3) ? Constants.FLOAD : (Constants.FLOAD0 + local)); break; case 'd': setOpcode((local > 3) ? Constants.DLOAD : (Constants.DLOAD0 + local)); break; default: setOpcode((local > 3) ? Constants.ALOAD : (Constants.ALOAD0 + local)); } } if (len != getLength()) invalidateByteIndexes(); return this; } /** * Equivalent to setLocal (0).setType (Object.class); the * this ptr is always passed in local variable 0. * * @return this instruction, for method chaining */ public LoadInstruction setThis() { return (LoadInstruction) setLocal(0).setType(Object.class); } /** * Equivalent to getLocal () == 0 && getType () == * Object.class; the this ptr * is always passed in local variable 0. */ public boolean isThis() { return getLocal() == 0 && getType() == Object.class; } /** * LoadInstructions are equal if the type they reference the same * type and locals index or if either is unset. */ public boolean equalsInstruction(Instruction other) { if (other == this) return true; if (!super.equalsInstruction(other)) return false; String type = getTypeName(); String otherType = ((LoadInstruction) other).getTypeName(); return type == null || otherType == null || type.equals(otherType); } public void acceptVisit(BCVisitor visit) { visit.enterLoadInstruction(this); visit.exitLoadInstruction(this); } void read(Instruction orig) { super.read(orig); LoadInstruction ins = (LoadInstruction) orig; _type = ins._type; } void read(DataInput in) throws IOException { super.read(in); switch (getOpcode()) { case Constants.ILOAD: case Constants.LLOAD: case Constants.FLOAD: case Constants.DLOAD: case Constants.ALOAD: setLocal(in.readUnsignedByte()); break; } } void write(DataOutput out) throws IOException { super.write(out); switch (getOpcode()) { case Constants.ILOAD: case Constants.LLOAD: case Constants.FLOAD: case Constants.DLOAD: case Constants.ALOAD: out.writeByte(getLocal()); } } void calculateOpcode() { // taken care of when setting type setType(getTypeName()); } void calculateLocal() { switch (getOpcode()) { case Constants.ILOAD0: case Constants.LLOAD0: case Constants.FLOAD0: case Constants.DLOAD0: case Constants.ALOAD0: setLocal(0); break; case Constants.ILOAD1: case Constants.LLOAD1: case Constants.FLOAD1: case Constants.DLOAD1: case Constants.ALOAD1: setLocal(1); break; case Constants.ILOAD2: case Constants.LLOAD2: case Constants.FLOAD2: case Constants.DLOAD2: case Constants.ALOAD2: setLocal(2); break; case Constants.ILOAD3: case Constants.LLOAD3: case Constants.FLOAD3: case Constants.DLOAD3: case Constants.ALOAD3: setLocal(3); break; } } } serp-1.14.1.orig/src/main/java/serp/bytecode/RetInstruction.java0000755000000000000000000000176010460270414021443 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.visitor.*; /** * The ret instruction is used in the implementation of finally. * * @author Abe White */ public class RetInstruction extends LocalVariableInstruction { RetInstruction(Code owner) { super(owner, Constants.RET); } int getLength() { return super.getLength() + 1; } public boolean equalsInstruction(Instruction other) { if (this == other) return true; if (!(other instanceof RetInstruction)) return false; return super.equalsInstruction(other); } public void acceptVisit(BCVisitor visit) { visit.enterRetInstruction(this); visit.exitRetInstruction(this); } void read(DataInput in) throws IOException { super.read(in); setLocal(in.readUnsignedByte()); } void write(DataOutput out) throws IOException { super.write(out); out.writeByte(getLocal()); } } serp-1.14.1.orig/src/main/java/serp/bytecode/package.html0000755000000000000000000001477210455026337020103 0ustar

Bytecode Manipuation

This package contains a framework for Java bytecode manipulation.

Bytecode manipulation is a powerful tool in the arsenal of the Java developer. It can be used for tasks from compiling alternative programming languages to run in a JVM, to creating new classes on the fly at runtime, to instrumenting classes for performance analysis, to debugging, to altering or enhancing the capabilities of existing compiled classes. Traditionally, however, this power has come at a price: modifying bytecode has required an in-depth knowledge of the class file structure and has necessitated very low-level programming techniques. These costs have proven too much for most developers, and bytecode manipulation has been largely ignored by the mainstream.

The goal of the serp bytecode framework is to tap the full power of bytecode modification while lowering its associated costs. The framework provides a set of high-level APIs for manipulating all aspects of bytecode, from large-scale structures like class member fields to the individual instructions that comprise the code of methods. While in order to perform any advanced manipulation, some understanding of the class file format and especially of the JVM instruction set is necessary, the framework makes it as easy as possible to enter the world of bytecode development.

There are several other excellent bytecode frameworks available. Serp excels, however, in the following areas:

Serp is not ideally suited to all applications. Here are a few disadvantages of serp:

The first class that you should study in this package is the {@link serp.bytecode.Project} type. From there, move onto the {@link serp.bytecode.BCClass}, and trace its APIs into {@link serp.bytecode.BCField}s, {@link serp.bytecode.BCMethod}s, and finally into actual {@link serp.bytecode.Code}.

serp-1.14.1.orig/src/main/java/serp/bytecode/TypedInstruction.java0000755000000000000000000000723510460270414022001 0ustar package serp.bytecode; import java.util.*; import serp.bytecode.lowlevel.*; import serp.util.*; /** * Any typed instruction. * * @author Abe White */ public abstract class TypedInstruction extends Instruction { private static final Set _opcodeTypes = new HashSet(); static { _opcodeTypes.add(int.class.getName()); _opcodeTypes.add(long.class.getName()); _opcodeTypes.add(float.class.getName()); _opcodeTypes.add(double.class.getName()); _opcodeTypes.add(Object.class.getName()); _opcodeTypes.add(byte.class.getName()); _opcodeTypes.add(char.class.getName()); _opcodeTypes.add(short.class.getName()); _opcodeTypes.add(boolean.class.getName()); _opcodeTypes.add(void.class.getName()); } TypedInstruction(Code owner) { super(owner); } TypedInstruction(Code owner, int opcode) { super(owner, opcode); } /** * Return the type for the given name. Takes into account * the given mappings and the demote flag. * * @param mappings mappings of one type to another; for example, * array instruction treat booleans as ints, so * to reflect that there should be an index x of the * array such that mappings[x][0] = boolean.class and * mappings[x][1] = int.class; may be null if no special mappings are needed * @param demote if true, all object types will be demoted to Object.class */ String mapType(String type, Class[][] mappings, boolean demote) { if (type == null) return null; type = getProject().getNameCache().getExternalForm(type, false); if (!_opcodeTypes.contains(type) && demote) type = Object.class.getName(); if (mappings != null) for (int i = 0; i < mappings.length; i++) if (mappings[i][0].getName().equals(type)) type = mappings[i][1].getName(); return type; } /** * Return the type name for this instruction. * If the type has not been set, this method will return null. */ public abstract String getTypeName(); /** * Return the type for this instruction. * If the type has not been set, this method will return null. */ public Class getType() { String type = getTypeName(); if (type == null) return null; return Strings.toClass(type, getClassLoader()); } /** * Return the type for this instruction. * If the type has not been set, this method will return null. */ public BCClass getTypeBC() { String type = getTypeName(); if (type == null) return null; return getProject().loadClass(type, getClassLoader()); } /** * Set the type of this instruction. Types that have no direct * support will be converted accordingly. * * @return this instruction, for method chaining */ public abstract TypedInstruction setType(String type); /** * Set the type of this instruction. Types that have no direct * support will be converted accordingly. * * @return this instruction, for method chaining */ public TypedInstruction setType(Class type) { if (type == null) return setType((String) null); return setType(type.getName()); } /** * Set the type of this instruction. Types that have no direct * support will be converted accordingly. * * @return this instruction, for method chaining */ public TypedInstruction setType(BCClass type) { if (type == null) return setType((String) null); return setType(type.getName()); } } serp-1.14.1.orig/src/main/java/serp/bytecode/SourceFile.java0000755000000000000000000000534010460270414020505 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; /** * Attribute naming the source file for this class. * * @author Abe White */ public class SourceFile extends Attribute { int _sourceFileIndex = 0; SourceFile(int nameIndex, Attributes owner) { super(nameIndex, owner); } int getLength() { return 2; } /** * Return the index into the class {@link ConstantPool} of the * {@link UTF8Entry} naming the source file for this class, or 0 if not set. */ public int getFileIndex() { return _sourceFileIndex; } /** * Set the index into the class {@link ConstantPool} of the * {@link UTF8Entry} naming the source file for this class. */ public void setFileIndex(int sourceFileIndex) { if (sourceFileIndex < 0) sourceFileIndex = 0; _sourceFileIndex = sourceFileIndex; } /** * Return the name of the source file, or null if not set. */ public String getFileName() { if (_sourceFileIndex == 0) return null; return ((UTF8Entry) getPool().getEntry(_sourceFileIndex)).getValue(); } /** * Return the file object for the source file, or null if not set. * * @param dir the directory of the file, or null */ public File getFile(File dir) { String name = getFileName(); if (name == null) return null; return new File(dir, name); } /** * Set the name of the source file. The name should be the file name * only; it should not include the path to the file. */ public void setFile(String name) { if (name == null) setFileIndex(0); else setFileIndex(getPool().findUTF8Entry(name, true)); } /** * Set the source file. Note that only the file name is recorded; * the path to the file is discarded. */ public void setFile(File file) { if (file == null) setFile((String) null); else setFile(file.getName()); } /** * Set the file name from the current class name plus the .java extension. */ public void setFromClassName() { setFile(((BCClass) getOwner()).getClassName() + ".java"); } public void acceptVisit(BCVisitor visit) { visit.enterSourceFile(this); visit.exitSourceFile(this); } void read(Attribute other) { setFile(((SourceFile) other).getFileName()); } void read(DataInput in, int length) throws IOException { setFileIndex(in.readUnsignedShort()); } void write(DataOutput out, int length) throws IOException { out.writeShort(getFileIndex()); } } serp-1.14.1.orig/src/main/java/serp/bytecode/InstructionPtr.java0000755000000000000000000000163710460270414021461 0ustar package serp.bytecode; import java.util.*; /** * An entity that maintains ptrs to instructions in a code block. * * @author Abe White */ public interface InstructionPtr { /** * Use the byte indexes read from the class file to calculate and * set references to the target instruction(s) for this ptr. * This method will be called after the byte code * has been read in for the first time and before it is written after * modification. */ public void updateTargets(); /** * Replace the given old, likely invalid, target with a new target. The * new target Instruction is guaranteed to be in the same code * block as this InstructionPtr. */ public void replaceTarget(Instruction oldTarget, Instruction newTarget); /** * Returns the Code block that owns the Instruction(s) this * InstructionPtr points to. */ public Code getCode(); } serp-1.14.1.orig/src/main/java/serp/bytecode/Attribute.java0000755000000000000000000000673010517502266020422 0ustar package serp.bytecode; import java.io.*; import java.lang.reflect.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * In bytecode attributes are used to represent anything that is not * part of the class structure. This includes the source file name, code of * methods, the line number table, etc. All attributes contain at a minimum * an immutable name that also determines the attribute's type. * * @author Abe White */ public abstract class Attribute extends Attributes implements VisitAcceptor { private int _nameIndex = 0; private Attributes _owner = null; Attribute(int nameIndex, Attributes owner) { _owner = owner; _nameIndex = nameIndex; } /** * Create an attribute of the appropriate type based on the * the attribute name. */ static Attribute create(String name, Attributes owner) { // special case for annotations int nameIndex = owner.getPool().findUTF8Entry(name, true); if ("RuntimeVisibleAnnotations".equals(name) || "RuntimeInvisibleAnnotations".equals(name)) return new Annotations(nameIndex, owner); try { Class type = Class.forName("serp.bytecode." + name); Constructor cons = type.getDeclaredConstructor(new Class[] { int.class, Attributes.class }); return (Attribute) cons.newInstance(new Object[] { Numbers.valueOf(nameIndex), owner }); } catch (Throwable t) { return new UnknownAttribute(nameIndex, owner); } } /** * Return the {@link Attributes} that owns this attribute. The entity * might be a {@link BCClass}, {@link BCField}, {@link BCMethod}, or other * attribute. */ public Attributes getOwner() { return _owner; } /** * Return the index in the {@link ConstantPool} of the {@link UTF8Entry} * holding the name of this attribute. */ public int getNameIndex() { return _nameIndex; } /** * Return the name of this attribute. */ public String getName() { return ((UTF8Entry) getPool().getEntry(_nameIndex)).getValue(); } public Project getProject() { return _owner.getProject(); } public ConstantPool getPool() { return _owner.getPool(); } public ClassLoader getClassLoader() { return _owner.getClassLoader(); } public boolean isValid() { return _owner != null; } Collection getAttributesHolder() { return Collections.EMPTY_LIST; } /** * Invalidate this attribute. */ void invalidate() { _owner = null; } /** * Return the length of the bytecode representation of this attribute * in bytes, excluding the name index. */ int getLength() { return 0; } /** * Copy the information from the given attribute to this one. Does * nothing by default. */ void read(Attribute other) { } /** * Read the attribute bytecode from the given stream, up to length * bytes, excluding the name index. Does nothing by default. */ void read(DataInput in, int length) throws IOException { } /** * Write the attribute bytecode to the given stream, up to length bytes, * excluding the name index. Does nothing by default. */ void write(DataOutput out, int length) throws IOException { } } serp-1.14.1.orig/src/main/java/serp/bytecode/IIncInstruction.java0000755000000000000000000000331310637750727021547 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.visitor.*; /** * The iinc instruction. * * @author Abe White */ public class IIncInstruction extends LocalVariableInstruction { private int _inc = 0; IIncInstruction(Code owner) { super(owner, Constants.IINC); } int getLength() { return super.getLength() + 2; } /** * Return the increment for this IINC instruction. */ public int getIncrement() { return _inc; } /** * Set the increment on this IINC instruction. * * @return this Instruction, for method chaining */ public IIncInstruction setIncrement(int val) { _inc = val; return this; } public boolean equalsInstruction(Instruction other) { if (this == other) return true; if (!(other instanceof IIncInstruction)) return false; if (!super.equalsInstruction(other)) return false; IIncInstruction ins = (IIncInstruction) other; return getIncrement() == 0 || ins.getIncrement() == 0 || getIncrement() == ins.getIncrement(); } public void acceptVisit(BCVisitor visit) { visit.enterIIncInstruction(this); visit.exitIIncInstruction(this); } void read(Instruction other) { super.read(other); _inc = ((IIncInstruction) other).getIncrement(); } void read(DataInput in) throws IOException { super.read(in); setLocal(in.readUnsignedByte()); _inc = in.readByte(); } void write(DataOutput out) throws IOException { super.write(out); out.writeByte(getLocal()); out.writeByte(_inc); } } serp-1.14.1.orig/src/main/java/serp/bytecode/Local.java0000755000000000000000000001645310640272105017505 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * A local variable or local variable type. * * @author Abe White * @author Sakir Murat Cengiz */ public abstract class Local implements BCEntity, InstructionPtr { private LocalTable _owner = null; private InstructionPtrStrategy _target = new InstructionPtrStrategy(this); private Instruction _end = null; private int _length = 0; private int _nameIndex = 0; private int _descriptorIndex = 0; private int _index = 0; Local(LocalTable owner) { _owner = owner; } /** * The owning table. */ public LocalTable getTable() { return _owner; } void invalidate() { _owner = null; } ////////////////////////// // Local index operations ////////////////////////// /** * Get the local variable index of the current frame for this local. */ public int getLocal() { return _index; } /** * Set the local variable index of the current frame for this local. */ public void setLocal(int index) { _index = index; } /** * Return the parameter that this local corresponds to, or -1 if none. */ public int getParam() { return getCode().getParamsIndex(getLocal()); } /** * Set the method parameter that this local corresponds to. */ public void setParam(int param) { setLocal(_owner.getCode().getLocalsIndex(param)); } //////////////////////////// // Start, Length operations //////////////////////////// /** * Return the index into the code byte array at which this local starts. */ public int getStartPc() { return _target.getByteIndex(); } /** * Return the instruction marking the beginning of this local. */ public Instruction getStart() { return _target.getTargetInstruction(); } /** * Set the index into the code byte array at which this local starts. */ public void setStartPc(int startPc) { _target.setByteIndex(startPc); } /** * Set the {@link Instruction} marking the beginning this local. * The instruction must already be a part of the method. * WARNING: if this instruction is deleted, the results are undefined. */ public void setStart(Instruction instruction) { _target.setTargetInstruction(instruction); } /** * The last {@link Instruction} for which this local is in scope. */ public Instruction getEnd() { if (_end != null) return _end; int idx = _target.getByteIndex() + _length; Instruction end = getCode().getInstruction(idx); return (end != null) ? (Instruction) end.prev : getCode().getLastInstruction(); } /** * Get the number of bytes for which this local has a value in * the code byte array. */ public int getLength() { if (_end != null) return _end.getByteIndex() + _end.getLength() - _target.getByteIndex(); return _length; } /** * Set the last {@link Instruction} for which this local is in scope. * The instruction must already be a part of the method. * WARNING: if this instruction is deleted, the results are undefined. */ public void setEnd(Instruction end) { if (end.getCode() != getCode()) throw new IllegalArgumentException("Instruction pointers and " + "targets must be part of the same code block."); _end = end; _length = -1; } /** * Set the number of bytes for which this local has a value in * the code byte array. */ public void setLength(int length) { if (length < 0) throw new IllegalArgumentException(String.valueOf(length)); _length = length; _end = null; } public void updateTargets() { _target.updateTargets(); _end = getEnd(); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { _target.replaceTarget(oldTarget, newTarget); if (getEnd() == oldTarget) setEnd(newTarget); } ///////////////////////// // Name, Type operations ///////////////////////// /** * Return the {@link ConstantPool} index of the {@link UTF8Entry} that * describes the name of this local. Defaults to 0. */ public int getNameIndex() { return _nameIndex; } /** * Set the {@link ConstantPool} index of the {@link UTF8Entry} that * describes the name of this local. */ public void setNameIndex(int nameIndex) { _nameIndex = nameIndex; } /** * Return the name of this local, or null if unset. */ public String getName() { if (getNameIndex() == 0) return null; return ((UTF8Entry) getPool().getEntry(getNameIndex())).getValue(); } /** * Set the name of this inner local. */ public void setName(String name) { if (name == null) setNameIndex(0); else setNameIndex(getPool().findUTF8Entry(name, true)); } /** * Return the {@link ConstantPool} index of the {@link UTF8Entry} that * describes this local. Defaults to 0. */ public int getTypeIndex() { return _descriptorIndex; } /** * Set the {@link ConstantPool} index of the {@link UTF8Entry} that * describes this local. */ public void setTypeIndex(int index) { _descriptorIndex = index; } /** * Return the full name of the local's type, or null if unset. */ public String getTypeName() { if (getTypeIndex() == 0) return null; UTF8Entry entry = (UTF8Entry) getPool().getEntry(getTypeIndex()); return getProject().getNameCache().getExternalForm(entry.getValue(), false); } /** * Set the type of this local. */ public void setType(String type) { if (type == null) setTypeIndex(0); else { type = getProject().getNameCache().getInternalForm(type, true); setTypeIndex(getPool().findUTF8Entry(type, true)); } } /////////////////////////// // BCEntity implementation /////////////////////////// public Project getProject() { return _owner.getProject(); } public ConstantPool getPool() { return _owner.getPool(); } public ClassLoader getClassLoader() { return _owner.getClassLoader(); } public boolean isValid() { return _owner != null; } ////////////////// // I/O operations ////////////////// void read(DataInput in) throws IOException { setStartPc(in.readUnsignedShort()); setLength(in.readUnsignedShort()); setNameIndex(in.readUnsignedShort()); setTypeIndex(in.readUnsignedShort()); setLocal(in.readUnsignedShort()); } void write(DataOutput out) throws IOException { out.writeShort(getStartPc()); out.writeShort(getLength()); out.writeShort(getNameIndex()); out.writeShort(getTypeIndex()); out.writeShort(getLocal()); } public Code getCode() { return _owner.getCode(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/FieldInstruction.java0000755000000000000000000002765410460270414021746 0ustar package serp.bytecode; import java.io.*; import java.lang.reflect.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * Instruction that takes as an argument a field to operate * on. Examples include getfield, getstatic, setfield, setstatic. * * @author Abe White */ public abstract class FieldInstruction extends Instruction { private int _index = 0; FieldInstruction(Code owner, int opcode) { super(owner, opcode); } int getLength() { return super.getLength() + 2; } //////////////////// // Field operations //////////////////// /** * Return the index in the class {@link ConstantPool} of the * {@link ComplexEntry} describing the field to operate on. */ public int getFieldIndex() { return _index; } /** * Set the index in the class {@link ConstantPool} of the * {@link ComplexEntry} describing the field to operate on. * * @return this instruction, for method chaining */ public FieldInstruction setFieldIndex(int index) { _index = index; return this; } /** * Return the field this instruction operates on, or null if not set. */ public BCField getField() { String dec = getFieldDeclarerName(); if (dec == null) return null; BCClass bc = getProject().loadClass(dec, getClassLoader()); BCField[] fields = bc.getFields(getFieldName()); if (fields.length == 0) return null; return fields[0]; } /** * Set the field this instruction operates on. * * @return this instruction, for method chaining */ public FieldInstruction setField(BCField field) { if (field == null) return setFieldIndex(0); return setField(field.getDeclarer().getName(), field.getName(), field.getTypeName()); } /** * Set the field this instruction operates on. * * @return this instruction, for method chaining */ public FieldInstruction setField(Field field) { if (field == null) return setFieldIndex(0); return setField(field.getDeclaringClass(), field.getName(), field.getType()); } /** * Set the field this instruction operates on. * * @param dec the full class name of the field's declaring class * @param name the field name * @param type the full class name of the field type * @return this instruction, for method chaining */ public FieldInstruction setField(String dec, String name, String type) { if (dec == null && name == null && type == null) return setFieldIndex(0); if (dec == null) dec = ""; if (name == null) name = ""; if (type == null) type = ""; dec = getProject().getNameCache().getInternalForm(dec, false); type = getProject().getNameCache().getInternalForm(type, true); return setFieldIndex(getPool().findFieldEntry(dec, name, type, true)); } /** * Set the field this instruction operates on, for fields that are * declared by the current class. * * @param name the field name * @param type the full class name of the field type * @return this instruction, for method chaining */ public FieldInstruction setField(String name, String type) { BCClass owner = getCode().getMethod().getDeclarer(); return setField(owner.getName(), name, type); } /** * Set the field this instruction operates on. * * @param dec the field's declaring class * @param name the field name * @param type the class of the field type * @return this instruction, for method chaining */ public FieldInstruction setField(Class dec, String name, Class type) { String decName = (dec == null) ? null : dec.getName(); String typeName = (type == null) ? null : type.getName(); return setField(decName, name, typeName); } /** * Set the field this instruction operates on, for fields that are * declared by the current class. * * @param name the field name * @param type the class of the field type * @return this instruction, for method chaining */ public FieldInstruction setField(String name, Class type) { BCClass owner = getCode().getMethod().getDeclarer(); String typeName = (type == null) ? null : type.getName(); return setField(owner.getName(), name, typeName); } /** * Set the field this instruction operates on. * * @param dec the field's declaring class * @param name the field name * @param type the class of the field type * @return this instruction, for method chaining */ public FieldInstruction setField(BCClass dec, String name, BCClass type) { String decName = (dec == null) ? null : dec.getName(); String typeName = (type == null) ? null : type.getName(); return setField(decName, name, typeName); } /** * Set the field this instruction operates on, for fields that are * declared by the current class. * * @param name the field name * @param type the class of the field type * @return this instruction, for method chaining */ public FieldInstruction setField(String name, BCClass type) { BCClass owner = getCode().getMethod().getDeclarer(); String typeName = (type == null) ? null : type.getName(); return setField(owner.getName(), name, typeName); } //////////////////////////////// // Name, Type, Owner operations //////////////////////////////// /** * Return the name of the field this instruction operates on, or null * if not set. */ public String getFieldName() { int index = getFieldIndex(); if (index == 0) return null; ComplexEntry entry = (ComplexEntry) getPool().getEntry(index); String name = entry.getNameAndTypeEntry().getNameEntry().getValue(); if (name.length() == 0) return null; return name; } /** * Set the name of the field this instruction operates on. * * @return this instruction, for method chaining */ public FieldInstruction setFieldName(String name) { return setField(getFieldDeclarerName(), name, getFieldTypeName()); } /** * Return the type of the field this instruction operates on, or null * if not set. */ public String getFieldTypeName() { int index = getFieldIndex(); if (index == 0) return null; ComplexEntry entry = (ComplexEntry) getPool().getEntry(index); String name = getProject().getNameCache().getExternalForm(entry. getNameAndTypeEntry().getDescriptorEntry().getValue(), false); if (name.length() == 0) return null; return name; } /** * Return the type of the field this instruction operates on, or null * if not set. */ public Class getFieldType() { String type = getFieldTypeName(); if (type == null) return null; return Strings.toClass(type, getClassLoader()); } /** * Return the type of the field this instruction operates on, or null * if not set. */ public BCClass getFieldTypeBC() { String type = getFieldTypeName(); if (type == null) return null; return getProject().loadClass(type, getClassLoader()); } /** * Set the type of the field this instruction operates on. * * @return this instruction, for method chaining */ public FieldInstruction setFieldType(String type) { return setField(getFieldDeclarerName(), getFieldName(), type); } /** * Set the type of the field this instruction operates on. * * @return this instruction, for method chaining */ public FieldInstruction setFieldType(Class type) { String name = null; if (type != null) name = type.getName(); return setFieldType(name); } /** * Set the type of the field this instruction operates on. * * @return this instruction, for method chaining */ public FieldInstruction setFieldType(BCClass type) { String name = null; if (type != null) name = type.getName(); return setFieldType(name); } /** * Return the declaring class of the field this instruction operates on, * or null if not set. */ public String getFieldDeclarerName() { int index = getFieldIndex(); if (index == 0) return null; ComplexEntry entry = (ComplexEntry) getPool().getEntry(index); String name = getProject().getNameCache().getExternalForm(entry. getClassEntry().getNameEntry().getValue(), false); if (name.length() == 0) return null; return name; } /** * Return the declaring class of the field this instruction operates on, * or null if not set. */ public Class getFieldDeclarerType() { String type = getFieldDeclarerName(); if (type == null) return null; return Strings.toClass(type, getClassLoader()); } /** * Return the declaring class of the field this instruction operates on, * or null if not set. */ public BCClass getFieldDeclarerBC() { String type = getFieldDeclarerName(); if (type == null) return null; return getProject().loadClass(type, getClassLoader()); } /** * Set the declaring class of the field this instruction operates on. * * @return this instruction, for method chaining */ public FieldInstruction setFieldDeclarer(String type) { return setField(type, getFieldName(), getFieldTypeName()); } /** * Set the declaring class of the field this instruction operates on. * * @return this instruction, for method chaining */ public FieldInstruction setFieldDeclarer(Class type) { String name = null; if (type != null) name = type.getName(); return setFieldDeclarer(name); } /** * Set the declaring class of the field this instruction operates on. * * @return this instruction, for method chaining */ public FieldInstruction setFieldDeclarer(BCClass type) { String name = null; if (type != null) name = type.getName(); return setFieldDeclarer(name); } /** * FieldInstructions are equal if the field they reference is the same, * or if the field of either is unset. */ public boolean equalsInstruction(Instruction other) { if (other == this) return true; if (!(other instanceof FieldInstruction)) return false; if (!super.equalsInstruction(other)) return false; FieldInstruction ins = (FieldInstruction) other; String s1 = getFieldName(); String s2 = ins.getFieldName(); if (!(s1 == null || s2 == null || s1.equals(s2))) return false; s1 = getFieldTypeName(); s2 = ins.getFieldTypeName(); if (!(s1 == null || s2 == null || s1.equals(s2))) return false; s1 = getFieldDeclarerName(); s2 = ins.getFieldDeclarerName(); if (!(s1 == null || s2 == null || s1.equals(s2))) return false; return true; } void read(Instruction orig) { super.read(orig); FieldInstruction ins = (FieldInstruction) orig; setField(ins.getFieldDeclarerName(), ins.getFieldName(), ins.getFieldTypeName()); } void read(DataInput in) throws IOException { super.read(in); setFieldIndex(in.readUnsignedShort()); } void write(DataOutput out) throws IOException { super.write(out); out.writeShort(getFieldIndex()); } } serp-1.14.1.orig/src/main/java/serp/bytecode/WideInstruction.java0000755000000000000000000002353310637750727021623 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.visitor.*; /** * The wide instruction, which is used to allow other * instructions to index values beyond what they can normally index baed * on the length of their arguments. * * @author Abe White */ public class WideInstruction extends LocalVariableInstruction { private static final Class[][] _mappings = new Class[][] { { byte.class, int.class }, { boolean.class, int.class }, { char.class, int.class }, { short.class, int.class }, { void.class, int.class }, }; private int _ins = Constants.NOP; private int _inc = -1; WideInstruction(Code owner) { super(owner, Constants.WIDE); } int getLength() { // opcode, ins, index int length = super.getLength() + 1 + 2; // increment if (_ins == Constants.IINC) length += 2; return length; } public int getStackChange() { switch (_ins) { case Constants.ILOAD: case Constants.FLOAD: case Constants.ALOAD: return 1; case Constants.LLOAD: case Constants.DLOAD: return 2; case Constants.ISTORE: case Constants.FSTORE: case Constants.ASTORE: return -1; case Constants.LSTORE: case Constants.DSTORE: return -2; default: return 0; } } public int getLogicalStackChange() { switch (_ins) { case Constants.ILOAD: case Constants.FLOAD: case Constants.ALOAD: case Constants.LLOAD: case Constants.DLOAD: return 1; case Constants.ISTORE: case Constants.FSTORE: case Constants.ASTORE: case Constants.LSTORE: case Constants.DSTORE: return -1; default: return 0; } } public String getTypeName() { switch (_ins) { case Constants.ILOAD: case Constants.ISTORE: return int.class.getName(); case Constants.LLOAD: case Constants.LSTORE: return long.class.getName(); case Constants.FLOAD: case Constants.FSTORE: return float.class.getName(); case Constants.DLOAD: case Constants.DSTORE: return double.class.getName(); case Constants.ALOAD: case Constants.ASTORE: return Object.class.getName(); default: return null; } } public TypedInstruction setType(String type) { type = mapType(type, _mappings, true); switch (_ins) { case Constants.ILOAD: case Constants.LLOAD: case Constants.FLOAD: case Constants.DLOAD: case Constants.ALOAD: if (type == null) throw new IllegalStateException(); switch (type.charAt(0)) { case 'i': return (TypedInstruction) setInstruction(Constants.ILOAD); case 'l': return (TypedInstruction) setInstruction(Constants.LLOAD); case 'f': return (TypedInstruction) setInstruction(Constants.FLOAD); case 'd': return (TypedInstruction) setInstruction(Constants.DLOAD); default: return (TypedInstruction) setInstruction(Constants.ALOAD); } case Constants.ISTORE: case Constants.LSTORE: case Constants.FSTORE: case Constants.DSTORE: case Constants.ASTORE: if (type == null) throw new IllegalStateException(); switch (type.charAt(0)) { case 'i': return (TypedInstruction) setInstruction(Constants.ISTORE); case 'l': return (TypedInstruction) setInstruction(Constants.LSTORE); case 'f': return (TypedInstruction) setInstruction(Constants.FSTORE); case 'd': return (TypedInstruction) setInstruction(Constants.DSTORE); default: return (TypedInstruction) setInstruction(Constants.ASTORE); } default: if (type != null) throw new IllegalStateException("Augmented instruction not " + "typed"); return this; } } /** * Return the opcode of the instruction to modify; this will return one * of the constants defined in {@link Constants}. */ public int getInstruction() { return _ins; } /** * Set the type of instruction this wide instruction modifies. */ public WideInstruction setInstruction(Instruction ins) { if (ins == null) return setInstruction(Constants.NOP); setInstruction(ins.getOpcode()); if (_ins == Constants.IINC) _inc = ((IIncInstruction) ins).getIncrement(); return this; } /** * Set the type of instruction this wide instruction modifies. */ public WideInstruction setInstruction(int opcode) { int len = getLength(); _ins = opcode; if (len != getLength()) invalidateByteIndexes(); return this; } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction iinc() { return setInstruction(Constants.IINC); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction ret() { return setInstruction(Constants.RET); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction iload() { return setInstruction(Constants.ILOAD); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction fload() { return setInstruction(Constants.FLOAD); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction aload() { return setInstruction(Constants.ALOAD); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction lload() { return setInstruction(Constants.LLOAD); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction dload() { return setInstruction(Constants.DLOAD); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction istore() { return setInstruction(Constants.ISTORE); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction fstore() { return setInstruction(Constants.FSTORE); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction astore() { return setInstruction(Constants.ASTORE); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction lstore() { return setInstruction(Constants.LSTORE); } /** * Set the type of instruction this wide instruction modifies. * * @return this instruction, for method chaining */ public WideInstruction dstore() { return setInstruction(Constants.DSTORE); } /** * Return the increment for this instruction if it augments IINC, or -1 * if unset. */ public int getIncrement() { return _inc; } /** * Set the increment on this instruction if it augments IINC. * * @return this Instruction, for method chaining */ public WideInstruction setIncrement(int val) { _inc = val; return this; } /** * WideInstructions are equal if the instruction they augment is the same * or unset. */ public boolean equalsInstruction(Instruction other) { if (other == this) return true; if (!super.equalsInstruction(other)) return false; if (!(other instanceof WideInstruction)) return false; WideInstruction ins = (WideInstruction) other; int code = getInstruction(); int otherCode = ins.getInstruction(); if (code != otherCode) return false; if (code == Constants.IINC) { int inc = getIncrement(); int otherInc = ins.getIncrement(); return (inc == -1) || (otherInc == -1) || (inc == otherInc); } return true; } public void acceptVisit(BCVisitor visit) { visit.enterWideInstruction(this); visit.exitWideInstruction(this); } void read(Instruction orig) { super.read(orig); setInstruction(((WideInstruction) orig).getInstruction()); } void read(DataInput in) throws IOException { super.read(in); _ins = in.readUnsignedByte(); setLocal(in.readUnsignedShort()); if (_ins == Constants.IINC) _inc = in.readUnsignedShort(); } void write(DataOutput out) throws IOException { super.write(out); out.writeByte(_ins); out.writeShort(getLocal()); if (_ins == Constants.IINC) out.writeShort(_inc); } } serp-1.14.1.orig/src/main/java/serp/bytecode/TableSwitchInstruction.java0000755000000000000000000001520210637750727023136 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * The tableswitch instruction. * * @author Abe White */ public class TableSwitchInstruction extends JumpInstruction { // case info private int _low = 0; private int _high = 0; private List _cases = new LinkedList(); TableSwitchInstruction(Code owner) { super(owner, Constants.TABLESWITCH); } /** * Returns the current byte offsets for the different * switch cases in this Instruction. */ public int[] getOffsets() { int bi = getByteIndex(); int[] offsets = new int[_cases.size()]; for (int i = 0; i < _cases.size(); i++) offsets[i] = ((InstructionPtrStrategy) _cases.get(i)).getByteIndex() - bi; return offsets; } /** * Sets the offsets for the instructions representing the different * switch statement cases. WARNING: these offsets will not be changed * in the event that the code is modified following this call. It is * typically a good idea to follow this call with a call to updateTargets * as soon as the instructions at the given offsets are valid, at which * point the Instructions themselves will be used as the targets and the * offsets will be updated as expected. */ public void setOffsets(int[] offsets) { int bi = getByteIndex(); _cases.clear(); for (int i = 0; i < offsets.length; i++) { InstructionPtrStrategy next = new InstructionPtrStrategy(this); next.setByteIndex(offsets[i] + bi); _cases.add(next); } invalidateByteIndexes(); } int getLength() { // don't call super int length = 1; // make the first byte of the 'default' a multiple of 4 from the // start of the method int byteIndex = getByteIndex() + 1; for (; (byteIndex % 4) != 0; byteIndex++, length++); // default, low, high length += 12; // offsets length += (4 * _cases.size()); return length; } /** * Synonymous with {@link #getTarget}. */ public Instruction getDefaultTarget() { return getTarget(); } /** * Synonymous with {@link #setTarget}. */ public TableSwitchInstruction setDefaultTarget(Instruction ins) { return (TableSwitchInstruction) setTarget(ins); } /** * Synonymous with {@link #getOffset}. */ public int getDefaultOffset() { return getOffset(); } /** * Synonymous with {@link #setOffset}. */ public TableSwitchInstruction setDefaultOffset(int offset) { setOffset(offset); return this; } public int getLow() { return _low; } public TableSwitchInstruction setLow(int low) { _low = low; return this; } public int getHigh() { return _high; } public TableSwitchInstruction setHigh(int high) { _high = high; return this; } /** * Return the targets for this switch, or empty array if not set. */ public Instruction[] getTargets() { Instruction[] result = new Instruction[_cases.size()]; for (int i = 0; i < _cases.size(); i++) result[i] = ((InstructionPtrStrategy) _cases.get(i)). getTargetInstruction(); return result; } /** * Set the jump points for this switch. * * @return this instruction, for method chaining */ public TableSwitchInstruction setTargets(Instruction[] targets) { _cases.clear(); if (targets != null) for (int i = 0; i < targets.length; i++) addTarget(targets[i]); return this; } /** * Add a target to this switch. * * @return this instruction, for method chaining */ public TableSwitchInstruction addTarget(Instruction target) { _cases.add(new InstructionPtrStrategy(this, target)); invalidateByteIndexes(); return this; } public int getStackChange() { return -1; } private Instruction findTarget(int jumpByteIndex, List inss) { Instruction ins; for (Iterator itr = inss.iterator(); itr.hasNext();) { ins = (Instruction) itr.next(); if (ins.getByteIndex() == jumpByteIndex) return ins; } return null; } public void updateTargets() { super.updateTargets(); for (Iterator itr = _cases.iterator(); itr.hasNext();) ((InstructionPtrStrategy) itr.next()).updateTargets(); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { super.replaceTarget(oldTarget, newTarget); for (Iterator itr = _cases.iterator(); itr.hasNext();) ((InstructionPtrStrategy) itr.next()).replaceTarget(oldTarget, newTarget); } public void acceptVisit(BCVisitor visit) { visit.enterTableSwitchInstruction(this); visit.exitTableSwitchInstruction(this); } void read(Instruction orig) { super.read(orig); TableSwitchInstruction ins = (TableSwitchInstruction) orig; setLow(ins.getLow()); setHigh(ins.getHigh()); InstructionPtrStrategy incoming; for (Iterator itr = ins._cases.iterator(); itr.hasNext();) { incoming = (InstructionPtrStrategy) itr.next(); InstructionPtrStrategy next = new InstructionPtrStrategy(this); next.setByteIndex(incoming.getByteIndex()); _cases.add(next); } invalidateByteIndexes(); } void read(DataInput in) throws IOException { // don't call super int bi = getByteIndex(); for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++) in.readByte(); setOffset(in.readInt()); setLow(in.readInt()); setHigh(in.readInt()); _cases.clear(); for (int i = 0; i < (_high - _low + 1); i++) { InstructionPtrStrategy next = new InstructionPtrStrategy(this); next.setByteIndex(bi + in.readInt()); _cases.add(next); } } void write(DataOutput out) throws IOException { // don't call super int bi = getByteIndex(); for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++) out.writeByte(0); out.writeInt(getOffset()); out.writeInt(getLow()); out.writeInt(getHigh()); for (Iterator itr = _cases.iterator(); itr.hasNext();) out.writeInt(((InstructionPtrStrategy) itr.next()).getByteIndex() - bi); } } serp-1.14.1.orig/src/main/java/serp/bytecode/Exceptions.java0000755000000000000000000002001710460270414020564 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * Attribute declaring the checked exceptions a method can throw. * * @author Abe White */ public class Exceptions extends Attribute { private List _indexes = new LinkedList(); Exceptions(int nameIndex, Attributes owner) { super(nameIndex, owner); } int getLength() { return 2 + (2 * _indexes.size()); } /** * Return the owning method. */ public BCMethod getMethod() { return (BCMethod) getOwner(); } /** * Return the indexes in the class {@link ConstantPool} of the * {@link ClassEntry}s for the exception types thrown by this method, or * an empty array if none. */ public int[] getExceptionIndexes() { int[] indexes = new int[_indexes.size()]; Iterator itr = _indexes.iterator(); for (int i = 0; i < indexes.length; i++) indexes[i] = ((Integer) itr.next()).intValue(); return indexes; } /** * Set the indexes in the class {@link ConstantPool} of the * {@link ClassEntry}s for the exception types thrown by this method. Use * null or an empty array for none. */ public void setExceptionIndexes(int[] exceptionIndexes) { _indexes.clear(); if (exceptionIndexes != null) for (int i = 0; i < exceptionIndexes.length; i++) _indexes.add(Numbers.valueOf(exceptionIndexes[i])); } /** * Return the names of the exception types for this method, or an empty * array if none. The names will be in a form suitable for a * {@link Class#forName} call. */ public String[] getExceptionNames() { String[] names = new String[_indexes.size()]; Iterator itr = _indexes.iterator(); int index; ClassEntry entry; for (int i = 0; i < names.length; i++) { index = ((Number) itr.next()).intValue(); entry = (ClassEntry) getPool().getEntry(index); names[i] = getProject().getNameCache().getExternalForm(entry. getNameEntry().getValue(), false); } return names; } /** * Return the {@link Class} objects for the exception types for this * method, or an empty array if none. */ public Class[] getExceptionTypes() { String[] names = getExceptionNames(); Class[] types = new Class[names.length]; for (int i = 0; i < names.length; i++) types[i] = Strings.toClass(names[i], getClassLoader()); return types; } /** * Return bytecode for the exception types of this * method, or an empty array if none. */ public BCClass[] getExceptionBCs() { String[] names = getExceptionNames(); BCClass[] types = new BCClass[names.length]; for (int i = 0; i < names.length; i++) types[i] = getProject().loadClass(names[i], getClassLoader()); return types; } /** * Set the checked exceptions thrown by this method. Use null or an * empty array for none. */ public void setExceptions(String[] exceptions) { if (exceptions != null) { for (int i = 0; i < exceptions.length; i++) if (exceptions[i] == null) throw new NullPointerException("exceptions[" + i + "] = null"); } clear(); if (exceptions != null) for (int i = 0; i < exceptions.length; i++) addException(exceptions[i]); } /** * Set the checked exceptions thrown by this method. Use null or an * empty array for none. */ public void setExceptions(Class[] exceptions) { String[] names = null; if (exceptions != null) { names = new String[exceptions.length]; for (int i = 0; i < exceptions.length; i++) names[i] = exceptions[i].getName(); } setExceptions(names); } /** * Set the checked exceptions thrown by this method. Use null or an * empty array for none. */ public void setExceptions(BCClass[] exceptions) { String[] names = null; if (exceptions != null) { names = new String[exceptions.length]; for (int i = 0; i < exceptions.length; i++) names[i] = exceptions[i].getName(); } setExceptions(names); } /** * Clear this method of all exception declarations. */ public void clear() { _indexes.clear(); } /** * Remove an exception type thrown by this method. * * @return true if the method had the exception type, false otherwise */ public boolean removeException(String type) { String internalForm = getProject().getNameCache().getInternalForm(type, false); ClassEntry entry; for (Iterator itr = _indexes.iterator(); itr.hasNext();) { entry = (ClassEntry) getPool().getEntry(((Integer) itr.next()). intValue()); if (entry.getNameEntry().getValue().equals(internalForm)) { itr.remove(); return true; } } return false; } /** * Remove an exception thrown by this method. * * @return true if the method had the exception type, false otherwise */ public boolean removeException(Class type) { if (type == null) return false; return removeException(type.getName()); } /** * Remove an exception thrown by this method. * * @return true if the method had the exception type, false otherwise */ public boolean removeException(BCClass type) { if (type == null) return false; return removeException(type.getName()); } /** * Add an exception type to those thrown by this method. */ public void addException(String type) { int index = getPool().findClassEntry(getProject().getNameCache(). getInternalForm(type, false), true); _indexes.add(Numbers.valueOf(index)); } /** * Add an exception to those thrown by this method. */ public void addException(Class type) { addException(type.getName()); } /** * Add an exception to those thrown by this method. */ public void addException(BCClass type) { addException(type.getName()); } /** * Return true if the method declares that it throws the given * exception type. */ public boolean throwsException(String type) { String[] exceptions = getExceptionNames(); for (int i = 0; i < exceptions.length; i++) if (exceptions[i].equals(type)) return true; return false; } /** * Return true if the method declares that it throws the given * exception type. */ public boolean throwsException(Class type) { if (type == null) return false; return throwsException(type.getName()); } /** * Return true if the method declares that it throws the given * exception type. */ public boolean throwsException(BCClass type) { if (type == null) return false; return throwsException(type.getName()); } public void acceptVisit(BCVisitor visit) { visit.enterExceptions(this); visit.exitExceptions(this); } void read(Attribute other) { setExceptions(((Exceptions) other).getExceptionNames()); } void read(DataInput in, int length) throws IOException { _indexes.clear(); int exceptionCount = in.readUnsignedShort(); for (int i = 0; i < exceptionCount; i++) _indexes.add(Numbers.valueOf((int) in.readUnsignedShort())); } void write(DataOutput out, int length) throws IOException { out.writeShort(_indexes.size()); for (Iterator itr = _indexes.iterator(); itr.hasNext();) out.writeShort(((Number) itr.next()).shortValue()); } } serp-1.14.1.orig/src/main/java/serp/bytecode/MonitorInstruction.java0000755000000000000000000000045410637750727022357 0ustar package serp.bytecode; /** * A synchronization instruction. * * @author Abe White */ public abstract class MonitorInstruction extends Instruction { MonitorInstruction(Code owner, int opcode) { super(owner, opcode); } public int getStackChange() { return -1; } } serp-1.14.1.orig/src/main/java/serp/bytecode/GotoInstruction.java0000755000000000000000000000313110637750727021633 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * An instruction that specifies a position in the code block to jump to. * Examples include go2, jsr, etc. * * @author Abe White */ public class GotoInstruction extends JumpInstruction { GotoInstruction(Code owner, int opcode) { super(owner, opcode); } public int getStackChange() { if (getOpcode() == Constants.JSR) return 1; return 0; } int getLength() { switch (getOpcode()) { case Constants.GOTOW: case Constants.JSRW: return super.getLength() + 4; default: return super.getLength() + 2; } } public void setOffset(int offset) { super.setOffset(offset); calculateOpcode(); } /** * Calculate our opcode based on the offset size. */ private void calculateOpcode() { int len = getLength(); int offset; switch (getOpcode()) { case Constants.GOTO: case Constants.GOTOW: offset = getOffset(); if (offset < (2 << 16)) setOpcode(Constants.GOTO); else setOpcode(Constants.GOTOW); break; case Constants.JSR: case Constants.JSRW: offset = getOffset(); if (offset < (2 << 16)) setOpcode(Constants.JSR); else setOpcode(Constants.JSRW); break; } if (len != getLength()) invalidateByteIndexes(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/StackInstruction.java0000755000000000000000000000635110637750727021777 0ustar package serp.bytecode; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; /** * Represents an instruction that manipulates the stack of the current * frame. Using the {@link #setType} methods is a hint about the type being * manipulated that might cause this instruction to use the wide version * of the opcode it represents (if manipulating a long or double). This * saves the developer from having to decide at compile time whether to * use pop or pop2, etc. * * @author Abe White */ public class StackInstruction extends TypedInstruction { StackInstruction(Code owner, int opcode) { super(owner, opcode); } public int getStackChange() { switch (getOpcode()) { case Constants.POP: return -1; case Constants.POP2: return -2; case Constants.DUP: case Constants.DUPX1: case Constants.DUPX2: return 1; case Constants.DUP2: case Constants.DUP2X1: case Constants.DUP2X2: return 2; default: return 0; } } /** * This method will always return null; use {@link #isWide} to determine * if this is pop2, dup2, etc. */ public String getTypeName() { return null; } public TypedInstruction setType(String type) { type = getProject().getNameCache().getExternalForm(type, false); return setWide(long.class.getName().equals(type) || double.class.getName().equals(type)); } /** * Return whether to use the wide form of the current opcode for * operations on longs or doubles. */ public boolean isWide() { switch (getOpcode()) { case Constants.POP2: case Constants.DUP2: case Constants.DUP2X1: case Constants.DUP2X2: return true; default: return false; } } /** * Set whether to use the wide form of the current opcode for operations * on longs or doubles. * * @return this instruction, for method chaining */ public StackInstruction setWide(boolean wide) { switch (getOpcode()) { case Constants.POP: if (wide) setOpcode(Constants.POP2); break; case Constants.POP2: if (!wide) setOpcode(Constants.POP); break; case Constants.DUP: if (wide) setOpcode(Constants.DUP2); break; case Constants.DUP2: if (!wide) setOpcode(Constants.DUP); break; case Constants.DUPX1: if (wide) setOpcode(Constants.DUP2X1); break; case Constants.DUP2X1: if (!wide) setOpcode(Constants.DUPX1); break; case Constants.DUPX2: if (wide) setOpcode(Constants.DUP2X2); break; case Constants.DUP2X2: if (!wide) setOpcode(Constants.DUPX2); break; } return this; } public void acceptVisit(BCVisitor visit) { visit.enterStackInstruction(this); visit.exitStackInstruction(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/Instruction.java0000755000000000000000000001057710637750727021016 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; /** * An opcode in a method of a class. * * @author Abe White */ public class Instruction extends CodeEntry implements BCEntity, VisitAcceptor { private Code _owner = null; private int _opcode = Constants.NOP; Instruction(Code owner) { _owner = owner; } Instruction(Code owner, int opcode) { _owner = owner; _opcode = opcode; } /** * Return the code block that owns this instruction. */ public Code getCode() { return _owner; } /** * Return the name of this instruction. */ public String getName() { return Constants.OPCODE_NAMES[_opcode]; } /** * Return the opcode this instruction represents. */ public int getOpcode() { return _opcode; } /** * Set the opcode this instruction represents. For internal use only. * * @return this instruction, for method chaining */ Instruction setOpcode(int opcode) { _opcode = opcode; return this; } /** * Return the index in the method code byte block at which this opcode * starts. Note that this information may be out of date if the code * block has been modified since last read/written. */ public int getByteIndex() { if (_owner != null) return _owner.getByteIndex(this); return 0; } /** * Notification that a change has been made to this instruction that * alters the structure of the code block, invalidating byte indexes. */ void invalidateByteIndexes() { if (_owner != null) _owner.invalidateByteIndexes(); } /** * Return the line number of this instruction, or null if none. This * method is subject to the validity constraints of {@link #getByteIndex}. * * @see LineNumberTable#getLineNumber(Instruction) */ public LineNumber getLineNumber() { LineNumberTable table = _owner.getLineNumberTable(false); if (table == null) return null; return table.getLineNumber(this); } /** * Return the length in bytes of this opcode, including all arguments. * For many opcodes this method relies on an up-to-date byte index. */ int getLength() { return 1; } /** * Return the logical number of stack positions changed by this * instruction. In other words, ignore weirdness with longs and doubles * taking two stack positions. */ public int getLogicalStackChange() { return getStackChange(); } /** * Return the number of stack positions this instruction pushes * or pops during its execution. * * @return 0 if the stack is not affected by this instruction, a * positive number if it pushes onto the stack, and a negative * number if it pops from the stack */ public int getStackChange() { return 0; } /** * Instructions are equal if their opcodes are the same. Subclasses * should override this method to perform a template comparison: * instructions should compare equal to other instructions of the same * type where the data is either the same or the data is unset. */ public boolean equalsInstruction(Instruction other) { if (other == this) return true; return other.getOpcode() == getOpcode(); } public Project getProject() { return _owner.getProject(); } public ConstantPool getPool() { return _owner.getPool(); } public ClassLoader getClassLoader() { return _owner.getClassLoader(); } public boolean isValid() { return _owner != null; } public void acceptVisit(BCVisitor visit) { } void invalidate() { _owner = null; } /** * Copy the given instruction data. */ void read(Instruction orig) { } /** * Read the arguments for this opcode from the given stream. * This method should be overridden by opcodes that take arguments. */ void read(DataInput in) throws IOException { } /** * Write the arguments for this opcode to the given stream. * This method should be overridden by opcodes that take arguments. */ void write(DataOutput out) throws IOException { } } serp-1.14.1.orig/src/main/java/serp/bytecode/SwitchInstruction.java0000755000000000000000000001356310637750727022176 0ustar package serp.bytecode; import java.io.*; import java.util.*; /** * Contains functionality common to the different switch types * (TableSwitch and LookupSwitch). * * @author Eric Lindauer */ public abstract class SwitchInstruction extends JumpInstruction { private List _cases = new LinkedList(); public SwitchInstruction(Code owner, int opcode) { super(owner, opcode); } /** * Returns the current byte offsets for the different * switch cases in this Instruction. */ public int[] getOffsets() { int bi = getByteIndex(); int[] offsets = new int[_cases.size()]; for (int i = 0; i < offsets.length; i++) offsets[i] = ((InstructionPtrStrategy) _cases.get(i)).getByteIndex() - bi; return offsets; } /** * Sets the offsets for the instructions representing the different * switch statement cases. WARNING: these offsets will not be changed * in the event that the code is modified following this call. It is * typically a good idea to follow this call with a call to updateTargets * as soon as the instructions at the given offsets are valid, at which * point the Instructions themselves will be used as the targets and the * offsets will be updated as expected. */ public void setOffsets(int[] offsets) { int bi = getByteIndex(); _cases.clear(); for (int i = 0; i < offsets.length; i++) { InstructionPtrStrategy next = new InstructionPtrStrategy(this); next.setByteIndex(offsets[i] + bi); _cases.add(next); } } public int countTargets() { return _cases.size(); } int getLength() { // don't call super.getLength(), cause JumpInstruction will return // value assuming this is an 'if' or 'goto' instruction int length = 1; // make the first byte of the 'default' a multiple of 4 from the // start of the method int byteIndex = getByteIndex() + 1; for (; (byteIndex % 4) != 0; byteIndex++, length++); return length; } /** * Synonymous with {@link #getTarget}. */ public Instruction getDefaultTarget() { return getTarget(); } /** * Synonymous with {@link #getOffset}. */ public int getDefaultOffset() { return getOffset(); } /** * Synonymous with {@link #setOffset}. */ public SwitchInstruction setDefaultOffset(int offset) { setOffset(offset); return this; } /** * Synonymous with {@link #setTarget}. */ public SwitchInstruction setDefaultTarget(Instruction ins) { return (SwitchInstruction) setTarget(ins); } /** * Return the targets for this switch, or empty array if not set. */ public Instruction[] getTargets() { Instruction[] result = new Instruction[_cases.size()]; for (int i = 0; i < _cases.size(); i++) result[i] = ((InstructionPtrStrategy) _cases.get(i)). getTargetInstruction(); return result; } /** * Set the jump points for this switch. * * @return this instruction, for method chaining */ public SwitchInstruction setTargets(Instruction[] targets) { _cases.clear(); if (targets != null) for (int i = 0; i < targets.length; i++) addTarget(targets[i]); return this; } /** * Add a target to this switch. * * @return this instruction, for method chaining */ public SwitchInstruction addTarget(Instruction target) { _cases.add(new InstructionPtrStrategy(this, target)); return this; } public int getStackChange() { return -1; } public void updateTargets() { super.updateTargets(); for (Iterator itr = _cases.iterator(); itr.hasNext();) ((InstructionPtrStrategy) itr.next()).updateTargets(); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { super.replaceTarget(oldTarget, newTarget); for (Iterator itr = _cases.iterator(); itr.hasNext();) ((InstructionPtrStrategy) itr.next()).replaceTarget(oldTarget, newTarget); } void read(Instruction orig) { super.read(orig); SwitchInstruction ins = (SwitchInstruction) orig; _cases.clear(); InstructionPtrStrategy incoming; for (Iterator itr = ins._cases.iterator(); itr.hasNext();) { incoming = (InstructionPtrStrategy) itr.next(); InstructionPtrStrategy next = new InstructionPtrStrategy(this); next.setByteIndex(incoming.getByteIndex()); _cases.add(next); } } void clearTargets() { _cases.clear(); } void readTarget(DataInput in) throws IOException { InstructionPtrStrategy next = new InstructionPtrStrategy(this); next.setByteIndex(getByteIndex() + in.readInt()); _cases.add(next); } /** * Set the match-jumppt pairs for this switch. * * @return this instruction, for method chaining */ public SwitchInstruction setCases(int[] matches, Instruction[] targets) { setMatches(matches); setTargets(targets); return this; } public SwitchInstruction setMatches(int[] matches) { clearMatches(); for (int i = 0; i < matches.length; i++) addMatch(matches[i]); return this; } /** * Add a case to this switch. * * @return this instruction, for method chaining */ public SwitchInstruction addCase(int match, Instruction target) { addMatch(match); addTarget(target); return this; } public abstract SwitchInstruction addMatch(int match); public abstract int[] getMatches(); abstract void clearMatches(); void calculateOpcode() { } } serp-1.14.1.orig/src/main/java/serp/bytecode/ConvertInstruction.java0000755000000000000000000002515110460270414022331 0ustar package serp.bytecode; import java.util.*; import serp.bytecode.visitor.*; import serp.util.*; /** * A conversion opcode such as i2l, f2i, etc. * Changing the types of the instruction will automatically * update the underlying opcode. Converting from one type to the same * type will result in a nop. * * @author Abe White */ public class ConvertInstruction extends TypedInstruction { private static final Class[][] _mappings = new Class[][] { { boolean.class, int.class }, { void.class, int.class }, { Object.class, int.class }, }; private static final Class[][] _fromMappings = new Class[][] { { boolean.class, int.class }, { void.class, int.class }, { Object.class, int.class }, { byte.class, int.class }, { char.class, int.class }, { short.class, int.class }, }; String _toType = null; String _fromType = null; ConvertInstruction(Code owner) { super(owner); } ConvertInstruction(Code owner, int opcode) { super(owner, opcode); } public int getLogicalStackChange() { return 0; } public int getStackChange() { switch (getOpcode()) { case Constants.I2L: case Constants.I2D: case Constants.F2L: case Constants.F2D: return 1; case Constants.L2I: case Constants.L2F: case Constants.D2I: case Constants.D2F: return -1; default: return 0; } } public String getTypeName() { switch (getOpcode()) { case Constants.L2I: case Constants.F2I: case Constants.D2I: return int.class.getName(); case Constants.I2L: case Constants.F2L: case Constants.D2L: return long.class.getName(); case Constants.I2F: case Constants.L2F: case Constants.D2F: return float.class.getName(); case Constants.I2D: case Constants.L2D: case Constants.F2D: return double.class.getName(); case Constants.I2B: return byte.class.getName(); case Constants.I2C: return char.class.getName(); case Constants.I2S: return short.class.getName(); default: return _toType; } } public TypedInstruction setType(String type) { String toType = mapType(type, _mappings, true); String fromType = getFromTypeName(); // if no valid opcode, remember current types in case they reset one // to create a valid opcode if (toType == null || fromType == null || toType.equals(fromType)) { _toType = toType; _fromType = fromType; return (TypedInstruction) setOpcode(Constants.NOP); } // ok, valid conversion possible, forget saved types _toType = null; _fromType = null; char to = toType.charAt(0); char from = fromType.charAt(0); switch (to) { case 'i': switch (from) { case 'l': return (TypedInstruction) setOpcode(Constants.L2I); case 'f': return (TypedInstruction) setOpcode(Constants.F2I); case 'd': return (TypedInstruction) setOpcode(Constants.D2I); } case 'l': switch (from) { case 'i': return (TypedInstruction) setOpcode(Constants.I2L); case 'f': return (TypedInstruction) setOpcode(Constants.F2L); case 'd': return (TypedInstruction) setOpcode(Constants.D2L); } case 'f': switch (from) { case 'i': return (TypedInstruction) setOpcode(Constants.I2F); case 'l': return (TypedInstruction) setOpcode(Constants.L2F); case 'd': return (TypedInstruction) setOpcode(Constants.D2F); } case 'd': switch (from) { case 'i': return (TypedInstruction) setOpcode(Constants.I2D); case 'l': return (TypedInstruction) setOpcode(Constants.L2D); case 'f': return (TypedInstruction) setOpcode(Constants.F2D); } case 'b': if (from == 'i') return (TypedInstruction) setOpcode(Constants.I2B); case 'C': if (from == 'i') return (TypedInstruction) setOpcode(Constants.I2C); case 'S': if (from == 'i') return (TypedInstruction) setOpcode(Constants.I2S); default: throw new IllegalStateException(); } } /** * Return the name of the type being converted from. * If neither type has been set, this method will return null. */ public String getFromTypeName() { switch (getOpcode()) { case Constants.I2L: case Constants.I2F: case Constants.I2D: case Constants.I2B: case Constants.I2S: case Constants.I2C: return int.class.getName(); case Constants.L2I: case Constants.L2F: case Constants.L2D: return long.class.getName(); case Constants.F2I: case Constants.F2L: case Constants.F2D: return float.class.getName(); case Constants.D2I: case Constants.D2L: case Constants.D2F: return double.class.getName(); default: return _fromType; } } /** * Return the {@link Class} of the type being converted from. * If neither type has been set, this method will return null. */ public Class getFromType() { String type = getFromTypeName(); if (type == null) return null; return Strings.toClass(type, getClassLoader()); } /** * Return the bytecode of the type being converted from. * If neither type has been set, this method will return null. */ public BCClass getFromTypeBC() { String type = getFromTypeName(); if (type == null) return null; return getProject().loadClass(type, getClassLoader()); } /** * Set the type being converted from. Types that have no direct * support will be converted accordingly. * * @return this instruction, for method chaining */ public ConvertInstruction setFromType(String type) { String fromType = mapType(type, _fromMappings, true); String toType = getTypeName(); // if no valid opcode, remember current types in case they reset one // to create a valid opcode if ((toType == null) || (fromType == null) || toType.equals(fromType)) { _toType = toType; _fromType = fromType; return (ConvertInstruction) setOpcode(Constants.NOP); } // ok, valid conversion possible, forget saved types _toType = null; _fromType = null; char to = toType.charAt(0); char from = fromType.charAt(0); switch (from) { case 'i': switch (to) { case 'l': return (ConvertInstruction) setOpcode(Constants.I2L); case 'f': return (ConvertInstruction) setOpcode(Constants.I2F); case 'd': return (ConvertInstruction) setOpcode(Constants.I2D); case 'b': return (ConvertInstruction) setOpcode(Constants.I2B); case 'c': return (ConvertInstruction) setOpcode(Constants.I2C); case 's': return (ConvertInstruction) setOpcode(Constants.I2S); } case 'l': switch (to) { case 'i': return (ConvertInstruction) setOpcode(Constants.L2I); case 'f': return (ConvertInstruction) setOpcode(Constants.L2F); case 'd': return (ConvertInstruction) setOpcode(Constants.L2D); } case 'f': switch (to) { case 'i': return (ConvertInstruction) setOpcode(Constants.F2I); case 'l': return (ConvertInstruction) setOpcode(Constants.F2L); case 'd': return (ConvertInstruction) setOpcode(Constants.F2D); } case 'd': switch (to) { case 'i': return (ConvertInstruction) setOpcode(Constants.D2I); case 'l': return (ConvertInstruction) setOpcode(Constants.D2L); case 'f': return (ConvertInstruction) setOpcode(Constants.D2F); } default: throw new IllegalStateException(); } } /** * Set the type being converted from. Types that have no direct * support will be converted accordingly. * * @return this instruction, for method chaining */ public ConvertInstruction setFromType(Class type) { if (type == null) return setFromType((String) null); return setFromType(type.getName()); } /** * Set the type being converted from. Types that have no direct * support will be converted accordingly. * * @return this instruction, for method chaining */ public ConvertInstruction setFromType(BCClass type) { if (type == null) return setFromType((String) null); return setFromType(type.getName()); } /** * ConvertInstructions are equal if the types they convert between are * either equal or unset. */ public boolean equalsInstruction(Instruction other) { if (other == this) return true; if (!(other instanceof ConvertInstruction)) return false; ConvertInstruction ins = (ConvertInstruction) other; if (getOpcode() != Constants.NOP && getOpcode() == ins.getOpcode()) return true; String type = getTypeName(); String otherType = ins.getTypeName(); if (!(type == null || otherType == null || type.equals(otherType))) return false; type = getFromTypeName(); otherType = ins.getFromTypeName(); return type == null || otherType == null || type.equals(otherType); } public void acceptVisit(BCVisitor visit) { visit.enterConvertInstruction(this); visit.exitConvertInstruction(this); } void read(Instruction orig) { super.read(orig); ConvertInstruction ins = (ConvertInstruction) orig; _toType = ins._toType; _fromType = ins._fromType; } } serp-1.14.1.orig/src/main/java/serp/bytecode/Synthetic.java0000755000000000000000000000066310460270414020422 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * Attribute marking a member as synthetic, or not present in the class * source code. * * @author Abe White */ public class Synthetic extends Attribute { Synthetic(int nameIndex, Attributes owner) { super(nameIndex, owner); } public void acceptVisit(BCVisitor visit) { visit.enterSynthetic(this); visit.exitSynthetic(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/MathInstruction.java0000755000000000000000000001545410460270414021607 0ustar package serp.bytecode; import java.util.*; import serp.bytecode.visitor.*; /** * One of the math operations defined in the {@link Constants} interface. * Changing the type or operation of the instruction will automatically * update the underlying opcode. * * @author Abe White */ public class MathInstruction extends TypedInstruction { private static final Class[][] _mappings = new Class[][] { { byte.class, int.class }, { boolean.class, int.class }, { char.class, int.class }, { short.class, int.class }, { void.class, int.class }, { Object.class, int.class }, }; private int _op = -1; private String _type = null; MathInstruction(Code owner) { super(owner); } MathInstruction(Code owner, int opcode) { super(owner, opcode); _op = getOperation(); } public int getStackChange() { int op = getOperation(); if (op == Constants.MATH_NEG || getOpcode() == Constants.NOP) return 0; String type = getTypeName(); if (long.class.getName().equals(type) || double.class.getName().equals(type)) { switch (getOpcode()) { case (Constants.LSHL): case (Constants.LSHR): case (Constants.LUSHR): return -1; default: return -2; } } return -1; } public int getLogicalStackChange() { int op = getOperation(); if (op == Constants.MATH_NEG || getOpcode() == Constants.NOP) return 0; return -1; } public String getTypeName() { switch (getOpcode()) { case Constants.IADD: case Constants.ISUB: case Constants.IMUL: case Constants.IDIV: case Constants.IREM: case Constants.INEG: case Constants.ISHL: case Constants.ISHR: case Constants.IUSHR: case Constants.IAND: case Constants.IOR: case Constants.IXOR: return int.class.getName(); case Constants.LADD: case Constants.LSUB: case Constants.LMUL: case Constants.LDIV: case Constants.LREM: case Constants.LNEG: case Constants.LSHL: case Constants.LSHR: case Constants.LUSHR: case Constants.LAND: case Constants.LOR: case Constants.LXOR: return long.class.getName(); case Constants.FADD: case Constants.FSUB: case Constants.FMUL: case Constants.FDIV: case Constants.FREM: case Constants.FNEG: return float.class.getName(); case Constants.DADD: case Constants.DSUB: case Constants.DMUL: case Constants.DDIV: case Constants.DREM: case Constants.DNEG: return double.class.getName(); default: return _type; } } public TypedInstruction setType(String type) { type = mapType(type, _mappings, true); // if an invalid type or op, revert to nop if (type == null || _op < 0) { _type = type; return (TypedInstruction) setOpcode(Constants.NOP); } // valid opcode, unset saved type _type = null; switch (type.charAt(0)) { case 'i': return (TypedInstruction) setOpcode(_op); case 'l': return (TypedInstruction) setOpcode(_op + 1); case 'f': return (TypedInstruction) setOpcode(_op + 2); case 'd': return (TypedInstruction) setOpcode(_op + 3); default: throw new IllegalStateException(); } } /** * Set the math operation to be performed. This should be one of the * math constant defined in {@link Constants}. * * @return this instruction, for method chaining */ public MathInstruction setOperation(int operation) { _op = operation; // this calculates the opcode setType(getTypeName()); return this; } /** * Return the operation for this math instruction; will be one of the * math constant defined in {@link Constants}, or -1 if unset. */ public int getOperation() { switch (getOpcode()) { case Constants.IADD: case Constants.LADD: case Constants.FADD: case Constants.DADD: return Constants.MATH_ADD; case Constants.ISUB: case Constants.LSUB: case Constants.FSUB: case Constants.DSUB: return Constants.MATH_SUB; case Constants.IMUL: case Constants.LMUL: case Constants.FMUL: case Constants.DMUL: return Constants.MATH_MUL; case Constants.IDIV: case Constants.LDIV: case Constants.FDIV: case Constants.DDIV: return Constants.MATH_DIV; case Constants.IREM: case Constants.LREM: case Constants.FREM: case Constants.DREM: return Constants.MATH_REM; case Constants.INEG: case Constants.LNEG: case Constants.FNEG: case Constants.DNEG: return Constants.MATH_NEG; case Constants.ISHL: case Constants.LSHL: return Constants.MATH_SHL; case Constants.ISHR: case Constants.LSHR: return Constants.MATH_SHR; case Constants.IUSHR: case Constants.LUSHR: return Constants.MATH_USHR; case Constants.IAND: case Constants.LAND: return Constants.MATH_AND; case Constants.IOR: case Constants.LOR: return Constants.MATH_OR; case Constants.IXOR: case Constants.LXOR: return Constants.MATH_XOR; default: return _op; } } /** * MathInstructions are equal if they have the same operation and type, * or the operation and type of either is unset. */ public boolean equalsInstruction(Instruction other) { if (this == other) return true; if (!(other instanceof MathInstruction)) return false; MathInstruction ins = (MathInstruction) other; int op = getOperation(); int otherOp = ins.getOperation(); boolean opEq = op == -1 || otherOp == -1 || op == otherOp; String type = getTypeName(); String otherType = ins.getTypeName(); boolean typeEq = type == null || otherType == null || type.equals(otherType); return opEq && typeEq; } public void acceptVisit(BCVisitor visit) { visit.enterMathInstruction(this); visit.exitMathInstruction(this); } void read(Instruction orig) { super.read(orig); MathInstruction ins = (MathInstruction) orig; _type = ins._type; _op = ins._op; } } serp-1.14.1.orig/src/main/java/serp/bytecode/LookupSwitchInstruction.java0000755000000000000000000001436510637750727023371 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; import serp.util.*; /** * The lookupswitch instruction. * * @author Abe White */ public class LookupSwitchInstruction extends JumpInstruction { // case info private List _matches = new LinkedList(); private List _cases = new LinkedList(); LookupSwitchInstruction(Code owner) { super(owner, Constants.LOOKUPSWITCH); } int getLength() { // don't call super.getLength(), cause JumpInstruction will return // value assuming this is an 'if' or 'goto' instruction int length = 1; // make the first byte of the 'default' a multiple of 4 from the // start of the method int byteIndex = getByteIndex() + 1; for (; (byteIndex % 4) != 0; byteIndex++, length++); // default, npairs length += 8; // pairs length += (8 * _matches.size()); return length; } public int getStackChange() { return -1; } /** * Synonymous with {@link #getTarget}. */ public Instruction getDefaultTarget() { return getTarget(); } /** * Synonymous with {@link #setTarget}. */ public LookupSwitchInstruction setDefaultTarget(Instruction ins) { return (LookupSwitchInstruction) setTarget(ins); } /** * Synonymous with {@link #getOffset}. */ public int getDefaultOffset() { return getOffset(); } /** * Synonymous with {@link #setOffset}. */ public LookupSwitchInstruction setDefaultOffset(int offset) { setOffset(offset); return this; } /** * Set the match-jumppt pairs for this switch. * * @return this instruction, for method chaining */ public LookupSwitchInstruction setCases(int[] matches, Instruction[] targets) { _matches.clear(); _cases.clear(); for (int i = 0; i < matches.length; i++) _matches.add(Numbers.valueOf(matches[i])); for (int i = 0; i < targets.length; i++) { InstructionPtrStrategy next = new InstructionPtrStrategy(this); next.setTargetInstruction(targets[i]); _cases.add(next); } invalidateByteIndexes(); return this; } public int[] getOffsets() { int bi = getByteIndex(); int[] offsets = new int[_cases.size()]; for (int i = 0; i < offsets.length; i++) offsets[i] = ((InstructionPtrStrategy) _cases.get(i)).getByteIndex() - bi; return offsets; } /** * Return the values of the case statements for this switch. */ public int[] getMatches() { int[] matches = new int[_matches.size()]; Iterator itr = _matches.iterator(); for (int i = 0; i < matches.length; i++) matches[i] = ((Integer) itr.next()).intValue(); return matches; } /** * Return the targets of the case statements for this switch. */ public Instruction[] getTargets() { Instruction[] result = new Instruction[_cases.size()]; for (int i = 0; i < result.length; i++) result[i] = ((InstructionPtrStrategy) _cases.get(i)). getTargetInstruction(); return result; } /** * Add a case to this switch. * * @return this instruction, for method chaining */ public LookupSwitchInstruction addCase(int match, Instruction target) { _matches.add(Numbers.valueOf(match)); _cases.add(new InstructionPtrStrategy(this, target)); invalidateByteIndexes(); return this; } private Instruction findJumpPoint(int jumpByteIndex, List inss) { Instruction ins; for (Iterator itr = inss.iterator(); itr.hasNext();) { ins = (Instruction) itr.next(); if (ins.getByteIndex() == jumpByteIndex) return ins; } return null; } public void updateTargets() { super.updateTargets(); for (Iterator itr = _cases.iterator(); itr.hasNext();) ((InstructionPtrStrategy) itr.next()).updateTargets(); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { super.replaceTarget(oldTarget, newTarget); for (Iterator itr = _cases.iterator(); itr.hasNext();) ((InstructionPtrStrategy) itr.next()).replaceTarget(oldTarget, newTarget); } public void acceptVisit(BCVisitor visit) { visit.enterLookupSwitchInstruction(this); visit.exitLookupSwitchInstruction(this); } void read(Instruction orig) { super.read(orig); LookupSwitchInstruction ins = (LookupSwitchInstruction) orig; _matches = new LinkedList(ins._matches); _cases.clear(); for (Iterator itr = ins._cases.iterator(); itr.hasNext();) { InstructionPtrStrategy origPtr = (InstructionPtrStrategy)itr.next(); InstructionPtrStrategy newPtr = new InstructionPtrStrategy(this); newPtr.setByteIndex(origPtr.getByteIndex()); _cases.add(newPtr); } invalidateByteIndexes(); } void read(DataInput in) throws IOException { // don't call super int bi = getByteIndex(); for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++) in.readByte(); setOffset(in.readInt()); _matches.clear(); _cases.clear(); for (int i = 0, pairCount = in.readInt(); i < pairCount; i++) { _matches.add(Numbers.valueOf(in.readInt())); InstructionPtrStrategy next = new InstructionPtrStrategy(this); next.setByteIndex(bi + in.readInt()); _cases.add(next); } } void write(DataOutput out) throws IOException { // don't call super int bi = getByteIndex(); for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++) out.writeByte(0); out.writeInt(getOffset()); out.writeInt(_matches.size()); for (int i = 0; i < _matches.size(); i++) { out.writeInt(((Integer) _matches.get(i)).intValue()); out.writeInt(((InstructionPtrStrategy) _cases.get(i)).getByteIndex() - bi); } } } serp-1.14.1.orig/src/main/java/serp/bytecode/LocalVariableTypeTable.java0000755000000000000000000000477010460270414022765 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * Code blocks compiled from source have local variable type tables mapping * generics-using locals used in opcodes to their names and signatures. * * @author Abe White */ public class LocalVariableTypeTable extends LocalTable { LocalVariableTypeTable(int nameIndex, Attributes owner) { super(nameIndex, owner); } /** * Return all the locals of this method. */ public LocalVariableType[] getLocalVariableTypes() { return (LocalVariableType[]) getLocals(); } /** * Return the local with the given locals index, or null if none. */ public LocalVariableType getLocalVariableType(int local) { return (LocalVariableType) getLocal(local); } /** * Return the local with the given name, or null if none. If multiple * locals have the given name, which is returned is undefined. */ public LocalVariableType getLocalVariableType(String name) { return (LocalVariableType) getLocal(name); } /** * Return all locals with the given name, or empty array if none. */ public LocalVariableType[] getLocalVariableTypes(String name) { return (LocalVariableType[]) getLocals(name); } /** * Import a local from another method/class. Note that * the program counter and length from the given local is copied * directly, and thus will be incorrect unless this method is the same * as the one the local is copied from, or the pc and length are reset. */ public LocalVariableType addLocalVariableType(LocalVariableType local) { return (LocalVariableType) addLocal(local); } /** * Add a local to this table. */ public LocalVariableType addLocalVariableType() { return (LocalVariableType) addLocal(); } /** * Add a local to this table. */ public LocalVariableType addLocalVariableType(String name, String type) { return (LocalVariableType) addLocal(name, type); } public void acceptVisit(BCVisitor visit) { visit.enterLocalVariableTypeTable(this); LocalVariableType[] locals = (LocalVariableType[]) getLocals(); for (int i = 0; i < locals.length; i++) locals[i].acceptVisit(visit); visit.exitLocalVariableTypeTable(this); } protected Local newLocal() { return new LocalVariableType(this); } protected Local[] newLocalArray(int size) { return new LocalVariableType[size]; } } serp-1.14.1.orig/src/main/java/serp/bytecode/Annotation.java0000755000000000000000000007460510517502266020577 0ustar package serp.bytecode; import java.io.*; import java.lang.reflect.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * A declared annotation. * * @author Abe White */ public class Annotation implements BCEntity, VisitAcceptor { private static Method ENUM_VALUEOF = null; private static Method ENUM_NAME = null; static { try { Class c = Class.forName("java.lang.Enum"); ENUM_VALUEOF = c.getMethod("valueOf", new Class[] { Class.class, String.class }); ENUM_NAME = c.getMethod("name", (Class[]) null); } catch (Throwable t) { // pre-1.5 JDK } } private BCEntity _owner = null; private int _typeIndex = 0; private List _properties = null; Annotation(BCEntity owner) { _owner = owner; } /** * Annotations are stored in an {@link Annotations} table or as * part of an {@link Annotation} property value. */ public BCEntity getOwner() { return _owner; } void invalidate() { _owner = null; } /** * The index in the class {@link ConstantPool} of the * {@link UTF8Entry} holding the type of this annotation. */ public int getTypeIndex() { return _typeIndex; } /** * The index in the class {@link ConstantPool} of the * {@link UTF8Entry} holding the type of this annotation. */ public void setTypeIndex(int index) { _typeIndex = index; } /** * The name of this annotation's type. */ public String getTypeName() { String desc = ((UTF8Entry) getPool().getEntry(_typeIndex)).getValue(); return getProject().getNameCache().getExternalForm(desc, false); } /** * The {@link Class} object for this annotation's type. */ public Class getType() { return Strings.toClass(getTypeName(), getClassLoader()); } /** * The bytecode for the type of this annotation. */ public BCClass getTypeBC() { return getProject().loadClass(getTypeName(), getClassLoader()); } /** * This annotation's type. */ public void setType(String type) { type = getProject().getNameCache().getInternalForm(type, true); _typeIndex = getPool().findUTF8Entry(type, true); } /** * This annotation's type. */ public void setType(Class type) { setType(type.getName()); } /** * This annotation's type. */ public void setType(BCClass type) { setType(type.getName()); } /** * All declared properties. */ public Property[] getProperties() { if (_properties == null) return new Property[0]; return (Property[]) _properties.toArray (new Property[_properties.size()]); } /** * Set the annotation properties. This method is useful when * importing properties from another instance. */ public void setProperties(Property[] props) { clearProperties(); if (props != null) for (int i = 0; i < props.length; i++) addProperty(props[i]); } /** * Return the property with the given name, or null if none. */ public Property getProperty(String name) { if (_properties == null) return null; Property prop; for (int i = 0; i < _properties.size(); i++) { prop = (Property) _properties.get(i); if (prop.getName().equals(name)) return prop; } return null; } /** * Import a property from another instance. * * @return the newly added property */ public Property addProperty(Property p) { Property prop = addProperty(p.getName()); prop.setValue(p.getValue()); return prop; } /** * Add a new property. */ public Property addProperty(String name) { Property prop = new Property(this); prop.setName(name); if (_properties == null) _properties = new ArrayList(); _properties.add(prop); return prop; } /** * Clear all annotation properties. */ public void clearProperties() { if (_properties == null) return; for (int i = 0; i < _properties.size(); i++) ((Property) _properties.get(i)).invalidate(); _properties.clear(); } /** * Remove the given property. * * @return true if an property was removed, false otherwise */ public boolean removeProperty(Property prop) { return prop != null && removeProperty(prop.getName()); } /** * Remove the property with the given name. * * @return true if a property was removed, false otherwise */ public boolean removeProperty(String name) { if (name == null || _properties == null) return false; Property prop; for (int i = 0; i < _properties.size(); i++) { prop = (Property) _properties.get(i); if (prop.getName().equals(name)) { prop.invalidate(); _properties.remove(i); return true; } } return false; } public Project getProject() { return _owner.getProject(); } public ConstantPool getPool() { return _owner.getPool(); } public ClassLoader getClassLoader() { return _owner.getClassLoader(); } public boolean isValid() { return _owner != null; } public void acceptVisit(BCVisitor visit) { visit.enterAnnotation(this); if (_properties != null) for (int i = 0; i < _properties.size(); i++) ((Property) _properties.get(i)).acceptVisit(visit); visit.exitAnnotation(this); } int getLength() { int len = 4; if (_properties != null) for (int i = 0; i < _properties.size(); i++) len += ((Property) _properties.get(i)).getLength(); return len; } void read(DataInput in) throws IOException { _typeIndex = in.readUnsignedShort(); clearProperties(); int props = in.readUnsignedShort(); if (props > 0) { if (_properties == null) _properties = new ArrayList(props); Property prop; for (int i = 0; i < props; i++) { prop = new Property(this); prop.read(in); _properties.add(prop); } } } void write(DataOutput out) throws IOException { out.writeShort(_typeIndex); out.writeShort((_properties == null) ? 0 : _properties.size()); if (_properties != null) { for (int i = 0; i < _properties.size(); i++) ((Property) _properties.get(i)).write(out); } } /** * An annotation property. */ public static class Property implements BCEntity, VisitAcceptor { private Annotation _owner = null; private int _nameIndex = 0; private final Value _value = new Value(); private Value[] _values = null; Property(Annotation owner) { _owner = owner; } /** * The owning annotation. */ public Annotation getAnnotation() { return _owner; } void invalidate() { _owner = null; } /** * Return the index in the class {@link ConstantPool} of the * {@link UTF8Entry} holding the name of this property. */ public int getNameIndex() { return _nameIndex; } /** * Set the index in the class {@link ConstantPool} of the * {@link UTF8Entry} holding the name of this property. */ public void setNameIndex(int index) { _nameIndex = index; } /** * Return the name of this property. */ public String getName() { return ((UTF8Entry) getPool().getEntry(_nameIndex)).getValue(); } /** * Set the name of this property. */ public void setName(String name) { _nameIndex = getPool().findUTF8Entry(name, true); } /** * Return the value of the property as its wrapper type. * Returns class values as the class name. */ public Object getValue() { if (_values == null) return getValue(_value); Object[] vals = new Object[_values.length]; for (int i = 0; i < vals.length; i++) vals[i] = getValue(_values[i]); return vals; } /** * Extract the Java value. */ private Object getValue(Value val) { if (val.index == -1) return val.value; Object o = ((ConstantEntry) getPool().getEntry(val.index)). getConstant(); if (val.index2 != -1) { // enum value String e = getProject().getNameCache(). getExternalForm((String) o, false); String name = ((UTF8Entry) getPool().getEntry(val.index2)). getValue(); try { Class cls = Class.forName(e, true, getClassLoader()); return ENUM_VALUEOF.invoke(null, new Object[] {cls, name}); } catch (Throwable t) { return e + "." + name; } } if (val.type == null) return o; switch (val.type.getName().charAt(0)) { case 'b': if (val.type == boolean.class) return (((Number) o).intValue() != 0) ? Boolean.TRUE : Boolean.FALSE; return new Byte(((Number) o).byteValue()); case 'c': return new Character((char) ((Number) o).intValue()); case 'j': // java.lang.Class return getProject().getNameCache().getExternalForm((String) o, false); case 's': return new Short(((Number) o).shortValue()); default: return o; } } /** * Set value of this property. The value should be an instance of any * primitive wrapper type, String, Class, BCClass, an enum constant, * an annotation, or an array of any of these types. */ public void setValue(Object value) { if (!value.getClass().isArray()) { _values = null; setValue(_value, value); } else { _value.value = null; _values = new Value[Array.getLength(value)]; for (int i = 0; i < _values.length; i++) { _values[i] = new Value(); setValue(_values[i], Array.get(value, i)); } } } /** * Set the given value. */ private void setValue(Value val, Object o) { if (o instanceof String) setValue(val, (String) o); else if (o instanceof Boolean) setValue(val, ((Boolean) o).booleanValue()); else if (o instanceof Byte) setValue(val, ((Byte) o).byteValue()); else if (o instanceof Character) setValue(val, ((Character) o).charValue()); else if (o instanceof Double) setValue(val, ((Double) o).doubleValue()); else if (o instanceof Float) setValue(val, ((Float) o).floatValue()); else if (o instanceof Integer) setValue(val, ((Integer) o).intValue()); else if (o instanceof Long) setValue(val, ((Long) o).longValue()); else if (o instanceof Short) setValue(val, ((Short) o).shortValue()); else if (o instanceof Class) setClassNameValue(val, ((Class) o).getName()); else if (o instanceof BCClass) setClassNameValue(val, ((BCClass) o).getName()); else if (o instanceof Annotation) setValue(val, (Annotation) o); else { String name = getEnumName(o); if (name != null) { String type = getProject().getNameCache(). getInternalForm(o.getClass().getName(), false); val.index = getPool().findUTF8Entry(type, true); val.index2 = getPool().findUTF8Entry(name, true); val.value = null; val.type = null; } else { val.index = -1; val.index2 = -1; val.value = o; val.type = o.getClass(); } } } /** * Return the name of this enum value, or null if not an enum. */ private static String getEnumName(Object o) { for (Class c = o.getClass(); true; c = c.getSuperclass()) { if (c == Object.class || c == null) return null; if ("java.lang.Enum".equals(c.getName())) break; } try { return (String) ENUM_NAME.invoke(o, (Object[]) null); } catch (Throwable t) { return o.toString(); } } /** * Return the string value of this property, or null if not set. */ public String getStringValue() { return (String) getValue(); } /** * Return the boolean value of this property, or false if not set. */ public boolean getBooleanValue() { Object value = getValue(); return (value == null) ? false : ((Boolean) value).booleanValue(); } /** * Return the byte value of this property, or false if not set. */ public byte getByteValue() { Object value = getValue(); return (value == null) ? (byte) 0 : ((Number) value).byteValue(); } /** * Return the int value of this property, or 0 if not set. */ public int getIntValue() { Object value = getValue(); return (value == null) ? 0 : ((Number) value).intValue(); } /** * Return the long value of this property, or 0 if not set. */ public long getLongValue() { Object value = getValue(); return (value == null) ? 0L : ((Number) value).longValue(); } /** * Return the float value of this property, or 0 if not set. */ public float getFloatValue() { Object value = getValue(); return (value == null) ? 0F : ((Number) value).floatValue(); } /** * Return the double value of this property, or 0 if not set. */ public double getDoubleValue() { Object value = getValue(); return (value == null) ? 0D : ((Number) value).doubleValue(); } /** * Return the short value of this property, or 0 if not set. */ public short getShortValue() { Object value = getValue(); return (value == null) ? (short) 0 : ((Number) value).shortValue(); } /** * Return the class value of this property, or null if not set. */ public String getClassNameValue() { return (String) getValue(); } /** * Return the annotation value of this property, or null if not set. */ public Annotation getAnnotationValue() { return (Annotation) getValue(); } /** * Set the string value of this property. */ public void setValue(String value) { _values = null; setValue(_value, value); } /** * Set the string value of this property. */ private void setValue(Value val, String o) { val.index = getPool().findUTF8Entry(o, true); val.index2 = -1; val.value = null; val.type = null; } /** * Set the boolean value of this property. */ public void setValue(boolean value) { _values = null; setValue(_value, value); } /** * Set the boolean value of this property. */ private void setValue(Value val, boolean o) { setValue(val, (o) ? 1 : 0); val.type = boolean.class; } /** * Set the byte value of this property. */ public void setValue(byte value) { _values = null; setValue(_value, value); } /** * Set the byte value of this property. */ private void setValue(Value val, byte o) { setValue(val, (int) o); val.type = byte.class; } /** * Set the int value of this property. */ public void setValue(int value) { _values = null; setValue(_value, value); } /** * Set the int value of this property. */ private void setValue(Value val, int o) { val.index = getPool().findIntEntry(o, true); val.index2 = -1; val.value = null; val.type = null; } /** * Set the long value of this property. */ public void setValue(long value) { _values = null; setValue(_value, value); } /** * Set the long value of this property. */ private void setValue(Value val, long o) { val.index = getPool().findLongEntry(o, true); val.index2 = -1; val.value = null; val.type = null; } /** * Set the float value of this property. */ public void setValue(float value) { _values = null; setValue(_value, value); } /** * Set the float value of this property. */ private void setValue(Value val, float o) { val.index = getPool().findFloatEntry(o, true); val.index2 = -1; val.value = null; val.type = null; } /** * Set the double value of this property. */ public void setValue(double value) { _values = null; setValue(_value, value); } /** * Set the double value of this property. */ private void setValue(Value val, double o) { val.index = getPool().findDoubleEntry(o, true); val.index2 = -1; val.value = null; val.type = null; } /** * Set the short value of this property. */ public void setValue(short value) { _values = null; setValue(_value, value); } /** * Set the short value of this property. */ private void setValue(Value val, short o) { setValue(val, (int) o); val.type = short.class; } /** * Set the class value of this property. */ public void setValue(Class value) { setClassNameValue(value.getName()); } /** * Set the class value of this property. */ public void setValue(BCClass value) { setClassNameValue(value.getName()); } /** * Set the class value of this property. */ public void setClassNameValue(String value) { _values = null; setClassNameValue(_value, value); } /** * Set the class value of this property. */ private void setClassNameValue(Value val, String o) { o = getProject().getNameCache().getInternalForm(o, true); val.index = getPool().findUTF8Entry(o, true); val.index2 = -1; val.value = null; val.type = Class.class; } /** * Set the annotation value of this property by importing the given * annotation from another instance. */ public Annotation setValue(Annotation value) { _values = null; return setValue(_value, value); } /** * Set the annotation value of this property by importing the given * annotation from another instance. */ private Annotation setValue(Value val, Annotation o) { Annotation anno = new Annotation(this); anno.setType(o.getTypeName()); anno.setProperties(o.getProperties()); val.index = -1; val.index2 = -1; val.value = anno; val.type = null; return anno; } /** * Set the annotation value of this property by importing the given * annotation from another instance. */ public Annotation[] setValue(Annotation[] value) { _value.value = null; _values = new Value[value.length]; Annotation[] ret = new Annotation[value.length]; for (int i = 0; i < _values.length; i++) { _values[i] = new Value(); ret[i] = setValue(_values[i], value[i]); } return ret; } /** * Set this property value to a new annotation of the given type, * returning the annotation for manipulation. */ public Annotation newAnnotationValue(Class type) { return newAnnotationValue(type.getName()); } /** * Set this property value to a new annotation of the given type, * returning the annotation for manipulation. */ public Annotation newAnnotationValue(BCClass type) { return newAnnotationValue(type.getName()); } /** * Set this property value to a new annotation of the given type, * returning the annotation for manipulation. */ public Annotation newAnnotationValue(String type) { Annotation anno = new Annotation(this); anno.setType(type); _values = null; _value.index = -1; _value.index2 = -1; _value.value = anno; _value.type = null; return anno; } /** * Set this property value to a new annotation array of the given type * and length, returning the annotations for manipulation. */ public Annotation[] newAnnotationArrayValue(Class type, int length) { return newAnnotationArrayValue(type.getName(), length); } /** * Set this property value to a new annotation array of the given type * and length, returning the annotations for manipulation. */ public Annotation[] newAnnotationArrayValue(BCClass type, int length) { return newAnnotationArrayValue(type.getName(), length); } /** * Set this property value to a new annotation array of the given type * and length, returning the annotations for manipulation. */ public Annotation[] newAnnotationArrayValue(String type, int length) { _value.value = null; _values = new Value[length]; Annotation[] ret = new Annotation[length]; for (int i = 0; i < length; i++) { ret[i] = new Annotation(this); ret[i].setType(type); _values[i] = new Value(); _values[i].index = -1; _values[i].index2 = -1; _values[i].value = ret[i]; _values[i].type = null; } return ret; } public Project getProject() { return _owner.getProject(); } public ConstantPool getPool() { return _owner.getPool(); } public ClassLoader getClassLoader() { return _owner.getClassLoader(); } public boolean isValid() { return _owner != null && (_values != null || _value.index != -1 || _value.value != null); } public void acceptVisit(BCVisitor visit) { visit.enterAnnotationProperty(this); visit.exitAnnotationProperty(this); } int getLength() { if (!isValid()) throw new IllegalStateException(); int len = 2; // name if (_values == null) len += getLength(_value); else { len += 3; // arr length + tag for (int i = 0; i < _values.length; i++) len += getLength(_values[i]); } return len; } /** * Return the length of the given value. */ private int getLength(Value val) { if (val.index2 != -1) return 5; // tag + enum type + enum name if (val.index != -1) return 3; // tag + constant or class return 1 + ((Annotation) val.value).getLength(); // tag + anno } void read(DataInput in) throws IOException { _nameIndex = in.readUnsignedShort(); int tag = in.readByte(); if (tag == '[') { int len = in.readUnsignedShort(); _values = new Value[len]; for (int i = 0; i < len; i++) { _values[i] = new Value(); read(_values[i], in.readByte(), in); } } else read(_value, tag, in); } /** * Read data into the given value. */ private void read(Value val, int tag, DataInput in) throws IOException { switch (tag) { case 'B': val.index = in.readUnsignedShort(); val.index2 = -1; val.value = null; val.type = byte.class; break; case 'C': val.index = in.readUnsignedShort(); val.index2 = -1; val.value = null; val.type = char.class; break; case 'D': case 'F': case 'I': case 'J': case 'S': case 's': val.index = in.readUnsignedShort(); val.index2 = -1; val.value = null; val.type = null; break; case 'Z': val.index = in.readUnsignedShort(); val.index2 = -1; val.value = null; val.type = boolean.class; break; case 'c': val.index = in.readUnsignedShort(); val.index2 = -1; val.value = null; val.type = Class.class; break; case 'e': val.index = in.readUnsignedShort(); val.index2 = in.readUnsignedShort(); val.value = null; val.type = null; break; case '@': Annotation anno = new Annotation(this); anno.read(in); val.index = -1; val.index2 = -1; val.value = anno; val.type = null; break; default: throw new IllegalStateException(String.valueOf(tag)); } } void write(DataOutput out) throws IOException { if (!isValid()) throw new IllegalStateException(); out.writeShort(_nameIndex); if (_values == null) write(_value, out); else { out.writeByte('['); out.writeShort(_values.length); for (int i = 0; i < _values.length; i++) write(_values[i], out); } } /** * Write the data for the given value to the stream. */ private void write(Value val, DataOutput out) throws IOException { if (val.index2 != -1) { out.writeByte('e'); out.writeShort(val.index); out.writeShort(val.index2); } else if (val.index != -1) { if (val.type != null) { switch (val.type.getName().charAt(0)) { case 'b': if (val.type == byte.class) out.writeByte('B'); else out.writeByte('Z'); break; case 'c': out.writeByte('C'); break; case 'j': // java.lang.Class out.writeByte('c'); break; case 's': out.writeByte('S'); break; default: throw new IllegalStateException(val.type.getName()); } } else { Entry entry = getPool().getEntry(val.index); if (entry instanceof DoubleEntry) out.writeByte('D'); else if (entry instanceof FloatEntry) out.writeByte('F'); else if (entry instanceof IntEntry) out.writeByte('I'); else if (entry instanceof LongEntry) out.writeByte('J'); else if (entry instanceof UTF8Entry) out.writeByte('s'); else throw new IllegalStateException(entry.getClass(). getName()); } out.writeShort(val.index); } else { out.writeByte('@'); ((Annotation) val.value).write(out); } } /** * Property value struct. */ private static class Value { public int index = -1; public int index2 = -1; public Class type = null; public Object value = null; } } } serp-1.14.1.orig/src/main/java/serp/bytecode/ArrayState.java0000755000000000000000000000275410660077275020546 0ustar package serp.bytecode; import java.util.*; /** * State implementing the behavior of an array class. * * @author Abe White */ class ArrayState extends State { private String _name = null; private String _componentName = null; public ArrayState(String name, String componentName) { _name = name; _componentName = componentName; } public int getMagic() { return Constants.VALID_MAGIC; } public int getMajorVersion() { return Constants.MAJOR_VERSION; } public int getMinorVersion() { return Constants.MINOR_VERSION; } public int getAccessFlags() { return Constants.ACCESS_PUBLIC | Constants.ACCESS_FINAL; } public int getIndex() { return 0; } public int getSuperclassIndex() { return 0; } public List getInterfacesHolder() { return Collections.EMPTY_LIST; } public List getFieldsHolder() { return Collections.EMPTY_LIST; } public List getMethodsHolder() { return Collections.EMPTY_LIST; } public Collection getAttributesHolder() { return Collections.EMPTY_LIST; } public String getName() { return _name; } public String getSuperclassName() { return Object.class.getName(); } public String getComponentName() { return _componentName; } public boolean isPrimitive() { return false; } public boolean isArray() { return true; } } serp-1.14.1.orig/src/main/java/serp/bytecode/NameCache.java0000755000000000000000000001766610460270414020267 0ustar package serp.bytecode; import java.util.*; /** * Caching and conversion of names in both internal and external form. * * @author Abe White */ public class NameCache { static final Object[][] _codes = new Object[][] { { byte.class, "B" }, { char.class, "C" }, { double.class, "D" }, { float.class, "F" }, { int.class, "I" }, { long.class, "J" }, { short.class, "S" }, { boolean.class, "Z" }, { void.class, "V" }, }; // caches of internal and external forms of strings private final Map _internal = new HashMap(); private final Map _internalDescriptor = new HashMap(); private final Map _external = new HashMap(); private final Map _externalHuman = new HashMap(); /** * Converts the given class name to its internal form. * * @param className the name to convert * @param descriptor true if the name is to be used for a descriptor * section -- the difference seems to be that for * descriptors, non-primitives are prefixed with 'L' and ended with ';' */ public String getInternalForm(String className, boolean descriptor) { if (className == null || className.length() == 0) return className; Map cache = (descriptor) ? _internalDescriptor : _internal; String cached = (String) cache.get(className); if (cached != null) return cached; String ret = getInternalFormInternal(className, descriptor); cache.put(className, ret); return ret; } /** * @see #getInternalForm */ private String getInternalFormInternal(String cls, boolean descriptor) { // handle array types, whether already in internal form or not StringBuffer prefix = new StringBuffer(); while (true) { if (cls.endsWith("[]")) { prefix.append("["); cls = cls.substring(0, cls.length() - 2); } else if (cls.startsWith("[")) { prefix.append("["); cls = cls.substring(1); } else break; } // handle primitive array types for (int i = 0; i < _codes.length; i++) if (cls.equals(_codes[i][1].toString()) || cls.equals(_codes[i][0].toString())) return prefix.append(_codes[i][1]).toString(); // if in descriptor form, strip leading 'L' and trailing ';' if (cls.startsWith("L") && cls.endsWith(";")) cls = cls.substring(1, cls.length() - 1); // non-primitive; make sure we don't prefix method descriptors with 'L' cls = cls.replace('.', '/'); if ((descriptor || prefix.length() > 0) && cls.charAt(0) != '(') return prefix.append("L").append(cls).append(";").toString(); return prefix.append(cls).toString(); } /** * Given the internal name of the class, return the 'normal' java name. * * @param internalName the internal name being used * @param humanReadable if the returned name should be in human-readable * form, rather than a form suitable for a * {@link Class#forName} call -- the difference * lies in the handling of arrays */ public String getExternalForm(String internalName, boolean humanReadable) { if (internalName == null || internalName.length() == 0) return internalName; Map cache = (humanReadable) ? _externalHuman : _external; String cached = (String) cache.get(internalName); if (cached != null) return cached; String ret = getExternalFormInternal(internalName, humanReadable); cache.put(internalName, ret); return ret; } /** * @see #getExternalForm */ private String getExternalFormInternal(String intern, boolean humanReadable) { if (!humanReadable) { // check against primitives for (int i = 0; i < _codes.length; i++) { if (intern.equals(_codes[i][1].toString())) return _codes[i][0].toString(); if (intern.equals(_codes[i][0].toString())) return intern; } intern = getInternalForm(intern, false); return intern.replace('/', '.'); } // handle arrays StringBuffer postfix = new StringBuffer(2); while (intern.startsWith("[")) { intern = intern.substring(1); postfix.append("[]"); } // strip off leading 'L' and trailing ';' if (intern.endsWith(";")) intern = intern.substring(1, intern.length() - 1); // check primitives for (int i = 0; i < _codes.length; i++) if (intern.equals(_codes[i][1].toString())) return _codes[i][0].toString() + postfix; return intern.replace('/', '.') + postfix; } /** * Construct a method descriptor from the given return and parameter * types, which will be converted to internal form. */ public String getDescriptor(String returnType, String[] paramTypes) { StringBuffer buf = new StringBuffer(); buf.append("("); if (paramTypes != null) { for (int i = 0; i < paramTypes.length; i++) { if (paramTypes[i] == null) throw new NullPointerException("paramTypes[" + i + "] = null"); buf.append(getInternalForm(paramTypes[i], true)); } } buf.append(")"); if (returnType == null) throw new NullPointerException("returnType = null"); buf.append(getInternalForm(returnType, true)); return buf.toString(); } /** * Return the return type, in internal form, for the given method * descriptor string. */ public String getDescriptorReturnName(String descriptor) { int index = descriptor.indexOf(')'); if (index == -1) return ""; return descriptor.substring(descriptor.indexOf(')') + 1); } /** * Return the parameter types, in internal form, for the given method * descriptor string. */ public String[] getDescriptorParamNames(String descriptor) { if (descriptor == null || descriptor.length() == 0) return new String[0]; int index = descriptor.indexOf(')'); if (index == -1) return new String[0]; // get rid of the parens and the return type descriptor = descriptor.substring(1, index); // break the param string into individual params List tokens = new LinkedList(); while (descriptor.length() > 0) { index = 0; // skip the '[' up to the first letter code while (!Character.isLetter(descriptor.charAt(index))) index++; // non-primitives always start with 'L' and end with ';' if (descriptor.charAt(index) == 'L') index = descriptor.indexOf(';'); tokens.add(descriptor.substring(0, index + 1)); descriptor = descriptor.substring(index + 1); } return (String[]) tokens.toArray(new String[tokens.size()]); } /** * Return the component type name for the given array type, or null * if the given string does not represent an array type name. The name * given should be in proper {@link Class#forName} form. */ public String getComponentName(String name) { if (name == null || !name.startsWith("[")) return null; name = name.substring(1); if (!name.startsWith("[") && name.endsWith(";")) name = name.substring(1, name.length() - 1); // will convert primitive type codes to names return getExternalForm(name, false); } /** * Clear the cache. */ public void clear() { _internal.clear(); _internalDescriptor.clear(); _external.clear(); _externalHuman.clear(); } } serp-1.14.1.orig/src/main/java/serp/bytecode/Annotations.java0000755000000000000000000001237110517502266020752 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * Java annotation data. * * @author Abe White */ public class Annotations extends Attribute { private final List _annotations = new ArrayList(); Annotations(int nameIndex, Attributes owner) { super(nameIndex, owner); } /** * Whether these annotations are runtime-visible. */ public boolean isRuntime() { return getName().equals(Constants.ATTR_RUNTIME_ANNOTATIONS); } /** * All declared annotations. */ public Annotation[] getAnnotations() { return (Annotation[]) _annotations.toArray (new Annotation[_annotations.size()]); } /** * Set the annotations. This method is useful when * importing annotations from another instance. */ public void setAnnotations(Annotation[] annos) { clear(); if (annos != null) for (int i = 0; i < annos.length; i++) addAnnotation(annos[i]); } /** * Return the annotation of the given type, or null if none. */ public Annotation getAnnotation(Class type) { return (type == null) ? null : getAnnotation(type.getName()); } /** * Return the annotation of the given type, or null if none. */ public Annotation getAnnotation(BCClass type) { return (type == null) ? null : getAnnotation(type.getName()); } /** * Return the annotation of the given type, or null if none. */ public Annotation getAnnotation(String type) { Annotation anno; for (int i = 0; i < _annotations.size(); i++) { anno = (Annotation) _annotations.get(i); if (anno.getTypeName().equals(type)) return anno; } return null; } /** * Import an annotation from another instance. * * @return the newly added annotation */ public Annotation addAnnotation(Annotation an) { Annotation anno = addAnnotation(an.getTypeName()); anno.setProperties(an.getProperties()); return anno; } /** * Add a new annotation. */ public Annotation addAnnotation(Class type) { return addAnnotation(type.getName()); } /** * Add a new annotation. */ public Annotation addAnnotation(BCClass type) { return addAnnotation(type.getName()); } /** * Add a new annotation. */ public Annotation addAnnotation(String type) { Annotation anno = new Annotation(this); anno.setType(type); _annotations.add(anno); return anno; } /** * Remove all annotations. */ public void clear() { for (int i = 0; i < _annotations.size(); i++) ((Annotation) _annotations.get(i)).invalidate(); _annotations.clear(); } /** * Remove the given annotation. * * @return true if an annotation was removed, false otherwise */ public boolean removeAnnotation(Annotation anno) { return anno != null && removeAnnotation(anno.getTypeName()); } /** * Remove the annotation of the given type. * * @return true if an annotation was removed, false otherwise */ public boolean removeAnnotation(Class type) { return type != null && removeAnnotation(type.getName()); } /** * Remove the annotation of the given type. * * @return true if an annotation was removed, false otherwise */ public boolean removeAnnotation(BCClass type) { return type != null && removeAnnotation(type.getName()); } /** * Remove the annotation of the given type. * * @return true if an annotation was removed, false otherwise */ public boolean removeAnnotation(String type) { if (type == null) return false; Annotation anno; for (int i = 0; i < _annotations.size(); i++) { anno = (Annotation) _annotations.get(i); if (anno.getTypeName().equals(type)) { anno.invalidate(); _annotations.remove(i); return true; } } return false; } int getLength() { int len = 2; for (int i = 0; i < _annotations.size(); i++) len += ((Annotation) _annotations.get(i)).getLength(); return len; } void read(Attribute other) { setAnnotations(((Annotations) other).getAnnotations()); } void read(DataInput in, int length) throws IOException { _annotations.clear(); int annos = in.readUnsignedShort(); Annotation anno; for (int i = 0; i < annos; i++) { anno = new Annotation(this); anno.read(in); _annotations.add(anno); } } void write(DataOutput out, int length) throws IOException { out.writeShort(_annotations.size()); for (int i = 0; i < _annotations.size(); i++) ((Annotation) _annotations.get(i)).write(out); } public void acceptVisit(BCVisitor visit) { visit.enterAnnotations(this); for (int i = 0; i < _annotations.size(); i++) ((Annotation) _annotations.get(i)).acceptVisit(visit); visit.exitAnnotations(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/InnerClass.java0000755000000000000000000003076710517502266020527 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * Any referenced class that is not a package member is represented by * this structure. This includes member classes and interfaces. * * @author Abe White */ public class InnerClass implements BCEntity, VisitAcceptor { private int _index = 0; private int _nameIndex = 0; private int _ownerIndex = 0; private int _access = Constants.ACCESS_PRIVATE; private InnerClasses _owner = null; InnerClass(InnerClasses owner) { _owner = owner; } /** * Inner classes are stored in an {@link InnerClasses} attribute. */ public InnerClasses getOwner() { return _owner; } void invalidate() { _owner = null; } ///////////////////// // Access operations ///////////////////// /** * Return the access flags of the inner class. */ public int getAccessFlags() { return _access; } /** * Set the access flags of the inner class. */ public void setAccessFlags(int accessFlags) { _access = accessFlags; } /** * Manipulate the inner class access flags. */ public boolean isPublic() { return (getAccessFlags() & Constants.ACCESS_PUBLIC) > 0; } /** * Manipulate the inner class access flags. */ public void makePublic() { setAccessFlags(getAccessFlags() | Constants.ACCESS_PUBLIC); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PRIVATE); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PROTECTED); } /** * Manipulate the inner class access flags. */ public boolean isProtected() { return (getAccessFlags() & Constants.ACCESS_PROTECTED) > 0; } /** * Manipulate the inner class access flags. */ public void makeProtected() { setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PRIVATE); setAccessFlags(getAccessFlags() | Constants.ACCESS_PROTECTED); } /** * Manipulate the inner class access flags. */ public boolean isPrivate() { return (getAccessFlags() & Constants.ACCESS_PRIVATE) > 0; } /** * Manipulate the inner class access flags. */ public void makePrivate() { setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC); setAccessFlags(getAccessFlags() | Constants.ACCESS_PRIVATE); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PROTECTED); } /** * Manipulate the inner class access flags. */ public boolean isFinal() { return (getAccessFlags() & Constants.ACCESS_FINAL) > 0; } /** * Manipulate the inner class access flags. */ public void setFinal(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_FINAL); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_FINAL); } /** * Manipulate the inner class access flags. */ public boolean isStatic() { return (getAccessFlags() & Constants.ACCESS_STATIC) > 0; } /** * Manipulate the inner class access flags. */ public void setStatic(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_STATIC); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_STATIC); } /** * Manipulate the class access flags. */ public boolean isInterface() { return (getAccessFlags() & Constants.ACCESS_INTERFACE) > 0; } /** * Manipulate the class access flags. */ public void setInterface(boolean on) { if (on) { setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE); setAbstract(true); } else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_INTERFACE); } /** * Manipulate the class access flags. */ public boolean isAbstract() { return (getAccessFlags() & Constants.ACCESS_ABSTRACT) > 0; } /** * Manipulate the class access flags. */ public void setAbstract(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_INTERFACE); } /** * Manipulate the inner class access flags. */ public boolean isSynthetic() { return (getAccessFlags() & Constants.ACCESS_SYNTHETIC) > 0; } /** * Manipulate the inner class access flags. */ public void setSynthetic(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_SYNTHETIC); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_SYNTHETIC); } /** * Manipulate the inner class access flags. */ public boolean isAnnotation() { return (getAccessFlags() & Constants.ACCESS_ANNOTATION) > 0; } /** * Manipulate the inner class access flags. Setting to true also makes this * an interface. */ public void setAnnotation(boolean on) { if (on) { setAccessFlags(getAccessFlags() | Constants.ACCESS_ANNOTATION); setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE); } else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ANNOTATION); } /** * Manipulate the inner class access flags. */ public boolean isEnum() { return (getAccessFlags() & Constants.ACCESS_ENUM) > 0; } /** * Manipulate the inner class access flags. */ public void setEnum(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_ENUM); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ENUM); } //////////////////////////////// // Name, type, owner operations //////////////////////////////// /** * Return the {@link ConstantPool} index of the {@link UTF8Entry} that * describes the simple name this class is referred to in source, or * 0 for anonymous classes. */ public int getNameIndex() { return _nameIndex; } /** * Set the {@link ConstantPool} index of the {@link UTF8Entry} that * describes the simple name this class is referred to in source, or * 0 for anonymous classes. */ public void setNameIndex(int nameIndex) { _nameIndex = nameIndex; } /** * Return the simple name of this inner class, or null if anonymous. */ public String getName() { if (getNameIndex() == 0) return null; return ((UTF8Entry) getPool().getEntry(getNameIndex())).getValue(); } /** * Set the simple name of this inner class. */ public void setName(String name) { if (name == null) setNameIndex(0); else setNameIndex(getPool().findUTF8Entry(name, true)); } /** * Return the {@link ConstantPool} index of the {@link ClassEntry} that * describes this class, or 0 if none. */ public int getTypeIndex() { return _index; } /** * Set the {@link ConstantPool} index of the {@link ClassEntry} that * describes this class. */ public void setTypeIndex(int index) { _index = index; } /** * Return the full name of the inner class, or null if unset. */ public String getTypeName() { if (getTypeIndex() == 0) return null; ClassEntry entry = (ClassEntry) getPool().getEntry(getTypeIndex()); return getProject().getNameCache().getExternalForm(entry.getNameEntry(). getValue(), false); } /** * Return the type of the inner class. * If the type has not been set, this method will return null. */ public Class getType() { String type = getTypeName(); if (type == null) return null; return Strings.toClass(type, getClassLoader()); } /** * Return the type for this instruction. * If the type has not been set, this method will return null. */ public BCClass getTypeBC() { String type = getTypeName(); if (type == null) return null; return getProject().loadClass(type, getClassLoader()); } /** * Set the type of this inner class. */ public void setType(String type) { if (type == null) setTypeIndex(0); else { type = getProject().getNameCache().getInternalForm(type, false); setTypeIndex(getPool().findClassEntry(type, true)); } } /** * Set the type of this inner class. */ public void setType(Class type) { if (type == null) setType((String) null); else setType(type.getName()); } /** * Set the type of this inner class. */ public void setType(BCClass type) { if (type == null) setType((String) null); else setType(type.getName()); } /** * Return the {@link ConstantPool} index of the {@link ClassEntry} that * describes the declaring class, or 0 if this class is not a member class. */ public int getDeclarerIndex() { return _ownerIndex; } /** * Set the {@link ConstantPool} index of the {@link ClassEntry} that * describes the declaring class, or 0 if this class is not a member class. */ public void setDeclarerIndex(int ownerIndex) { _ownerIndex = ownerIndex; } /** * Return the full name of the declaring class, or null if unset/not a * member. */ public String getDeclarerName() { if (getDeclarerIndex() == 0) return null; ClassEntry entry = (ClassEntry) getPool().getEntry(getDeclarerIndex()); return getProject().getNameCache().getExternalForm(entry.getNameEntry(). getValue(), false); } /** * Return the type of the declaring class. * If the type has not been set or the class is not a member, this method * will return null. */ public Class getDeclarerType() { String type = getDeclarerName(); if (type == null) return null; return Strings.toClass(type, getClassLoader()); } /** * Return the type for this instruction. * If the type has not been set or the class is not a member, this method * will return null. */ public BCClass getDeclarerBC() { String type = getDeclarerName(); if (type == null) return null; return getProject().loadClass(type, getClassLoader()); } /** * Set the type of this declaring class. */ public void setDeclarer(String type) { if (type == null) setDeclarerIndex(0); else { type = getProject().getNameCache().getInternalForm(type, false); setDeclarerIndex(getPool().findClassEntry(type, true)); } } /** * Set the type of this declaring class. */ public void setDeclarer(Class type) { if (type == null) setDeclarer((String) null); else setDeclarer(type.getName()); } /** * Set the type of this declaring class. */ public void setDeclarer(BCClass type) { if (type == null) setDeclarer((String) null); else setDeclarer(type.getName()); } /////////////////////////// // BCEntity implementation /////////////////////////// public Project getProject() { return _owner.getProject(); } public ConstantPool getPool() { return _owner.getPool(); } public ClassLoader getClassLoader() { return _owner.getClassLoader(); } public boolean isValid() { return _owner != null; } public void acceptVisit(BCVisitor visit) { visit.enterInnerClass(this); visit.exitInnerClass(this); } ////////////////// // I/O operations ////////////////// void read(DataInput in) throws IOException { setTypeIndex(in.readUnsignedShort()); setDeclarerIndex(in.readUnsignedShort()); setNameIndex(in.readUnsignedShort()); setAccessFlags(in.readUnsignedShort()); } void write(DataOutput out) throws IOException { out.writeShort(getTypeIndex()); out.writeShort(getDeclarerIndex()); out.writeShort(getNameIndex()); out.writeShort(getAccessFlags()); } } serp-1.14.1.orig/src/main/java/serp/bytecode/Project.java0000755000000000000000000002713210460270414020056 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * The Project represents a working set of classes. It caches parsed * bytecode and is responsible for bytecode class creation. Currently * changes made in one class are not reflected in other * classes, though this will be an option in the future. * *

Bytecode that has been parsed is held in a cache so that retrieving * a class with the same name multiple times always returns the same * {@link BCClass} instance.

* *

A future goal is to eventually have facilities for traversing jars * or directory structures to find classes that meet a given criteria (such * as implementing a given interface, etc) and to perform operations on entire * projects, similar to aspect-oriented programming.

* * @author Abe White */ public class Project implements VisitAcceptor { private final String _name; private final HashMap _cache = new HashMap(); private final NameCache _names = new NameCache(); /** * Default constructor. */ public Project() { this(null); } /** * Construct a named project. */ public Project(String name) { _name = name; } /** * Return the project name, or null if unset. */ public String getName() { return _name; } /** * Return the name cache, which includes utilities for converting names * from internal to external form and vice versa. */ public NameCache getNameCache() { return _names; } /** * Load a class with the given name. * * @see #loadClass(String,ClassLoader) */ public BCClass loadClass(String name) { return loadClass(name, null); } /** * Load the bytecode for the class with the given name. * If a {@link BCClass} with the given name already exists in this project, * it will be returned. Otherwise, a new {@link BCClass} will be created * with the given name and returned. If the name represents an existing * type, the returned instance will contain the parsed bytecode for * that type. If the name is of a primitive or array type, the returned * instance will act accordingly. * * @param name the name of the class, including package * @param loader the class loader to use to search for an existing * class with the given name; if null defaults to the * context loader of the current thread * @throws RuntimeException on parse error */ public BCClass loadClass(String name, ClassLoader loader) { // convert to proper Class.forName() form name = _names.getExternalForm(name, false); BCClass cached = checkCache(name); if (cached != null) return cached; // check for existing type if (loader == null) loader = Thread.currentThread().getContextClassLoader(); try { return loadClass(Strings.toClass(name, loader)); } catch (Exception e) { } String componentName = _names.getComponentName(name); BCClass ret = new BCClass(this); if (componentName != null) ret.setState(new ArrayState(name, componentName)); else { ret.setState(new ObjectState(_names)); ret.setName(name); ret.setSuperclass(Object.class); } cache(name, ret); return ret; } /** * Load the bytecode for the given class. * If a {@link BCClass} with the name of the given class already exists in * this project, it will be returned. Otherwise, the bytecode of the given * class will be parsed and returned as a new {@link BCClass}. If the * given class is an array or primitive type, the returned instance will * act accordingly. * * @param type the class to parse * @throws RuntimeException on parse error */ public BCClass loadClass(Class type) { BCClass cached = checkCache(type.getName()); if (cached != null) return cached; BCClass ret = new BCClass(this); if (type.isPrimitive()) ret.setState(new PrimitiveState(type, _names)); else if (type.isArray()) ret.setState(new ArrayState(type.getName(), _names.getExternalForm (type.getComponentType().getName(), false))); else { ret.setState(new ObjectState(_names)); try { ret.read(type); } catch (IOException ioe) { throw new RuntimeException(ioe.toString()); } } cache(type.getName(), ret); return ret; } /** * Load the bytecode from the given class file. * If this project already contains the class in the given file, it will * be returned. Otherwise a new {@link BCClass} will be created from the * given bytecode. * * @throws RuntimeException on parse error */ public BCClass loadClass(File classFile) { return loadClass(classFile, null); } /** * Load the bytecode from the given class file. * If this project already contains the class in the given file, it will * be returned. Otherwise a new {@link BCClass} will be created from the * given bytecode. * * @throws RuntimeException on parse error */ public BCClass loadClass(File classFile, ClassLoader loader) { // parse the bytecode from the file BCClass ret = new BCClass(this); ret.setState(new ObjectState(_names)); try { ret.read(classFile, loader); } catch (IOException ioe) { throw new RuntimeException(ioe.toString()); } String name = ret.getName(); BCClass cached = checkCache(name); if (cached != null) return cached; cache(name, ret); return ret; } /** * Load the bytecode from the given stream. * If this project already contains the class in the given stream, * it will be returned. Otherwise a new {@link BCClass} will be created * from the given bytecode. * * @throws RuntimeException on parse error */ public BCClass loadClass(InputStream in) { return loadClass(in, null); } /** * Load the bytecode from the given stream. * If this project already contains the class in the given stream, * it will be returned. Otherwise a new {@link BCClass} will be created * from the given bytecode. * * @throws RuntimeException on parse error */ public BCClass loadClass(InputStream in, ClassLoader loader) { BCClass ret = new BCClass(this); ret.setState(new ObjectState(_names)); try { ret.read(in, loader); } catch (IOException ioe) { throw new RuntimeException(ioe.toString()); } String name = ret.getName(); BCClass cached = checkCache(name); if (cached != null) return cached; cache(name, ret); return ret; } /** * Import the given bytecode from another project. If a {@link BCClass} * with the same name already exists in this project, it will be returned. * Otherwise, a new {@link BCClass} will be created from the * information in the given class. */ public BCClass loadClass(BCClass bc) { String name = bc.getName(); BCClass cached = checkCache(name); if (cached != null) return cached; BCClass ret = new BCClass(this); if (bc.isPrimitive()) ret.setState(new PrimitiveState(bc.getType(), _names)); else if (bc.isArray()) ret.setState(new ArrayState(bc.getName(), bc.getComponentName())); else { ret.setState(new ObjectState(_names)); ret.read(bc); } cache(name, ret); return ret; } /** * Clears all classes from this project. */ public void clear() { Collection values = _cache.values(); BCClass bc; for (Iterator itr = values.iterator(); itr.hasNext();) { bc = (BCClass) itr.next(); itr.remove(); bc.invalidate(); } _names.clear(); } /** * Remove a class from this project. After removal, the result of any * further operations on the class is undefined. * * @return true if the class belonged to this project, false otherwise */ public boolean removeClass(String type) { return removeClass(checkCache(type)); } /** * Remove a class from this project. After removal, the result of any * further operations on the class is undefined. * * @return true if the class belonged to this project, false otherwise */ public boolean removeClass(Class type) { if (type == null) return false; return removeClass(checkCache(type.getName())); } /** * Remove a class from this project. After removal, the result of any * further operations on the class is undefined. * * @return true if the class belonged to this project, false otherwise */ public boolean removeClass(BCClass type) { if (type == null) return false; if (!removeFromCache(type.getName(), type)) return false; type.invalidate(); return true; } /** * Return all loaded classes in the project. */ public BCClass[] getClasses() { Collection values = _cache.values(); return (BCClass[]) values.toArray(new BCClass[values.size()]); } /** * Return true if the project already contains the given class. */ public boolean containsClass(String type) { return _cache.containsKey(type); } /** * Return true if the project already contains the given class. */ public boolean containsClass(Class type) { return (type == null) ? false : containsClass(type.getName()); } /** * Return true if the project already contains the given class. */ public boolean containsClass(BCClass type) { return (type == null) ? false : containsClass(type.getName()); } public void acceptVisit(BCVisitor visit) { visit.enterProject(this); BCClass[] classes = getClasses(); for (int i = 0; i < classes.length; i++) classes[i].acceptVisit(visit); visit.exitProject(this); } /** * Renames the given class within this project. Used internally by * {@link BCClass} instances when their name is modified. * * @throws IllegalStateException if a class with the new name already exists */ void renameClass(String oldName, String newName, BCClass bc) { if (oldName.equals(newName)) return; BCClass cached = (BCClass) checkCache(newName); if (cached != null) throw new IllegalStateException("A class with name " + newName + " already exists in this project"); removeFromCache(oldName, bc); cache(newName, bc); } /** * Check the cache for a loaded type. */ private BCClass checkCache(String name) { return (BCClass) _cache.get(name); } /** * Cache a class. */ private void cache(String name, BCClass bc) { _cache.put(name, bc); } /** * Remove a cached class. */ private boolean removeFromCache(String name, BCClass bc) { BCClass rem = (BCClass) checkCache(name); if (rem != bc) return false; _cache.remove(name); return true; } } serp-1.14.1.orig/src/main/java/serp/bytecode/BCClassLoader.java0000755000000000000000000000305710460270414021051 0ustar package serp.bytecode; /** * Class loader that will attempt to find requested classes in a given * {@link Project}. * * @author Abe White */ public class BCClassLoader extends ClassLoader { private Project _project = null; /** * Constructor. Supply the project to use when looking for classes. */ public BCClassLoader(Project project) { _project = project; } /** * Constructor. Supply the project to use when looking for classes. * * @param parent the parent classoader */ public BCClassLoader(Project project, ClassLoader loader) { super(loader); _project = project; } /** * Return this class loader's project. */ public Project getProject() { return _project; } protected Class findClass(String name) throws ClassNotFoundException { byte[] bytes; try { BCClass type; if (!_project.containsClass(name)) type = createClass(name); else type = _project.loadClass(name); if (type == null) throw new ClassNotFoundException(name); bytes = type.toByteArray(); } catch (RuntimeException re) { throw new ClassNotFoundException(re.toString()); } return defineClass(name, bytes, 0, bytes.length); } /** * Override this method if unfound classes should be created on-the-fly. * Returns null by default. */ protected BCClass createClass(String name) { return null; } } serp-1.14.1.orig/src/main/java/serp/bytecode/ClassInstruction.java0000755000000000000000000000524510637750727022000 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; /** * An instruction that takes as an argument a class to operate * on. Examples include anewarray, checkcast, instance, anew, etc. * * @author Abe White */ public class ClassInstruction extends TypedInstruction { private int _index = 0; ClassInstruction(Code owner, int opcode) { super(owner, opcode); } public int getStackChange() { if (getOpcode() == Constants.NEW) return 1; return 0; } int getLength() { return super.getLength() + 2; } /** * Return the {@link ConstantPool} index of the * {@link ClassEntry} describing the class for this instruction. */ public int getTypeIndex() { return _index; } /** * Set the {@link ConstantPool} index of the * {@link 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) _index = 0; else { type = getProject().getNameCache().getInternalForm(type, false); _index = 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); _index = in.readUnsignedShort(); } void write(DataOutput out) throws IOException { super.write(out); out.writeShort(_index); } } serp-1.14.1.orig/src/main/java/serp/bytecode/BCClass.java0000755000000000000000000017117110660351262017730 0ustar package serp.bytecode; import java.io.*; import java.net.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * The BCClass represents a class object in the bytecode framework, in many * ways mirroring the {@link Class} class of Java reflection. The represented * class might be a primitive, array, existing object type, or some new user- * defined type. As with most entities in the bytecode framework, the BCClass * contains methods to manipulate the low-level state of the class (constant * pool indexes, etc), but these can and should be ignored in * favor of the available high-level methods. * *

A BCClass instance is loaded from a {@link Project} and remains * attached to that project for its lifetime. If a BCClass is removed from * its project, the result of any further operations on the class are * undefined.

* *

Note that if a BCClass represents a primitive or array type, all of the * available mutator methods and any methods that access the constant pool * will throw {@link UnsupportedOperationException}s.

* * @author Abe White */ public class BCClass extends Annotated implements VisitAcceptor { private Project _project = null; private State _state = null; private ClassLoader _loader = null; /** * Hide constructor. For use by the owning project only. */ BCClass(Project project) { _project = project; } /** * Set the class state. For use by the owning project only. */ void setState(State state) { _state = state; } /** * Invalidate this class. */ void invalidate() { _project = null; _state = State.INVALID; } ////////////////// // I/O operations ////////////////// /** * Initialize from the class definition in the given file. For use by * the owning project only. */ void read(File classFile, ClassLoader loader) throws IOException { InputStream in = new FileInputStream(classFile); try { read(in, loader); } finally { in.close(); } } /** * Initialize from the class definition in the given stream. For use by * the owning project only. */ void read(InputStream instream, ClassLoader loader) throws IOException { DataInput in = new DataInputStream(instream); // header information _state.setMagic(in.readInt()); _state.setMinorVersion(in.readUnsignedShort()); _state.setMajorVersion(in.readUnsignedShort()); // constant pool _state.getPool().read(in); // access flags _state.setAccessFlags(in.readUnsignedShort()); // class, super class, interfaces _state.setIndex(in.readUnsignedShort()); _state.setSuperclassIndex(in.readUnsignedShort()); List interfaces = _state.getInterfacesHolder(); interfaces.clear(); int interfaceCount = in.readUnsignedShort(); for (int i = 0; i < interfaceCount; i++) interfaces.add(Numbers.valueOf(in.readUnsignedShort())); // fields List fields = _state.getFieldsHolder(); fields.clear(); int fieldCount = in.readUnsignedShort(); BCField field; for (int i = 0; i < fieldCount; i++) { field = new BCField(this); fields.add(field); field.read(in); } // methods List methods = _state.getMethodsHolder(); methods.clear(); int methodCount = in.readUnsignedShort(); BCMethod method; for (int i = 0; i < methodCount; i++) { method = new BCMethod(this); methods.add(method); method.read(in); } readAttributes(in); _loader = loader; } /** * Initialize from the bytecode of the definition of the given class. * For use by the owning project only. */ void read(Class type) throws IOException { // find out the length of the package name int dotIndex = type.getName().lastIndexOf('.') + 1; // strip the package off of the class name String className = type.getName().substring(dotIndex); // attempt to get the class file for the class as a stream InputStream in = type.getResourceAsStream(className + ".class"); try { read(in, type.getClassLoader()); } finally { in.close(); } } /** * Initialize from the given parsed bytecode. * For use by the owning project only. */ void read(BCClass orig) { try { ByteArrayInputStream in = new ByteArrayInputStream (orig.toByteArray()); read(in, orig.getClassLoader()); in.close(); } catch (IOException ioe) { throw new RuntimeException(ioe.toString()); } } /** * Write the class bytecode to the .class file in the proper directory of * the CLASSPATH. The file must exist already, so this method only works * on existing classes. */ public void write() throws IOException { String name = getName(); int dotIndex = name.lastIndexOf('.') + 1; name = name.substring(dotIndex); Class type = getType(); // attempt to get the class file for the class as a stream; // we need to use the url decoder in case the target directory // has spaces in it OutputStream out = new FileOutputStream(URLDecoder.decode (type.getResource(name + ".class").getFile())); try { write(out); } finally { out.close(); } } /** * Write the class bytecode to the specified file. */ public void write(File classFile) throws IOException { OutputStream out = new FileOutputStream(classFile); try { write(out); } finally { out.close(); } } /** * Write the class bytecode to the specified stream. */ public void write(OutputStream outstream) throws IOException { DataOutput out = new DataOutputStream(outstream); // header information out.writeInt(_state.getMagic()); out.writeShort(_state.getMinorVersion()); out.writeShort(_state.getMajorVersion()); // constant pool _state.getPool().write(out); // access flags out.writeShort(_state.getAccessFlags()); // class, super class out.writeShort(_state.getIndex()); out.writeShort(_state.getSuperclassIndex()); // interfaces List interfaces = _state.getInterfacesHolder(); out.writeShort(interfaces.size()); for (Iterator itr = interfaces.iterator(); itr.hasNext();) out.writeShort(((Number) itr.next()).intValue()); // fields List fields = _state.getFieldsHolder(); out.writeShort(fields.size()); for (Iterator itr = fields.iterator(); itr.hasNext();) ((BCField) itr.next()).write(out); // methods List methods = _state.getMethodsHolder(); out.writeShort(methods.size()); for (Iterator itr = methods.iterator(); itr.hasNext();) ((BCMethod) itr.next()).write(out); // attributes writeAttributes(out); } /** * Return the bytecode of this class as a byte array, possibly for use * in a custom {@link ClassLoader}. */ public byte[] toByteArray() { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { write(out); out.flush(); return out.toByteArray(); } catch (IOException ioe) { throw new RuntimeException(ioe.toString()); } finally { try { out.close(); } catch (IOException ioe) {} } } ///////////////////// // Access operations ///////////////////// /** * Return the magic number for this class; if this is a valid type, this * should be equal to {@link Constants#VALID_MAGIC} (the default value). */ public int getMagic() { return _state.getMagic(); } /** * Set the magic number for this class; if this is a valid type, this * should be equal to {@link Constants#VALID_MAGIC} (the default value). */ public void setMagic(int magic) { _state.setMagic(magic); } /** * Return the major version of the bytecode spec used for this class. * JVMs are only required to operate with versions that they understand; * leaving the default value of {@link Constants#MAJOR_VERSION} is safe. */ public int getMajorVersion() { return _state.getMajorVersion(); } /** * Set the major version of the bytecode spec used for this class. * JVMs are only required to operate with versions that they understand; * leaving the default value of {@link Constants#MAJOR_VERSION} is safe. */ public void setMajorVersion(int majorVersion) { _state.setMajorVersion(majorVersion); } /** * Get the minor version of the bytecode spec used for this class. * JVMs are only required to operate with versions that they understand; * leaving the default value of {@link Constants#MINOR_VERSION} is safe. */ public int getMinorVersion() { return _state.getMinorVersion(); } /** * Set the minor version of the bytecode spec used for this class. * JVMs are only required to operate with versions that they understand; * leaving the default value of {@link Constants#MINOR_VERSION} is safe. */ public void setMinorVersion(int minorVersion) { _state.setMinorVersion(minorVersion); } /** * Return the access flags for this class as a bit array of * ACCESS_XXX constants from {@link Constants}. This can be used to * transfer access flags between classes without getting/setting each * possible flag. */ public int getAccessFlags() { return _state.getAccessFlags(); } /** * Set the access flags for this class as a bit array of * ACCESS_XXX constants from {@link Constants}. This can be used to * transfer access flags between classes without getting/setting each * possible flag. */ public void setAccessFlags(int access) { _state.setAccessFlags(access); } /** * Manipulate the class access flags. */ public boolean isPublic() { return (getAccessFlags() & Constants.ACCESS_PUBLIC) > 0; } /** * Manipulate the class access flags. */ public void makePublic() { setAccessFlags(getAccessFlags() | Constants.ACCESS_PUBLIC); } /** * Manipulate the class access flags. */ public boolean isPackage() { return !isPublic(); } /** * Manipulate the class access flags. */ public void makePackage() { setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC); } /** * Manipulate the class access flags. */ public boolean isFinal() { return (getAccessFlags() & Constants.ACCESS_FINAL) > 0; } /** * Manipulate the class access flags. */ public void setFinal(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_FINAL); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_FINAL); } /** * Manipulate the class access flags. */ public boolean isInterface() { return (getAccessFlags() & Constants.ACCESS_INTERFACE) > 0; } /** * Manipulate the class access flags. */ public void setInterface(boolean on) { if (on) { setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE); setAbstract(true); } else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_INTERFACE); } /** * Manipulate the class access flags. */ public boolean isAbstract() { return (getAccessFlags() & Constants.ACCESS_ABSTRACT) > 0; } /** * Manipulate the class access flags. */ public void setAbstract(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_ABSTRACT); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ABSTRACT); } /** * Manipulate the class access flags. */ public boolean isSynthetic() { return (getAccessFlags() & Constants.ACCESS_SYNTHETIC) > 0; } /** * Manipulate the class access flags. */ public void setSynthetic(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_SYNTHETIC); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_SYNTHETIC); } /** * Manipulate the class access flags. */ public boolean isAnnotation() { return (getAccessFlags() & Constants.ACCESS_ANNOTATION) > 0; } /** * Manipulate the class access flags. Setting to true also makes this * an interface. */ public void setAnnotation(boolean on) { if (on) { setAccessFlags(getAccessFlags() | Constants.ACCESS_ANNOTATION); setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE); } else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ANNOTATION); } /** * Manipulate the class access flags. */ public boolean isEnum() { return (getAccessFlags() & Constants.ACCESS_ENUM) > 0; } /** * Manipulate the class access flags. */ public void setEnum(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_ENUM); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ENUM); } /** * Return true if this class is a primitive type. */ public boolean isPrimitive() { return _state.isPrimitive(); } /** * Return true if this class is an array type. */ public boolean isArray() { return _state.isArray(); } ///////////////////////// // Class name operations ///////////////////////// /** * Return the {@link ConstantPool} index of the * {@link ClassEntry} for this class. Returns 0 if the class does not * have a constant pool (such as a primitive or array). */ public int getIndex() { return _state.getIndex(); } /** * Set the {@link ConstantPool} index of the {@link ClassEntry} for this * class. Unlike most other low-level methods, the index * will be checked against the pool immediately; * classes must have a valid name at all times. */ public void setIndex(int index) { String oldName = getName(); String newName = ((ClassEntry) getPool().getEntry(index)). getNameEntry().getValue(); beforeRename(oldName, newName); _state.setIndex(index); } /** * Return the name of this class, including package name. The name will * be in a form suitable for a {@link Class#forName} call. */ public String getName() { return _state.getName(); } /** * Return the name of the class only, without package. */ public String getClassName() { String name = _project.getNameCache().getExternalForm(getName(), true); return name.substring(name.lastIndexOf('.') + 1); } /** * Return the package name only, without class, or null if none. */ public String getPackageName() { String name = _project.getNameCache().getExternalForm(getName(), true); int index = name.lastIndexOf('.'); if (index == -1) return null; return name.substring(0, index); } /** * Set the name of this class, including package name. */ public void setName(String name) { name = _project.getNameCache().getExternalForm(name, false); String oldName = getName(); // get a reference to the class entry for this class int index = getIndex(); if (index == 0) index = getPool().findClassEntry(name, true); ClassEntry entry = (ClassEntry) getPool().getEntry(index); // make sure the rename is ok with the project beforeRename(oldName, name); // reset the name index of the class entry to the new name int nameIndex = getPool().findUTF8Entry(_project.getNameCache(). getInternalForm(name, false), true); entry.setNameIndex(nameIndex); // we might have just added a new entry; set the index _state.setIndex(index); } /** * Return the {@link Class} object for this class, if it is loadable. */ public Class getType() { return Strings.toClass(getName(), getClassLoader()); } /** * Return the component type name of this class, or null if not an array. * The name will be in a form suitable for a {@link Class#forName} call. */ public String getComponentName() { return _state.getComponentName(); } /** * Return the component type of this class, or null if not an array. */ public Class getComponentType() { String componentName = getComponentName(); if (componentName == null) return null; return Strings.toClass(componentName, getClassLoader()); } /** * Return the component type of this class, or null if not an array. */ public BCClass getComponentBC() { String componentName = getComponentName(); if (componentName == null) return null; return getProject().loadClass(componentName, getClassLoader()); } ///////////////////////// // Superclass operations ///////////////////////// /** * Return the {@link ConstantPool} index of the * {@link ClassEntry} for the superclass of this class. Returns -1 if * the class does not have a constant pool (such as a primitive or array). */ public int getSuperclassIndex() { return _state.getSuperclassIndex(); } /** * Set the {@link ConstantPool} index of the * {@link ClassEntry} for the superclass of this class. */ public void setSuperclassIndex(int index) { _state.setSuperclassIndex(index); } /** * Return the name of the superclass for this class, including package * name. The name will be in a form suitable for a * {@link Class#forName} call, or null for types without superclasses. */ public String getSuperclassName() { return _state.getSuperclassName(); } /** * Return the {@link Class} object for the superclass of this class, if it * is loadable. Returns null for types without superclasses. */ public Class getSuperclassType() { String name = getSuperclassName(); if (name == null) return null; return Strings.toClass(name, getClassLoader()); } /** * Return the bytecode of the superclass of this class, or * null for types without superclasses. */ public BCClass getSuperclassBC() { String name = getSuperclassName(); if (name == null) return null; return getProject().loadClass(name, getClassLoader()); } /** * Set the superclass of this class. */ public void setSuperclass(String name) { if (name == null) setSuperclassIndex(0); else setSuperclassIndex(getPool().findClassEntry(_project.getNameCache(). getInternalForm(name, false), true)); } /** * Set the superclass of this class. */ public void setSuperclass(Class type) { if (type == null) setSuperclass((String) null); else setSuperclass(type.getName()); } /** * Set the superclass of this class. */ public void setSuperclass(BCClass type) { if (type == null) setSuperclass((String) null); else setSuperclass(type.getName()); } //////////////////////// // Interface operations //////////////////////// /** * Return the list of {@link ConstantPool} indexes of the * {@link ClassEntry}s describing all the interfaces this class declares * that it implements/extends. * * @return the implmented interfaces, or an empty array if none */ public int[] getDeclaredInterfaceIndexes() { List interfaces = _state.getInterfacesHolder(); int[] indexes = new int[interfaces.size()]; for (int i = 0; i < interfaces.size(); i++) indexes[i] = ((Number) interfaces.get(i)).intValue(); return indexes; } /** * Set the list of {@link ConstantPool} indexes of the * {@link ClassEntry}s describing all the interfaces this class declares * it implements/extends; set to null or an empty array if none. */ public void setDeclaredInterfaceIndexes(int[] interfaceIndexes) { List stateIndexes = _state.getInterfacesHolder(); stateIndexes.clear(); Integer idx; for (int i = 0; i < interfaceIndexes.length; i++) { idx = Numbers.valueOf(interfaceIndexes[i]); if (!stateIndexes.contains(idx)) stateIndexes.add(idx); } } /** * Return the names of the interfaces declared for this class, including * package names, or an empty array if none. The names will be in a form * suitable for a {@link Class#forName} call. */ public String[] getDeclaredInterfaceNames() { int[] indexes = getDeclaredInterfaceIndexes(); String[] names = new String[indexes.length]; ClassEntry entry; for (int i = 0; i < indexes.length; i++) { entry = (ClassEntry) getPool().getEntry(indexes[i]); names[i] = _project.getNameCache().getExternalForm (entry.getNameEntry().getValue(), false); } return names; } /** * Return the {@link Class} objects for the declared interfaces of this * class, or an empty array if none. */ public Class[] getDeclaredInterfaceTypes() { String[] names = getDeclaredInterfaceNames(); Class[] types = new Class[names.length]; for (int i = 0; i < names.length; i++) types[i] = Strings.toClass(names[i], getClassLoader()); return types; } /** * Return the bytecode for the declared interfaces of this class, or an * empty array if none. */ public BCClass[] getDeclaredInterfaceBCs() { String[] names = getDeclaredInterfaceNames(); BCClass[] types = new BCClass[names.length]; for (int i = 0; i < names.length; i++) types[i] = getProject().loadClass(names[i], getClassLoader()); return types; } /** * Set the interfaces declared implemented/extended by this class; set to * null or an empty array if none. */ public void setDeclaredInterfaces(String[] interfaces) { clearDeclaredInterfaces(); if (interfaces != null) for (int i = 0; i < interfaces.length; i++) declareInterface(interfaces[i]); } /** * Set the interfaces declared implemented/extended by this class; set to * null or an empty array if none. */ public void setDeclaredInterfaces(Class[] interfaces) { String[] names = null; if (interfaces != null) { names = new String[interfaces.length]; for (int i = 0; i < interfaces.length; i++) names[i] = interfaces[i].getName(); } setDeclaredInterfaces(names); } /** * Set the interfaces declared implemented/extended by this class; set to * null or an empty array if none. */ public void setDeclaredInterfaces(BCClass[] interfaces) { String[] names = null; if (interfaces != null) { names = new String[interfaces.length]; for (int i = 0; i < interfaces.length; i++) names[i] = interfaces[i].getName(); } setDeclaredInterfaces(names); } /** * Return the names of all unique interfaces implemented by this class, * including those of all superclasses. The names will be returned in a * form suitable for a {@link Class#forName} call. * This method does not recurse into interfaces-of-interfaces. */ public String[] getInterfaceNames() { Collection allNames = new LinkedList(); String[] names; for (BCClass type = this; type != null; type = type.getSuperclassBC()) { names = type.getDeclaredInterfaceNames(); for (int i = 0; i < names.length; i++) allNames.add(names[i]); } return (String[]) allNames.toArray(new String[allNames.size()]); } /** * Return the {@link Class} objects of all unique interfaces implemented * by this class, including those of all superclasses. * This method does not recurse into interfaces-of-interfaces. */ public Class[] getInterfaceTypes() { Collection allTypes = new LinkedList(); Class[] types; for (BCClass type = this; type != null; type = type.getSuperclassBC()) { types = type.getDeclaredInterfaceTypes(); for (int i = 0; i < types.length; i++) allTypes.add(types[i]); } return (Class[]) allTypes.toArray(new Class[allTypes.size()]); } /** * Return the bytecode of all unique interfaces implemented by this class, * including those of all superclasses. * This method does not recurse into interfaces-of-interfaces. */ public BCClass[] getInterfaceBCs() { Collection allTypes = new LinkedList(); BCClass[] types; for (BCClass type = this; type != null; type = type.getSuperclassBC()) { types = type.getDeclaredInterfaceBCs(); for (int i = 0; i < types.length; i++) allTypes.add(types[i]); } return (BCClass[]) allTypes.toArray(new BCClass[allTypes.size()]); } /** * Clear this class of all interface declarations. */ public void clearDeclaredInterfaces() { _state.getInterfacesHolder().clear(); } /** * Remove an interface declared by this class. * * @return true if the class had the interface, false otherwise */ public boolean removeDeclaredInterface(String name) { String[] names = getDeclaredInterfaceNames(); Iterator itr = _state.getInterfacesHolder().iterator(); for (int i = 0; i < names.length; i++) { itr.next(); if (names[i].equals(name)) { itr.remove(); return true; } } return false; } /** * Remove an interface declared by this class. * * @return true if the class had the interface, false otherwise */ public boolean removeDeclaredInterface(Class type) { if (type == null) return false; return removeDeclaredInterface(type.getName()); } /** * Remove an interface declared by this class. * * @return true if the class had the interface, false otherwise */ public boolean removeDeclaredInterface(BCClass type) { if (type == null) return false; return removeDeclaredInterface(type.getName()); } /** * Rearrange declared interface order. */ public void moveDeclaredInterface(int fromIdx, int toIdx) { if (fromIdx == toIdx) return; List interfaces = _state.getInterfacesHolder(); Object o = interfaces.remove(fromIdx); interfaces.add(toIdx, o); } /** * Add an interface to those declared by this class. */ public void declareInterface(String name) { Integer index = Numbers.valueOf(getPool().findClassEntry(_project. getNameCache().getInternalForm(name, false), true)); List interfaces = _state.getInterfacesHolder(); if (!interfaces.contains(index)) interfaces.add(index); } /** * Add an interface to those declared by this class. */ public void declareInterface(Class type) { declareInterface(type.getName()); } /** * Add an interface to those declared by this class. */ public void declareInterface(BCClass type) { declareInterface(type.getName()); } /** * Return true if this class or any of its superclasses implement/extend * the given interface/class. * This method does not recurse into interfaces-of-interfaces. */ public boolean isInstanceOf(String name) { name = _project.getNameCache().getExternalForm(name, false); String[] interfaces = getInterfaceNames(); for (int i = 0; i < interfaces.length; i++) if (interfaces[i].equals(name)) return true; for (BCClass type = this; type != null; type = type.getSuperclassBC()) if (type.getName().equals(name)) return true; return false; } /** * Return true if this class or any of its superclasses implement/extend * the given interface/class. * This method does not recurse into interfaces-of-interfaces. */ public boolean isInstanceOf(Class type) { if (type == null) return false; return isInstanceOf(type.getName()); } /** * Return true if this class or any of its superclasses implement/extend * the given interface/class. * This method does not recurse into interfaces-of-interfaces. */ public boolean isInstanceOf(BCClass type) { if (type == null) return false; return isInstanceOf(type.getName()); } ////////////////////// // Field operations ////////////////////// /** * Return all the declared fields of this class, or an empty array if none. */ public BCField[] getDeclaredFields() { List fields = _state.getFieldsHolder(); return (BCField[]) fields.toArray(new BCField[fields.size()]); } /** * Return the declared field with the given name, or null if none. */ public BCField getDeclaredField(String name) { BCField[] fields = getDeclaredFields(); for (int i = 0; i < fields.length; i++) if (fields[i].getName().equals(name)) return fields[i]; return null; } /** * Return all the fields of this class, including those of all * superclasses, or an empty array if none. */ public BCField[] getFields() { Collection allFields = new LinkedList(); BCField[] fields; for (BCClass type = this; type != null; type = type.getSuperclassBC()) { fields = type.getDeclaredFields(); for (int i = 0; i < fields.length; i++) allFields.add(fields[i]); } return (BCField[]) allFields.toArray(new BCField[allFields.size()]); } /** * Return all fields with the given name, including those of all * superclasses, or an empty array if none. */ public BCField[] getFields(String name) { List matches = new LinkedList(); BCField[] fields = getFields(); for (int i = 0; i < fields.length; i++) if (fields[i].getName().equals(name)) matches.add(fields[i]); return (BCField[]) matches.toArray(new BCField[matches.size()]); } /** * Set the fields for this class; this method is useful for importing all * fields from another class. Set to null or empty array if none. */ public void setDeclaredFields(BCField[] fields) { clearDeclaredFields(); if (fields != null) for (int i = 0; i < fields.length; i++) declareField(fields[i]); } /** * Import the information from given field as a new field in this class. * * @return the added field */ public BCField declareField(BCField field) { BCField newField = declareField(field.getName(), field.getTypeName()); newField.setAccessFlags(field.getAccessFlags()); newField.setAttributes(field.getAttributes()); return newField; } /** * Add a field to this class. * * @return the added field */ public BCField declareField(String name, String type) { BCField field = new BCField(this); _state.getFieldsHolder().add(field); field.initialize(name, _project.getNameCache().getInternalForm(type, true)); return field; } /** * Add a field to this class. * * @return the added field */ public BCField declareField(String name, Class type) { String typeName = (type == null) ? null : type.getName(); return declareField(name, typeName); } /** * Add a field to this class. * * @return the added field */ public BCField declareField(String name, BCClass type) { String typeName = (type == null) ? null : type.getName(); return declareField(name, typeName); } /** * Clear all fields from this class. */ public void clearDeclaredFields() { List fields = _state.getFieldsHolder(); BCField field; for (Iterator itr = fields.iterator(); itr.hasNext();) { field = (BCField) itr.next(); itr.remove(); field.invalidate(); } } /** * Remove a field from this class. After this method, the removed field * will be invalid, and the result of any operations on it is undefined. * * @return true if this class contained the field, false otherwise */ public boolean removeDeclaredField(String name) { List fields = _state.getFieldsHolder(); BCField field; for (Iterator itr = fields.iterator(); itr.hasNext();) { field = (BCField) itr.next(); if (field.getName().equals(name)) { itr.remove(); field.invalidate(); return true; } } return false; } /** * Remove a field from this class. After this method, the removed field * will be invalid, and the result of any operations on it is undefined. * * @return true if this class contained the field, false otherwise */ public boolean removeDeclaredField(BCField field) { if (field == null) return false; return removeDeclaredField(field.getName()); } /** * Rearrange declared field order. */ public void moveDeclaredField(int fromIdx, int toIdx) { if (fromIdx == toIdx) return; List fields = _state.getFieldsHolder(); Object o = fields.remove(fromIdx); fields.add(toIdx, o); } ////////////////////// // Method operations ////////////////////// /** * Return all methods declared by this class. Constructors and static * initializers are included. */ public BCMethod[] getDeclaredMethods() { List methods = _state.getMethodsHolder(); return (BCMethod[]) methods.toArray(new BCMethod[methods.size()]); } /** * Return the declared method with the given name, or null if none. * If multiple methods are declared with the given name, which is returned * is undefined. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod getDeclaredMethod(String name) { BCMethod[] methods = getDeclaredMethods(); for (int i = 0; i < methods.length; i++) if (methods[i].getName().equals(name)) return methods[i]; return null; } /** * Return all the declared methods with the given name, or an empty array * if none. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod[] getDeclaredMethods(String name) { Collection matches = new LinkedList(); BCMethod[] methods = getDeclaredMethods(); for (int i = 0; i < methods.length; i++) if (methods[i].getName().equals(name)) matches.add(methods[i]); return (BCMethod[]) matches.toArray(new BCMethod[matches.size()]); } /** * Return the declared method with the given name and parameter types, * or null if none. If multiple methods are declared with the given name * and parameters, which is returned is undefined. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod getDeclaredMethod(String name, String[] paramTypes) { if (paramTypes == null) paramTypes = new String[0]; BCMethod[] methods = getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals(name) && paramsMatch(methods[i], paramTypes)) return methods[i]; } return null; } /** * Return true iff the given method's parameters match params. */ private boolean paramsMatch(BCMethod meth, String[] params) { String[] mparams = meth.getParamNames(); if (mparams.length != params.length) return false; for (int i = 0; i < params.length; i++) { if (!mparams[i].equals(_project.getNameCache(). getExternalForm(params[i], false))) return false; } return true; } /** * Return the declared method with the given name and parameter types, * or null if none. If multiple methods are declared with the given name * and parameters, which is returned is undefined. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod getDeclaredMethod(String name, Class[] paramTypes) { if (paramTypes == null) return getDeclaredMethod(name, (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return getDeclaredMethod(name, paramNames); } /** * Return the declared method with the given name and parameter types, * or null if none. If multiple methods are declared with the given name * and parameters, which is returned is undefined. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod getDeclaredMethod(String name, BCClass[] paramTypes) { if (paramTypes == null) return getDeclaredMethod(name, (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return getDeclaredMethod(name, paramNames); } /** * Return all declared methods with the given name and parameter types. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod[] getDeclaredMethods(String name, String[] paramTypes) { if (paramTypes == null) paramTypes = new String[0]; BCMethod[] methods = getDeclaredMethods(); List matches = null; for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals(name) && paramsMatch(methods[i], paramTypes)) { if (matches == null) matches = new ArrayList(3); matches.add(methods[i]); } } if (matches == null) return new BCMethod[0]; return (BCMethod[]) matches.toArray(new BCMethod[matches.size()]); } /** * Return all declared methods with the given name and parameter types. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod[] getDeclaredMethods(String name, Class[] paramTypes) { if (paramTypes == null) return getDeclaredMethods(name, (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return getDeclaredMethods(name, paramNames); } /** * Return all declared methods with the given name and parameter types. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod[] getDeclaredMethods(String name, BCClass[] paramTypes) { if (paramTypes == null) return getDeclaredMethods(name, (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return getDeclaredMethods(name, paramNames); } /** * Return the declared method with the given name and signature, * or null if none. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod getDeclaredMethod(String name, String returnType, String[] paramTypes) { if (paramTypes == null) paramTypes = new String[0]; BCMethod[] methods = getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals(name) && methods[i].getReturnName().equals(_project.getNameCache(). getExternalForm(returnType, false)) && paramsMatch(methods[i], paramTypes)) return methods[i]; } return null; } /** * Return the declared method with the given name and signature, * or null if none. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod getDeclaredMethod(String name, Class returnType, Class[] paramTypes) { if (paramTypes == null) return getDeclaredMethod(name, returnType.getName(), (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return getDeclaredMethod(name, returnType.getName(), paramNames); } /** * Return the declared method with the given name and signature, * or null if none. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod getDeclaredMethod(String name, BCClass returnType, BCClass[] paramTypes) { if (paramTypes == null) return getDeclaredMethod(name, returnType.getName(), (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return getDeclaredMethod(name, returnType.getName(), paramNames); } /** * Return the methods of this class, including those of all superclasses, * or an empty array if none. * The base version of methods that are overridden will be included, as * will all constructors and static initializers. * The methods will be ordered from those in the most-specific type up to * those in {@link Object}. */ public BCMethod[] getMethods() { Collection allMethods = new LinkedList(); BCMethod[] methods; for (BCClass type = this; type != null; type = type.getSuperclassBC()) { methods = type.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) allMethods.add(methods[i]); } return (BCMethod[]) allMethods.toArray(new BCMethod[allMethods.size()]); } /** * Return the methods with the given name, including those of all * superclasses, or an empty array if none. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod[] getMethods(String name) { Collection matches = new LinkedList(); BCMethod[] methods = getMethods(); for (int i = 0; i < methods.length; i++) if (methods[i].getName().equals(name)) matches.add(methods[i]); return (BCMethod[]) matches.toArray(new BCMethod[matches.size()]); } /** * Return the methods with the given name and parameter types, including * those of all superclasses, or an empty array if none. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod[] getMethods(String name, String[] paramTypes) { if (paramTypes == null) paramTypes = new String[0]; String[] curParams; boolean match; BCMethod[] methods = getMethods(); Collection matches = new LinkedList(); for (int i = 0; i < methods.length; i++) { if (!methods[i].getName().equals(name)) continue; curParams = methods[i].getParamNames(); if (curParams.length != paramTypes.length) continue; match = true; for (int j = 0; j < paramTypes.length; j++) { if (!curParams[j].equals(_project.getNameCache(). getExternalForm(paramTypes[j], false))) { match = false; break; } } if (match) matches.add(methods[i]); } return (BCMethod[]) matches.toArray(new BCMethod[matches.size()]); } /** * Return the methods with the given name and parameter types, including * those of all superclasses, or an empty array if none. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod[] getMethods(String name, Class[] paramTypes) { if (paramTypes == null) return getMethods(name, (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return getMethods(name, paramNames); } /** * Return the methods with the given name and parameter types, including * those of all superclasses, or an empty array if none. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. */ public BCMethod[] getMethods(String name, BCClass[] paramTypes) { if (paramTypes == null) return getMethods(name, (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return getMethods(name, paramNames); } /** * Set the methods for this class; this method is useful for importing all * methods from another class. Set to null or empty array if none. */ public void setDeclaredMethods(BCMethod[] methods) { clearDeclaredMethods(); if (methods != null) for (int i = 0; i < methods.length; i++) declareMethod(methods[i]); } /** * Import the information in the given method as a new method of this class. * * @return the added method */ public BCMethod declareMethod(BCMethod method) { BCMethod newMethod = declareMethod(method.getName(), method.getReturnName(), method.getParamNames()); newMethod.setAccessFlags(method.getAccessFlags()); newMethod.setAttributes(method.getAttributes()); return newMethod; } /** * Add a method to this class. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. * * @return the added method */ public BCMethod declareMethod(String name, String returnType, String[] paramTypes) { BCMethod method = new BCMethod(this); _state.getMethodsHolder().add(method); method.initialize(name, _project.getNameCache(). getDescriptor(returnType, paramTypes)); return method; } /** * Add a method to this class. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. * * @return the added method */ public BCMethod declareMethod(String name, Class returnType, Class[] paramTypes) { String[] paramNames = null; if (paramTypes != null) { paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); } String returnName = (returnType == null) ? null : returnType.getName(); return declareMethod(name, returnName, paramNames); } /** * Add a method to this class. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. * * @return the added method */ public BCMethod declareMethod(String name, BCClass returnType, BCClass[] paramTypes) { String[] paramNames = null; if (paramTypes != null) { paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); } String returnName = (returnType == null) ? null : returnType.getName(); return declareMethod(name, returnName, paramNames); } /** * Clear all declared methods from this class. */ public void clearDeclaredMethods() { List methods = _state.getMethodsHolder(); BCMethod method; for (Iterator itr = methods.iterator(); itr.hasNext();) { method = (BCMethod) itr.next(); itr.remove(); method.invalidate(); } } /** * Remove a method from this class. After this method, the removed method * will be invalid, and the result of any operations on it is undefined. * If multiple methods match the given name, which is removed is undefined. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. * * @return true if this class contained the method, false otherwise */ public boolean removeDeclaredMethod(String name) { List methods = _state.getMethodsHolder(); BCMethod method; for (Iterator itr = methods.iterator(); itr.hasNext();) { method = (BCMethod) itr.next(); if (method.getName().equals(name)) { itr.remove(); method.invalidate(); return true; } } return false; } /** * Removes a method from this class. After this method, the removed method * will be invalid, and the result of any operations on it is undefined. * * @return true if this class contained the method, false otherwise */ public boolean removeDeclaredMethod(BCMethod method) { if (method == null) return false; return removeDeclaredMethod(method.getName(), method.getParamNames()); } /** * Removes a method from this class. After this method, the removed method * will be invalid, and the result of any operations on it is undefined. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. * * @return true if this class contained the method, false otherwise */ public boolean removeDeclaredMethod(String name, String[] paramTypes) { if (paramTypes == null) paramTypes = new String[0]; String[] curParams; boolean match; List methods = _state.getMethodsHolder(); BCMethod method; for (Iterator itr = methods.iterator(); itr.hasNext();) { method = (BCMethod) itr.next(); if (!method.getName().equals(name)) continue; curParams = method.getParamNames(); if (curParams.length != paramTypes.length) continue; match = true; for (int j = 0; j < paramTypes.length; j++) { if (!curParams[j].equals(_project.getNameCache(). getExternalForm(paramTypes[j], false))) { match = false; break; } } if (match) { itr.remove(); method.invalidate(); return true; } } return false; } /** * Removes a method from this class. After this method, the removed method * will be invalid, and the result of any operations on it is undefined. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. * * @return true if this class contained the method, false otherwise */ public boolean removeDeclaredMethod(String name, Class[] paramTypes) { if (paramTypes == null) return removeDeclaredMethod(name, (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return removeDeclaredMethod(name, paramNames); } /** * Removes a method from this class. After this method, the removed method * will be invalid, and the result of any operations on it is undefined. * Note that in bytecode, constructors are named <init> * and static initializers are named <clinit>. * * @return true if this class contained the method, false otherwise */ public boolean removeDeclaredMethod(String name, BCClass[] paramTypes) { if (paramTypes == null) return removeDeclaredMethod(name, (String[]) null); String[] paramNames = new String[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) paramNames[i] = paramTypes[i].getName(); return removeDeclaredMethod(name, paramNames); } /** * Rearrange method order. */ public void moveDeclaredMethod(int fromIdx, int toIdx) { if (fromIdx == toIdx) return; List methods = _state.getMethodsHolder(); Object o = methods.remove(fromIdx); methods.add(toIdx, o); } /////////////////////// // Convenience methods /////////////////////// /** * Convenience method to add a default constructor to this class. * If a default constructor already exists, this method will return it * without modification. * This method can only be called if the superclass has been set. * * @return the default constructor */ public BCMethod addDefaultConstructor() { BCMethod method = getDeclaredMethod("", (String[]) null); if (method != null) return method; method = declareMethod("", void.class, null); Code code = method.getCode(true); code.setMaxStack(1); code.setMaxLocals(1); code.xload().setThis(); code.invokespecial() .setMethod(getSuperclassName(), "", "void", null); code.vreturn(); return method; } /** * Return source file information for the class. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new source file attribute will be added * if not already present * @return the source file information, or null if none and the * add param is set to false */ public SourceFile getSourceFile(boolean add) { SourceFile source = (SourceFile) getAttribute(Constants.ATTR_SOURCE); if (!add || (source != null)) return source; return (SourceFile) addAttribute(Constants.ATTR_SOURCE); } /** * Remove the source file attribute for the class. * Acts internally through the {@link Attributes} interface. * * @return true if there was a file to remove */ public boolean removeSourceFile() { return removeAttribute(Constants.ATTR_SOURCE); } /** * Return inner classes information for the class. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new inner classes attribute will be added * if not already present * @return the inner classes information, or null if none and the * add param is set to false */ public InnerClasses getInnerClasses(boolean add) { InnerClasses inner = (InnerClasses) getAttribute (Constants.ATTR_INNERCLASS); if (!add || (inner != null)) return inner; return (InnerClasses) addAttribute(Constants.ATTR_INNERCLASS); } /** * Remove the inner classes attribute for the class. * Acts internally through the {@link Attributes} interface. * * @return true if there was an attribute to remove */ public boolean removeInnerClasses() { return removeAttribute(Constants.ATTR_INNERCLASS); } /** * Convenience method to return deprecation information for the class. * Acts internally through the {@link Attributes} interface. */ public boolean isDeprecated() { return getAttribute(Constants.ATTR_DEPRECATED) != null; } /** * Convenience method to set whether this class should be considered * deprecated. Acts internally through the {@link Attributes} interface. */ public void setDeprecated(boolean on) { if (!on) removeAttribute(Constants.ATTR_DEPRECATED); else if (!isDeprecated()) addAttribute(Constants.ATTR_DEPRECATED); } /////////////////////////////////// // Implementation of VisitAcceptor /////////////////////////////////// public void acceptVisit(BCVisitor visit) { visit.enterBCClass(this); ConstantPool pool = null; try { pool = _state.getPool(); } catch (UnsupportedOperationException uoe) { } if (pool != null) pool.acceptVisit(visit); BCField[] fields = getDeclaredFields(); for (int i = 0; i < fields.length; i++) { visit.enterBCMember(fields[i]); fields[i].acceptVisit(visit); visit.exitBCMember(fields[i]); } BCMethod[] methods = getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { visit.enterBCMember(methods[i]); methods[i].acceptVisit(visit); visit.exitBCMember(methods[i]); } visitAttributes(visit); visit.exitBCClass(this); } //////////////////////////////// // Implementation of Attributes //////////////////////////////// public Project getProject() { return _project; } public ConstantPool getPool() { return _state.getPool(); } public ClassLoader getClassLoader() { if (_loader != null) return _loader; return Thread.currentThread().getContextClassLoader(); } public boolean isValid() { return _project != null; } Collection getAttributesHolder() { return _state.getAttributesHolder(); } /////////////////////////////// // Implementation of Annotated /////////////////////////////// BCClass getBCClass() { return this; } /** * Attempts to change the class name with the owning project. The project * can reject the change if a class with the given new name already * exists; therefore this method should be called before the change is * recorded in the class. */ private void beforeRename(String oldName, String newName) { if ((_project != null) && (oldName != null)) _project.renameClass(oldName, newName, this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/MethodInstruction.java0000755000000000000000000005152210637750727022152 0ustar package serp.bytecode; import java.io.*; import java.lang.reflect.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; import serp.util.*; /** * An instruction that invokes a method. * * @author Abe White */ public class MethodInstruction extends Instruction { private int _index = 0; MethodInstruction(Code owner, int opcode) { super(owner, opcode); } int getLength() { if (getOpcode() == Constants.INVOKEINTERFACE) return super.getLength() + 4; return super.getLength() + 2; } public int getLogicalStackChange() { String ret = getMethodReturnName(); if (ret == null) return 0; // subtract a stack pos for the this ptr int stack = 0; if (getOpcode() != Constants.INVOKESTATIC) stack--; // and for each arg String[] params = getMethodParamNames(); for (int i = 0; i < params.length; i++) stack--; // add for the return value, if any if (!void.class.getName().equals(ret)) stack++; return stack; } public int getStackChange() { String ret = getMethodReturnName(); if (ret == null) return 0; // subtract a stack pos for the this ptr int stack = 0; if (getOpcode() != Constants.INVOKESTATIC) stack--; // and for each arg (2 for longs, doubles) String[] params = getMethodParamNames(); for (int i = 0; i < params.length; i++, stack--) if (long.class.getName().equals(params[i]) || double.class.getName().equals(params[i])) stack--; // add for the return value, if any if (!void.class.getName().equals(ret)) stack++; if (long.class.getName().equals(ret) || double.class.getName().equals(ret)) stack++; return stack; } ///////////////////// // Method operations ///////////////////// /** * Return the index in the class {@link ConstantPool} of the * {@link ComplexEntry} describing the method to operate on. */ public int getMethodIndex() { return _index; } /** * Set the index in the class {@link ConstantPool} of the * {@link ComplexEntry} describing the method to operate on. * * @return this instruction, for method chaining */ public MethodInstruction setMethodIndex(int index) { _index = index; return this; } /** * Return the method this instruction operates on, or null if not set. */ public BCMethod getMethod() { String dec = getMethodDeclarerName(); if (dec == null) return null; BCClass bc = getProject().loadClass(dec, getClassLoader()); BCMethod[] meths = bc.getMethods(getMethodName(),getMethodParamNames()); if (meths.length == 0) return null; return meths[0]; } /** * Set the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethod(BCMethod method) { if (method == null) return setMethodIndex(0); return setMethod(method.getDeclarer().getName(), method.getName(), method.getReturnName(), method.getParamNames(), false); } /** * Set the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethod(Method method) { if (method == null) return setMethodIndex(0); return setMethod(method.getDeclaringClass(), method.getName(), method.getReturnType(), method.getParameterTypes()); } /** * Set the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethod(Constructor method) { if (method == null) return setMethodIndex(0); setOpcode(Constants.INVOKESPECIAL); return setMethod(method.getDeclaringClass(), "", void.class, method.getParameterTypes()); } /** * Set the method this instruction operates on. * * @param dec the full class name of the method's declaring class * @param name the method name * @param returnType the full class name of the method return type * @param param the full class names of the method param types * @return this instruction, for method chaining */ public MethodInstruction setMethod(String dec, String name, String returnType, String[] params) { return setMethod(dec, name, returnType, params, true); } /** * Set the method this instruction operates on. * * @param dec the full class name of the method's declaring class * @param name the method name * @param returnType the full class name of the method return type * @param param the full class names of the method param types * @param copy whether to copy the the parameter array * @return this instruction, for method chaining */ private MethodInstruction setMethod(String dec, String name, String returnType, String[] params, boolean copy) { if (name == null && returnType == null && dec == null && (params == null || params.length == 0)) return setMethodIndex(0); if (dec == null) dec = ""; if (name == null) name = ""; if (returnType == null) returnType = ""; if (params == null) params = new String[0]; else if (copy) { String[] pcopy = new String[params.length]; System.arraycopy(params, 0, pcopy, 0, params.length); params = pcopy; } NameCache cache = getProject().getNameCache(); returnType = cache.getInternalForm(returnType, true); dec = cache.getInternalForm(dec, false); for (int i = 0; i < params.length; i++) params[i] = cache.getInternalForm(params[i], true); String desc = cache.getDescriptor(returnType, params); if (getOpcode() == Constants.INVOKEINTERFACE) return setMethodIndex(getPool().findInterfaceMethodEntry(dec, name, desc, true)); return setMethodIndex(getPool().findMethodEntry(dec, name, desc, true)); } /** * Set the method this instruction operates on, for methods that are * declared by the current class. * * @param name the method name * @param returnType the full class name of the method return type * @param param the full class names of the method param types * @return this instruction, for method chaining */ public MethodInstruction setMethod(String name, String returnType, String[] params) { BCClass owner = getCode().getMethod().getDeclarer(); return setMethod(owner.getName(), name, returnType, params); } /** * Set the method this instruction operates on. * * @param dec the method's declaring class * @param name the method name * @param returnType the class of the method return type * @param param the class of the method param types * @return this instruction, for method chaining */ public MethodInstruction setMethod(Class dec, String name, Class returnType, Class[] params) { String decName = (dec == null) ? null : dec.getName(); String returnName = (returnType == null) ? null : returnType.getName(); String[] paramNames = null; if (params != null) { paramNames = new String[params.length]; for (int i = 0; i < params.length; i++) paramNames[i] = params[i].getName(); } return setMethod(decName, name, returnName, paramNames, false); } /** * Set the method this instruction operates on, for methods that are * declared by the current class. * * @param name the method name * @param returnType the class of the method return type * @param param the class of the method param types * @return this instruction, for method chaining */ public MethodInstruction setMethod(String name, Class returnType, Class[] params) { BCClass owner = getCode().getMethod().getDeclarer(); String returnName = (returnType == null) ? null : returnType.getName(); String[] paramNames = null; if (params != null) { paramNames = new String[params.length]; for (int i = 0; i < params.length; i++) paramNames[i] = params[i].getName(); } return setMethod(owner.getName(), name, returnName, paramNames, false); } /** * Set the method this instruction operates on. * * @param dec the method's declaring class * @param name the method name * @param returnType the class of the method return type * @param param the class of the method param types * @return this instruction, for method chaining */ public MethodInstruction setMethod(BCClass dec, String name, BCClass returnType, BCClass[] params) { String decName = (dec == null) ? null : dec.getName(); String returnName = (returnType == null) ? null : returnType.getName(); String[] paramNames = null; if (params != null) { paramNames = new String[params.length]; for (int i = 0; i < params.length; i++) paramNames[i] = params[i].getName(); } return setMethod(decName, name, returnName, paramNames, false); } /** * Set the method this instruction operates on, for methods that are * declared by the current class. * * @param name the method name * @param returnType the class of the method return type * @param param the class of the method param types * @return this instruction, for method chaining */ public MethodInstruction setMethod(String name, BCClass returnType, BCClass[] params) { BCClass owner = getCode().getMethod().getDeclarer(); String returnName = (returnType == null) ? null : returnType.getName(); String[] paramNames = null; if (params != null) { paramNames = new String[params.length]; for (int i = 0; i < params.length; i++) paramNames[i] = params[i].getName(); } return setMethod(owner.getName(), name, returnName, paramNames, false); } ///////////////////////////////////////// // Name, Return, Param, Owner operations ///////////////////////////////////////// /** * Return the name of the method this instruction operates on, or null * if not set. */ public String getMethodName() { if (_index == 0) return null; ComplexEntry entry = (ComplexEntry) getPool().getEntry(_index); String name = entry.getNameAndTypeEntry().getNameEntry().getValue(); if (name.length() == 0) return null; return name; } /** * Set the name of the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethodName(String name) { return setMethod(getMethodDeclarerName(), name, getMethodReturnName(), getMethodParamNames()); } /** * Return the return type of the method this instruction operates on, * or null if not set. */ public String getMethodReturnName() { if (_index == 0) return null; ComplexEntry entry = (ComplexEntry) getPool().getEntry(_index); String desc = entry.getNameAndTypeEntry().getDescriptorEntry(). getValue(); NameCache cache = getProject().getNameCache(); String name = cache.getExternalForm(cache.getDescriptorReturnName(desc), false); if (name.length() == 0) return null; return name; } /** * Return the return type of the method this instruction operates on, * or null if not set. */ public Class getMethodReturnType() { String type = getMethodReturnName(); if (type == null) return null; return Strings.toClass(type, getClassLoader()); } /** * Return the return type of the method this instruction operates on, * or null if not set. */ public BCClass getMethodReturnBC() { String type = getMethodReturnName(); if (type == null) return null; return getProject().loadClass(type, getClassLoader()); } /** * Set the return type of the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethodReturn(String type) { return setMethod(getMethodDeclarerName(), getMethodName(), type, getMethodParamNames()); } /** * Set the return type of the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethodReturn(Class type) { String name = null; if (type != null) name = type.getName(); return setMethodReturn(name); } /** * Set the return type of the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethodReturn(BCClass type) { String name = null; if (type != null) name = type.getName(); return setMethodReturn(name); } /** * Return the param types of the method this instruction operates on, * or empty array if none. */ public String[] getMethodParamNames() { if (_index == 0) return new String[0]; ComplexEntry entry = (ComplexEntry) getPool().getEntry(_index); String desc = entry.getNameAndTypeEntry().getDescriptorEntry(). getValue(); NameCache cache = getProject().getNameCache(); String[] names = cache.getDescriptorParamNames(desc); for (int i = 0; i < names.length; i++) names[i] = cache.getExternalForm(names[i], false); return names; } /** * Return the param types of the method this instruction operates on, * or empty array if none. */ public Class[] getMethodParamTypes() { String[] paramNames = getMethodParamNames(); 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 param types of the method this instruction operates on, * or empty array if none. */ public BCClass[] getMethodParamBCs() { String[] paramNames = getMethodParamNames(); 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 param types of the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethodParams(String[] types) { return setMethod(getMethodDeclarerName(), getMethodName(), getMethodReturnName(), types); } /** * Set the param types of the method this instruction operates on. * * @return this instruction, for method chaining */ public void setMethodParams(Class[] types) { if (types == null) setMethodParams((String[]) null); else { String[] names = new String[types.length]; for (int i = 0; i < types.length; i++) names[i] = types[i].getName(); setMethodParams(names); } } /** * Set the param types of the method this instruction operates on. * * @return this instruction, for method chaining */ public void setMethodParams(BCClass[] types) { if (types == null) setMethodParams((String[]) null); else { String[] names = new String[types.length]; for (int i = 0; i < types.length; i++) names[i] = types[i].getName(); setMethodParams(names); } } /** * Return the declaring type of the method this instruction operates on, * or null if not set. */ public String getMethodDeclarerName() { if (_index == 0) return null; ComplexEntry entry = (ComplexEntry) getPool().getEntry(_index); String name = getProject().getNameCache().getExternalForm (entry.getClassEntry().getNameEntry().getValue(), false); if (name.length() == 0) return null; return name; } /** * Return the declaring type of the method this instruction operates on, * or null if not set. */ public Class getMethodDeclarerType() { String type = getMethodDeclarerName(); if (type == null) return null; return Strings.toClass(type, getClassLoader()); } /** * Return the declaring type of the method this instruction operates on, * or null if not set. */ public BCClass getMethodDeclarerBC() { String type = getMethodDeclarerName(); if (type == null) return null; return getProject().loadClass(type, getClassLoader()); } /** * Set the declaring type of the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethodDeclarer(String type) { return setMethod(type, getMethodName(), getMethodReturnName(), getMethodParamNames()); } /** * Set the declaring type of the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethodDeclarer(Class type) { String name = null; if (type != null) name = type.getName(); return setMethodDeclarer(name); } /** * Set the declaring type of the method this instruction operates on. * * @return this instruction, for method chaining */ public MethodInstruction setMethodDeclarer(BCClass type) { String name = null; if (type != null) name = type.getName(); return setMethodDeclarer(name); } /** * MethodInstructions are equal if the method they reference is the same, * or if the method of either is unset. */ public boolean equalsInstruction(Instruction other) { if (other == this) return true; if (!(other instanceof MethodInstruction)) return false; if (!super.equalsInstruction(other)) return false; MethodInstruction ins = (MethodInstruction) other; String s1 = getMethodName(); String s2 = ins.getMethodName(); if (!(s1 == null || s2 == null || s1.equals(s2))) return false; s1 = getMethodReturnName(); s2 = ins.getMethodReturnName(); if (!(s1 == null || s2 == null || s1.equals(s2))) return false; s1 = getMethodDeclarerName(); s2 = ins.getMethodDeclarerName(); if (!(s1 == null || s2 == null || s1.equals(s2))) return false; String[] p1 = getMethodParamNames(); String[] p2 = ins.getMethodParamNames(); if (!(p1.length == 0 || p2.length == 0 || p1.length == p2.length)) return false; for (int i = 0; i < p1.length; i++) if (!(p1[i] == null || p2[i] == null || p1[i].equals(p2[i]))) return false; return true; } public void acceptVisit(BCVisitor visit) { visit.enterMethodInstruction(this); visit.exitMethodInstruction(this); } void read(Instruction orig) { super.read(orig); MethodInstruction ins = (MethodInstruction) orig; setMethod(ins.getMethodDeclarerName(), ins.getMethodName(), ins.getMethodReturnName(), ins.getMethodParamNames()); } void read(DataInput in) throws IOException { super.read(in); _index = in.readUnsignedShort(); if (getOpcode() == Constants.INVOKEINTERFACE) { in.readByte(); in.readByte(); } } void write(DataOutput out) throws IOException { super.write(out); out.writeShort(_index); if (getOpcode() == Constants.INVOKEINTERFACE) { String[] args = getMethodParamNames(); int count = 1; for (int i = 0; i < args.length; i++, count++) if (long.class.getName().equals(args[i]) || double.class.getName().equals(args[i])) count++; out.writeByte(count); out.writeByte(0); } } } serp-1.14.1.orig/src/main/java/serp/bytecode/IfInstruction.java0000755000000000000000000000273610637750727021273 0ustar package serp.bytecode; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; /** * An if instruction such as ifnull, ifeq, etc. * * @author Abe White */ public class IfInstruction extends JumpInstruction { IfInstruction(Code owner, int opcode) { super(owner, opcode); } public int getStackChange() { switch (getOpcode()) { case Constants.IFACMPEQ: case Constants.IFACMPNE: case Constants.IFICMPEQ: case Constants.IFICMPNE: case Constants.IFICMPLT: case Constants.IFICMPGT: case Constants.IFICMPLE: case Constants.IFICMPGE: return -2; case Constants.IFEQ: case Constants.IFNE: case Constants.IFLT: case Constants.IFGT: case Constants.IFLE: case Constants.IFGE: case Constants.IFNULL: case Constants.IFNONNULL: return -1; default: return super.getStackChange(); } } int getLength() { return super.getLength() + 2; } public String getTypeName() { switch (getOpcode()) { case Constants.IFACMPEQ: case Constants.IFACMPNE: case Constants.IFNULL: case Constants.IFNONNULL: return "java.lang.Object"; default: return "I"; } } public void acceptVisit(BCVisitor visit) { visit.enterIfInstruction(this); visit.exitIfInstruction(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/LocalVariableType.java0000755000000000000000000000120210460270414022000 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * A local variable type contains the name, signature, index and scope * of a generics-using local used in opcodes. * * @author Abe White */ public class LocalVariableType extends Local { LocalVariableType(LocalVariableTypeTable owner) { super(owner); } /** * The owning table. */ public LocalVariableTypeTable getLocalVariableTypeTable() { return (LocalVariableTypeTable) getTable(); } public void acceptVisit(BCVisitor visit) { visit.enterLocalVariableType(this); visit.exitLocalVariableType(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/ClassConstantInstruction.java0000755000000000000000000001404110460270414023464 0ustar package serp.bytecode; import java.util.*; import serp.bytecode.lowlevel.*; /** * Pseudo-instruction used to place {@link 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. * * @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 class$ 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, "", 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); } } serp-1.14.1.orig/src/main/java/serp/bytecode/visitor/0000755000000000000000000000000011401260237017272 5ustar serp-1.14.1.orig/src/main/java/serp/bytecode/visitor/package.html0000755000000000000000000000041110455026340021555 0ustar

Bytecode Visitor

This package implements the visitor pattern on bytecode entities and provides a useful concrete visitor that pretty-prints a detailed document describing any bytecode entity.

serp-1.14.1.orig/src/main/java/serp/bytecode/visitor/PrettyPrintVisitor.java0000755000000000000000000003330510623131051024024 0ustar package serp.bytecode.visitor; import java.io.*; import serp.bytecode.*; import serp.bytecode.lowlevel.*; /** * Visitor type that outputs a detailed, formatted document of the * visited entity; similar to the javap -c command but more detailed. * * @author Abe White */ public class PrettyPrintVisitor extends BCVisitor { private PrintWriter _out = null; private String _prefix = ""; /** * Constructor; all pritning will go to stdout. */ public PrettyPrintVisitor() { _out = new PrintWriter(System.out); } /** * Constructor. * * @param out the stream to print to */ public PrettyPrintVisitor(PrintWriter out) { _out = out; } /** * Invoke with the class or file names to pretty print; the * functionality is similar to the javap -c command, but more * detailed. */ public static void main(String[] args) throws ClassNotFoundException, IOException { if (args.length == 0) { System.err.println("Usage: java " + PrettyPrintVisitor.class.getName() + " +"); System.exit(1); } PrettyPrintVisitor ppv = new PrettyPrintVisitor(); Project project = new Project(); BCClass type; for (int i = 0; i < args.length; i++) { if (args[i].endsWith(".class")) type = project.loadClass(new File(args[i])); else type = project.loadClass(Class.forName(args[i], false, PrettyPrintVisitor.class.getClassLoader())); ppv.visit(type); } } public void visit(VisitAcceptor entity) { super.visit(entity); _out.flush(); } public void enterProject(Project obj) { openBlock("Project"); println("name=" + obj.getName()); } public void exitProject(Project obj) { closeBlock(); } public void enterBCClass(BCClass obj) { openBlock("Class"); println("magic=" + obj.getMagic()); println("minor=" + obj.getMinorVersion()); println("major=" + obj.getMajorVersion()); println("access=" + obj.getAccessFlags()); println("name=" + obj.getIndex() + " <" + obj.getName() + ">"); println("super=" + obj.getSuperclassIndex() + " <" + obj.getSuperclassName() + ">"); int[] indexes = obj.getDeclaredInterfaceIndexes(); String[] names = obj.getDeclaredInterfaceNames(); for (int i = 0; i < indexes.length; i++) println("interface=" + indexes[i] + " <" + names[i] + ">"); } public void exitBCClass(BCClass obj) { closeBlock(); } public void enterBCField(BCField obj) { openBlock("Field"); println("access=" + obj.getAccessFlags()); println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); println("type=" + obj.getDescriptorIndex() + " <" + obj.getTypeName() + ">"); } public void exitBCField(BCField obj) { closeBlock(); } public void enterBCMethod(BCMethod obj) { openBlock("Method"); println("access=" + obj.getAccessFlags()); println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); println("descriptor=" + obj.getDescriptorIndex()); println("return=" + obj.getReturnName()); String[] params = obj.getParamNames(); for (int i = 0; i < params.length; i++) println("param=" + params[i]); } public void exitBCMethod(BCMethod obj) { closeBlock(); } public void enterAttribute(Attribute obj) { openBlock(obj.getName()); } public void exitAttribute(Attribute obj) { closeBlock(); } public void enterConstantValue(ConstantValue obj) { println("value=" + obj.getValueIndex() + " <" + obj.getTypeName() + "=" + obj.getValue() + ">"); } public void enterExceptions(Exceptions obj) { int[] indexes = obj.getExceptionIndexes(); String[] names = obj.getExceptionNames(); for (int i = 0; i < indexes.length; i++) println("exception=" + indexes[i] + " <" + names[i] + ">"); } public void enterSourceFile(SourceFile obj) { println("source=" + obj.getFileIndex() + " <" + obj.getFileName() + ">"); } public void enterCode(Code obj) { println("maxStack=" + obj.getMaxStack()); println("maxLocals=" + obj.getMaxLocals()); println(""); } public void enterExceptionHandler(ExceptionHandler obj) { openBlock("ExceptionHandler"); println("startPc=" + obj.getTryStartPc()); println("endPc=" + obj.getTryEndPc()); println("handlerPc=" + obj.getHandlerStartPc()); println("catch=" + obj.getCatchIndex() + " <" + obj.getCatchName() + ">"); } public void exitExceptionHandler(ExceptionHandler obj) { closeBlock(); } public void enterInnerClass(InnerClass obj) { openBlock("InnerClass"); println("access=" + obj.getAccessFlags()); println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); println("type=" + obj.getTypeIndex() + "<" + obj.getTypeName() + ">"); println("declarer=" + obj.getDeclarerIndex() + "<" + obj.getDeclarerName() + ">"); } public void exitInnerClass(InnerClass obj) { closeBlock(); } public void enterLineNumber(LineNumber obj) { openBlock("LineNumber"); println("startPc=" + obj.getStartPc()); println("line=" + obj.getLine()); } public void exitLineNumber(LineNumber obj) { closeBlock(); } public void enterLocalVariable(LocalVariable obj) { openBlock("LocalVariable"); println("startPc=" + obj.getStartPc()); println("length=" + obj.getLength()); println("local=" + obj.getLocal()); println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); println("type=" + obj.getTypeIndex() + " <" + obj.getTypeName() + ">"); } public void exitLocalVariable(LocalVariable obj) { closeBlock(); } public void enterLocalVariableType(LocalVariableType obj) { openBlock("LocalVariableType"); println("startPc=" + obj.getStartPc()); println("length=" + obj.getLength()); println("local=" + obj.getLocal()); println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); println("signature=" + obj.getTypeIndex() + " <" + obj.getTypeName() + ">"); } public void exitLocalVariableType(LocalVariableType obj) { closeBlock(); } public void enterAnnotation(Annotation obj) { openBlock("Annotation"); println("type=" + obj.getTypeIndex() + " <" + obj.getTypeName() + ">"); } public void exitAnnotation(Annotation obj) { closeBlock(); } public void enterAnnotationProperty(Annotation.Property obj) { openBlock("Property"); println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">"); Object val = obj.getValue(); if (val instanceof Object[]) { Object[] arr = (Object[]) val; for (int i = 0; i < arr.length; i++) printAnnotationPropertyValue(arr[i]); } else printAnnotationPropertyValue(val); } private void printAnnotationPropertyValue(Object obj) { if (obj == null) println("value=null"); else if (obj instanceof Annotation) { _out.print(_prefix); _out.print("value="); ((Annotation) obj).acceptVisit(this); } else println("value=(" + obj.getClass().getName() + ") " + obj); } public void exitAnnotationProperty(Annotation.Property obj) { closeBlock(); } public void enterInstruction(Instruction obj) { _out.print(_prefix + obj.getByteIndex() + " " + obj.getName() + " "); } public void exitInstruction(Instruction obj) { _out.println(); } public void enterClassInstruction(ClassInstruction obj) { _out.print(obj.getTypeIndex() + " <" + obj.getTypeName() + ">"); } public void enterConstantInstruction(ConstantInstruction obj) { _out.print("<" + obj.getValue() + ">"); } public void enterGetFieldInstruction(GetFieldInstruction obj) { _out.print(obj.getFieldIndex() + " <" + obj.getFieldTypeName() + " " + obj.getFieldDeclarerName() + "." + obj.getFieldName() + ">"); } public void enterIIncInstruction(IIncInstruction obj) { _out.print(obj.getLocal() + " "); if (obj.getIncrement() < 0) _out.print("-"); _out.print(obj.getIncrement()); } public void enterJumpInstruction(JumpInstruction obj) { _out.print(obj.getOffset()); } public void enterIfInstruction(IfInstruction obj) { _out.print(obj.getOffset()); } public void enterLoadInstruction(LoadInstruction obj) { _out.print("<" + obj.getLocal() + ">"); } public void enterLookupSwitchInstruction(LookupSwitchInstruction obj) { _out.println(); _prefix += " "; int[] offsets = obj.getOffsets(); int[] matches = obj.getMatches(); for (int i = 0; i < offsets.length; i++) println("case " + matches[i] + "=" + offsets[i]); _out.print(_prefix + "default=" + obj.getDefaultOffset()); _prefix = _prefix.substring(2); } public void enterMethodInstruction(MethodInstruction obj) { _out.print(obj.getMethodIndex() + " <" + obj.getMethodReturnName() + " " + obj.getMethodDeclarerName() + "." + obj.getMethodName() + "("); String[] params = obj.getMethodParamNames(); int dotIndex; for (int i = 0; i < params.length; i++) { dotIndex = params[i].lastIndexOf('.'); if (dotIndex != -1) params[i] = params[i].substring(dotIndex + 1); _out.print(params[i]); if (i != (params.length - 1)) _out.print(", "); } _out.print(")>"); } public void enterMultiANewArrayInstruction(MultiANewArrayInstruction obj) { _out.print(obj.getTypeIndex() + " " + obj.getDimensions() + " <" + obj.getTypeName()); String post = ""; for (int i = 0; i < obj.getDimensions(); i++) post += "[]"; _out.print(post + ">"); } public void enterNewArrayInstruction(NewArrayInstruction obj) { _out.print(obj.getTypeCode() + " <" + obj.getTypeName() + "[]>"); } public void enterPutFieldInstruction(PutFieldInstruction obj) { _out.print(obj.getFieldIndex() + " <" + obj.getFieldTypeName() + " " + obj.getFieldDeclarerName() + "." + obj.getFieldName() + ">"); } public void enterRetInstruction(RetInstruction obj) { _out.print(obj.getLocal()); } public void enterStoreInstruction(StoreInstruction obj) { _out.print("<" + obj.getLocal() + ">"); } public void enterTableSwitchInstruction(TableSwitchInstruction obj) { _out.println(); _prefix += " "; println("low=" + obj.getLow()); println("high=" + obj.getHigh()); int[] offsets = obj.getOffsets(); for (int i = 0; i < offsets.length; i++) println("case=" + offsets[i]); _out.print(_prefix + "default=" + obj.getDefaultOffset()); _prefix = _prefix.substring(2); } public void enterWideInstruction(WideInstruction obj) { int ins = obj.getInstruction(); _out.print(ins + " <" + Constants.OPCODE_NAMES[ins] + ">"); } public void enterConstantPool(ConstantPool obj) { openBlock("ConstantPool"); } public void exitConstantPool(ConstantPool obj) { closeBlock(); } public void enterEntry(Entry obj) { String name = obj.getClass().getName(); openBlock(obj.getIndex() + ": " + name.substring(name.lastIndexOf('.') + 1)); } public void exitEntry(Entry obj) { closeBlock(); } public void enterClassEntry(ClassEntry obj) { println("name=" + obj.getNameIndex()); } public void enterDoubleEntry(DoubleEntry obj) { println("value=" + obj.getValue()); } public void enterFieldEntry(FieldEntry obj) { println("class=" + obj.getClassIndex()); println("nameAndType=" + obj.getNameAndTypeIndex()); } public void enterFloatEntry(FloatEntry obj) { println("value=" + obj.getValue()); } public void enterIntEntry(IntEntry obj) { println("value=" + obj.getValue()); } public void enterInterfaceMethodEntry(InterfaceMethodEntry obj) { println("class=" + obj.getClassIndex()); println("nameAndType=" + obj.getNameAndTypeIndex()); } public void enterLongEntry(LongEntry obj) { println("value=" + obj.getValue()); } public void enterMethodEntry(MethodEntry obj) { println("class=" + obj.getClassIndex()); println("nameAndType=" + obj.getNameAndTypeIndex()); } public void enterNameAndTypeEntry(NameAndTypeEntry obj) { println("name=" + obj.getNameIndex()); println("descriptor=" + obj.getDescriptorIndex()); } public void enterStringEntry(StringEntry obj) { println("index=" + obj.getStringIndex()); } public void enterUTF8Entry(UTF8Entry obj) { println("value=" + obj.getValue()); } private void println(String ln) { _out.print(_prefix); _out.println(ln); } private void openBlock(String name) { println(name + " {"); _prefix += " "; } private void closeBlock() { _prefix = _prefix.substring(2); println("}"); } } serp-1.14.1.orig/src/main/java/serp/bytecode/visitor/BCVisitor.java0000755000000000000000000002212010517502267022012 0ustar package serp.bytecode.visitor; import serp.bytecode.*; import serp.bytecode.Deprecated; import serp.bytecode.lowlevel.*; /** * Base class for visitors on a bytecode entity. The public {@link #visit} * method will traverse the object graph of the given entity, calling the * enter* and exit* methods as it visits each * object. The traversal is done depth-first. Subclasses should override * only the methods for visiting the entities they are interested in. * Whenever there is a general method (i.e. enter/exitEntry) as * well as a more specific one (i.e. enter/exitStringEntry), the * more general method will be called first, followed by a call on the correct * specific method. Most subclasses will override either the general or * specific cases, but not both. * * @author Abe White */ public class BCVisitor { /** * Visit the given entity. */ public void visit(VisitAcceptor obj) { if (obj == null) return; obj.acceptVisit(this); } public void enterProject(Project obj) { } public void exitProject(Project obj) { } public void enterBCClass(BCClass obj) { } public void exitBCClass(BCClass obj) { } public void enterBCMember(BCMember obj) { } public void exitBCMember(BCMember obj) { } public void enterBCField(BCField obj) { } public void exitBCField(BCField obj) { } public void enterBCMethod(BCMethod obj) { } public void exitBCMethod(BCMethod obj) { } public void enterAttribute(Attribute obj) { } public void exitAttribute(Attribute obj) { } public void enterConstantValue(ConstantValue obj) { } public void exitConstantValue(ConstantValue obj) { } public void enterDeprecated(Deprecated obj) { } public void exitDeprecated(Deprecated obj) { } public void enterExceptions(Exceptions obj) { } public void exitExceptions(Exceptions obj) { } public void enterInnerClasses(InnerClasses obj) { } public void exitInnerClasses(InnerClasses obj) { } public void enterLineNumberTable(LineNumberTable obj) { } public void exitLineNumberTable(LineNumberTable obj) { } public void enterLocalVariableTable(LocalVariableTable obj) { } public void exitLocalVariableTable(LocalVariableTable obj) { } public void enterLocalVariableTypeTable(LocalVariableTypeTable obj) { } public void exitLocalVariableTypeTable(LocalVariableTypeTable obj) { } public void enterAnnotations(Annotations obj) { } public void exitAnnotations(Annotations obj) { } public void enterAnnotation(Annotation obj) { } public void exitAnnotation(Annotation obj) { } public void enterAnnotationProperty(Annotation.Property obj) { } public void exitAnnotationProperty(Annotation.Property obj) { } public void enterSourceFile(SourceFile obj) { } public void exitSourceFile(SourceFile obj) { } public void enterSynthetic(Synthetic obj) { } public void exitSynthetic(Synthetic obj) { } public void enterUnknownAttribute(UnknownAttribute obj) { } public void exitUnknownAttribute(UnknownAttribute obj) { } public void enterCode(Code obj) { } public void exitCode(Code obj) { } public void enterExceptionHandler(ExceptionHandler obj) { } public void exitExceptionHandler(ExceptionHandler obj) { } public void enterInnerClass(InnerClass obj) { } public void exitInnerClass(InnerClass obj) { } public void enterLineNumber(LineNumber obj) { } public void exitLineNumber(LineNumber obj) { } public void enterLocalVariable(LocalVariable obj) { } public void exitLocalVariable(LocalVariable obj) { } public void enterLocalVariableType(LocalVariableType obj) { } public void exitLocalVariableType(LocalVariableType obj) { } public void enterInstruction(Instruction obj) { } public void exitInstruction(Instruction obj) { } public void enterArrayLoadInstruction(ArrayLoadInstruction obj) { } public void exitArrayLoadInstruction(ArrayLoadInstruction obj) { } public void enterArrayStoreInstruction(ArrayStoreInstruction obj) { } public void exitArrayStoreInstruction(ArrayStoreInstruction obj) { } public void enterClassInstruction(ClassInstruction obj) { } public void exitClassInstruction(ClassInstruction obj) { } public void enterConstantInstruction(ConstantInstruction obj) { } public void exitConstantInstruction(ConstantInstruction obj) { } public void enterConvertInstruction(ConvertInstruction obj) { } public void exitConvertInstruction(ConvertInstruction obj) { } public void enterGetFieldInstruction(GetFieldInstruction obj) { } public void exitGetFieldInstruction(GetFieldInstruction obj) { } public void enterIIncInstruction(IIncInstruction obj) { } public void exitIIncInstruction(IIncInstruction obj) { } public void enterJumpInstruction(JumpInstruction obj) { } public void exitJumpInstruction(JumpInstruction obj) { } public void enterIfInstruction(IfInstruction obj) { } public void exitIfInstruction(IfInstruction obj) { } public void enterLoadInstruction(LoadInstruction obj) { } public void exitLoadInstruction(LoadInstruction obj) { } public void enterLookupSwitchInstruction(LookupSwitchInstruction obj) { } public void exitLookupSwitchInstruction(LookupSwitchInstruction obj) { } public void enterMathInstruction(MathInstruction obj) { } public void exitMathInstruction(MathInstruction obj) { } public void enterMethodInstruction(MethodInstruction obj) { } public void exitMethodInstruction(MethodInstruction obj) { } public void enterMultiANewArrayInstruction(MultiANewArrayInstruction obj) { } public void exitMultiANewArrayInstruction(MultiANewArrayInstruction obj) { } public void enterNewArrayInstruction(NewArrayInstruction obj) { } public void exitNewArrayInstruction(NewArrayInstruction obj) { } public void enterPutFieldInstruction(PutFieldInstruction obj) { } public void exitPutFieldInstruction(PutFieldInstruction obj) { } public void enterRetInstruction(RetInstruction obj) { } public void exitRetInstruction(RetInstruction obj) { } public void enterReturnInstruction(ReturnInstruction obj) { } public void exitReturnInstruction(ReturnInstruction obj) { } public void enterStackInstruction(StackInstruction obj) { } public void exitStackInstruction(StackInstruction obj) { } public void enterStoreInstruction(StoreInstruction obj) { } public void exitStoreInstruction(StoreInstruction obj) { } public void enterTableSwitchInstruction(TableSwitchInstruction obj) { } public void exitTableSwitchInstruction(TableSwitchInstruction obj) { } public void enterWideInstruction(WideInstruction obj) { } public void exitWideInstruction(WideInstruction obj) { } public void enterMonitorEnterInstruction(MonitorEnterInstruction obj) { } public void exitMonitorEnterInstruction(MonitorEnterInstruction obj) { } public void enterMonitorExitInstruction(MonitorExitInstruction obj) { } public void exitMonitorExitInstruction(MonitorExitInstruction obj) { } public void enterCmpInstruction(CmpInstruction obj) { } public void exitCmpInstruction(CmpInstruction obj) { } public void enterConstantPool(ConstantPool obj) { } public void exitConstantPool(ConstantPool obj) { } public void enterEntry(Entry obj) { } public void exitEntry(Entry obj) { } public void enterClassEntry(ClassEntry obj) { } public void exitClassEntry(ClassEntry obj) { } public void enterDoubleEntry(DoubleEntry obj) { } public void exitDoubleEntry(DoubleEntry obj) { } public void enterFieldEntry(FieldEntry obj) { } public void exitFieldEntry(FieldEntry obj) { } public void enterFloatEntry(FloatEntry obj) { } public void exitFloatEntry(FloatEntry obj) { } public void enterIntEntry(IntEntry obj) { } public void exitIntEntry(IntEntry obj) { } public void enterInterfaceMethodEntry(InterfaceMethodEntry obj) { } public void exitInterfaceMethodEntry(InterfaceMethodEntry obj) { } public void enterLongEntry(LongEntry obj) { } public void exitLongEntry(LongEntry obj) { } public void enterMethodEntry(MethodEntry obj) { } public void exitMethodEntry(MethodEntry obj) { } public void enterNameAndTypeEntry(NameAndTypeEntry obj) { } public void exitNameAndTypeEntry(NameAndTypeEntry obj) { } public void enterStringEntry(StringEntry obj) { } public void exitStringEntry(StringEntry obj) { } public void enterUTF8Entry(UTF8Entry obj) { } public void exitUTF8Entry(UTF8Entry obj) { } } serp-1.14.1.orig/src/main/java/serp/bytecode/visitor/VisitAcceptor.java0000755000000000000000000000110410460270415022716 0ustar package serp.bytecode.visitor; /** * Interface denoting an entity that can accept a {@link BCVisitor} and * provide its internal state to it. All entities in the bytecode framework * implement this interface. * * @author Abe White */ public interface VisitAcceptor { /** * Accept a visit from a {@link BCVisitor}, calling the appropriate methods * to notify the visitor that it has entered this entity, and * to provide it with the proper callbacks for each sub-entity owned * by this one. */ public void acceptVisit(BCVisitor visitor); } serp-1.14.1.orig/src/main/java/serp/bytecode/LocalTable.java0000755000000000000000000001275710460270414020461 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * Code blocks compiled from source have local tables mapping * locals used in opcodes to their names and descriptions. * * @author Abe White */ public abstract class LocalTable extends Attribute implements InstructionPtr { private List _locals = new ArrayList(); LocalTable(int nameIndex, Attributes owner) { super(nameIndex, owner); } /** * Return all the locals of this method. */ public Local[] getLocals() { return (Local[]) _locals.toArray(newLocalArray(_locals.size())); } /** * Return the local with the given locals index, or null if none. */ public Local getLocal(int local) { for (int i = 0; i < _locals.size(); i++) if (((Local) _locals.get(i)).getLocal() == local) return (Local) _locals.get(i); return null; } /** * Return the local with the given name, or null if none. If multiple * locals have the given name, which is returned is undefined. */ public Local getLocal(String name) { String loc; for (int i = 0; i < _locals.size(); i++) { loc = ((Local) _locals.get(i)).getName(); if ((loc == null && name == null) || (loc != null && loc.equals(name))) return (Local) _locals.get(i); } return null; } /** * Return all locals with the given name, or empty array if none. */ public Local[] getLocals(String name) { List matches = new LinkedList(); String loc; for (int i = 0; i < _locals.size(); i++) { loc = ((Local) _locals.get(i)).getName(); if ((loc == null && name == null) || (loc != null && loc.equals(name))) matches.add(_locals.get(i)); } return (Local[]) matches.toArray(newLocalArray(matches.size())); } /** * Set the locals of this table. This method is useful when * importing locals from another method. */ public void setLocals(Local[] locals) { clear(); if (locals != null) for (int i = 0; i < locals.length; i++) addLocal(locals[i]); } /** * Import a local from another method/class. Note that * the program counter and length from the given local is copied * directly, and thus will be incorrect unless this method is the same * as the one the local is copied from, or the pc and length are reset. */ public Local addLocal(Local local) { Local newLocal = addLocal(local.getName(), local.getTypeName()); newLocal.setStartPc(local.getStartPc()); newLocal.setLength(local.getLength()); return newLocal; } /** * Add a local to this table. */ public Local addLocal() { Local local = newLocal(); _locals.add(local); return local; } /** * Create a new element of this table. */ protected abstract Local newLocal(); /** * Create a new array. */ protected abstract Local[] newLocalArray(int size); /** * Add a local to this table. */ public Local addLocal(String name, String type) { Local local = addLocal(); local.setName(name); local.setType(type); return local; } /** * Clear all locals from this table. */ public void clear() { for (int i = 0; i < _locals.size(); i++) ((Local) _locals.get(i)).invalidate(); _locals.clear(); } /** * Removes the local with the given locals index from the table. * * @return true if a local was removed, false otherwise */ public boolean removeLocal(int local) { return removeLocal(getLocal(local)); } /** * Removes the local with the given name from this method. * * @return true if a local was removed, false otherwise */ public boolean removeLocal(String name) { return removeLocal(getLocal(name)); } /** * Removes a local from this method. After this method, the local * will be invalid, and the result of any operations on it is undefined. * * @return true if a local was removed, false otherwise */ public boolean removeLocal(Local local) { if (local == null || !_locals.remove(local)) return false; local.invalidate(); return true; } public void updateTargets() { for (int i = 0; i < _locals.size(); i++) ((Local) _locals.get(i)).updateTargets(); } public void replaceTarget(Instruction oldTarget, Instruction newTarget) { for (int i = 0; i < _locals.size(); i++) ((Local) _locals.get(i)).replaceTarget(oldTarget, newTarget); } public Code getCode() { return (Code) getOwner(); } int getLength() { return 2 + (10 * _locals.size()); } void read(Attribute other) { setLocals(((LocalTable) other).getLocals()); } void read(DataInput in, int length) throws IOException { clear(); int numLocals = in.readUnsignedShort(); Local Local; for (int i = 0; i < numLocals; i++) { Local = addLocal(); Local.read(in); } } void write(DataOutput out, int length) throws IOException { out.writeShort(_locals.size()); for (int i = 0; i < _locals.size(); i++) ((Local) _locals.get(i)).write(out); } } serp-1.14.1.orig/src/main/java/serp/bytecode/ArrayStoreInstruction.java0000755000000000000000000000525010460270414023002 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * Store a value from the stack into an array. * * @author Abe White */ public class ArrayStoreInstruction extends ArrayInstruction { private static final Class[][] _mappings = new Class[][] { { boolean.class, int.class }, { void.class, int.class }, }; ArrayStoreInstruction(Code owner) { super(owner); } ArrayStoreInstruction(Code owner, int opcode) { super(owner, opcode); } public int getLogicalStackChange() { switch (getOpcode()) { case Constants.NOP: return 0; default: return -3; } } public int getStackChange() { switch (getOpcode()) { case Constants.DASTORE: case Constants.LASTORE: return -4; case Constants.NOP: return 0; default: return -3; } } public String getTypeName() { switch (getOpcode()) { case Constants.IASTORE: return int.class.getName(); case Constants.LASTORE: return long.class.getName(); case Constants.FASTORE: return float.class.getName(); case Constants.DASTORE: return double.class.getName(); case Constants.AASTORE: return Object.class.getName(); case Constants.BASTORE: return byte.class.getName(); case Constants.CASTORE: return char.class.getName(); case Constants.SASTORE: return short.class.getName(); default: return null; } } public TypedInstruction setType(String type) { type = mapType(type, _mappings, true); if (type == null) return (TypedInstruction) setOpcode(Constants.NOP); switch (type.charAt(0)) { case 'i': return (TypedInstruction) setOpcode(Constants.IASTORE); case 'l': return (TypedInstruction) setOpcode(Constants.LASTORE); case 'f': return (TypedInstruction) setOpcode(Constants.FASTORE); case 'd': return (TypedInstruction) setOpcode(Constants.DASTORE); case 'b': return (TypedInstruction) setOpcode(Constants.BASTORE); case 'c': return (TypedInstruction) setOpcode(Constants.CASTORE); case 's': return (TypedInstruction) setOpcode(Constants.SASTORE); default: return (TypedInstruction) setOpcode(Constants.AASTORE); } } public void acceptVisit(BCVisitor visit) { visit.enterArrayStoreInstruction(this); visit.exitArrayStoreInstruction(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/MonitorExitInstruction.java0000755000000000000000000000067410460270414023175 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * The monitorexit instruction. * * @author Abe White */ public class MonitorExitInstruction extends MonitorInstruction { MonitorExitInstruction(Code owner) { super(owner, Constants.MONITOREXIT); } public void acceptVisit(BCVisitor visit) { visit.enterMonitorExitInstruction(this); visit.exitMonitorExitInstruction(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/Code.java0000755000000000000000000023600510640272103017320 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; /** * Representation of a code block of a class. * The methods of this class mimic those of the same name in the * {@link java.util.ListIterator} class. Note that the size and index * information of the code block will change as opcodes are added. * *

Code blocks are usually obtained from a {@link BCMethod}, but can also * be constructed via the default constructor. Blocks created this way can * be used to provide template instructions to the various search/replace * methods in this class.

* *

The code class contains methods named after most JVM instructions, each * of which adds the matching opcode to the code block at the * current iterator position. It also contains generic versions of various * JVM instructions whose opcodes are not set until their properties are set * with additional information. Almost all instruction types are able to * 'morph' their opcode on the fly as the arguments to the instruction change. * Thus the developer can initially call, for example, the aload * opcode, but later change the type to load to int and the * opcode will automatically morph to the iload opcode.

* * @author Abe White */ public class Code extends Attribute { private final CodeEntry _head; private final CodeEntry _tail; private CodeIterator _ci; private int _maxStack = 0; private int _maxLocals = 0; private int _size = 0; private Collection _handlers = new LinkedList(); private Collection _attrs = new LinkedList(); private boolean _byteIndexesValid; Code(int nameIndex, Attributes owner) { super(nameIndex, owner); _head = new CodeEntry(); _tail = new CodeEntry(); _head.next = _tail; _tail.prev = _head; _ci = new CodeIterator(_head, -1); } /** * The public constructor is for creating template code modules * that produce {@link Instruction}s used in matching through * the various search and replace methods. */ public Code() { this(0, new Project().loadClass("", null).declareMethod("", void.class, null)); } /** * The owning method. */ public BCMethod getMethod() { return (BCMethod) getOwner(); } Collection getAttributesHolder() { return _attrs; } //////////////////////////// // Stack, Locals operations //////////////////////////// /** * Return the maximum stack depth set for this code block. */ public int getMaxStack() { return _maxStack; } /** * Set the maximum stack depth for this code block. */ public void setMaxStack(int max) { _maxStack = max; } /** * Return the maximum number of local variables (including params) * set for this method. */ public int getMaxLocals() { return _maxLocals; } /** * Set the maximum number of local variables (including params) in * this method. */ public void setMaxLocals(int max) { _maxLocals = max; } /** * Return the local variable index for the paramIndex'th parameter to * the method. Local variable indexes differ from parameter indexes because: * a) non-static methods use the 0th local variable for the 'this' ptr, and * b) double and long values occupy two spots in the local variable array. * Returns -1 if the given index is not valid. */ public int getLocalsIndex(int paramIndex) { if (paramIndex < 0) return -1; int pos = 0; if (!getMethod().isStatic()) pos = 1; String[] params = getMethod().getParamNames(); for (int i = 0; i < paramIndex; i++, pos++) { if (i == params.length) return -1; if (params[i].equals(long.class.getName()) || params[i].equals(double.class.getName())) pos++; } return pos; } /** * Return the parameter index for the given local index, or -1 if * the given local does not reference a param. * * @see #getLocalsIndex */ public int getParamsIndex(int localIndex) { int pos = 0; if (!getMethod().isStatic()) pos = 1; String[] params = getMethod().getParamNames(); for (int i = 0; i < params.length; i++, pos++) { if (localIndex == pos) return i; if (params[i].equals(long.class.getName()) || params[i].equals(double.class.getName())) pos++; } return -1; } /** * Return the next available local variable index. */ public int getNextLocalsIndex() { calculateMaxLocals(); return getMaxLocals(); } /** * Calculate and set the number of locals needed based on * the instructions used and the parameters of the method this code * block is a part of. * * @see #setMaxLocals */ public void calculateMaxLocals() { // start off assuming the max number needed is the // number for all the params String[] params = getMethod().getParamNames(); int max = 0; if ((params.length == 0) && !getMethod().isStatic()) max = 1; else if (params.length > 0) { max = getLocalsIndex(params.length - 1) + 1; if (params[params.length - 1].equals(long.class.getName()) || params[params.length - 1].equals(double.class.getName())) max++; } // check to see if there are any store instructions that // try to reference beyond that point StoreInstruction store; int current; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { current = 0; if (entry instanceof StoreInstruction) { store = (StoreInstruction) entry; current = store.getLocal() + 1; if (store.getType().equals(long.class) || store.getType().equals(double.class)) current++; if (current > max) max = current; } } setMaxLocals(max); } /** * Calculate and set the maximum stack depth needed for * the instructions used. * * @see #setMaxStack */ public void calculateMaxStack() { int stack = 0; int max = 0; ExceptionHandler[] handlers = getExceptionHandlers(); Instruction ins; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { ins = (Instruction) entry; stack += ins.getStackChange(); // if this is the start of a try, the exception will be placed // on the stack for (int j = 0; j < handlers.length; j++) if (handlers[j].getTryStart() == ins) stack++; if (stack > max) max = stack; } setMaxStack(max); } /////////////////////////////// // ExceptionHandler operations /////////////////////////////// /** * Return the exception handlers active in this code block, or an * empty array if none. */ public ExceptionHandler[] getExceptionHandlers() { return (ExceptionHandler[]) _handlers.toArray (new ExceptionHandler[_handlers.size()]); } /** * Return the exception handler that catches the given exception type; * if multiple handlers catch the given type, which is returned is * undefined. */ public ExceptionHandler getExceptionHandler(String catchType) { catchType = getProject().getNameCache().getExternalForm(catchType, false); String type; ExceptionHandler[] handlers = getExceptionHandlers(); for (int i = 0; i < handlers.length; i++) { type = handlers[i].getCatchName(); if ((type == null && catchType == null) || (type != null && type.equals(catchType))) return handlers[i]; } return null; } /** * Return the exception handler that catches the given exception type; * if multiple handlers catch the given type, which is returned is * undefined. */ public ExceptionHandler getExceptionHandler(Class catchType) { if (catchType == null) return getExceptionHandler((String) null); return getExceptionHandler(catchType.getName()); } /** * Return the exception handler that catches the given exception type; * if multiple handlers catch the given type, which is returned is * undefined. */ public ExceptionHandler getExceptionHandler(BCClass catchType) { if (catchType == null) return getExceptionHandler((String) null); return getExceptionHandler(catchType.getName()); } /** * Return all exception handlers that catch the given exception type, * or an empty array if none. */ public ExceptionHandler[] getExceptionHandlers(String catchType) { catchType = getProject().getNameCache().getExternalForm(catchType, false); List matches = new LinkedList(); String type; ExceptionHandler[] handlers = getExceptionHandlers(); for (int i = 0; i < handlers.length; i++) { type = handlers[i].getCatchName(); if ((type == null && catchType == null) || (type != null && type.equals(catchType))) matches.add(handlers[i]); } return (ExceptionHandler[]) matches.toArray (new ExceptionHandler[matches.size()]); } /** * Return all exception handlers that catch the given exception type, * or an empty array if none. */ public ExceptionHandler[] getExceptionHandlers(Class catchType) { if (catchType == null) return getExceptionHandlers((String) null); return getExceptionHandlers(catchType.getName()); } /** * Return all exception handlers that catch the given exception type, * or an empty array if none. */ public ExceptionHandler[] getExceptionHandlers(BCClass catchType) { if (catchType == null) return getExceptionHandlers((String) null); return getExceptionHandlers(catchType.getName()); } /** * Set the exception handlers for this code block. This method is useful * for importing all handlers from another code block. Set to null or * empty array if none. */ public void setExceptionHandlers(ExceptionHandler[] handlers) { clearExceptionHandlers(); if (handlers != null) for (int i = 0; i < handlers.length; i++) addExceptionHandler(handlers[i]); } /** * Import the given exception handler from another code block. */ public ExceptionHandler addExceptionHandler(ExceptionHandler handler) { ExceptionHandler newHandler = addExceptionHandler(); newHandler.read(handler); return newHandler; } /** * Add an exception handler to this code block. */ public ExceptionHandler addExceptionHandler() { ExceptionHandler handler = new ExceptionHandler(this); _handlers.add(handler); return handler; } /** * Add an exception handler to this code block. * * @param tryStart the first instruction of the try {} block * @param tryEnd the last instruction of the try {} block * @param handlerStart the first instruction of the catch {} block * @param catchType the type of exception being caught */ public ExceptionHandler addExceptionHandler(Instruction tryStart, Instruction tryEnd, Instruction handlerStart, String catchType) { ExceptionHandler handler = addExceptionHandler(); handler.setTryStart(tryStart); handler.setTryEnd(tryEnd); handler.setHandlerStart(handlerStart); handler.setCatch(catchType); return handler; } /** * Add an exception handler to this code block. * * @param tryStart the first instruction of the try {} block * @param tryEnd the last instruction of the try {} block * @param handlerStart the first instruction of the catch {} block * @param catchType the type of exception being caught */ public ExceptionHandler addExceptionHandler(Instruction tryStart, Instruction tryEnd, Instruction handlerStart, Class catchType) { String catchName = null; if (catchType != null) catchName = catchType.getName(); return addExceptionHandler(tryStart, tryEnd, handlerStart, catchName); } /** * Add an exception handler to this code block. * * @param tryStart the first instruction of the try {} block * @param tryEnd the last instruction of the try {} block * @param handlerStart the first instruction of the catch {} block * @param catchType the type of exception being caught */ public ExceptionHandler addExceptionHandler(Instruction tryStart, Instruction tryEnd, Instruction handlerStart, BCClass catchType) { String catchName = null; if (catchType != null) catchName = catchType.getName(); return addExceptionHandler(tryStart, tryEnd, handlerStart, catchName); } /** * Clear all exception handlers. */ public void clearExceptionHandlers() { ExceptionHandler handler; for (Iterator itr = _handlers.iterator(); itr.hasNext();) { handler = (ExceptionHandler) itr.next(); itr.remove(); handler.invalidate(); } } /** * Remove the exception handler that catches the given type. */ public boolean removeExceptionHandler(String catchType) { return removeExceptionHandler(getExceptionHandler(catchType)); } /** * Remove the exception handler that catches the given type. * * @return true if the handler was removed, false otherwise */ public boolean removeExceptionHandler(Class catchType) { if (catchType == null) return removeExceptionHandler((String) null); return removeExceptionHandler(catchType.getName()); } /** * Remove the exception handler that catches the given type. * * @return true if the handler was removed, false otherwise */ public boolean removeExceptionHandler(BCClass catchType) { if (catchType == null) return removeExceptionHandler((String) null); return removeExceptionHandler(catchType.getName()); } /** * Remove an exception handler from this code block. The given handler * must belong to this code block. */ public boolean removeExceptionHandler(ExceptionHandler handler) { if ((handler == null) || !_handlers.remove(handler)) return false; handler.invalidate(); return true; } ///////////////////////// // Code block operations ///////////////////////// /** * Return the number of instructions in the method. */ public int size() { return _size; } /** * Reset the position of the instruction iterator to the first opcode. */ public void beforeFirst() { _ci = new CodeIterator(_head, -1); } /** * Set the position of the instruction iterator to after the last opcode. */ public void afterLast() { if (_size == 0) _ci = new CodeIterator(_head, -1); else _ci = new CodeIterator(_tail.prev, _size - 1); } /** * Position the iterator just before the given instruction. The * instruction must belong to this method. */ public void before(Instruction ins) { if (ins.getCode() != this) throw new IllegalArgumentException("ins.code != this"); _ci = new CodeIterator(ins.prev, CodeIterator.UNSET); } /** * Position the iterator just after the given instruction. The * instruction must belong to this method. */ public void after(Instruction ins) { before(ins); next(); } /** * Return true if a subsequent call to {@link #next} will return an * instruction. */ public boolean hasNext() { return _ci.hasNext(); } /** * Return true if a subsequent call to {@link #previous} will return an * instruction. */ public boolean hasPrevious() { return _ci.hasPrevious(); } /** * Return the next instruction. */ public Instruction next() { return (Instruction) _ci.next(); } /** * Return the index of the next instruction, or {@link #size} if at end. */ public int nextIndex() { return _ci.nextIndex(); } /** * Return the previous instruction. */ public Instruction previous() { return (Instruction) _ci.previous(); } /** * Return the index of the previous instruction, or -1 if at beginning. */ public int previousIndex() { return _ci.previousIndex(); } /** * Place the iterator before the given list index. */ public void before(int index) { if (index < 0 || index >= _size) throw new IndexOutOfBoundsException(String.valueOf(index)); CodeEntry entry = _head; for (int i = 0; i < index; entry = entry.next, i++); _ci = new CodeIterator(entry, index - 1); } /** * Place the iterator after the given list index. */ public void after(int index) { before(index); next(); } /** * Find the next instruction from the current iterator position that * matches the given one, according to the {@link Object#equals} methods of * the instruction types. This allows for matching based on template * instructions, as the equals methods of most instructions return * true if the information for the given instruction has not been filled * in. If a match is found, the iterator is placed after the matching * Instruction. If no match is found, moves the iterator to * {@link #afterLast}. * * @return true if match found */ public boolean searchForward(Instruction template) { if (template == null) return false; while (hasNext()) if (template.equalsInstruction(next())) return true; return false; } /** * Find the closest previous instruction from the current iterator * position that matches the given one, according to the * {@link Object#equals} methods of the instruction types. This allows * for matching based on template instructions, as the equals methods of * most instructions return true if the information for the given * instruction has not been filled in. If a match is found, the iterator * is placed before the matching Instruction. If no match is found, * moves the iterator to {@link #beforeFirst}. * * @return true if match found */ public boolean searchBackward(Instruction template) { if (template == null) return false; while (hasPrevious()) if (template.equalsInstruction(previous())) return true; return false; } /** * Adds a copy of the given instruction. * * @return the newly added instruction */ public Instruction add(Instruction ins) { Instruction newIns = createInstruction(ins.getOpcode()); newIns.read(ins); _ci.add(newIns); return newIns; } /** * Replaces the last iterated instruction with a copy of the given one. * This method will also make sure that all jump points * that referenced the old opcode are updated correctly. * * @return the newly added instruction * @see ListIterator#set */ public Instruction set(Instruction ins) { Instruction newIns = createInstruction(ins.getOpcode()); newIns.read(ins); _ci.set(newIns); return newIns; } /** * Replaces all the instructions in this code block that match the * given template with the given instruction. After this method, * the iterator will be {@link #afterLast}. * * @return the number of substitutions made */ public int replace(Instruction template, Instruction with) { beforeFirst(); int count; for (count = 0; searchForward(template); count++) set(with); return count; } /** * Equivalent to looping over each given template/replacement * pair and calling {@link #replace(Instruction,Instruction)} for each. */ public int replace(Instruction[] templates, Instruction[] with) { if (templates == null || with == null) return 0; int count = 0; for (int i = 0; i < templates.length; i++) { if (with == null) count += replace(templates[i], null); else count += replace(templates[i], with[i]); } return count; } /** * Remove the last iterated instruction. * * @see ListIterator#remove */ public void remove() { _ci.remove(); } ////////////////////////// // Instruction operations ////////////////////////// /** * Load a class constant onto the stack. * For primitive types, this translates into a * getstatic for the TYPE field of the primitive's wrapper type. * For non-primitives, things get much more complex. Suffice it to * say that the operation involves adding synthetic static fields * and even methods to the class. Note that this instruction requires * up to 3 stack positions to execute. */ public ClassConstantInstruction classconstant() { return new ClassConstantInstruction(getMethod().getDeclarer(), this, nop()); } /** * Add the nop opcode. */ public Instruction nop() { return addInstruction(Constants.NOP); } /** * Load some constant onto the stack. The {@link ConstantInstruction} * type takes any constant and correctly translates it into the proper * opcode, depending on the constant type and value. For example, * if the constant value is set to 0L, the opcode will be set to * lconst0. */ public ConstantInstruction constant() { return (ConstantInstruction) addInstruction(new ConstantInstruction (this)); } /** * Load a local variable onto the stack. This instruction will result * in a nop until its type and local index are set. */ public LoadInstruction xload() { return (LoadInstruction) addInstruction(new LoadInstruction(this)); } /** * Load an int local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction iload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(int.class)); } /** * Load a long local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction lload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(long.class)); } /** * Load a float local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction fload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(float.class)); } /** * Load a double local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction dload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(double.class)); } /** * Load an object local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction aload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(Object.class)); } /** * Store a value from the stack into a local variable. This instruction * will result in a nop until its type and local index are set. */ public StoreInstruction xstore() { return (StoreInstruction) addInstruction(new StoreInstruction(this)); } /** * Store an int value from the stack into a local variable. This * instruction will result in a nop until its local index is * set. */ public StoreInstruction istore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(int.class)); } /** * Store a long value from the stack into a local variable. This * instruction will resultin a nop until its local index is * set. */ public StoreInstruction lstore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(long.class)); } /** * Store a float value from the stack into a local variable. This * instruction will result in a nop until its local index is * set. */ public StoreInstruction fstore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(float.class)); } /** * Store a double value from the stack into a local variable. This * instruction will result in a nop until its local index is * set. */ public StoreInstruction dstore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(double.class)); } /** * Store an object value from the stack into a local variable. This * instruction will result in a nop until its local index is * set. */ public StoreInstruction astore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(Object.class)); } /** * Add the ret opcode, used in implementing * finally clauses. */ public RetInstruction ret() { return (RetInstruction) addInstruction(Constants.RET); } /** * Add the iinc opcode. */ public IIncInstruction iinc() { return (IIncInstruction) addInstruction(Constants.IINC); } /** * Add the wide opcode. */ public WideInstruction wide() { return (WideInstruction) addInstruction(Constants.WIDE); } /** * Load an array value onto the stack. This instruction will result * in a nop until its type is set. */ public ArrayLoadInstruction xaload() { return (ArrayLoadInstruction) addInstruction(new ArrayLoadInstruction( this)); } /** * Load an int array value onto the stack; the iaload opcode. */ public ArrayLoadInstruction iaload() { return (ArrayLoadInstruction) addInstruction(Constants.IALOAD); } /** * Load a long array value onto the stack; the laload opcode. */ public ArrayLoadInstruction laload() { return (ArrayLoadInstruction) addInstruction(Constants.LALOAD); } /** * Load a float array value onto the stack; the faload opcode. */ public ArrayLoadInstruction faload() { return (ArrayLoadInstruction) addInstruction(Constants.FALOAD); } /** * Load a double array value onto the stack; the daload opcode. */ public ArrayLoadInstruction daload() { return (ArrayLoadInstruction) addInstruction(Constants.DALOAD); } /** * Load an object array value onto the stack; the aaload * opcode. */ public ArrayLoadInstruction aaload() { return (ArrayLoadInstruction) addInstruction(Constants.AALOAD); } /** * Load a byte array value onto the stack; the baload opcode. */ public ArrayLoadInstruction baload() { return (ArrayLoadInstruction) addInstruction(Constants.BALOAD); } /** * Load a char array value onto the stack; the caload opcode. */ public ArrayLoadInstruction caload() { return (ArrayLoadInstruction) addInstruction(Constants.CALOAD); } /** * Load a short array value onto the stack; the saload opcode. */ public ArrayLoadInstruction saload() { return (ArrayLoadInstruction) addInstruction(Constants.SALOAD); } /** * Store a value from the stack into an array. This instruction * will result in a nop until its type is set. */ public ArrayStoreInstruction xastore() { return (ArrayStoreInstruction) addInstruction(new ArrayStoreInstruction( this)); } /** * Store an int value from the stack into an array; the * iastore opcode. */ public ArrayStoreInstruction iastore() { return (ArrayStoreInstruction) addInstruction(Constants.IASTORE); } /** * Store a long value from the stack into an array; the * lastore opcode. */ public ArrayStoreInstruction lastore() { return (ArrayStoreInstruction) addInstruction(Constants.LASTORE); } /** * Store a float value from the stack into an array; the * fastore opcode. */ public ArrayStoreInstruction fastore() { return (ArrayStoreInstruction) addInstruction(Constants.FASTORE); } /** * Store a double value from the stack into an array; the * dastore opcode. */ public ArrayStoreInstruction dastore() { return (ArrayStoreInstruction) addInstruction(Constants.DASTORE); } /** * Store an object value from the stack into an array; the * aastore opcode. */ public ArrayStoreInstruction aastore() { return (ArrayStoreInstruction) addInstruction(Constants.AASTORE); } /** * Store a byte value from the stack into an array; the * bastore opcode. */ public ArrayStoreInstruction bastore() { return (ArrayStoreInstruction) addInstruction(Constants.BASTORE); } /** * Store a char value from the stack into an array; the * castore opcode. */ public ArrayStoreInstruction castore() { return (ArrayStoreInstruction) addInstruction(Constants.CASTORE); } /** * Store a short value from the stack into an array; the * sastore opcode. */ public ArrayStoreInstruction sastore() { return (ArrayStoreInstruction) addInstruction(Constants.SASTORE); } /** * The pop opcode. */ public StackInstruction pop() { return (StackInstruction) addInstruction(Constants.POP); } /** * The pop2 opcode. */ public StackInstruction pop2() { return (StackInstruction) addInstruction(Constants.POP2); } /** * The dup opcode. */ public StackInstruction dup() { return (StackInstruction) addInstruction(Constants.DUP); } /** * The dupx1 opcode. */ public StackInstruction dupx1() { return (StackInstruction) addInstruction(Constants.DUPX1); } /** * The dupx2 opcode. */ public StackInstruction dupx2() { return (StackInstruction) addInstruction(Constants.DUPX2); } /** * The dup2 opcode. */ public StackInstruction dup2() { return (StackInstruction) addInstruction(Constants.DUP2); } /** * The dup2x1 opcode. */ public StackInstruction dup2x1() { return (StackInstruction) addInstruction(Constants.DUP2X1); } /** * The dup2x2 opcode. */ public StackInstruction dup2x2() { return (StackInstruction) addInstruction(Constants.DUP2X2); } /** * The swap opcode. */ public StackInstruction swap() { return (StackInstruction) addInstruction(Constants.SWAP); } /** * Perform some math operation on the stack items. This instruction will * result in a nop until its operation and type are set. */ public MathInstruction math() { return (MathInstruction) addInstruction(new MathInstruction(this)); } /** * Add the top two stack values. This instruction will result in * a nop until its type is set. */ public MathInstruction xadd() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_ADD); } /** * Add the top two stack int values; the iadd opcode. */ public MathInstruction iadd() { return (MathInstruction) addInstruction(Constants.IADD); } /** * Add the top two stack long values; the ladd opcode. */ public MathInstruction ladd() { return (MathInstruction) addInstruction(Constants.LADD); } /** * Add the top two stack float values; the fadd opcode. */ public MathInstruction fadd() { return (MathInstruction) addInstruction(Constants.FADD); } /** * Add the top two stack double values; the dadd opcode. */ public MathInstruction dadd() { return (MathInstruction) addInstruction(Constants.DADD); } /** * Subtract the top two stack values. This instruction will result in * a nop until its type is set. */ public MathInstruction xsub() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_SUB); } /** * Subtract the top two stack int values; the isub opcode. */ public MathInstruction isub() { return (MathInstruction) addInstruction(Constants.ISUB); } /** * Subtract the top two stack long values; the lsub opcode. */ public MathInstruction lsub() { return (MathInstruction) addInstruction(Constants.LSUB); } /** * Subtract the top two stack float values; the fsub opcode. */ public MathInstruction fsub() { return (MathInstruction) addInstruction(Constants.FSUB); } /** * Subtract the top two stack double values; the dsub opcode. */ public MathInstruction dsub() { return (MathInstruction) addInstruction(Constants.DSUB); } /** * Multiply the top two stack values. This instruction will result in * a nop until its type is set. */ public MathInstruction xmul() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_MUL); } /** * Multiply the top two stack int values; the imul opcode. */ public MathInstruction imul() { return (MathInstruction) addInstruction(Constants.IMUL); } /** * Multiply the top two stack long values; the lmul opcode. */ public MathInstruction lmul() { return (MathInstruction) addInstruction(Constants.LMUL); } /** * Multiply the top two stack float values; the fmul opcode. */ public MathInstruction fmul() { return (MathInstruction) addInstruction(Constants.FMUL); } /** * Multiply the top two stack double values; the dmul opcode. */ public MathInstruction dmul() { return (MathInstruction) addInstruction(Constants.DMUL); } /** * Divide the top two stack values. This instruction will result in * a nop until its type is set. */ public MathInstruction xdiv() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_DIV); } /** * Divide the top two stack int values; the idiv opcode. */ public MathInstruction idiv() { return (MathInstruction) addInstruction(Constants.IDIV); } /** * Divide the top two stack long values; the ldiv opcode. */ public MathInstruction ldiv() { return (MathInstruction) addInstruction(Constants.LDIV); } /** * Divide the top two stack float values; the fdiv opcode. */ public MathInstruction fdiv() { return (MathInstruction) addInstruction(Constants.FDIV); } /** * Divide the top two stack double values; the ddiv opcode. */ public MathInstruction ddiv() { return (MathInstruction) addInstruction(Constants.DDIV); } /** * Take the remainder of the top two stack values. This instruction will * result in a nop until its type is set. */ public MathInstruction xrem() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_REM); } /** * Take the remainder of the top two int stack values; the * irem opcode. */ public MathInstruction irem() { return (MathInstruction) addInstruction(Constants.IREM); } /** * Take the remainder of the top two long stack values; the * lrem opcode. */ public MathInstruction lrem() { return (MathInstruction) addInstruction(Constants.LREM); } /** * Take the remainder of the top two float stack values; the * frem opcode. */ public MathInstruction frem() { return (MathInstruction) addInstruction(Constants.FREM); } /** * Take the remainder of the top two double stack values; the * drem opcode. */ public MathInstruction drem() { return (MathInstruction) addInstruction(Constants.DREM); } /** * Negate the top stack value. This instruction will result in a * nop until its type is set. */ public MathInstruction xneg() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_NEG); } /** * Negate the top stack int value; the ineg opcode. */ public MathInstruction ineg() { return (MathInstruction) addInstruction(Constants.INEG); } /** * Negate the top stack long value; the lneg opcode. */ public MathInstruction lneg() { return (MathInstruction) addInstruction(Constants.LNEG); } /** * Negate the top stack float value; the fneg opcode. */ public MathInstruction fneg() { return (MathInstruction) addInstruction(Constants.FNEG); } /** * Negate the top stack double value; the dneg opcode. */ public MathInstruction dneg() { return (MathInstruction) addInstruction(Constants.DNEG); } /** * Shift the top stack values. This instruction will result in a * nop until its type is set. */ public MathInstruction xshl() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_SHL); } /** * Shift the top stack int values; the ishl opcode. */ public MathInstruction ishl() { return (MathInstruction) addInstruction(Constants.ISHL); } /** * Shift the top stack long values; the lshl opcode. */ public MathInstruction lshl() { return (MathInstruction) addInstruction(Constants.LSHL); } /** * Shift the top stack values. This instruction will result in a * nop until its type is set. */ public MathInstruction xshr() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_SHR); } /** * Shift the top stack int values; the ishr opcode. */ public MathInstruction ishr() { return (MathInstruction) addInstruction(Constants.ISHR); } /** * Shift the top stack long values; the lshr opcode. */ public MathInstruction lshr() { return (MathInstruction) addInstruction(Constants.LSHR); } /** * Shift the top stack values. This instruction will result in a * nop until its type is set. */ public MathInstruction xushr() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_USHR); } /** * Shift the top stack int values; the iushr opcode. */ public MathInstruction iushr() { return (MathInstruction) addInstruction(Constants.IUSHR); } /** * Shift the top stack long values; the lushr opcode. */ public MathInstruction lushr() { return (MathInstruction) addInstruction(Constants.LUSHR); } /** * Take the mathematical and of the top two stack values. This instruction * results in a nop until its type is set. */ public MathInstruction xand() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_AND); } /** * Take the mathematical and of the top two stack int values; the * iand opcode. */ public MathInstruction iand() { return (MathInstruction) addInstruction(Constants.IAND); } /** * Take the mathematical and of the top two stack long values; the * land opcode. */ public MathInstruction land() { return (MathInstruction) addInstruction(Constants.LAND); } /** * Take the mathematical or of the top two stack values. This instruction * results in a nop until its type is set. */ public MathInstruction xor() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_OR); } /** * Take the mathematical or of the top two stack int values; the * ior opcode. */ public MathInstruction ior() { return (MathInstruction) addInstruction(Constants.IOR); } /** * Take the mathematical or of the top two stack long values; the * lor opcode. */ public MathInstruction lor() { return (MathInstruction) addInstruction(Constants.LOR); } /** * Take the mathematical xor of the top two stack values. This instruction * results in a nop until its type is set. */ public MathInstruction xxor() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_XOR); } /** * Take the mathematical xor of the top two stack int values; the * ixor opcode. */ public MathInstruction ixor() { return (MathInstruction) addInstruction(Constants.IXOR); } /** * Take the mathematical xor of the top two stack long values; the * lxor opcode. */ public MathInstruction lxor() { return (MathInstruction) addInstruction(Constants.LXOR); } /** * Convert the top stack value to another type. This instruction * will result in a nop until the types to convert * between are set. */ public ConvertInstruction convert() { return (ConvertInstruction)addInstruction(new ConvertInstruction(this)); } /** * Compare the top two stack values. This instruction will result in a * nop until its type is set. */ public CmpInstruction xcmp() { return (CmpInstruction) addInstruction(new CmpInstruction(this)); } /** * Compare the top two stack values; the lcmp opcode. */ public CmpInstruction lcmp() { return (CmpInstruction) addInstruction(Constants.LCMP); } /** * Compare the top two stack values; the fcmpl opcode. */ public CmpInstruction fcmpl() { return (CmpInstruction) addInstruction(Constants.FCMPL); } /** * Compare the top two stack values; the fcmpg opcode. */ public CmpInstruction fcmpg() { return (CmpInstruction) addInstruction(Constants.FCMPG); } /** * Compare the top two stack values; the dcmpl opcode. */ public CmpInstruction dcmpl() { return (CmpInstruction) addInstruction(Constants.DCMPL); } /** * Compare the top two stack values; the dcmpg opcode. */ public CmpInstruction dcmpg() { return (CmpInstruction) addInstruction(Constants.DCMPG); } /** * The ifeq opcode. */ public IfInstruction ifeq() { return (IfInstruction) addInstruction(Constants.IFEQ); } /** * The ifne opcode. */ public IfInstruction ifne() { return (IfInstruction) addInstruction(Constants.IFNE); } /** * The iflt opcode. */ public IfInstruction iflt() { return (IfInstruction) addInstruction(Constants.IFLT); } /** * The ifge opcode. */ public IfInstruction ifge() { return (IfInstruction) addInstruction(Constants.IFGE); } /** * The ifgt opcode. */ public IfInstruction ifgt() { return (IfInstruction) addInstruction(Constants.IFGT); } /** * The ifle opcode. */ public IfInstruction ifle() { return (IfInstruction) addInstruction(Constants.IFLE); } /** * The ificmpeq opcode. */ public IfInstruction ificmpeq() { return (IfInstruction) addInstruction(Constants.IFICMPEQ); } /** * The ificmpne opcode. */ public IfInstruction ificmpne() { return (IfInstruction) addInstruction(Constants.IFICMPNE); } /** * The ificmplt opcode. */ public IfInstruction ificmplt() { return (IfInstruction) addInstruction(Constants.IFICMPLT); } /** * The ificmpge opcode. */ public IfInstruction ificmpge() { return (IfInstruction) addInstruction(Constants.IFICMPGE); } /** * The ificmpgt opcode. */ public IfInstruction ificmpgt() { return (IfInstruction) addInstruction(Constants.IFICMPGT); } /** * The ificmple opcode. */ public IfInstruction ificmple() { return (IfInstruction) addInstruction(Constants.IFICMPLE); } /** * The ifacmpeq opcode. */ public IfInstruction ifacmpeq() { return (IfInstruction) addInstruction(Constants.IFACMPEQ); } /** * The ifacmpne opcode. */ public IfInstruction ifacmpne() { return (IfInstruction) addInstruction(Constants.IFACMPNE); } /** * The ifnull opcode. */ public IfInstruction ifnull() { return (IfInstruction) addInstruction(Constants.IFNULL); } /** * The ifnonnull opcode. */ public IfInstruction ifnonnull() { return (IfInstruction) addInstruction(Constants.IFNONNULL); } /** * The go2 opcode. */ public JumpInstruction go2() { return (JumpInstruction) addInstruction(Constants.GOTO); } /** * The jsr opcode used in implementing finally * clauses. */ public JumpInstruction jsr() { return (JumpInstruction) addInstruction(Constants.JSR); } /** * The tableswitch opcode. */ public TableSwitchInstruction tableswitch() { return (TableSwitchInstruction) addInstruction(Constants.TABLESWITCH); } /** * The lookupswitch opcode. */ public LookupSwitchInstruction lookupswitch() { return (LookupSwitchInstruction) addInstruction(Constants.LOOKUPSWITCH); } /** * Return from a method. This method will result in a * nop until its type is set. */ public ReturnInstruction xreturn() { return (ReturnInstruction) addInstruction(new ReturnInstruction(this)); } /** * Return void from a method; the return opcode. */ public ReturnInstruction vreturn() { return (ReturnInstruction) addInstruction(Constants.RETURN); } /** * Return an int from a method; the ireturn opcode. */ public ReturnInstruction ireturn() { return (ReturnInstruction) addInstruction(Constants.IRETURN); } /** * Return a long from a method; the lreturn opcode. */ public ReturnInstruction lreturn() { return (ReturnInstruction) addInstruction(Constants.LRETURN); } /** * Return a float from a method; the freturn opcode. */ public ReturnInstruction freturn() { return (ReturnInstruction) addInstruction(Constants.FRETURN); } /** * Return a double from a method; the dreturn opcode. */ public ReturnInstruction dreturn() { return (ReturnInstruction) addInstruction(Constants.DRETURN); } /** * Return an object from a method; the areturn opcode. */ public ReturnInstruction areturn() { return (ReturnInstruction) addInstruction(Constants.ARETURN); } /** * Load the value from a field onto the stack; the getfield * opcode. */ public GetFieldInstruction getfield() { return (GetFieldInstruction) addInstruction(Constants.GETFIELD); } /** * Load the value from a static field onto the stack; the * getstatic opcode. */ public GetFieldInstruction getstatic() { return (GetFieldInstruction) addInstruction(Constants.GETSTATIC); } /** * Place the value of a field onto the stack; the putfield * opcode. */ public PutFieldInstruction putfield() { return (PutFieldInstruction) addInstruction(Constants.PUTFIELD); } /** * Place the value of a static field onto the stack; the * putstatic opcode. */ public PutFieldInstruction putstatic() { return (PutFieldInstruction) addInstruction(Constants.PUTSTATIC); } /** * Invoke a virtual method; the invokevirtual opcode. */ public MethodInstruction invokevirtual() { return (MethodInstruction) addInstruction(Constants.INVOKEVIRTUAL); } /** * Invoke a method non-virtually, as for constructors and superclass * methods; the invokespecial opcode. */ public MethodInstruction invokespecial() { return (MethodInstruction) addInstruction(Constants.INVOKESPECIAL); } /** * Invoke a method on an interface; the invokeinterface opcode. */ public MethodInstruction invokeinterface() { return (MethodInstruction) addInstruction(Constants.INVOKEINTERFACE); } /** * Invoke a static method; the invokestatic opcode. */ public MethodInstruction invokestatic() { return (MethodInstruction) addInstruction(Constants.INVOKESTATIC); } /** * Create a new instance of an object; the new opcode. */ public ClassInstruction anew() { return (ClassInstruction) addInstruction(Constants.NEW); } /** * Create a new instance of an object array; the anew opcode. */ public ClassInstruction anewarray() { return (ClassInstruction) addInstruction(Constants.ANEWARRAY); } /** * Cast an object on the stack to another type; the checkcast * opcode. */ public ClassInstruction checkcast() { return (ClassInstruction) addInstruction(Constants.CHECKCAST); } /** * Test if a stack object is an instance of a class; the * instanceof opcode. */ public ClassInstruction isinstance() { return (ClassInstruction) addInstruction(Constants.INSTANCEOF); } /** * Create a new multidimensional array; the multianewarray * opcode. */ public MultiANewArrayInstruction multianewarray() { return (MultiANewArrayInstruction) addInstruction (Constants.MULTIANEWARRAY); } /** * Create a new array of a primitive type; the newarray opcode. */ public NewArrayInstruction newarray() { return (NewArrayInstruction) addInstruction(Constants.NEWARRAY); } /** * Get the length of an array on the stack; the arraylength * opcode. */ public Instruction arraylength() { return addInstruction(Constants.ARRAYLENGTH); } /** * Throw an exception; the athrow opcode. */ public Instruction athrow() { return addInstruction(Constants.ATHROW); } /** * The monitorenter opcode. */ public MonitorEnterInstruction monitorenter() { return (MonitorEnterInstruction) addInstruction(Constants.MONITORENTER); } /** * The monitorexit opcode. */ public MonitorExitInstruction monitorexit() { return (MonitorExitInstruction) addInstruction(Constants.MONITOREXIT); } ///////////////////////// // Wholisitic operations ///////////////////////// /** * Return all the Instructions of this method. */ public Instruction[] getInstructions() { Instruction[] arr = new Instruction[_size]; int i = 0; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) arr[i++] = (Instruction) entry; return arr; } int getLength() { // covers maxStack, maxLocals, codeLength, exceptionTableLength, // attributeCount int length = 12; // add code Instruction last = getLastInstruction(); if (last != null) length += last.getByteIndex() + last.getLength(); // add exception reps; each is 8 bytes length += (8 * _handlers.size()); // add all attribute lengths Attribute[] attrs = getAttributes(); for (int i = 0; i < attrs.length; i++) length += (attrs[i].getLength() + 6); return length; } public void acceptVisit(BCVisitor visit) { visit.enterCode(this); Instruction ins; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { ins = (Instruction) entry; visit.enterInstruction(ins); ins.acceptVisit(visit); visit.exitInstruction(ins); } for (Iterator i = _handlers.iterator(); i.hasNext();) ((ExceptionHandler) i.next()).acceptVisit(visit); visitAttributes(visit); visit.exitCode(this); } ////////////////////////// // Convenience operations ////////////////////////// /** * Return line number information for the code. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new line number table will be added * if not already present * @return the line number information, or null if none * and the add param is set to false */ public LineNumberTable getLineNumberTable(boolean add) { LineNumberTable attr = (LineNumberTable) getAttribute (Constants.ATTR_LINENUMBERS); if (!add || (attr != null)) return attr; return (LineNumberTable) addAttribute(Constants.ATTR_LINENUMBERS); } /** * Remove the line number table for the code. * Acts internally through the {@link Attributes} interface. * * @return true if there was a table to remove */ public boolean removeLineNumberTable() { return removeAttribute(Constants.ATTR_LINENUMBERS); } /** * Return local variable information for the code. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new local variable table will be * added if not already present * @return the local variable information, or null if none * and the add param is set to false */ public LocalVariableTable getLocalVariableTable(boolean add) { LocalVariableTable attr = (LocalVariableTable) getAttribute (Constants.ATTR_LOCALS); if (!add || (attr != null)) return attr; return (LocalVariableTable) addAttribute(Constants.ATTR_LOCALS); } /** * Remove the local variable table for the code. * Acts internally through the {@link Attributes} interface. * * @return true if there was a table to remove */ public boolean removeLocalVariableTables() { return removeAttribute(Constants.ATTR_LOCALS); } /** * Return local variable generics information for the code. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new local variable type table will be * added if not already present * @return the local variable type information, or null if none * and the add param is set to false */ public LocalVariableTypeTable getLocalVariableTypeTable(boolean add) { LocalVariableTypeTable attr = (LocalVariableTypeTable) getAttribute (Constants.ATTR_LOCAL_TYPES); if (!add || (attr != null)) return attr; return (LocalVariableTypeTable)addAttribute(Constants.ATTR_LOCAL_TYPES); } /** * Remove the local variable type table for the code. * Acts internally through the {@link Attributes} interface. * * @return true if there was a table to remove */ public boolean removeLocalVariableTypeTables() { return removeAttribute(Constants.ATTR_LOCAL_TYPES); } ////////////////// // I/O operations ////////////////// void read(Attribute attr) { Code orig = (Code) attr; _maxStack = orig.getMaxStack(); _maxLocals = orig.getMaxLocals(); // clear existing code _head.next = _tail; _tail.prev = _head; _size = 0; _byteIndexesValid = false; beforeFirst(); _handlers.clear(); // copy all instructions; don't set constant instruction values until // instruction ptrs have been updated in case the instruction width // changes because of differences in the constant pool (LDC vs LDCW) Instruction ins; Instruction origIns; for (CodeEntry entry = orig._head.next; entry != orig._tail; entry = entry.next) { origIns = (Instruction) entry; ins = createInstruction(origIns.getOpcode()); _ci.addInternal(ins); if (!(ins instanceof ConstantInstruction)) ins.read(origIns); } // copy exception handlers ExceptionHandler[] origHandlers = orig.getExceptionHandlers(); ExceptionHandler handler; for (int i = 0; i < origHandlers.length; i++) { handler = addExceptionHandler(); handler.read(origHandlers[i]); handler.updateTargets(); } // reset all opcode ptrs to the new copied opcodes updateInstructionPointers(); setAttributes(orig.getAttributes()); // setup local variable markers LocalVariableTable locals = getLocalVariableTable(false); if (locals != null) locals.updateTargets(); // setup local variable markers LocalVariableTypeTable localTypes = getLocalVariableTypeTable(false); if (localTypes != null) localTypes.updateTargets(); // setup line number markers LineNumberTable lines = getLineNumberTable(false); if (lines != null) lines.updateTargets(); // now copy constant instruction values CodeEntry copy = _head.next; for (CodeEntry entry = orig._head.next; entry != orig._tail; entry = entry.next, copy = copy.next) { if (entry instanceof ConstantInstruction) ((ConstantInstruction) copy).read((Instruction) entry); } beforeFirst(); } void read(DataInput in, int length) throws IOException { _maxStack = in.readUnsignedShort(); _maxLocals = in.readUnsignedShort(); readCode(in, in.readInt()); _handlers.clear(); int exceptionCount = in.readUnsignedShort(); ExceptionHandler excep; for (int i = 0; i < exceptionCount; i++) { excep = addExceptionHandler(); excep.read(in); excep.updateTargets(); } readAttributes(in); // setup local variable markers LocalVariableTable locals = getLocalVariableTable(false); if (locals != null) locals.updateTargets(); // setup local variable markers LocalVariableTypeTable localTypes = getLocalVariableTypeTable(false); if (localTypes != null) localTypes.updateTargets(); // setup line number markers LineNumberTable lines = getLineNumberTable(false); if (lines != null) lines.updateTargets(); } void write(DataOutput out, int length) throws IOException { out.writeShort(_maxStack); out.writeShort(_maxLocals); byte[] code = toByteArray(); out.writeInt(code.length); out.write(code); out.writeShort(_handlers.size()); for (Iterator itr = _handlers.iterator(); itr.hasNext();) ((ExceptionHandler) itr.next()).write(out); writeAttributes(out); } private void readCode(DataInput in, int len) throws IOException { _head.next = _tail; _tail.prev = _head; _size = 0; _byteIndexesValid = true; beforeFirst(); Instruction ins; for (int byteIndex = 0; byteIndex < len;) { ins = createInstruction(in.readUnsignedByte()); _ci.addInternal(ins); ins.byteIndex = byteIndex; ins.read(in); byteIndex += ins.getLength(); } updateInstructionPointers(); beforeFirst(); // sanity check if (!_byteIndexesValid) throw new IllegalStateException(); } /** * Ensures that all the opcode targets are set up correctly. */ private void updateInstructionPointers() { for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) if (entry instanceof InstructionPtr) ((InstructionPtr) entry).updateTargets(); } /** * Returns the byteIndex of the given instruction. */ int getByteIndex(Instruction ins) { if (_byteIndexesValid && ins.byteIndex != -1) return ins.byteIndex; int byteIndex = 0; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { if (entry == ins) return byteIndex; byteIndex += ((Instruction) entry).getLength(); } throw new IllegalArgumentException("ins.owner != this"); } /** * Invalidate all byteindexes when the code block changes. */ void invalidateByteIndexes() { _byteIndexesValid = false; } /** * Returns the instruction in this code block found at the given byte index. */ Instruction getInstruction(int byteIndex) { if (byteIndex < 0) return null; int curIndex = 0; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { if (byteIndex == curIndex) return (Instruction) entry; curIndex += ((Instruction) entry).getLength(); } // some instruction ptrs are actually to a "next" instruction, so // allow one past the end if (byteIndex == curIndex) return null; throw new IllegalArgumentException(String.valueOf(byteIndex)); } /** * Return the first instruction in this code block, or null if none. */ Instruction getFirstInstruction() { return (Instruction) _head.next; } /** * Return the last instruction in this code block, or null if none. */ Instruction getLastInstruction() { return (Instruction) _tail.prev; } /** * Returns the number of instructions that occur before 'ins' * in this code block that 'ins' is a part of. * * @throws IllegalArgumentException if this code block is not the owner * of ins */ private int indexOf(Instruction ins) { int i = 0; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next, i++) if (entry == ins) return i; throw new IllegalArgumentException("ins.code != this"); } private void writeCode(DataOutput out) throws IOException { Instruction ins; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { ins = (Instruction) entry; out.writeByte(ins.getOpcode()); ins.write(out); } } private byte[] toByteArray() throws IOException { ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); DataOutputStream stream = new DataOutputStream(byteStream); try { writeCode(stream); return byteStream.toByteArray(); } finally { try { stream.close(); } catch (Exception e) {} } } private void fromByteArray(byte[] code) throws IOException { if (code == null) { _head.next = _tail; _tail.prev = _head; _size = 0; } else { DataInputStream stream = new DataInputStream (new ByteArrayInputStream(code)); try { readCode(stream, code.length); } finally { try { stream.close(); } catch (Exception e) {} } } } private Instruction addInstruction(Instruction ins) { _ci.add(ins); return ins; } private Instruction addInstruction(int opcode) { return addInstruction(createInstruction(opcode)); } /** * Creates an Instruction, with this code block as the owner. * Note that the Instruction is not added to this Code block. */ private Instruction createInstruction(int opcode) { switch (opcode) { case Constants.NOP: case Constants.ARRAYLENGTH: case Constants.ATHROW: return new Instruction(this, opcode); case Constants.ACONSTNULL: case Constants.ICONSTM1: case Constants.ICONST0: case Constants.ICONST1: case Constants.ICONST2: case Constants.ICONST3: case Constants.ICONST4: case Constants.ICONST5: case Constants.LCONST0: case Constants.LCONST1: case Constants.FCONST0: case Constants.FCONST1: case Constants.FCONST2: case Constants.DCONST0: case Constants.DCONST1: case Constants.BIPUSH: case Constants.SIPUSH: case Constants.LDC: case Constants.LDCW: case Constants.LDC2W: return new ConstantInstruction(this, opcode); case Constants.ILOAD: case Constants.LLOAD: case Constants.FLOAD: case Constants.DLOAD: case Constants.ALOAD: case Constants.ILOAD0: case Constants.ILOAD1: case Constants.ILOAD2: case Constants.ILOAD3: case Constants.LLOAD0: case Constants.LLOAD1: case Constants.LLOAD2: case Constants.LLOAD3: case Constants.FLOAD0: case Constants.FLOAD1: case Constants.FLOAD2: case Constants.FLOAD3: case Constants.DLOAD0: case Constants.DLOAD1: case Constants.DLOAD2: case Constants.DLOAD3: case Constants.ALOAD0: case Constants.ALOAD1: case Constants.ALOAD2: case Constants.ALOAD3: return new LoadInstruction(this, opcode); case Constants.IALOAD: case Constants.LALOAD: case Constants.FALOAD: case Constants.DALOAD: case Constants.AALOAD: case Constants.BALOAD: case Constants.CALOAD: case Constants.SALOAD: return new ArrayLoadInstruction(this, opcode); case Constants.ISTORE: case Constants.LSTORE: case Constants.FSTORE: case Constants.DSTORE: case Constants.ASTORE: case Constants.ISTORE0: case Constants.ISTORE1: case Constants.ISTORE2: case Constants.ISTORE3: case Constants.LSTORE0: case Constants.LSTORE1: case Constants.LSTORE2: case Constants.LSTORE3: case Constants.FSTORE0: case Constants.FSTORE1: case Constants.FSTORE2: case Constants.FSTORE3: case Constants.DSTORE0: case Constants.DSTORE1: case Constants.DSTORE2: case Constants.DSTORE3: case Constants.ASTORE0: case Constants.ASTORE1: case Constants.ASTORE2: case Constants.ASTORE3: return new StoreInstruction(this, opcode); case Constants.IASTORE: case Constants.LASTORE: case Constants.FASTORE: case Constants.DASTORE: case Constants.AASTORE: case Constants.BASTORE: case Constants.CASTORE: case Constants.SASTORE: return new ArrayStoreInstruction(this, opcode); case Constants.POP: case Constants.POP2: case Constants.DUP: case Constants.DUPX1: case Constants.DUPX2: case Constants.DUP2: case Constants.DUP2X1: case Constants.DUP2X2: case Constants.SWAP: return new StackInstruction(this, opcode); case Constants.IADD: case Constants.LADD: case Constants.FADD: case Constants.DADD: case Constants.ISUB: case Constants.LSUB: case Constants.FSUB: case Constants.DSUB: case Constants.IMUL: case Constants.LMUL: case Constants.FMUL: case Constants.DMUL: case Constants.IDIV: case Constants.LDIV: case Constants.FDIV: case Constants.DDIV: case Constants.IREM: case Constants.LREM: case Constants.FREM: case Constants.DREM: case Constants.INEG: case Constants.LNEG: case Constants.FNEG: case Constants.DNEG: case Constants.ISHL: case Constants.LSHL: case Constants.ISHR: case Constants.LSHR: case Constants.IUSHR: case Constants.LUSHR: case Constants.IAND: case Constants.LAND: case Constants.IOR: case Constants.LOR: case Constants.IXOR: case Constants.LXOR: return new MathInstruction(this, opcode); case Constants.IINC: return new IIncInstruction(this); case Constants.I2L: case Constants.I2F: case Constants.I2D: case Constants.L2I: case Constants.L2F: case Constants.L2D: case Constants.F2I: case Constants.F2L: case Constants.F2D: case Constants.D2I: case Constants.D2L: case Constants.D2F: case Constants.I2B: case Constants.I2C: case Constants.I2S: return new ConvertInstruction(this, opcode); case Constants.LCMP: case Constants.FCMPL: case Constants.FCMPG: case Constants.DCMPL: case Constants.DCMPG: return new CmpInstruction(this, opcode); case Constants.IFEQ: case Constants.IFNE: case Constants.IFLT: case Constants.IFGE: case Constants.IFGT: case Constants.IFLE: case Constants.IFICMPEQ: case Constants.IFICMPNE: case Constants.IFICMPLT: case Constants.IFICMPGE: case Constants.IFICMPGT: case Constants.IFICMPLE: case Constants.IFACMPEQ: case Constants.IFACMPNE: case Constants.IFNULL: case Constants.IFNONNULL: return new IfInstruction(this, opcode); case Constants.GOTO: case Constants.JSR: case Constants.GOTOW: case Constants.JSRW: return new GotoInstruction(this, opcode); case Constants.RET: return new RetInstruction(this); case Constants.TABLESWITCH: return new TableSwitchInstruction(this); case Constants.LOOKUPSWITCH: return new LookupSwitchInstruction(this); case Constants.IRETURN: case Constants.LRETURN: case Constants.FRETURN: case Constants.DRETURN: case Constants.ARETURN: case Constants.RETURN: return new ReturnInstruction(this, opcode); case Constants.GETSTATIC: case Constants.GETFIELD: return new GetFieldInstruction(this, opcode); case Constants.PUTSTATIC: case Constants.PUTFIELD: return new PutFieldInstruction(this, opcode); case Constants.INVOKEVIRTUAL: case Constants.INVOKESPECIAL: case Constants.INVOKESTATIC: case Constants.INVOKEINTERFACE: return new MethodInstruction(this, opcode); case Constants.NEW: case Constants.ANEWARRAY: case Constants.CHECKCAST: case Constants.INSTANCEOF: return new ClassInstruction(this, opcode); case Constants.NEWARRAY: return new NewArrayInstruction(this); case Constants.MONITORENTER: return new MonitorEnterInstruction(this); case Constants.MONITOREXIT: return new MonitorExitInstruction(this); case Constants.WIDE: return new WideInstruction(this); case Constants.MULTIANEWARRAY: return new MultiANewArrayInstruction(this); default: throw new IllegalArgumentException("Illegal opcode: " + opcode); } } /** * Returns another listIterator view of the Instructions in this * code block. Useful for performing read-only searches through * Instructions without effecting the pointer location of the main * code block. */ public ListIterator listIterator() { return new CodeIterator(_head, -1); } /** * Helper class to handle invalidation of instructions on removal * and notification of modification on addition. */ private class CodeIterator implements ListIterator { public static final int UNSET = -99; private CodeEntry _bn = null; // "before next" entry private Instruction _last = null; // last entry returned private int _index = UNSET; // index of _bn public CodeIterator(CodeEntry entry, int index) { _bn = entry; _index = index; } public boolean hasNext() { return _bn.next != _tail; } public boolean hasPrevious() { return _bn != _head; } public Object next() { if (!hasNext()) throw new NoSuchElementException(); _bn = _bn.next; _last = (Instruction) _bn; if (_index != UNSET) _index++; return _last; } public int nextIndex() { return initIndex() + 1; } public Object previous() { if (!hasPrevious()) throw new NoSuchElementException(); _last = (Instruction) _bn; _bn = _bn.prev; if (_index != UNSET) _index--; return _last; } public int previousIndex() { return initIndex(); } private int initIndex() { if (_index == UNSET) { if (_bn == _head) _index = -1; else _index = indexOf((Instruction) _bn); } return _index; } public void add(Object obj) { addInternal(obj); invalidateByteIndexes(); } private void addInternal(Object obj) { if (obj == null) throw new NullPointerException("obj = null"); Instruction ins = (Instruction) obj; if (_size == 0) { _head.next = ins; _tail.prev = ins; ins.prev = _head; ins.next = _tail; _index = 0; } else { CodeEntry next = _bn.next; _bn.next = ins; next.prev = ins; ins.prev = _bn; ins.next = next; if (_index != UNSET) _index++; } _bn = ins; _last = ins; _size++; } public void set(Object obj) { if (obj == null) throw new NullPointerException("obj = null"); if (_last == null) throw new IllegalStateException(); Instruction ins = (Instruction) obj; ins.prev = _last.prev; ins.next = _last.next; ins.prev.next = ins; ins.next.prev = ins; replaceTarget(_last, ins); _last.invalidate(); if (_bn == _last) _bn = ins; _last = ins; invalidateByteIndexes(); } public void remove() { if (_last == null) throw new IllegalStateException(); if (_bn == _last) _bn = _last.prev; _index--; _last.prev.next = _last.next; _last.next.prev = _last.prev; _size--; Instruction orig = _last; Instruction replace = null; if (orig.next != _tail) replace = (Instruction) orig.next; else replace = nop(); replaceTarget(orig, replace); orig.invalidate(); _last = null; invalidateByteIndexes(); } private void replaceTarget(Instruction orig, Instruction replace) { for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { if (entry instanceof InstructionPtr) ((InstructionPtr) entry).replaceTarget(orig, replace); } // update the ExceptionHandler pointers ExceptionHandler[] handlers = getExceptionHandlers(); for (int i = 0; i < handlers.length; i++) handlers[i].replaceTarget(orig, replace); // update LineNumber pointers LineNumberTable lineNumbers = getLineNumberTable(false); if (lineNumbers != null) lineNumbers.replaceTarget(orig, replace); // update LocalVariable pointers LocalVariableTable variables = getLocalVariableTable(false); if (variables != null) variables.replaceTarget(orig, replace); // update LocalVariableType pointers LocalVariableTypeTable types = getLocalVariableTypeTable(false); if (types != null) types.replaceTarget(orig, replace); } } } serp-1.14.1.orig/src/main/java/serp/bytecode/UnknownAttribute.java0000755000000000000000000000246010460270414021770 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.visitor.*; /** * An unrecognized attribute; class files are allowed to contain * attributes that are not recognized, and the JVM must ignore them. * * @author Abe White */ public class UnknownAttribute extends Attribute { private byte[] _value = new byte[0]; UnknownAttribute(int nameIndex, Attributes owner) { super(nameIndex, owner); } int getLength() { return _value.length; } /** * The value is of unknown content, so it is stored as a byte array. */ public byte[] getValue() { return _value; } /** * The value is of unknown content, so it is stored as a byte array. */ public void setValue(byte[] value) { if (value == null) value = new byte[0]; _value = value; } public void acceptVisit(BCVisitor visit) { visit.enterUnknownAttribute(this); visit.exitUnknownAttribute(this); } void read(Attribute other) { setValue(((UnknownAttribute) other).getValue()); } void read(DataInput in, int length) throws IOException { _value = new byte[length]; in.readFully(_value); } void write(DataOutput out, int length) throws IOException { out.write(_value); } } serp-1.14.1.orig/src/main/java/serp/bytecode/StoreInstruction.java0000755000000000000000000001473110637750727022027 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.visitor.*; /** * An instruction to store a value from a local variable onto the stack. * * @author Abe White */ public class StoreInstruction extends LocalVariableInstruction { private static final Class[][] _mappings = new Class[][] { { byte.class, int.class }, { boolean.class, int.class }, { char.class, int.class }, { short.class, int.class }, { void.class, int.class }, }; String _type = null; StoreInstruction(Code owner) { super(owner); } StoreInstruction(Code owner, int opcode) { super(owner, opcode); } int getLength() { switch (getOpcode()) { case Constants.ISTORE: case Constants.LSTORE: case Constants.FSTORE: case Constants.DSTORE: case Constants.ASTORE: return super.getLength() + 1; default: return super.getLength(); } } public int getLogicalStackChange() { switch (getOpcode()) { case Constants.NOP: return 0; default: return -1; } } public int getStackChange() { switch (getOpcode()) { case Constants.LSTORE: case Constants.LSTORE0: case Constants.LSTORE1: case Constants.LSTORE2: case Constants.LSTORE3: case Constants.DSTORE: case Constants.DSTORE0: case Constants.DSTORE1: case Constants.DSTORE2: case Constants.DSTORE3: return -2; case Constants.NOP: return 0; default: return -1; } } public String getTypeName() { switch (getOpcode()) { case Constants.ISTORE: case Constants.ISTORE0: case Constants.ISTORE1: case Constants.ISTORE2: case Constants.ISTORE3: return int.class.getName(); case Constants.LSTORE: case Constants.LSTORE0: case Constants.LSTORE1: case Constants.LSTORE2: case Constants.LSTORE3: return long.class.getName(); case Constants.FSTORE: case Constants.FSTORE0: case Constants.FSTORE1: case Constants.FSTORE2: case Constants.FSTORE3: return float.class.getName(); case Constants.DSTORE: case Constants.DSTORE0: case Constants.DSTORE1: case Constants.DSTORE2: case Constants.DSTORE3: return double.class.getName(); case Constants.ASTORE: case Constants.ASTORE0: case Constants.ASTORE1: case Constants.ASTORE2: case Constants.ASTORE3: return Object.class.getName(); default: return _type; } } public TypedInstruction setType(String type) { type = mapType(type, _mappings, true); int local = getLocal(); int len = getLength(); // if an invalid type or local, revert to nop if ((type == null) || (local < 0)) { _type = type; setOpcode(Constants.NOP); } else { // valid opcode, unset saved type _type = null; switch (type.charAt(0)) { case 'i': setOpcode((local > 3) ? Constants.ISTORE : (Constants.ISTORE0 + local)); break; case 'l': setOpcode((local > 3) ? Constants.LSTORE : (Constants.LSTORE0 + local)); break; case 'f': setOpcode((local > 3) ? Constants.FSTORE : (Constants.FSTORE0 + local)); break; case 'd': setOpcode((local > 3) ? Constants.DSTORE : (Constants.DSTORE0 + local)); break; default: setOpcode((local > 3) ? Constants.ASTORE : (Constants.ASTORE0 + local)); break; } } if (len != getLength()) invalidateByteIndexes(); return this; } /** * StoreInstructions are equal if the type they reference the same * type and locals index or if either is unset. */ public boolean equalsInstruction(Instruction other) { if (other == this) return true; if (!super.equalsInstruction(other)) return false; String type = getTypeName(); String otherType = ((StoreInstruction) other).getTypeName(); return type == null || otherType == null || type.equals(otherType); } public void acceptVisit(BCVisitor visit) { visit.enterStoreInstruction(this); visit.exitStoreInstruction(this); } void read(Instruction orig) { super.read(orig); StoreInstruction ins = (StoreInstruction) orig; _type = ins._type; } void read(DataInput in) throws IOException { super.read(in); switch (getOpcode()) { case Constants.ISTORE: case Constants.LSTORE: case Constants.FSTORE: case Constants.DSTORE: case Constants.ASTORE: setLocal(in.readUnsignedByte()); break; } } void write(DataOutput out) throws IOException { super.write(out); switch (getOpcode()) { case Constants.ISTORE: case Constants.LSTORE: case Constants.FSTORE: case Constants.DSTORE: case Constants.ASTORE: out.writeByte(getLocal()); } } void calculateOpcode() { // taken care of when setting type setType(getTypeName()); } void calculateLocal() { switch (getOpcode()) { case Constants.ISTORE0: case Constants.LSTORE0: case Constants.FSTORE0: case Constants.DSTORE0: case Constants.ASTORE0: setLocal(0); break; case Constants.ISTORE1: case Constants.LSTORE1: case Constants.FSTORE1: case Constants.DSTORE1: case Constants.ASTORE1: setLocal(1); break; case Constants.ISTORE2: case Constants.LSTORE2: case Constants.FSTORE2: case Constants.DSTORE2: case Constants.ASTORE2: setLocal(2); break; case Constants.ISTORE3: case Constants.LSTORE3: case Constants.FSTORE3: case Constants.DSTORE3: case Constants.ASTORE3: setLocal(3); break; } } } serp-1.14.1.orig/src/main/java/serp/bytecode/Attributes.java0000755000000000000000000001273210460270414020576 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; /** * Abstract superclass for all bytecode entities that hold attributes. * * @author Abe White */ public abstract class Attributes implements BCEntity { /** * Return all the attributes owned by this entity. * * @return all owned attributes, or empty array if none */ public Attribute[] getAttributes() { Collection attrs = getAttributesHolder(); return (Attribute[]) attrs.toArray(new Attribute[attrs.size()]); } /** * Return the attribute with the given name. If multiple attributes * share the name, which is returned is undefined. */ public Attribute getAttribute(String name) { Collection attrs = getAttributesHolder(); Attribute attr; for (Iterator itr = attrs.iterator(); itr.hasNext();) { attr = (Attribute) itr.next(); if (attr.getName().equals(name)) return attr; } return null; } /** * Return all attributes with the given name. * * @return the matching attributes, or empty array if none */ public Attribute[] getAttributes(String name) { List matches = new LinkedList(); Collection attrs = getAttributesHolder(); Attribute attr; for (Iterator itr = attrs.iterator(); itr.hasNext();) { attr = (Attribute) itr.next(); if (attr.getName().equals(name)) matches.add(attr); } return (Attribute[]) matches.toArray(new Attribute[matches.size()]); } /** * Set the attributes for this entity; this method is useful for importing * all attributes from another entity. Set to null or empty array if none. */ public void setAttributes(Attribute[] attrs) { clearAttributes(); if (attrs != null) for (int i = 0; i < attrs.length; i++) addAttribute(attrs[i]); } /** * Import an attribute from another entity, or make a copy of one * on this entity. */ public Attribute addAttribute(Attribute attr) { Attribute newAttr = addAttribute(attr.getName()); newAttr.read(attr); return newAttr; } /** * Add an attribute of the given type. */ public Attribute addAttribute(String name) { Attribute attr = Attribute.create(name, this); getAttributesHolder().add(attr); return attr; } /** * Clear all attributes from this entity. */ public void clearAttributes() { Collection attrs = getAttributesHolder(); Attribute attr; for (Iterator itr = attrs.iterator(); itr.hasNext();) { attr = (Attribute) itr.next(); itr.remove(); attr.invalidate(); } } /** * Remove all attributes with the given name from this entity. * * @return true if an attribute was removed, false otherwise */ public boolean removeAttribute(String name) { return removeAttribute(getAttribute(name)); } /** * Remove the given attribute. After being removed, the attribute * is invalid, and the result of any operations on it are undefined. * * @return true if the attribute was removed, false otherwise */ public boolean removeAttribute(Attribute attribute) { if ((attribute == null) || !getAttributesHolder().remove(attribute)) return false; attribute.invalidate(); return true; } /** * Convenience method to be called by BCEntities when being visited * by a {@link BCVisitor}; this method will allow the visitor to visit all * attributes of this entity. */ void visitAttributes(BCVisitor visit) { Attribute attr; for (Iterator itr = getAttributesHolder().iterator(); itr.hasNext();) { attr = (Attribute) itr.next(); visit.enterAttribute(attr); attr.acceptVisit(visit); visit.exitAttribute(attr); } } /** * Build the attribute list from the given stream. * Relies on the ability of attributes to read themselves, and * requires access to the constant pool, which must already by read. */ void readAttributes(DataInput in) throws IOException { Collection attrs = getAttributesHolder(); attrs.clear(); Attribute attribute; String name; for (int i = in.readUnsignedShort(); i > 0; i--) { name = ((UTF8Entry) getPool().getEntry(in.readUnsignedShort())). getValue(); attribute = addAttribute(name); attribute.read(in, in.readInt()); } } /** * Writes all the owned attributes to the given stream. * Relies on the ability of attributes to write themselves. */ void writeAttributes(DataOutput out) throws IOException { Collection attrs = getAttributesHolder(); out.writeShort(attrs.size()); Attribute attribute; int length; for (Iterator itr = attrs.iterator(); itr.hasNext();) { attribute = (Attribute) itr.next(); out.writeShort(attribute.getNameIndex()); length = attribute.getLength(); out.writeInt(length); attribute.write(out, length); } } /** * Return the collection used to hold the attributes of this entity. */ abstract Collection getAttributesHolder(); } serp-1.14.1.orig/src/main/java/serp/bytecode/BCMember.java0000755000000000000000000002564210524677056020106 0ustar package serp.bytecode; import java.io.*; import java.util.*; import serp.bytecode.lowlevel.*; /** * A member field or method of a class. * * @author Abe White */ public abstract class BCMember extends Annotated { private BCClass _owner = null; private int _access = Constants.ACCESS_PRIVATE; private int _nameIndex = 0; private int _descriptorIndex = 0; private Collection _attrs = new LinkedList(); BCMember(BCClass owner) { _owner = owner; } /** * Return the {@link BCClass} that declares this member. */ public BCClass getDeclarer() { return _owner; } ///////////////////// // Access operations ///////////////////// /** * Return the access flags for this member as a bit array of * ACCESS_XXX constants from {@link Constants}. This can be used to * transfer access flags between members without getting/setting each * possible access flag. Defaults to {@link Constants#ACCESS_PRIVATE} */ public int getAccessFlags() { return _access; } /** * Set the access flags for this member as a bit array of * ACCESS_XXX constants from {@link Constants}. This can be used to * transfer access flags between members without getting/setting each * possible access flag. Defaults to {@link Constants#ACCESS_PRIVATE} */ public void setAccessFlags(int access) { _access = access; } /** * Manipulate the member access flags. */ public boolean isPublic() { return (getAccessFlags() & Constants.ACCESS_PUBLIC) > 0; } /** * Manipulate the member access flags. */ public void makePublic() { setAccessFlags(getAccessFlags() | Constants.ACCESS_PUBLIC); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PRIVATE); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PROTECTED); } /** * Manipulate the member access flags. */ public boolean isProtected() { return (getAccessFlags() & Constants.ACCESS_PROTECTED) > 0; } /** * Manipulate the member access flags. */ public void makeProtected() { setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PRIVATE); setAccessFlags(getAccessFlags() | Constants.ACCESS_PROTECTED); } /** * Manipulate the member access flags. */ public boolean isPrivate() { return (getAccessFlags() & Constants.ACCESS_PRIVATE) > 0; } /** * Manipulate the member access flags. */ public void makePrivate() { setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC); setAccessFlags(getAccessFlags() | Constants.ACCESS_PRIVATE); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PROTECTED); } /** * Manipulate the member access flags. */ public boolean isPackage() { boolean hasAccess = false; hasAccess |= (getAccessFlags() & Constants.ACCESS_PRIVATE) > 0; hasAccess |= (getAccessFlags() & Constants.ACCESS_PROTECTED) > 0; hasAccess |= (getAccessFlags() & Constants.ACCESS_PUBLIC) > 0; return !hasAccess; } /** * Manipulate the member access flags. */ public void makePackage() { setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PRIVATE); setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PROTECTED); } /** * Manipulate the member access flags. */ public boolean isFinal() { return (getAccessFlags() & Constants.ACCESS_FINAL) > 0; } /** * Manipulate the member access flags. */ public void setFinal(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_FINAL); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_FINAL); } /** * Manipulate the member access flags. */ public boolean isStatic() { return (getAccessFlags() & Constants.ACCESS_STATIC) > 0; } /** * Manipulate the member access flags. */ public void setStatic(boolean on) { if (on) setAccessFlags(getAccessFlags() | Constants.ACCESS_STATIC); else setAccessFlags(getAccessFlags() & ~Constants.ACCESS_STATIC); } /** * Manipulate the field access flags. This method also checks the synthetic * member attribute. */ public boolean isSynthetic() { return (getAccessFlags() & Constants.ACCESS_SYNTHETIC) > 0 || getAttribute(Constants.ATTR_SYNTHETIC) != null; } /** * Manipulate the field access flags. This method also manipulates the * synthetic member attribute. */ public void setSynthetic(boolean on) { if (on) { setAccessFlags(getAccessFlags() | Constants.ACCESS_SYNTHETIC); addAttribute(Constants.ATTR_SYNTHETIC); } else { setAccessFlags(getAccessFlags() & ~Constants.ACCESS_SYNTHETIC); removeAttribute(Constants.ATTR_SYNTHETIC); } } ///////////////////////// // Descriptor operations ///////////////////////// /** * Return the index in the class {@link ConstantPool} of the * {@link UTF8Entry} holding the name of this member. */ public int getNameIndex() { return _nameIndex; } /** * Set the index in the class {@link ConstantPool} of the * {@link UTF8Entry} holding the name of this member. */ public void setNameIndex(int index) { String origName = getName(); _nameIndex = index; // change all the references in the owning class setEntry(origName, getDescriptor()); } /** * Return the index in the class {@link ConstantPool} of the * {@link UTF8Entry} holding the descriptor of this member. */ public int getDescriptorIndex() { return _descriptorIndex; } /** * Set the index in the class {@link ConstantPool} of the * {@link UTF8Entry} holding the descriptor of this member. */ public void setDescriptorIndex(int index) { String origDesc = getDescriptor(); _descriptorIndex = index; // change all the references in the owning class setEntry(getName(), origDesc); } /** * Return the name of this member. */ public String getName() { return ((UTF8Entry) getPool().getEntry(_nameIndex)).getValue(); } /** * Set the name of this member. */ public void setName(String name) { String origName = getName(); // reset the name _nameIndex = getPool().findUTF8Entry(name, true); // change all references in the owning class setEntry(origName, getDescriptor()); } /** * Return the descriptor of this member, in internal form. */ public String getDescriptor() { return ((UTF8Entry) getPool().getEntry(_descriptorIndex)).getValue(); } /** * Set the descriptor of this member. */ public void setDescriptor(String desc) { String origDesc = getDescriptor(); // reset the desc desc = getProject().getNameCache().getInternalForm(desc, true); _descriptorIndex = getPool().findUTF8Entry(desc, true); // change all the references in the owning class setEntry(getName(), origDesc); } /** * Resets the {@link ComplexEntry} of the owning class corresponding to * this member. Changes in the member will therefore propogate to all * code in the class. */ private void setEntry(String origName, String origDesc) { // find the entry matching this member, if any String owner = getProject().getNameCache().getInternalForm (_owner.getName(), false); ConstantPool pool = getPool(); int index; if (this instanceof BCField) index = pool.findFieldEntry(origName, origDesc, owner, false); else if (!_owner.isInterface()) index = pool.findMethodEntry(origName, origDesc, owner, false); else index = pool.findInterfaceMethodEntry(origName, origDesc, owner, false); // change the entry to match the new info; this is dones so // that refs to the member in code will still be valid after the // change, without changing any other constants that happened to match // the old name and/or descriptor if (index != 0) { ComplexEntry complex = (ComplexEntry) pool.getEntry(index); int ntIndex = pool.findNameAndTypeEntry(getName(), getDescriptor(), true); complex.setNameAndTypeIndex(ntIndex); } } /////////////////////// // Convenience methods /////////////////////// /** * Convenience method to return deprecation information for the member. * Acts internally through the {@link Attributes} interface. */ public boolean isDeprecated() { return getAttribute(Constants.ATTR_DEPRECATED) != null; } /** * Convenience method to set whether this member should be considered * deprecated. Acts internally through the {@link Attributes} interface. */ public void setDeprecated(boolean on) { if (!on) removeAttribute(Constants.ATTR_DEPRECATED); else if (!isDeprecated()) addAttribute(Constants.ATTR_DEPRECATED); } //////////////////////////////// // Implementation of Attributes //////////////////////////////// public Project getProject() { return _owner.getProject(); } public ConstantPool getPool() { return _owner.getPool(); } public ClassLoader getClassLoader() { return _owner.getClassLoader(); } public boolean isValid() { return _owner != null; } Collection getAttributesHolder() { return _attrs; } /** * Either this method or {@link #read} must be called prior to use * of this class. The given descriptor must be in internal form. */ void initialize(String name, String descriptor) { _nameIndex = getPool().findUTF8Entry(name, true); _descriptorIndex = getPool().findUTF8Entry(descriptor, true); } /////////////////////////////// // Implementation of Annotated /////////////////////////////// BCClass getBCClass() { return _owner; } /** * Used when this member is deleted from its class. */ void invalidate() { _owner = null; } void read(DataInput in) throws IOException { _access = in.readUnsignedShort(); _nameIndex = in.readUnsignedShort(); _descriptorIndex = in.readUnsignedShort(); readAttributes(in); } void write(DataOutput out) throws IOException { out.writeShort(_access); out.writeShort(_nameIndex); out.writeShort(_descriptorIndex); writeAttributes(out); } } serp-1.14.1.orig/src/main/java/serp/bytecode/Deprecated.java0000755000000000000000000000063510460270414020507 0ustar package serp.bytecode; import serp.bytecode.visitor.*; /** * Attribute signifying that a method or class is deprecated. * * @author Abe White */ public class Deprecated extends Attribute { Deprecated(int nameIndex, Attributes owner) { super(nameIndex, owner); } public void acceptVisit(BCVisitor visit) { visit.enterDeprecated(this); visit.exitDeprecated(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/BCEntity.java0000755000000000000000000000143510460270414020127 0ustar package serp.bytecode; import serp.bytecode.lowlevel.*; /** * Interface implemented by all bytecode entities. Entities must be able * to access the project, constant pool, and class loader of the current class. * * @author Abe White */ public interface BCEntity { /** * Return the project of the current class. */ public Project getProject(); /** * Return the constant pool of the current class. */ public ConstantPool getPool(); /** * Return the class loader to use when loading related classes. */ public ClassLoader getClassLoader(); /** * Return false if this entity has been removed from its parent; in this * case the results of any operations on the entity are undefined. */ public boolean isValid(); } serp-1.14.1.orig/src/main/java/serp/bytecode/ConstantValue.java0000755000000000000000000001337510460270414021242 0ustar package serp.bytecode; import java.io.*; import serp.bytecode.lowlevel.*; import serp.bytecode.visitor.*; /** * A constant value for a member field. * * @author Abe White */ public class ConstantValue extends Attribute { int _valueIndex = 0; ConstantValue(int nameIndex, Attributes owner) { super(nameIndex, owner); } int getLength() { return 2; } /** * Return the owning field. */ public BCField getField() { return (BCField) getOwner(); } /** * Return the {@link ConstantPool} index of the {@link ConstantEntry} * holding the value of this constant. Defaults to 0. */ public int getValueIndex() { return _valueIndex; } /** * Set the {@link ConstantPool} of the {@link ConstantEntry} * holding the value of this constant. */ public void setValueIndex(int valueIndex) { _valueIndex = valueIndex; } /** * Return the type of constant this attribute represents, or null if * not set. */ public String getTypeName() { Class type = getType(); if (type == null) return null; return type.getName(); } /** * Return the type of constant this attribute represents (String.class, * int.class, etc), or null if not set. */ public Class getType() { Object value = getValue(); if (value == null) return null; Class type = value.getClass(); if (type == Integer.class) return int.class; if (type == Float.class) return float.class; if (type == Double.class) return double.class; if (type == Long.class) return long.class; return String.class; } /** * Return the bytecode for the type of constant this attribute represents. */ public BCClass getTypeBC() { return getProject().loadClass(getType()); } /** * Return the value of this constant as an Object of the appropriate * type (String, Integer, Double, etc), or null if not set. */ public Object getValue() { if (_valueIndex <= 0) return null; return ((ConstantEntry) getPool().getEntry(_valueIndex)).getConstant(); } /** * Set the value of this constant using the appropriate wrapper Object * type (String, Integer, Double, etc). Types that are not directly * supported will be converted accordingly if possible. */ public void setValue(Object value) { Class type = value.getClass(); if (type == Boolean.class) setIntValue((((Boolean) value).booleanValue()) ? 1 : 0); else if (type == Character.class) setIntValue((int) ((Character) value).charValue()); else if (type == Byte.class || type == Integer.class || type == Short.class) setIntValue(((Number) value).intValue()); else if (type == Float.class) setFloatValue(((Number) value).floatValue()); else if (type == Double.class) setDoubleValue(((Number) value).doubleValue()); else if (type == Long.class) setLongValue(((Number) value).longValue()); else setStringValue(value.toString()); } /** * Get the value of this int constant, or 0 if not set. */ public int getIntValue() { if (getValueIndex() <= 0) return 0; return ((IntEntry) getPool().getEntry(getValueIndex())).getValue(); } /** * Set the value of this int constant. */ public void setIntValue(int value) { setValueIndex(getPool().findIntEntry(value, true)); } /** * Get the value of this float constant. */ public float getFloatValue() { if (getValueIndex() <= 0) return 0F; return ((FloatEntry) getPool().getEntry(getValueIndex())).getValue(); } /** * Set the value of this float constant. */ public void setFloatValue(float value) { setValueIndex(getPool().findFloatEntry(value, true)); } /** * Get the value of this double constant. */ public double getDoubleValue() { if (getValueIndex() <= 0) return 0D; return ((DoubleEntry) getPool().getEntry(getValueIndex())).getValue(); } /** * Set the value of this double constant. */ public void setDoubleValue(double value) { setValueIndex(getPool().findDoubleEntry(value, true)); } /** * Get the value of this long constant. */ public long getLongValue() { if (getValueIndex() <= 0) return 0L; return ((LongEntry) getPool().getEntry(getValueIndex())).getValue(); } /** * Set the value of this long constant. */ public void setLongValue(long value) { setValueIndex(getPool().findLongEntry(value, true)); } /** * Get the value of this string constant. */ public String getStringValue() { if (getValueIndex() <= 0) return null; return ((StringEntry) getPool().getEntry(getValueIndex())). getStringEntry().getValue(); } /** * Set the value of this string constant. */ public void setStringValue(String value) { setValueIndex(getPool().findStringEntry(value, true)); } public void acceptVisit(BCVisitor visit) { visit.enterConstantValue(this); visit.exitConstantValue(this); } void read(Attribute other) { setValue(((ConstantValue) other).getValue()); } void read(DataInput in, int length) throws IOException { setValueIndex(in.readUnsignedShort()); } void write(DataOutput out, int length) throws IOException { out.writeShort(getValueIndex()); } } serp-1.14.1.orig/src/main/java/serp/bytecode/PrimitiveState.java0000755000000000000000000000301010660077275021422 0ustar package serp.bytecode; import java.util.*; import serp.bytecode.lowlevel.*; /** * State implementing the behavior of a primitive class. * * @author Abe White */ class PrimitiveState extends State { private final Class _type; private final NameCache _names; public PrimitiveState(Class type, NameCache names) { _type = type; _names = names; } public int getMagic() { return Constants.VALID_MAGIC; } public int getMajorVersion() { return Constants.MAJOR_VERSION; } public int getMinorVersion() { return Constants.MINOR_VERSION; } public int getAccessFlags() { return Constants.ACCESS_PUBLIC | Constants.ACCESS_FINAL; } public int getIndex() { return 0; } public int getSuperclassIndex() { return 0; } public List getInterfacesHolder() { return Collections.EMPTY_LIST; } public List getFieldsHolder() { return Collections.EMPTY_LIST; } public List getMethodsHolder() { return Collections.EMPTY_LIST; } public Collection getAttributesHolder() { return Collections.EMPTY_LIST; } public String getName() { return _names.getExternalForm(_type.getName(), false); } public String getSuperclassName() { return null; } public String getComponentName() { return null; } public boolean isPrimitive() { return true; } public boolean isArray() { return false; } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/0000755000000000000000000000000011401260237017424 5ustar serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/ConstantPoolTable.java0000755000000000000000000001125210460270415023671 0ustar package serp.bytecode.lowlevel; import java.io.*; /** * Efficient representation of the constant pool as a table. This class * can be used to parse out bits of information from bytecode without * instantiating a full {@link serp.bytecode.BCClass}. * * @author Abe White */ public class ConstantPoolTable { private byte[] _bytecode = null; private int[] _table = null; private int _idx = 0; /** * Constructor; supply class bytecode. */ public ConstantPoolTable(byte[] b) { _bytecode = b; _table = new int[readUnsignedShort(b, 8)]; _idx = parse(b, _table); } /** * Constructor; supply input stream to bytecode. */ public ConstantPoolTable(InputStream in) throws IOException { this(toByteArray(in)); } /** * Allows static computation of the byte index after the constant * pool without caching constant pool information. */ public static int getEndIndex(byte[] b) { return parse(b, null); } /** * Parse class bytecode, returning end index of pool. */ private static int parse(byte[] b, int[] table) { // each entry is the index in the byte array of the data for a const // pool entry int entries = (table == null) ? readUnsignedShort(b, 8) : table.length; int idx = 10; for (int i = 1; i < entries; i++) { if (table != null) table[i] = idx + 1; // skip entry type switch (b[idx]) { case 1: // utf8 idx += (3 + readUnsignedShort(b, idx + 1)); break; case 3: // integer case 4: // float case 9: // field case 10: // method case 11: // interface method case 12: // name idx += 5; break; case 5: // long case 6: // double idx += 9; i++; // wide entry break; default: idx += 3; } } return idx; } /** * Read a byte value at the given offset into the given bytecode. */ public static int readByte(byte[] b, int idx) { return b[idx] & 0xFF; } /** * Read an unsigned short value at the given offset into the given bytecode. */ public static int readUnsignedShort(byte[] b, int idx) { return (readByte(b, idx) << 8) | readByte(b, idx + 1); } /** * Read an int value at the given offset into the given bytecode. */ public static int readInt(byte[] b, int idx) { return (readByte(b, idx) << 24) | (readByte(b, idx + 1) << 16) | (readByte(b, idx + 2) << 8) | readByte(b, idx + 3); } /** * Read a long value at the given offset into the given bytecode. */ public static long readLong(byte[] b, int idx) { return (readInt(b, idx) << 32) | readInt(b, idx + 4); } /** * Read a UTF-8 string value at the given offset into the given bytecode. */ public static String readString(byte[] b, int idx) { int len = readUnsignedShort(b, idx); try { return new String(b, idx + 2, len, "UTF-8"); } catch (UnsupportedEncodingException uee) { throw new ClassFormatError(uee.toString()); } } /** * Read the contents of the given stream. */ private static byte[] toByteArray(InputStream in) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; for (int r; (r = in.read(buf)) != -1; bout.write(buf, 0, r)); return bout.toByteArray(); } /** * Return the index into the bytecode of the end of the constant pool. */ public int getEndIndex() { return _idx; } /** * Return the given table entry. */ public int get(int idx) { return _table[idx]; } /** * Read a byte value at the given offset. */ public int readByte(int idx) { return readByte(_bytecode, idx); } /** * Read an unsigned short value at the given offset. */ public int readUnsignedShort(int idx) { return readUnsignedShort(_bytecode, idx); } /** * Read an int value at the given offset. */ public int readInt(int idx) { return readInt(_bytecode, idx); } /** * Read a long value at the given offset. */ public long readLong(int idx) { return readLong(_bytecode, idx); } /** * Read a UTF-8 string value at the given offset. */ public String readString(int idx) { return readString(_bytecode, idx); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/ConstantPool.java0000755000000000000000000004352610460270415022732 0ustar package serp.bytecode.lowlevel; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; import serp.util.*; /** * A bytecode constant pool, containing entries for all strings, * constants, classes, etc referenced in the class structure and method * opcodes. In keeping with the low-level bytecode representation, all pool * indexes are 1-based and {@link LongEntry}s and {@link DoubleEntry}s each * occupy two indexes in the pool. * * @author Abe White */ public class ConstantPool implements VisitAcceptor { private List _entries = new ArrayList(50); private Map _lookup = new HashMap(50); /** * Default constructor. */ public ConstantPool() { } /** * Return all the entries in the pool. */ public Entry[] getEntries() { List entries = new ArrayList(_entries.size()); Entry entry; for (Iterator itr = _entries.iterator(); itr.hasNext();) { entry = (Entry) itr.next(); if (entry != null) entries.add(entry); } return (Entry[]) entries.toArray(new Entry[entries.size()]); } /** * Retrieve the entry at the specified 1-based index. * * @throws IndexOutOfBoundsException if index is invalid, * including the case that it points to the second slot of a * long or double entry */ public Entry getEntry(int index) { Entry entry = (Entry) _entries.get(index - 1); if (entry == null) throw new IndexOutOfBoundsException("index = " + index); return entry; } /** * Return the index of the given entry, or 0 if it is not in the pool. */ public int indexOf(Entry entry) { if (entry == null || entry.getPool() != this) return 0; return entry.getIndex(); } /** * Add an entry to the pool. * * @return the index at which the entry was added */ public int addEntry(Entry entry) { if (entry.getPool() != this) addEntry(getKey(entry), entry); return entry.getIndex(); } /** * Add an entry to the pool using the given key. */ private int addEntry(Object key, Entry entry) { entry.setPool(this); _entries.add(entry); entry.setIndex(_entries.size()); _lookup.put(key, entry); if (entry.isWide()) _entries.add(null); return entry.getIndex(); } /** * Remove the given entry from the pool. * * @return false if the entry is not in the pool, true otherwise */ public boolean removeEntry(Entry entry) { if (entry == null || entry.getPool() != this) return false; int index = entry.getIndex() - 1; entry.setPool(null); entry.setIndex(0); _entries.remove(index); if (entry.isWide()) _entries.remove(index); _lookup.remove(getKey(entry)); // rehash all the entries after the removed one with their new index Object key; for (int i = index; i < _entries.size(); i++) { entry = (Entry) _entries.get(i); if (entry != null) { key = getKey(entry); _lookup.remove(key); entry.setIndex(i + 1); _lookup.put(key, entry); } } return true; } /** * Clear all entries from the pool. */ public void clear() { Entry entry; for (Iterator itr = _entries.iterator(); itr.hasNext();) { entry = (Entry) itr.next(); if (entry != null) { entry.setPool(null); entry.setIndex(0); } } _entries.clear(); _lookup.clear(); } /** * Return the number of places occupied in the pool, including the fact * that long and double entries occupy two places. */ public int size() { return _entries.size(); } /** * Return the index of the {@link UTF8Entry} with the given value, or * 0 if it does not exist. * * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findUTF8Entry(String value, boolean add) { if (value == null) { if (add) throw new NullPointerException("value = null"); return 0; } int index = find(value); if (!add || index > 0) return index; return addEntry(value, new UTF8Entry(value)); } /** * Return the constant pool index of the {@link DoubleEntry} for the given * value, or 0 if it does not exist. * * @param value the value to find * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findDoubleEntry(double value, boolean add) { Double key = new Double(value); int index = find(key); if (!add || (index > 0)) return index; return addEntry(key, new DoubleEntry(value)); } /** * Return the constant pool index of the {@link FloatEntry} for the given * value, or 0 if it does not exist. * * @param value the value to find * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findFloatEntry(float value, boolean add) { Float key = new Float(value); int index = find(key); if (!add || index > 0) return index; return addEntry(key, new FloatEntry(value)); } /** * Return the constant pool index of the {@link IntEntry} for the given * value, or 0 if it does not exist. * * @param value the value to find * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findIntEntry(int value, boolean add) { Integer key = Numbers.valueOf(value); int index = find(key); if (!add || index > 0) return index; return addEntry(key, new IntEntry(value)); } /** * Return the constant pool index of the {@link LongEntry} for the given * value, or 0 if it does not exist. * * @param value the value to find * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findLongEntry(long value, boolean add) { Long key = Numbers.valueOf(value); int index = find(key); if (!add || index > 0) return index; return addEntry(key, new LongEntry(value)); } /** * Return the constant pool index of the {@link StringEntry} for the given * string value, or 0 if it does not exist. * * @param value the value to find * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findStringEntry(String value, boolean add) { int valueIndex = findUTF8Entry(value, add); if (valueIndex == 0) return 0; StringKey key = new StringKey(valueIndex); int index = find(key); if (!add || index > 0) return index; return addEntry(key, new StringEntry(valueIndex)); } /** * Return the constant pool index of the {@link ClassEntry} for the given * class name, or 0 if it does not exist. * * @param name the class name in internal form * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findClassEntry(String name, boolean add) { int nameIndex = findUTF8Entry(name, add); if (nameIndex == 0) return 0; ClassKey key = new ClassKey(nameIndex); int index = find(key); if (!add || index > 0) return index; return addEntry(key, new ClassEntry(nameIndex)); } /** * Return the constant pool index of the {@link NameAndTypeEntry} for the * given name and descriptor, or 0 if it does not exist. * * @param name the name of the entity * @param desc the descriptor of the entity in internal form * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findNameAndTypeEntry(String name, String desc, boolean add) { int nameIndex = findUTF8Entry(name, add); if (nameIndex == 0) return 0; int descIndex = findUTF8Entry(desc, add); if (descIndex == 0) return 0; NameAndTypeKey key = new NameAndTypeKey(nameIndex, descIndex); int index = find(key); if (!add || index > 0) return index; return addEntry(key, new NameAndTypeEntry(nameIndex, descIndex)); } /** * Return the constant pool index of the {@link FieldEntry} for the * given name, descriptor, and owner class name. * * @param owner the name of the field's owning class in internal form * @param name the name of the field * @param desc the descriptor of the field in internal form * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findFieldEntry(String owner, String name, String desc, boolean add) { return findComplexEntry(owner, name, desc, Entry.FIELD, add); } /** * Return the constant pool index of the {@link MethodEntry} for the * given name, descriptor, and owner class name. * * @param owner the name of the method's owning class in internal form * @param name the name of the method * @param desc the descriptor of the method in internal form * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findMethodEntry(String owner, String name, String desc, boolean add) { return findComplexEntry(owner, name, desc, Entry.METHOD, add); } /** * Return the constant pool index of the {@link InterfaceMethodEntry} for * the given name, descriptor, and owner class name. * * @param owner the name of the method's owning class in internal form * @param name the name of the method * @param desc the descriptor of the method in internal form * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ public int findInterfaceMethodEntry(String owner, String name, String desc, boolean add) { return findComplexEntry(owner, name, desc, Entry.INTERFACEMETHOD, add); } /** * Return the constant pool index of the {@link ComplexEntry} for the * given name, descriptor, and owner class name. * * @param owner the name of the owning class in internal form * @param name the name of the entity * @param desc the descriptor of the entity in internal form * @param type the type of entry: field, method, interface method * @param add if true, the entry will be added if it does not * already exist, and the new entry's index returned */ private int findComplexEntry(String owner, String name, String desc, int type, boolean add) { int classIndex = findClassEntry(owner, add); if (classIndex == 0) return 0; int descIndex = findNameAndTypeEntry(name, desc, add); if (descIndex == 0) return 0; Object key = null; switch (type) { case Entry.FIELD: key = new FieldKey(classIndex, descIndex); break; case Entry.METHOD: key = new MethodKey(classIndex, descIndex); break; case Entry.INTERFACEMETHOD: key = new InterfaceMethodKey(classIndex, descIndex); break; } int index = find(key); if (!add || index > 0) return index; Entry entry = null; switch (type) { case Entry.FIELD: entry = new FieldEntry(classIndex, descIndex); break; case Entry.METHOD: entry = new MethodEntry(classIndex, descIndex); break; case Entry.INTERFACEMETHOD: entry = new InterfaceMethodEntry(classIndex, descIndex); break; } return addEntry(key, entry); } public void acceptVisit(BCVisitor visit) { visit.enterConstantPool(this); Entry entry; for (Iterator itr = _entries.iterator(); itr.hasNext();) { entry = (Entry) itr.next(); if (entry == null) continue; visit.enterEntry(entry); entry.acceptVisit(visit); visit.exitEntry(entry); } visit.exitConstantPool(this); } /** * Fill the constant pool from the given bytecode stream. */ public void read(DataInput in) throws IOException { clear(); int entryCount = in.readUnsignedShort(); Entry entry; for (int i = 1; i < entryCount; i++) { entry = Entry.read(in); addEntry(entry); if (entry.isWide()) i++; } } /** * Write the constant pool to the given bytecode stream. */ public void write(DataOutput out) throws IOException { out.writeShort(_entries.size() + 1); Entry entry; for (Iterator itr = _entries.iterator(); itr.hasNext();) { entry = (Entry) itr.next(); if (entry != null) Entry.write(entry, out); } } /** * Called by constant pool entries when they are mutated. */ void modifyEntry(Object origKey, Entry entry) { _lookup.remove(origKey); _lookup.put(getKey(entry), entry); } /** * Returns the constant pool index of the entry with the given key. */ private int find(Object key) { Entry entry = (Entry) _lookup.get(key); if (entry == null) return 0; return entry.getIndex(); } /** * Return the hash key used for the specified entry. */ static Object getKey(Entry entry) { switch (entry.getType()) { case Entry.CLASS: return new ClassKey(((ClassEntry) entry).getNameIndex()); case Entry.FIELD: FieldEntry fe = (FieldEntry) entry; return new FieldKey(fe.getClassIndex(), fe.getNameAndTypeIndex()); case Entry.METHOD: MethodEntry me = (MethodEntry) entry; return new MethodKey(me.getClassIndex(), me.getNameAndTypeIndex()); case Entry.INTERFACEMETHOD: InterfaceMethodEntry ime = (InterfaceMethodEntry) entry; return new InterfaceMethodKey(ime.getClassIndex(), ime.getNameAndTypeIndex()); case Entry.STRING: return new StringKey(((StringEntry) entry).getStringIndex()); case Entry.INT: case Entry.FLOAT: case Entry.LONG: case Entry.DOUBLE: case Entry.UTF8: return ((ConstantEntry) entry).getConstant(); case Entry.NAMEANDTYPE: NameAndTypeEntry nte = (NameAndTypeEntry) entry; return new NameAndTypeKey(nte.getNameIndex(), nte.getDescriptorIndex()); default: return null; } } /** * Base class key for entries with one ptr to another entry. */ private static abstract class PtrKey { private final int _index; public PtrKey(int index) { _index = index; } public int hashCode() { return _index; } public boolean equals(Object other) { if (other == this) return true; if (other.getClass() != getClass()) return false; return ((PtrKey) other)._index == _index; } } /** * Key for string entries. */ private static class StringKey extends PtrKey { public StringKey(int index) { super(index); } } /** * Key for class entries. */ private static class ClassKey extends PtrKey { public ClassKey(int index) { super(index); } } /** * Base class key for entries with two ptr to other entries. */ private static abstract class DoublePtrKey { private final int _index1; private final int _index2; public DoublePtrKey(int index1, int index2) { _index1 = index1; _index2 = index2; } public int hashCode() { return _index1 ^ _index2; } public boolean equals(Object other) { if (other == this) return true; if (other.getClass() != getClass()) return false; DoublePtrKey key = (DoublePtrKey) other; return key._index1 == _index1 && key._index2 == _index2; } } /** * Key for name and type entries. */ private static class NameAndTypeKey extends DoublePtrKey { public NameAndTypeKey(int index1, int index2) { super(index1, index2); } } /** * Key for field entries. */ private static class FieldKey extends DoublePtrKey { public FieldKey(int index1, int index2) { super(index1, index2); } } /** * Key for method entries. */ private static class MethodKey extends DoublePtrKey { public MethodKey(int index1, int index2) { super(index1, index2); } } /** * Key for interface method entries. */ private static class InterfaceMethodKey extends DoublePtrKey { public InterfaceMethodKey(int index1, int index2) { super(index1, index2); } } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/NameAndTypeEntry.java0000755000000000000000000000552710460270415023475 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; /** * Entry containing indexes referencing a name and a descriptor. Used * to describe fields and methods of other classes referenced by opcodes. * * @author Abe White */ public class NameAndTypeEntry extends Entry { private int _nameIndex = 0; private int _descriptorIndex = 0; /** * Default constructor. */ public NameAndTypeEntry() { } /** * Constructor. * * @param nameIndex the constant pool index of the * {@link UTF8Entry} containing the name of this entity * @param descriptorIndex the constant pool index of the * {@link UTF8Entry} containing the descriptor for this entity */ public NameAndTypeEntry(int nameIndex, int descriptorIndex) { _nameIndex = nameIndex; _descriptorIndex = descriptorIndex; } public int getType() { return Entry.NAMEANDTYPE; } /** * Return the constant pool index of the {@link UTF8Entry} * containing the name of this entity. */ public int getNameIndex() { return _nameIndex; } /** * Set the constant pool index of the {@link UTF8Entry} * containing the name of this entity. */ public void setNameIndex(int nameIndex) { Object key = beforeModify(); _nameIndex = nameIndex; afterModify(key); } /** * Return the name's referenced {@link UTF8Entry}. This method can only * be run for entries that have been added to a constant pool. */ public UTF8Entry getNameEntry() { return (UTF8Entry) getPool().getEntry(_nameIndex); } /** * Return the constant pool index of the {@link UTF8Entry} * containing the descriptor for this entity. */ public int getDescriptorIndex() { return _descriptorIndex; } /** * Set the constant pool index of a {@link UTF8Entry} * containing the descriptor for this entity. */ public void setDescriptorIndex(int descriptorIndex) { Object key = beforeModify(); _descriptorIndex = descriptorIndex; afterModify(key); } /** * Return the descriptor's referenced {@link UTF8Entry}. This method * can only be run for entries that have been added to a constant pool. */ public UTF8Entry getDescriptorEntry() { return (UTF8Entry) getPool().getEntry(_descriptorIndex); } public void acceptVisit(BCVisitor visit) { visit.enterNameAndTypeEntry(this); visit.exitNameAndTypeEntry(this); } void readData(DataInput in) throws IOException { _nameIndex = in.readUnsignedShort(); _descriptorIndex = in.readUnsignedShort(); } void writeData(DataOutput out) throws IOException { out.writeShort(_nameIndex); out.writeShort(_descriptorIndex); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/DoubleEntry.java0000755000000000000000000000264610460270415022541 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; /** * A constant double value in the constant pool. * * @author Abe White */ public class DoubleEntry extends Entry implements ConstantEntry { private double _value = 0.0; /** * Default constructor. */ public DoubleEntry() { } /** * Constructor. * * @param value the constant double value of this entry */ public DoubleEntry(double value) { _value = value; } public boolean isWide() { return true; } public int getType() { return Entry.DOUBLE; } /** * Return the value of the constant. */ public double getValue() { return _value; } /** * Set the value of the constant. */ public void setValue(double value) { Object key = beforeModify(); _value = value; afterModify(key); } public Object getConstant() { return new Double(getValue()); } public void setConstant(Object value) { setValue(((Number) value).doubleValue()); } public void acceptVisit(BCVisitor visit) { visit.enterDoubleEntry(this); visit.exitDoubleEntry(this); } void readData(DataInput in) throws IOException { _value = in.readDouble(); } void writeData(DataOutput out) throws IOException { out.writeDouble(_value); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/StringEntry.java0000755000000000000000000000367510460270415022600 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; /** * A String constant in the constant pool. String constants * hold a reference to a {@link UTF8Entry} that stores the actual value. * * @author Abe White */ public class StringEntry extends Entry implements ConstantEntry { private int _stringIndex = -1; /** * Default constructor. */ public StringEntry() { } /** * Constructor. * * @param stringIndex the constant pool index of the {@link UTF8Entry} * containing the value of this string */ public StringEntry(int stringIndex) { _stringIndex = stringIndex; } public int getType() { return Entry.STRING; } /** * Return the constant pool index of the {@link UTF8Entry} * storing the value of this string. */ public int getStringIndex() { return _stringIndex; } /** * Set the constant pool index of the {@link UTF8Entry} * storing the value of this string. */ public void setStringIndex(int stringIndex) { Object key = beforeModify(); _stringIndex = stringIndex; afterModify(key); } /** * Return the referenced {@link UTF8Entry}. This method can only * be run for entries that have been added to a constant pool. */ public UTF8Entry getStringEntry() { return (UTF8Entry) getPool().getEntry(_stringIndex); } public Object getConstant() { return getStringEntry().getValue(); } public void setConstant(Object value) { getStringEntry().setConstant(value); } public void acceptVisit(BCVisitor visit) { visit.enterStringEntry(this); visit.exitStringEntry(this); } void readData(DataInput in) throws IOException { _stringIndex = in.readUnsignedShort(); } void writeData(DataOutput out) throws IOException { out.writeShort(_stringIndex); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/package.html0000755000000000000000000000057010455026340021715 0ustar

Lowlevel Bytecode Manipuation

This package contains facilities for lowlevel bytecode manipulation through the class constant pool. It is generally not necessary to use this package directly, as all necessary functionality is made available at a high level via the serp.bytecode package.

serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/InterfaceMethodEntry.java0000755000000000000000000000133610460270415024363 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; /** * A reference to an interface method. * * @author Abe White */ public class InterfaceMethodEntry extends ComplexEntry { /** * Default constructor. */ public InterfaceMethodEntry() { } /** * Constructor. * * @see ComplexEntry#ComplexEntry(int,int) */ public InterfaceMethodEntry(int classIndex, int nameAndTypeIndex) { super(classIndex, nameAndTypeIndex); } public int getType() { return Entry.INTERFACEMETHOD; } public void acceptVisit(BCVisitor visit) { visit.enterInterfaceMethodEntry(this); visit.exitInterfaceMethodEntry(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/ClassEntry.java0000755000000000000000000000406010460270415022364 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; /** * A constant pool entry describing a class. * Class entries are used to refer to the current class, the superclass, * implemented interfaces, etc. Each class entry contains the constant pool * index of the {@link UTF8Entry} that stores the class name, which is * represented in internal form. * * @author Abe White */ public class ClassEntry extends Entry implements ConstantEntry { private int _nameIndex = 0; /** * Default constructor. */ public ClassEntry() { } /** * Constructor. * * @param nameIndex the constant pool index of the {@link UTF8Entry} * containing the class name */ public ClassEntry(int nameIndex) { _nameIndex = nameIndex; } /** * Return the constant pool index of the {@link UTF8Entry} * containing the class name. Defaults to 0. */ public int getNameIndex() { return _nameIndex; } /** * Set the constant pool index of the {@link UTF8Entry} * containing the class name. */ public void setNameIndex(int nameIndex) { Object key = beforeModify(); _nameIndex = nameIndex; afterModify(key); } /** * Return the referenced {@link UTF8Entry}. This method can only * be run for entries that have been added to a constant pool. */ public UTF8Entry getNameEntry() { return (UTF8Entry) getPool().getEntry(_nameIndex); } public int getType() { return Entry.CLASS; } public Object getConstant() { return getNameEntry().getValue(); } public void setConstant(Object value) { getNameEntry().setConstant(value); } public void acceptVisit(BCVisitor visit) { visit.enterClassEntry(this); visit.exitClassEntry(this); } void readData(DataInput in) throws IOException { _nameIndex = in.readUnsignedShort(); } void writeData(DataOutput out) throws IOException { out.writeShort(_nameIndex); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/Entry.java0000755000000000000000000001025410460270415021400 0ustar package serp.bytecode.lowlevel; import java.io.*; import java.util.*; import serp.bytecode.visitor.*; /** * Base type for all constant pool entries. Entries should generally be * considered immutable; modifying an entry directly can have dire * consequences, and often renders the resulting class file invalid. * *

Entries cannot be shared among constant pools.

* * @author Abe White */ public abstract class Entry implements VisitAcceptor { public static final int UTF8 = 1; public static final int INT = 3; public static final int FLOAT = 4; public static final int LONG = 5; public static final int DOUBLE = 6; public static final int CLASS = 7; public static final int STRING = 8; public static final int FIELD = 9; public static final int METHOD = 10; public static final int INTERFACEMETHOD = 11; public static final int NAMEANDTYPE = 12; private ConstantPool _pool = null; private int _index = 0; /** * Read a single entry from the given bytecode stream and returns it. */ public static Entry read(DataInput in) throws IOException { Entry entry = create(in.readUnsignedByte()); entry.readData(in); return entry; } /** * Write the given entry to the given bytecode stream. */ public static void write(Entry entry, DataOutput out) throws IOException { out.writeByte(entry.getType()); entry.writeData(out); } /** * Create an entry based on its type code. */ public static Entry create(int type) { switch (type) { case CLASS: return new ClassEntry(); case FIELD: return new FieldEntry(); case METHOD: return new MethodEntry(); case INTERFACEMETHOD: return new InterfaceMethodEntry(); case STRING: return new StringEntry(); case INT: return new IntEntry(); case FLOAT: return new FloatEntry(); case LONG: return new LongEntry(); case DOUBLE: return new DoubleEntry(); case NAMEANDTYPE: return new NameAndTypeEntry(); case UTF8: return new UTF8Entry(); default: throw new IllegalArgumentException("type = " + type); } } /** * Return the type code for this entry type. */ public abstract int getType(); /** * Return true if this is a wide entry -- i.e. if it takes up two * places in the constant pool. Returns false by default. */ public boolean isWide() { return false; } /** * Returns the constant pool containing this entry, or null if none. */ public ConstantPool getPool() { return _pool; } /** * Returns the index of the entry in the owning constant pool, or 0. */ public int getIndex() { return _index; } /** * This method is called after reading the entry type from bytecode. * It should read all the data for this entry from the given stream. */ abstract void readData(DataInput in) throws IOException; /** * This method is called after writing the entry type to bytecode. * It should write all data for this entry to the given stream. */ abstract void writeData(DataOutput out) throws IOException; /** * Subclasses must call this method before their state is mutated. */ Object beforeModify() { if (_pool == null) return null; return _pool.getKey(this); } /** * Subclasses must call this method when their state is mutated. */ void afterModify(Object key) { if (_pool != null) _pool.modifyEntry(key, this); } /** * Sets the owning pool of the entry. */ void setPool(ConstantPool pool) { // attempting to overwrite current pool? if (_pool != null && pool != null && _pool != pool) throw new IllegalStateException("Entry already belongs to a pool"); _pool = pool; } /** * Set the index of this entry within the pool. */ void setIndex(int index) { _index = index; } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/UTF8Entry.java0000755000000000000000000000261510460270415022051 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; /** * A unicode string value in the constant pool. * * @author Abe White */ public class UTF8Entry extends Entry implements ConstantEntry { private String _value = ""; /** * Default constructor. */ public UTF8Entry() { } /** * Constructor. * * @param value the constant string value of this entry */ public UTF8Entry(String value) { _value = value; } public int getType() { return Entry.UTF8; } /** * Return the value of the entry. */ public String getValue() { return _value; } /** * Set the value of the entry. */ public void setValue(String value) { if (value == null) throw new NullPointerException("value = null"); Object key = beforeModify(); _value = value; afterModify(key); } public Object getConstant() { return getValue(); } public void setConstant(Object value) { setValue((String) value); } public void acceptVisit(BCVisitor visit) { visit.enterUTF8Entry(this); visit.exitUTF8Entry(this); } void readData(DataInput in) throws IOException { _value = in.readUTF(); } void writeData(DataOutput out) throws IOException { out.writeUTF(_value); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/MethodEntry.java0000755000000000000000000000124310460270415022537 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; /** * A reference to a class method. * * @author Abe White */ public class MethodEntry extends ComplexEntry { /** * Default constructor. */ public MethodEntry() { } /** * Constructor. * * @see ComplexEntry#ComplexEntry(int,int) */ public MethodEntry(int classIndex, int nameAndTypeIndex) { super(classIndex, nameAndTypeIndex); } public int getType() { return Entry.METHOD; } public void acceptVisit(BCVisitor visit) { visit.enterMethodEntry(this); visit.exitMethodEntry(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/IntEntry.java0000755000000000000000000000255510460270415022060 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; import serp.util.*; /** * A constant int value in the constant pool. * * @author Abe White */ public class IntEntry extends Entry implements ConstantEntry { private int _value = -1; /** * Default constructor. */ public IntEntry() { } /** * Constructor. * * @param value the constant int value of this entry */ public IntEntry(int value) { _value = value; } public int getType() { return Entry.INT; } /** * Return the value of this constant. */ public int getValue() { return _value; } /** * Set the value of this constant. */ public void setValue(int value) { Object key = beforeModify(); _value = value; afterModify(key); } public Object getConstant() { return Numbers.valueOf(getValue()); } public void setConstant(Object value) { setValue(((Number) value).intValue()); } protected void readData(DataInput in) throws IOException { _value = in.readInt(); } protected void writeData(DataOutput out) throws IOException { out.writeInt(_value); } public void acceptVisit(BCVisitor visit) { visit.enterIntEntry(this); visit.exitIntEntry(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/FieldEntry.java0000755000000000000000000000123410460270415022342 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; /** * A reference to a class field. * * @author Abe White */ public class FieldEntry extends ComplexEntry { /** * Default constructor. */ public FieldEntry() { } /** * Constructor. * * @see ComplexEntry#ComplexEntry(int,int) */ public FieldEntry(int classIndex, int nameAndTypeIndex) { super(classIndex, nameAndTypeIndex); } public int getType() { return Entry.FIELD; } public void acceptVisit(BCVisitor visit) { visit.enterFieldEntry(this); visit.exitFieldEntry(this); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/ConstantEntry.java0000755000000000000000000000071010460270415023106 0ustar package serp.bytecode.lowlevel; /** * Interface implemented by entries representing constant values. Allows * generic access the constant value regardless of type. * * @author Abe White */ public interface ConstantEntry { /** * Return the value of the constant held by this entry. */ public Object getConstant(); /** * Set the value of the constant held by this entry. */ public void setConstant(Object value); } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/LongEntry.java0000755000000000000000000000263210460270415022221 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; import serp.util.*; /** * A long constant in the constant pool. * * @author Abe White */ public class LongEntry extends Entry implements ConstantEntry { private long _value = 0L; /** * Default constructor. */ public LongEntry() { } /** * Constructor. * * @param value the constant long value of this entry */ public LongEntry(long value) { _value = value; } public boolean isWide() { return true; } public int getType() { return Entry.LONG; } /** * Return the value of the constant. */ public long getValue() { return _value; } /** * Set the value of the constant. */ public void setValue(long value) { Object key = beforeModify(); _value = value; afterModify(key); } public Object getConstant() { return Numbers.valueOf(getValue()); } public void setConstant(Object value) { setValue(((Number) value).longValue()); } public void acceptVisit(BCVisitor visit) { visit.enterLongEntry(this); visit.exitLongEntry(this); } void readData(DataInput in) throws IOException { _value = in.readLong(); } void writeData(DataOutput out) throws IOException { out.writeLong(_value); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/ComplexEntry.java0000755000000000000000000000533210460270415022731 0ustar package serp.bytecode.lowlevel; import java.io.*; /** * Base class for field, method, and interface method constant pool * entries. All complex entries reference the {@link ClassEntry} of the * class that owns the entity and a {@link NameAndTypeEntry} describing * the entity. * * @author Abe White */ public abstract class ComplexEntry extends Entry { private int _classIndex = 0; private int _nameAndTypeIndex = 0; /** * Default constructor. */ public ComplexEntry() { } /** * Constructor. * * @param classIndex the constant pool index of the * {@link ClassEntry} describing the owner of this entity * @param nameAndTypeIndex the constant pool index of the * {@link NameAndTypeEntry} describing this entity */ public ComplexEntry(int classIndex, int nameAndTypeIndex) { _classIndex = classIndex; _nameAndTypeIndex = nameAndTypeIndex; } /** * Return the constant pool index of the {@link ClassEntry} describing * the owning class of this entity. Defaults to 0. */ public int getClassIndex() { return _classIndex; } /** * Set the constant pool index of the {@link ClassEntry} describing * the owning class of this entity. */ public void setClassIndex(int classIndex) { Object key = beforeModify(); _classIndex = classIndex; afterModify(key); } /** * Return the referenced {@link ClassEntry}. This method can only * be run for entries that have been added to a constant pool. */ public ClassEntry getClassEntry() { return (ClassEntry) getPool().getEntry(_classIndex); } /** * Return the constant pool index of the {@link NameAndTypeEntry} * describing this entity. */ public int getNameAndTypeIndex() { return _nameAndTypeIndex; } /** * Set the constant pool index of the {@link NameAndTypeEntry} * describing this entity. */ public void setNameAndTypeIndex(int nameAndTypeIndex) { Object key = beforeModify(); _nameAndTypeIndex = nameAndTypeIndex; afterModify(key); } /** * Return the referenced {@link NameAndTypeEntry}. This method can only * be run for entries that have been added to a constant pool. */ public NameAndTypeEntry getNameAndTypeEntry() { return (NameAndTypeEntry) getPool().getEntry(_nameAndTypeIndex); } void readData(DataInput in) throws IOException { _classIndex = in.readUnsignedShort(); _nameAndTypeIndex = in.readUnsignedShort(); } void writeData(DataOutput out) throws IOException { out.writeShort(_classIndex); out.writeShort(_nameAndTypeIndex); } } serp-1.14.1.orig/src/main/java/serp/bytecode/lowlevel/FloatEntry.java0000755000000000000000000000253710460270415022373 0ustar package serp.bytecode.lowlevel; import java.io.*; import serp.bytecode.visitor.*; /** * A constant float value in the constant pool. * * @author Abe White */ public class FloatEntry extends Entry implements ConstantEntry { private float _value = 0.0F; /** * Default constructor. */ public FloatEntry() { } /** * Constructor. * * @param value the constant float value of this entry */ public FloatEntry(float value) { _value = value; } public int getType() { return Entry.FLOAT; } /** * Return the value of this constant. */ public float getValue() { return _value; } /** * Set the value of this constant. */ public void setValue(float value) { Object key = beforeModify(); _value = value; afterModify(key); } public Object getConstant() { return new Float(getValue()); } public void setConstant(Object value) { setValue(((Number) value).floatValue()); } public void acceptVisit(BCVisitor visit) { visit.enterFloatEntry(this); visit.exitFloatEntry(this); } void readData(DataInput in) throws IOException { _value = in.readFloat(); } void writeData(DataOutput out) throws IOException { out.writeFloat(_value); } } serp-1.14.1.orig/src/main/java/serp/util/0000755000000000000000000000000011401260237014752 5ustar serp-1.14.1.orig/src/main/java/serp/util/Strings.java0000755000000000000000000002501010460270415017252 0ustar package serp.util; import java.math.*; import java.util.*; /** * String utiltity methods. * * @author Abe White */ public class Strings { private static final Object[][] _codes = new Object[][] { { byte.class, "byte", "B" }, { char.class, "char", "C" }, { double.class, "double", "D" }, { float.class, "float", "F" }, { int.class, "int", "I" }, { long.class, "long", "J" }, { short.class, "short", "S" }, { boolean.class, "boolean", "Z" }, { void.class, "void", "V" } }; /** * Replace all instances of from in str * with to. * * @param str the candidate string to replace * @param from the token to replace * @param to the new token * @return the string with all the replacements made */ public static String replace(String str, String from, String to) { String[] split = split(str, from, Integer.MAX_VALUE); return join(split, to); } /** * Splits the given string on the given token. Follows the semantics * of the Java 1.4 {@link String#split(String,int)} method, but does * not treat the given token as a regular expression. */ public static String[] split(String str, String token, int max) { if (str == null || str.length() == 0) return new String[0]; if (token == null || token.length() == 0) throw new IllegalArgumentException("token: [" + token + "]"); // split on token LinkedList ret = new LinkedList(); int start = 0; for (int split = 0; split != -1;) { split = str.indexOf(token, start); if (split == -1 && start >= str.length()) ret.add(""); else if (split == -1) ret.add(str.substring(start)); else { ret.add(str.substring(start, split)); start = split + token.length(); } } // now take max into account; this isn't the most efficient way // of doing things since we split the maximum number of times // regardless of the given parameters, but it makes things easy if (max == 0) { // discard any trailing empty splits while (ret.getLast().equals("")) ret.removeLast(); } else if (max > 0 && ret.size() > max) { // move all splits over max into the last split StringBuffer buf = new StringBuffer(ret.removeLast().toString()); while (ret.size() >= max) { buf.insert(0, token); buf.insert(0, ret.removeLast()); } ret.add(buf.toString()); } return (String[]) ret.toArray(new String[ret.size()]); } /** * Joins the given strings, placing the given token between them. */ public static String join(Object[] strings, String token) { if (strings == null) return null; StringBuffer buf = new StringBuffer(20 * strings.length); for (int i = 0; i < strings.length; i++) { if (i > 0) buf.append(token); if (strings[i] != null) buf.append(strings[i]); } return buf.toString(); } /** * Return the class for the given string, correctly handling * primitive types. If the given class loader is null, the context * loader of the current thread will be used. * * @throws RuntimeException on load error */ public static Class toClass(String str, ClassLoader loader) { return toClass(str, false, loader); } /** * Return the class for the given string, correctly handling * primitive types. If the given class loader is null, the context * loader of the current thread will be used. * * @throws RuntimeException on load error */ public static Class toClass(String str, boolean resolve, ClassLoader loader) { if (str == null) throw new NullPointerException("str == null"); // array handling int dims = 0; while (str.endsWith("[]")) { dims++; str = str.substring(0, str.length() - 2); } // check against primitive types boolean primitive = false; if (str.indexOf('.') == -1) { for (int i = 0; !primitive && (i < _codes.length); i++) { if (_codes[i][1].equals(str)) { if (dims == 0) return (Class) _codes[i][0]; str = (String) _codes[i][2]; primitive = true; } } } if (dims > 0) { int size = str.length() + dims; if (!primitive) size += 2; StringBuffer buf = new StringBuffer(size); for (int i = 0; i < dims; i++) buf.append('['); if (!primitive) buf.append('L'); buf.append(str); if (!primitive) buf.append(';'); str = buf.toString(); } if (loader == null) loader = Thread.currentThread().getContextClassLoader(); try { return Class.forName(str, resolve, loader); } catch (Throwable t) { throw new IllegalArgumentException(t.toString()); } } /** * Return only the class name, without package. */ public static String getClassName(Class cls) { return (cls == null) ? null : getClassName(cls.getName()); } /** * Return only the class name. */ public static String getClassName(String fullName) { if (fullName == null) return null; // special case for arrays int dims = 0; for (int i = 0; i < fullName.length(); i++) { if (fullName.charAt(i) != '[') { dims = i; break; } } if (dims > 0) fullName = fullName.substring(dims); // check for primitives for (int i = 0; i < _codes.length; i++) { if (_codes[i][2].equals(fullName)) { fullName = (String) _codes[i][1]; break; } } fullName = fullName.substring(fullName.lastIndexOf('.') + 1); for (int i = 0; i < dims; i++) fullName = fullName + "[]"; return fullName; } /** * Return only the package, or empty string if none. */ public static String getPackageName(Class cls) { return (cls == null) ? null : getPackageName(cls.getName()); } /** * Return only the package, or empty string if none. */ public static String getPackageName(String fullName) { if (fullName == null) return null; int dotIdx = fullName.lastIndexOf('.'); return (dotIdx == -1) ? "" : fullName.substring(0, dotIdx); } /** * Return val as the type specified by * type. If type is a primitive, the * primitive wrapper type is created and returned, and * nulls are converted to the Java default for the * primitive type. * * @param val The string value to parse * @param type The type to parse. This must be a primitive or a * primitive wrapper, or one of {@link BigDecimal}, * {@link BigInteger}, {@link String}, {@link Date}. * @throws IllegalArgumentException if type is not a * supported type, or if val cannot be * converted into an instance of type type. */ public static Object parse(String val, Class type) { if (!canParse(type)) throw new IllegalArgumentException("invalid type: " + type.getName()); // deal with null value if (val == null) { if (!type.isPrimitive()) return null; if (type == boolean.class) return Boolean.FALSE; if (type == byte.class) return new Byte((byte) 0); if (type == char.class) return new Character((char) 0); if (type == double.class) return new Double(0); if (type == float.class) return new Float(0); if (type == int.class) return Numbers.valueOf(0); if (type == long.class) return Numbers.valueOf(0L); if (type == short.class) return new Short((short) 0); throw new IllegalStateException("invalid type: " + type); } // deal with non-null value if (type == boolean.class || type == Boolean.class) return Boolean.valueOf(val); if (type == byte.class || type == Byte.class) return Byte.valueOf(val); if (type == char.class || type == Character.class) { if (val.length() == 0) return new Character((char) 0); if (val.length() == 1) return new Character(val.charAt(0)); throw new IllegalArgumentException("'" + val + "' is longer than " + "one character."); } if (type == double.class || type == Double.class) return Double.valueOf(val); if (type == float.class || type == Float.class) return Float.valueOf(val); if (type == int.class || type == Integer.class) return Integer.valueOf(val); if (type == long.class || type == Long.class) return Long.valueOf(val); if (type == short.class || type == Short.class) return Short.valueOf(val); if (type == String.class) return val; if (type == Date.class) return new Date(val); if (type == BigInteger.class) return new BigInteger(val); if (type == BigDecimal.class) return new BigDecimal(val); throw new IllegalArgumentException("Invalid type: " + type); } /** * Whether the given type is parsable via {@link #parse}. */ public static boolean canParse(Class type) { return type.isPrimitive() || type == Boolean.class || type == Byte.class || type == Character.class || type == Short.class || type == Integer.class || type == Long.class || type == Float.class || type == Double.class || type == String.class || type == Date.class || type == BigInteger.class || type == BigDecimal.class; } } serp-1.14.1.orig/src/main/java/serp/util/package.html0000755000000000000000000000016310455026340017241 0ustar

Utilties

Utilities used by bytecode libraries.

serp-1.14.1.orig/src/main/java/serp/util/Numbers.java0000755000000000000000000000222110460270415017233 0ustar package serp.util; /** * Number utilities. * * @author Abe White */ public class Numbers { private static final Integer INT_NEGONE = new Integer(-1); private static final Long LONG_NEGONE = new Long(-1); private static final Integer[] INTEGERS = new Integer[50]; private static final Long[] LONGS = new Long[50]; static { for (int i = 0; i < INTEGERS.length; i++) INTEGERS[i] = new Integer(i); for (int i = 0; i < LONGS.length; i++) LONGS[i] = new Long(i); } /** * Return the wrapper for the given number, taking advantage of cached * common values. */ public static Integer valueOf(int n) { if (n == -1) return INT_NEGONE; if (n >= 0 && n < INTEGERS.length) return INTEGERS[n]; return new Integer(n); } /** * Return the wrapper for the given number, taking advantage of cached * common values. */ public static Long valueOf(long n) { if (n == -1) return LONG_NEGONE; if (n >= 0 && n < LONGS.length) return LONGS[(int) n]; return new Long(n); } } serp-1.14.1.orig/pom.xml0000644000000000000000000001053510677227260011726 0ustar 4.0.0 net.sourceforge.serp serp jar Serp 1.14.1 Serp is an open source framework for manipulating Java bytecode. http://serp.sourceforge.net sourceforge http://sourceforge.net/tracker/?group_id=31479&atid=402282 2002 abewhite Abe White awhite@bea.com Marc Prud'hommeaux mwp1@cornell.edu BSD LICENSE.txt scm:cvs:pserver:anonymous@serp.cvs.sourceforge.net:/cvsroot/serp:serp/serp scm:cvs:ext:${maven.username}@serp.cvs.sourceforge.net:/cvsroot/serp:serp/serp http://serp.cvs.sourceforge.net/serp/serp junit junit 3.8.1 compile maven-surefire-plugin true maven-compiler-plugin 1.3 1.3 maven-site-plugin ../site-staging maven-assembly-plugin bin serp-${pom.version} serp http://serp.sourceforge.net/m2repo org.codehaus.mojo jxr-maven-plugin true org.apache.maven.plugins maven-javadoc-plugin true true http://java.sun.com/j2se/1.5.0/docs/api maven-pmd-plugin maven-project-info-reports-plugin org.codehaus.mojo surefire-report-maven-plugin serp scp://shell.sourceforge.net/home/groups/s/se/serp/htdocs/m2repo serp serp scpexe://shell.sourceforge.net/home/groups/s/se/serp/htdocs/site/