Skip to content

Commit 4c8f43b

Browse files
committed
TransformationPhase
1 parent 678522d commit 4c8f43b

File tree

9 files changed

+97
-22
lines changed

9 files changed

+97
-22
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ yarn_mappings=18w49a.22
99
loader_version=0.14.21
1010

1111
# Mod Properties
12-
mod_version=0.1.2
12+
mod_version=0.2
1313
maven_group=net.mine_diver
1414
archives_base_name=SpASM

src/main/java/net/mine_diver/spasm/api/transform/ClassTransformer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
import org.jetbrains.annotations.NotNull;
44
import org.objectweb.asm.tree.ClassNode;
55

6-
public interface ClassTransformer {
6+
public interface ClassTransformer extends PhaseListener {
77
@NotNull TransformationResult transform(final @NotNull ClassLoader classLoader, final @NotNull ClassNode classNode);
88
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package net.mine_diver.spasm.api.transform;
2+
3+
import com.google.common.collect.ImmutableSet;
4+
import com.google.common.collect.Sets;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
import java.util.EnumSet;
8+
9+
public interface PhaseListener {
10+
ImmutableSet<TransformationPhase>
11+
DEFAULT_PHASES = Sets.immutableEnumSet(TransformationPhase.BEFORE_MIXINS),
12+
ALL_PHASES = Sets.immutableEnumSet(EnumSet.allOf(TransformationPhase.class));
13+
14+
15+
default @NotNull ImmutableSet<TransformationPhase> getPhases() {
16+
return DEFAULT_PHASES;
17+
}
18+
}

src/main/java/net/mine_diver/spasm/api/transform/RawClassTransformer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
import java.util.Optional;
66

7-
public interface RawClassTransformer {
7+
public interface RawClassTransformer extends PhaseListener {
88
@NotNull Optional<byte[]> transform(final @NotNull ClassLoader classLoader, final @NotNull String className, final byte @NotNull [] classBytes);
99
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package net.mine_diver.spasm.api.transform;
2+
3+
import net.mine_diver.spasm.impl.SpASM;
4+
5+
public enum TransformationPhase {
6+
BEFORE_MIXINS,
7+
AFTER_MIXINS;
8+
9+
public static TransformationPhase getCurrent() {
10+
return SpASM.getCurrentPhase();
11+
}
12+
}

src/main/java/net/mine_diver/spasm/impl/MixinTransformerHook.java

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import lombok.AccessLevel;
44
import lombok.experimental.FieldDefaults;
55
import lombok.val;
6+
import net.mine_diver.spasm.api.transform.TransformationPhase;
67
import net.mine_diver.spasm.api.transform.TransformationResult;
78
import org.objectweb.asm.ClassReader;
89
import org.objectweb.asm.ClassWriter;
@@ -25,24 +26,39 @@ class MixinTransformerHook<T extends TreeTransformer & IMixinTransformer> extend
2526

2627
@Override
2728
public byte[] transformClassBytes(String name, String transformedName, byte[] basicClass) {
28-
if (basicClass != null && !name.startsWith("org.objectweb.asm.") && !name.startsWith("net.mine_diver.spasm.") && !name.startsWith("com.google.common.")) {
29-
val classLoader = Thread.currentThread().getContextClassLoader();
30-
for (int i = 0; i < RAW_TRANSFORMERS.size(); i++) {
31-
val transformationResult = RAW_TRANSFORMERS.get(i).transform(classLoader, name, basicClass);
32-
if (transformationResult.isPresent()) basicClass = transformationResult.get();
33-
}
34-
val classNode = new ClassNode();
35-
new ClassReader(basicClass).accept(classNode, 0);
36-
switch (TRANSFORMERS.stream()
37-
.map(classTransformer -> classTransformer.transform(classLoader, classNode))
38-
.reduce(PASS, TransformationResult::choose)) {
39-
case SUCCESS:
40-
val classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
41-
classNode.accept(classWriter);
42-
basicClass = classWriter.toByteArray();
43-
break;
44-
}
29+
if (shouldSkip(name, basicClass)) return super.transformClassBytes(name, transformedName, basicClass);
30+
val classLoader = Thread.currentThread().getContextClassLoader();
31+
basicClass = transform(name, basicClass, classLoader, TransformationPhase.BEFORE_MIXINS);
32+
basicClass = super.transformClassBytes(name, transformedName, basicClass);
33+
basicClass = transform(name, basicClass, classLoader, TransformationPhase.AFTER_MIXINS);
34+
return basicClass;
35+
}
36+
37+
private static boolean shouldSkip(String name, byte[] basicClass) {
38+
return basicClass == null || name.startsWith("org.objectweb.asm.") || name.startsWith("net.mine_diver.spasm.") || name.startsWith("com.google.common.");
39+
}
40+
41+
private static byte[] transform(String name, byte[] basicClass, ClassLoader classLoader, TransformationPhase phase) {
42+
SpASM.currentPhase = phase;
43+
for (int i = 0; i < RAW_TRANSFORMERS.size(); i++) {
44+
val transformer = RAW_TRANSFORMERS.get(i);
45+
if (!transformer.getPhases().contains(phase)) continue;
46+
val transformationResult = transformer.transform(classLoader, name, basicClass);
47+
if (transformationResult.isPresent()) basicClass = transformationResult.get();
48+
}
49+
val classNode = new ClassNode();
50+
new ClassReader(basicClass).accept(classNode, 0);
51+
switch (TRANSFORMERS.stream()
52+
.filter(transformer -> transformer.getPhases().contains(phase))
53+
.map(classTransformer -> classTransformer.transform(classLoader, classNode))
54+
.reduce(PASS, TransformationResult::choose)) {
55+
case SUCCESS:
56+
val classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
57+
classNode.accept(classWriter);
58+
basicClass = classWriter.toByteArray();
59+
break;
4560
}
46-
return super.transformClassBytes(name, transformedName, basicClass);
61+
SpASM.currentPhase = null;
62+
return basicClass;
4763
}
4864
}

src/main/java/net/mine_diver/spasm/impl/SpASM.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import net.fabricmc.loader.api.FabricLoader;
66
import net.mine_diver.spasm.api.transform.ClassTransformer;
77
import net.mine_diver.spasm.api.transform.RawClassTransformer;
8+
import net.mine_diver.spasm.api.transform.TransformationPhase;
89
import org.jetbrains.annotations.NotNull;
910
import org.objectweb.asm.tree.ClassNode;
1011
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
@@ -18,6 +19,7 @@
1819
public class SpASM implements IMixinConfigPlugin {
1920
static final ImmutableList<ClassTransformer> TRANSFORMERS = entrypoint("transformer", ClassTransformer.class);
2021
static final ImmutableList<RawClassTransformer> RAW_TRANSFORMERS = entrypoint("raw_transformer", RawClassTransformer.class);
22+
static TransformationPhase currentPhase;
2123

2224
static {
2325
try {
@@ -42,6 +44,10 @@ private static <T extends TreeTransformer & IMixinTransformer> void hook() throw
4244
mixinTransformerField.set(knotClassDelegate, new MixinTransformerHook<>((T) mixinTransformerField.get(knotClassDelegate)));
4345
}
4446

47+
public static TransformationPhase getCurrentPhase() {
48+
return currentPhase;
49+
}
50+
4551
@Override
4652
public void onLoad(String mixinPackage) {}
4753

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package net.mine_diver.spasm.test;
2+
3+
import com.google.common.collect.ImmutableSet;
4+
import net.mine_diver.spasm.api.transform.RawClassTransformer;
5+
import net.mine_diver.spasm.api.transform.TransformationPhase;
6+
import org.jetbrains.annotations.NotNull;
7+
8+
import java.util.Arrays;
9+
import java.util.Optional;
10+
11+
public class AllPhaseTransformer implements RawClassTransformer {
12+
@Override
13+
public @NotNull ImmutableSet<TransformationPhase> getPhases() {
14+
return ALL_PHASES;
15+
}
16+
17+
@Override
18+
public @NotNull Optional<byte[]> transform(@NotNull ClassLoader classLoader, @NotNull String className, byte @NotNull [] classBytes) {
19+
System.out.println("Phase transformer! " + className + " " + Arrays.hashCode(classBytes) + " " + TransformationPhase.getCurrent());
20+
return Optional.empty();
21+
}
22+
}

src/test/resources/fabric.mod.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"net.mine_diver.spasm.test.TestTransformer"
2121
],
2222
"spasm:raw_transformer": [
23-
"net.mine_diver.spasm.test.TestRawTransformer"
23+
"net.mine_diver.spasm.test.TestRawTransformer",
24+
"net.mine_diver.spasm.test.AllPhaseTransformer"
2425
]
2526
},
2627
"depends": {

0 commit comments

Comments
 (0)