From 5540c815de36e316d0749ce2163f12c61895b327 Mon Sep 17 00:00:00 2001 From: asiekierka Date: Wed, 17 Aug 2016 18:35:12 +0200 Subject: Revert "Removed unused methods" This reverts commit 1742190f784d0d62e7cc869eebafdfe1927e448f. --- .../cuchaz/enigma/bytecode/CheckCastIterator.java | 117 ++++++++++++++++++++ .../java/cuchaz/enigma/bytecode/ClassRenamer.java | 10 ++ .../cuchaz/enigma/bytecode/ConstPoolEditor.java | 122 +++++++++++++++++++++ .../bytecode/accessors/ClassInfoAccessor.java | 4 + .../bytecode/accessors/ConstInfoAccessor.java | 42 +++++++ .../accessors/InvokeDynamicInfoAccessor.java | 4 + .../bytecode/accessors/MemberRefInfoAccessor.java | 4 + .../accessors/MethodHandleInfoAccessor.java | 4 + .../bytecode/accessors/MethodTypeInfoAccessor.java | 4 + .../accessors/NameAndTypeInfoAccessor.java | 4 + .../bytecode/accessors/StringInfoAccessor.java | 4 + .../bytecode/accessors/Utf8InfoAccessor.java | 28 +++++ 12 files changed, 347 insertions(+) create mode 100644 src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java create mode 100644 src/main/java/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java (limited to 'src/main/java/cuchaz/enigma/bytecode') diff --git a/src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java b/src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java new file mode 100644 index 0000000..19c39d3 --- /dev/null +++ b/src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2015 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html + *

+ * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.bytecode; + +import java.util.Iterator; + +import cuchaz.enigma.bytecode.CheckCastIterator.CheckCast; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.MethodEntry; +import cuchaz.enigma.mapping.Signature; +import javassist.bytecode.*; + +public class CheckCastIterator implements Iterator { + + public static class CheckCast { + + public String className; + public MethodEntry prevMethodEntry; + + public CheckCast(String className, MethodEntry prevMethodEntry) { + this.className = className; + this.prevMethodEntry = prevMethodEntry; + } + } + + private ConstPool constants; + private CodeAttribute attribute; + private CodeIterator iter; + private CheckCast next; + + public CheckCastIterator(CodeAttribute codeAttribute) throws BadBytecode { + this.constants = codeAttribute.getConstPool(); + this.attribute = codeAttribute; + this.iter = this.attribute.iterator(); + + this.next = getNext(); + } + + @Override + public boolean hasNext() { + return this.next != null; + } + + @Override + public CheckCast next() { + CheckCast out = this.next; + try { + this.next = getNext(); + } catch (BadBytecode ex) { + throw new Error(ex); + } + return out; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + private CheckCast getNext() throws BadBytecode { + int prevPos = 0; + while (this.iter.hasNext()) { + int pos = this.iter.next(); + int opcode = this.iter.byteAt(pos); + switch (opcode) { + case Opcode.CHECKCAST: + + // get the type of this op code (next two bytes are a classinfo index) + MethodEntry prevMethodEntry = getMethodEntry(prevPos); + if (prevMethodEntry != null) { + return new CheckCast(this.constants.getClassInfo(this.iter.s16bitAt(pos + 1)), prevMethodEntry); + } + break; + } + prevPos = pos; + } + return null; + } + + private MethodEntry getMethodEntry(int pos) { + switch (this.iter.byteAt(pos)) { + case Opcode.INVOKEVIRTUAL: + case Opcode.INVOKESTATIC: + case Opcode.INVOKEDYNAMIC: + case Opcode.INVOKESPECIAL: { + int index = this.iter.s16bitAt(pos + 1); + return new MethodEntry( + new ClassEntry(Descriptor.toJvmName(this.constants.getMethodrefClassName(index))), + this.constants.getMethodrefName(index), + new Signature(this.constants.getMethodrefType(index)) + ); + } + + case Opcode.INVOKEINTERFACE: { + int index = this.iter.s16bitAt(pos + 1); + return new MethodEntry( + new ClassEntry(Descriptor.toJvmName(this.constants.getInterfaceMethodrefClassName(index))), + this.constants.getInterfaceMethodrefName(index), + new Signature(this.constants.getInterfaceMethodrefType(index)) + ); + } + } + return null; + } + + public Iterable casts() { + return () -> CheckCastIterator.this; + } +} diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java index 4a77eec..c13aae4 100644 --- a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java @@ -90,6 +90,16 @@ public class ClassRenamer { }); } + public static void moveAllClassesIntoDefaultPackage(CtClass c, final String oldPackageName) { + renameClasses(c, className -> { + ClassEntry entry = new ClassEntry(className); + if (entry.getPackageName().equals(oldPackageName)) { + return entry.getSimpleName(); + } + return null; + }); + } + @SuppressWarnings("unchecked") public static void renameClasses(CtClass c, ClassNameReplacer replacer) { diff --git a/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java b/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java index af8c79a..256df61 100644 --- a/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java +++ b/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java @@ -17,6 +17,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; +import cuchaz.enigma.bytecode.accessors.ClassInfoAccessor; import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor; import javassist.bytecode.ConstPool; @@ -77,6 +78,22 @@ public class ConstPoolEditor { this.pool = pool; } + public void writePool(DataOutputStream out) { + try { + methodWritePool.invoke(this.pool, out); + } catch (Exception ex) { + throw new Error(ex); + } + } + + public static ConstPool readPool(DataInputStream in) { + try { + return constructorPool.newInstance(in); + } catch (Exception ex) { + throw new Error(ex); + } + } + public String getMemberrefClassname(int memberrefIndex) { return Descriptor.toJvmName(this.pool.getClassInfo(this.pool.getMemberClass(memberrefIndex))); } @@ -101,6 +118,48 @@ public class ConstPoolEditor { } } + public int addItem(Object item) { + try { + return (Integer) addItem.invoke(this.pool, item); + } catch (Exception ex) { + throw new Error(ex); + } + } + + public int addItemForceNew(Object item) { + try { + return (Integer) addItem0.invoke(this.pool, item); + } catch (Exception ex) { + throw new Error(ex); + } + } + + @SuppressWarnings("rawtypes") + public void removeLastItem() { + try { + // remove the item from the cache + HashMap cache = getCache(); + if (cache != null) { + Object item = getItem(this.pool.getSize() - 1); + cache.remove(item); + } + + // remove the actual item + // based off of LongVector.addElement() + Object item = items.get(this.pool); + Object[][] object = (Object[][]) objects.get(items); + int numElements = (Integer) elements.get(items) - 1; + int nth = numElements >> 7; + int offset = numElements & (128 - 1); + object[nth][offset] = null; + + // decrement the number of items + elements.set(item, numElements); + numItems.set(this.pool, (Integer) numItems.get(this.pool) - 1); + } catch (Exception ex) { + throw new Error(ex); + } + } @SuppressWarnings("rawtypes") public HashMap getCache() { @@ -138,4 +197,67 @@ public class ConstPoolEditor { assert (newName.equals(getMemberrefName(memberrefIndex))); assert (newType.equals(getMemberrefType(memberrefIndex))); } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public void changeClassName(int classNameIndex, String newName) { + // NOTE: when changing values, we always need to copy-on-write + try { + // get the class item + Object item = getItem(classNameIndex).getItem(); + + // update the cache + HashMap cache = getCache(); + if (cache != null) { + cache.remove(item); + } + + // add the new name and repoint the name-and-type to it + new ClassInfoAccessor(item).setNameIndex(this.pool.addUtf8Info(newName)); + + // update the cache + if (cache != null) { + cache.put(item, item); + } + } catch (Exception ex) { + throw new Error(ex); + } + } + + public static ConstPool newConstPool() { + // const pool expects the name of a class to initialize itself + // but we want an empty pool + // so give it a bogus name, and then clear the entries afterwards + ConstPool pool = new ConstPool("a"); + + ConstPoolEditor editor = new ConstPoolEditor(pool); + int size = pool.getSize(); + for (int i = 0; i < size - 1; i++) { + editor.removeLastItem(); + } + + // make sure the pool is actually empty + // although, in this case "empty" means one thing in it + // the JVM spec says index 0 should be reserved + assert (pool.getSize() == 1); + assert (editor.getItem(0) == null); + assert (editor.getItem(1) == null); + assert (editor.getItem(2) == null); + assert (editor.getItem(3) == null); + + // also, clear the cache + editor.getCache().clear(); + + return pool; + } + + public String dump() { + StringBuilder buf = new StringBuilder(); + for (int i = 1; i < this.pool.getSize(); i++) { + buf.append(String.format("%4d", i)); + buf.append(" "); + buf.append(getItem(i).toString()); + buf.append("\n"); + } + return buf.toString(); + } } diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java index 316bb5e..66f2283 100644 --- a/src/main/java/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java @@ -39,6 +39,10 @@ public class ClassInfoAccessor { } } + public static boolean isType(ConstInfoAccessor accessor) { + return clazz.isAssignableFrom(accessor.getItem().getClass()); + } + static { try { clazz = Class.forName("javassist.bytecode.ClassInfo"); diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java index 474a3ef..bc7af87 100644 --- a/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java @@ -10,8 +10,12 @@ ******************************************************************************/ package cuchaz.enigma.bytecode.accessors; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.lang.reflect.Field; @@ -55,6 +59,44 @@ public class ConstInfoAccessor { } } + public ConstInfoAccessor copy() { + return new ConstInfoAccessor(copyItem()); + } + + public Object copyItem() { + // I don't know of a simpler way to copy one of these silly things... + try { + // serialize the item + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(buf); + write(out); + + // deserialize the item + DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf.toByteArray())); + Object item = new ConstInfoAccessor(in).getItem(); + in.close(); + + return item; + } catch (Exception ex) { + throw new Error(ex); + } + } + + public void write(DataOutputStream out) throws IOException { + try { + out.writeUTF(this.item.getClass().getName()); + out.writeInt(getIndex()); + + Method method = this.item.getClass().getMethod("write", DataOutputStream.class); + method.setAccessible(true); + method.invoke(this.item, out); + } catch (IOException ex) { + throw ex; + } catch (Exception ex) { + throw new Error(ex); + } + } + @Override public String toString() { try { diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java index a158394..69aee16 100644 --- a/src/main/java/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java @@ -57,6 +57,10 @@ public class InvokeDynamicInfoAccessor { } } + public static boolean isType(ConstInfoAccessor accessor) { + return clazz.isAssignableFrom(accessor.getItem().getClass()); + } + static { try { clazz = Class.forName("javassist.bytecode.InvokeDynamicInfo"); diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java index 2835508..0e0297b 100644 --- a/src/main/java/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java @@ -56,6 +56,10 @@ public class MemberRefInfoAccessor { } } + public static boolean isType(ConstInfoAccessor accessor) { + return clazz.isAssignableFrom(accessor.getItem().getClass()); + } + static { try { clazz = Class.forName("javassist.bytecode.MemberrefInfo"); diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java index a203b43..9a7dd69 100644 --- a/src/main/java/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java @@ -56,6 +56,10 @@ public class MethodHandleInfoAccessor { } } + public static boolean isType(ConstInfoAccessor accessor) { + return clazz.isAssignableFrom(accessor.getItem().getClass()); + } + static { try { clazz = Class.forName("javassist.bytecode.MethodHandleInfo"); diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java index 993c79b..5ec9c3b 100644 --- a/src/main/java/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java @@ -39,6 +39,10 @@ public class MethodTypeInfoAccessor { } } + public static boolean isType(ConstInfoAccessor accessor) { + return clazz.isAssignableFrom(accessor.getItem().getClass()); + } + static { try { clazz = Class.forName("javassist.bytecode.MethodTypeInfo"); diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java index d6c2531..95df37c 100644 --- a/src/main/java/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java @@ -56,6 +56,10 @@ public class NameAndTypeInfoAccessor { } } + public static boolean isType(ConstInfoAccessor accessor) { + return clazz.isAssignableFrom(accessor.getItem().getClass()); + } + static { try { clazz = Class.forName("javassist.bytecode.NameAndTypeInfo"); diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java index e211381..1c55a44 100644 --- a/src/main/java/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java @@ -39,6 +39,10 @@ public class StringInfoAccessor { } } + public static boolean isType(ConstInfoAccessor accessor) { + return clazz.isAssignableFrom(accessor.getItem().getClass()); + } + static { try { clazz = Class.forName("javassist.bytecode.StringInfo"); diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java new file mode 100644 index 0000000..7a2cb66 --- /dev/null +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2015 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html + *

+ * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.bytecode.accessors; + +public class Utf8InfoAccessor { + + private static Class clazz; + + static { + try { + clazz = Class.forName("javassist.bytecode.Utf8Info"); + } catch (Exception ex) { + throw new Error(ex); + } + } + + public static boolean isType(ConstInfoAccessor accessor) { + return clazz.isAssignableFrom(accessor.getItem().getClass()); + } +} -- cgit v1.2.3