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);
}
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);
}
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;
}
Aggregations