/*
* $Id: Code.java,v 1.8 2002/09/16 08:05:02 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.codec;
import java.util.ArrayList;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class Code extends Attribute
{
protected Method _method;
protected int _codeindex;
protected Bytes _bytes;
protected DataOutputStream _code;
protected ExceptionHandler _current = null;
protected ArrayList _exceptions = new ArrayList();
protected int _maxlocals = 0;
protected int[] _local = new int[8];
protected int _locals = 0;
protected int _stack = 0;
protected int _maxstack = 0;
public Code(Method method, ConstantPool pool)
{
super(pool);
_method = method;
_codeindex = pool.addUtf8(ATTR_Code);
_bytes = new Bytes();
_code = new DataOutputStream(_bytes);
if ((_method.getFlags() & ACC_STATIC) == 0) {
_maxlocals++;
}
}
public Method getMethod()
{
return _method;
}
public void pushop()
{
_stack++;
if (_stack > _maxstack) {
_maxstack = _stack;
}
}
public void pushop(int amount)
{
_stack += amount;
if (_stack > _maxstack) {
_maxstack = _stack;
}
}
public void popop()
{
_stack--;
}
public void popop(int amount)
{
_stack -= amount;
if (_stack<0) {
_stack = 0;
} else if (_stack > _maxstack) {
_maxstack = _stack;
}
}
public int size()
{
return _bytes.size();
}
protected boolean isByte(int i)
{
return i>=Byte.MIN_VALUE && i<=Byte.MAX_VALUE;
}
protected boolean isShort(int i)
{
return i>=Short.MIN_VALUE && i<=Short.MAX_VALUE;
}
public String getName()
{
return ATTR_Code;
}
public Target getTarget()
{
return new Target(address());
}
public Source getSource()
{
return new Source(this);
}
public int address()
{
return _bytes.address();
}
public int getFirstLocal()
{
return ((_method.getFlags() & ACC_STATIC) != 0) ? 0 : 1;
}
public Code aload_first()
{
aload(getFirstLocal());
return this;
}
public int addLocal()
{
int size = _locals;
if (size>0) {
return _local[--_locals];
}
return _maxlocals++;
}
public void endLocal(int releasedLocal)
{
int length = _local.length;
int size = _locals;
if (size >= length) {
int[] local = new int[length+8];
System.arraycopy(_local, 0, local, 0, length);
_local = local;
}
_local[_locals++] = releasedLocal;
}
public void addLocals(int amount)
{
while(amount-- > 0) {
addLocal();
}
}
public ExceptionHandler getCurrentHandler()
{
return _current;
}
public ExceptionHandler startExceptionHandler(boolean withfinally)
{
_current = new ExceptionHandler(this, _current, withfinally);
return _current;
}
public void endExceptionHandler(ExceptionHandler handler)
{
if (_current != handler) {
//throw new RuntimeException("Current exception handler is different than the one being closed");
}
_current = handler.getParent();
_exceptions.add(handler);
}
public Code writeShort(int address, short s)
{
_bytes.setShort(address, s);
return this;
}
public Code writeInt(int address, int i)
{
_bytes.setInt(address, i);
return this;
}
protected Code writeByte(int b)
{
try {
_code.writeByte(b);
} catch (IOException e) {
}
return this;
}
protected Code writeShort(int s)
{
try {
_code.writeShort(s);
} catch (IOException e) {
}
return this;
}
protected Code writeInt(int s)
{
try {
_code.writeInt(s);
} catch (IOException e) {
}
return this;
}
public Code arraylength()
{
writeByte(190);
return this;
}
public Code anewarray(int index)
{
writeByte(189);
writeShort(index);
return this;
}
public Code anewarray(String classname)
{
writeByte(189);
writeShort(_pool.addClass(classname));
return this;
}
public Code anewarray(Info clazz)
{
writeByte(189);
writeShort(clazz.getIndex());
return this;
}
public Code anewarray(int index, int dims)
{
writeByte(197);
writeShort(index);
writeByte(dims);
return this;
}
public Code anewarray(String classname, int dims)
{
writeByte(197);
writeShort(_pool.addClass(classname));
writeByte(dims);
return this;
}
public Code anewarray(Info clazz, int dims)
{
writeByte(197);
writeShort(clazz.getIndex());
writeByte(dims);
return this;
}
public Code aastore()
{
popop(3);
writeByte(83);
return this;
}
public Code aaload()
{
popop();
writeByte(50);
return this;
}
public Code newarray(int type)
{
writeByte(188);
writeByte(type);
return this;
}
public Code newarray(Info info)
{
writeByte(188);
writeByte(info.getIndex());
return this;
}
public Code checkcast(int type)
{
writeByte(192);
writeShort(type);
return this;
}
public Code checkcast(String classname)
{
return checkcast(_pool.addClass(classname));
}
public Code instance_of(int type)
{
writeByte(193);
writeShort(type);
return this;
}
public Code instance_of(String classname)
{
return instance_of(_pool.addClass(classname));
}
public Code laload()
{
writeByte(47);
return this;
}
public Code lastore()
{
popop(4);
writeByte(80);
return this;
}
public Code faload()
{
popop();
writeByte(48);
return this;
}
public Code fastore()
{
popop(3);
writeByte(81);
return this;
}
public Code daload()
{
writeByte(49);
return this;
}
public Code dastore()
{
popop(4);
writeByte(82);
return this;
}
public Code baload()
{
popop();
writeByte(51);
return this;
}
public Code bastore()
{
popop(3);
writeByte(84);
return this;
}
public Code caload()
{
popop();
writeByte(52);
return this;
}
public Code castore()
{
popop(3);
writeByte(85);
return this;
}
public Code saload()
{
popop();
writeByte(53);
return this;
}
public Code sastore()
{
popop(3);
writeByte(86);
return this;
}
public Code iaload()
{
popop();
writeByte(46);
return this;
}
public Code iastore()
{
popop(3);
writeByte(79);
return this;
}
public Code aconst_null()
{
pushop();
return writeByte(1);
}
public Code astring(String str)
{
if (str == null) {
return aconst_null();
} else {
return ldc(_pool.addString(str));
}
}
public Code aload(int local)
{
pushop();
if (0<=local && local<=3) {
writeByte(42 + local);
} else {
if (isByte(local)) {
writeByte(25);
writeByte(local);
} else {
writeByte(196);
writeByte(25);
writeShort(local);
}
}
return this;
}
public Code astore(int local)
{
popop();
if (0<=local && local<=3) {
writeByte(75 + local);
} else {
if (isByte(local)) {
writeByte(58);
writeByte(local);
} else {
writeByte(196);
writeByte(58);
writeShort(local);
}
}
return this;
}
public Code iload(int local)
{
pushop();
if (0<=local && local<=3) {
writeByte(26 + local);
} else {
if (isByte(local)) {
writeByte(21);
writeByte(local);
} else {
writeByte(196);
writeByte(21);
writeShort(local);
}
}
return this;
}
public Code istore(int local)
{
popop();
if (0<=local && local<=3) {
writeByte(59 + local);
} else {
if (isByte(local)) {
writeByte(54);
writeByte(local);
} else {
writeByte(196);
writeByte(54);
writeShort(local);
}
}
return this;
}
public Code iadd()
{
popop();
return writeByte(96);
}
public Code athrow()
{
popop();
return writeByte(191);
}
public Code ireturn()
{
popop();
return writeByte(172);
}
public Code areturn()
{
popop();
return writeByte(176);
}
public Code vreturn()
{
return writeByte(177);
}
public Code ldc(int index)
{
return ldc(_pool.get(index));
}
public Code ldc(Info info)
{
int index = info.getIndex();
if (info.getWidth()==2) {
pushop(2);
writeByte(20);
writeShort(index);
} else {
pushop();
if (index<256) {
writeByte(18);
writeByte(index);
} else {
writeByte(19);
writeShort(index);
}
}
return this;
}
public Code invokevirtual(int index)
{
return invokevirtual(_pool.get(index));
}
public Code invokevirtual(Info info)
{
MethodRefInfo methodinfo = (MethodRefInfo)info;
int retw = methodinfo.getReturnWidth();
int argc = methodinfo.getArgumentCount();
popop(argc+1-retw);
writeByte(182);
writeShort(info.getIndex());
return this;
}
public Code invokespecial(int index)
{
return invokespecial(_pool.get(index));
}
public Code invokespecial(Info info)
{
MethodRefInfo methodinfo = (MethodRefInfo)info;
int retw = methodinfo.getReturnWidth();
int argc = methodinfo.getArgumentCount();
popop(argc+1-retw);
writeByte(183);
writeShort(info.getIndex());
return this;
}
public Code invokestatic(int index)
{
return invokestatic(_pool.get(index));
}
public Code invokestatic(Info info)
{
MethodRefInfo methodinfo = (MethodRefInfo)info;
int retw = methodinfo.getReturnWidth();
int argc = methodinfo.getArgumentCount();
popop(argc-retw);
writeByte(184);
writeShort(info.getIndex());
return this;
}
public Code invokeinterface(int index)
{
return invokeinterface(_pool.get(index));
}
public Code invokeinterface(Info info)
{
MethodRefInfo methodinfo = (MethodRefInfo)info;
int retw = methodinfo.getReturnWidth();
int argc = methodinfo.getArgumentCount();
popop(1+argc-retw);
writeByte(185);
writeShort(info.getIndex());
writeByte(1 + argc);
writeByte(0);
return this;
}
public Code self()
{
pushop();
return writeByte(42);
}
public Code getfield(int index)
{
pushop(((FieldRefInfo)_pool.get(index)).getFieldWidth() - 1);
writeByte(180);
writeShort(index);
return this;
}
public Code getstatic(int index)
{
pushop(((FieldRefInfo)_pool.get(index)).getFieldWidth());
writeByte(178);
writeShort(index);
return this;
}
public Code putfield(int index)
{
popop(1 + ((FieldRefInfo)_pool.get(index)).getFieldWidth());
writeByte(181);
writeShort(index);
return this;
}
public Code putstatic(int index)
{
popop(((FieldRefInfo)_pool.get(index)).getFieldWidth());
writeByte(179);
writeShort(index);
return this;
}
public Code getfield(Info info)
{
pushop(((FieldRefInfo)info).getFieldWidth() - 1);
writeByte(180);
writeShort(info.getIndex());
return this;
}
public Code getstatic(Info info)
{
pushop(((FieldRefInfo)info).getFieldWidth());
writeByte(178);
writeShort(info.getIndex());
return this;
}
public Code putfield(Info info)
{
popop(((FieldRefInfo)info).getFieldWidth() + 1);
writeByte(181);
writeShort(info.getIndex());
return this;
}
public Code putstatic(Info info)
{
popop(((FieldRefInfo)info).getFieldWidth());
writeByte(179);
writeShort(info.getIndex());
return this;
}
public Code getfield(Field field)
{
pushop(field.getWidth() - 1);
writeByte(180);
writeShort(field.getIndex());
return this;
}
public Code getstatic(Field field)
{
pushop(field.getWidth());
writeByte(178);
writeShort(field.getIndex());
return this;
}
public Code putfield(Field field)
{
popop(field.getWidth() + 1);
writeByte(181);
writeShort(field.getIndex());
return this;
}
public Code putstatic(Field field)
{
popop(field.getWidth());
writeByte(179);
writeShort(field.getIndex());
return this;
}
public Code anew(int index)
{
pushop();
writeByte(187);
writeShort(index);
return this;
}
public Code anew(Info info)
{
pushop();
writeByte(187);
writeShort(info.getIndex());
return this;
}
public Code dup()
{
pushop();
return writeByte(89);
}
public Code dup_x1()
{
pushop();
return writeByte(90);
}
public Code dup_x2()
{
pushop();
return writeByte(91);
}
public Code dup2()
{
pushop(2);
return writeByte(92);
}
public Code dup2_x1()
{
pushop(2);
return writeByte(93);
}
public Code dup2_x2()
{
pushop(2);
return writeByte(94);
}
public Code pop()
{
popop();
return writeByte(87);
}
public Code iconst(boolean b)
{
return iconst(b ? 1 : 0);
}
public Code iconst(int i)
{
if (i>=-1 && i<=5) {
pushop();
writeByte(2 + (i+1));
} else if (isByte(i)) {
pushop();
writeByte(16);
writeByte((byte)i);
} else if (isShort(i)) {
pushop();
writeByte(17);
writeShort((short)i);
} else {
return ldc(_pool.addInt(i));
}
return this;
}
public Code lconst(long l)
{
if (l == 0) {
pushop(2);
writeByte(9);
return this;
} else if (l == 1) {
pushop(2);
writeByte(10);
return this;
}
return ldc(_pool.addLong(l));
}
public Code fconst(float f)
{
if (f == 0.0) {
pushop();
writeByte(11);
return this;
} else if (f == 1.0) {
pushop();
writeByte(12);
return this;
} else if (f == 2.0) {
pushop();
writeByte(13);
return this;
}
return ldc(_pool.addFloat(f));
}
public Code dconst(double d)
{
if (d == 0.0) {
pushop(2);
writeByte(14);
return this;
} else if (d == 1.0) {
pushop(2);
writeByte(15);
return this;
}
return ldc(_pool.addDouble(d));
}
public Code go_to(Target target)
{
int address = address();
writeByte(167);
writeShort(target.getAddress() - address);
return this;
}
public Code go_to(Source source)
{
int address = address();
writeByte(167);
writeShort(0x7fff);
source.add(address, address+1);
return this;
}
public Source go_to()
{
int address = address();
writeByte(167);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_null(Target target)
{
popop();
int address = address();
writeByte(198);
writeShort(target.getAddress() - address);
return this;
}
public Code if_null(Source source)
{
popop();
int address = address();
writeByte(198);
writeShort(0x7ff);
source.add(address, address+1);
return this;
}
public Source if_null()
{
popop();
int address = address();
writeByte(198);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_nonnull(Target target)
{
popop();
int address = address();
writeByte(199);
writeShort(target.getAddress() - address);
return this;
}
public Code if_nonnull(Source source)
{
popop();
int address = address();
writeByte(199);
writeShort(0x7ff);
source.add(address, address+1);
return this;
}
public Source if_nonnull()
{
popop();
int address = address();
writeByte(199);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_icmpeq(Target target)
{
popop(2);
int address = address();
writeByte(159);
writeShort(target.getAddress() - address);
return this;
}
public Code if_icmpeq(Source source)
{
popop(2);
int address = address();
writeByte(159);
writeShort(0x7ff);
source.add(address, address+1);
return this;
}
public Source if_icmpeq()
{
popop(2);
int address = address();
writeByte(159);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_icmpne(Target target)
{
popop(2);
int address = address();
writeByte(160);
writeShort(target.getAddress() - address);
return this;
}
public Code if_icmpne(Source source)
{
popop(2);
int address = address();
writeByte(160);
writeShort(0x7ff);
source.add(address, address+1);
return this;
}
public Source if_icmpne()
{
popop(2);
int address = address();
writeByte(160);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_icmpge(Target target)
{
popop(2);
int address = address();
writeByte(162);
writeShort(target.getAddress() - address);
return this;
}
public Code if_icmpge(Source source)
{
popop(2);
int address = address();
writeByte(162);
writeShort(0x7ff);
source.add(address, address+1);
return this;
}
public Source if_icmpge()
{
popop(2);
int address = address();
writeByte(162);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_eq(Target target)
{
popop();
int address = address();
writeByte(153);
writeShort(target.getAddress() - address);
return this;
}
public Code if_eq(Source source)
{
popop();
int address = address();
writeByte(153);
writeShort(0x7ff);
source.add(address, address+1);
return this;
}
public Source if_eq()
{
popop();
int address = address();
writeByte(153);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_ne(Target target)
{
popop();
int address = address();
writeByte(154);
writeShort(target.getAddress() - address);
return this;
}
public Code if_ne(Source source)
{
popop();
int address = address();
writeByte(154);
writeShort(0x7ff);
source.add(address, address+1);
return this;
}
public Source if_ne()
{
popop();
int address = address();
writeByte(154);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_lt(Target target)
{
popop();
int address = address();
writeByte(155);
writeShort(target.getAddress() - address);
return this;
}
public Code if_lt(Source source)
{
popop();
int address = address();
writeByte(155);
writeShort(0x7ff);
source.add(address, address+1);
return this;
}
public Source if_lt()
{
popop();
int address = address();
writeByte(155);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_le(Target target)
{
popop();
int address = address();
writeByte(158);
writeShort(target.getAddress() - address);
return this;
}
public Code if_le(Source source)
{
popop();
int address = address();
writeByte(158);
writeShort(0x7ff);
source.add(address, address+1);
return this;
}
public Source if_le()
{
popop();
int address = address();
writeByte(158);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_gt(Target target)
{
popop();
int address = address();
writeByte(157);
writeShort(target.getAddress() - address);
return this;
}
public Code if_gt(Source source)
{
popop();
int address = address();
writeByte(157);
writeShort(0x7fff);
source.add(address, address+1);
return this;
}
public Source if_gt()
{
popop();
int address = address();
writeByte(157);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code if_ge(Target target)
{
popop();
int address = address();
writeByte(156);
writeShort(target.getAddress() - address);
return this;
}
public Code if_ge(Source source)
{
popop();
int address = address();
writeByte(156);
writeShort(0x7fff);
source.add(address, address+1);
return this;
}
public Source if_ge()
{
popop();
int address = address();
writeByte(156);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code ixor()
{
popop();
writeByte(130);
return this;
}
public Code iinc(int local, int amount)
{
if (isByte(amount) && local<0xff) {
writeByte(132);
writeByte((byte)local);
writeByte((byte)amount);
return this;
}
writeShort(196);
writeByte(132);
writeShort((short)local);
writeShort((short)amount);
return this;
}
public Code jsr(Target target)
{
int address = address();
writeByte(168);
writeShort(target.getAddress() - address);
return this;
}
public Code jsr(Source source)
{
int address = address();
writeByte(168);
writeShort(0);
source.add(address, address+1);
return this;
}
public Source jsr()
{
int address = address();
writeByte(168);
writeShort(0x7fff);
return new Source(this, address, address+1);
}
public Code ret(int local)
{
writeShort(169);
writeByte(local);
return this;
}
public Code monitorenter()
{
popop();
writeByte(194);
return this;
}
public Code monitorexit()
{
popop();
writeByte(195);
return this;
}
public Code swap()
{
writeByte(95);
return this;
}
public Code nop()
{
writeByte(0);
return this;
}
public Code print(String text)
{
getstatic(_pool.addFieldRef(
"java/lang/System", "out", "Ljava/io/PrintStream;"));
astring(text);
invokevirtual(_pool.addMethodRef(
"java/io/PrintStream", "print", "(Ljava/lang/String;)V"));
return this;
}
public Code println(String text)
{
getstatic(_pool.addFieldRef(
"java/lang/System", "out", "Ljava/io/PrintStream;"));
astring(text);
invokevirtual(_pool.addMethodRef(
"java/io/PrintStream", "println", "(Ljava/lang/String;)V"));
return this;
}
public Switch select()
{
popop();
return new Switch(this);
}
public int getExceptionTableSize()
{
int count = 0;
int size = _exceptions.size();
for(int i=0; i<size; i++) {
ExceptionHandler h = (ExceptionHandler)_exceptions.get(i);
count += h.getTableSize();
}
return count;
}
public void write(DataOutputStream output) throws IOException
{
if (_stack != 0) {
System.out.println("Code stack integrity failed: "+_stack+" operands at the end of method");
//throw new RuntimeException("Code stack integrity failed: "+_stack+" operands at the end of method");
}
int exsize = getExceptionTableSize();
int size = _bytes.size() + 12 + exsize * 4 * 2;
output.writeShort(_codeindex);
output.writeInt(size);
output.writeShort(_maxstack);
output.writeShort(_maxlocals);
output.writeInt(_bytes.size());
_bytes.writeTo(output);
output.writeShort(exsize);
int n = _exceptions.size();
for(int i=0; i<n; i++) {
((ExceptionHandler)_exceptions.get(i)).write(output);
}
output.writeShort(0);
}
}