Search in sources :

Example 16 with MethodInsnNode

use of org.objectweb.asm.tree.MethodInsnNode in project quasar by puniverse.

the class InstrumentMethod method collectCodeBlocks.

private void collectCodeBlocks() {
    final int numIns = mn.instructions.size();
    codeBlocks[0] = FrameInfo.FIRST;
    for (int i = 0; i < numIns; i++) {
        final Frame f = frames[i];
        if (f != null) {
            // reachable ?
            final AbstractInsnNode in = mn.instructions.get(i);
            if (in.getType() == AbstractInsnNode.METHOD_INSN || in.getType() == AbstractInsnNode.INVOKE_DYNAMIC_INSN) {
                boolean susp = true;
                if (in.getType() == AbstractInsnNode.METHOD_INSN) {
                    final MethodInsnNode min = (MethodInsnNode) in;
                    int opcode = min.getOpcode();
                    if (isSyntheticAccess(min.owner, min.name))
                        db.log(LogLevel.DEBUG, "Synthetic accessor method call at instruction %d is assumed suspendable", i);
                    else if (isReflectInvocation(min.owner, min.name))
                        db.log(LogLevel.DEBUG, "Reflective method call at instruction %d is assumed suspendable", i);
                    else if (isMethodHandleInvocation(min.owner, min.name))
                        db.log(LogLevel.DEBUG, "MethodHandle invocation at instruction %d is assumed suspendable", i);
                    else if (isInvocationHandlerInvocation(min.owner, min.name))
                        db.log(LogLevel.DEBUG, "InvocationHandler invocation at instruction %d is assumed suspendable", i);
                    else {
                        SuspendableType st = db.isMethodSuspendable(min.owner, min.name, min.desc, opcode);
                        if (st == SuspendableType.NON_SUSPENDABLE) {
                            susp = false;
                        } else if (st == null) {
                            db.log(LogLevel.WARNING, "Method not found in class - assuming suspendable: %s#%s%s (at %s:%s#%s)", min.owner, min.name, min.desc, sourceName, className, mn.name);
                            susp = true;
                        } else if (st != SuspendableType.SUSPENDABLE_SUPER) {
                            db.log(LogLevel.DEBUG, "Method call at instruction %d to %s#%s%s is suspendable", i, min.owner, min.name, min.desc);
                        }
                        if (st == SuspendableType.SUSPENDABLE_SUPER) {
                            db.log(LogLevel.DEBUG, "Method call at instruction %d to %s#%s%s to suspendable-super (instrumentation for proxy support will be enabled)", i, min.owner, min.name, min.desc);
                            this.callsSuspendableSupers = true;
                        }
                    }
                } else if (in.getType() == AbstractInsnNode.INVOKE_DYNAMIC_INSN) {
                    // invoke dynamic
                    final InvokeDynamicInsnNode idin = (InvokeDynamicInsnNode) in;
                    if (idin.bsm.getOwner().equals("java/lang/invoke/LambdaMetafactory")) {
                        // lambda
                        db.log(LogLevel.DEBUG, "Lambda at instruction %d", i);
                        susp = false;
                    } else
                        db.log(LogLevel.DEBUG, "InvokeDynamic Method call at instruction %d to is assumed suspendable", i);
                }
                if (susp) {
                    FrameInfo fi = addCodeBlock(f, i);
                    splitTryCatch(fi);
                } else if (in.getType() == AbstractInsnNode.METHOD_INSN) {
                    // not invokedynamic
                    // noinspection ConstantConditions
                    final MethodInsnNode min = (MethodInsnNode) in;
                    db.log(LogLevel.DEBUG, "Method call at instruction %d to %s#%s%s is not suspendable", i, min.owner, min.name, min.desc);
                    possiblyWarnAboutBlocking(min);
                }
            }
        }
    }
    addCodeBlock(null, numIns);
}
Also used : SuspendableType(co.paralleluniverse.fibers.instrument.MethodDatabase.SuspendableType) Frame(org.objectweb.asm.tree.analysis.Frame) MethodInsnNode(org.objectweb.asm.tree.MethodInsnNode) InvokeDynamicInsnNode(org.objectweb.asm.tree.InvokeDynamicInsnNode) AbstractInsnNode(org.objectweb.asm.tree.AbstractInsnNode)

Example 17 with MethodInsnNode

use of org.objectweb.asm.tree.MethodInsnNode in project quasar by puniverse.

the class InstrumentMethod method accept.

