use of org.apache.bcel.generic.Instruction in project jop by jop-devel.
the class LoopBounds method transfer.
public ContextMap<CallString, Map<Location, ValueMapping>> transfer(InstructionHandle stmt, FlowEdge edge, ContextMap<CallString, Map<Location, ValueMapping>> input, Interpreter<CallString, Map<Location, ValueMapping>> interpreter, Map<InstructionHandle, ContextMap<CallString, Map<Location, ValueMapping>>> state) {
Context context = new Context(input.getContext());
Map<Location, ValueMapping> in = (Map<Location, ValueMapping>) input.get(context.callString);
ContextMap<CallString, Map<Location, ValueMapping>> retval = new ContextMap<CallString, Map<Location, ValueMapping>>(context, new LinkedHashMap<CallString, Map<Location, ValueMapping>>());
Instruction instruction = stmt.getInstruction();
// shortcut for infeasible paths
if (in == null) {
context.stackPtr += instruction.produceStack(context.constPool()) - instruction.consumeStack(context.constPool());
return retval;
}
Map<Location, ValueMapping> result = new LinkedHashMap<Location, ValueMapping>();
retval.put(context.callString, result);
switch(instruction.getOpcode()) {
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:
{
ConstantPushInstruction instr = (ConstantPushInstruction) instruction;
result = new LinkedHashMap<Location, ValueMapping>(in);
retval.put(context.callString, result);
int value = instr.getValue().intValue();
result.put(new Location(context.stackPtr), new ValueMapping(value));
}
break;
case Constants.ACONST_NULL:
result = in;
retval.put(context.callString, result);
break;
case Constants.LDC:
case Constants.LDC_W:
{
LDC instr = (LDC) instruction;
result = new LinkedHashMap<Location, ValueMapping>(in);
retval.put(context.callString, result);
Type type = instr.getType(context.constPool());
if (type.equals(Type.INT)) {
Integer value = (Integer) instr.getValue(context.constPool());
result.put(new Location(context.stackPtr), new ValueMapping(value));
} else if (type.equals(Type.STRING)) {
String value = (String) instr.getValue(context.constPool());
String name = "char[]";
name += "@" + context.method() + ":" + stmt.getPosition();
result.put(new Location(name + ".length"), new ValueMapping(value.length()));
// System.out.println(name+": \""+value+"\"");
}
}
break;
case Constants.LDC2_W:
result = in;
retval.put(context.callString, result);
break;
case Constants.ISTORE_0:
case Constants.ISTORE_1:
case Constants.ISTORE_2:
case Constants.ISTORE_3:
case Constants.ISTORE:
{
StoreInstruction instr = (StoreInstruction) instruction;
int index = instr.getIndex();
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 1 && l.stackLoc != index) {
result.put(l, in.get(l));
}
if (l.stackLoc == context.stackPtr - 1) {
ValueMapping v = new ValueMapping(in.get(l), true);
if (in.get(l).source == null || in.get(l).source.stackLoc != index) {
v.defscope = ValueMapping.scope;
}
result.put(new Location(index), v);
}
}
}
break;
case Constants.ASTORE_0:
case Constants.ASTORE_1:
case Constants.ASTORE_2:
case Constants.ASTORE_3:
case Constants.ASTORE:
result = in;
retval.put(context.callString, result);
break;
case Constants.LSTORE_0:
case Constants.LSTORE_1:
case Constants.LSTORE_2:
case Constants.LSTORE_3:
case Constants.LSTORE:
// drop top entries to avoid clobbering
filterSet(in, result, context.stackPtr - 2);
break;
case Constants.ILOAD_0:
case Constants.ILOAD_1:
case Constants.ILOAD_2:
case Constants.ILOAD_3:
case Constants.ILOAD:
{
LoadInstruction instr = (LoadInstruction) instruction;
filterSet(in, result, context.stackPtr);
int index = instr.getIndex();
for (Location l : in.keySet()) {
if (l.stackLoc == index) {
ValueMapping m = new ValueMapping(in.get(l), true);
m.source = l;
result.put(new Location(context.stackPtr), m);
}
}
}
break;
case Constants.ALOAD_0:
case Constants.ALOAD_1:
case Constants.ALOAD_2:
case Constants.ALOAD_3:
case Constants.ALOAD:
result = in;
retval.put(context.callString, result);
break;
case Constants.ARRAYLENGTH:
{
filterSet(in, result, context.stackPtr - 1);
DFATool p = interpreter.getDFATool();
Set<String> receivers = p.getReceivers(stmt, context.callString);
Location location = new Location(context.stackPtr - 1);
boolean valid = false;
if (receivers == null) {
System.out.println("no receivers at: " + context.callString.toStringList() + context.method() + stmt);
} else {
for (String arrayName : receivers) {
ValueMapping m = in.get(new Location(arrayName + ".length"));
if (m != null) {
ValueMapping value = new ValueMapping(m, false);
value.join(result.get(location));
result.put(location, value);
valid = true;
}
}
}
if (!valid) {
result.put(new Location(context.stackPtr - 1), new ValueMapping());
}
}
break;
case Constants.PUTFIELD:
{
PUTFIELD instr = (PUTFIELD) instruction;
int fieldSize = instr.getFieldType(context.constPool()).getSize();
for (Location l : in.keySet()) {
if (l.stackLoc >= 0 && l.stackLoc < context.stackPtr - 1 - fieldSize) {
result.put(l, in.get(l));
}
}
// System.out.println(context.stackPtr+","+fieldSize+": "+result);
DFATool p = interpreter.getDFATool();
Set<String> receivers = p.getReceivers(stmt, context.callString);
if (receivers == null) {
warnNoReceiver(context, stmt);
} else {
for (String fieldName : receivers) {
String f = fieldName.substring(fieldName.lastIndexOf("."), fieldName.length());
String strippedName;
if (fieldName.indexOf("@") >= 0) {
strippedName = fieldName.split("@")[0] + f;
} else {
strippedName = fieldName;
}
if (p.containsField(strippedName)) {
for (Location l : in.keySet()) {
if (l.stackLoc < 0 && !receivers.contains(l.heapLoc)) {
result.put(l, in.get(l));
}
if (l.stackLoc == context.stackPtr - 1) {
result.put(new Location(fieldName), new ValueMapping(in.get(l), false));
}
}
}
}
}
}
break;
case Constants.GETFIELD:
{
GETFIELD instr = (GETFIELD) instruction;
filterSet(in, result, context.stackPtr - 1);
DFATool p = interpreter.getDFATool();
Set<String> receivers = p.getReceivers(stmt, context.callString);
Location location = new Location(context.stackPtr - 1);
boolean valid = false;
if (receivers == null) {
warnNoReceiver(context, stmt);
} else {
for (String fieldName : receivers) {
String f = fieldName.substring(fieldName.lastIndexOf("."), fieldName.length());
String strippedName;
if (fieldName.indexOf("@") >= 0) {
strippedName = fieldName.split("@")[0] + f;
} else {
strippedName = fieldName;
}
if (p.containsField(strippedName)) {
for (Location l : in.keySet()) {
if (l.heapLoc.equals(fieldName)) {
ValueMapping value = new ValueMapping(in.get(l), false);
value.join(result.get(location));
result.put(location, value);
valid = true;
}
}
}
}
}
if (!valid && !(instr.getFieldType(context.constPool()) instanceof ReferenceType)) {
result.put(new Location(context.stackPtr - 1), new ValueMapping());
}
}
break;
case Constants.PUTSTATIC:
{
PUTSTATIC instr = (PUTSTATIC) instruction;
int fieldSize = instr.getFieldType(context.constPool()).getSize();
for (Location l : in.keySet()) {
if (l.stackLoc >= 0 && l.stackLoc < context.stackPtr - fieldSize) {
result.put(l, in.get(l));
}
}
DFATool p = interpreter.getDFATool();
Set<String> receivers = p.getReceivers(stmt, context.callString);
for (String fieldName : receivers) {
if (p.containsField(fieldName)) {
for (Location l : in.keySet()) {
if (l.stackLoc < 0 && !receivers.contains(l.heapLoc)) {
result.put(l, in.get(l));
}
if (l.stackLoc == context.stackPtr - 1) {
result.put(new Location(fieldName), new ValueMapping(in.get(l), false));
}
}
}
}
}
break;
case Constants.GETSTATIC:
{
GETSTATIC instr = (GETSTATIC) instruction;
result = new LinkedHashMap<Location, ValueMapping>(in);
retval.put(context.callString, result);
DFATool p = interpreter.getDFATool();
Set<String> receivers = p.getReceivers(stmt, context.callString);
Location location = new Location(context.stackPtr);
boolean valid = false;
for (String fieldName : receivers) {
if (p.containsField(fieldName)) {
for (Location l : in.keySet()) {
if (l.heapLoc.equals(fieldName)) {
ValueMapping value = new ValueMapping(in.get(l), false);
value.join(result.get(location));
result.put(location, value);
valid = true;
}
}
}
}
if (!valid && !(instr.getFieldType(context.constPool()) instanceof ReferenceType)) {
result.put(new Location(context.stackPtr), new ValueMapping());
}
}
break;
case Constants.IASTORE:
case Constants.CASTORE:
case Constants.SASTORE:
case Constants.BASTORE:
{
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 3) {
result.put(l, in.get(l));
}
}
DFATool p = interpreter.getDFATool();
Set<String> receivers = p.getReceivers(stmt, context.callString);
if (receivers == null) {
warnNoReceiver(context, stmt);
break;
}
for (String name : receivers) {
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
Location loc = new Location(name);
ValueMapping val = new ValueMapping(in.get(l), false);
val.join(in.get(loc));
result.put(loc, val);
}
}
}
}
break;
case Constants.AASTORE:
{
filterSet(in, result, context.stackPtr - 3);
}
break;
case Constants.IALOAD:
case Constants.CALOAD:
case Constants.SALOAD:
case Constants.BALOAD:
{
filterSet(in, result, context.stackPtr - 2);
DFATool p = interpreter.getDFATool();
Location location = new Location(context.stackPtr - 2);
boolean valid = false;
Set<String> receivers = p.getReceivers(stmt, context.callString);
for (String name : receivers) {
for (Location l : in.keySet()) {
if (l.heapLoc.equals(name)) {
ValueMapping value = new ValueMapping(in.get(l), false);
value.join(result.get(location));
result.put(location, value);
valid = true;
}
}
}
if (!valid) {
result.put(new Location(context.stackPtr - 2), new ValueMapping(0));
}
}
break;
case Constants.AALOAD:
{
ValueMapping v = in.get(new Location(context.stackPtr - 1));
if (v == null) {
logger.warn("no value at: " + context.callString.toStringList() + context.method() + stmt);
} else {
recordArrayIndex(stmt, context, v.assigned);
}
filterSet(in, result, context.stackPtr - 2);
}
break;
case Constants.DUP:
{
for (Location l : in.keySet()) {
result.put(l, in.get(l));
if (l.stackLoc == context.stackPtr - 1) {
result.put(new Location(context.stackPtr), new ValueMapping(in.get(l), true));
}
}
}
break;
case Constants.DUP_X1:
{
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 2) {
result.put(l, in.get(l));
}
if (l.stackLoc == context.stackPtr - 1) {
result.put(new Location(context.stackPtr - 2), new ValueMapping(in.get(l), true));
result.put(new Location(context.stackPtr), new ValueMapping(in.get(l), true));
}
if (l.stackLoc == context.stackPtr - 2) {
result.put(new Location(context.stackPtr - 1), new ValueMapping(in.get(l), true));
}
}
}
break;
case Constants.DUP2:
{
for (Location l : in.keySet()) {
result.put(l, in.get(l));
if (l.stackLoc == context.stackPtr - 2) {
result.put(new Location(context.stackPtr), new ValueMapping(in.get(l), true));
}
if (l.stackLoc == context.stackPtr - 1) {
result.put(new Location(context.stackPtr + 1), new ValueMapping(in.get(l), true));
}
}
}
break;
case Constants.POP:
{
filterSet(in, result, context.stackPtr - 1);
}
break;
case Constants.POP2:
{
filterSet(in, result, context.stackPtr - 2);
}
break;
case Constants.IINC:
{
IINC instr = (IINC) instruction;
int index = instr.getIndex();
int increment = instr.getIncrement();
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr) {
result.put(l, in.get(l));
}
if (l.stackLoc == index) {
ValueMapping m = new ValueMapping(in.get(l), true);
m.assigned.add(increment);
m.constrained.add(increment);
Interval operand = new Interval(increment, increment);
if (m.increment != null && !m.softinc) {
m.increment.join(operand);
} else if (m.increment != null && m.softinc) {
if ((m.increment.getLb() < 0 && operand.getUb() > 0) || (m.increment.getUb() > 0 && operand.getLb() < 0)) {
m.increment.join(operand);
} else {
m.increment = operand;
}
m.softinc = false;
} else {
m.increment = operand;
m.softinc = false;
}
result.put(l, m);
}
}
}
break;
case Constants.IADD:
{
Interval operand = new Interval();
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
operand = in.get(l).assigned;
}
}
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 2) {
result.put(l, in.get(l));
} else if (l.stackLoc == context.stackPtr - 2) {
ValueMapping m = new ValueMapping(in.get(l), true);
m.assigned.add(operand);
m.constrained.add(operand);
if (m.increment != null && !m.softinc) {
m.increment.join(operand);
} else if (m.increment != null && m.softinc) {
if ((m.increment.getLb() < 0 && operand.getUb() > 0) || (m.increment.getUb() > 0 && operand.getLb() < 0)) {
m.increment.join(operand);
} else {
m.increment = operand;
}
m.softinc = false;
} else {
m.increment = operand;
m.softinc = false;
}
result.put(l, m);
}
}
}
break;
case Constants.ISUB:
{
Interval operand = new Interval();
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
operand = in.get(l).assigned;
}
}
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 2) {
result.put(l, in.get(l));
} else if (l.stackLoc == context.stackPtr - 2) {
ValueMapping m = new ValueMapping(in.get(l), true);
m.assigned.sub(operand);
m.constrained.sub(operand);
// decrement rather than increment
operand.neg();
if (m.increment != null && !m.softinc) {
m.increment.join(operand);
} else if (m.increment != null && m.softinc) {
if ((m.increment.getLb() < 0 && operand.getUb() > 0) || (m.increment.getUb() > 0 && operand.getLb() < 0)) {
m.increment.join(operand);
} else {
m.increment = operand;
}
m.softinc = false;
} else {
m.increment = operand;
m.softinc = false;
}
result.put(l, m);
}
}
}
break;
case Constants.INEG:
{
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 1) {
result.put(l, in.get(l));
} else if (l.stackLoc == context.stackPtr - 1) {
ValueMapping m = new ValueMapping(in.get(l), true);
m.assigned.neg();
m.constrained.neg();
m.increment = new Interval();
result.put(l, m);
}
}
}
break;
case Constants.IUSHR:
{
Interval operand = new Interval();
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
operand = in.get(l).assigned;
}
}
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 2) {
result.put(l, in.get(l));
} else if (l.stackLoc == context.stackPtr - 2) {
ValueMapping m = new ValueMapping(in.get(l), true);
m.assigned.ushr(operand);
m.constrained.ushr(operand);
m.increment = new Interval();
result.put(l, m);
}
}
}
break;
case Constants.ISHR:
{
Interval operand = new Interval();
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
operand = in.get(l).assigned;
}
}
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 2) {
result.put(l, in.get(l));
} else if (l.stackLoc == context.stackPtr - 2) {
ValueMapping m = new ValueMapping(in.get(l), true);
m.assigned.shr(operand);
m.constrained.shr(operand);
m.increment = new Interval();
result.put(l, m);
}
}
}
break;
case Constants.IMUL:
{
Interval operand = new Interval();
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
operand = in.get(l).assigned;
}
}
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 2) {
result.put(l, in.get(l));
} else if (l.stackLoc == context.stackPtr - 2) {
ValueMapping m = new ValueMapping(in.get(l), true);
m.assigned.mul(operand);
m.constrained.mul(operand);
m.increment = new Interval();
result.put(l, m);
}
}
}
break;
case Constants.IDIV:
{
Interval operand = new Interval();
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
operand = in.get(l).assigned;
}
}
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 2) {
result.put(l, in.get(l));
} else if (l.stackLoc == context.stackPtr - 2) {
ValueMapping m = new ValueMapping(in.get(l), true);
m.assigned.div(operand);
m.constrained.div(operand);
m.increment = new Interval();
result.put(l, m);
}
}
}
break;
case Constants.IAND:
case Constants.IOR:
case Constants.IXOR:
case Constants.IREM:
case Constants.ISHL:
{
// TODO: we could be more clever for some operations
for (Location l : in.keySet()) {
if (l.stackLoc < context.stackPtr - 2) {
result.put(l, in.get(l));
} else if (l.stackLoc == context.stackPtr - 2) {
ValueMapping m = new ValueMapping();
result.put(l, m);
}
}
}
break;
case Constants.I2B:
case Constants.I2C:
case Constants.I2S:
// TODO: is this really correct?
result = in;
retval.put(context.callString, result);
break;
case Constants.MONITORENTER:
result = in;
retval.put(context.callString, result);
context.syncLevel++;
break;
case Constants.MONITOREXIT:
result = in;
retval.put(context.callString, result);
context.syncLevel--;
if (context.syncLevel < 0) {
System.err.println("Synchronization level mismatch.");
System.exit(-1);
}
break;
case Constants.CHECKCAST:
result = in;
retval.put(context.callString, result);
break;
case Constants.INSTANCEOF:
{
filterSet(in, result, context.stackPtr - 1);
ValueMapping bool = new ValueMapping();
bool.assigned.setLb(0);
bool.assigned.setUb(1);
result.put(new Location(context.stackPtr - 1), bool);
}
break;
case Constants.NEW:
{
result = in;
retval.put(context.callString, result);
}
break;
case Constants.NEWARRAY:
{
NEWARRAY instr = (NEWARRAY) instruction;
String name = instr.getType().toString();
name += "@" + context.method() + ":" + stmt.getPosition();
filterSet(in, result, context.stackPtr - 1);
boolean valid = false;
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
result.put(new Location(name + ".length"), in.get(l));
recordSize(stmt, context, in.get(l).assigned);
valid = true;
}
}
if (!valid) {
ValueMapping v = new ValueMapping();
result.put(new Location(name + ".length"), v);
recordSize(stmt, context, v.assigned);
}
}
break;
case Constants.ANEWARRAY:
{
ANEWARRAY instr = (ANEWARRAY) instruction;
String name = instr.getType(context.constPool()).toString() + "[]";
name += "@" + context.method() + ":" + stmt.getPosition();
//System.out.println("NEW ARRAY: "+name);
filterSet(in, result, context.stackPtr - 1);
boolean valid = false;
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
result.put(new Location(name + ".length"), in.get(l));
recordSize(stmt, context, in.get(l).assigned);
valid = true;
}
}
if (!valid) {
ValueMapping v = new ValueMapping();
result.put(new Location(name + ".length"), v);
recordSize(stmt, context, v.assigned);
}
}
break;
case Constants.MULTIANEWARRAY:
{
MULTIANEWARRAY instr = (MULTIANEWARRAY) instruction;
int dim = instr.getDimensions();
filterSet(in, result, context.stackPtr - dim);
String type = instr.getType(context.constPool()).toString();
type = type.substring(0, type.indexOf("["));
Interval[] size = new Interval[dim];
for (int i = 1; i <= dim; i++) {
String name = type;
for (int k = 0; k < i; k++) {
name += "[]";
}
name += "@" + context.method() + ":" + stmt.getPosition();
boolean valid = false;
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - i) {
result.put(new Location(name + ".length"), in.get(l));
if (size[i - 1] != null) {
size[i - 1].join(in.get(l).assigned);
} else {
size[i - 1] = in.get(l).assigned;
}
valid = true;
}
}
if (!valid) {
ValueMapping v = new ValueMapping();
result.put(new Location(name + ".length"), v);
size[i - 1] = v.assigned;
}
}
recordSize(stmt, context, size);
}
break;
case Constants.GOTO:
result = in;
retval.put(context.callString, result);
break;
case Constants.IFNULL:
case Constants.IFNONNULL:
{
checkScope(context, stmt);
filterSet(in, result, context.stackPtr - 1);
}
break;
case Constants.IF_ACMPEQ:
case Constants.IF_ACMPNE:
{
checkScope(context, stmt);
filterSet(in, result, context.stackPtr - 2);
}
break;
case Constants.IFEQ:
case Constants.IFNE:
case Constants.IFLT:
case Constants.IFGE:
case Constants.IFLE:
case Constants.IFGT:
checkScope(context, stmt);
result = doIf(stmt, edge, context, in, result);
retval.put(context.callString, result);
break;
case Constants.IF_ICMPEQ:
case Constants.IF_ICMPNE:
case Constants.IF_ICMPLT:
case Constants.IF_ICMPGE:
case Constants.IF_ICMPGT:
case Constants.IF_ICMPLE:
checkScope(context, stmt);
result = doIfIcmp(stmt, edge, context, in, result);
retval.put(context.callString, result);
break;
case Constants.LOOKUPSWITCH:
case Constants.TABLESWITCH:
result = in;
retval.put(context.callString, result);
break;
case Constants.INVOKEVIRTUAL:
case Constants.INVOKEINTERFACE:
case Constants.INVOKESTATIC:
case Constants.INVOKESPECIAL:
{
DFATool p = interpreter.getDFATool();
Set<String> receivers = p.getReceivers(stmt, context.callString);
if (receivers == null) {
warnUnknownReceivers(context, stmt);
result = in;
break;
}
for (String methodName : receivers) {
doInvoke(methodName, stmt, context, input, interpreter, state, retval);
}
}
break;
case Constants.ARETURN:
case Constants.RETURN:
{
filterSet(in, result, 0);
}
break;
case Constants.IRETURN:
{
filterSet(in, result, 0);
for (Location l : in.keySet()) {
if (l.stackLoc == context.stackPtr - 1) {
result.put(new Location(0), new ValueMapping(in.get(l), false));
}
}
}
break;
default:
// System.out.println("unknown instruction: "+stmt);
result = in;
retval.put(context.callString, result);
break;
}
// System.out.println(stmt);
// System.out.print(stmt.getInstruction()+":\t{ ");
// if (retval != null) {
// for (Iterator<Map<Location, ValueMapping>> k = retval.values().iterator(); k.hasNext(); ) {
// Map<Location, ValueMapping> m = k.next();
// System.out.print(m+", ");
// }
// }
// System.out.println("}");
context.stackPtr += instruction.produceStack(context.constPool()) - instruction.consumeStack(context.constPool());
return retval;
}
use of org.apache.bcel.generic.Instruction in project jop by jop-devel.
the class SymbolicPointsTo method transfer.
public ContextMap<CallString, SymbolicAddressMap> transfer(InstructionHandle stmt, FlowEdge edge, ContextMap<CallString, SymbolicAddressMap> input, Interpreter<CallString, SymbolicAddressMap> interpreter, Map<InstructionHandle, ContextMap<CallString, SymbolicAddressMap>> state) {
Context context = new Context(input.getContext());
if (DEBUG_PRINT) {
System.out.println("[S] " + context.callString.toStringList() + ": " + context.method() + " / " + stmt);
}
SymbolicAddressMap in = input.get(context.callString);
ContextMap<CallString, SymbolicAddressMap> retval = new ContextMap<CallString, SymbolicAddressMap>(context, input);
Instruction instruction = stmt.getInstruction();
int newStackPtr = context.stackPtr + instruction.produceStack(context.constPool()) - instruction.consumeStack(context.constPool());
int opcode = instruction.getOpcode();
switch(opcode) {
/* Constants (boring) */
case Constants.DCONST_0:
case Constants.DCONST_1:
case Constants.LCONST_0:
case Constants.LCONST_1:
/* Instructions above need two stack slots */
case Constants.FCONST_0:
case Constants.FCONST_1:
case Constants.FCONST_2:
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:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.ACONST_NULL:
{
// Null -> No reference
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
result.putStack(newStackPtr - 1, bsFactory.empty());
retval.put(context.callString, result);
}
break;
/* Long/Double Constants */
case Constants.LDC2_W:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
/* Int/Float/String Constants */
case Constants.LDC:
case Constants.LDC_W:
{
LDC ldc = (LDC) instruction;
Type t = ldc.getType(context.constPool());
if (t instanceof ReferenceType) {
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
/* FIXME: This is overly conservative, but class pointer not available here */
String classContext = context.getMethodInfo().getMemberID().toString();
SymbolicAddress addr = SymbolicAddress.stringLiteral(classContext, ldc.getIndex());
result.putStack(newStackPtr - 1, bsFactory.singleton(addr));
retval.put(context.callString, result);
} else {
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
}
break;
case Constants.DSTORE:
case Constants.DSTORE_0:
case Constants.DSTORE_1:
case Constants.DSTORE_2:
case Constants.DSTORE_3:
case Constants.LSTORE:
case Constants.LSTORE_0:
case Constants.LSTORE_1:
case Constants.LSTORE_2:
case Constants.LSTORE_3:
case Constants.FSTORE:
case Constants.FSTORE_0:
case Constants.FSTORE_1:
case Constants.FSTORE_2:
case Constants.FSTORE_3:
case Constants.ISTORE_0:
case Constants.ISTORE_1:
case Constants.ISTORE_2:
case Constants.ISTORE_3:
case Constants.ISTORE:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
//
case Constants.ASTORE_0:
case Constants.ASTORE_1:
case Constants.ASTORE_2:
case Constants.ASTORE_3:
case Constants.ASTORE:
{
// copy value to local variable
StoreInstruction instr = (StoreInstruction) instruction;
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
if (DEBUG_PRINT) {
System.out.println(String.format("[DD] Copy: stack[%d] <- stack[%d]", instr.getIndex(), context.stackPtr - 1));
}
result.copyStack(in, instr.getIndex(), context.stackPtr - 1);
retval.put(context.callString, result);
}
break;
/* Load variables (boring) */
case Constants.DLOAD_0:
case Constants.DLOAD_1:
case Constants.DLOAD_2:
case Constants.DLOAD_3:
case Constants.DLOAD:
case Constants.LLOAD_0:
case Constants.LLOAD_1:
case Constants.LLOAD_2:
case Constants.LLOAD_3:
case Constants.LLOAD:
/* Instructions above need two stack slots */
case Constants.FLOAD_0:
case Constants.FLOAD_1:
case Constants.FLOAD_2:
case Constants.FLOAD_3:
case Constants.FLOAD:
case Constants.ILOAD_0:
case Constants.ILOAD_1:
case Constants.ILOAD_2:
case Constants.ILOAD_3:
case Constants.ILOAD:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
/* Floating Point Comparison (boring) */
case Constants.DCMPG:
case Constants.DCMPL:
case Constants.LCMP:
/* Instructions above need two stack slots */
case Constants.FCMPG:
case Constants.FCMPL:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.ALOAD_0:
case Constants.ALOAD_1:
case Constants.ALOAD_2:
case Constants.ALOAD_3:
case Constants.ALOAD:
{
LoadInstruction instr = (LoadInstruction) instruction;
// copy value from local variable
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
result.copyStack(in, context.stackPtr, instr.getIndex());
retval.put(context.callString, result);
}
break;
// Access Object Handle (area), top of stack
case Constants.ARRAYLENGTH:
{
putResult(stmt, context, input.get(context.callString).getStack(context.stackPtr - 1));
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
// Access Object Handle, second on stack
case Constants.PUTFIELD:
{
PUTFIELD instr = (PUTFIELD) instruction;
putResult(stmt, context, input.get(context.callString).getStack(context.stackPtr - 1 - instr.getType(context.constPool()).getSize()));
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
// Change alias information
if (instr.getFieldType(context.constPool()) instanceof ReferenceType) {
String ty = instr.getFieldType(context.constPool()).getSignature();
result.addAlias(ty, in.getStack(context.stackPtr - 1));
}
retval.put(context.callString, result);
}
break;
// Access Object Handle, top of stack
case Constants.GETFIELD:
{
putResult(stmt, context, input.get(context.callString).getStack(context.stackPtr - 1));
GETFIELD instr = (GETFIELD) instruction;
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
if (instr.getFieldType(context.constPool()) instanceof ReferenceType) {
BoundedSet<SymbolicAddress> newMapping = SymbolicAddress.fieldAccess(bsFactory, in.getStack(context.stackPtr - 1), instr.getFieldName(context.constPool()));
newMapping.addAll(in.getAliases(instr.getFieldType(context.constPool()).getSignature()));
result.putStack(context.stackPtr - 1, newMapping);
}
retval.put(context.callString, result);
}
break;
// Handles the same way as MOV
case Constants.PUTSTATIC:
{
PUTSTATIC instr = (PUTSTATIC) instruction;
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
if (instr.getFieldType(context.constPool()) instanceof ReferenceType) {
BoundedSet<SymbolicAddress> pointers = in.getStack(context.stackPtr - 1);
result.putHeap(fieldSignature(context, instr), pointers);
}
retval.put(context.callString, result);
}
break;
// Handled the same as MOV
case Constants.GETSTATIC:
{
GETSTATIC instr = (GETSTATIC) instruction;
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
if (instr.getFieldType(context.constPool()) instanceof ReferenceType) {
result.putStack(context.stackPtr, in.getHeap(fieldSignature(context, instr)));
}
retval.put(context.callString, result);
}
break;
case Constants.LASTORE:
case Constants.DASTORE:
case Constants.IASTORE:
case Constants.FASTORE:
case Constants.CASTORE:
case Constants.SASTORE:
case Constants.BASTORE:
{
int offset = 3;
if (opcode == Constants.LASTORE || opcode == Constants.DASTORE)
offset = 4;
putResult(stmt, context, input.get(context.callString).getStack(context.stackPtr - offset));
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
// changing the heap -> TOP
case Constants.AASTORE:
{
putResult(stmt, context, input.get(context.callString).getStack(context.stackPtr - 3));
AASTORE instr = (AASTORE) stmt.getInstruction();
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
// Change alias information
if (instr.getType(context.constPool()) instanceof ReferenceType) {
String ty = instr.getType(context.constPool()).getSignature();
result.addAlias(ty, in.getStack(context.stackPtr - 1));
}
retval.put(context.callString, result);
}
break;
case Constants.DALOAD:
case Constants.LALOAD:
case Constants.IALOAD:
case Constants.FALOAD:
case Constants.CALOAD:
case Constants.SALOAD:
case Constants.BALOAD:
{
putResult(stmt, context, input.get(context.callString).getStack(context.stackPtr - 2));
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
// TODO: Use index info
case Constants.AALOAD:
{
putResult(stmt, context, input.get(context.callString).getStack(context.stackPtr - 2));
//AALOAD instr = (AALOAD)instruction;
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
BoundedSet<SymbolicAddress> objectMapping = in.getStack(context.stackPtr - 2);
BoundedSet<SymbolicAddress> newMapping;
LoopBounds bounds = interpreter.getDFATool().getLoopBounds();
if (executedOnce.query(stmt)) {
newMapping = bsFactory.singleton(SymbolicAddress.newName());
} else if (objectMapping.isSaturated() || bounds == null) {
newMapping = bsFactory.top();
} else {
Interval interval = bounds.getArrayIndices(stmt, context.callString);
if (interval.hasLb() && interval.hasUb()) {
newMapping = bsFactory.empty();
for (SymbolicAddress addr : objectMapping.getSet()) {
for (int i = interval.getLb(); i <= interval.getUb(); i++) {
newMapping.add(addr.accessArray(i));
}
}
} else {
newMapping = bsFactory.top();
}
}
// Doesn't work, but is probably stupid anyway :(
// LoopBounds bounds = interpreter.getDFATool().getLoopBounds();
// bounds.getArraySizes().get(stmt).get(context.callString);
// newMapping = bsFactory.empty();
// Interval[] sizeBounds = { new Interval(2,3) };
// for(Interval i : sizeBounds) {
// if(! i.hasUb()) {
// newMapping = bsFactory.top();
// }
// int ub = i.getUb();
// for(int j = 0; j <= ub; j++) {
// for(SymbolicAddress addr: objectMapping.getSet()) {
// newMapping.add(addr.accessArray(j));
// }
// }
// }
// }
result.putStack(context.stackPtr - 2, newMapping);
retval.put(context.callString, result);
}
break;
case Constants.DUP:
{
// copy value on stack
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
result.copyStack(in, context.stackPtr, context.stackPtr - 1);
retval.put(context.callString, result);
}
break;
case Constants.DUP_X1:
{
// copy value on stack
SymbolicAddressMap result = in.cloneFilterStack(context.stackPtr - 2);
result.copyStack(in, context.stackPtr - 2, context.stackPtr - 1);
result.copyStack(in, context.stackPtr - 1, context.stackPtr - 2);
result.copyStack(in, context.stackPtr, context.stackPtr - 1);
retval.put(context.callString, result);
}
break;
case Constants.DUP_X2:
{
// copy value on stack
SymbolicAddressMap result = in.cloneFilterStack(context.stackPtr - 3);
result.copyStack(in, context.stackPtr - 3, context.stackPtr - 1);
result.copyStack(in, context.stackPtr - 2, context.stackPtr - 3);
result.copyStack(in, context.stackPtr - 1, context.stackPtr - 2);
result.copyStack(in, context.stackPtr, context.stackPtr - 1);
retval.put(context.callString, result);
}
break;
case Constants.DUP2:
{
// v1,v2 -> v1,v2,v1,v2
SymbolicAddressMap result = in.cloneFilterStack(context.stackPtr);
result.copyStack(in, context.stackPtr, context.stackPtr - 2);
result.copyStack(in, context.stackPtr + 1, context.stackPtr - 1);
retval.put(context.callString, result);
}
break;
case Constants.POP:
case Constants.POP2:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.IINC:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.IADD:
case Constants.ISUB:
case Constants.INEG:
case Constants.IUSHR:
case Constants.ISHR:
case Constants.IAND:
case Constants.IOR:
case Constants.IXOR:
case Constants.IMUL:
case Constants.IDIV:
case Constants.IREM:
case Constants.ISHL:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
/* Long,Float and Double operations (boring) */
case Constants.DADD:
case Constants.DSUB:
case Constants.DMUL:
case Constants.DDIV:
case Constants.DREM:
case Constants.LADD:
case Constants.LSUB:
case Constants.LUSHR:
case Constants.LSHR:
case Constants.LAND:
case Constants.LOR:
case Constants.LXOR:
case Constants.LMUL:
case Constants.LDIV:
case Constants.LREM:
case Constants.LSHL:
/* Instructions above need two stack slots */
case Constants.DNEG:
case Constants.LNEG:
case Constants.FADD:
case Constants.FSUB:
case Constants.FNEG:
case Constants.FMUL:
case Constants.FDIV:
case Constants.FREM:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
/* Conversion of primitives (boring) */
case Constants.D2F:
case Constants.D2I:
/* Instructions above need two stack slots */
case Constants.D2L:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.L2F:
case Constants.L2I:
/* Instructions above need two stack slots */
case Constants.L2D:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.F2D:
case Constants.I2D:
case Constants.F2L:
case Constants.I2L:
/* Instructions above need one stack slot less */
case Constants.F2I:
case Constants.I2B:
case Constants.I2C:
case Constants.I2F:
case Constants.I2S:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.MONITORENTER:
// not supported yet
if (ASSUME_NO_CONC)
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
else
retval.put(context.callString, SymbolicAddressMap.top());
break;
case Constants.MONITOREXIT:
// not supported yet
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
break;
case Constants.CHECKCAST:
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
break;
case Constants.INSTANCEOF:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.NEW:
case Constants.NEWARRAY:
case Constants.ANEWARRAY:
{
SymbolicAddressMap result = in.cloneFilterStack(newStackPtr);
BoundedSet<SymbolicAddress> newMapping;
if (executedOnce.query(stmt)) {
newMapping = bsFactory.singleton(SymbolicAddress.newName());
} else {
newMapping = bsFactory.top();
}
int objPtr = (instruction.getOpcode() == Constants.NEW) ? context.stackPtr : (context.stackPtr - 1);
result.putStack(objPtr, newMapping);
retval.put(context.callString, result);
}
break;
case Constants.MULTIANEWARRAY:
{
// not supported yet
retval.put(context.callString, SymbolicAddressMap.top());
}
break;
case Constants.GOTO:
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
break;
case Constants.IFNULL:
case Constants.IFNONNULL:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.IF_ACMPEQ:
case Constants.IF_ACMPNE:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
case Constants.IFEQ:
case Constants.IFNE:
case Constants.IFLT:
case Constants.IFGE:
case Constants.IFLE:
case Constants.IFGT:
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
break;
case Constants.IF_ICMPEQ:
case Constants.IF_ICMPNE:
case Constants.IF_ICMPLT:
case Constants.IF_ICMPGE:
case Constants.IF_ICMPGT:
case Constants.IF_ICMPLE:
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
break;
case Constants.LOOKUPSWITCH:
case Constants.TABLESWITCH:
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
break;
case Constants.INVOKEVIRTUAL:
case Constants.INVOKEINTERFACE:
case Constants.INVOKESTATIC:
case Constants.INVOKESPECIAL:
{
DFATool p = interpreter.getDFATool();
Set<String> receivers = p.getReceivers(stmt, context.callString);
retval.put(context.callString, new SymbolicAddressMap(bsFactory));
if (receivers == null || receivers.size() == 0) {
String errMsg = String.format("%s : invoke %s: %s receivers", context.method(), instruction.toString(context.constPool().getConstantPool()), (receivers == null ? "Unknown" : "No"));
// Get static receivers (FIXME: this just workarounds DFA bugs)
if (opcode == Constants.INVOKESTATIC) {
receivers = new HashSet<String>();
InvokeInstruction invInstruction = (InvokeInstruction) instruction;
String klass = invInstruction.getClassName(context.constPool());
String name = invInstruction.getMethodName(context.constPool());
String sig = invInstruction.getSignature(context.constPool());
String recv = klass + "." + name + sig;
Logger.getLogger(this.getClass()).info("Using static receiver: " + recv);
receivers.add(recv);
} else {
Logger.getLogger(this.getClass()).error(errMsg);
throw new AssertionError(errMsg);
}
}
if (instruction.getOpcode() == Constants.INVOKEVIRTUAL || instruction.getOpcode() == Constants.INVOKEINTERFACE) {
MethodInfo mi = p.getMethod(receivers.iterator().next());
int refPos = MethodHelper.getArgSize(mi);
// mi.methodId,refPos,context.stackPtr,input.get(context.callString)));
try {
putResult(stmt, context, input.get(context.callString).getStack(context.stackPtr - refPos));
} catch (Error e) {
System.err.println("We have problems with method " + mi);
System.err.println(e.getMessage());
}
}
for (String methodName : receivers) {
doInvoke(methodName, stmt, context, input, interpreter, state, retval);
}
}
break;
case Constants.ARETURN:
{
SymbolicAddressMap result = in.cloneFilterStack(0);
// store results
result.copyStack(in, 0, context.stackPtr - 1);
retval.put(context.callString, result);
}
break;
/* The values of other return statements are not of interest here */
case Constants.DRETURN:
case Constants.LRETURN:
case Constants.FRETURN:
case Constants.IRETURN:
case Constants.RETURN:
{
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
}
break;
default:
System.err.println("unknown instruction: " + stmt + " in method " + context.method());
retval.put(context.callString, in.cloneFilterStack(newStackPtr));
break;
}
// DEBUGGING
if (DEBUG_PRINT) {
System.out.println("[F] " + context.method() + " / " + stmt);
System.out.println(" Stackptr: " + context.stackPtr + " -> " + newStackPtr);
System.out.println(" Before: ");
input.get(context.callString).print(System.out, 4);
System.out.println(" After: ");
retval.get(context.callString).print(System.out, 4);
}
context.stackPtr = newStackPtr;
return retval;
}
use of org.apache.bcel.generic.Instruction in project jop by jop-devel.
the class CallStringReceiverTypes method transfer.
public ContextMap<CallString, Set<TypeMapping>> transfer(InstructionHandle stmt, FlowEdge edge, ContextMap<CallString, Set<TypeMapping>> input, Interpreter<CallString, Set<TypeMapping>> interpreter, Map<InstructionHandle, ContextMap<CallString, Set<TypeMapping>>> state) {
Context context = new Context(input.getContext());
Set<TypeMapping> in = input.get(context.callString);
ContextMap<CallString, Set<TypeMapping>> retval = new ContextMap<CallString, Set<TypeMapping>>(context, new LinkedHashMap<CallString, Set<TypeMapping>>());
Set<TypeMapping> result = new LinkedHashSet<TypeMapping>();
retval.put(context.callString, result);
Instruction instruction = stmt.getInstruction();
switch(instruction.getOpcode()) {
case Constants.NOP:
result = in;
retval.put(context.callString, result);
break;
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.FCONST_0:
case Constants.FCONST_1:
case Constants.FCONST_2:
case Constants.LCONST_0:
case Constants.LCONST_1:
case Constants.DCONST_0:
case Constants.DCONST_1:
case Constants.LDC2_W:
result = in;
retval.put(context.callString, result);
break;
case Constants.LDC:
case Constants.LDC_W:
{
LDC instr = (LDC) instruction;
result = new LinkedHashSet<TypeMapping>(in);
retval.put(context.callString, result);
Type type = instr.getType(context.constPool());
if (type.equals(Type.STRING)) {
result.add(new TypeMapping(context.stackPtr, type.toString()));
String value = type.toString() + ".value";
String name = "char[]";
name += "@" + context.method() + ":" + stmt.getPosition();
result.add(new TypeMapping(value, name));
}
}
break;
case Constants.DUP:
{
for (TypeMapping m : in) {
result.add(m);
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(context.stackPtr, m.type));
}
}
}
break;
case Constants.DUP_X1:
{
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 2) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(context.stackPtr - 2, m.type));
result.add(new TypeMapping(context.stackPtr, m.type));
}
if (m.stackLoc == context.stackPtr - 2) {
result.add(new TypeMapping(context.stackPtr - 1, m.type));
}
}
}
break;
case Constants.DUP_X2:
{
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 3) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(context.stackPtr - 3, m.type));
result.add(new TypeMapping(context.stackPtr, m.type));
}
if (m.stackLoc == context.stackPtr - 2) {
result.add(new TypeMapping(context.stackPtr - 1, m.type));
}
if (m.stackLoc == context.stackPtr - 3) {
result.add(new TypeMapping(context.stackPtr - 2, m.type));
}
}
}
break;
case Constants.DUP2:
{
for (TypeMapping m : in) {
result.add(m);
if (m.stackLoc == context.stackPtr - 2) {
result.add(new TypeMapping(context.stackPtr, m.type));
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(context.stackPtr + 1, m.type));
}
}
}
break;
case Constants.DUP2_X1:
{
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 3) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 2) {
result.add(new TypeMapping(context.stackPtr - 3, m.type));
result.add(new TypeMapping(context.stackPtr, m.type));
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(context.stackPtr - 2, m.type));
result.add(new TypeMapping(context.stackPtr + 1, m.type));
}
if (m.stackLoc == context.stackPtr - 3) {
result.add(new TypeMapping(context.stackPtr - 1, m.type));
}
}
}
break;
case Constants.DUP2_X2:
{
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 3) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 2) {
result.add(new TypeMapping(context.stackPtr - 4, m.type));
result.add(new TypeMapping(context.stackPtr, m.type));
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(context.stackPtr - 3, m.type));
result.add(new TypeMapping(context.stackPtr + 1, m.type));
}
if (m.stackLoc == context.stackPtr - 4) {
result.add(new TypeMapping(context.stackPtr - 2, m.type));
}
if (m.stackLoc == context.stackPtr - 3) {
result.add(new TypeMapping(context.stackPtr - 1, m.type));
}
}
}
break;
case Constants.SWAP:
{
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 2) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 2) {
result.add(new TypeMapping(context.stackPtr - 1, m.type));
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(context.stackPtr - 2, m.type));
}
}
}
break;
case Constants.POP:
filterSet(in, result, context.stackPtr - 1);
break;
case Constants.POP2:
filterSet(in, result, context.stackPtr - 2);
break;
case Constants.GETFIELD:
{
GETFIELD instr = (GETFIELD) instruction;
List<String> receivers = new LinkedList<String>();
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 1) {
result.add(m);
} else if (m.stackLoc == context.stackPtr - 1) {
receivers.add(m.type);
}
}
// if (receivers.isEmpty()
// && instr.getFieldType(context.constPool) != Type.INT) {
// System.out.println("GETFIELD not found: "+context.method+"@"+stmt+": "+instr.getFieldName(context.constPool));
//// System.exit(1);
// }
DFATool p = interpreter.getDFATool();
String fieldName = instr.getFieldName(context.constPool());
for (String receiver : receivers) {
//String heapLoc = receiver + "." + instr.getFieldName(context.constPool);
//String namedLoc = receiver.split("@")[0] + "." + instr.getFieldName(context.constPool);
String className = receiver.split("@")[0];
ClassInfo classInfo = p.classForField(className, fieldName);
if (classInfo != null) {
String heapLoc = classInfo.getClassName() + "." + fieldName;
recordReceiver(stmt, context, heapLoc);
for (TypeMapping m : in) {
if (heapLoc.equals(m.heapLoc)) {
result.add(new TypeMapping(context.stackPtr - 1, m.type));
}
}
}
}
}
break;
case Constants.PUTFIELD:
{
PUTFIELD instr = (PUTFIELD) instruction;
List<String> receivers = new LinkedList<String>();
int fieldSize = instr.getFieldType(context.constPool()).getSize();
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 1 - fieldSize) {
result.add(m);
} else if (m.stackLoc == context.stackPtr - 1 - fieldSize) {
receivers.add(m.type);
}
}
// if (receivers.isEmpty()) {
// System.out.println("PUTFIELD not found: "+context.method+"@"+stmt+": "+instr.getFieldName(context.constPool));
//// System.exit(-1);
// }
DFATool p = interpreter.getDFATool();
String fieldName = instr.getFieldName(context.constPool());
for (String receiver : receivers) {
//String heapLoc = receiver + "." + instr.getFieldName(context.constPool);
//String namedLoc = receiver.split("@")[0] + "." + instr.getFieldName(context.constPool);
String className = receiver.split("@")[0];
ClassInfo classInfo = p.classForField(className, fieldName);
if (classInfo != null) {
String heapLoc = classInfo.getClassName() + "." + fieldName;
recordReceiver(stmt, context, heapLoc);
for (TypeMapping m : in) {
if (!heapLoc.equals(m.heapLoc) || context.threaded) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(heapLoc, m.type));
}
}
}
}
if (instr.getFieldType(context.constPool()) instanceof ReferenceType) {
doInvokeStatic("com.jopdesign.sys.JVM.f_putfield_ref(III)V", stmt, context, input, interpreter, state, retval);
}
}
break;
case Constants.GETSTATIC:
{
GETSTATIC instr = (GETSTATIC) instruction;
DFATool p = interpreter.getDFATool();
FieldRef ref = context.getMethodInfo().getCode().getFieldRef(instr);
String fieldName = ref.getName();
String className = ref.getClassName();
ClassInfo classInfo = p.classForField(className, fieldName);
if (classInfo != null) {
String heapLoc = classInfo.getClassName() + "." + fieldName;
recordReceiver(stmt, context, heapLoc);
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr) {
result.add(m);
}
if (heapLoc.equals(m.heapLoc)) {
result.add(new TypeMapping(context.stackPtr, m.type));
}
}
} else {
// System.out.println("GETSTATIC not found: "+heapLoc);
// System.exit(1);
}
}
break;
case Constants.PUTSTATIC:
{
PUTSTATIC instr = (PUTSTATIC) instruction;
DFATool p = interpreter.getDFATool();
FieldRef ref = context.getMethodInfo().getCode().getFieldRef(instr);
String fieldName = ref.getName();
String className = ref.getClassName();
ClassInfo classInfo = p.classForField(className, fieldName);
if (classInfo != null) {
String heapLoc = classInfo.getClassName() + "." + fieldName;
recordReceiver(stmt, context, heapLoc);
for (TypeMapping m : in) {
if (m.stackLoc >= 0 && m.stackLoc < context.stackPtr - 1) {
result.add(m);
} else if (m.stackLoc == -1 && (!heapLoc.equals(m.heapLoc) || context.threaded)) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(heapLoc, m.type));
}
}
} else {
// System.out.println("PUTSTATIC not found: "+heapLoc);
// System.exit(1);
}
if (instr.getFieldType(context.constPool()) instanceof ReferenceType) {
doInvokeStatic("com.jopdesign.sys.JVM.f_putstatic_ref(II)V", stmt, context, input, interpreter, state, retval);
}
}
break;
case Constants.ARRAYLENGTH:
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 1) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 1) {
recordReceiver(stmt, context, m.type);
}
}
break;
case Constants.IASTORE:
case Constants.BASTORE:
case Constants.CASTORE:
case Constants.SASTORE:
case Constants.FASTORE:
{
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 3) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 3) {
recordReceiver(stmt, context, m.type);
}
}
}
break;
case Constants.LASTORE:
case Constants.DASTORE:
{
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 4) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 4) {
recordReceiver(stmt, context, m.type);
}
}
}
break;
case Constants.AASTORE:
{
List<String> receivers = new LinkedList<String>();
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 3) {
result.add(m);
} else if (m.stackLoc == context.stackPtr - 3) {
receivers.add(m.type);
recordReceiver(stmt, context, m.type);
}
}
for (String healLoc : receivers) {
for (TypeMapping m : in) {
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(healLoc, m.type));
}
}
}
doInvokeStatic("com.jopdesign.sys.JVM.f_aastore(III)V", stmt, context, input, interpreter, state, retval);
}
break;
case Constants.IALOAD:
case Constants.BALOAD:
case Constants.CALOAD:
case Constants.SALOAD:
case Constants.FALOAD:
{
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 2) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 2) {
recordReceiver(stmt, context, m.type);
}
}
}
break;
case Constants.LALOAD:
case Constants.DALOAD:
{
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 2) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 2) {
recordReceiver(stmt, context, m.type);
}
}
}
break;
case Constants.AALOAD:
{
List<String> receivers = new LinkedList<String>();
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 2) {
result.add(m);
} else if (m.stackLoc == context.stackPtr - 2) {
receivers.add(m.type);
recordReceiver(stmt, context, m.type);
}
}
for (String heapLoc : receivers) {
for (TypeMapping m : in) {
if (heapLoc.equals(m.heapLoc)) {
result.add(new TypeMapping(context.stackPtr - 2, m.type));
}
}
}
}
break;
case Constants.NEW:
{
NEW instr = (NEW) instruction;
filterSet(in, result, context.stackPtr);
String name = instr.getType(context.constPool()).toString();
name += "@" + context.method() + ":" + stmt.getPosition();
result.add(new TypeMapping(context.stackPtr, name));
doInvokeStatic("com.jopdesign.sys.JVM.f_" + stmt.getInstruction().getName() + "(I)I", stmt, context, input, interpreter, state, retval);
}
break;
case Constants.ANEWARRAY:
{
ANEWARRAY instr = (ANEWARRAY) instruction;
filterSet(in, result, context.stackPtr - 1);
String name = instr.getType(context.constPool()).toString() + "[]";
name += "@" + context.method() + ":" + stmt.getPosition();
result.add(new TypeMapping(context.stackPtr - 1, name));
doInvokeStatic("com.jopdesign.sys.JVM.f_" + stmt.getInstruction().getName() + "(II)I", stmt, context, input, interpreter, state, retval);
}
break;
case Constants.NEWARRAY:
{
NEWARRAY instr = (NEWARRAY) instruction;
filterSet(in, result, context.stackPtr - 1);
String name = instr.getType().toString();
name += "@" + context.method() + ":" + stmt.getPosition();
result.add(new TypeMapping(context.stackPtr - 1, name));
doInvokeStatic("com.jopdesign.sys.JVM.f_" + stmt.getInstruction().getName() + "(II)I", stmt, context, input, interpreter, state, retval);
}
break;
case Constants.MULTIANEWARRAY:
{
MULTIANEWARRAY instr = (MULTIANEWARRAY) instruction;
int dim = instr.getDimensions();
filterSet(in, result, context.stackPtr - dim);
String type = instr.getType(context.constPool()).toString();
type = type.substring(0, type.indexOf("["));
for (int i = 1; i <= dim; i++) {
String type1 = type;
String type2 = type;
for (int k = 0; k < i; k++) {
type1 += "[]";
}
for (int k = 0; k < i - 1; k++) {
type2 += "[]";
}
type1 += "@" + context.method() + ":" + stmt.getPosition();
type2 += "@" + context.method() + ":" + stmt.getPosition();
result.add(new TypeMapping(type1, type2));
}
String name = instr.getType(context.constPool()).toString();
name += "@" + context.method() + ":" + stmt.getPosition();
result.add(new TypeMapping(context.stackPtr - dim, name));
doInvokeStatic("com.jopdesign.sys.JVM.f_" + stmt.getInstruction().getName() + "()I", stmt, context, input, interpreter, state, retval);
}
break;
case Constants.ILOAD_0:
case Constants.ILOAD_1:
case Constants.ILOAD_2:
case Constants.ILOAD_3:
case Constants.ILOAD:
case Constants.FLOAD_0:
case Constants.FLOAD_1:
case Constants.FLOAD_2:
case Constants.FLOAD_3:
case Constants.FLOAD:
case Constants.LLOAD_0:
case Constants.LLOAD_1:
case Constants.LLOAD_2:
case Constants.LLOAD_3:
case Constants.LLOAD:
case Constants.DLOAD_0:
case Constants.DLOAD_1:
case Constants.DLOAD_2:
case Constants.DLOAD_3:
case Constants.DLOAD:
result = in;
retval.put(context.callString, result);
break;
case Constants.ALOAD_0:
case Constants.ALOAD_1:
case Constants.ALOAD_2:
case Constants.ALOAD_3:
case Constants.ALOAD:
{
LoadInstruction instr = (LoadInstruction) instruction;
int index = instr.getIndex();
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr) {
result.add(m);
}
if (m.stackLoc == index) {
result.add(new TypeMapping(context.stackPtr, m.type));
}
}
}
break;
case Constants.ISTORE_0:
case Constants.ISTORE_1:
case Constants.ISTORE_2:
case Constants.ISTORE_3:
case Constants.ISTORE:
case Constants.FSTORE_0:
case Constants.FSTORE_1:
case Constants.FSTORE_2:
case Constants.FSTORE_3:
case Constants.FSTORE:
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:
result = in;
retval.put(context.callString, result);
break;
case Constants.ASTORE_0:
case Constants.ASTORE_1:
case Constants.ASTORE_2:
case Constants.ASTORE_3:
case Constants.ASTORE:
{
StoreInstruction instr = (StoreInstruction) instruction;
int index = instr.getIndex();
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 1 && m.stackLoc != index) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(index, m.type));
}
}
}
break;
case Constants.FCMPL:
case Constants.FCMPG:
case Constants.LCMP:
case Constants.DCMPL:
case Constants.DCMPG:
result = in;
retval.put(context.callString, result);
break;
case Constants.IFEQ:
case Constants.IFNE:
case Constants.IFLT:
case Constants.IFGE:
case Constants.IFGT:
case Constants.IFLE:
case Constants.IFNULL:
case Constants.IFNONNULL:
filterSet(in, result, context.stackPtr - 1);
break;
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:
filterSet(in, result, context.stackPtr - 2);
break;
case Constants.TABLESWITCH:
case Constants.LOOKUPSWITCH:
filterSet(in, result, context.stackPtr - 1);
break;
case Constants.GOTO:
result = in;
retval.put(context.callString, result);
break;
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:
case Constants.FADD:
case Constants.FSUB:
case Constants.FMUL:
case Constants.FDIV:
case Constants.FREM:
case Constants.DADD:
case Constants.DSUB:
case Constants.DMUL:
case Constants.DDIV:
case Constants.DREM:
case Constants.IINC:
case Constants.INEG:
case Constants.FNEG:
case Constants.LNEG:
case Constants.DNEG:
case Constants.LADD:
case Constants.LAND:
case Constants.LOR:
case Constants.LXOR:
case Constants.LSUB:
case Constants.LSHL:
case Constants.LSHR:
case Constants.LUSHR:
result = in;
retval.put(context.callString, result);
break;
case Constants.LMUL:
case Constants.LDIV:
case Constants.LREM:
result = new LinkedHashSet<TypeMapping>(in);
retval.put(context.callString, result);
doInvokeStatic("com.jopdesign.sys.JVM.f_" + stmt.getInstruction().getName() + "(JJ)J", stmt, context, input, interpreter, state, retval);
break;
case Constants.I2B:
case Constants.I2C:
case Constants.I2S:
case Constants.I2F:
case Constants.F2I:
case Constants.I2L:
case Constants.I2D:
case Constants.F2L:
case Constants.F2D:
case Constants.L2I:
case Constants.D2I:
case Constants.L2F:
case Constants.D2F:
case Constants.L2D:
case Constants.D2L:
result = in;
retval.put(context.callString, result);
break;
case Constants.INSTANCEOF:
filterSet(in, result, context.stackPtr - 1);
break;
case Constants.CHECKCAST:
{
DFATool p = interpreter.getDFATool();
CHECKCAST instr = (CHECKCAST) instruction;
for (TypeMapping m : in) {
if (m.stackLoc < context.stackPtr - 1) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 1) {
// check whether this class can possibly be cast
String constClassName = instr.getType(context.constPool()).toString();
ClassInfo staticClass = p.getAppInfo().getClassInfo(constClassName);
ClassInfo dynamicClass = p.getAppInfo().getClassInfo(m.type.split("@")[0]);
// System.out.println("CHECKCAST: "+context.callString.asList()+"/"+context.method+": "+stmt+": "+constClassName+" vs "+m.type);
if (dynamicClass.isSubclassOf(staticClass)) {
result.add(m);
// System.out.println("yay!");
}
}
}
}
break;
case Constants.MONITORENTER:
filterSet(in, result, context.stackPtr - 1);
context.syncLevel++;
break;
case Constants.MONITOREXIT:
filterSet(in, result, context.stackPtr - 1);
context.syncLevel--;
if (context.syncLevel < 0) {
System.err.println("Synchronization level mismatch.");
System.exit(-1);
}
break;
case Constants.INVOKEVIRTUAL:
case Constants.INVOKEINTERFACE:
{
InvokeInstruction instr = (InvokeInstruction) instruction;
int argSize = MethodHelper.getArgSize(instr, context.constPool());
DFATool p = interpreter.getDFATool();
MethodRef ref = context.getMethodInfo().getCode().getInvokeSite(stmt).getInvokeeRef();
ClassInfo constClass = ref.getClassInfo();
// find possible receiver types
List<String> receivers = new LinkedList<String>();
for (TypeMapping m : in) {
if (m.stackLoc == context.stackPtr - argSize) {
String clName = m.type.split("@")[0];
ClassInfo dynamicClass;
// check whether this class can possibly be a receiver
try {
dynamicClass = p.getAppInfo().getClassInfo(clName);
} catch (MissingClassError ex) {
logger.error("TRANSFER/" + instr + ": " + ex);
continue;
}
if ((instr instanceof INVOKEVIRTUAL && dynamicClass.isSubclassOf(constClass)) || (instr instanceof INVOKEINTERFACE && dynamicClass.isImplementationOf(constClass))) {
receivers.add(clName);
} else {
logger.debug(context.method() + ": class " + constClass + " is not a superclass of " + clName);
}
}
}
/* Get the actual set of invoked methods */
//ArrayList<MethodInfo> invokeCandidates = new ArrayList<MethodInfo>();
String signature = ref.getMethodSignature();
for (String receiver : receivers) {
// find receiving method
MethodInfo impl = p.getAppInfo().getMethodInfoInherited(receiver, signature);
if (impl == null) {
throw new AppInfoError("Could not find implementation for: " + receiver + "#" + signature);
}
doInvokeVirtual(receiver, impl, stmt, context, input, interpreter, state, retval);
}
// add relevant information to result
filterSet(in, result, context.stackPtr - argSize);
}
break;
case Constants.INVOKESTATIC:
case Constants.INVOKESPECIAL:
{
InvokeInstruction instr = (InvokeInstruction) instruction;
int argSize = MethodHelper.getArgSize(instr, context.constPool());
MethodRef ref = context.getMethodInfo().getCode().getInvokeSite(stmt).getInvokeeRef();
MethodInfo impl = ref.getMethodInfo();
if (impl == null) {
throw new AppInfoError("Cannot find implementation of " + ref);
} else if (impl.isPrivate() && !impl.isStatic()) {
doInvokeVirtual(ref.getClassName(), impl, stmt, context, input, interpreter, state, retval);
} else {
doInvokeStatic(impl.getMemberID().toString(), stmt, context, input, interpreter, state, retval);
}
// add relevant information to result
filterSet(in, result, context.stackPtr - argSize);
}
break;
case Constants.RETURN:
case Constants.IRETURN:
case Constants.FRETURN:
case Constants.LRETURN:
case Constants.DRETURN:
filterSet(in, result, 0);
break;
case Constants.ARETURN:
{
for (TypeMapping m : in) {
if (m.stackLoc < 0) {
result.add(m);
}
if (m.stackLoc == context.stackPtr - 1) {
result.add(new TypeMapping(0, m.type));
}
}
}
break;
default:
System.out.println("Unknown opcode: " + instruction.toString(context.constPool().getConstantPool()));
System.exit(-1);
}
// System.out.print(instruction+":\t{ ");
// for (Iterator k = result.iterator(); k.hasNext(); ) {
// ReceiverTypes.TypeMapping m = (ReceiverTypes.TypeMapping) k.next();
// if (m.stackLoc >= 0) {
// System.out.print("<stack[" + m.stackLoc + "], " + m.type +">, ");
// } else {
// System.out.print("<" + m.heapLoc + ", " + m.type +">, ");
// }
// }
// System.out.println("}");
// System.out.println("AFTER "+context.method+": "+stmt+" / "+context.callString.asList());
// System.out.print(stmt.getInstruction()+":\t{ ");
// System.out.print(context.callString.asList()+": "+retval.get(context.callString));
// System.out.println(" }");
context.stackPtr += instruction.produceStack(context.constPool()) - instruction.consumeStack(context.constPool());
return retval;
}
use of org.apache.bcel.generic.Instruction in project jop by jop-devel.
the class InlineHelper method checkCode.
/**
* check the code of the invoked method if it contains instructions which prevent inlining.
*
* @param invoker the method into which the invokee will be inlined.
* @param invokee the invoked method.
* @return true if the code can be inlined and {@link #prepareInlining(MethodInfo, MethodInfo)} will succeed.
*/
private boolean checkCode(MethodInfo invoker, MethodInfo invokee) {
MethodCode code = invokee.getCode();
// Go through code, check for access to fields and invocations
for (InstructionHandle ih : code.getInstructionList(true, false).getInstructionHandles()) {
Instruction instr = ih.getInstruction();
if (instr instanceof InvokeInstruction) {
InvokeSite invokeSite = code.getInvokeSite(ih);
MethodRef ref = invokeSite.getInvokeeRef();
MethodInfo method = ref.getMethodInfo();
if (method == null) {
// TODO perform basic check on classnames if invoked method must already be public?
return false;
}
// invokespecial is somewhat, well, special..
if (invokeSite.isInvokeSpecial()) {
if (checkInvokeSpecial(invoker, invokee, invokeSite, ref.getClassInfo(), method) == CheckResult.SKIP) {
return false;
}
} else {
// check if fields need to be set to public
if (checkNeedsPublic(invoker, invokee, ref.getClassInfo(), method) == CheckResult.SKIP) {
return false;
}
}
} else if (instr instanceof FieldInstruction) {
FieldRef ref = code.getFieldRef(ih);
FieldInfo field = ref.getFieldInfo();
if (field == null) {
// TODO perform basic check on classnames if field is already public?
return false;
}
// check if fields need to be set to public
if (checkNeedsPublic(invoker, invokee, ref.getClassInfo(), field) == CheckResult.SKIP) {
return false;
}
}
}
return true;
}
use of org.apache.bcel.generic.Instruction in project jop by jop-devel.
the class InlineHelper method checkJVMCall.
private boolean checkJVMCall(InvokeSite invokeSite, MethodInfo invokee) {
if (!invokeSite.isJVMCall()) {
return true;
}
if (inlineConfig.doInlineJVMCalls() == JVMInline.NONE) {
return false;
}
if (inlineConfig.doInlineJVMCalls() == JVMInline.ALL) {
return true;
}
// Check if params and return type match what is expected on the stack due to the instruction to replace
ConstantPoolGen cpg = invokeSite.getInvoker().getConstantPoolGen();
Instruction instr = invokeSite.getInstructionHandle().getInstruction();
if (!TypeHelper.canAssign(StackHelper.consumeStack(cpg, instr), invokee.getArgumentTypes())) {
return false;
}
if (!invokee.getType().equals(Type.VOID)) {
if (!TypeHelper.canAssign(new Type[] { invokee.getType() }, StackHelper.produceStack(cpg, instr))) {
return false;
}
}
return true;
}
Aggregations