Skip to content
This repository was archived by the owner on May 12, 2024. It is now read-only.

Commit 5ad15d5

Browse files
authored
Merge pull request #11 from RaphiMC/optimize_stackmapframes
Optimize stackmapframes
2 parents 8f31a46 + 03662f5 commit 5ad15d5

58 files changed

Lines changed: 363 additions & 191 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/JavaDowngraderTransformer.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import net.lenni0451.classtransform.utils.ASMUtils;
2323
import net.raphimc.javadowngrader.JavaDowngrader;
2424
import net.raphimc.javadowngrader.RuntimeDepCollector;
25+
import net.raphimc.javadowngrader.transformer.DowngradeResult;
26+
import org.objectweb.asm.ClassWriter;
2527
import org.objectweb.asm.tree.ClassNode;
2628

2729
import java.util.function.Predicate;
@@ -62,10 +64,10 @@ public JavaDowngraderTransformer(final TransformerManager transformerManager, fi
6264
}
6365

6466
JavaDowngraderTransformer(
65-
TransformerManager transformerManager,
66-
int targetVersion,
67-
Predicate<String> classFilter,
68-
RuntimeDepCollector depCollector
67+
TransformerManager transformerManager,
68+
int targetVersion,
69+
Predicate<String> classFilter,
70+
RuntimeDepCollector depCollector
6971
) {
7072
this.transformerManager = transformerManager;
7173
this.targetVersion = targetVersion;
@@ -83,11 +85,12 @@ public byte[] transform(String className, byte[] bytecode, boolean calculateStac
8385
return null;
8486
}
8587

86-
final ClassNode classNode = ASMUtils.fromBytes(bytecode);
87-
JavaDowngrader.downgrade(classNode, this.targetVersion, this.depCollector);
88+
final ClassNode classNode = ASMUtils.fromBytes(bytecode, 0);
89+
final DowngradeResult result = JavaDowngrader.downgrade(classNode, this.targetVersion, this.depCollector);
8890

8991
if (calculateStackMapFrames) {
90-
return ASMUtils.toBytes(classNode, this.transformerManager.getClassTree(), this.transformerManager.getClassProvider());
92+
int flags = result.requiresStackMapFrames() ? ClassWriter.COMPUTE_FRAMES : ClassWriter.COMPUTE_MAXS;
93+
return ASMUtils.toBytes(classNode, this.transformerManager.getClassTree(), this.transformerManager.getClassProvider(), flags);
9194
} else {
9295
return ASMUtils.toStacklessBytes(classNode);
9396
}
@@ -124,10 +127,10 @@ public Builder depCollector(RuntimeDepCollector depCollector) {
124127

125128
public JavaDowngraderTransformer build() {
126129
return new JavaDowngraderTransformer(
127-
transformerManager,
128-
targetVersion,
129-
classFilter,
130-
depCollector
130+
transformerManager,
131+
targetVersion,
132+
classFilter,
133+
depCollector
131134
);
132135
}
133136
}

impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/AbstractClassProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ protected AbstractClassProvider(final IClassProvider parent) {
3333
}
3434

3535
@Override
36-
public byte[] getClass(String name) {
36+
public byte[] getClass(String name) throws ClassNotFoundException {
3737
if (this.parent == null) {
3838
throw new NoSuchElementException("Unable to find class '" + name + "'");
3939
}

impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/LazyFileClassProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public LazyFileClassProvider(final Collection<File> path, final IClassProvider p
3939
}
4040

4141
@Override
42-
public byte[] getClass(String name) {
42+
public byte[] getClass(String name) throws ClassNotFoundException {
4343
for (int i = 0; i < this.path.length; i++) {
4444
Object element = this.path[i];
4545
if (element instanceof File) {
@@ -51,7 +51,7 @@ public byte[] getClass(String name) {
5151
}
5252
try {
5353
return ((PathClassProvider) element).getClass(name);
54-
} catch (NoSuchElementException ignored) {
54+
} catch (ClassNotFoundException ignored) {
5555
}
5656
}
5757
return super.getClass(name);

impl-classtransform/src/main/java/net/raphimc/javadowngrader/impl/classtransform/classprovider/PathClassProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public PathClassProvider(final Path root, final IClassProvider parent) {
4040
}
4141

4242
@Override
43-
public byte[] getClass(String name) {
43+
public byte[] getClass(String name) throws ClassNotFoundException {
4444
final Path path = this.root.resolve(ClassNameUtil.toClassFilename(name));
4545
if (Files.exists(path)) {
4646
try {

src/main/java/net/raphimc/javadowngrader/JavaDowngrader.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package net.raphimc.javadowngrader;
1919

20+
import net.raphimc.javadowngrader.transformer.DowngradeResult;
2021
import net.raphimc.javadowngrader.transformer.DowngradingTransformer;
2122
import net.raphimc.javadowngrader.transformer.j10.Java11ToJava10;
2223
import net.raphimc.javadowngrader.transformer.j11.Java12ToJava11;
@@ -61,10 +62,11 @@ public class JavaDowngrader {
6162
*
6263
* @param classNode The class to downgrade
6364
* @param targetVersion The target Java version
65+
* @return The {@link DowngradeResult}
6466
* @see ClassNode
6567
*/
66-
public static void downgrade(final ClassNode classNode, final int targetVersion) {
67-
downgrade(classNode, targetVersion, RuntimeDepCollector.NULL);
68+
public static DowngradeResult downgrade(final ClassNode classNode, final int targetVersion) {
69+
return downgrade(classNode, targetVersion, RuntimeDepCollector.NULL);
6870
}
6971

7072
/**
@@ -74,15 +76,18 @@ public static void downgrade(final ClassNode classNode, final int targetVersion)
7476
* @param targetVersion The target Java version
7577
* @param depCollector The {@link RuntimeDepCollector} to use to collect runtime dependencies. Check the javadoc
7678
* of {@link RuntimeDepCollector} for more info.
79+
* @return The {@link DowngradeResult}
7780
* @see ClassNode
7881
* @see RuntimeDepCollector
7982
*/
80-
public static void downgrade(final ClassNode classNode, final int targetVersion, final RuntimeDepCollector depCollector) {
83+
public static DowngradeResult downgrade(final ClassNode classNode, final int targetVersion, final RuntimeDepCollector depCollector) {
84+
final DowngradeResult result = new DowngradeResult();
8185
for (DowngradingTransformer transformer : TRANSFORMER) {
8286
if (transformer.getTargetVersion() >= targetVersion && (classNode.version & 0xFF) > transformer.getTargetVersion()) {
83-
transformer.transform(classNode, depCollector);
87+
transformer.transform(classNode, depCollector, result);
8488
}
8589
}
90+
return result;
8691
}
8792

8893
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* This file is part of JavaDowngrader - https://github.com/RaphiMC/JavaDowngrader
3+
* Copyright (C) 2023 RK_01/RaphiMC and contributors
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package net.raphimc.javadowngrader.transformer;
19+
20+
public class DowngradeResult {
21+
22+
private int transformerCount;
23+
private boolean requiresStackMapFrames;
24+
25+
/**
26+
* @return The amount of transformers that were applied
27+
*/
28+
public int getTransformerCount() {
29+
return this.transformerCount;
30+
}
31+
32+
/**
33+
* Increments the transformer count by 1.
34+
*/
35+
public void incrementTransformerCount() {
36+
this.transformerCount++;
37+
}
38+
39+
/**
40+
* @return If the class requires stack map frame recalculation
41+
*/
42+
public boolean requiresStackMapFrames() {
43+
return this.requiresStackMapFrames;
44+
}
45+
46+
/**
47+
* Sets the class to require stack map frame recalculation.
48+
*/
49+
public void setRequiresStackMapFrames() {
50+
this.requiresStackMapFrames = true;
51+
}
52+
53+
/**
54+
* Adds the values of the given result to this result.
55+
*
56+
* @param result The result to add
57+
*/
58+
public void add(final DowngradeResult result) {
59+
this.transformerCount += result.transformerCount;
60+
this.requiresStackMapFrames |= result.requiresStackMapFrames;
61+
}
62+
63+
}

src/main/java/net/raphimc/javadowngrader/transformer/DowngradingTransformer.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,19 @@ protected void addClassReplacement(final String oldName, final String newName, S
7979
this.classReplacements.put(oldName, classes);
8080
}
8181

82-
public void transform(final ClassNode classNode) {
83-
transform(classNode, RuntimeDepCollector.NULL);
82+
public void transform(final ClassNode classNode, final DowngradeResult result) {
83+
transform(classNode, RuntimeDepCollector.NULL, result);
8484
}
8585

86-
public void transform(final ClassNode classNode, final RuntimeDepCollector depCollector) {
86+
public void transform(final ClassNode classNode, final RuntimeDepCollector depCollector, final DowngradeResult result) {
8787
if ((classNode.version & 0xFF) > this.sourceVersion) {
8888
throw new IllegalArgumentException("Input class version is higher than supported");
8989
}
9090
if ((classNode.version & 0xFF) <= this.targetVersion) {
9191
return;
9292
}
9393

94-
this.preTransform(classNode);
94+
this.preTransform(classNode, result);
9595

9696
int bridge = 100;
9797
for (final MethodNode methodNode : classNode.methods) {
@@ -112,9 +112,11 @@ public void transform(final ClassNode classNode, final RuntimeDepCollector depCo
112112
}
113113
if (replacer != null) {
114114
methodNode.instructions.insertBefore(
115-
methodInsn, replacer.getReplacement(classNode, methodNode, methodInsn.name, methodInsn.desc, depCollector)
115+
methodInsn, replacer.getReplacement(classNode, methodNode, methodInsn.name, methodInsn.desc, depCollector, result)
116116
);
117117
methodNode.instructions.remove(methodInsn);
118+
119+
result.incrementTransformerCount();
118120
}
119121
} else if (insn instanceof InvokeDynamicInsnNode) {
120122
final InvokeDynamicInsnNode invokeDynamicInsn = (InvokeDynamicInsnNode) insn;
@@ -131,20 +133,21 @@ public void transform(final ClassNode classNode, final RuntimeDepCollector depCo
131133
}
132134
if (replacer != null) {
133135
final String desc = handle.getTag() == Opcodes.H_INVOKESTATIC || handle.getTag() == Opcodes.H_GETSTATIC || handle.getTag() == Opcodes.H_PUTSTATIC
134-
? handle.getDesc()
135-
: "(L" + handle.getOwner() + ';' + handle.getDesc().substring(1);
136+
? handle.getDesc()
137+
: "(L" + handle.getOwner() + ';' + handle.getDesc().substring(1);
136138
final MethodNode bridgeMethod = new MethodNode(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, BRIDGE_PREFIX + (bridge++), desc, null, null);
137139
final Type[] argumentTypes = Type.getArgumentTypes(desc);
138140
for (int i1 = 0; i1 < argumentTypes.length; i1++) {
139141
bridgeMethod.instructions.add(new VarInsnNode(argumentTypes[i1].getOpcode(Opcodes.ILOAD), i1));
140142
}
141143
bridgeMethod.instructions.add(replacer.getReplacement(
142-
classNode, bridgeMethod, handle.getName(), handle.getDesc(), depCollector
144+
classNode, bridgeMethod, handle.getName(), handle.getDesc(), depCollector, result
143145
));
144146
bridgeMethod.instructions.add(new InsnNode(Type.getReturnType(handle.getDesc()).getOpcode(Opcodes.IRETURN)));
145147
classNode.methods.add(bridgeMethod);
146148

147149
invokeDynamicInsn.bsmArgs[i] = new Handle(Opcodes.H_INVOKESTATIC, classNode.name, bridgeMethod.name, bridgeMethod.desc, (classNode.access & Opcodes.ACC_INTERFACE) != 0);
150+
result.incrementTransformerCount();
148151
}
149152
}
150153
}
@@ -162,6 +165,7 @@ public String map(String internalName) {
162165
if (classes == null) {
163166
return internalName;
164167
}
168+
result.setRequiresStackMapFrames();
165169
classes.forEach(depCollector);
166170
return classes.get(0);
167171
}
@@ -182,15 +186,15 @@ public String map(String internalName) {
182186
}
183187
}
184188

185-
this.postTransform(classNode);
189+
this.postTransform(classNode, result);
186190

187191
classNode.version = this.targetVersion;
188192
}
189193

190-
protected void preTransform(final ClassNode classNode) {
194+
protected void preTransform(final ClassNode classNode, final DowngradeResult result) {
191195
}
192196

193-
protected void postTransform(final ClassNode classNode) {
197+
protected void postTransform(final ClassNode classNode, final DowngradeResult result) {
194198
}
195199

196200
public int getSourceVersion() {

src/main/java/net/raphimc/javadowngrader/transformer/MethodCallReplacer.java

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

2525
public interface MethodCallReplacer {
2626

27-
InsnList getReplacement(final ClassNode classNode, final MethodNode method, String originalName, final String originalDesc, final RuntimeDepCollector depCollector);
27+
InsnList getReplacement(final ClassNode classNode, final MethodNode method, String originalName, final String originalDesc, final RuntimeDepCollector depCollector, final DowngradeResult result);
2828

2929
}

src/main/java/net/raphimc/javadowngrader/transformer/j10/Java11ToJava10.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package net.raphimc.javadowngrader.transformer.j10;
1919

20+
import net.raphimc.javadowngrader.transformer.DowngradeResult;
2021
import net.raphimc.javadowngrader.transformer.DowngradingTransformer;
2122
import net.raphimc.javadowngrader.transformer.j10.methodcallreplacer.*;
2223
import org.objectweb.asm.Opcodes;
@@ -49,7 +50,7 @@ public Java11ToJava10() {
4950
}
5051

5152
@Override
52-
protected void preTransform(ClassNode classNode) {
53+
protected void preTransform(ClassNode classNode, DowngradeResult result) {
5354
this.makePackagePrivate(classNode);
5455
}
5556

src/main/java/net/raphimc/javadowngrader/transformer/j10/methodcallreplacer/CharacterToStringMCR.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@
1818
package net.raphimc.javadowngrader.transformer.j10.methodcallreplacer;
1919

2020
import net.raphimc.javadowngrader.RuntimeDepCollector;
21+
import net.raphimc.javadowngrader.transformer.DowngradeResult;
2122
import net.raphimc.javadowngrader.transformer.MethodCallReplacer;
2223
import org.objectweb.asm.Opcodes;
2324
import org.objectweb.asm.tree.*;
2425

2526
public class CharacterToStringMCR implements MethodCallReplacer {
2627
@Override
27-
public InsnList getReplacement(ClassNode classNode, MethodNode method, String originalName, String originalDesc, RuntimeDepCollector depCollector) {
28+
public InsnList getReplacement(ClassNode classNode, MethodNode method, String originalName, String originalDesc, RuntimeDepCollector depCollector, DowngradeResult result) {
2829
final InsnList replacement = new InsnList();
2930

3031
// int

0 commit comments

Comments
 (0)