public void accept(MethodVisitor mv, boolean hasAnnotation) {
    db.log(LogLevel.INFO, "Instrumenting method %s:%s#%s%s", sourceName, className, mn.name, mn.desc);
    if (mn.name.charAt(0) == '<')
        throw new UnableToInstrumentException("special method", className, mn.name, mn.desc);
    collectCallsites();
    final boolean skipInstrumentation = canInstrumentationBeSkipped(suspCallsBcis);
    emitInstrumentedAnn(db, mv, mn, sourceName, className, skipInstrumentation, startSourceLine, endSourceLine, suspCallsSourceLines, suspCallsNames, null);
    if (skipInstrumentation) {
        db.log(LogLevel.INFO, "[OPTIMIZE] Skipping instrumentation for method %s:%s#%s%s", sourceName, className, mn.name, mn.desc);
        // Dump
        mn.accept(mv);
        return;
    }
    // Else instrument
    // Must be called first, sets flags & state used below
    collectCodeBlocks();
    // noinspection ConstantConditions
    final boolean handleProxyInvocations = HANDLE_PROXY_INVOCATIONS && callsSuspendableSupers;
    mv.visitCode();
    Label lMethodStart = new Label();
    Label lMethodStart2 = new Label();
    Label lMethodEnd = new Label();
    Label lCatchSEE = new Label();
    Label lCatchUTE = new Label();
    Label lCatchAll = new Label();
    Label[] lMethodCalls = new Label[numCodeBlocks - 1];
    Label[][] refInvokeTryCatch;
    for (int i = 1; i < numCodeBlocks; i++) lMethodCalls[i - 1] = new Label();
    mv.visitInsn(Opcodes.ACONST_NULL);
    mv.visitVarInsn(Opcodes.ASTORE, lvarInvocationReturnValue);
    // if (verifyInstrumentation) {
    // mv.visitInsn(Opcodes.ICONST_0);
    // mv.visitVarInsn(Opcodes.ISTORE, lvarSuspendableCalled);
    // }
    mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchSEE, SUSPEND_EXECUTION_NAME);
    mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchSEE, RUNTIME_SUSPEND_EXECUTION_NAME);
    if (handleProxyInvocations)
        mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchUTE, UNDECLARED_THROWABLE_NAME);
    // Prepare visitTryCatchBlocks for InvocationTargetException.
    // With reflective invocations, the SuspendExecution exception will be wrapped in InvocationTargetException. We need to catch it and unwrap it.
    // Note that the InvocationTargetException will be regenrated on every park, adding further overhead on top of the reflective call.
    // This must be done here, before all other visitTryCatchBlock, because the exception's handler
    // will be matched according to the order of in which visitTryCatchBlock has been called. Earlier calls take precedence.
    refInvokeTryCatch = new Label[numCodeBlocks - 1][];
    for (int i = 1; i < numCodeBlocks; i++) {
        final FrameInfo fi = codeBlocks[i];
        final AbstractInsnNode in = mn.instructions.get(fi.endInstruction);
        if (mn.instructions.get(fi.endInstruction) instanceof MethodInsnNode) {
            MethodInsnNode min = (MethodInsnNode) in;
            if (isReflectInvocation(min.owner, min.name)) {
                Label[] ls = new Label[3];
                for (int k = 0; k < 3; k++) ls[k] = new Label();
                refInvokeTryCatch[i - 1] = ls;
                mv.visitTryCatchBlock(ls[0], ls[1], ls[2], "java/lang/reflect/InvocationTargetException");
            }
        }
    }
    // Output try-catch blocks
    for (final Object o : mn.tryCatchBlocks) {
        final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
        if (// we allow catch of SuspendExecution only in methods annotated with @Suspendable and in lambda-generated ones.
        SUSPEND_EXECUTION_NAME.equals(tcb.type) && !hasAnnotation && !mn.name.startsWith(Classes.LAMBDA_METHOD_PREFIX))
            throw new UnableToInstrumentException("catch for SuspendExecution", className, mn.name, mn.desc);
        if (// we allow catch of SuspendExecution in method annotated with @Suspendable.
        handleProxyInvocations && UNDECLARED_THROWABLE_NAME.equals(tcb.type))
            throw new UnableToInstrumentException("catch for UndeclaredThrowableException", className, mn.name, mn.desc);
        // if (INTERRUPTED_EXCEPTION_NAME.equals(tcb.type))
        // throw new UnableToInstrumentException("catch for " + InterruptedException.class.getSimpleName(), className, mn.name, mn.desc);
        tcb.accept(mv);
    }
    // Output parameter annotations
    if (mn.visibleParameterAnnotations != null)
        dumpParameterAnnotations(mv, mn.visibleParameterAnnotations, true);
    if (mn.invisibleParameterAnnotations != null)
        dumpParameterAnnotations(mv, mn.invisibleParameterAnnotations, false);
    // Output method annotations
    if (mn.visibleAnnotations != null) {
        for (Object o : mn.visibleAnnotations) {
            AnnotationNode an = (AnnotationNode) o;
            an.accept(mv.visitAnnotation(an.desc, true));
        }
    }
    mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchAll, null);
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, STACK_NAME, "getStack", "()L" + STACK_NAME + ";", false);
    mv.visitInsn(Opcodes.DUP);
    mv.visitVarInsn(Opcodes.ASTORE, lvarStack);
    // println(mv, "STACK: ", lvarStack);
    // dumpStack(mv);
    // DUAL
    mv.visitJumpInsn(Opcodes.IFNULL, lMethodStart);
    mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
    // we'll assume we have been resumed
    emitStoreResumed(mv, true);
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "nextMethodEntry", "()I", false);
    mv.visitTableSwitchInsn(1, numCodeBlocks - 1, lMethodStart2, lMethodCalls);
    mv.visitLabel(lMethodStart2);
    // the following code handles the case of an instrumented method called not as part of a suspendable code path
    // isFirstInStack will return false in that case.
    mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "isFirstInStackOrPushed", "()Z", false);
    // if true
    mv.visitJumpInsn(Opcodes.IFNE, lMethodStart);
    // This will reset the fiber stack local if isFirstStack returns false.
    mv.visitInsn(Opcodes.ACONST_NULL);
    mv.visitVarInsn(Opcodes.ASTORE, lvarStack);
    mv.visitLabel(lMethodStart);
    // no, we have not been resumed
    emitStoreResumed(mv, false);
    dumpCodeBlock(mv, 0, 0);
    // Blocks leading to suspendable calls
    for (int i = 1; i < numCodeBlocks; i++) {
        final FrameInfo fi = codeBlocks[i];
        // Emit instrumented call
        final AbstractInsnNode min = mn.instructions.get(fi.endInstruction);
        final String owner = getMethodOwner(min), name = getMethodName(min), desc = getMethodDesc(min);
        if (isYieldMethod(owner, name)) {
            // special case - call to yield
            if (min.getOpcode() != Opcodes.INVOKESTATIC)
                throw new UnableToInstrumentException("invalid call to suspending method.", className, mn.name, mn.desc);
            final int numYieldArgs = TypeAnalyzer.getNumArguments(desc);
            final boolean yieldReturnsValue = (Type.getReturnType(desc) != Type.VOID_TYPE);
            // we preserve the arguments for the call to yield on the operand stack
            emitStoreState(mv, i, fi, numYieldArgs);
            // we have not been resumed
            emitStoreResumed(mv, false);
            // emitSuspendableCalled(mv);
            // we call the yield method
            min.accept(mv);
            if (yieldReturnsValue)
                // we ignore the returned value...
                mv.visitInsn(Opcodes.POP);
            // we resume AFTER the call
            mv.visitLabel(lMethodCalls[i - 1]);
            final Label afterPostRestore = new Label();
            mv.visitVarInsn(Opcodes.ILOAD, lvarResumed);
            mv.visitJumpInsn(Opcodes.IFEQ, afterPostRestore);
            emitPostRestore(mv);
            mv.visitLabel(afterPostRestore);
            emitRestoreState(mv, i, fi, numYieldArgs);
            if (yieldReturnsValue)
                // ... and replace the returned value with the value of resumed
                mv.visitVarInsn(Opcodes.ILOAD, lvarResumed);
            // See #211: if Fiber.park() is the last call before catch, ASM generates
            // empty handlers (start_pc = end_pc) that won't pass ASM's nor JVM's bytecode checker because of
            // exception_table's spec here: https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.3
            mv.visitInsn(Opcodes.NOP);
            dumpCodeBlock(mv, i, 1);
        } else {
            final Label lbl = new Label();
            // DUAL
            mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
            mv.visitJumpInsn(Opcodes.IFNULL, lbl);
            // normal case - call to a suspendable method - resume before the call
            emitStoreState(mv, i, fi, 0);
            // we have not been resumed
            emitStoreResumed(mv, false);
            // emitPreemptionPoint(mv, PREEMPTION_CALL);
            mv.visitLabel(lMethodCalls[i - 1]);
            emitRestoreState(mv, i, fi, 0);
            // DUAL
            mv.visitLabel(lbl);
            if (isReflectInvocation(owner, name)) {
                // We catch the InvocationTargetException and unwrap it if it wraps a SuspendExecution exception.
                Label[] ls = refInvokeTryCatch[i - 1];
                final Label startTry = ls[0];
                final Label endTry = ls[1];
                final Label startCatch = ls[2];
                final Label endCatch = new Label();
                final Label notSuspendExecution = new Label();
                // mv.visitTryCatchBlock(startTry, endTry, startCatch, "java/lang/reflect/InvocationTargetException");
                // try {
                mv.visitLabel(startTry);
                // method.invoke()
                min.accept(mv);
                // save return value
                mv.visitVarInsn(Opcodes.ASTORE, lvarInvocationReturnValue);
                // }
                mv.visitLabel(endTry);
                mv.visitJumpInsn(Opcodes.GOTO, endCatch);
                // catch(InvocationTargetException ex) {
                mv.visitLabel(startCatch);
                mv.visitInsn(Opcodes.DUP);
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
                mv.visitTypeInsn(Opcodes.INSTANCEOF, SUSPEND_EXECUTION_NAME);
                mv.visitJumpInsn(Opcodes.IFEQ, notSuspendExecution);
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
                mv.visitLabel(notSuspendExecution);
                mv.visitInsn(Opcodes.ATHROW);
                mv.visitLabel(endCatch);
                // restore return value
                mv.visitVarInsn(Opcodes.ALOAD, lvarInvocationReturnValue);
                dumpCodeBlock(mv, i, 1);
            } else {
                // emitSuspendableCalled(mv);
                dumpCodeBlock(mv, i, 0);
            }
        }
    }
    // Emit catchall's catch section
    mv.visitLabel(lMethodEnd);
    if (handleProxyInvocations) {
        mv.visitLabel(lCatchUTE);
        mv.visitInsn(Opcodes.DUP);
        // println(mv, "CTCH: ");
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
        // println(mv, "CAUSE: ");
        mv.visitTypeInsn(Opcodes.INSTANCEOF, SUSPEND_EXECUTION_NAME);
        mv.visitJumpInsn(Opcodes.IFEQ, lCatchAll);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
        mv.visitJumpInsn(Opcodes.GOTO, lCatchSEE);
    }
    mv.visitLabel(lCatchAll);
    emitPopMethod(mv);
    mv.visitLabel(lCatchSEE);
    // println(mv, "THROW: ");
    // rethrow shared between catchAll and catchSSE
    mv.visitInsn(Opcodes.ATHROW);
    if (mn.localVariables != null) {
        for (Object o : mn.localVariables) ((LocalVariableNode) o).accept(mv);
    }
    // Needed by ASM analysis
    mv.visitMaxs(mn.maxStack + ADD_OPERANDS, mn.maxLocals + NUM_LOCALS + additionalLocals);
    mv.visitEnd();
}
Also used : TryCatchBlockNode(org.objectweb.asm.tree.TryCatchBlockNode) Label(org.objectweb.asm.Label) AbstractInsnNode(org.objectweb.asm.tree.AbstractInsnNode) AnnotationNode(org.objectweb.asm.tree.AnnotationNode) MethodInsnNode(org.objectweb.asm.tree.MethodInsnNode)

