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

com.feilong.lib.javassist.bytecode.CodeAttribute Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package com.feilong.lib.javassist.bytecode;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Code_attribute.
 *
 * 

* To browse the code field of * a Code_attribute structure, * use CodeIterator. * * @see CodeIterator * @see #iterator() */ public class CodeAttribute extends AttributeInfo implements Opcode{ /** * The name of this attribute "Code". */ public static final String tag = "Code"; // code[] is stored in AttributeInfo.info. private int maxStack; private int maxLocals; private ExceptionTable exceptions; private List attributes; /** * Constructs a Code_attribute. * * @param cp * constant pool table * @param stack * max_stack * @param locals * max_locals * @param code * code[] * @param etable * exception_table[] */ public CodeAttribute(ConstPool cp, int stack, int locals, byte[] code, ExceptionTable etable){ super(cp, tag); maxStack = stack; maxLocals = locals; info = code; exceptions = etable; attributes = new ArrayList<>(); } /** * Constructs a copy of Code_attribute. * Specified class names are replaced during the copy. * * @param cp * constant pool table. * @param src * source Code attribute. * @param classnames * pairs of replaced and substituted * class names. */ private CodeAttribute(ConstPool cp, CodeAttribute src, Map classnames) throws BadBytecode{ super(cp, tag); maxStack = src.getMaxStack(); maxLocals = src.getMaxLocals(); exceptions = src.getExceptionTable().copy(cp, classnames); attributes = new ArrayList<>(); List src_attr = src.getAttributes(); int num = src_attr.size(); for (int i = 0; i < num; ++i){ AttributeInfo ai = src_attr.get(i); attributes.add(ai.copy(cp, classnames)); } info = src.copyCode(cp, classnames, exceptions, this); } CodeAttribute(ConstPool cp, int name_id, DataInputStream in) throws IOException{ super(cp, name_id, (byte[]) null); @SuppressWarnings("unused") int attr_len = in.readInt(); maxStack = in.readUnsignedShort(); maxLocals = in.readUnsignedShort(); int code_len = in.readInt(); info = new byte[code_len]; in.readFully(info); exceptions = new ExceptionTable(cp, in); attributes = new ArrayList<>(); int num = in.readUnsignedShort(); for (int i = 0; i < num; ++i){ attributes.add(AttributeInfo.read(cp, in)); } } /** * Makes a copy. Class names are replaced according to the * given Map object. * * @param newCp * the constant pool table used by the new copy. * @param classnames * pairs of replaced and substituted * class names. * @exception RuntimeCopyException * if a BadBytecode * exception is thrown, it is * converted into * RuntimeCopyException. * * @return CodeAttribute object. */ @Override public AttributeInfo copy(ConstPool newCp,Map classnames) throws RuntimeCopyException{ try{ return new CodeAttribute(newCp, this, classnames); }catch (BadBytecode e){ throw new RuntimeCopyException("bad bytecode. fatal?"); } } /** * An exception that may be thrown by copy() * in CodeAttribute. */ public static class RuntimeCopyException extends RuntimeException{ /** default serialVersionUID */ private static final long serialVersionUID = 1L; /** * Constructs an exception. */ public RuntimeCopyException(String s){ super(s); } } /** * Returns the length of this attribute_info * structure. * The returned value is attribute_length + 6. */ @Override public int length(){ return 18 + info.length + exceptions.size() * 8 + AttributeInfo.getLength(attributes); } @Override void write(DataOutputStream out) throws IOException{ out.writeShort(name); // attribute_name_index out.writeInt(length() - 6); // attribute_length out.writeShort(maxStack); // max_stack out.writeShort(maxLocals); // max_locals out.writeInt(info.length); // code_length out.write(info); // code exceptions.write(out); out.writeShort(attributes.size()); // attributes_count AttributeInfo.writeAll(attributes, out); // attributes } /** * This method is not available. * * @throws java.lang.UnsupportedOperationException * always thrown. */ @Override public byte[] get(){ throw new UnsupportedOperationException("CodeAttribute.get()"); } /** * This method is not available. * * @throws java.lang.UnsupportedOperationException * always thrown. */ @Override public void set(byte[] newinfo){ throw new UnsupportedOperationException("CodeAttribute.set()"); } @Override void renameClass(String oldname,String newname){ AttributeInfo.renameClass(attributes, oldname, newname); } @Override void renameClass(Map classnames){ AttributeInfo.renameClass(attributes, classnames); } @Override void getRefClasses(Map classnames){ AttributeInfo.getRefClasses(attributes, classnames); } /** * Returns the name of the class declaring the method including * this code attribute. */ public String getDeclaringClass(){ ConstPool cp = getConstPool(); return cp.getClassName(); } /** * Returns max_stack. */ public int getMaxStack(){ return maxStack; } /** * Sets max_stack. */ public void setMaxStack(int value){ maxStack = value; } /** * Computes the maximum stack size and sets max_stack * to the computed size. * * @throws BadBytecode * if this method fails in computing. * @return the newly computed value of max_stack */ public int computeMaxStack() throws BadBytecode{ maxStack = new CodeAnalyzer(this).computeMaxStack(); return maxStack; } /** * Returns max_locals. */ public int getMaxLocals(){ return maxLocals; } /** * Sets max_locals. */ public void setMaxLocals(int value){ maxLocals = value; } /** * Returns code_length. */ public int getCodeLength(){ return info.length; } /** * Returns code[]. */ public byte[] getCode(){ return info; } /** * Sets code[]. */ void setCode(byte[] newinfo){ super.set(newinfo); } /** * Makes a new iterator for reading this code attribute. */ public CodeIterator iterator(){ return new CodeIterator(this); } /** * Returns exception_table[]. */ public ExceptionTable getExceptionTable(){ return exceptions; } /** * Returns attributes[]. * It returns a list of AttributeInfo. * A new element can be added to the returned list * and an existing element can be removed from the list. * * @see AttributeInfo */ public List getAttributes(){ return attributes; } /** * Returns the attribute with the specified name. * If it is not found, this method returns null. * * @param name * attribute name * @return an AttributeInfo object or null. */ public AttributeInfo getAttribute(String name){ return AttributeInfo.lookup(attributes, name); } /** * Adds a stack map table. If another copy of stack map table * is already contained, the old one is removed. * * @param smt * the stack map table added to this code attribute. * If it is null, a new stack map is not added. * Only the old stack map is removed. */ public void setAttribute(StackMapTable smt){ AttributeInfo.remove(attributes, StackMapTable.tag); if (smt != null){ attributes.add(smt); } } /** * Adds a stack map table for J2ME (CLDC). If another copy of stack map table * is already contained, the old one is removed. * * @param sm * the stack map table added to this code attribute. * If it is null, a new stack map is not added. * Only the old stack map is removed. * @since 3.12 */ public void setAttribute(StackMap sm){ AttributeInfo.remove(attributes, StackMap.tag); if (sm != null){ attributes.add(sm); } } /** * Copies code. */ private byte[] copyCode(ConstPool destCp,Map classnames,ExceptionTable etable,CodeAttribute destCa) throws BadBytecode{ int len = getCodeLength(); byte[] newCode = new byte[len]; destCa.info = newCode; LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(), newCode, destCp, classnames); return LdcEntry.doit(newCode, ldc, etable, destCa); } private static LdcEntry copyCode( byte[] code, int beginPos, int endPos, ConstPool srcCp, byte[] newcode, ConstPool destCp, Map classnameMap) throws BadBytecode{ int i2, index; LdcEntry ldcEntry = null; for (int i = beginPos; i < endPos; i = i2){ i2 = CodeIterator.nextOpcode(code, i); byte c = code[i]; newcode[i] = c; switch (c & 0xff) { case LDC_W: case LDC2_W: case GETSTATIC: case PUTSTATIC: case GETFIELD: case PUTFIELD: case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: case NEW: case ANEWARRAY: case CHECKCAST: case INSTANCEOF: copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, classnameMap); break; case LDC: index = code[i + 1] & 0xff; index = srcCp.copy(index, destCp, classnameMap); if (index < 0x100){ newcode[i + 1] = (byte) index; }else{ newcode[i] = NOP; newcode[i + 1] = NOP; LdcEntry ldc = new LdcEntry(); ldc.where = i; ldc.index = index; ldc.next = ldcEntry; ldcEntry = ldc; } break; case INVOKEINTERFACE: copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, classnameMap); newcode[i + 3] = code[i + 3]; newcode[i + 4] = code[i + 4]; break; case INVOKEDYNAMIC: copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, classnameMap); newcode[i + 3] = 0; newcode[i + 4] = 0; break; case MULTIANEWARRAY: copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, classnameMap); newcode[i + 3] = code[i + 3]; break; default: while (++i < i2){ newcode[i] = code[i]; } break; } } return ldcEntry; } private static void copyConstPoolInfo( int i, byte[] code, ConstPool srcCp, byte[] newcode, ConstPool destCp, Map classnameMap){ int index = ((code[i] & 0xff) << 8) | (code[i + 1] & 0xff); index = srcCp.copy(index, destCp, classnameMap); newcode[i] = (byte) (index >> 8); newcode[i + 1] = (byte) index; } static class LdcEntry{ LdcEntry next; int where; int index; static byte[] doit(byte[] code,LdcEntry ldc,ExceptionTable etable,CodeAttribute ca) throws BadBytecode{ if (ldc != null){ code = CodeIterator.changeLdcToLdcW(code, etable, ca, ldc); } /* * The original code was the following: * * while (ldc != null) { * int where = ldc.where; * code = CodeIterator.insertGapCore0(code, where, 1, false, etable, ca); * code[where] = (byte)Opcode.LDC_W; * ByteArray.write16bit(ldc.index, code, where + 1); * ldc = ldc.next; * } * * But this code does not support a large method > 32KB. */ return code; } } /** * Changes the index numbers of the local variables * to append a new parameter. * This method does not update LocalVariableAttribute, * LocalVariableTypeAttribute, * StackMapTable, or StackMap. * These attributes must be explicitly updated. * * @param where * the index of the new parameter. * @param size * the type size of the new parameter (1 or 2). * * @see LocalVariableAttribute#shiftIndex(int, int) * @see LocalVariableTypeAttribute#shiftIndex(int, int) * @see StackMapTable#insertLocal(int, int, int) * @see StackMap#insertLocal(int, int, int) */ public void insertLocalVar(int where,int size) throws BadBytecode{ CodeIterator ci = iterator(); while (ci.hasNext()){ shiftIndex(ci, where, size); } setMaxLocals(getMaxLocals() + size); } /** * @param lessThan * If the index of the local variable is * less than this value, it does not change. * Otherwise, the index is increased. * @param delta * the indexes of the local variables are * increased by this value. */ private static void shiftIndex(CodeIterator ci,int lessThan,int delta) throws BadBytecode{ int index = ci.next(); int opcode = ci.byteAt(index); if (opcode < ILOAD){ return; }else if (opcode < IASTORE){ if (opcode < ILOAD_0){ // iload, lload, fload, dload, aload shiftIndex8(ci, index, opcode, lessThan, delta); }else if (opcode < IALOAD){ // iload_0, ..., aload_3 shiftIndex0(ci, index, opcode, lessThan, delta, ILOAD_0, ILOAD); }else if (opcode < ISTORE){ return; }else if (opcode < ISTORE_0){ // istore, lstore, ... shiftIndex8(ci, index, opcode, lessThan, delta); }else{ // istore_0, ..., astore_3 shiftIndex0(ci, index, opcode, lessThan, delta, ISTORE_0, ISTORE); } }else if (opcode == IINC){ int var = ci.byteAt(index + 1); if (var < lessThan){ return; } var += delta; if (var < 0x100){ ci.writeByte(var, index + 1); }else{ int plus = (byte) ci.byteAt(index + 2); int pos = ci.insertExGap(3); ci.writeByte(WIDE, pos - 3); ci.writeByte(IINC, pos - 2); ci.write16bit(var, pos - 1); ci.write16bit(plus, pos + 1); } }else if (opcode == RET){ shiftIndex8(ci, index, opcode, lessThan, delta); }else if (opcode == WIDE){ int var = ci.u16bitAt(index + 2); if (var < lessThan){ return; } var += delta; ci.write16bit(var, index + 2); } } private static void shiftIndex8(CodeIterator ci,int index,int opcode,int lessThan,int delta) throws BadBytecode{ int var = ci.byteAt(index + 1); if (var < lessThan){ return; } var += delta; if (var < 0x100){ ci.writeByte(var, index + 1); }else{ int pos = ci.insertExGap(2); ci.writeByte(WIDE, pos - 2); ci.writeByte(opcode, pos - 1); ci.write16bit(var, pos); } } private static void shiftIndex0(CodeIterator ci,int index,int opcode,int lessThan,int delta,int opcode_i_0,int opcode_i) throws BadBytecode{ int var = (opcode - opcode_i_0) % 4; if (var < lessThan){ return; } var += delta; if (var < 4){ ci.writeByte(opcode + delta, index); }else{ opcode = (opcode - opcode_i_0) / 4 + opcode_i; if (var < 0x100){ int pos = ci.insertExGap(1); ci.writeByte(opcode, pos - 1); ci.writeByte(var, pos); }else{ int pos = ci.insertExGap(3); ci.writeByte(WIDE, pos - 1); ci.writeByte(opcode, pos); ci.write16bit(var, pos + 1); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy