Search in sources :

Example 1 with SuspendableType

use of co.paralleluniverse.fibers.instrument.MethodDatabase.SuspendableType in project quasar by puniverse.

the class InstrumentClass method visitMethod.

@Override
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
    SuspendableType markedSuspendable = null;
    if (suspendableInterface)
        markedSuspendable = SuspendableType.SUSPENDABLE_SUPER;
    if (markedSuspendable == null)
        markedSuspendable = classifier.isSuspendable(db, sourceName, sourceDebugInfo, isInterface, className, classEntry.getSuperName(), classEntry.getInterfaces(), name, desc, signature, exceptions);
    final SuspendableType setSuspendable = classEntry.check(name, desc);
    if (setSuspendable == null)
        classEntry.set(name, desc, markedSuspendable != null ? markedSuspendable : SuspendableType.NON_SUSPENDABLE);
    final SuspendableType suspendable = max(markedSuspendable, setSuspendable, SuspendableType.NON_SUSPENDABLE);
    if (checkAccessForMethodVisitor(access) && !isYieldMethod(className, name)) {
        if (methods == null)
            methods = new ArrayList<>();
        final MethodNode mn = new MethodNode(access, name, desc, signature, exceptions);
        return new MethodVisitor(ASMAPI, mn) {

            private SuspendableType susp = suspendable;

            private boolean commited = false;

            @Override
            public AnnotationVisitor visitAnnotation(String adesc, boolean visible) {
                // look for @Suspendable or @DontInstrument annotation
                if (adesc.equals(SUSPENDABLE_DESC))
                    susp = SuspendableType.SUSPENDABLE;
                else if (adesc.equals(DONT_INSTRUMENT_DESC))
                    susp = SuspendableType.NON_SUSPENDABLE;
                susp = suspendableToSuperIfAbstract(access, susp);
                return super.visitAnnotation(adesc, visible);
            }

            @Override
            public void visitCode() {
                commit();
                super.visitCode();
            }

            @Override
            public void visitEnd() {
                if (exception != null)
                    return;
                commit();
                try {
                    super.visitEnd();
                } catch (RuntimeException e) {
                    exception = e;
                }
            }

            private void commit() {
                if (commited)
                    return;
                commited = true;
                if (db.isDebug())
                    db.log(LogLevel.INFO, "Method %s#%s%s suspendable: %s (markedSuspendable: %s setSuspendable: %s)", className, name, desc, susp, susp, setSuspendable);
                classEntry.set(name, desc, susp);
                if (susp == SuspendableType.SUSPENDABLE && checkAccessForMethodInstrumentation(access)) {
                    if (isSynchronized(access)) {
                        if (!db.isAllowMonitors())
                            throw new UnableToInstrumentException("synchronization", className, name, desc);
                        else
                            db.log(LogLevel.WARNING, "Method %s#%s%s is synchronized", className, name, desc);
                    }
                    methods.add(mn);
                } else {
                    MethodVisitor _mv = makeOutMV(mn);
                    _mv = new JSRInlinerAdapter(_mv, access, name, desc, signature, exceptions);
                    mn.accept(new MethodVisitor(ASMAPI, _mv) {

                        @Override
                        public void visitEnd() {
                        // don't call visitEnd on MV
                        }
                    });
                    // write method as-is
                    this.mv = _mv;
                }
            }
        };
    }
    return super.visitMethod(access, name, desc, signature, exceptions);
}
Also used : SuspendableType(co.paralleluniverse.fibers.instrument.MethodDatabase.SuspendableType) MethodNode(org.objectweb.asm.tree.MethodNode) ArrayList(java.util.ArrayList) JSRInlinerAdapter(org.objectweb.asm.commons.JSRInlinerAdapter) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 2 with SuspendableType

use of co.paralleluniverse.fibers.instrument.MethodDatabase.SuspendableType 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 3 with SuspendableType

use of co.paralleluniverse.fibers.instrument.MethodDatabase.SuspendableType in project quasar by puniverse.

the class CheckInstrumentationVisitor method visitMethod.

@Override
public MethodVisitor visitMethod(final int access, final String name, final String desc, String signature, String[] exceptions) {
    SuspendableType suspendable = null;
    if (suspendableInterface)
        suspendable = SuspendableType.SUSPENDABLE_SUPER;
    if (suspendable == null)
        suspendable = classEntry.check(name, desc);
    if (suspendable == null)
        suspendable = classifier.isSuspendable(db, sourceName, sourceDebugInfo, isInterface, className, classEntry.getSuperName(), classEntry.getInterfaces(), name, desc, signature, exceptions);
    if (suspendable == SuspendableType.SUSPENDABLE) {
        hasSuspendable = true;
        // synchronized methods can't be made suspendable
        if ((access & Opcodes.ACC_SYNCHRONIZED) == Opcodes.ACC_SYNCHRONIZED) {
            if (!className.equals("clojure/lang/LazySeq") && !db.isAllowMonitors())
                throw new UnableToInstrumentException("synchronized method", className, name, desc);
        }
    }
    suspendable = InstrumentClass.suspendableToSuperIfAbstract(access, suspendable);
    classEntry.set(name, desc, suspendable);
    if (// look for @Suspendable annotation
    suspendable == null)
        return new MethodVisitor(ASMAPI) {

            private boolean susp = false;

            @Override
            public AnnotationVisitor visitAnnotation(String adesc, boolean visible) {
                if (adesc.equals(SUSPENDABLE_DESC))
                    susp = true;
                return null;
            }

            @Override
            public void visitEnd() {
                super.visitEnd();
                classEntry.set(name, desc, InstrumentClass.suspendableToSuperIfAbstract(access, susp ? SuspendableType.SUSPENDABLE : SuspendableType.NON_SUSPENDABLE));
                hasSuspendable = hasSuspendable | susp;
            }
        };
    else
        return null;
}
Also used : SuspendableType(co.paralleluniverse.fibers.instrument.MethodDatabase.SuspendableType) AnnotationVisitor(org.objectweb.asm.AnnotationVisitor) MethodVisitor(org.objectweb.asm.MethodVisitor)

Aggregations

SuspendableType (co.paralleluniverse.fibers.instrument.MethodDatabase.SuspendableType)3 MethodVisitor (org.objectweb.asm.MethodVisitor)2 ArrayList (java.util.ArrayList)1 AnnotationVisitor (org.objectweb.asm.AnnotationVisitor)1 JSRInlinerAdapter (org.objectweb.asm.commons.JSRInlinerAdapter)1 AbstractInsnNode (org.objectweb.asm.tree.AbstractInsnNode)1 InvokeDynamicInsnNode (org.objectweb.asm.tree.InvokeDynamicInsnNode)1 MethodInsnNode (org.objectweb.asm.tree.MethodInsnNode)1 MethodNode (org.objectweb.asm.tree.MethodNode)1 Frame (org.objectweb.asm.tree.analysis.Frame)1