Example 18 with MethodInsnNode

use of org.objectweb.asm.tree.MethodInsnNode in project Minechem by iopleke.

the class MinechemTransformer method findInstructionNode.

private static AbstractInsnNode findInstructionNode(InstructionNode instructionNode, MethodNode methodNode) {
    boolean close = false;
    AbstractInsnNode result = null;
    for (Iterator<AbstractInsnNode> itr = methodNode.instructions.iterator(); itr.hasNext(); ) {
        AbstractInsnNode node = itr.next();
        if (node instanceof MethodInsnNode) {
            if (close) {
                if (((MethodInsnNode) node).name.equals(instructionNode.getBefore())) {
                    return instructionNode.replace ? node : result;
                } else {
                    close = false;
                }
            }
            if (((MethodInsnNode) node).name.equals(instructionNode.getAfter())) {
                close = true;
                result = node;
            }
        }
    }
    return result == null ? methodNode.instructions.getLast().getPrevious() : result;
}
Also used : MethodInsnNode(org.objectweb.asm.tree.MethodInsnNode) AbstractInsnNode(org.objectweb.asm.tree.AbstractInsnNode)

Example 19 with MethodInsnNode

use of org.objectweb.asm.tree.MethodInsnNode 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 20 with MethodInsnNode

use of org.objectweb.asm.tree.MethodInsnNode in project MinecraftForge by MinecraftForge.

