/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package javassist.bytecode;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import javassist.CtClass;
/**
* Code_attribute
.
*
*
To browse the code
field of
* a Code_attribute
structure,
* use CodeIterator
.
*
* @see CodeIterator
*/
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 LinkedList 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 LinkedList();
}
/**
* 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);
info = src.copyCode(cp, classnames, exceptions);
attributes = new LinkedList();
/* Since an index into the source constant pool table may not
be translated, we don't copy the attributes.
*/
/*
List src_attr = src.getAttributes();
int num = src_attr.size();
for (int i = 0; i < num; ++i) {
AttributeInfo ai = (AttributeInfo)src_attr.get(i);
attributes.add(ai.copy(cp, classnames));
}
*/
}
CodeAttribute(ConstPool cp, int name_id, DataInputStream in)
throws IOException
{
super(cp, name_id, (byte[])null);
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 LinkedList();
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.
*/
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 {
/**
* Constructs an exception.
*/
public RuntimeCopyException(String s) {
super(s);
}
}
/**
* Returns the length of this attribute_info
* structure.
* The returned value is attribute_length + 6
.
*/
public int length() {
return 18 + info.length + exceptions.size() * 8
+ AttributeInfo.getLength(attributes);
}
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.
*/
public byte[] get() {
throw new UnsupportedOperationException("CodeAttribute.get()");
}
/**
* This method is not available.
*
* @throws java.lang.UnsupportedOperationException always thrown.
*/
public void set(byte[] newinfo) {
throw new UnsupportedOperationException("CodeAttribute.set()");
}
/**
* 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;
}
/**
* 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
.
*
* @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);
}
/**
* Copies code.
*/
private byte[] copyCode(ConstPool destCp, Map classnames,
ExceptionTable etable)
throws BadBytecode
{
int len = getCodeLength();
byte[] newCode = new byte[len];
LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(),
newCode, destCp, classnames);
return LdcEntry.doit(newCode, ldc, etable);
}
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 {
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 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;
}
}
final class LdcEntry {
LdcEntry next;
int where;
int index;
static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable)
throws BadBytecode
{
while (ldc != null) {
int where = ldc.where;
code = CodeIterator.insertGap(code, where, 1, false, etable);
code[where] = (byte)Opcode.LDC_W;
ByteArray.write16bit(ldc.index, code, where + 1);
ldc = ldc.next;
}
return code;
}
}