/*
* This file is part of JOP, the Java Optimized Processor
* see <http://www.jopdesign.com/>
*
* Copyright (C) 2011, Stefan Hepp (stefan@stefant.org).
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.common.type;
import com.jopdesign.common.misc.AppInfoError;
import com.jopdesign.common.misc.MiscUtils;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.ANEWARRAY;
import org.apache.bcel.generic.ArithmeticInstruction;
import org.apache.bcel.generic.ArrayInstruction;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.CHECKCAST;
import org.apache.bcel.generic.CPInstruction;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.ConstantPushInstruction;
import org.apache.bcel.generic.ConversionInstruction;
import org.apache.bcel.generic.FieldInstruction;
import org.apache.bcel.generic.GETFIELD;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.LoadInstruction;
import org.apache.bcel.generic.MULTIANEWARRAY;
import org.apache.bcel.generic.NEW;
import org.apache.bcel.generic.NEWARRAY;
import org.apache.bcel.generic.PUTFIELD;
import org.apache.bcel.generic.PUTSTATIC;
import org.apache.bcel.generic.ReturnInstruction;
import org.apache.bcel.generic.StoreInstruction;
import org.apache.bcel.generic.Type;
import org.apache.bcel.generic.TypedInstruction;
import java.util.Arrays;
/**
* Just a container of various helper methods to work with types
* @author Stefan Hepp (stefan@stefant.org)
*/
public class StackHelper {
public static Type[] consumeStack(ConstantPoolGen cpg, Instruction instruction) {
// TODO any better (BCEL) way to do this?
switch (instruction.getOpcode()) {
case Constants.NOP:
case Constants.ACONST_NULL:
case Constants.ICONST_M1:
case Constants.ICONST_0:
case Constants.ICONST_1:
case Constants.ICONST_2:
case Constants.ICONST_3:
case Constants.ICONST_4:
case Constants.ICONST_5:
case Constants.BIPUSH:
case Constants.SIPUSH:
case Constants.LCONST_0:
case Constants.LCONST_1:
case Constants.FCONST_0:
case Constants.FCONST_1:
case Constants.FCONST_2:
case Constants.DCONST_0:
case Constants.DCONST_1:
case Constants.LDC:
case Constants.LDC_W:
case Constants.LDC2_W:
case Constants.ILOAD_0:
case Constants.ILOAD_1:
case Constants.ILOAD_2:
case Constants.ILOAD_3:
case Constants.ILOAD:
case Constants.LLOAD_0:
case Constants.LLOAD_1:
case Constants.LLOAD_2:
case Constants.LLOAD_3:
case Constants.LLOAD:
case Constants.FLOAD_0:
case Constants.FLOAD_1:
case Constants.FLOAD_2:
case Constants.FLOAD_3:
case Constants.FLOAD:
case Constants.DLOAD_0:
case Constants.DLOAD_1:
case Constants.DLOAD_2:
case Constants.DLOAD_3:
case Constants.DLOAD:
case Constants.ALOAD_0:
case Constants.ALOAD_1:
case Constants.ALOAD_2:
case Constants.ALOAD_3:
case Constants.ALOAD:
return Type.NO_ARGS;
case Constants.ISTORE_0:
case Constants.ISTORE_1:
case Constants.ISTORE_2:
case Constants.ISTORE_3:
case Constants.ISTORE:
case Constants.ASTORE_0:
case Constants.ASTORE_1:
case Constants.ASTORE_2:
case Constants.ASTORE_3:
case Constants.ASTORE:
case Constants.LSTORE_0:
case Constants.LSTORE_1:
case Constants.LSTORE_2:
case Constants.LSTORE_3:
case Constants.LSTORE:
case Constants.DSTORE_0:
case Constants.DSTORE_1:
case Constants.DSTORE_2:
case Constants.DSTORE_3:
case Constants.DSTORE:
case Constants.FSTORE_0:
case Constants.FSTORE_1:
case Constants.FSTORE_2:
case Constants.FSTORE_3:
case Constants.FSTORE: {
StoreInstruction instr = (StoreInstruction) instruction;
return new Type[] { instr.getType(cpg) };
}
case Constants.DUP:
return new Type[] {Type.UNKNOWN};
case Constants.DUP_X1:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN};
case Constants.DUP_X2:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN};
case Constants.DUP2:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN};
case Constants.DUP2_X1:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN};
case Constants.DUP2_X2:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN};
case Constants.POP:
return new Type[] {Type.UNKNOWN};
case Constants.POP2:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN};
case Constants.SWAP:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN};
case Constants.IASTORE:
case Constants.FASTORE:
case Constants.LASTORE:
case Constants.DASTORE:
case Constants.CASTORE:
case Constants.SASTORE:
case Constants.BASTORE:
case Constants.AASTORE: {
Type t = ((ArrayInstruction)instruction).getType(cpg);
return new Type[] { new ArrayType(t, 1), Type.INT, t };
}
case Constants.IALOAD:
case Constants.LALOAD:
case Constants.FALOAD:
case Constants.DALOAD:
case Constants.CALOAD:
case Constants.SALOAD:
case Constants.BALOAD:
case Constants.AALOAD: {
Type t = ((ArrayInstruction)instruction).getType(cpg);
return new Type[] { new ArrayType(t, 1), Type.INT };
}
case Constants.IINC:
return Type.NO_ARGS;
case Constants.IADD:
case Constants.ISUB:
case Constants.IMUL:
case Constants.IDIV:
case Constants.IREM:
case Constants.ISHL:
case Constants.ISHR:
case Constants.IUSHR:
case Constants.IAND:
case Constants.IOR:
case Constants.IXOR:
return new Type[] {Type.INT, Type.INT};
case Constants.INEG:
return new Type[] {Type.INT};
case Constants.LADD:
case Constants.LSUB:
case Constants.LMUL:
case Constants.LDIV:
case Constants.LREM:
case Constants.LAND:
case Constants.LOR:
case Constants.LXOR:
return new Type[] {Type.LONG, Type.LONG};
case Constants.LSHL:
case Constants.LSHR:
case Constants.LUSHR:
return new Type[] {Type.LONG, Type.INT};
case Constants.LNEG:
return new Type[] {Type.LONG};
case Constants.FADD:
case Constants.FSUB:
case Constants.FMUL:
case Constants.FDIV:
case Constants.FREM:
return new Type[] {Type.FLOAT, Type.FLOAT};
case Constants.FNEG:
return new Type[] {Type.FLOAT};
case Constants.DADD:
case Constants.DSUB:
case Constants.DMUL:
case Constants.DDIV:
case Constants.DREM:
return new Type[] {Type.DOUBLE, Type.DOUBLE};
case Constants.DNEG:
return new Type[] {Type.DOUBLE};
case Constants.I2B:
case Constants.I2C:
case Constants.I2S:
case Constants.I2L:
case Constants.I2F:
case Constants.I2D:
return new Type[] {Type.INT};
case Constants.L2I:
case Constants.L2F:
case Constants.L2D:
return new Type[] {Type.LONG};
case Constants.F2I:
case Constants.F2L:
case Constants.F2D:
return new Type[] {Type.FLOAT};
case Constants.D2I:
case Constants.D2L:
case Constants.D2F:
return new Type[] {Type.FLOAT};
case Constants.LCMP:
case Constants.FCMPL:
case Constants.FCMPG:
case Constants.DCMPL:
case Constants.DCMPG: {
Type t = ((TypedInstruction)instruction).getType(cpg);
return new Type[] {t, t};
}
case Constants.IFNULL:
case Constants.IFNONNULL:
return new Type[] {Type.OBJECT};
case Constants.IFEQ:
case Constants.IFNE:
case Constants.IFLT:
case Constants.IFGE:
case Constants.IFLE:
case Constants.IFGT:
return new Type[] {Type.INT};
case Constants.IF_ICMPEQ:
case Constants.IF_ICMPNE:
case Constants.IF_ICMPLT:
case Constants.IF_ICMPGE:
case Constants.IF_ICMPGT:
case Constants.IF_ICMPLE:
return new Type[] {Type.INT, Type.INT};
case Constants.IF_ACMPEQ:
case Constants.IF_ACMPNE:
return new Type[] {Type.OBJECT, Type.OBJECT};
case Constants.GOTO:
case Constants.JSR:
case Constants.RET:
return Type.NO_ARGS;
case Constants.RETURN:
return Type.NO_ARGS;
case Constants.ARETURN:
case Constants.IRETURN:
case Constants.LRETURN:
case Constants.FRETURN:
case Constants.DRETURN: {
Type t = ((ReturnInstruction)instruction).getType();
return new Type[] {t};
}
case Constants.LOOKUPSWITCH:
case Constants.TABLESWITCH:
return new Type[] {Type.INT};
case Constants.PUTFIELD: {
PUTFIELD p = (PUTFIELD)instruction;
return new Type[] {p.getReferenceType(cpg), p.getFieldType(cpg)};
}
case Constants.PUTSTATIC: {
PUTSTATIC p = (PUTSTATIC)instruction;
return new Type[] {p.getFieldType(cpg)};
}
case Constants.GETFIELD: {
GETFIELD g = (GETFIELD)instruction;
return new Type[] {g.getReferenceType(cpg)};
}
case Constants.GETSTATIC:
return Type.NO_ARGS;
case Constants.INVOKESTATIC: {
InvokeInstruction invoke = (InvokeInstruction)instruction;
return invoke.getArgumentTypes(cpg);
}
case Constants.INVOKEVIRTUAL:
case Constants.INVOKEINTERFACE:
case Constants.INVOKESPECIAL: {
InvokeInstruction invoke = (InvokeInstruction)instruction;
return MiscUtils.concat(invoke.getReferenceType(cpg), invoke.getArgumentTypes(cpg));
}
case Constants.MONITORENTER:
case Constants.MONITOREXIT:
return new Type[] {Type.OBJECT};
case Constants.ATHROW:
return new Type[] {Type.OBJECT};
case Constants.CHECKCAST:
case Constants.INSTANCEOF:
return new Type[] {Type.OBJECT};
case Constants.NEW:
return Type.NO_ARGS;
case Constants.NEWARRAY:
case Constants.ANEWARRAY:
return new Type[] {Type.INT};
case Constants.MULTIANEWARRAY: {
Type[] t = new Type[((MULTIANEWARRAY)instruction).getDimensions()];
Arrays.fill(t, Type.INT);
return t;
}
case Constants.ARRAYLENGTH:
return new Type[] {new ArrayType(Type.UNKNOWN, 1)};
default:
throw new AppInfoError("Instruction not supported: "+instruction);
}
}
public static Type[] produceStack(ConstantPoolGen cpg, Instruction instruction) {
switch (instruction.getOpcode()) {
case Constants.NOP:
return Type.NO_ARGS;
case Constants.ACONST_NULL:
return new Type[] {Type.NULL};
case Constants.ICONST_M1:
case Constants.ICONST_0:
case Constants.ICONST_1:
case Constants.ICONST_2:
case Constants.ICONST_3:
case Constants.ICONST_4:
case Constants.ICONST_5:
case Constants.BIPUSH:
case Constants.SIPUSH:
case Constants.LCONST_0:
case Constants.LCONST_1:
case Constants.FCONST_0:
case Constants.FCONST_1:
case Constants.FCONST_2:
case Constants.DCONST_0:
case Constants.DCONST_1: {
ConstantPushInstruction instr = (ConstantPushInstruction)instruction;
return new Type[] {instr.getType(cpg)};
}
case Constants.LDC:
case Constants.LDC_W:
case Constants.LDC2_W: {
CPInstruction instr = (CPInstruction) instruction;
return new Type[] {instr.getType(cpg)};
}
case Constants.ISTORE_0:
case Constants.ISTORE_1:
case Constants.ISTORE_2:
case Constants.ISTORE_3:
case Constants.ISTORE:
case Constants.ASTORE_0:
case Constants.ASTORE_1:
case Constants.ASTORE_2:
case Constants.ASTORE_3:
case Constants.ASTORE:
case Constants.LSTORE_0:
case Constants.LSTORE_1:
case Constants.LSTORE_2:
case Constants.LSTORE_3:
case Constants.LSTORE:
case Constants.DSTORE_0:
case Constants.DSTORE_1:
case Constants.DSTORE_2:
case Constants.DSTORE_3:
case Constants.DSTORE:
case Constants.FSTORE_0:
case Constants.FSTORE_1:
case Constants.FSTORE_2:
case Constants.FSTORE_3:
case Constants.FSTORE:
return Type.NO_ARGS;
case Constants.ILOAD_0:
case Constants.ILOAD_1:
case Constants.ILOAD_2:
case Constants.ILOAD_3:
case Constants.ILOAD:
case Constants.LLOAD_0:
case Constants.LLOAD_1:
case Constants.LLOAD_2:
case Constants.LLOAD_3:
case Constants.LLOAD:
case Constants.FLOAD_0:
case Constants.FLOAD_1:
case Constants.FLOAD_2:
case Constants.FLOAD_3:
case Constants.FLOAD:
case Constants.DLOAD_0:
case Constants.DLOAD_1:
case Constants.DLOAD_2:
case Constants.DLOAD_3:
case Constants.DLOAD:
case Constants.ALOAD_0:
case Constants.ALOAD_1:
case Constants.ALOAD_2:
case Constants.ALOAD_3:
case Constants.ALOAD: {
LoadInstruction instr = (LoadInstruction) instruction;
return new Type[] {instr.getType(cpg)};
}
case Constants.DUP:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN};
case Constants.DUP_X1:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN};
case Constants.DUP_X2:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN};
case Constants.DUP2:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN};
case Constants.DUP2_X1:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN};
case Constants.DUP2_X2:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN,
Type.UNKNOWN, Type.UNKNOWN, Type.UNKNOWN};
case Constants.POP:
case Constants.POP2:
return Type.NO_ARGS;
case Constants.SWAP:
return new Type[] {Type.UNKNOWN, Type.UNKNOWN};
case Constants.IASTORE:
case Constants.LASTORE:
case Constants.FASTORE:
case Constants.DASTORE:
case Constants.CASTORE:
case Constants.SASTORE:
case Constants.BASTORE:
case Constants.AASTORE:
return Type.NO_ARGS;
case Constants.IALOAD:
case Constants.LALOAD:
case Constants.FALOAD:
case Constants.DALOAD:
case Constants.CALOAD:
case Constants.SALOAD:
case Constants.BALOAD:
case Constants.AALOAD:
return new Type[] { ((ArrayInstruction)instruction).getType(cpg) };
case Constants.IINC:
return Type.NO_ARGS;
case Constants.IADD:
case Constants.ISUB:
case Constants.IMUL:
case Constants.IDIV:
case Constants.INEG:
case Constants.IREM:
case Constants.LADD:
case Constants.LSUB:
case Constants.LMUL:
case Constants.LDIV:
case Constants.LNEG:
case Constants.LREM:
case Constants.FADD:
case Constants.FSUB:
case Constants.FMUL:
case Constants.FDIV:
case Constants.FNEG:
case Constants.FREM:
case Constants.DADD:
case Constants.DSUB:
case Constants.DMUL:
case Constants.DDIV:
case Constants.DNEG:
case Constants.DREM:
case Constants.ISHL:
case Constants.ISHR:
case Constants.IUSHR:
case Constants.LSHL:
case Constants.LSHR:
case Constants.LUSHR:
case Constants.IAND:
case Constants.IOR:
case Constants.IXOR:
case Constants.LAND:
case Constants.LOR:
case Constants.LXOR:
return new Type[] { ((ArithmeticInstruction)instruction).getType(cpg) };
case Constants.I2B:
case Constants.I2C:
case Constants.I2S:
case Constants.I2L:
case Constants.I2F:
case Constants.I2D:
case Constants.L2I:
case Constants.L2F:
case Constants.L2D:
case Constants.F2I:
case Constants.F2L:
case Constants.F2D:
case Constants.D2I:
case Constants.D2L:
case Constants.D2F:
return new Type[] { ((ConversionInstruction)instruction).getType(cpg) };
case Constants.LCMP:
case Constants.FCMPL:
case Constants.FCMPG:
case Constants.DCMPL:
case Constants.DCMPG:
return new Type[] {Type.INT};
case Constants.IFNULL:
case Constants.IFNONNULL:
case Constants.IFEQ:
case Constants.IFNE:
case Constants.IFLT:
case Constants.IFGE:
case Constants.IFLE:
case Constants.IFGT:
case Constants.IF_ICMPEQ:
case Constants.IF_ICMPNE:
case Constants.IF_ICMPLT:
case Constants.IF_ICMPGE:
case Constants.IF_ICMPGT:
case Constants.IF_ICMPLE:
case Constants.IF_ACMPEQ:
case Constants.IF_ACMPNE:
case Constants.GOTO:
case Constants.ARETURN:
case Constants.RETURN:
case Constants.IRETURN:
case Constants.LRETURN:
case Constants.FRETURN:
case Constants.DRETURN:
case Constants.LOOKUPSWITCH:
case Constants.TABLESWITCH:
return Type.NO_ARGS;
case Constants.PUTFIELD:
case Constants.PUTSTATIC:
return Type.NO_ARGS;
case Constants.GETFIELD:
case Constants.GETSTATIC: {
FieldInstruction instr = (FieldInstruction)instruction;
return new Type[] {instr.getFieldType(cpg)};
}
case Constants.INVOKEVIRTUAL:
case Constants.INVOKEINTERFACE:
case Constants.INVOKESTATIC:
case Constants.INVOKESPECIAL: {
InvokeInstruction invoke = (InvokeInstruction)instruction;
Type t = invoke.getReturnType(cpg);
if (Type.VOID.equals(t)) {
return Type.NO_ARGS;
} else {
return new Type[] {t};
}
}
case Constants.MONITORENTER:
case Constants.MONITOREXIT:
case Constants.ATHROW:
return Type.NO_ARGS;
case Constants.CHECKCAST:
return new Type[] { ((CHECKCAST)instruction).getType(cpg) };
case Constants.INSTANCEOF:
return new Type[] { Type.INT };
case Constants.NEW:
return new Type[] { ((NEW)instruction).getType(cpg) };
case Constants.NEWARRAY: {
Type t = ((NEWARRAY)instruction).getType();
return new Type[] { new ArrayType(t, 1) };
}
case Constants.ANEWARRAY: {
Type t = ((ANEWARRAY)instruction).getType(cpg);
return new Type[] { new ArrayType(t, 1) };
}
case Constants.MULTIANEWARRAY: {
MULTIANEWARRAY instr = (MULTIANEWARRAY) instruction;
return new Type[] { new ArrayType(instr.getType(cpg), instr.getDimensions()) };
}
case Constants.ARRAYLENGTH:
return new Type[] {Type.INT};
default:
throw new AppInfoError("Instruction not supported: "+instruction);
}
}
}