the class ItemStackTransformer method transform.

@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
    if (!"net.minecraft.item.ItemStack".equals(name))
        return basicClass;
    ClassNode classNode = new ClassNode();
    ClassReader classReader = new ClassReader(basicClass);
    classReader.accept(classNode, 0);
    FieldNode itemField = null;
    for (FieldNode f : classNode.fields) {
        if (ITEM_TYPE.equals(f.desc) && itemField == null) {
            itemField = f;
        } else if (ITEM_TYPE.equals(f.desc)) {
            throw new RuntimeException("Error processing ItemStack - found a duplicate Item field");
        }
    }
    if (itemField == null) {
        throw new RuntimeException("Error processing ItemStack - no Item field declared (is the code somehow obfuscated?)");
    }
    MethodNode getItemMethod = null;
    for (MethodNode m : classNode.methods) {
        if (m.name.equals("getItemRaw"))
            continue;
        if (GETITEM_DESC.equals(m.desc) && getItemMethod == null) {
            getItemMethod = m;
        } else if (GETITEM_DESC.equals(m.desc)) {
            throw new RuntimeException("Error processing ItemStack - duplicate getItem method found");
        }
    }
    if (getItemMethod == null) {
        throw new RuntimeException("Error processing ItemStack - no getItem method found (is the code somehow obfuscated?)");
    }
    for (MethodNode m : classNode.methods) {
        if (m.name.equals("getItemRaw"))
            continue;
        for (ListIterator<AbstractInsnNode> it = m.instructions.iterator(); it.hasNext(); ) {
            AbstractInsnNode insnNode = it.next();
            if (insnNode.getType() == AbstractInsnNode.FIELD_INSN) {
                FieldInsnNode fi = (FieldInsnNode) insnNode;
                if (itemField.name.equals(fi.name) && fi.getOpcode() == Opcodes.GETFIELD) {
                    it.remove();
                    MethodInsnNode replace = new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "net/minecraft/item/ItemStack", getItemMethod.name, getItemMethod.desc, false);
                    it.add(replace);
                }
            }
        }
    }
    ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    classNode.accept(writer);
    return writer.toByteArray();
}
Also used : ClassNode(org.objectweb.asm.tree.ClassNode) FieldNode(org.objectweb.asm.tree.FieldNode) MethodNode(org.objectweb.asm.tree.MethodNode) MethodInsnNode(org.objectweb.asm.tree.MethodInsnNode) ClassReader(org.objectweb.asm.ClassReader) FieldInsnNode(org.objectweb.asm.tree.FieldInsnNode) AbstractInsnNode(org.objectweb.asm.tree.AbstractInsnNode) ClassWriter(org.objectweb.asm.ClassWriter)

