Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
co.paralleluniverse.fibers.instrument.SuspOffsetsAfterInstrClassVisitor Maven / Gradle / Ivy
Go to download
The core library for Fibers on Java, compatible with Java 11-16. Forked from puniverse/quasar
/*
* Quasar: lightweight threads and actors for the JVM.
* Copyright (c) 2015-2016, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.fibers.instrument;
import co.paralleluniverse.fibers.Instrumented;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodNode;
import java.util.*;
import static co.paralleluniverse.fibers.instrument.Classes.*;
import static co.paralleluniverse.fibers.instrument.QuasarInstrumentor.ASMAPI;
/**
* @author circlespainter
*/
class SuspOffsetsAfterInstrClassVisitor extends ClassVisitor {
private final MethodDatabase db;
private String sourceName, className;
SuspOffsetsAfterInstrClassVisitor(ClassVisitor cv, MethodDatabase db) {
super(ASMAPI, cv);
this.db = db;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
this.className = name;
// need atleast 1.5 for annotations to work
if (version < Opcodes.V1_5)
version = Opcodes.V1_5;
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public void visitSource(String source, String debug) {
this.sourceName = source;
super.visitSource(source, debug);
}
@Override
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
if ((access & Opcodes.ACC_NATIVE) == 0 && !isYieldMethod(className, name)) {
// Bytecode-level AST of a method, being a MethodVisitor itself can be filled through delegation from another visitor
final MethodNode mn = new MethodNode(access, name, desc, signature, exceptions);
// Analyze, fill and enqueue method ASTs
final MethodVisitor outMV = super.visitMethod(access, name, desc, signature, exceptions);
return new MethodVisitor(ASMAPI, outMV) {
private Label currLabel = null;
private int prevOffset = -1;
private boolean instrumented;
private boolean optimized = false;
private int methodStart = -1, methodEnd = -1;
private int[] suspCallSites = new int[0];
private String[] suspCallSiteNames = new String[0];
private List suspOffsetsAfterInstrL = new ArrayList<>();
@Override
public AnnotationVisitor visitAnnotation(final String adesc, boolean visible) {
if (Classes.INSTRUMENTED_DESC.equals(adesc)) {
instrumented = true;
return new AnnotationVisitor(ASMAPI) { // Only collect info
@Override
public void visit(String attrib, Object value) {
if (null != attrib)
switch (attrib) {
case Instrumented.FIELD_NAME_METHOD_START:
methodStart = (Integer) value;
break;
case Instrumented.FIELD_NAME_METHOD_END:
methodEnd = (Integer) value;
break;
case Instrumented.FIELD_NAME_METHOD_OPTIMIZED:
optimized = (Boolean) value;
break;
case Instrumented.FIELD_NAME_SUSPENDABLE_CALL_SITES:
suspCallSites = (int[]) value;
break;
case Instrumented.FIELD_NAME_SUSPENDABLE_CALL_SITES_OFFSETS_AFTER_INSTR:
; // Ignore, we're filling it
break;
default:
throw new RuntimeException("Unexpected `@Instrumented` field: " + attrib);
}
}
@Override
public AnnotationVisitor visitArray(String attrib) {
// String[] value not handled by visit
if (Instrumented.FIELD_NAME_SUSPENDABLE_CALL_SITE_NAMES.equals(attrib))
return new AnnotationVisitor(ASMAPI) {
List callSites = new ArrayList<>();
@Override
public void visit(String attrib, Object value) {
callSites.add((String) value);
}
@Override
public void visitEnd() {
suspCallSiteNames = callSites.toArray(new String[0]);
}
};
else
return super.visitArray(name);
}
};
}
return super.visitAnnotation(adesc, visible);
}
@Override
public void visitLocalVariable(String name, String desc, String sig, Label lStart, Label lEnd, int slot) {
super.visitLocalVariable(name, desc, sig, lStart, lEnd, slot);
}
@Override
public void visitLabel(Label label) {
if (instrumented) {
currLabel = label;
}
super.visitLabel(label);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
if (instrumented) {
final int type = AbstractInsnNode.METHOD_INSN;
if (InstrumentMethod.isSuspendableCall(db, type, opcode, owner, name, desc) &&
!Classes.STACK_NAME.equals(owner) && // postRestore
currLabel != null && currLabel.info instanceof Integer)
addLine();
}
super.visitMethodInsn(opcode, owner, name, desc, isInterface);
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle handle, Object... objects) {
if (instrumented) {
final int type = AbstractInsnNode.INVOKE_DYNAMIC_INSN;
final int opcode = Opcodes.INVOKEDYNAMIC;
if (InstrumentMethod.isSuspendableCall(db, type, opcode, handle.getOwner(), name, desc) &&
!Classes.STACK_NAME.equals(handle.getOwner()) && // postRestore
currLabel != null && currLabel.info instanceof Integer)
addLine();
}
super.visitInvokeDynamicInsn(name, desc, handle, objects);
}
@Override
public void visitEnd() {
if (instrumented)
InstrumentMethod.emitInstrumentedAnn (
db, outMV, mn, sourceName, className, optimized, methodStart, methodEnd,
suspCallSites, suspCallSiteNames, toIntArray(suspOffsetsAfterInstrL));
super.visitEnd();
}
private void addLine() {
final int currOffset = (Integer) currLabel.info;
if (currOffset > prevOffset) {
suspOffsetsAfterInstrL.add(currOffset);
prevOffset = currOffset;
}
}
};
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
}