All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.rapidark.framework.thirdparty.asm.ClassWriter Maven / Gradle / Ivy

The newest version!
package com.github.rapidark.framework.thirdparty.asm;

public class ClassWriter extends ClassVisitor {
	public static final int COMPUTE_MAXS = 1;
	public static final int COMPUTE_FRAMES = 2;
	static final int TYPE_UNINIT = 31;
	Item[] typeTable;
	FieldWriter firstField;
	FieldWriter lastField;
	MethodWriter firstMethod;
	MethodWriter lastMethod;
	boolean invalidFrames;
	static final int ACC_SYNTHETIC_ATTRIBUTE = 262144;
	static final int TO_ACC_SYNTHETIC = 64;
	static final int NOARG_INSN = 0;
	static final int SBYTE_INSN = 1;
	static final int SHORT_INSN = 2;
	static final int VAR_INSN = 3;
	static final int IMPLVAR_INSN = 4;
	static final int TYPE_INSN = 5;
	static final int FIELDORMETH_INSN = 6;
	static final int ITFMETH_INSN = 7;
	static final int INDYMETH_INSN = 8;
	static final int LABEL_INSN = 9;
	static final int LABELW_INSN = 10;
	static final int LDC_INSN = 11;
	static final int LDCW_INSN = 12;
	static final int IINC_INSN = 13;
	static final int TABL_INSN = 14;
	static final int LOOK_INSN = 15;
	static final int MANA_INSN = 16;
	static final int WIDE_INSN = 17;
	static final byte[] TYPE;
	static final int CLASS = 7;
	static final int FIELD = 9;
	static final int METH = 10;
	static final int IMETH = 11;
	static final int STR = 8;
	static final int INT = 3;
	static final int FLOAT = 4;
	static final int LONG = 5;
	static final int DOUBLE = 6;
	static final int NAME_TYPE = 12;
	static final int UTF8 = 1;
	static final int MTYPE = 16;
	static final int HANDLE = 15;
	static final int INDY = 18;
	static final int HANDLE_BASE = 20;
	static final int TYPE_NORMAL = 30;
	static final int TYPE_MERGED = 32;
	static final int BSM = 33;
	ClassReader cr;
	int version;
	int index;
	final ByteVector pool;
	Item[] items;
	int threshold;
	final Item key;
	final Item key2;
	final Item key3;
	final Item key4;
	private short typeCount;
	private int access;
	private int name;
	String thisName;
	private int signature;
	private int superName;
	private int interfaceCount;
	private int[] interfaces;
	private int sourceFile;
	private ByteVector sourceDebug;
	private int enclosingMethodOwner;
	private int enclosingMethod;
	private AnnotationWriter anns;
	private AnnotationWriter ianns;
	private Attribute attrs;
	private int innerClassesCount;
	private ByteVector innerClasses;
	int bootstrapMethodsCount;
	ByteVector bootstrapMethods;
	private final boolean computeMaxs;
	private final boolean computeFrames;

	static {
		byte[] b = new byte['Ü'];
		String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAAAAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ";
		for (int i = 0; i < b.length; i++) {
			b[i] = ((byte) (s.charAt(i) - 'A'));
		}
		TYPE = b;
	}

	public ClassWriter(int flags) {
		super(262144);
		this.index = 1;
		this.pool = new ByteVector();
		this.items = new Item['Ā'];
		this.threshold = ((int) (0.75D * this.items.length));
		this.key = new Item();
		this.key2 = new Item();
		this.key3 = new Item();
		this.key4 = new Item();
		this.computeMaxs = ((flags & 0x1) != 0);
		this.computeFrames = ((flags & 0x2) != 0);
	}

	public ClassWriter(ClassReader classReader, int flags) {
		this(flags);
		classReader.copyPool(this);
		this.cr = classReader;
	}

