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;
|
package ex11;
|
||||||
|
|
||||||
import ch.usi.dag.disl.annotation.Before;
|
import ch.usi.dag.disl.annotation.Before;
|
||||||
import ch.usi.dag.disl.dynamiccontext.DynamicContext;
|
import ch.usi.dag.disl.annotation.ThreadLocal;
|
||||||
import ch.usi.dag.disl.guardcontext.ReflectionStaticContext;
|
import ch.usi.dag.disl.marker.BodyMarker;
|
||||||
import ch.usi.dag.disl.marker.BytecodeMarker;
|
import ch.usi.dag.disl.marker.BytecodeMarker;
|
||||||
import ch.usi.dag.disl.staticcontext.InstructionStaticContext;
|
import ch.usi.dag.disl.staticcontext.InstructionStaticContext;
|
||||||
|
import ch.usi.dag.disl.staticcontext.InvocationStaticContext;
|
||||||
import ch.usi.dag.disl.staticcontext.MethodStaticContext;
|
import ch.usi.dag.disl.staticcontext.MethodStaticContext;
|
||||||
|
|
||||||
public class Instrumentation {
|
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,
|
static void atObjectRefCallSite(final InstructionStaticContext isc,
|
||||||
final MethodStaticContext msc,
|
final MethodStaticContext msc,
|
||||||
final ArgumentLengthStaticContext ivc,
|
final InvocationStaticContext ivc) {
|
||||||
final DynamicContext dc) {
|
opCode = isc.getOpcode();
|
||||||
final Object objectRef = dc.getStackValue(ivc.getArgumentLength(), Object.class);
|
index = isc.getIndex();
|
||||||
|
caller = msc.thisMethodFullName().concat(msc.thisMethodDescriptor());
|
||||||
|
callee = ivc.getInternalName().concat(ivc.getDescriptor());
|
||||||
final String callTarget = objectRef.getClass().getName().replace('.', '/')
|
initialized = true;
|
||||||
.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
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@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,
|
static void atStaticCallSite(final InstructionStaticContext isc,
|
||||||
final MethodStaticContext msc,
|
final MethodStaticContext msc,
|
||||||
final ArgumentLengthStaticContext ivc) {
|
final InvocationStaticContext ivc) {
|
||||||
Profiler.registerCall(new Profiler.CallInfo(
|
final String v = ivc.getInternalName().concat(ivc.getDescriptor());
|
||||||
|
Profiler.registerCall(new CallInfo(
|
||||||
isc.getOpcode(),
|
isc.getOpcode(),
|
||||||
isc.getIndex(),
|
isc.getIndex(),
|
||||||
msc.thisMethodFullName().concat(msc.thisMethodDescriptor()),
|
msc.thisMethodFullName().concat(msc.thisMethodDescriptor()),
|
||||||
ivc.getInternalNameWithDescriptor(),
|
v,
|
||||||
ivc.getInternalNameWithDescriptor()
|
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;
|
package ex11;
|
||||||
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public final class Profiler {
|
public final class Profiler {
|
||||||
private static final Map<CallInfo, long[]> count = new HashMap<>();
|
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]++;
|
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