// Copyright (c) Corporation for National Research Initiatives
package org.python.compiler;
import java.io.*;
import java.util.Vector;
class ExceptionLabel {
public Label start, end, handler;
public int exc;
public ExceptionLabel(Label start, Label end, Label handler, int exc) {
this.start = start;
this.end = end;
this.handler = handler;
this.exc = exc;
}
}
public class Code extends Attribute {
ConstantPool pool;
public int stack;
int max_stack;
public DataOutputStream code;
ByteArrayOutputStream stream;
String sig;
String locals[];
int nlocals;
int argcount;
int att_name;
Vector labels, exceptions;
LineNumberTable linenumbers;
int returnLocal;
public Label getLabel() {
Label l = new Label(this);
addLabel(l);
return l;
}
public Label getLabelAtPosition() {
Label l = getLabel();
l.setPosition();
return l;
}
public void addLabel(Label l) {
labels.addElement(l);
}
public int size() {
return stream.size();
}
public Code(String sig, ConstantPool pool, boolean isStatic) {
this.sig = sig;
max_stack = 2;
stack = 0;
this.pool = pool;
stream = new ByteArrayOutputStream();
code = new DataOutputStream(stream);
nlocals = -ConstantPool.sigSize(sig, false);
if (!isStatic)
nlocals = nlocals + 1;
argcount = nlocals;
locals = new String[nlocals + 128];
labels = new Vector();
exceptions = new Vector();
try {
att_name = pool.UTF8("Code");
} catch (IOException e) {
att_name = 0;
}
}
public int getLocal(String type) {
//Could optimize this to skip arguments?
for (int l = argcount; l < nlocals; l++) {
if (locals[l] == null) {
locals[l] = type;
return l;
}
}
if (nlocals >= locals.length) {
String[] new_locals = new String[locals.length * 2];
System.arraycopy(locals, 0, new_locals, 0, locals.length);
locals = new_locals;
}
locals[nlocals] = type;
nlocals += 1;
return nlocals - 1;
}
public void freeLocal(int l) {
if (locals[l] == null)
System.out.println("Double free:" + l);
locals[l] = null;
}
java.util.BitSet finallyLocals = new java.util.BitSet();
public int getFinallyLocal(String type) {
int l = getLocal(type);
finallyLocals.set(l);
return l;
}
public void freeFinallyLocal(int l) {
finallyLocals.clear(l);
freeLocal(l);
}
public int getReturnLocal() {
if (returnLocal == 0)
returnLocal = getLocal("return");
return returnLocal;
}
public Vector getActiveLocals() {
Vector ret = new Vector();
ret.setSize(nlocals);
for (int l = argcount; l < nlocals; l++) {
if (l == returnLocal || finallyLocals.get(l))
continue;
ret.setElementAt(locals[l], l);
}
return ret;
}
public void addExceptionHandler(Label begin, Label end, Label handler, int exc) {
exceptions.addElement(new ExceptionLabel(begin, end, handler, exc));
}
/*
cl = self.code_length()
self.length = cl+12+8*len(self.exc_table)
cw.put2(self.name)
cw.put4(self.length)
cw.put2(self.max_stack)
cw.put2(len(self.locals))
cw.put4(cl)
self.dump_code(cw)
cw.put2(len(self.exc_table))
for start, end, handler, exc in self.exc_table:
cw.put2(self.labels[start])
cw.put2(self.labels[end])
cw.put2(self.labels[handler])
cw.put2(exc)
cw.dump_attributes(self.attributes)
*/
public void fixLabels(byte[] bytes) throws IOException {
for (int i = 0; i < labels.size(); i++) {
((Label) labels.elementAt(i)).fix(bytes);
}
}
public void write(DataOutputStream stream) throws IOException {
byte[] bytes = this.stream.toByteArray();
fixLabels(bytes);
int n = exceptions.size();
int length = bytes.length + 12 + 8 * n;
;
if (linenumbers != null)
length += linenumbers.length();
stream.writeShort(att_name);
stream.writeInt(length);
stream.writeShort(max_stack);
stream.writeShort(nlocals);
stream.writeInt(bytes.length);
stream.write(bytes);
//No Exceptions for now
stream.writeShort(n);
for (int i = 0; i < n; i++) {
ExceptionLabel e = (ExceptionLabel) exceptions.elementAt(i);
stream.writeShort(e.start.getPosition());
stream.writeShort(e.end.getPosition());
stream.writeShort(e.handler.getPosition());
stream.writeShort(e.exc);
}
if (linenumbers != null)
ClassFile.writeAttributes(stream, new Attribute[] { linenumbers });
else
ClassFile.writeAttributes(stream, new Attribute[0]);
}
public void push(int i) {
//System.out.println("push: "+i+" : "+stack);
stack = stack + i;
if (stack > max_stack)
max_stack = stack;
if (stack < 0)
throw new InternalError("stack < 0: " + stack);
}
public void branch(int b, Label label) throws IOException {
int offset = size();
code.writeByte(b);
label.setBranch(offset, 2);
label.setStack(stack);
}
public void print(String s) throws IOException {
getstatic("java/lang/System", "out", "Ljava/io/PrintStream;");
ldc(s);
invokevirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V");
}
public void aaload() throws IOException {
code.writeByte(50);
push(-1);
}
public void aastore() throws IOException {
code.writeByte(83);
push(-3);
}
public void aconst_null() throws IOException {
code.writeByte(1);
push(1);
}
public void aload(int i) throws IOException {
if (i >= 0 && i < 4) {
code.writeByte(42 + i);
} else {
code.writeByte(25);
code.writeByte(i);
}
push(1);
}
public void anewarray(int c) throws IOException {
code.writeByte(189);
code.writeShort(c);
//push(-1); push(1);
}
public void areturn() throws IOException {
code.writeByte(176);
push(-1);
}
public void arraylength() throws IOException {
code.writeByte(190);
//push(-1); push(1);
}
public void astore(int i) throws IOException {
if (i >= 0 && i < 4) {
code.writeByte(75 + i);
} else {
code.writeByte(58);
code.writeByte(i);
}
push(-1);
}
public void athrow() throws IOException {
code.writeByte(191);
push(-1);
}
public void checkcast(int c) throws IOException {
code.writeByte(192);
code.writeShort(c);
}
public void dload(int i) throws IOException {
if (i >= 0 && i < 4) {
code.writeByte(38 + i);
} else {
code.writeByte(24);
code.writeByte(i);
}
push(2);
}
public void dreturn() throws IOException {
code.writeByte(175);
push(-2);
}
public void dup() throws IOException {
code.writeByte(89);
push(1);
}
public void dup_x1() throws IOException {
code.writeByte(90);
push(1);
}
public void fload(int i) throws IOException {
if (i >= 0 && i < 4) {
code.writeByte(34 + i);
} else {
code.writeByte(23);
code.writeByte(i);
}
push(1);
}
public void freturn() throws IOException {
code.writeByte(174);
push(-1);
}
public void getfield(int c) throws IOException {
code.writeByte(180);
code.writeShort(c);
push(pool.sizes[c] - 1);
}
public void getfield(String c, String name, String type) throws IOException {
getfield(pool.Fieldref(c, name, type));
}
public void getstatic(int c) throws IOException {
code.writeByte(178);
code.writeShort(c);
push(pool.sizes[c]);
}
public void getstatic(String c, String name, String type) throws IOException {
getstatic(pool.Fieldref(c, name, type));
}
public void goto_(Label label) throws IOException {
branch(167, label);
}
public void iconst(int i) throws IOException {
if (i >= -1 && i <= 5) {
code.writeByte(3 + i);
} else {
if (i > -127 && i < 128) {
code.writeByte(16);
if (i < 0)
i = 256 + i;
code.writeByte(i);
} else {
if (i > -32767 && i < 32768) {
code.writeByte(17);
if (i < 0)
i = i + 65536;
code.writeShort(i);
} else {
ldc(pool.Integer(i));
}
}
}
push(1);
}
public void if_icmpne(Label label) throws IOException {
push(-2);
branch(160, label);
}
public void ifeq(Label label) throws IOException {
push(-1);
branch(153, label);
}
public void ifne(Label label) throws IOException {
push(-1);
branch(154, label);
}
public void ifnonnull(Label label) throws IOException {
push(-1);
branch(199, label);
}
public void ifnull(Label label) throws IOException {
push(-1);
branch(198, label);
}
public void iinc(int i, int increment) throws IOException {
code.writeByte(132);
code.writeByte(i);
code.writeByte(increment);
}
public void iinc(int i) throws IOException {
iinc(i, 1);
}
public void iload(int i) throws IOException {
if (i >= 0 && i < 4) {
code.writeByte(26 + i);
} else {
code.writeByte(21);
code.writeByte(i);
}
push(1);
}
public void invokespecial(int c) throws IOException {
code.writeByte(183);
code.writeShort(c);
push(pool.sizes[c] - 1);
}
public void invokestatic(int c) throws IOException {
code.writeByte(184);
code.writeShort(c);
push(pool.sizes[c]);
}
public void invokevirtual(int c) throws IOException {
code.writeByte(182);
code.writeShort(c);
push(pool.sizes[c] - 1);
}
public void invokevirtual(String c, String name, String type) throws IOException {
invokevirtual(pool.Methodref(c, name, type));
}
public void ireturn() throws IOException {
code.writeByte(172);
push(-1);
}
public void istore(int i) throws IOException {
if (i >= 0 && i < 4) {
code.writeByte(59 + i);
} else {
code.writeByte(54);
code.writeByte(i);
}
push(-1);
}
public void jsr(Label label) throws IOException {
//push(-1);
int offset = size();
code.writeByte(168);
label.setBranch(offset, 2);
label.setStack(stack + 1);
}
public void ldc(int c) throws IOException {
int size = pool.sizes[c];
if (size == 1) {
if (c < 256) {
code.writeByte(18);
code.writeByte(c);
} else {
code.writeByte(19);
code.writeShort(c);
}
} else {
code.writeByte(20);
code.writeShort(c);
}
push(pool.sizes[c]);
}
public void ldc(String s) throws IOException {
ldc(pool.String(s));
}
public void lload(int i) throws IOException {
if (i >= 0 && i < 4) {
code.writeByte(30 + i);
} else {
code.writeByte(22);
code.writeByte(i);
}
push(2);
}
public void lreturn() throws IOException {
code.writeByte(173);
push(-2);
}
public void new_(int c) throws IOException {
code.writeByte(187);
code.writeShort(c);
push(1);
}
public void pop() throws IOException {
code.writeByte(87);
push(-1);
}
public void putfield(int c) throws IOException {
code.writeByte(181);
code.writeShort(c);
push(-pool.sizes[c] - 1);
}
public void putfield(String c, String name, String type) throws IOException {
putfield(pool.Fieldref(c, name, type));
}
public void putstatic(int c) throws IOException {
code.writeByte(179);
code.writeShort(c);
push(-pool.sizes[c]);
}
public void putstatic(String c, String name, String type) throws IOException {
putstatic(pool.Fieldref(c, name, type));
}
public void return_() throws IOException {
code.writeByte(177);
}
public void ret(int index) throws IOException {
code.writeByte(169);
code.writeByte(index);
}
public void swap() throws IOException {
code.writeByte(95);
}
public void tableswitch(Label def, int low, Label[] labels) throws IOException {
int position = size();
push(-1);
code.writeByte(170);
for (int j = 0; j < 3 - (position % 4); j++)
code.writeByte(0);
def.setBranch(position, 4);
code.writeInt(low);
code.writeInt(labels.length - 1);
for (int i = 0; i < labels.length; i++) {
labels[i].setBranch(position, 4);
}
}
public void setline(int line) throws IOException {
if (linenumbers == null)
linenumbers = new LineNumberTable(pool);
linenumbers.addLine(size(), line);
}
}