Aggregations

MethodInsnNode (org.objectweb.asm.tree.MethodInsnNode)26 AbstractInsnNode (org.objectweb.asm.tree.AbstractInsnNode)12 MethodNode (org.objectweb.asm.tree.MethodNode)5 FieldInsnNode (org.objectweb.asm.tree.FieldInsnNode)4 ArrayList (java.util.ArrayList)3 Type (org.objectweb.asm.Type)3 InsnList (org.objectweb.asm.tree.InsnList)3 InvokeDynamicInsnNode (org.objectweb.asm.tree.InvokeDynamicInsnNode)3 TypeInsnNode (org.objectweb.asm.tree.TypeInsnNode)3 BasicValue (org.objectweb.asm.tree.analysis.BasicValue)3 List (java.util.List)2 AnnotationNode (org.objectweb.asm.tree.AnnotationNode)2 ClassNode (org.objectweb.asm.tree.ClassNode)2 FieldNode (org.objectweb.asm.tree.FieldNode)2 InsnNode (org.objectweb.asm.tree.InsnNode)2 JumpInsnNode (org.objectweb.asm.tree.JumpInsnNode)2 VarInsnNode (org.objectweb.asm.tree.VarInsnNode)2 Frame (org.objectweb.asm.tree.analysis.Frame)2 SuspendableType (co.paralleluniverse.fibers.instrument.MethodDatabase.SuspendableType)1 com.mxgraph.swing.mxGraphComponent (com.mxgraph.swing.mxGraphComponent)1