	public final void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
		this.version = version;
		this.access = access;
		this.name = newClass(name);
		this.thisName = name;
		if (signature != null) {
			this.signature = newUTF8(signature);
		}
		this.superName = (superName == null ? 0 : newClass(superName));
		if ((interfaces != null) && (interfaces.length > 0)) {
			this.interfaceCount = interfaces.length;
			this.interfaces = new int[this.interfaceCount];
			for (int i = 0; i < this.interfaceCount; i++) {
				this.interfaces[i] = newClass(interfaces[i]);
			}
		}
	}

	public final void visitSource(String file, String debug) {
		if (file != null) {
			this.sourceFile = newUTF8(file);
		}
		if (debug != null) {
			this.sourceDebug = new ByteVector().putUTF8(debug);
		}
	}

	public final void visitOuterClass(String owner, String name, String desc) {
		this.enclosingMethodOwner = newClass(owner);
		if ((name != null) && (desc != null)) {
			this.enclosingMethod = newNameType(name, desc);
		}
	}

	public final AnnotationVisitor visitAnnotation(String desc, boolean visible) {
		ByteVector bv = new ByteVector();

		bv.putShort(newUTF8(desc)).putShort(0);
		AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2);
		if (visible) {
			aw.next = this.anns;
			this.anns = aw;
		} else {
			aw.next = this.ianns;
			this.ianns = aw;
		}
		return aw;
	}

	public final void visitAttribute(Attribute attr) {
		attr.next = this.attrs;
		this.attrs = attr;
	}

	public final void visitInnerClass(String name, String outerName, String innerName, int access) {
		if (this.innerClasses == null) {
			this.innerClasses = new ByteVector();
		}
		this.innerClassesCount += 1;
		this.innerClasses.putShort(name == null ? 0 : newClass(name));
		this.innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
		this.innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
		this.innerClasses.putShort(access);
	}

	public final FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
		return new FieldWriter(this, access, name, desc, signature, value);
	}

	public final MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
		return new MethodWriter(this, access, name, desc, signature, exceptions, this.computeMaxs, this.computeFrames);
	}

	public final void visitEnd() {
	}

	public byte[] toByteArray() {
		if (this.index > 65535) {
			throw new RuntimeException("Class file too large!");
		}
		int size = 24 + 2 * this.interfaceCount;
		int nbFields = 0;
		FieldWriter fb = this.firstField;
		while (fb != null) {
			nbFields++;
			size += fb.getSize();
			fb = (FieldWriter) fb.fv;
		}
		int nbMethods = 0;
		MethodWriter mb = this.firstMethod;
		while (mb != null) {
			nbMethods++;
			size += mb.getSize();
			mb = (MethodWriter) mb.mv;
		}
		int attributeCount = 0;
		if (this.bootstrapMethods != null) {
			attributeCount++;
			size += 8 + this.bootstrapMethods.length;
			newUTF8("BootstrapMethods");
		}
		if (this.signature != 0) {
			attributeCount++;
			size += 8;
			newUTF8("Signature");
		}
		if (this.sourceFile != 0) {
			attributeCount++;
			size += 8;
			newUTF8("SourceFile");
		}
		if (this.sourceDebug != null) {
			attributeCount++;
			size += this.sourceDebug.length + 4;
			newUTF8("SourceDebugExtension");
		}
		if (this.enclosingMethodOwner != 0) {
			attributeCount++;
			size += 10;
			newUTF8("EnclosingMethod");
		}
		if ((this.access & 0x20000) != 0) {
			attributeCount++;
			size += 6;
			newUTF8("Deprecated");
		}
		if (((this.access & 0x1000) != 0) && (((this.version & 0xFFFF) < 49) || ((this.access & 0x40000) != 0))) {
			attributeCount++;
			size += 6;
			newUTF8("Synthetic");
		}
		if (this.innerClasses != null) {
			attributeCount++;
			size += 8 + this.innerClasses.length;
			newUTF8("InnerClasses");
		}
		if (this.anns != null) {
			attributeCount++;
			size += 8 + this.anns.getSize();
			newUTF8("RuntimeVisibleAnnotations");
		}
		if (this.ianns != null) {
			attributeCount++;
			size += 8 + this.ianns.getSize();
			newUTF8("RuntimeInvisibleAnnotations");
		}
		if (this.attrs != null) {
			attributeCount += this.attrs.getCount();
			size += this.attrs.getSize(this, null, 0, -1, -1);
		}
		size += this.pool.length;

		ByteVector out = new ByteVector(size);
		out.putInt(-889275714).putInt(this.version);
		out.putShort(this.index).putByteArray(this.pool.data, 0, this.pool.length);
		int mask = 0x60000 | (this.access & 0x40000) / 64;
		out.putShort(this.access & (mask ^ 0xFFFFFFFF)).putShort(this.name).putShort(this.superName);
		out.putShort(this.interfaceCount);
		for (int i = 0; i < this.interfaceCount; i++) {
			out.putShort(this.interfaces[i]);
		}
		out.putShort(nbFields);
		fb = this.firstField;
		while (fb != null) {
			fb.put(out);
			fb = (FieldWriter) fb.fv;
		}
		out.putShort(nbMethods);
		mb = this.firstMethod;
		while (mb != null) {
			mb.put(out);
			mb = (MethodWriter) mb.mv;
		}
		out.putShort(attributeCount);
		if (this.bootstrapMethods != null) {
			out.putShort(newUTF8("BootstrapMethods"));
			out.putInt(this.bootstrapMethods.length + 2).putShort(this.bootstrapMethodsCount);
			out.putByteArray(this.bootstrapMethods.data, 0, this.bootstrapMethods.length);
		}
		if (this.signature != 0) {
			out.putShort(newUTF8("Signature")).putInt(2).putShort(this.signature);
		}
		if (this.sourceFile != 0) {
			out.putShort(newUTF8("SourceFile")).putInt(2).putShort(this.sourceFile);
		}
		if (this.sourceDebug != null) {
			int len = this.sourceDebug.length - 2;
			out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
			out.putByteArray(this.sourceDebug.data, 2, len);
		}
		if (this.enclosingMethodOwner != 0) {
			out.putShort(newUTF8("EnclosingMethod")).putInt(4);
			out.putShort(this.enclosingMethodOwner).putShort(this.enclosingMethod);
		}
		if ((this.access & 0x20000) != 0) {
			out.putShort(newUTF8("Deprecated")).putInt(0);
		}
		if (((this.access & 0x1000) != 0) && (((this.version & 0xFFFF) < 49) || ((this.access & 0x40000) != 0))) {
			out.putShort(newUTF8("Synthetic")).putInt(0);
		}
		if (this.innerClasses != null) {
			out.putShort(newUTF8("InnerClasses"));
			out.putInt(this.innerClasses.length + 2).putShort(this.innerClassesCount);
			out.putByteArray(this.innerClasses.data, 0, this.innerClasses.length);
		}
		if (this.anns != null) {
			out.putShort(newUTF8("RuntimeVisibleAnnotations"));
			this.anns.put(out);
		}
		if (this.ianns != null) {
			out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
			this.ianns.put(out);
		}
		if (this.attrs != null) {
			this.attrs.put(this, null, 0, -1, -1, out);
		}
		if (this.invalidFrames) {
			ClassWriter cw = new ClassWriter(2);
			new ClassReader(out.data).accept(cw, 4);
			return cw.toByteArray();
		}
		return out.data;
	}

	Item newConstItem(Object cst) {
		if ((cst instanceof Integer)) {
			int val = ((Integer) cst).intValue();
			return newInteger(val);
		}
		if ((cst instanceof Byte)) {
			int val = ((Byte) cst).intValue();
			return newInteger(val);
		}
		if ((cst instanceof Character)) {
			int val = ((Character) cst).charValue();
			return newInteger(val);
		}
		if ((cst instanceof Short)) {
			int val = ((Short) cst).intValue();
			return newInteger(val);
		}
		if ((cst instanceof Boolean)) {
			int val = ((Boolean) cst).booleanValue() ? 1 : 0;
			return newInteger(val);
		}
		if ((cst instanceof Float)) {
			float val = ((Float) cst).floatValue();
			return newFloat(val);
		}
		if ((cst instanceof Long)) {
			long val = ((Long) cst).longValue();
			return newLong(val);
		}
		if ((cst instanceof Double)) {
			double val = ((Double) cst).doubleValue();
			return newDouble(val);
		}
		if ((cst instanceof String)) {
			return newString((String) cst);
		}
		if ((cst instanceof Type)) {
			Type t = (Type) cst;
			int s = t.getSort();
			if (s == 10) {
				return newClassItem(t.getInternalName());
			}
			if (s == 11) {
				return newMethodTypeItem(t.getDescriptor());
			}
			return newClassItem(t.getDescriptor());
		}
		if ((cst instanceof Handle)) {
			Handle h = (Handle) cst;
			return newHandleItem(h.tag, h.owner, h.name, h.desc);
		}
		throw new IllegalArgumentException("value " + cst);
	}

	public int newConst(Object cst) {
		return newConstItem(cst).index;
	}

	public int newUTF8(String value) {
		this.key.set(1, value, null, null);
		Item result = get(this.key);
		if (result == null) {
			this.pool.putByte(1).putUTF8(value);
			result = new Item(this.index++, this.key);
			put(result);
		}
		return result.index;
	}

	Item newClassItem(String value) {
		this.key2.set(7, value, null, null);
		Item result = get(this.key2);
		if (result == null) {
			this.pool.put12(7, newUTF8(value));
			result = new Item(this.index++, this.key2);
			put(result);
		}
		return result;
	}

	public int newClass(String value) {
		return newClassItem(value).index;
	}

	Item newMethodTypeItem(String methodDesc) {
		this.key2.set(16, methodDesc, null, null);
		Item result = get(this.key2);
		if (result == null) {
			this.pool.put12(16, newUTF8(methodDesc));
			result = new Item(this.index++, this.key2);
			put(result);
		}
		return result;
	}

	public int newMethodType(String methodDesc) {
		return newMethodTypeItem(methodDesc).index;
	}

	Item newHandleItem(int tag, String owner, String name, String desc) {
		this.key4.set(20 + tag, owner, name, desc);
		Item result = get(this.key4);
		if (result == null) {
			if (tag <= 4) {
				put112(15, tag, newField(owner, name, desc));
			} else {
				put112(15, tag, newMethod(owner, name, desc, tag == 9));
			}
			result = new Item(this.index++, this.key4);
			put(result);
		}
		return result;
	}

	public int newHandle(int tag, String owner, String name, String desc) {
		return newHandleItem(tag, owner, name, desc).index;
	}

	Item newInvokeDynamicItem(String name, String desc, Handle bsm, Object... bsmArgs) {
		ByteVector bootstrapMethods = this.bootstrapMethods;
		if (bootstrapMethods == null) {
			bootstrapMethods = this.bootstrapMethods = new ByteVector();
		}
		int position = bootstrapMethods.length;

		int hashCode = bsm.hashCode();
		bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, bsm.desc));

		int argsLength = bsmArgs.length;
		bootstrapMethods.putShort(argsLength);
		for (int i = 0; i < argsLength; i++) {
			Object bsmArg = bsmArgs[i];
			hashCode ^= bsmArg.hashCode();
			bootstrapMethods.putShort(newConst(bsmArg));
		}
		byte[] data = bootstrapMethods.data;
		int length = 2 + argsLength << 1;
		hashCode &= 0x7FFFFFFF;
		Item result = this.items[(hashCode % this.items.length)];
		while (result != null) {
			if ((result.type != 33) || (result.hashCode != hashCode)) {
				result = result.next;
			} else {
				int resultPosition = result.intVal;
				for (int p = 0; p < length; p++) {
					if (data[(position + p)] != data[(resultPosition + p)]) {
						result = result.next;
						break;
					}
				}
				break;
			}
		}
		int bootstrapMethodIndex;
		if (result != null) {
			bootstrapMethodIndex = result.index;
			bootstrapMethods.length = position;
		} else {
			bootstrapMethodIndex = this.bootstrapMethodsCount++;
			result = new Item(bootstrapMethodIndex);
			result.set(position, hashCode);
			put(result);
		}
		this.key3.set(name, desc, bootstrapMethodIndex);
		result = get(this.key3);
		if (result == null) {
			put122(18, bootstrapMethodIndex, newNameType(name, desc));
			result = new Item(this.index++, this.key3);
			put(result);
		}
		return result;
	}

	public int newInvokeDynamic(String name, String desc, Handle bsm, Object... bsmArgs) {
		return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index;
	}

	Item newFieldItem(String owner, String name, String desc) {
		this.key3.set(9, owner, name, desc);
		Item result = get(this.key3);
		if (result == null) {
			put122(9, newClass(owner), newNameType(name, desc));
			result = new Item(this.index++, this.key3);
			put(result);
		}
		return result;
	}

	public int newField(String owner, String name, String desc) {
		return newFieldItem(owner, name, desc).index;
	}

	Item newMethodItem(String owner, String name, String desc, boolean itf) {
		int type = itf ? 11 : 10;
		this.key3.set(type, owner, name, desc);
		Item result = get(this.key3);
		if (result == null) {
			put122(type, newClass(owner), newNameType(name, desc));
			result = new Item(this.index++, this.key3);
			put(result);
		}
		return result;
	}

	public int newMethod(String owner, String name, String desc, boolean itf) {
		return newMethodItem(owner, name, desc, itf).index;
	}

	Item newInteger(int value) {
		this.key.set(value);
		Item result = get(this.key);
		if (result == null) {
			this.pool.putByte(3).putInt(value);
			result = new Item(this.index++, this.key);
			put(result);
		}
		return result;
	}

	Item newFloat(float value) {
		this.key.set(value);
		Item result = get(this.key);
		if (result == null) {
			this.pool.putByte(4).putInt(this.key.intVal);
			result = new Item(this.index++, this.key);
			put(result);
		}
		return result;
	}

	Item newLong(long value) {
		this.key.set(value);
		Item result = get(this.key);
		if (result == null) {
			this.pool.putByte(5).putLong(value);
			result = new Item(this.index, this.key);
			this.index += 2;
			put(result);
		}
		return result;
	}

	Item newDouble(double value) {
		this.key.set(value);
		Item result = get(this.key);
		if (result == null) {
			this.pool.putByte(6).putLong(this.key.longVal);
			result = new Item(this.index, this.key);
			this.index += 2;
			put(result);
		}
		return result;
	}

	private Item newString(String value) {
		this.key2.set(8, value, null, null);
		Item result = get(this.key2);
		if (result == null) {
			this.pool.put12(8, newUTF8(value));
			result = new Item(this.index++, this.key2);
			put(result);
		}
		return result;
	}

	public int newNameType(String name, String desc) {
		return newNameTypeItem(name, desc).index;
	}

	Item newNameTypeItem(String name, String desc) {
		this.key2.set(12, name, desc, null);
		Item result = get(this.key2);
		if (result == null) {
			put122(12, newUTF8(name), newUTF8(desc));
			result = new Item(this.index++, this.key2);
			put(result);
		}
		return result;
	}

	int addType(String type) {
		this.key.set(30, type, null, null);
		Item result = get(this.key);
		if (result == null) {
			result = addType(this.key);
		}
		return result.index;
	}

	int addUninitializedType(String type, int offset) {
		this.key.type = 31;
		this.key.intVal = offset;
		this.key.strVal1 = type;
		this.key.hashCode = (0x7FFFFFFF & 31 + type.hashCode() + offset);
		Item result = get(this.key);
		if (result == null) {
			result = addType(this.key);
		}
		return result.index;
	}

	private Item addType(Item item) {
		this.typeCount = ((short) (this.typeCount + 1));
		Item result = new Item(this.typeCount, this.key);
		put(result);
		if (this.typeTable == null) {
			this.typeTable = new Item[16];
		}
		if (this.typeCount == this.typeTable.length) {
			Item[] newTable = new Item[2 * this.typeTable.length];
			System.arraycopy(this.typeTable, 0, newTable, 0, this.typeTable.length);
			this.typeTable = newTable;
		}
		this.typeTable[this.typeCount] = result;
		return result;
	}

	int getMergedType(int type1, int type2) {
		this.key2.type = 32;
		this.key2.longVal = (type1 | type2 << 32);
		this.key2.hashCode = (0x7FFFFFFF & 32 + type1 + type2);
		Item result = get(this.key2);
		if (result == null) {
			String t = this.typeTable[type1].strVal1;
			String u = this.typeTable[type2].strVal1;
			this.key2.intVal = addType(getCommonSuperClass(t, u));
			result = new Item(0, this.key2);
			put(result);
		}
		return result.intVal;
	}

	protected String getCommonSuperClass(String type1, String type2) {
		ClassLoader classLoader = getClass().getClassLoader();
		Class d;
		Class c;
		try {
			c = Class.forName(type1.replace('/', '.'), false, classLoader);
			d = Class.forName(type2.replace('/', '.'), false, classLoader);
		} catch (Exception e) {
			throw new RuntimeException(e.toString());
		}

		if (c.isAssignableFrom(d)) {
			return type1;
		}
		if (d.isAssignableFrom(c)) {
			return type2;
		}
		if ((c.isInterface()) || (d.isInterface())) {
			return "java/lang/Object";
		}
		do {
			c = c.getSuperclass();
		} while (!

		c.isAssignableFrom(d));
		return c.getName().replace('.', '/');
	}

	private Item get(Item key) {
		Item i = this.items[(key.hashCode % this.items.length)];
		while ((i != null) && ((i.type != key.type) || (!key.isEqualTo(i)))) {
			i = i.next;
		}
		return i;
	}

	private void put(Item i) {
		if (this.index + this.typeCount > this.threshold) {
			int ll = this.items.length;
			int nl = ll * 2 + 1;
			Item[] newItems = new Item[nl];
			for (int l = ll - 1; l >= 0; l--) {
				Item j = this.items[l];
				while (j != null) {
					int index = j.hashCode % newItems.length;
					Item k = j.next;
					j.next = newItems[index];
					newItems[index] = j;
					j = k;
				}
			}
			this.items = newItems;
			this.threshold = ((int) (nl * 0.75D));
		}
		int index = i.hashCode % this.items.length;
		i.next = this.items[index];
		this.items[index] = i;
	}

	private void put122(int b, int s1, int s2) {
		this.pool.put12(b, s1).putShort(s2);
	}

	private void put112(int b1, int b2, int s) {
		this.pool.put11(b1, b2).putShort(s);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy