Search in sources :

Example 6 with BasicValue

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);
    }
}
Also used : Type(org.objectweb.asm.Type) MethodInsnNode(org.objectweb.asm.tree.MethodInsnNode) ArrayList(java.util.ArrayList) List(java.util.List) BasicValue(org.objectweb.asm.tree.analysis.BasicValue)

Example 7 with BasicValue

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);
}
Also used : Frame(org.objectweb.asm.tree.analysis.Frame) BasicValue(org.objectweb.asm.tree.analysis.BasicValue)

Example 8 with BasicValue

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);
}
Also used : Type(org.objectweb.asm.Type) AnalyzerException(org.objectweb.asm.tree.analysis.AnalyzerException) BasicValue(org.objectweb.asm.tree.analysis.BasicValue)

Example 9 with BasicValue

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;
}
Also used : Type(org.objectweb.asm.Type) BasicValue(org.objectweb.asm.tree.analysis.BasicValue)

Example 10 with BasicValue

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);
}
Also used : BasicValue(org.objectweb.asm.tree.analysis.BasicValue)

Aggregations

BasicValue (org.objectweb.asm.tree.analysis.BasicValue)13 Type (org.objectweb.asm.Type)3 Frame (org.objectweb.asm.tree.analysis.Frame)3 MethodInsnNode (org.objectweb.asm.tree.MethodInsnNode)2 MethodNode (org.objectweb.asm.tree.MethodNode)2 AnalyzerException (org.objectweb.asm.tree.analysis.AnalyzerException)2 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 CheckMethodVisitorFsm (org.apache.drill.exec.compile.CheckMethodVisitorFsm)1 UdfAnalyzerUtils.findMethodNode (org.apache.flink.api.java.sca.UdfAnalyzerUtils.findMethodNode)1 MethodVisitor (org.objectweb.asm.MethodVisitor)1 ClassNode (org.objectweb.asm.tree.ClassNode)1 FieldInsnNode (org.objectweb.asm.tree.FieldInsnNode)1 Analyzer (org.objectweb.asm.tree.analysis.Analyzer)1 SimpleVerifier (org.objectweb.asm.tree.analysis.SimpleVerifier)1