Bonus done

This commit is contained in:
Claudio Maggioni 2023-01-20 18:26:55 +01:00
parent 38c67580ae
commit 7969cef8aa
6 changed files with 106 additions and 113 deletions

View file

@ -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;
}
}
}

View 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);
}
}

View file

@ -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
)); ));
} }
} }

View file

@ -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();
}
}

View file

@ -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);
}
}
} }

View file

@ -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.");
}
}