Bonus done
This commit is contained in:
parent
38c67580ae
commit
7969cef8aa
6 changed files with 106 additions and 113 deletions
|
@ -1,38 +0,0 @@
|
|||
package ex11;
|
||||
|
||||
import ch.usi.dag.disl.staticcontext.InvocationStaticContext;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
import org.objectweb.asm.signature.SignatureVisitor;
|
||||
|
||||
public class ArgumentLengthStaticContext extends InvocationStaticContext {
|
||||
|
||||
public String getInternalNameWithDescriptor() {
|
||||
return getInternalName() + getDescriptor();
|
||||
}
|
||||
|
||||
public int getArgumentLength() {
|
||||
final String descriptor = getDescriptor();
|
||||
final ArgumentLengthVisitor av = new ArgumentLengthVisitor();
|
||||
final SignatureReader sv = new SignatureReader(descriptor);
|
||||
sv.accept(av);
|
||||
return av.getLength();
|
||||
}
|
||||
|
||||
private static class ArgumentLengthVisitor extends SignatureVisitor {
|
||||
private int length = 0;
|
||||
|
||||
public ArgumentLengthVisitor() {
|
||||
super(589824);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitParameterType() {
|
||||
length++;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
40
DiSLProject2022/src-profiler/ex11/CallInfo.java
Normal file
40
DiSLProject2022/src-profiler/ex11/CallInfo.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package ex11;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record CallInfo(int instruction, long index, String caller, String callee, String callTarget) {
|
||||
private static final String FORMAT = "CallerMethodFQIN %s\nCallerBCI %d\ninvoketype %s\nCalleeMethodFQIN %s\nCallTargetFQIN %s";
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
CallInfo callInfo = (CallInfo) o;
|
||||
return instruction == callInfo.instruction && index == callInfo.index && caller.equals(callInfo.caller) &&
|
||||
callee.equals(callInfo.callee) && callTarget.equals(callInfo.callTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(instruction, index, caller, callee, callTarget);
|
||||
}
|
||||
|
||||
public String invokeType() {
|
||||
return switch (instruction) {
|
||||
case Opcodes.INVOKEDYNAMIC -> "dynamic";
|
||||
case Opcodes.INVOKESTATIC -> "static";
|
||||
case Opcodes.INVOKEINTERFACE -> "interface";
|
||||
case Opcodes.INVOKESPECIAL -> "special";
|
||||
case Opcodes.INVOKEVIRTUAL -> "virtual";
|
||||
default -> throw new IllegalStateException("Not an INVOKE* bytecode instruction: " + instruction);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(FORMAT, caller, index, invokeType(), callee, callTarget);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,46 +1,74 @@
|
|||
package ex11;
|
||||
|
||||
import ch.usi.dag.disl.annotation.Before;
|
||||
import ch.usi.dag.disl.dynamiccontext.DynamicContext;
|
||||
import ch.usi.dag.disl.guardcontext.ReflectionStaticContext;
|
||||
import ch.usi.dag.disl.annotation.ThreadLocal;
|
||||
import ch.usi.dag.disl.marker.BodyMarker;
|
||||
import ch.usi.dag.disl.marker.BytecodeMarker;
|
||||
import ch.usi.dag.disl.staticcontext.InstructionStaticContext;
|
||||
import ch.usi.dag.disl.staticcontext.InvocationStaticContext;
|
||||
import ch.usi.dag.disl.staticcontext.MethodStaticContext;
|
||||
|
||||
public class Instrumentation {
|
||||
@Before(marker = BytecodeMarker.class, args = "invokevirtual, invokespecial, invokeinterface", guard = TemporaryGuard.class)
|
||||
|
||||
@ThreadLocal
|
||||
private static int opCode;
|
||||
|
||||
@ThreadLocal
|
||||
private static int index;
|
||||
|
||||
@ThreadLocal
|
||||
private static String callee;
|
||||
|
||||
@ThreadLocal
|
||||
private static String caller;
|
||||
|
||||
@ThreadLocal
|
||||
private static boolean initialized;
|
||||
|
||||
@Before(marker = BytecodeMarker.class, args = "invokevirtual, invokeinterface")
|
||||
static void atObjectRefCallSite(final InstructionStaticContext isc,
|
||||
final MethodStaticContext msc,
|
||||
final ArgumentLengthStaticContext ivc,
|
||||
final DynamicContext dc) {
|
||||
final Object objectRef = dc.getStackValue(ivc.getArgumentLength(), Object.class);
|
||||
|
||||
|
||||
final String callTarget = objectRef.getClass().getName().replace('.', '/')
|
||||
.concat(".")
|
||||
.concat(ivc.getName());
|
||||
|
||||
// TODO: call target signature (handle covariant return types)
|
||||
|
||||
Profiler.registerCall(new Profiler.CallInfo(
|
||||
isc.getOpcode(),
|
||||
isc.getIndex(),
|
||||
msc.thisMethodFullName().concat(msc.thisMethodDescriptor()),
|
||||
ivc.getInternalNameWithDescriptor(),
|
||||
callTarget
|
||||
));
|
||||
final InvocationStaticContext ivc) {
|
||||
opCode = isc.getOpcode();
|
||||
index = isc.getIndex();
|
||||
caller = msc.thisMethodFullName().concat(msc.thisMethodDescriptor());
|
||||
callee = ivc.getInternalName().concat(ivc.getDescriptor());
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Before(marker = BytecodeMarker.class, args = "invokestatic", guard = TemporaryGuard.class)
|
||||
@Before(marker = BytecodeMarker.class, args = "invokedynamic")
|
||||
static void atObjectRefCallSiteDynamic(final InstructionStaticContext isc,
|
||||
final MethodStaticContext msc,
|
||||
final InvocationStaticContext ivc) {
|
||||
opCode = isc.getOpcode();
|
||||
index = isc.getIndex();
|
||||
caller = msc.thisMethodFullName().concat(msc.thisMethodDescriptor());
|
||||
callee = "[UNDETERMINED]";
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Before(marker = BodyMarker.class, guard = IsNotConstructorOrPrivateMethod.class)
|
||||
static void beforeMethod(MethodStaticContext msc) {
|
||||
// we can ignore here constructors and private methods since we know they must be invoked with "invokespecial"
|
||||
// which performs static binding. Instrumenting the constructor of java.lang.Object would actually cause a
|
||||
// segmentation fault of the JVM.
|
||||
if (initialized) {
|
||||
Profiler.registerCall(new CallInfo(opCode, index, caller, callee, msc.getUniqueInternalName()));
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Before(marker = BytecodeMarker.class, args = "invokestatic, invokespecial")
|
||||
static void atStaticCallSite(final InstructionStaticContext isc,
|
||||
final MethodStaticContext msc,
|
||||
final ArgumentLengthStaticContext ivc) {
|
||||
Profiler.registerCall(new Profiler.CallInfo(
|
||||
final InvocationStaticContext ivc) {
|
||||
final String v = ivc.getInternalName().concat(ivc.getDescriptor());
|
||||
Profiler.registerCall(new CallInfo(
|
||||
isc.getOpcode(),
|
||||
isc.getIndex(),
|
||||
msc.thisMethodFullName().concat(msc.thisMethodDescriptor()),
|
||||
ivc.getInternalNameWithDescriptor(),
|
||||
ivc.getInternalNameWithDescriptor()
|
||||
v,
|
||||
v
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package ex11;
|
||||
|
||||
import ch.usi.dag.disl.annotation.GuardMethod;
|
||||
import ch.usi.dag.disl.staticcontext.ClassStaticContext;
|
||||
import ch.usi.dag.disl.staticcontext.MethodStaticContext;
|
||||
|
||||
public class IsNotConstructorOrPrivateMethod {
|
||||
@GuardMethod
|
||||
public static boolean guard(final ClassStaticContext csc, final MethodStaticContext msc) {
|
||||
return !msc.isMethodConstructor() && !msc.isMethodPrivate();
|
||||
}
|
||||
}
|
|
@ -1,10 +1,7 @@
|
|||
package ex11;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class Profiler {
|
||||
private static final Map<CallInfo, long[]> count = new HashMap<>();
|
||||
|
@ -28,39 +25,4 @@ public final class Profiler {
|
|||
count.computeIfAbsent(info, ignored -> new long[1])[0]++;
|
||||
}
|
||||
|
||||
public record CallInfo(int instruction, long index, String caller, String callee, String callTarget) {
|
||||
private static final String FORMAT = "CallerMethodFQIN %s\nCallerBCI %d\ninvoketype %s\nCalleeMethodFQIN %s\nCallTargetFQIN %s";
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
CallInfo callInfo = (CallInfo) o;
|
||||
return index == callInfo.index && instruction == callInfo.instruction &&
|
||||
caller.equals(callInfo.caller) && callee.equals(callInfo.callee) &&
|
||||
callTarget.equals(callInfo.callTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(instruction, index, caller, callee, callTarget);
|
||||
}
|
||||
|
||||
public String invokeType() {
|
||||
return switch (instruction) {
|
||||
case Opcodes.INVOKEDYNAMIC -> "dynamic";
|
||||
case Opcodes.INVOKESTATIC -> "static";
|
||||
case Opcodes.INVOKEINTERFACE -> "interface";
|
||||
case Opcodes.INVOKESPECIAL -> "special";
|
||||
case Opcodes.INVOKEVIRTUAL -> "virtual";
|
||||
default -> throw new IllegalStateException("Not an INVOKE* bytecode instruction: " + instruction);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(FORMAT, caller, index, invokeType(), callee, callTarget);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package ex11;
|
||||
|
||||
import ch.usi.dag.disl.annotation.GuardMethod;
|
||||
import ch.usi.dag.disl.staticcontext.ClassStaticContext;
|
||||
|
||||
public class TemporaryGuard {
|
||||
@GuardMethod
|
||||
public static boolean isEx11(final ClassStaticContext csc) {
|
||||
return csc.getName().startsWith("ex11.");
|
||||
}
|
||||
}
|
Reference in a new issue