/*
 * 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 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 Also:
/** * <code>Code_attribute</code>. * * <p>To browse the <code>code</code> field of * a <code>Code_attribute</code> structure, * use <code>CodeIterator</code>. * * @see CodeIterator * @see #iterator() */
public class CodeAttribute extends AttributeInfo implements Opcode {
The name of this attribute "Code".
/** * The name of this attribute <code>"Code"</code>. */
public static final String tag = "Code"; // code[] is stored in AttributeInfo.info. private int maxStack; private int maxLocals; private ExceptionTable exceptions; private List<AttributeInfo> attributes;
Constructs a Code_attribute.
Params:
  • cp – constant pool table
  • stack – max_stack
  • locals – max_locals
  • code – code[]
  • etable – exception_table[]
/** * Constructs a <code>Code_attribute</code>. * * @param cp constant pool table * @param stack <code>max_stack</code> * @param locals <code>max_locals</code> * @param code <code>code[]</code> * @param etable <code>exception_table[]</code> */
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<AttributeInfo>(); }
Constructs a copy of Code_attribute. Specified class names are replaced during the copy.
Params:
  • cp – constant pool table.
  • src – source Code attribute.
  • classnames – pairs of replaced and substituted class names.
/** * Constructs a copy of <code>Code_attribute</code>. * 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<String,String> classnames) throws BadBytecode { super(cp, tag); maxStack = src.getMaxStack(); maxLocals = src.getMaxLocals(); exceptions = src.getExceptionTable().copy(cp, classnames); attributes = new ArrayList<AttributeInfo>(); List<AttributeInfo> 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<AttributeInfo>(); 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.
Params:
  • newCp – the constant pool table used by the new copy.
  • classnames – pairs of replaced and substituted class names.
Throws:
  • RuntimeCopyException – if a BadBytecode exception is thrown, it is converted into RuntimeCopyException.
Returns:CodeAttribute object.
/** * Makes a copy. Class names are replaced according to the * given <code>Map</code> 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 <code>BadBytecode</code> * exception is thrown, it is * converted into * <code>RuntimeCopyException</code>. * * @return <code>CodeAttribute</code> object. */
@Override public AttributeInfo copy(ConstPool newCp, Map<String,String> 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.
/** * An exception that may be thrown by <code>copy()</code> * in <code>CodeAttribute</code>. */
public static class RuntimeCopyException extends RuntimeException {
default serialVersionUID
/** default serialVersionUID */
private static final long serialVersionUID = 1L;
Constructs an exception.
/** * Constructs an exception. */
public RuntimeCopyException(String s) { super(s); } }
Returns the length of this attribute_info structure. The returned value is attribute_length + 6.
/** * Returns the length of this <code>attribute_info</code> * structure. * The returned value is <code>attribute_length + 6</code>. */
@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:
  • UnsupportedOperationException – always thrown.
/** * 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:
  • UnsupportedOperationException – always thrown.
/** * 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<String,String> classnames) { AttributeInfo.renameClass(attributes, classnames); } @Override void getRefClasses(Map<String,String> classnames) { AttributeInfo.getRefClasses(attributes, classnames); }
Returns the name of the class declaring the method including this code attribute.
/** * 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.
/** * Returns <code>max_stack</code>. */
public int getMaxStack() { return maxStack; }
Sets max_stack.
/** * Sets <code>max_stack</code>. */
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.
Returns:the newly computed value of max_stack
/** * Computes the maximum stack size and sets <code>max_stack</code> * to the computed size. * * @throws BadBytecode if this method fails in computing. * @return the newly computed value of <code>max_stack</code> */
public int computeMaxStack() throws BadBytecode { maxStack = new CodeAnalyzer(this).computeMaxStack(); return maxStack; }
Returns max_locals.
/** * Returns <code>max_locals</code>. */
public int getMaxLocals() { return maxLocals; }
Sets max_locals.
/** * Sets <code>max_locals</code>. */
public void setMaxLocals(int value) { maxLocals = value; }
Returns code_length.
/** * Returns <code>code_length</code>. */
public int getCodeLength() { return info.length; }
Returns code[].
/** * Returns <code>code[]</code>. */
public byte[] getCode() { return info; }
Sets code[].
/** * Sets <code>code[]</code>. */
void setCode(byte[] newinfo) { super.set(newinfo); }
Makes a new iterator for reading this code attribute.
/** * Makes a new iterator for reading this code attribute. */
public CodeIterator iterator() { return new CodeIterator(this); }
Returns exception_table[].
/** * Returns <code>exception_table[]</code>. */
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 Also:
  • AttributeInfo
/** * Returns <code>attributes[]</code>. * It returns a list of <code>AttributeInfo</code>. * A new element can be added to the returned list * and an existing element can be removed from the list. * * @see AttributeInfo */
public List<AttributeInfo> getAttributes() { return attributes; }
Returns the attribute with the specified name. If it is not found, this method returns null.
Params:
  • name – attribute name
Returns: an AttributeInfo object or null.
/** * Returns the attribute with the specified name. * If it is not found, this method returns null. * * @param name attribute name * @return an <code>AttributeInfo</code> 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.
Params:
  • 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.
/** * 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.
Params:
  • 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
/** * 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.
/** * Copies code. */
private byte[] copyCode(ConstPool destCp, Map<String,String> 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<String,String> 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<String,String> 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.
Params:
  • where – the index of the new parameter.
  • size – the type size of the new parameter (1 or 2).
See Also:
/** * Changes the index numbers of the local variables * to append a new parameter. * This method does not update <code>LocalVariableAttribute</code>, * <code>LocalVariableTypeAttribute</code>, * <code>StackMapTable</code>, or <code>StackMap</code>. * 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); }
Params:
  • lessThan – If the index of the local variable is less than this value, it does not change. Otherwise, the index is increased.
  • delta – the indexes of the local variables are increased by this value.
/** * @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); } } } }