67 lines
2.2 KiB
Java
67 lines
2.2 KiB
Java
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|