use of org.objectweb.asm.tree.analysis.BasicValue in project flink by apache.
the class NestedMethodAnalyzer method naryOperation.
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public BasicValue naryOperation(AbstractInsnNode insn, List rawValues) throws AnalyzerException {
final List<BasicValue> values = (List<BasicValue>) rawValues;
boolean isStatic = false;
switch(insn.getOpcode()) {
case INVOKESTATIC:
isStatic = true;
case INVOKESPECIAL:
case INVOKEVIRTUAL:
case INVOKEINTERFACE:
final MethodInsnNode method = (MethodInsnNode) insn;
String methodOwner = method.owner;
// that contains the actual implementation to determine the tuple size
if (method.name.equals("getField") || method.name.equals("setField")) {
try {
final String newMethodOwner = (String) findMethodNode(methodOwner, method.name, method.desc)[1];
if (newMethodOwner.startsWith("org/apache/flink/api/java/tuple/Tuple")) {
methodOwner = newMethodOwner;
}
} catch (IllegalStateException e) {
// proceed with the known method owner
}
}
// special case: collect method of Collector
if (method.name.equals("collect") && methodOwner.equals("org/apache/flink/util/Collector") && isTagged(values.get(0)) && tagged(values.get(0)).isCollector()) {
// check for invalid return value
if (isTagged(values.get(1)) && tagged(values.get(1)).isNull()) {
analyzer.handleNullReturn();
} else // valid return value with input dependencies
if (hasImportantDependencies(values.get(1))) {
// add a copy and a reference
// to capture the current state and future changes in alternative paths
analyzer.getCollectorValues().add(tagged(values.get(1)));
analyzer.getCollectorValues().add(tagged(values.get(1)).copy());
} else // valid return value without input dependencies
{
analyzer.getCollectorValues().add(null);
}
} else // special case: iterator method of Iterable
if (method.name.equals("iterator") && methodOwner.equals("java/lang/Iterable") && isTagged(values.get(0)) && tagged(values.get(0)).isInputIterable()) {
return new TaggedValue(Type.getObjectType("java/util/Iterator"), (tagged(values.get(0)).isInput1Iterable()) ? Tag.INPUT_1_ITERATOR : Tag.INPUT_2_ITERATOR);
} else // special case: hasNext method of Iterator
if (method.name.equals("hasNext") && methodOwner.equals("java/util/Iterator") && isTagged(values.get(0)) && tagged(values.get(0)).isInputIterator() && !analyzer.isUdfBinary() && !analyzer.isIteratorTrueAssumptionApplied()) {
return new TaggedValue(Type.BOOLEAN_TYPE, Tag.ITERATOR_TRUE_ASSUMPTION);
} else // special case: next method of Iterator
if (method.name.equals("next") && methodOwner.equals("java/util/Iterator") && isTagged(values.get(0)) && tagged(values.get(0)).isInputIterator()) {
// after this call it is not possible to assume "TRUE" of "hasNext()" again
analyzer.applyIteratorTrueAssumption();
if (tagged(values.get(0)).isInput1Iterator()) {
return analyzer.getInput1AsTaggedValue();
} else {
return analyzer.getInput2AsTaggedValue();
}
} else // special case: do not follow the getRuntimeContext method of RichFunctions
if (!isStatic && isTagged(values.get(0)) && tagged(values.get(0)).isThis() && hasImportantDependencies(values.get(0)) && !isGetRuntimeContext(method)) {
TaggedValue tv = invokeNestedMethod(values, method);
if (tv != null) {
return tv;
}
} else // we can assume that method has at least one argument
if ((!isStatic && isTagged(values.get(0)) && tagged(values.get(0)).isThis() && hasImportantDependencies(values, true)) || (!isStatic && (!isTagged(values.get(0)) || !tagged(values.get(0)).isThis()) && hasImportantDependencies(values, false)) || (isStatic && hasImportantDependencies(values, false))) {
// special case: Java unboxing/boxing methods on input
Type newType;
if (isTagged(values.get(0)) && tagged(values.get(0)).isInput() && (!isStatic && (newType = checkForUnboxing(method.name, methodOwner)) != null || (isStatic && (newType = checkForBoxing(method.name, method.desc, methodOwner)) != null))) {
return tagged(values.get(0)).copy(newType);
} else // special case: setField method of TupleXX
if (method.name.equals("setField") && methodOwner.startsWith("org/apache/flink/api/java/tuple/Tuple") && isTagged(values.get(0))) {
final TaggedValue tuple = tagged(values.get(0));
tuple.setTag(Tag.CONTAINER);
// if not, we can not determine a state for the tuple
if (!isTagged(values.get(2)) || !tagged(values.get(2)).isIntConstant()) {
tuple.makeRegular();
} else {
final int constant = tagged(values.get(2)).getIntConstant();
if (constant < 0 || Integer.parseInt(methodOwner.split("Tuple")[1]) <= constant) {
analyzer.handleInvalidTupleAccess();
}
// if it is at least tagged, add it anyways
if (isTagged(values.get(1))) {
tuple.addContainerMapping("f" + constant, tagged(values.get(1)), currentFrame);
} else // mark the field as it has an undefined state
{
tuple.addContainerMapping("f" + constant, null, currentFrame);
}
}
} else // special case: getField method of TupleXX
if (method.name.equals("getField") && methodOwner.startsWith("org/apache/flink/api/java/tuple/Tuple")) {
// we can assume that 0 is an input dependent tuple
final TaggedValue tuple = tagged(values.get(0));
// constant field index
if (// constant
isTagged(values.get(1)) && tagged(values.get(1)).isIntConstant()) {
final int constant = tagged(values.get(1)).getIntConstant();
if (constant < 0 || Integer.valueOf(methodOwner.split("Tuple")[1]) <= constant) {
analyzer.handleInvalidTupleAccess();
}
if (tuple.containerContains("f" + constant)) {
final TaggedValue tupleField = tuple.getContainerMapping().get("f" + constant);
if (tupleField != null) {
return tupleField;
}
}
} else // unknown field index
{
// we need to make the tuple regular as we cannot track modifications of fields
tuple.makeRegular();
return new TaggedValue(Type.getObjectType("java/lang/Object"));
}
} else // nested method invocation
{
TaggedValue tv = invokeNestedMethod(values, method);
if (tv != null) {
return tv;
}
}
}
return super.naryOperation(insn, values);
default:
// TODO support for INVOKEDYNAMIC instructions
return super.naryOperation(insn, values);
}
}
use of org.objectweb.asm.tree.analysis.BasicValue in project quasar by puniverse.
the class InstrumentMethod method emitRestoreState.
private void emitRestoreState(MethodVisitor mv, @SuppressWarnings("UnusedParameters") int idx, FrameInfo fi, int numArgsPreserved) {
Frame f = frames[fi.endInstruction];
// restore local vars
for (int i = firstLocal; i < f.getLocals(); i++) {
BasicValue v = (BasicValue) f.getLocal(i);
if (!isNullType(v)) {
int slotIdx = fi.localSlotIndices[i];
assert slotIdx >= 0 && slotIdx < fi.numSlots;
emitRestoreValue(mv, v, lvarStack, slotIdx, i);
mv.visitVarInsn(v.getType().getOpcode(Opcodes.ISTORE), i);
} else if (v != BasicValue.UNINITIALIZED_VALUE) {
mv.visitInsn(Opcodes.ACONST_NULL);
mv.visitVarInsn(Opcodes.ASTORE, i);
}
}
// restore operand stack
for (int i = 0; i < f.getStackSize() - numArgsPreserved; i++) {
BasicValue v = (BasicValue) f.getStack(i);
if (!isOmitted(v)) {
if (!isNullType(v)) {
int slotIdx = fi.stackSlotIndices[i];
assert slotIdx >= 0 && slotIdx < fi.numSlots;
emitRestoreValue(mv, v, lvarStack, slotIdx, -1);
} else
mv.visitInsn(Opcodes.ACONST_NULL);
}
}
if (fi.lAfter != null)
fi.lAfter.accept(mv);
}
use of org.objectweb.asm.tree.analysis.BasicValue in project quasar by puniverse.
the class TypeInterpreter method binaryOperation.
@Override
public BasicValue binaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2) throws AnalyzerException {
if (insn.getOpcode() == Opcodes.AALOAD) {
final Type t1 = value1.getType();
if (t1 == null)
// f.e. if the AALOAD array argument is conditionally initialized.
throw new AnalyzerException(insn, "AALOAD needs a first parameter");
final Type resultType = Type.getType(t1.getDescriptor().substring(1));
return new BasicValue(resultType);
}
return super.binaryOperation(insn, value1, value2);
}
use of org.objectweb.asm.tree.analysis.BasicValue in project quasar by puniverse.
the class TypeInterpreter method merge.
@Override
public BasicValue merge(BasicValue v, BasicValue w) {
if (!v.equals(w)) {
// db.log(LogLevel.DEBUG, "merge: %s %s", v, w);
if (v.isReference() && w.isReference()) {
int dimensions = 0;
Type typeV = v.getType();
Type typeW = w.getType();
final String internalV = typeV.getInternalName();
final String internalW = typeW.getInternalName();
if ("null".equals(internalV))
return w;
if ("null".equals(internalW))
return v;
if (typeV.getSort() != typeW.getSort()) {
db.log(LogLevel.DEBUG, "Array and non-array type can't be merged: %s %s", v, w);
return BasicValue.UNINITIALIZED_VALUE;
}
if (typeW.getSort() == Type.ARRAY) {
dimensions = typeV.getDimensions();
if (dimensions != typeW.getDimensions()) {
db.log(LogLevel.DEBUG, "Arrays with different dimensions can't be merged: %s %s", v, w);
return BasicValue.UNINITIALIZED_VALUE;
}
typeV = typeV.getElementType();
typeW = typeW.getElementType();
if (typeV.getSort() != Type.OBJECT || typeW.getSort() != Type.OBJECT) {
db.log(LogLevel.DEBUG, "Arrays of different primitive type can't be merged: %s %s", v, w);
return BasicValue.UNINITIALIZED_VALUE;
}
}
String superClass = db.getCommonSuperClass(internalV, internalW);
if (superClass == null) {
if (db.isException(internalW)) {
db.log(LogLevel.WARNING, "Could not determine super class for v=%s w=%s - decided to use exception %s", v, w, w);
return w;
}
if (db.isException(internalV)) {
db.log(LogLevel.WARNING, "Could not determine super class for v=%s w=%s - decided to use exception %s", v, w, v);
return v;
}
db.log(LogLevel.WARNING, "Could not determine super class for v=%s w=%s - decided to use java/lang/Object", v, w);
superClass = "java/lang/Object";
}
String typeDescriptor = makeTypeDescriptor(superClass, dimensions);
db.log(LogLevel.INFO, "Common super class for v=%s w=%s is %s", v, w, typeDescriptor);
return new BasicValue(Type.getType(typeDescriptor));
}
return BasicValue.UNINITIALIZED_VALUE;
}
return v;
}
use of org.objectweb.asm.tree.analysis.BasicValue in project drill by apache.
the class InstructionModifier method peekFromTop.
/**
* Peek at a value in the current frame's stack, counting down from the top.
*
* @param depth how far down to peek; 0 is the top of the stack, 1 is the
* first element down, etc
* @return the value on the stack, or null if it isn't a ReplacingBasciValue
*/
private ReplacingBasicValue peekFromTop(final int depth) {
Preconditions.checkArgument(depth >= 0);
final Frame<BasicValue> frame = list.currentFrame;
final BasicValue basicValue = frame.getStack((frame.getStackSize() - 1) - depth);
return filterReplacement(basicValue);
}
Aggregations