Skip to content

Commit

Permalink
Create separate exception for irrecoverable header mismatches
Browse files Browse the repository at this point in the history
  • Loading branch information
Hapstyx committed Nov 30, 2024
1 parent d2d1a89 commit 44e2e74
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -162,25 +162,20 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str
MethodHeader computedMethodHeader = submissionClassInfo.getComputedMethodHeader(name, descriptor);

if (!TransformationUtils.contextIsCompatible(access, computedMethodHeader.access())) {
MethodHeader methodHeader = new MethodHeader(computedMethodHeader.owner(),
computedMethodHeader = new MethodHeader(computedMethodHeader.owner(),
access,
name + "$submission",
transformationContext.toComputedType(descriptor).getDescriptor(),
signature,
exceptions);
return new SubmissionMethodVisitor(methodHeader.toMethodVisitor(getDelegate()),
transformationContext,
submissionClassInfo,
originalMethodHeader,
methodHeader);
} else {
visitedMethods.add(computedMethodHeader);
return new SubmissionMethodVisitor(computedMethodHeader.toMethodVisitor(getDelegate()),
transformationContext,
submissionClassInfo,
originalMethodHeader,
computedMethodHeader);
}
return new SubmissionMethodVisitor(computedMethodHeader.toMethodVisitor(getDelegate()),
transformationContext,
submissionClassInfo,
originalMethodHeader,
computedMethodHeader);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,10 +327,8 @@ public void visitCode() {
}

if (headerMismatch) {
TransformationUtils.buildExceptionForHeaderMismatch(getDelegate(),
"Method has incorrect return or parameter types",
computedMethodHeader,
originalMethodHeader);
new IncompatibleHeaderException("Method has incorrect return or parameter types", computedMethodHeader, originalMethodHeader)
.replicateInBytecode(getDelegate(), true);
} else {
// visit original code
super.visitCode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public final class Constants {
public static final Type STRING_ARRAY_TYPE = Type.getType(String[].class);
public static final Type SET_TYPE = Type.getType(Set.class);

public static final Type HEADER_TYPE = Type.getType(Header.class);
public static final Type CLASS_HEADER_TYPE = Type.getType(ClassHeader.class);
public static final Type FIELD_HEADER_TYPE = Type.getType(FieldHeader.class);
public static final Type METHOD_HEADER_TYPE = Type.getType(MethodHeader.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.tudalgo.algoutils.transform.util;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;

import static org.objectweb.asm.Opcodes.*;
import static org.objectweb.asm.Opcodes.ATHROW;

/**
* Thrown to indicate that a class, field or method (including constructors) was declared incorrectly.
* <p>
* For fields, this means that the field was declared static in the submission class while not being
* declared static in the solution class, or vice versa.
* </p>
* <p>
* For methods, it may indicate the same problem as for fields.
* It may also indicate that methods or constructors have the wrong number of parameters.
* Lastly, it may indicate that the return type or parameter types are incompatible, e.g.,
* a submission class' method returns a primitive type while the solution class' method returns
* a reference type.
* </p>
*
* @author Daniel Mangold
*/
public class IncompatibleHeaderException extends RuntimeException {

private final String message;
private final Header expected;
private final Header actual;

/**
* Constructs a new {@link IncompatibleHeaderException} instance.
*
* @param message the exception message
* @param expected the expected header
* @param actual the actual header
*/
public IncompatibleHeaderException(String message, Header expected, Header actual) {
super();
this.message = message;
this.expected = expected;
this.actual = actual;
}

@Override
public String getMessage() {
return "%s%nExpected: %s%nActual: %s%n".formatted(message, expected, actual);
}

/**
* Replicates this exception in bytecode and optionally throws it.
* If it is not thrown, a reference to the newly created instance is located at the top
* of the method visitor's stack upon return.
*
* @param mv the method visitor to use
* @param throwException whether the exception should be thrown
* @return the maximum stack size used
*/
public int replicateInBytecode(MethodVisitor mv, boolean throwException) {
int maxStack, stackSize;

mv.visitTypeInsn(NEW, Type.getInternalName(getClass()));
mv.visitInsn(DUP);
mv.visitLdcInsn(message);
maxStack = stackSize = 3;
maxStack = Math.max(maxStack, stackSize++ + expected.buildHeader(mv));
maxStack = Math.max(maxStack, stackSize + actual.buildHeader(mv));
mv.visitMethodInsn(INVOKESPECIAL,
Type.getInternalName(getClass()),
"<init>",
Type.getMethodDescriptor(Type.VOID_TYPE, Constants.STRING_TYPE, Constants.HEADER_TYPE, Constants.HEADER_TYPE),
false);
if (throwException) {
mv.visitInsn(ATHROW);
}
return maxStack;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -217,20 +217,6 @@ public static int buildArray(MethodVisitor mv, Type componentType, Object[] arra
return maxStack;
}

public static void buildExceptionForHeaderMismatch(MethodVisitor mv, String message, Header expected, Header actual) {
mv.visitTypeInsn(NEW, Type.getInternalName(AssertionFailedError.class));
mv.visitInsn(DUP);
mv.visitLdcInsn(message);
expected.buildHeader(mv);
actual.buildHeader(mv);
mv.visitMethodInsn(INVOKESPECIAL,
Type.getInternalName(AssertionFailedError.class),
"<init>",
Type.getMethodDescriptor(Type.VOID_TYPE, Constants.STRING_TYPE, Constants.OBJECT_TYPE, Constants.OBJECT_TYPE),
false);
mv.visitInsn(ATHROW);
}

/**
* Returns a human-readable form of the given modifiers.
*
Expand Down

0 comments on commit 44e2e74

Please sign in to comment.