diff --git a/DiSLProject2022/src-profiler/ex11/ArgumentLengthStaticContext.java b/DiSLProject2022/src-profiler/ex11/ArgumentLengthStaticContext.java deleted file mode 100644 index 01a28d2..0000000 --- a/DiSLProject2022/src-profiler/ex11/ArgumentLengthStaticContext.java +++ /dev/null @@ -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; - } - } -} diff --git a/DiSLProject2022/src-profiler/ex11/CallInfo.java b/DiSLProject2022/src-profiler/ex11/CallInfo.java new file mode 100644 index 0000000..07b4870 --- /dev/null +++ b/DiSLProject2022/src-profiler/ex11/CallInfo.java @@ -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); + } + +} diff --git a/DiSLProject2022/src-profiler/ex11/Instrumentation.java b/DiSLProject2022/src-profiler/ex11/Instrumentation.java index d0a6940..37d0e0b 100644 --- a/DiSLProject2022/src-profiler/ex11/Instrumentation.java +++ b/DiSLProject2022/src-profiler/ex11/Instrumentation.java @@ -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 )); } } diff --git a/DiSLProject2022/src-profiler/ex11/IsNotConstructorOrPrivateMethod.java b/DiSLProject2022/src-profiler/ex11/IsNotConstructorOrPrivateMethod.java new file mode 100644 index 0000000..047d1d8 --- /dev/null +++ b/DiSLProject2022/src-profiler/ex11/IsNotConstructorOrPrivateMethod.java @@ -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(); + } +} diff --git a/DiSLProject2022/src-profiler/ex11/Profiler.java b/DiSLProject2022/src-profiler/ex11/Profiler.java index ecadd51..a6fdb53 100644 --- a/DiSLProject2022/src-profiler/ex11/Profiler.java +++ b/DiSLProject2022/src-profiler/ex11/Profiler.java @@ -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 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); - } - } - } diff --git a/DiSLProject2022/src-profiler/ex11/TemporaryGuard.java b/DiSLProject2022/src-profiler/ex11/TemporaryGuard.java deleted file mode 100644 index 87a97ce..0000000 --- a/DiSLProject2022/src-profiler/ex11/TemporaryGuard.java +++ /dev/null @@ -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."); - } -}