com.caucho.bytecode.CodeVisitor Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.bytecode;
import com.caucho.util.IntArray;
import com.caucho.util.L10N;
import java.util.ArrayList;
/**
* Visitor for travelling the code.
*/
public class CodeVisitor {
static private final L10N L = new L10N(CodeVisitor.class);
private JavaClass _javaClass;
protected CodeAttribute _codeAttr;
private byte []_code;
protected int _offset;
public CodeVisitor()
{
}
public CodeVisitor(JavaClass javaClass, CodeAttribute codeAttr)
{
init(javaClass, codeAttr);
}
public void init(JavaClass javaClass, CodeAttribute codeAttr)
{
_javaClass = javaClass;
_codeAttr = codeAttr;
_code = codeAttr.getCode();
_offset = 0;
}
/**
* Returns the java class.
*/
public JavaClass getJavaClass()
{
return _javaClass;
}
/**
* Returns the code attribute.
*/
public CodeAttribute getCodeAttribute()
{
return _codeAttr;
}
/**
* Returns the offset.
*/
public int getOffset()
{
return _offset;
}
/**
* Sets the offset.
*/
public void setOffset(int offset)
{
_offset = offset;
}
/**
* Returns the code buffer.
*/
public byte []getCode()
{
return _code;
}
/**
* Returns the exceptions.
*/
public ArrayList getExceptions()
{
return _codeAttr.getExceptions();
}
/**
* Returns the opcode at the cursor.
*/
public int getOpcode()
{
int op = getCode()[_offset] & 0xff;
if (op == WIDE)
return getCode()[_offset + 1] & 0xff;
else
return op;
}
/**
* Goes to the next opcode.
*/
public boolean next()
{
_offset = nextOffset();
return _offset >= 0;
}
/**
* Goes to the next opcode.
*/
protected int nextOffset()
{
int opcode = getCode()[_offset] & 0xff;
int length = OP_LEN[opcode];
switch (opcode) {
case GOTO:
case GOTO_W:
case RET:
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case ARETURN:
case RETURN:
case ATHROW:
return -1;
case TABLESWITCH:
{
int arg = _offset + 1;
arg += (4 - arg % 4) % 4;
int low = getInt(arg + 4);
int high = getInt(arg + 8);
return arg + 12 + (high - low + 1) * 4;
}
case LOOKUPSWITCH:
{
return -1;
/*
int arg = _offset + 1;
arg += (4 - arg % 4) % 4;
int n = getInt(arg + 4);
int next = arg + 12 + n * 8;
return next;
*/
}
case WIDE:
{
int op2 = getCode()[_offset + 1] & 0xff;
if (op2 == IINC)
length = 5;
else
length = 3;
break;
}
}
if (length < 0 || length > 0x10)
throw new UnsupportedOperationException(L.l("{0}: can't handle opcode {1}",
"" + _offset,
"" + getOpcode()));
return _offset + length + 1;
}
/**
* Returns true for a simple branch, i.e. a branch with a simple target.
*/
public boolean isBranch()
{
switch (getOpcode()) {
case IFNULL:
case IFNONNULL:
case IFNE:
case IFEQ:
case IFLT:
case IFGE:
case IFGT:
case IFLE:
case IF_ICMPEQ:
case IF_ICMPNE:
case IF_ICMPLT:
case IF_ICMPGE:
case IF_ICMPGT:
case IF_ICMPLE:
case IF_ACMPEQ:
case IF_ACMPNE:
case JSR:
case JSR_W:
case GOTO:
case GOTO_W:
return true;
}
return false;
}
/**
* Returns the branch target.
*/
public int getBranchTarget()
{
switch (getOpcode()) {
case IFNULL:
case IFNONNULL:
case IFNE:
case IFEQ:
case IFLT:
case IFGE:
case IFGT:
case IFLE:
case IF_ICMPEQ:
case IF_ICMPNE:
case IF_ICMPLT:
case IF_ICMPLE:
case IF_ICMPGE:
case IF_ICMPGT:
case IF_ACMPEQ:
case IF_ACMPNE:
case GOTO:
case JSR:
return _offset + getShortArg();
case GOTO_W:
case JSR_W:
return _offset + getIntArg();
default:
throw new UnsupportedOperationException();
}
}
/**
* Returns true for a switch.
*/
public boolean isSwitch()
{
switch (getOpcode()) {
case TABLESWITCH:
case LOOKUPSWITCH:
return true;
default:
return false;
}
}
/**
* Returns the branch target.
*/
public int []getSwitchTargets()
{
switch (getOpcode()) {
case TABLESWITCH:
{
int arg = _offset + 1;
arg += (4 - arg % 4) % 4;
int low = getInt(arg + 4);
int high = getInt(arg + 8);
int []targets = new int[high - low + 2];
targets[0] = getInt(arg) + _offset;
for (int i = 0; i <= high - low; i++) {
targets[i + 1] = getInt(arg + 12 + i * 4) + _offset;
}
return targets;
}
case LOOKUPSWITCH:
{
int arg = _offset + 1;
arg += (4 - arg % 4) % 4;
int n = getInt(arg + 4);
int []targets = new int[n + 1];
targets[0] = getInt(arg) + _offset;
for (int i = 0; i < n; i++) {
int off = arg + 8 + i * 8 + 4;
targets[i + 1] = getInt(off) + _offset;
}
return targets;
}
default:
throw new UnsupportedOperationException("getSwitchTargets");
}
}
/**
* Returns a constant pool item.
*/
public ConstantPoolEntry getConstantArg()
{
switch (getOpcode()) {
case LDC:
return _javaClass.getConstantPool().getEntry(getByteArg());
case LDC_W:
return _javaClass.getConstantPool().getEntry(getShortArg());
default:
throw new UnsupportedOperationException();
}
}
/**
* Reads a byte argument.
*/
public int getByteArg()
{
return getCode()[_offset + 1];
}
/**
* Gets a byte arg
*/
public int getByteArg(int offset)
{
return getByte(_offset + offset);
}
/**
* Sets a byte value.
*/
public void setByteArg(int offset, int value)
{
getCode()[_offset + offset + 0] = (byte) value;
}
/**
* Reads a short argument.
*/
public int getShortArg()
{
return getShort(_offset + 1);
}
/**
* Sets a short value.
*/
public int getShortArg(int offset)
{
return getShort(_offset + offset);
}
/**
* Sets a short value.
*/
public void setShortArg(int offset, int value)
{
setShort(_offset + offset, value);
}
/**
* Sets a short value.
*/
public void setShort(int offset, int value)
{
byte []code = getCode();
code[offset + 0] = (byte) (value >> 8);
code[offset + 1] = (byte) (value);
}
/**
* Reads an integer.
*/
public int getIntArg()
{
return getInt(_offset + 1);
}
/**
* Sets a short value.
*/
public void setInt(int offset, int value)
{
byte []code = getCode();
code[offset + 0] = (byte) (value >> 24);
code[offset + 1] = (byte) (value >> 16);
code[offset + 2] = (byte) (value >> 8);
code[offset + 3] = (byte) (value);
}
/**
* Reads a byte value.
*/
public int getByte(int offset)
{
return getCode()[offset + 0] & 0xff;
}
/**
* Reads a short value.
*/
public int getShort(int offset)
{
int b0 = getCode()[offset + 0] & 0xff;
int b1 = getCode()[offset + 1] & 0xff;
return (short) ((b0 << 8) + b1);
}
/**
* Reads an int argument.
*/
public int getInt(int offset)
{
byte []code = getCode();
int b0 = code[offset + 0] & 0xff;
int b1 = code[offset + 1] & 0xff;
int b2 = code[offset + 2] & 0xff;
int b3 = code[offset + 3] & 0xff;
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
}
/**
* Analyzes the code for a method
*/
public void analyze(Analyzer analyzer)
throws Exception
{
analyze(analyzer, true);
}
/**
* Analyzes the code for a method
*/
public void analyze(Analyzer analyzer, boolean allowFlow)
throws Exception
{
analyzeImpl(analyzer, allowFlow, new IntArray(), new IntArray());
}
/**
* Analyzes the code for a method
*/
protected void analyzeImpl(Analyzer analyzer, boolean allowFlow,
IntArray pendingTargets,
IntArray completedTargets)
throws Exception
{
setOffset(0);
pendingTargets.add(0);
ArrayList exns;
exns = getExceptions();
for (int i = 0; i < exns.size(); i++) {
CodeAttribute.ExceptionItem exn = exns.get(i);
pendingTargets.add(exn.getHandler());
}
analyze(analyzer, allowFlow, pendingTargets, completedTargets);
}
/**
* Analyzes the code for a basic block.
*/
private void analyze(Analyzer analyzer,
boolean allowFlow,
IntArray pendingTargets,
IntArray completedTargets)
throws Exception
{
pending:
while (pendingTargets.size() > 0) {
int pc = pendingTargets.pop();
if (allowFlow) {
if (completedTargets.contains(pc))
continue pending;
completedTargets.add(pc);
}
setOffset(pc);
flow:
do {
pc = getOffset();
if (pc < 0)
throw new IllegalStateException();
if (! allowFlow) {
if (completedTargets.contains(pc))
break flow;
completedTargets.add(pc);
}
if (isBranch()) {
int targetPC = getBranchTarget();
if (! pendingTargets.contains(targetPC))
pendingTargets.add(targetPC);
}
else if (isSwitch()) {
int []switchTargets = getSwitchTargets();
for (int i = 0; i < switchTargets.length; i++) {
if (! pendingTargets.contains(switchTargets[i]))
pendingTargets.add(switchTargets[i]);
}
}
analyzer.analyze(this);
} while (next());
}
}
public static final int NOP = 0x00;
public static final int ACONST_NULL = 0x01;
public static final int ICONST_M1 = 0x02;
public static final int ICONST_0 = 0x03;
public static final int ICONST_1 = 0x04;
public static final int ICONST_2 = 0x05;
public static final int ICONST_3 = 0x06;
public static final int ICONST_4 = 0x07;
public static final int ICONST_5 = 0x08;
public static final int LCONST_0 = 0x09;
public static final int LCONST_1 = 0x0a;
public static final int FCONST_0 = 0x0b;
public static final int FCONST_1 = 0x0c;
public static final int FCONST_2 = 0x0d;
public static final int DCONST_0 = 0x0e;
public static final int DCONST_1 = 0x0f;
public static final int BIPUSH = 0x10;
public static final int SIPUSH = 0x11;
public static final int LDC = 0x12;
public static final int LDC_W = 0x13;
public static final int LDC2_W = 0x14;
public static final int ILOAD = 0x15;
public static final int LLOAD = 0x16;
public static final int FLOAD = 0x17;
public static final int DLOAD = 0x18;
public static final int ALOAD = 0x19;
public static final int ILOAD_0 = 0x1a;
public static final int ILOAD_1 = 0x1b;
public static final int ILOAD_2 = 0x1c;
public static final int ILOAD_3 = 0x1d;
public static final int LLOAD_0 = 0x1e;
public static final int LLOAD_1 = 0x1f;
public static final int LLOAD_2 = 0x20;
public static final int LLOAD_3 = 0x21;
public static final int FLOAD_0 = 0x22;
public static final int FLOAD_1 = 0x23;
public static final int FLOAD_2 = 0x24;
public static final int FLOAD_3 = 0x25;
public static final int DLOAD_0 = 0x26;
public static final int DLOAD_1 = 0x27;
public static final int DLOAD_2 = 0x28;
public static final int DLOAD_3 = 0x29;
public static final int ALOAD_0 = 0x2a;
public static final int ALOAD_1 = 0x2b;
public static final int ALOAD_2 = 0x2c;
public static final int ALOAD_3 = 0x2d;
public static final int IALOAD = 0x2e;
public static final int LALOAD = 0x2f;
public static final int FALOAD = 0x30;
public static final int DALOAD = 0x31;
public static final int AALOAD = 0x32;
public static final int BALOAD = 0x33;
public static final int CALOAD = 0x34;
public static final int SALOAD = 0x35;
public static final int ISTORE = 0x36;
public static final int LSTORE = 0x37;
public static final int FSTORE = 0x38;
public static final int DSTORE = 0x39;
public static final int ASTORE = 0x3a;
public static final int ISTORE_0 = 0x3b;
public static final int ISTORE_1 = 0x3c;
public static final int ISTORE_2 = 0x3d;
public static final int ISTORE_3 = 0x3e;
public static final int LSTORE_0 = 0x3f;
public static final int LSTORE_1 = 0x40;
public static final int LSTORE_2 = 0x41;
public static final int LSTORE_3 = 0x42;
public static final int FSTORE_0 = 0x43;
public static final int FSTORE_1 = 0x44;
public static final int FSTORE_2 = 0x45;
public static final int FSTORE_3 = 0x46;
public static final int DSTORE_0 = 0x47;
public static final int DSTORE_1 = 0x48;
public static final int DSTORE_2 = 0x49;
public static final int DSTORE_3 = 0x4a;
public static final int ASTORE_0 = 0x4b;
public static final int ASTORE_1 = 0x4c;
public static final int ASTORE_2 = 0x4d;
public static final int ASTORE_3 = 0x4e;
public static final int IASTORE = 0x4f;
public static final int LASTORE = 0x50;
public static final int FASTORE = 0x51;
public static final int DASTORE = 0x52;
public static final int AASTORE = 0x53;
public static final int BASTORE = 0x54;
public static final int CASTORE = 0x55;
public static final int SASTORE = 0x56;
public static final int POP = 0x57;
public static final int POP2 = 0x58;
public static final int DUP = 0x59;
public static final int DUP_X1 = 0x5a;
public static final int DUP_X2 = 0x5b;
public static final int DUP2 = 0x5c;
public static final int DUP2_X1 = 0x5d;
public static final int DUP2_X2 = 0x5e;
public static final int SWAP = 0x5f;
public static final int IADD = 0x60;
public static final int LADD = 0x61;
public static final int FADD = 0x62;
public static final int DADD = 0x63;
public static final int ISUB = 0x64;
public static final int LSUB = 0x65;
public static final int FSUB = 0x66;
public static final int DSUB = 0x67;
public static final int IMUL = 0x68;
public static final int LMUL = 0x69;
public static final int FMUL = 0x6a;
public static final int DMUL = 0x6b;
public static final int IDIV = 0x6c;
public static final int LDIV = 0x6d;
public static final int FDIV = 0x6e;
public static final int DDIV = 0x6f;
public static final int IREM = 0x70;
public static final int LREM = 0x71;
public static final int FREM = 0x72;
public static final int DREM = 0x73;
public static final int INEG = 0x74;
public static final int LNEG = 0x75;
public static final int FNEG = 0x76;
public static final int DNEG = 0x77;
public static final int ISHL = 0x78;
public static final int LSHL = 0x79;
public static final int ISHR = 0x7a;
public static final int LSHR = 0x7b;
public static final int IUSHR = 0x7c;
public static final int LUSHR = 0x7d;
public static final int IAND = 0x7e;
public static final int LAND = 0x7f;
public static final int IOR = 0x80;
public static final int LOR = 0x81;
public static final int IXOR = 0x82;
public static final int LXOR = 0x83;
public static final int IINC = 0x84;
public static final int I2L = 0x85;
public static final int I2F = 0x86;
public static final int I2D = 0x87;
public static final int L2I = 0x88;
public static final int L2F = 0x89;
public static final int L2D = 0x8a;
public static final int F2I = 0x8b;
public static final int F2L = 0x8c;
public static final int F2D = 0x8d;
public static final int D2I = 0x8e;
public static final int D2L = 0x8f;
public static final int D2F = 0x90;
public static final int I2B = 0x91;
public static final int I2C = 0x92;
public static final int I2S = 0x93;
public static final int LCMP = 0x94;
public static final int FCMPL = 0x95;
public static final int FCMPG = 0x96;
public static final int DCMPL = 0x97;
public static final int DCMPG = 0x98;
public static final int IFEQ = 0x99;
public static final int IFNE = 0x9a;
public static final int IFLT = 0x9b;
public static final int IFGE = 0x9c;
public static final int IFGT = 0x9d;
public static final int IFLE = 0x9e;
public static final int IF_ICMPEQ = 0x9f;
public static final int IF_ICMPNE = 0xa0;
public static final int IF_ICMPLT = 0xa1;
public static final int IF_ICMPGE = 0xa2;
public static final int IF_ICMPGT = 0xa3;
public static final int IF_ICMPLE = 0xa4;
public static final int IF_ACMPEQ = 0xa5;
public static final int IF_ACMPNE = 0xa6;
public static final int GOTO = 0xa7;
public static final int JSR = 0xa8;
public static final int RET = 0xa9;
public static final int TABLESWITCH = 0xaa;
public static final int LOOKUPSWITCH = 0xab;
public static final int IRETURN = 0xac;
public static final int LRETURN = 0xad;
public static final int FRETURN = 0xae;
public static final int DRETURN = 0xaf;
public static final int ARETURN = 0xb0;
public static final int RETURN = 0xb1;
public static final int GETSTATIC = 0xb2;
public static final int PUTSTATIC = 0xb3;
public static final int GETFIELD = 0xb4;
public static final int PUTFIELD = 0xb5;
public static final int INVOKEVIRTUAL = 0xb6;
public static final int INVOKESPECIAL = 0xb7;
public static final int INVOKESTATIC = 0xb8;
public static final int INVOKEINTERFACE = 0xb9;
public static final int RESERVED_0 = 0xba;
public static final int NEW = 0xbb;
public static final int NEWARRAY = 0xbc;
public static final int ANEWARRAY = 0xbd;
public static final int ARRAYLENGTH = 0xbe;
public static final int ATHROW = 0xbf;
public static final int CHECKCAST = 0xc0;
public static final int INSTANCEOF = 0xc1;
public static final int MONITORENTER = 0xc2;
public static final int MONITOREXIT = 0xc3;
public static final int WIDE = 0xc4;
public static final int MULTIANEWARRAY = 0xc5;
public static final int IFNULL = 0xc6;
public static final int IFNONNULL = 0xc7;
public static final int GOTO_W = 0xc8;
public static final int JSR_W = 0xc9;
// the reset are reserved
private static final int OP_LEN[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */
1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 10 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 30 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 */
0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, /* 90 */
2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 99, 99, 0, 0, 0, 0, /* a0 */
0, 0, 2, 2, 2, 2, 2, 2, 2, 4, 4, 2, 1, 2, 0, 0, /* b0 */
2, 2, 0, 0, 99, 3, 2, 2, 4, 4, -1, -1, -1, -1, -1, -1, /* c0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy