@Override public BasicValue binaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2) throws AnalyzerException { switch (insn.getOpcode()) { case PUTFIELD: // put value2 into value1 // skip untagged values if (!isTagged(value1)) { return null; } final TaggedValue taggedValue = (TaggedValue) value1; final FieldInsnNode field = (FieldInsnNode) insn; final boolean value2HasInputDependency = hasImportantDependencies(value2); // if value1 is not an input, make value1 a container and add value2 to it // PUTFIELD on inputs is not allowed if (!taggedValue.isInput() && value2HasInputDependency) { if (!taggedValue.canContainFields()) { taggedValue.setTag(Tag.CONTAINER); } taggedValue.addContainerMapping(field.name, tagged(value2), currentFrame); } // if value1 is filled with non-input, make it container and mark the field // PUTFIELD on inputs is not allowed else if (!taggedValue.isInput() && !value2HasInputDependency) { if (!taggedValue.canContainFields()) { taggedValue.setTag(Tag.CONTAINER); } taggedValue.addContainerMapping(field.name, null, currentFrame); } // PUTFIELD on input leads to input modification // make input regular else if (taggedValue.isInput()) { taggedValue.makeRegular(); } return null; default: return super.binaryOperation(insn, value1, value2); } }
@Override public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException { switch (insn.getOpcode()) { // modify jump instructions if we can assume that the hasNext operation will always // be true at the first call case IFEQ: if (isTagged(value) && tagged(value).isIteratorTrueAssumption()) { modifiedAsmAnalyzer.requestIFEQLoopModification(); } return super.unaryOperation(insn, value); case IFNE: if (isTagged(value) && tagged(value).isIteratorTrueAssumption()) { modifiedAsmAnalyzer.requestIFNELoopModification(); } return super.unaryOperation(insn, value); case CHECKCAST: return value; case PUTSTATIC: analyzer.handlePutStatic(); return super.unaryOperation(insn, value); case GETFIELD: final FieldInsnNode field = (FieldInsnNode) insn; // skip untagged values if (!isTagged(value)) { return super.unaryOperation(insn, value); } final TaggedValue taggedValue = (TaggedValue) value; // inputs are atomic, a GETFIELD results in undefined state if (taggedValue.isInput()) { return super.unaryOperation(insn, value); } // access of input container field // or access of a KNOWN UDF instance variable else if (taggedValue.canContainFields() && taggedValue.containerContains(field.name)) { final TaggedValue tv = taggedValue.getContainerMapping().get(field.name); if (tv != null) { return tv; } } // access of a yet UNKNOWN UDF instance variable else if (taggedValue.isThis() && !taggedValue.containerContains(field.name)) { final TaggedValue tv = new TaggedValue(Type.getType(field.desc)); taggedValue.addContainerMapping(field.name, tv, currentFrame); return tv; } // access of a yet unknown container, mark it as a container else if (taggedValue.isRegular()) { taggedValue.setTag(Tag.CONTAINER); final TaggedValue tv = new TaggedValue(Type.getType(field.desc)); taggedValue.addContainerMapping(field.name, tv, currentFrame); return tv; } return super.unaryOperation(insn, value); case IINC: // modification of a local variable or input if (isTagged(value) && (tagged(value).isIntConstant() || tagged(value).isInput())) { tagged(value).makeRegular(); } return super.unaryOperation(insn, value); default: return super.unaryOperation(insn, value); } }