Skip to content

Commit

Permalink
Merge branch 'main' into feature/better-versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
Machine-Maker committed Sep 28, 2024
2 parents 51a731b + faa3e98 commit 72f505f
Show file tree
Hide file tree
Showing 22 changed files with 172 additions and 85 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ jobs:
fail-fast: true
steps:
- uses: actions/checkout@v4
- uses: gradle/actions/wrapper-validation@v3
- name: JDK ${{ matrix.java }}
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
- uses: gradle/actions/setup-gradle@v3
- uses: gradle/actions/setup-gradle@v4
- name: Build
run: ./gradlew build --stacktrace
- name: Determine Status
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ private DefineClassRule(final String proxyClassName, final boolean assumeClassLo
this.assumeClassLoader = assumeClassLoader;
}

@Override
public boolean shouldProcess(final ClassProcessingContext context, final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface, final boolean isInvokeDynamic) {
return true; // see comment below
}

// We could split this into multiple rules and return false for shouldProcess when the processing class doesn't
// extend (S)CL. However since the MethodHandles.Lookup portion always needs to run, the actual benefit would
// be beyond minute (if not actually worse).
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/io/papermc/asm/rules/builder/RuleFactory.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.papermc.asm.rules.builder;

import io.papermc.asm.rules.RewriteRule;
import io.papermc.asm.rules.builder.matcher.field.FieldMatcher;
import io.papermc.asm.rules.builder.matcher.field.FieldMatcherBuilder;
import io.papermc.asm.rules.builder.matcher.method.MethodMatcher;
import io.papermc.asm.rules.builder.matcher.method.targeted.TargetedMethodMatcher;
import java.lang.constant.ClassDesc;
Expand All @@ -28,6 +28,8 @@ static RuleFactory.Factory combine(final RuleFactory.Factory... factories) {

void plainStaticRewrite(ClassDesc newOwner, MethodMatcher methodMatcher);

void plainStaticRewrite(ClassDesc newOwner, MethodMatcher methodMatcher, String staticMethodName);

default void changeParamToSuper(final Class<?> oldParamType, final Class<?> newParamType, final MethodMatcher methodMatcher) {
if (!newParamType.isAssignableFrom(oldParamType)) {
throw new IllegalArgumentException(newParamType + " is not a superclass of " + oldParamType);
Expand Down Expand Up @@ -70,7 +72,7 @@ default void changeReturnTypeDirectWithContext(final Class<?> newReturnType, fin

void changeReturnTypeDirectWithContext(ClassDesc newReturnType, Method staticHandler, TargetedMethodMatcher targetedMethodMatcher);

void changeFieldToMethod(@Nullable String getterName, @Nullable String setterName, boolean isInterfaceMethod, Consumer<? super FieldMatcher.Builder> builderConsumer);
void changeFieldToMethod(@Nullable String getterName, @Nullable String setterName, boolean isInterfaceMethod, Consumer<? super FieldMatcherBuilder> builderConsumer);

default void moveInstanceMethod(final Class<?> newOwner, final String newMethodName, final MethodMatcher methodMatcher) {
this.moveInstanceMethod(desc(newOwner), newMethodName, methodMatcher);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.papermc.asm.rules.RewriteRule;
import io.papermc.asm.rules.builder.matcher.field.FieldMatcher;
import io.papermc.asm.rules.builder.matcher.field.FieldMatcherBuilder;
import io.papermc.asm.rules.builder.matcher.method.MethodMatcher;
import io.papermc.asm.rules.builder.matcher.method.targeted.TargetedMethodMatcher;
import io.papermc.asm.rules.field.FieldToMethodRewrite;
Expand Down Expand Up @@ -43,6 +44,11 @@ public void plainStaticRewrite(final ClassDesc newOwner, final MethodMatcher met
this.addRule(new DirectStaticRewrite(this.owners, methodMatcher, newOwner));
}

@Override
public void plainStaticRewrite(final ClassDesc newOwner, final MethodMatcher methodMatcher, final String staticMethodName) {
this.addRule(new DirectStaticRewrite(this.owners, staticMethodName, methodMatcher, newOwner));
}

@Override
public void changeParamToSuper(final ClassDesc legacyParamType, final ClassDesc newParamType, final MethodMatcher methodMatcher) {
this.addRule(new SuperTypeParamRewrite(this.owners, methodMatcher, legacyParamType, newParamType));
Expand Down Expand Up @@ -78,7 +84,7 @@ private void changeReturnTypeDirect(final ClassDesc newReturnType, final Method
}

@Override
public void changeFieldToMethod(final @Nullable String getterName, final @Nullable String setterName, final boolean isInterfaceMethod, final Consumer<? super FieldMatcher.Builder> builderConsumer) {
public void changeFieldToMethod(final @Nullable String getterName, final @Nullable String setterName, final boolean isInterfaceMethod, final Consumer<? super FieldMatcherBuilder> builderConsumer) {
this.addRule(new FieldToMethodRewrite(this.owners, build(builderConsumer, FieldMatcher::builder), getterName, setterName, isInterfaceMethod));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,16 @@
package io.papermc.asm.rules.builder.matcher.field;

import java.lang.constant.ClassDesc;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;

import static java.util.function.Predicate.isEqual;

@FunctionalInterface
public interface FieldMatcher {

boolean matchesName(String name);
static FieldMatcherBuilderImpl builder() {
return new FieldMatcherBuilderImpl();
}

boolean matches(String name, String descriptor);

static Builder builder() {
return new Builder();
default FieldMatcher or(final FieldMatcher other) {
return (name, descriptor) -> this.matches(name, descriptor) || other.matches(name, descriptor);
}

final class Builder implements io.papermc.asm.util.Builder<FieldMatcher> {

private Predicate<String> byName = $ -> false;
private Predicate<? super ClassDesc> byType = $ -> true;

private Builder() {
}

public Builder names(final String... names) {
return this.names(List.of(names));
}

public Builder names(final Collection<String> names) {
this.byName = this.byName.or(names::contains);
return this;
}

public Builder desc(final ClassDesc desc) {
return this.desc(isEqual(desc));
}

public Builder desc(final Predicate<? super ClassDesc> predicate) {
this.byType = predicate;
return this;
}

@Override
public FieldMatcher build() {
return new FieldMatcherImpl(this.byName, this.byType);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.papermc.asm.rules.builder.matcher.field;

import io.papermc.asm.util.Builder;
import java.lang.constant.ClassDesc;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;

import static java.util.function.Predicate.isEqual;

public interface FieldMatcherBuilder extends Builder<FieldMatcher> {

default FieldMatcherBuilder match(final String fieldName) {
return this.match(fieldName, $ -> true);
}

default FieldMatcherBuilder match(final String fieldName, final ClassDesc fieldDesc) {
return this.match(fieldName, isEqual(fieldDesc));
}

default FieldMatcherBuilder match(final String fieldName, final Predicate<ClassDesc> fieldDescPredicate) {
return this.match(isEqual(fieldName), fieldDescPredicate);
}

default FieldMatcherBuilder match(final Collection<String> fieldNames) {
return this.match(fieldNames, $ -> true);
}

default FieldMatcherBuilder match(final Collection<String> fieldNames, final ClassDesc fieldDesc) {
return this.match(fieldNames, isEqual(fieldDesc));
}

default FieldMatcherBuilder match(final Collection<String> fieldNames, final Predicate<ClassDesc> fieldDescPredicate) {
final List<String> copy = List.copyOf(fieldNames);
return this.match(copy::contains, fieldDescPredicate);
}

default FieldMatcherBuilder match(final Predicate<String> fieldNamePredicate) {
return this.match(fieldNamePredicate, $ -> true);
}

default FieldMatcherBuilder match(final Predicate<String> fieldNamePredicate, final ClassDesc fieldDesc) {
return this.match(fieldNamePredicate, isEqual(fieldDesc));
}

FieldMatcherBuilder match(Predicate<String> fieldNamePredicate, Predicate<ClassDesc> fieldDescPredicate);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.papermc.asm.rules.builder.matcher.field;

import java.lang.constant.ClassDesc;
import java.util.function.Predicate;

public final class FieldMatcherBuilderImpl implements FieldMatcherBuilder {

private FieldMatcher matcher = (name, descriptor) -> false;

FieldMatcherBuilderImpl() {
}

@Override
public FieldMatcherBuilder match(final Predicate<String> fieldNamePredicate, final Predicate<ClassDesc> fieldDescPredicate) {
this.matcher = this.matcher.or((name, descriptor) -> fieldNamePredicate.test(name) && fieldDescPredicate.test(ClassDesc.ofDescriptor(descriptor)));
return this;
}

@Override
public FieldMatcher build() {
return this.matcher;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ public FieldMatcherImpl(final Predicate<? super String> byName, final Predicate<
this.byDesc = byDesc;
}

@Override
public boolean matchesName(final String name) {
return this.byName.test(name);
}

@Override
public boolean matches(final String name, final String descriptor) {
return this.byName.test(name) && this.byDesc.test(classDesc(descriptor));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.papermc.asm.rules.builder.matcher.method;

import java.lang.constant.MethodTypeDesc;
import java.util.function.Consumer;
import java.util.function.Predicate;

@FunctionalInterface
Expand All @@ -10,6 +11,10 @@ static MethodMatcherBuilder builder() {
return new MethodMatcherBuilderImpl();
}

static MethodMatcher single(final String name, final Consumer<MethodMatcherBuilder.MatchBuilder> matchBuilderConsumer) {
return builder().match(name, matchBuilderConsumer).build();
}

boolean matches(int opcode, boolean isInvokeDynamic, String name, String descriptor);

default boolean matches(final int opcode, final boolean isInvokeDynamic, final String name, final MethodTypeDesc descriptor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ private static MethodMatcher createStaticMatcher(final ClassDesc legacyEnumType)
.build();
}

final class EnumVirtualMethods implements GeneratedStaticRewrite {
final class EnumVirtualMethods implements GeneratedStaticRewrite, OwnableMethodRewriteRule.Filtered {

@Override
public MethodMatcher methodMatcher() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,12 @@ public void visitFieldInsn(final int opcode, final String owner, final String na
interface Rewrite {
void apply(MethodVisitor delegate);
}

record SimpleRewrite(int opcode, String owner, String name, ClassDesc fieldTypeDesc) implements Rewrite {

@Override
public void apply(final MethodVisitor delegate) {
delegate.visitFieldInsn(this.opcode, this.owner, this.name, this.fieldTypeDesc.descriptorString());
}
}
}
27 changes: 13 additions & 14 deletions src/main/java/io/papermc/asm/rules/field/FieldToMethodRewrite.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,20 @@ MethodTypeDesc desc(final ClassDesc fieldTypeDesc) {
}

@Override
public Rewrite rewrite(final ClassProcessingContext context, final int opcode, final String owner, final String name, final ClassDesc fieldTypeDesc) {
public @Nullable Rewrite rewrite(final ClassProcessingContext context, final int opcode, final String owner, final String name, final ClassDesc fieldTypeDesc) {
final Type type = switch (opcode) {
case Opcodes.GETFIELD, Opcodes.GETSTATIC -> Type.GETTER;
case Opcodes.PUTFIELD, Opcodes.PUTSTATIC -> Type.SETTER;
default -> throw new IllegalArgumentException("Unexpected opcode: " + opcode);
};
final @Nullable String methodName = switch (type) {
case GETTER -> this.getterName;
case SETTER -> this.setterName;
};
if (methodName == null) {
return null;
}
return (delegate) -> {
final Type type = switch (opcode) {
case Opcodes.GETFIELD, Opcodes.GETSTATIC -> Type.GETTER;
case Opcodes.PUTFIELD, Opcodes.PUTSTATIC -> Type.SETTER;
default -> throw new IllegalArgumentException("Unexpected opcode: " + opcode);
};
final @Nullable String methodName = switch (type) {
case GETTER -> this.getterName;
case SETTER -> this.setterName;
};
if (methodName == null) {
return;
}

delegate.visitMethodInsn(type.opcode(opcode), owner, methodName, type.desc(fieldTypeDesc).descriptorString(), this.isInterfaceMethod);
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@

import io.papermc.asm.ClassProcessingContext;
import io.papermc.asm.rules.builder.matcher.method.MethodMatcher;
import io.papermc.asm.rules.generate.GeneratedMethodHolder;
import io.papermc.asm.rules.method.rewrite.ConstructorRewrite;
import io.papermc.asm.rules.method.rewrite.MethodRewrite;
import io.papermc.asm.rules.method.rewrite.SimpleRewrite;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;

import static io.papermc.asm.util.DescriptorUtils.toOwner;
import static io.papermc.asm.util.OpcodeUtils.staticOp;

/**
* Rewrites a method by just directly routing it to an identical static method in another class.
Expand All @@ -12,7 +21,29 @@
* @param methodMatcher the method matcher to use
* @param staticRedirectOwner the owner to redirect to
*/
public record DirectStaticRewrite(Set<ClassDesc> owners, MethodMatcher methodMatcher, ClassDesc staticRedirectOwner) implements StaticRewrite {
public record DirectStaticRewrite(Set<ClassDesc> owners, @Nullable String staticMethodName, MethodMatcher methodMatcher, ClassDesc staticRedirectOwner) implements StaticRewrite, OwnableMethodRewriteRule.Filtered {

public DirectStaticRewrite(final Set<ClassDesc> owners, final MethodMatcher methodMatcher, final ClassDesc staticRedirectOwner) {
this(owners, null, methodMatcher, staticRedirectOwner);
}

@Override
public MethodRewrite<GeneratedMethodHolder.MethodCallData> createRewrite(final ClassProcessingContext context, final MethodTypeDesc intermediateDescriptor, final GeneratedMethodHolder.MethodCallData originalCallData) {
if (this.staticMethodName() == null) {
return StaticRewrite.super.createRewrite(context, intermediateDescriptor, originalCallData);
} else {
return new SimpleRewrite(staticOp(originalCallData.isInvokeDynamic()), this.staticRedirectOwner(context), this.staticMethodName(), this.transformToRedirectDescriptor(intermediateDescriptor), false, originalCallData.isInvokeDynamic());
}
}

@Override
public MethodRewrite<GeneratedMethodHolder.ConstructorCallData> createConstructorRewrite(final ClassProcessingContext context, final MethodTypeDesc intermediateDescriptor, final GeneratedMethodHolder.ConstructorCallData originalCallData) {
if (this.staticMethodName() == null) {
return StaticRewrite.super.createConstructorRewrite(context, intermediateDescriptor, originalCallData);
} else {
return new ConstructorRewrite(this.staticRedirectOwner(context), toOwner(originalCallData.owner()), this.staticMethodName(), this.transformToRedirectDescriptor(intermediateDescriptor));
}
}

@Override
public ClassDesc staticRedirectOwner(final ClassProcessingContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ public interface MethodRewriteRule extends RewriteRule {
* @param isInvokeDynamic if the method call is from an invokedynamic instruction
* @return true to continue processing the instruction
*/
default boolean shouldProcess(final ClassProcessingContext context, final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface, final boolean isInvokeDynamic) {
return true;
}
boolean shouldProcess(final ClassProcessingContext context, final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface, final boolean isInvokeDynamic);

/**
* Creates a {@link MethodRewrite} which will be applied to the processed bytecode.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public record MoveInstanceMethod(
MethodMatcher methodMatcher,
ClassDesc newOwner,
String newMethodName
) implements GeneratedStaticRewrite {
) implements GeneratedStaticRewrite, OwnableMethodRewriteRule.Filtered {

@Override
public @Nullable MethodRewrite<?> rewrite(final ClassProcessingContext context, final boolean isInvokeDynamic, final int opcode, final ClassDesc owner, final String name, final MethodTypeDesc descriptor, final boolean isInterface) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import static io.papermc.asm.util.OpcodeUtils.isVirtual;
import static io.papermc.asm.util.OpcodeUtils.staticOp;

public interface StaticRewrite extends OwnableMethodRewriteRule.Filtered {
public interface StaticRewrite extends MethodRewriteRule {

String CONSTRUCTOR_METHOD_NAME = "<init>";

Expand Down
Loading

0 comments on commit 72f505f

Please sign in to comment.