22
33import jakarta .annotation .Nonnull ;
44import jakarta .annotation .Nullable ;
5+ import org .objectweb .asm .ClassReader ;
6+ import org .objectweb .asm .ClassVisitor ;
57import org .objectweb .asm .ClassWriter ;
8+ import org .objectweb .asm .MethodVisitor ;
69import org .objectweb .asm .Type ;
710import org .objectweb .asm .tree .ClassNode ;
811import org .slf4j .Logger ;
12+ import software .coley .recaf .RecafConstants ;
913import software .coley .recaf .analytics .logging .Logging ;
14+ import software .coley .recaf .info .JvmClassInfo ;
1015import software .coley .recaf .services .inheritance .InheritanceGraph ;
1116import software .coley .recaf .util .visitors .WorkspaceClassWriter ;
17+ import software .coley .recaf .workspace .model .bundle .JvmClassBundle ;
18+ import software .coley .recaf .workspace .model .resource .RuntimeWorkspaceResource ;
1219import xyz .wagyourtail .jvmdg .ClassDowngrader ;
1320import xyz .wagyourtail .jvmdg .cli .Flags ;
1421import xyz .wagyourtail .jvmdg .util .Pair ;
22+ import xyz .wagyourtail .jvmdg .version .map .FullyQualifiedMemberNameAndDesc ;
1523import xyz .wagyourtail .jvmdg .version .map .MemberNameAndDesc ;
1624
1725import java .io .IOException ;
1826import java .util .Arrays ;
27+ import java .util .HashSet ;
1928import java .util .List ;
2029import java .util .Map ;
2130import java .util .Set ;
2938 */
3039public class JavaDowngraderUtil {
3140 private static final Logger logger = Logging .get (JavaDowngraderUtil .class );
41+ private static final String [] undesirableStubs = {
42+ // Array of stubs (owner;name;desc) that we do not want to pass back to callers.
43+ "Lxyz/wagyourtail/jvmdg/j18/stub/java_base/J_L_System;getProperty;(Ljava/lang/String;)Ljava/lang/String;" ,
44+ "Lxyz/wagyourtail/jvmdg/j18/stub/java_base/J_L_System;getProperties;()Ljava/util/Properties;"
45+ };
3246
3347 /**
3448 * Downgrade the provided classes.
@@ -74,6 +88,8 @@ public static void downgrade(int targetJavaVersion,
7488
7589 Flags flags = new Flags ();
7690 flags .classVersion = targetClassVersion ;
91+ for (String undesirableStub : undesirableStubs )
92+ flags .debugSkipStub .add (FullyQualifiedMemberNameAndDesc .of (undesirableStub ));
7793
7894 try (ClassDowngrader downgrader = new RecafClassDowngrader (flags , inheritanceGraph )) {
7995 int maxClassFileVersion = downgrader .maxVersion ();
@@ -94,6 +110,7 @@ public static void downgrade(int targetJavaVersion,
94110 try {
95111 Map <String , byte []> downgraded = downgrader .downgrade (new AtomicReference <>(className ), classBytes , false ,
96112 key -> getBytes (maxClassFileVersion , classes , key ));
113+ fillStubClasses (downgraded );
97114 if (downgraded != null )
98115 downgraded .forEach (transformConsumer );
99116 } catch (Throwable t ) {
@@ -118,6 +135,40 @@ private static byte[] getBytes(int maxClassFileVersion, @Nonnull Map<String, byt
118135 return classBytes ;
119136 }
120137
138+ private static void fillStubClasses (@ Nullable Map <String , byte []> downgraded ) {
139+ if (downgraded == null || downgraded .isEmpty ())
140+ return ;
141+
142+ // Find all referenced stubs from the downgraded classes.
143+ Set <String > referencedStubs = new HashSet <>();
144+ for (byte [] classBytes : downgraded .values ()) {
145+ ClassReader reader = new ClassReader (classBytes );
146+ reader .accept (new ClassVisitor (RecafConstants .getAsmVersion ()) {
147+ public MethodVisitor visitMethod (int access , String name , String descriptor , String signature , String [] exceptions ) {
148+ return new MethodVisitor (RecafConstants .getAsmVersion ()) {
149+ public void visitFieldInsn (int opcode , String owner , String name , String descriptor ) {
150+ if (owner .startsWith ("xyz/wagyourtail/jvmdg/" ) && owner .contains ("/stub/" ))
151+ referencedStubs .add (owner );
152+ }
153+
154+ public void visitMethodInsn (int opcode , String owner , String name , String descriptor , boolean isInterface ) {
155+ if (owner .startsWith ("xyz/wagyourtail/jvmdg/" ) && owner .contains ("/stub/" ))
156+ referencedStubs .add (owner .replace ('/' , '.' ));
157+ }
158+ };
159+ }
160+ }, ClassReader .SKIP_DEBUG | ClassReader .SKIP_FRAMES );
161+ }
162+
163+ // Add all referenced stubs to the downgraded output.
164+ JvmClassBundle runtimeBundle = RuntimeWorkspaceResource .getInstance ().getJvmClassBundle ();
165+ for (String referencedStub : referencedStubs ) {
166+ JvmClassInfo cls = runtimeBundle .get (referencedStub );
167+ if (cls != null )
168+ downgraded .put (cls .getName (), cls .getBytecode ());
169+ }
170+ }
171+
121172 private static class RecafClassDowngrader extends ClassDowngrader {
122173 private final InheritanceGraph inheritanceGraph ;
123174
0 commit comments