⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 classfilewriter.java

📁 javascript语言的解释器源码
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
package org.mozilla.classfile;import org.mozilla.javascript.ObjToIntMap;import org.mozilla.javascript.ObjArray;import org.mozilla.javascript.UintMap;import java.io.*;/** * ClassFileWriter *  * A ClassFileWriter is used to write a Java class file. Methods are provided to * create fields and methods, and within methods to write Java bytecodes. *  * @author Roger Lawrence */public class ClassFileWriter {	/**	 * Construct a ClassFileWriter for a class.	 * 	 * @param className	 *            the name of the class to write, including full package	 *            qualification.	 * @param superClassName	 *            the name of the superclass of the class to write, including	 *            full package qualification.	 * @param sourceFileName	 *            the name of the source file to use for producing debug	 *            information, or null if debug information is not desired	 */	public ClassFileWriter(String className, String superClassName,			String sourceFileName) {		generatedClassName = className;		itsConstantPool = new ConstantPool(this);		itsThisClassIndex = itsConstantPool.addClass(className);		itsSuperClassIndex = itsConstantPool.addClass(superClassName);		if (sourceFileName != null)			itsSourceFileNameIndex = itsConstantPool.addUtf8(sourceFileName);		itsFlags = ACC_PUBLIC;	}	public final String getClassName() {		return generatedClassName;	}	/**	 * Add an interface implemented by this class.	 * 	 * This method may be called multiple times for classes that implement	 * multiple interfaces.	 * 	 * @param interfaceName	 *            a name of an interface implemented by the class being written,	 *            including full package qualification.	 */	public void addInterface(String interfaceName) {		short interfaceIndex = itsConstantPool.addClass(interfaceName);		itsInterfaces.add(new Short(interfaceIndex));	}	public static final short ACC_PUBLIC = 0x0001, ACC_PRIVATE = 0x0002,			ACC_PROTECTED = 0x0004, ACC_STATIC = 0x0008, ACC_FINAL = 0x0010,			ACC_SYNCHRONIZED = 0x0020, ACC_VOLATILE = 0x0040,			ACC_TRANSIENT = 0x0080, ACC_NATIVE = 0x0100, ACC_ABSTRACT = 0x0400;	/**	 * Set the class's flags.	 * 	 * Flags must be a set of the following flags, bitwise or'd together:	 * ACC_PUBLIC ACC_PRIVATE ACC_PROTECTED ACC_FINAL ACC_ABSTRACT TODO: check	 * that this is the appropriate set	 * 	 * @param flags	 *            the set of class flags to set	 */	public void setFlags(short flags) {		itsFlags = flags;	}	static String getSlashedForm(String name) {		return name.replace('.', '/');	}	/**	 * Convert Java class name in dot notation into	 * "Lname-with-dots-replaced-by-slashes;" form suitable for use as JVM type	 * signatures.	 */	public static String classNameToSignature(String name) {		int nameLength = name.length();		int colonPos = 1 + nameLength;		char[] buf = new char[colonPos + 1];		buf[0] = 'L';		buf[colonPos] = ';';		name.getChars(0, nameLength, buf, 1);		for (int i = 1; i != colonPos; ++i) {			if (buf[i] == '.') {				buf[i] = '/';			}		}		return new String(buf, 0, colonPos + 1);	}	/**	 * Add a field to the class.	 * 	 * @param fieldName	 *            the name of the field	 * @param type	 *            the type of the field using ...	 * @param flags	 *            the attributes of the field, such as ACC_PUBLIC, etc. bitwise	 *            or'd together	 */	public void addField(String fieldName, String type, short flags) {		short fieldNameIndex = itsConstantPool.addUtf8(fieldName);		short typeIndex = itsConstantPool.addUtf8(type);		itsFields.add(new ClassFileField(fieldNameIndex, typeIndex, flags));	}	/**	 * Add a field to the class.	 * 	 * @param fieldName	 *            the name of the field	 * @param type	 *            the type of the field using ...	 * @param flags	 *            the attributes of the field, such as ACC_PUBLIC, etc. bitwise	 *            or'd together	 * @param value	 *            an initial integral value	 */	public void addField(String fieldName, String type, short flags, int value) {		short fieldNameIndex = itsConstantPool.addUtf8(fieldName);		short typeIndex = itsConstantPool.addUtf8(type);		ClassFileField field = new ClassFileField(fieldNameIndex, typeIndex,				flags);		field.setAttributes(itsConstantPool.addUtf8("ConstantValue"),				(short) 0, (short) 0, itsConstantPool.addConstant(value));		itsFields.add(field);	}	/**	 * Add a field to the class.	 * 	 * @param fieldName	 *            the name of the field	 * @param type	 *            the type of the field using ...	 * @param flags	 *            the attributes of the field, such as ACC_PUBLIC, etc. bitwise	 *            or'd together	 * @param value	 *            an initial long value	 */	public void addField(String fieldName, String type, short flags, long value) {		short fieldNameIndex = itsConstantPool.addUtf8(fieldName);		short typeIndex = itsConstantPool.addUtf8(type);		ClassFileField field = new ClassFileField(fieldNameIndex, typeIndex,				flags);		field.setAttributes(itsConstantPool.addUtf8("ConstantValue"),				(short) 0, (short) 2, itsConstantPool.addConstant(value));		itsFields.add(field);	}	/**	 * Add a field to the class.	 * 	 * @param fieldName	 *            the name of the field	 * @param type	 *            the type of the field using ...	 * @param flags	 *            the attributes of the field, such as ACC_PUBLIC, etc. bitwise	 *            or'd together	 * @param value	 *            an initial double value	 */	public void addField(String fieldName, String type, short flags,			double value) {		short fieldNameIndex = itsConstantPool.addUtf8(fieldName);		short typeIndex = itsConstantPool.addUtf8(type);		ClassFileField field = new ClassFileField(fieldNameIndex, typeIndex,				flags);		field.setAttributes(itsConstantPool.addUtf8("ConstantValue"),				(short) 0, (short) 2, itsConstantPool.addConstant(value));		itsFields.add(field);	}	/**	 * Add Information about java variable to use when generating the local	 * variable table.	 * 	 * @param name	 *            variable name.	 * @param type	 *            variable type as bytecode descriptor string.	 * @param startPC	 *            the starting bytecode PC where this variable is live, or -1 if	 *            it does not have a Java register.	 * @param register	 *            the Java register number of variable or -1 if it does not have	 *            a Java register.	 */	public void addVariableDescriptor(String name, String type, int startPC,			int register) {		int nameIndex = itsConstantPool.addUtf8(name);		int descriptorIndex = itsConstantPool.addUtf8(type);		int[] chunk = { nameIndex, descriptorIndex, startPC, register };		if (itsVarDescriptors == null) {			itsVarDescriptors = new ObjArray();		}		itsVarDescriptors.add(chunk);	}	/**	 * Add a method and begin adding code.	 * 	 * This method must be called before other methods for adding code,	 * exception tables, etc. can be invoked.	 * 	 * @param methodName	 *            the name of the method	 * @param type	 *            a string representing the type	 * @param flags	 *            the attributes of the field, such as ACC_PUBLIC, etc. bitwise	 *            or'd together	 */	public void startMethod(String methodName, String type, short flags) {		short methodNameIndex = itsConstantPool.addUtf8(methodName);		short typeIndex = itsConstantPool.addUtf8(type);		itsCurrentMethod = new ClassFileMethod(methodNameIndex, typeIndex,				flags);		itsMethods.add(itsCurrentMethod);	}	/**	 * Complete generation of the method.	 * 	 * After this method is called, no more code can be added to the method	 * begun with <code>startMethod</code>.	 * 	 * @param maxLocals	 *            the maximum number of local variable slots (a.k.a. Java	 *            registers) used by the method	 * @param vars	 *            the array of the variables for the method, or null if none	 */	public void stopMethod(short maxLocals) {		if (itsCurrentMethod == null)			throw new IllegalStateException("No method to stop");		fixLabelGotos();		itsMaxLocals = maxLocals;		int lineNumberTableLength = 0;		if (itsLineNumberTable != null) {			// 6 bytes for the attribute header			// 2 bytes for the line number count			// 4 bytes for each entry			lineNumberTableLength = 6 + 2 + (itsLineNumberTableTop * 4);		}		int variableTableLength = 0;		if (itsVarDescriptors != null) {			// 6 bytes for the attribute header			// 2 bytes for the variable count			// 10 bytes for each entry			variableTableLength = 6 + 2 + (itsVarDescriptors.size() * 10);		}		int attrLength = 2 + // attribute_name_index				4 + // attribute_length				2 + // max_stack				2 + // max_locals				4 + // code_length				itsCodeBufferTop + 2 + // exception_table_length				(itsExceptionTableTop * 8) + 2 + // attributes_count				lineNumberTableLength + variableTableLength;		byte[] codeAttribute = new byte[attrLength];		int index = 0;		int codeAttrIndex = itsConstantPool.addUtf8("Code");		index = putInt16(codeAttrIndex, codeAttribute, index);		attrLength -= 6; // discount the attribute header		index = putInt32(attrLength, codeAttribute, index);		index = putInt16(itsMaxStack, codeAttribute, index);		index = putInt16(itsMaxLocals, codeAttribute, index);		index = putInt32(itsCodeBufferTop, codeAttribute, index);		System.arraycopy(itsCodeBuffer, 0, codeAttribute, index,				itsCodeBufferTop);		index += itsCodeBufferTop;		if (itsExceptionTableTop > 0) {			index = putInt16(itsExceptionTableTop, codeAttribute, index);			for (int i = 0; i < itsExceptionTableTop; i++) {				ExceptionTableEntry ete = itsExceptionTable[i];				short startPC = (short) getLabelPC(ete.itsStartLabel);				short endPC = (short) getLabelPC(ete.itsEndLabel);				short handlerPC = (short) getLabelPC(ete.itsHandlerLabel);				short catchType = ete.itsCatchType;				if (startPC == -1)					throw new IllegalStateException("start label not defined");				if (endPC == -1)					throw new IllegalStateException("end label not defined");				if (handlerPC == -1)					throw new IllegalStateException("handler label not defined");				index = putInt16(startPC, codeAttribute, index);				index = putInt16(endPC, codeAttribute, index);				index = putInt16(handlerPC, codeAttribute, index);				index = putInt16(catchType, codeAttribute, index);			}		} else {			// write 0 as exception table length			index = putInt16(0, codeAttribute, index);		}		int attributeCount = 0;		if (itsLineNumberTable != null)			attributeCount++;		if (itsVarDescriptors != null)			attributeCount++;		index = putInt16(attributeCount, codeAttribute, index);		if (itsLineNumberTable != null) {			int lineNumberTableAttrIndex = itsConstantPool					.addUtf8("LineNumberTable");			index = putInt16(lineNumberTableAttrIndex, codeAttribute, index);			int tableAttrLength = 2 + (itsLineNumberTableTop * 4);			index = putInt32(tableAttrLength, codeAttribute, index);			index = putInt16(itsLineNumberTableTop, codeAttribute, index);			for (int i = 0; i < itsLineNumberTableTop; i++) {				index = putInt32(itsLineNumberTable[i], codeAttribute, index);			}		}		if (itsVarDescriptors != null) {			int variableTableAttrIndex = itsConstantPool					.addUtf8("LocalVariableTable");			index = putInt16(variableTableAttrIndex, codeAttribute, index);			int varCount = itsVarDescriptors.size();			int tableAttrLength = 2 + (varCount * 10);			index = putInt32(tableAttrLength, codeAttribute, index);			index = putInt16(varCount, codeAttribute, index);			for (int i = 0; i < varCount; i++) {				int[] chunk = (int[]) itsVarDescriptors.get(i);				int nameIndex = chunk[0];				int descriptorIndex = chunk[1];				int startPC = chunk[2];				int register = chunk[3];				int length = itsCodeBufferTop - startPC;				index = putInt16(startPC, codeAttribute, index);				index = putInt16(length, codeAttribute, index);				index = putInt16(nameIndex, codeAttribute, index);				index = putInt16(descriptorIndex, codeAttribute, index);				index = putInt16(register, codeAttribute, index);			}		}		itsCurrentMethod.setCodeAttribute(codeAttribute);		itsExceptionTable = null;		itsExceptionTableTop = 0;		itsLineNumberTableTop = 0;		itsCodeBufferTop = 0;		itsCurrentMethod = null;		itsMaxStack = 0;		itsStackTop = 0;		itsLabelTableTop = 0;		itsFixupTableTop = 0;		itsVarDescriptors = null;	}	/**	 * Add the single-byte opcode to the current method.	 * 	 * @param theOpCode	 *            the opcode of the bytecode	 */	public void add(int theOpCode) {		if (opcodeCount(theOpCode) != 0)			throw new IllegalArgumentException("Unexpected operands");		int newStack = itsStackTop + stackChange(theOpCode);		if (newStack < 0 || Short.MAX_VALUE < newStack)			badStack(newStack);		if (DEBUGCODE)			System.out.println("Add " + bytecodeStr(theOpCode));		addToCodeBuffer(theOpCode);		itsStackTop = (short) newStack;		if (newStack > itsMaxStack)			itsMaxStack = (short) newStack;		if (DEBUGSTACK) {			System.out.println("After " + bytecodeStr(theOpCode) + " stack = "					+ itsStackTop);		}	}	/**	 * Add a single-operand opcode to the current method.	 * 	 * @param theOpCode	 *            the opcode of the bytecode	 * @param theOperand	 *            the operand of the bytecode	 */	public void add(int theOpCode, int theOperand) {		if (DEBUGCODE) {			System.out.println("Add " + bytecodeStr(theOpCode) + ", "					+ Integer.toHexString(theOperand));		}		int newStack = itsStackTop + stackChange(theOpCode);		if (newStack < 0 || Short.MAX_VALUE < newStack)			badStack(newStack);		switch (theOpCode) {		case ByteCode.GOTO:			// fallthru...		case ByteCode.IFEQ:		case ByteCode.IFNE:		case ByteCode.IFLT:		case ByteCode.IFGE:		case ByteCode.IFGT:		case ByteCode.IFLE:		case ByteCode.IF_ICMPEQ:		case ByteCode.IF_ICMPNE:		case ByteCode.IF_ICMPLT:		case ByteCode.IF_ICMPGE:		case ByteCode.IF_ICMPGT:		case ByteCode.IF_ICMPLE:		case ByteCode.IF_ACMPEQ:		case ByteCode.IF_ACMPNE:		case ByteCode.JSR:		case ByteCode.IFNULL:		case ByteCode.IFNONNULL: {			if ((theOperand & 0x80000000) != 0x80000000) {				if ((theOperand < 0) || (theOperand > 65535))					throw new IllegalArgumentException("Bad label for branch");			}			int branchPC = itsCodeBufferTop;			addToCodeBuffer(theOpCode);			if ((theOperand & 0x80000000) != 0x80000000) {				// hard displacement				addToCodeInt16(theOperand);			} else { // a label				int targetPC = getLabelPC(theOperand);				if (DEBUGLABELS) {					int theLabel = theOperand & 0x7FFFFFFF;					System.out.println("Fixing branch to " + theLabel + " at "							+ targetPC + " from " + branchPC);				}				if (targetPC != -1) {					int offset = targetPC - branchPC;					addToCodeInt16(offset);				} else {					addLabelFixup(theOperand, branchPC + 1);					addToCodeInt16(0);				}			}		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -