|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.reflect; |
|
|
|
class ClassFileAssembler implements ClassFileConstants { |
|
private ByteVector vec; |
|
private short cpIdx = 0; |
|
|
|
public ClassFileAssembler() { |
|
this(ByteVectorFactory.create()); |
|
} |
|
|
|
public ClassFileAssembler(ByteVector vec) { |
|
this.vec = vec; |
|
} |
|
|
|
public ByteVector getData() { |
|
return vec; |
|
} |
|
|
|
|
|
public short getLength() { |
|
return (short) vec.getLength(); |
|
} |
|
|
|
public void emitMagicAndVersion() { |
|
emitInt(0xCAFEBABE); |
|
emitShort((short) 0); |
|
emitShort((short) 49); |
|
} |
|
|
|
public void emitInt(int val) { |
|
emitByte((byte) (val >> 24)); |
|
emitByte((byte) ((val >> 16) & 0xFF)); |
|
emitByte((byte) ((val >> 8) & 0xFF)); |
|
emitByte((byte) (val & 0xFF)); |
|
} |
|
|
|
public void emitShort(short val) { |
|
emitByte((byte) ((val >> 8) & 0xFF)); |
|
emitByte((byte) (val & 0xFF)); |
|
} |
|
|
|
|
|
void emitShort(short bci, short val) { |
|
vec.put(bci, (byte) ((val >> 8) & 0xFF)); |
|
vec.put(bci + 1, (byte) (val & 0xFF)); |
|
} |
|
|
|
public void emitByte(byte val) { |
|
vec.add(val); |
|
} |
|
|
|
public void append(ClassFileAssembler asm) { |
|
append(asm.vec); |
|
} |
|
|
|
public void append(ByteVector vec) { |
|
for (int i = 0; i < vec.getLength(); i++) { |
|
emitByte(vec.get(i)); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
pool index before emitting at least one constant pool entry. */ |
|
public short cpi() { |
|
if (cpIdx == 0) { |
|
throw new RuntimeException("Illegal use of ClassFileAssembler"); |
|
} |
|
return cpIdx; |
|
} |
|
|
|
public void emitConstantPoolUTF8(String str) { |
|
// NOTE: can not use str.getBytes("UTF-8") here because of |
|
|
|
byte[] bytes = UTF8.encode(str); |
|
emitByte(CONSTANT_Utf8); |
|
emitShort((short) bytes.length); |
|
for (int i = 0; i < bytes.length; i++) { |
|
emitByte(bytes[i]); |
|
} |
|
cpIdx++; |
|
} |
|
|
|
public void emitConstantPoolClass(short index) { |
|
emitByte(CONSTANT_Class); |
|
emitShort(index); |
|
cpIdx++; |
|
} |
|
|
|
public void emitConstantPoolNameAndType(short nameIndex, short typeIndex) { |
|
emitByte(CONSTANT_NameAndType); |
|
emitShort(nameIndex); |
|
emitShort(typeIndex); |
|
cpIdx++; |
|
} |
|
|
|
public void emitConstantPoolFieldref |
|
(short classIndex, short nameAndTypeIndex) |
|
{ |
|
emitByte(CONSTANT_Fieldref); |
|
emitShort(classIndex); |
|
emitShort(nameAndTypeIndex); |
|
cpIdx++; |
|
} |
|
|
|
public void emitConstantPoolMethodref |
|
(short classIndex, short nameAndTypeIndex) |
|
{ |
|
emitByte(CONSTANT_Methodref); |
|
emitShort(classIndex); |
|
emitShort(nameAndTypeIndex); |
|
cpIdx++; |
|
} |
|
|
|
public void emitConstantPoolInterfaceMethodref |
|
(short classIndex, short nameAndTypeIndex) |
|
{ |
|
emitByte(CONSTANT_InterfaceMethodref); |
|
emitShort(classIndex); |
|
emitShort(nameAndTypeIndex); |
|
cpIdx++; |
|
} |
|
|
|
public void emitConstantPoolString(short utf8Index) { |
|
emitByte(CONSTANT_String); |
|
emitShort(utf8Index); |
|
cpIdx++; |
|
} |
|
|
|
//---------------------------------------------------------------------- |
|
// Opcodes. Keeps track of maximum stack and locals. Make a new |
|
// assembler for each piece of assembled code, then append the |
|
// result to the previous assembler's class file. |
|
// |
|
|
|
private int stack = 0; |
|
private int maxStack = 0; |
|
private int maxLocals = 0; |
|
|
|
private void incStack() { |
|
setStack(stack + 1); |
|
} |
|
|
|
private void decStack() { |
|
--stack; |
|
} |
|
|
|
public short getMaxStack() { |
|
return (short) maxStack; |
|
} |
|
|
|
public short getMaxLocals() { |
|
return (short) maxLocals; |
|
} |
|
|
|
|
|
|
|
value of max locals) */ |
|
public void setMaxLocals(int maxLocals) { |
|
this.maxLocals = maxLocals; |
|
} |
|
|
|
|
|
public int getStack() { |
|
return stack; |
|
} |
|
|
|
|
|
public void setStack(int value) { |
|
stack = value; |
|
if (stack > maxStack) { |
|
maxStack = stack; |
|
} |
|
} |
|
|
|
/////////////// |
|
// Constants // |
|
/////////////// |
|
|
|
public void opc_aconst_null() { |
|
emitByte(opc_aconst_null); |
|
incStack(); |
|
} |
|
|
|
public void opc_sipush(short constant) { |
|
emitByte(opc_sipush); |
|
emitShort(constant); |
|
incStack(); |
|
} |
|
|
|
public void opc_ldc(byte cpIdx) { |
|
emitByte(opc_ldc); |
|
emitByte(cpIdx); |
|
incStack(); |
|
} |
|
|
|
///////////////////////////////////// |
|
// Local variable loads and stores // |
|
///////////////////////////////////// |
|
|
|
public void opc_iload_0() { |
|
emitByte(opc_iload_0); |
|
if (maxLocals < 1) maxLocals = 1; |
|
incStack(); |
|
} |
|
|
|
public void opc_iload_1() { |
|
emitByte(opc_iload_1); |
|
if (maxLocals < 2) maxLocals = 2; |
|
incStack(); |
|
} |
|
|
|
public void opc_iload_2() { |
|
emitByte(opc_iload_2); |
|
if (maxLocals < 3) maxLocals = 3; |
|
incStack(); |
|
} |
|
|
|
public void opc_iload_3() { |
|
emitByte(opc_iload_3); |
|
if (maxLocals < 4) maxLocals = 4; |
|
incStack(); |
|
} |
|
|
|
public void opc_lload_0() { |
|
emitByte(opc_lload_0); |
|
if (maxLocals < 2) maxLocals = 2; |
|
incStack(); |
|
incStack(); |
|
} |
|
|
|
public void opc_lload_1() { |
|
emitByte(opc_lload_1); |
|
if (maxLocals < 3) maxLocals = 3; |
|
incStack(); |
|
incStack(); |
|
} |
|
|
|
public void opc_lload_2() { |
|
emitByte(opc_lload_2); |
|
if (maxLocals < 4) maxLocals = 4; |
|
incStack(); |
|
incStack(); |
|
} |
|
|
|
public void opc_lload_3() { |
|
emitByte(opc_lload_3); |
|
if (maxLocals < 5) maxLocals = 5; |
|
incStack(); |
|
incStack(); |
|
} |
|
|
|
public void opc_fload_0() { |
|
emitByte(opc_fload_0); |
|
if (maxLocals < 1) maxLocals = 1; |
|
incStack(); |
|
} |
|
|
|
public void opc_fload_1() { |
|
emitByte(opc_fload_1); |
|
if (maxLocals < 2) maxLocals = 2; |
|
incStack(); |
|
} |
|
|
|
public void opc_fload_2() { |
|
emitByte(opc_fload_2); |
|
if (maxLocals < 3) maxLocals = 3; |
|
incStack(); |
|
} |
|
|
|
public void opc_fload_3() { |
|
emitByte(opc_fload_3); |
|
if (maxLocals < 4) maxLocals = 4; |
|
incStack(); |
|
} |
|
|
|
public void opc_dload_0() { |
|
emitByte(opc_dload_0); |
|
if (maxLocals < 2) maxLocals = 2; |
|
incStack(); |
|
incStack(); |
|
} |
|
|
|
public void opc_dload_1() { |
|
emitByte(opc_dload_1); |
|
if (maxLocals < 3) maxLocals = 3; |
|
incStack(); |
|
incStack(); |
|
} |
|
|
|
public void opc_dload_2() { |
|
emitByte(opc_dload_2); |
|
if (maxLocals < 4) maxLocals = 4; |
|
incStack(); |
|
incStack(); |
|
} |
|
|
|
public void opc_dload_3() { |
|
emitByte(opc_dload_3); |
|
if (maxLocals < 5) maxLocals = 5; |
|
incStack(); |
|
incStack(); |
|
} |
|
|
|
public void opc_aload_0() { |
|
emitByte(opc_aload_0); |
|
if (maxLocals < 1) maxLocals = 1; |
|
incStack(); |
|
} |
|
|
|
public void opc_aload_1() { |
|
emitByte(opc_aload_1); |
|
if (maxLocals < 2) maxLocals = 2; |
|
incStack(); |
|
} |
|
|
|
public void opc_aload_2() { |
|
emitByte(opc_aload_2); |
|
if (maxLocals < 3) maxLocals = 3; |
|
incStack(); |
|
} |
|
|
|
public void opc_aload_3() { |
|
emitByte(opc_aload_3); |
|
if (maxLocals < 4) maxLocals = 4; |
|
incStack(); |
|
} |
|
|
|
public void opc_aaload() { |
|
emitByte(opc_aaload); |
|
decStack(); |
|
} |
|
|
|
public void opc_astore_0() { |
|
emitByte(opc_astore_0); |
|
if (maxLocals < 1) maxLocals = 1; |
|
decStack(); |
|
} |
|
|
|
public void opc_astore_1() { |
|
emitByte(opc_astore_1); |
|
if (maxLocals < 2) maxLocals = 2; |
|
decStack(); |
|
} |
|
|
|
public void opc_astore_2() { |
|
emitByte(opc_astore_2); |
|
if (maxLocals < 3) maxLocals = 3; |
|
decStack(); |
|
} |
|
|
|
public void opc_astore_3() { |
|
emitByte(opc_astore_3); |
|
if (maxLocals < 4) maxLocals = 4; |
|
decStack(); |
|
} |
|
|
|
//////////////////////// |
|
// Stack manipulation // |
|
//////////////////////// |
|
|
|
public void opc_pop() { |
|
emitByte(opc_pop); |
|
decStack(); |
|
} |
|
|
|
public void opc_dup() { |
|
emitByte(opc_dup); |
|
incStack(); |
|
} |
|
|
|
public void opc_dup_x1() { |
|
emitByte(opc_dup_x1); |
|
incStack(); |
|
} |
|
|
|
public void opc_swap() { |
|
emitByte(opc_swap); |
|
} |
|
|
|
/////////////////////////////// |
|
// Widening conversions only // |
|
/////////////////////////////// |
|
|
|
public void opc_i2l() { |
|
emitByte(opc_i2l); |
|
} |
|
|
|
public void opc_i2f() { |
|
emitByte(opc_i2f); |
|
} |
|
|
|
public void opc_i2d() { |
|
emitByte(opc_i2d); |
|
} |
|
|
|
public void opc_l2f() { |
|
emitByte(opc_l2f); |
|
} |
|
|
|
public void opc_l2d() { |
|
emitByte(opc_l2d); |
|
} |
|
|
|
public void opc_f2d() { |
|
emitByte(opc_f2d); |
|
} |
|
|
|
////////////////// |
|
// Control flow // |
|
////////////////// |
|
|
|
public void opc_ifeq(short bciOffset) { |
|
emitByte(opc_ifeq); |
|
emitShort(bciOffset); |
|
decStack(); |
|
} |
|
|
|
|
|
straight-through control flow. */ |
|
public void opc_ifeq(Label l) { |
|
short instrBCI = getLength(); |
|
emitByte(opc_ifeq); |
|
l.add(this, instrBCI, getLength(), getStack() - 1); |
|
emitShort((short) -1); |
|
} |
|
|
|
public void opc_if_icmpeq(short bciOffset) { |
|
emitByte(opc_if_icmpeq); |
|
emitShort(bciOffset); |
|
setStack(getStack() - 2); |
|
} |
|
|
|
|
|
control flow. */ |
|
public void opc_if_icmpeq(Label l) { |
|
short instrBCI = getLength(); |
|
emitByte(opc_if_icmpeq); |
|
l.add(this, instrBCI, getLength(), getStack() - 2); |
|
emitShort((short) -1); |
|
} |
|
|
|
public void opc_goto(short bciOffset) { |
|
emitByte(opc_goto); |
|
emitShort(bciOffset); |
|
} |
|
|
|
|
|
control flow. */ |
|
public void opc_goto(Label l) { |
|
short instrBCI = getLength(); |
|
emitByte(opc_goto); |
|
l.add(this, instrBCI, getLength(), getStack()); |
|
emitShort((short) -1); |
|
} |
|
|
|
public void opc_ifnull(short bciOffset) { |
|
emitByte(opc_ifnull); |
|
emitShort(bciOffset); |
|
decStack(); |
|
} |
|
|
|
|
|
control flow. */ |
|
public void opc_ifnull(Label l) { |
|
short instrBCI = getLength(); |
|
emitByte(opc_ifnull); |
|
l.add(this, instrBCI, getLength(), getStack() - 1); |
|
emitShort((short) -1); |
|
decStack(); |
|
} |
|
|
|
public void opc_ifnonnull(short bciOffset) { |
|
emitByte(opc_ifnonnull); |
|
emitShort(bciOffset); |
|
decStack(); |
|
} |
|
|
|
|
|
control flow. */ |
|
public void opc_ifnonnull(Label l) { |
|
short instrBCI = getLength(); |
|
emitByte(opc_ifnonnull); |
|
l.add(this, instrBCI, getLength(), getStack() - 1); |
|
emitShort((short) -1); |
|
decStack(); |
|
} |
|
|
|
///////////////////////// |
|
// Return instructions // |
|
///////////////////////// |
|
|
|
public void opc_ireturn() { |
|
emitByte(opc_ireturn); |
|
setStack(0); |
|
} |
|
|
|
public void opc_lreturn() { |
|
emitByte(opc_lreturn); |
|
setStack(0); |
|
} |
|
|
|
public void opc_freturn() { |
|
emitByte(opc_freturn); |
|
setStack(0); |
|
} |
|
|
|
public void opc_dreturn() { |
|
emitByte(opc_dreturn); |
|
setStack(0); |
|
} |
|
|
|
public void opc_areturn() { |
|
emitByte(opc_areturn); |
|
setStack(0); |
|
} |
|
|
|
public void opc_return() { |
|
emitByte(opc_return); |
|
setStack(0); |
|
} |
|
|
|
////////////////////// |
|
// Field operations // |
|
////////////////////// |
|
|
|
public void opc_getstatic(short fieldIndex, int fieldSizeInStackSlots) { |
|
emitByte(opc_getstatic); |
|
emitShort(fieldIndex); |
|
setStack(getStack() + fieldSizeInStackSlots); |
|
} |
|
|
|
public void opc_putstatic(short fieldIndex, int fieldSizeInStackSlots) { |
|
emitByte(opc_putstatic); |
|
emitShort(fieldIndex); |
|
setStack(getStack() - fieldSizeInStackSlots); |
|
} |
|
|
|
public void opc_getfield(short fieldIndex, int fieldSizeInStackSlots) { |
|
emitByte(opc_getfield); |
|
emitShort(fieldIndex); |
|
setStack(getStack() + fieldSizeInStackSlots - 1); |
|
} |
|
|
|
public void opc_putfield(short fieldIndex, int fieldSizeInStackSlots) { |
|
emitByte(opc_putfield); |
|
emitShort(fieldIndex); |
|
setStack(getStack() - fieldSizeInStackSlots - 1); |
|
} |
|
|
|
//////////////////////// |
|
// Method invocations // |
|
//////////////////////// |
|
|
|
|
|
other values count as 1. */ |
|
public void opc_invokevirtual(short methodIndex, |
|
int numArgs, |
|
int numReturnValues) |
|
{ |
|
emitByte(opc_invokevirtual); |
|
emitShort(methodIndex); |
|
setStack(getStack() - numArgs - 1 + numReturnValues); |
|
} |
|
|
|
|
|
other values count as 1. */ |
|
public void opc_invokespecial(short methodIndex, |
|
int numArgs, |
|
int numReturnValues) |
|
{ |
|
emitByte(opc_invokespecial); |
|
emitShort(methodIndex); |
|
setStack(getStack() - numArgs - 1 + numReturnValues); |
|
} |
|
|
|
|
|
other values count as 1. */ |
|
public void opc_invokestatic(short methodIndex, |
|
int numArgs, |
|
int numReturnValues) |
|
{ |
|
emitByte(opc_invokestatic); |
|
emitShort(methodIndex); |
|
setStack(getStack() - numArgs + numReturnValues); |
|
} |
|
|
|
|
|
other values count as 1. */ |
|
public void opc_invokeinterface(short methodIndex, |
|
int numArgs, |
|
byte count, |
|
int numReturnValues) |
|
{ |
|
emitByte(opc_invokeinterface); |
|
emitShort(methodIndex); |
|
emitByte(count); |
|
emitByte((byte) 0); |
|
setStack(getStack() - numArgs - 1 + numReturnValues); |
|
} |
|
|
|
////////////////// |
|
// Array length // |
|
////////////////// |
|
|
|
public void opc_arraylength() { |
|
emitByte(opc_arraylength); |
|
} |
|
|
|
///////// |
|
// New // |
|
///////// |
|
|
|
public void opc_new(short classIndex) { |
|
emitByte(opc_new); |
|
emitShort(classIndex); |
|
incStack(); |
|
} |
|
|
|
//////////// |
|
// Athrow // |
|
//////////// |
|
|
|
public void opc_athrow() { |
|
emitByte(opc_athrow); |
|
setStack(1); |
|
} |
|
|
|
////////////////////////////// |
|
// Checkcast and instanceof // |
|
////////////////////////////// |
|
|
|
|
|
public void opc_checkcast(short classIndex) { |
|
emitByte(opc_checkcast); |
|
emitShort(classIndex); |
|
} |
|
|
|
public void opc_instanceof(short classIndex) { |
|
emitByte(opc_instanceof); |
|
emitShort(classIndex); |
|
} |
|
} |