ex11 minus invokedynamic handling and return type for call target
This commit is contained in:
parent
6a7bf23a9d
commit
38c67580ae
4 changed files with 157 additions and 0 deletions
|
@ -0,0 +1,38 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,46 @@
|
||||||
package ex11;
|
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.marker.BytecodeMarker;
|
||||||
|
import ch.usi.dag.disl.staticcontext.InstructionStaticContext;
|
||||||
|
import ch.usi.dag.disl.staticcontext.MethodStaticContext;
|
||||||
|
|
||||||
public class Instrumentation {
|
public class Instrumentation {
|
||||||
|
@Before(marker = BytecodeMarker.class, args = "invokevirtual, invokespecial, invokeinterface", guard = TemporaryGuard.class)
|
||||||
|
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
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before(marker = BytecodeMarker.class, args = "invokestatic", guard = TemporaryGuard.class)
|
||||||
|
static void atStaticCallSite(final InstructionStaticContext isc,
|
||||||
|
final MethodStaticContext msc,
|
||||||
|
final ArgumentLengthStaticContext ivc) {
|
||||||
|
Profiler.registerCall(new Profiler.CallInfo(
|
||||||
|
isc.getOpcode(),
|
||||||
|
isc.getIndex(),
|
||||||
|
msc.thisMethodFullName().concat(msc.thisMethodDescriptor()),
|
||||||
|
ivc.getInternalNameWithDescriptor(),
|
||||||
|
ivc.getInternalNameWithDescriptor()
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
66
DiSLProject2022/src-profiler/ex11/Profiler.java
Normal file
66
DiSLProject2022/src-profiler/ex11/Profiler.java
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
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<>();
|
||||||
|
|
||||||
|
private static boolean stop = false;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
|
stop = true;
|
||||||
|
for (final var entry : count.entrySet()) {
|
||||||
|
System.out.println(entry.getKey().toString() + "\n#invokes " + entry.getValue()[0] + "\n");
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Profiler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerCall(final CallInfo info) {
|
||||||
|
if (stop) return;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
DiSLProject2022/src-profiler/ex11/TemporaryGuard.java
Normal file
11
DiSLProject2022/src-profiler/ex11/TemporaryGuard.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
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