diff --git a/ajde.core/pom.xml b/ajde.core/pom.xml index 8b147cdcfd..4741247178 100644 --- a/ajde.core/pom.xml +++ b/ajde.core/pom.xml @@ -45,6 +45,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons + org.aspectj testing-util diff --git a/ajde/pom.xml b/ajde/pom.xml index dd552c5af3..44428acc4b 100644 --- a/ajde/pom.xml +++ b/ajde/pom.xml @@ -36,6 +36,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons + org.aspectj org.aspectj.ajdt.core diff --git a/ajdoc/pom.xml b/ajdoc/pom.xml index cb22d21459..f183c37e9c 100644 --- a/ajdoc/pom.xml +++ b/ajdoc/pom.xml @@ -58,6 +58,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons + org.aspectj testing-util diff --git a/aspectjtools/pom.xml b/aspectjtools/pom.xml index 2280deb3f4..12d18fecfe 100644 --- a/aspectjtools/pom.xml +++ b/aspectjtools/pom.xml @@ -364,6 +364,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons + org.aspectj runtime diff --git a/aspectjweaver/aspectjweaver-assembly.xml b/aspectjweaver/aspectjweaver-assembly.xml index 576bb27009..877ddf6b1e 100644 --- a/aspectjweaver/aspectjweaver-assembly.xml +++ b/aspectjweaver/aspectjweaver-assembly.xml @@ -17,6 +17,7 @@ false org.ow2.asm:asm + org.ow2.asm:asm-commons diff --git a/aspectjweaver/pom.xml b/aspectjweaver/pom.xml index 34cefc74c9..c5702e2aa5 100644 --- a/aspectjweaver/pom.xml +++ b/aspectjweaver/pom.xml @@ -389,10 +389,19 @@ weaver ${project.version} + + org.aspectj + loadtime + ${project.version} + org.ow2.asm asm + + org.ow2.asm + asm-commons + diff --git a/loadtime/pom.xml b/loadtime/pom.xml index e73382812a..549ee286d9 100644 --- a/loadtime/pom.xml +++ b/loadtime/pom.xml @@ -41,6 +41,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons + org.aspectj testing-util diff --git a/loadtime/src/main/java/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java b/loadtime/src/main/java/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java index ad700fcfd0..9a10520755 100644 --- a/loadtime/src/main/java/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java +++ b/loadtime/src/main/java/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java @@ -11,23 +11,16 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.security.ProtectionDomain; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; import org.aspectj.bridge.AbortException; import org.aspectj.bridge.Constants; @@ -54,6 +47,9 @@ import org.aspectj.weaver.tools.WeavingAdaptor; import org.aspectj.weaver.tools.cache.WeavedClassCache; +import org.objectweb.asm.*; +import org.objectweb.asm.commons.ClassRemapper; +import org.objectweb.asm.commons.Remapper; import sun.misc.Unsafe; /** @@ -1029,156 +1025,243 @@ public void flushGeneratedClassesFor(String className) { } } - private Unsafe unsafe; + private static final Object lock = new Object(); - private Unsafe getUnsafe() throws NoSuchFieldException, IllegalAccessException { - if (unsafe == null) { - Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafeField.setAccessible(true); - return (Unsafe) theUnsafeField.get(null); - } - return unsafe; - } + /** + * Instance of either {@link sun.misc.Unsafe} or {@link jdk.internal.misc.Unsafe}. Luckily, both types have + * {@code defineClass} methods with identical signatures. I.e., method handle {@link #defineClassMethodHandle} can be + * invoked with the same set of parameters for both types. + */ + private static Object unsafeInstance = null; - private static Method bindTo_Method, invokeWithArguments_Method = null; - private static Object defineClassMethodHandle = null; + /** + * Method handle for defining new classes in arbitrary class loaders. For invocation, use in connection with + * {@link #unsafeInstance}. + */ + private static MethodHandle defineClassMethodHandle; - private static Boolean initializedForJava11 = false; + static { + try { + createDefineClassMethodHandle(); + } + catch (Exception initializationError) { + new RuntimeException( + "The aspect weaver cannot determine any valid method to define auxiliary classes in arbitrary class loaders. " + + "Aspect weaving will *not* work, and you will see subsequent errors. Please search for corresponding " + + "issues at https://github.com/eclipse-aspectj/aspectj/issues. If there are none, please create a new one.", + initializationError + ).printStackTrace(); + } + } - // In order to let this code compile on earlier versions of Java (8), use reflection to discover the elements - // we need to define classes. - private static synchronized void initializeForJava11() { - if (initializedForJava11) return; + /** + * Scaffolding for defining classes in arbitrary class loaders + *

+ * Inspired by and shamelessly adapted from Byte Buddy's {@code ClassInjector}. + * Special thanks to Byte Buddy (BB) author Rafael Winterhalter, who briefly mentioned this approach in a + * GitHub comment related to JDK issue + * JDK-8200559. + *

+ * Background: Instead of BB, we use ASM and reflection as follows: + *

+ * All these serve the sole purpose enable LTW without {@code --add-opens java.base/java.lang=ALL-UNNAMED} on the + * JVM command line on JDK 16+, which was necessary for AspectJ 1.9.7 (Java 16) to 1.9.21 (Java 21). + * + * @throws Exception if anything goes wrong, trying to determine a usable {@code defineClass} method handle from any + * of the inspected classes + */ + private static synchronized void createDefineClassMethodHandle() throws Exception { + Unsafe publicUnsafeInstance = null; try { - // MethodType defineClassMethodType = MethodType.methodType(Class.class, new Class[]{String.class, byte[].class, int.class, int.class, ProtectionDomain.class}); - Class methodType_Class = Class.forName("java.lang.invoke.MethodType"); - Method methodTypeMethodOnMethodTypeClass = methodType_Class.getDeclaredMethod("methodType", Class.class,Class[].class); - methodTypeMethodOnMethodTypeClass.setAccessible(true); - Object defineClassMethodType = methodTypeMethodOnMethodTypeClass.invoke(null, Class.class, new Class[] {String.class,byte[].class,int.class,int.class,ProtectionDomain.class}); - - // MethodHandles.Lookup methodHandlesLookup = MethodHandles.lookup(); - Class methodHandles_Class = Class.forName("java.lang.invoke.MethodHandles"); - Method lookupMethodOnMethodHandlesClass = methodHandles_Class.getDeclaredMethod("lookup"); - lookupMethodOnMethodHandlesClass.setAccessible(true); - Object methodHandlesLookup = lookupMethodOnMethodHandlesClass.invoke(null); - - // MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(ClassLoader.class, methodHandlesLookup); - Class methodHandlesLookup_Class = Class.forName("java.lang.invoke.MethodHandles$Lookup"); - Method privateLookupMethodOnMethodHandlesClass = methodHandles_Class.getDeclaredMethod("privateLookupIn",Class.class,methodHandlesLookup_Class); - privateLookupMethodOnMethodHandlesClass.setAccessible(true); - Object lookup = privateLookupMethodOnMethodHandlesClass.invoke(null, ClassLoader.class, methodHandlesLookup); - - // MethodHandle defineClassMethodHandle = lookup.findVirtual(ClassLoader.class, "defineClass", defineClassMethodType); - Method findVirtual_Method = methodHandlesLookup_Class.getDeclaredMethod("findVirtual", Class.class,String.class,methodType_Class); - findVirtual_Method.setAccessible(true); - defineClassMethodHandle = findVirtual_Method.invoke(lookup, ClassLoader.class, "defineClass",defineClassMethodType); - - // clazz = defineClassMethodHandle.bindTo(loader).invokeWithArguments(name, bytes, 0, bytes.length); - Class methodHandle_Class = Class.forName("java.lang.invoke.MethodHandle"); - bindTo_Method = methodHandle_Class.getDeclaredMethod("bindTo", Object.class); - invokeWithArguments_Method = methodHandle_Class.getDeclaredMethod("invokeWithArguments",Object[].class); - - initializedForJava11 = true; - } catch (Exception e) { - e.printStackTrace(); + Field publicUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + publicUnsafeField.setAccessible(true); + publicUnsafeInstance = (Unsafe) publicUnsafeField.get(null); + synchronized (lock) { + unsafeInstance = publicUnsafeInstance; + defineClassMethodHandle = createMethodHandle( + "sun.misc.Unsafe", "defineClass", + String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class + ); + } + } + catch (Exception publicUnsafeException) { + if (publicUnsafeInstance == null) + throw publicUnsafeException; + long overrideOffset = getAccessibleObjectOverrideOffset(publicUnsafeInstance); + Class internalUnsafeType = Class.forName("jdk.internal.misc.Unsafe"); + Field internalUnsafeField = internalUnsafeType.getDeclaredField("theUnsafe"); + publicUnsafeInstance.putBoolean(internalUnsafeField, overrideOffset, true); + Method internalUnsafeDefineClassMethod = internalUnsafeType.getMethod( + "defineClass", + String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class + ); + publicUnsafeInstance.putBoolean(internalUnsafeDefineClassMethod, overrideOffset, true); + synchronized (lock) { + unsafeInstance = internalUnsafeField.get(null); + defineClassMethodHandle = createMethodHandle(internalUnsafeDefineClassMethod); + } } } - private void defineClass(ClassLoader loader, String name, byte[] bytes, ProtectionDomain protectionDomain) { - if (trace.isTraceEnabled()) { - trace.enter("defineClass", this, new Object[] { loader, name, bytes }); + private static long getAccessibleObjectOverrideOffset(Unsafe unsafe) + throws IOException, ClassNotFoundException, NoSuchFieldException + { + Objects.requireNonNull(unsafe); + Field overrideField; + try { + overrideField = AccessibleObject.class.getDeclaredField("override"); + } + catch (NoSuchFieldException ignored) { + // On JDK 12+, field AccessibleObject.override is protected from reflection. The work-around is to create a + // mirror class with the same field layout by transforming the original class, so we can calculate the field + // offset of 'override' and set a value in the original class using the now known offset. + Class mirrorClass = getMirrorClass( + "java.lang.reflect.AccessibleObject", "org.aspectj.mirror.AccessibleObject", true + ); + overrideField = mirrorClass.getDeclaredField("override"); + } + return unsafe.objectFieldOffset(overrideField); + } + + public static MethodHandle createMethodHandle(String className, String methodName, Class... argumentTypes) + throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException + { + Class clazz = Class.forName(className); + Method method = clazz.getDeclaredMethod(methodName, argumentTypes); + return createMethodHandle(method, false); + } + + public static MethodHandle createMethodHandle(Method method) throws IllegalAccessException { + return createMethodHandle(method, false); + } + + public static MethodHandle createMethodHandle(Method method, boolean setAccessible) + throws IllegalAccessException + { + // Use Method::setAccessible to access private methods. Caveat: This does not work for classes in packages not + // exported to the calling module (for LTW usually the unnamed module). + if (setAccessible) + method.setAccessible(true); + return MethodHandles.lookup().unreflect(method); + } + + @SuppressWarnings("SameParameterValue") + private static Class getMirrorClass(String originalClass, String mirrorClass, boolean removeMethods) + throws IOException, ClassNotFoundException + { + Objects.requireNonNull(originalClass); + Objects.requireNonNull(mirrorClass); + if (mirrorClass.equals(originalClass)) + throw new IllegalArgumentException("Mirror class name must be different from original " + originalClass); + byte[] mirrorClassBytes = getMirrorClassBytes(originalClass, mirrorClass, removeMethods); + ClassLoader mirrorClassLoader = new SingleClassLoader(mirrorClass, mirrorClassBytes); + return mirrorClassLoader.loadClass(mirrorClass); + } + + private static byte[] getMirrorClassBytes(String originalClass, String mirrorClass, boolean removeMethods) + throws IOException, ClassNotFoundException + { + Class aClass = Class.forName(originalClass); + try (InputStream input = aClass.getResourceAsStream(aClass.getSimpleName() + ".class")) { + Objects.requireNonNull(input); + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); + ClassRemapper classRemapper = new ClassRemapper(classWriter, new ClassNameRemapper(originalClass, mirrorClass)); + ClassVisitor classVisitor = removeMethods ? new MethodAndConstructorRemover(classRemapper) : classRemapper; + new ClassReader(input).accept(classVisitor, 0); + return classWriter.toByteArray(); } - Object clazz = null; - debug("generating class '" + name + "'"); - if (LangUtil.is11VMOrGreater()) { - try { - if (!initializedForJava11) { - initializeForJava11(); - } - // Do this: clazz = defineClassMethodHandle.bindTo(loader).invokeWithArguments(name, bytes, 0, bytes.length, protectionDomain); - Object o = bindTo_Method.invoke(defineClassMethodHandle,loader); - clazz = invokeWithArguments_Method.invoke(o, new Object[] {new Object[] {name, bytes, 0, bytes.length, protectionDomain}}); + } - } catch (Throwable t) { - t.printStackTrace(System.err); - warn("define generated class failed", t); - } - } else { - try { - if (defineClassMethod == null) { - synchronized (lock) { - getUnsafe(); - defineClassMethod = - Unsafe.class.getDeclaredMethod("defineClass", String.class,byte[].class,Integer.TYPE,Integer.TYPE, ClassLoader.class,ProtectionDomain.class); - } - } - defineClassMethod.setAccessible(true); - clazz = defineClassMethod.invoke(getUnsafe(), name,bytes,0,bytes.length,loader,protectionDomain); - } catch (LinkageError le) { - le.printStackTrace(); - // likely thrown due to defining something that already exists? - // Old comments from before moving to Unsafe.defineClass(): - // is already defined (happens for X$ajcMightHaveAspect interfaces since aspects are reweaved) - // TODO maw I don't think this is OK and - } catch (Exception e) { - e.printStackTrace(System.err); - warn("define generated class failed", e); - } + private static class ClassNameRemapper extends Remapper { + private final String originalClass; + private final String mirrorClass; + + public ClassNameRemapper(String originalClass, String mirrorClass) { + this.originalClass = originalClass.replace('.', '/'); + this.mirrorClass = mirrorClass.replace('.', '/'); } - if (trace.isTraceEnabled()) { - trace.exit("defineClass", clazz); + @Override + public String map(String internalName) { + return internalName.equals(originalClass) ? mirrorClass : internalName; } } - static Method defineClassMethod; - private static final Object lock = new Object(); + /** + * ASM class visitor removing all methods and constructors from the given class, leaving only the original fields + */ + private static class MethodAndConstructorRemover extends ClassVisitor { + public MethodAndConstructorRemover(ClassRemapper classRemapper) { + super(Opcodes.ASM9, classRemapper); + } -// /* -// This method is equivalent to the following code but use reflection to compile on Java 7: -// MethodHandles.Lookup baseLookup = MethodHandles.lookup(); -// MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(ClassLoader.class, baseLookup); -// MethodHandle defineClassMethodHandle = lookup.findVirtual(ClassLoader.class, "defineClass", defineClassMethodType); -// handle.bindTo(classLoader).invokeWithArguments(className, classBytes, 0, classBytes.length)); -// */ -//@Override -//@SuppressWarnings("unchecked") -//public Class defineClass(ClassLoader classLoader, String className, byte[] classBytes) { -// Object baseLookup = methodHandlesLookup.invoke(null); -// Object lookup = methodHandlesPrivateLookupIn.invoke(null, ClassLoader.class, baseLookup); -// MethodHandle defineClassMethodHandle = (MethodHandle) lookupFindVirtual.invoke(lookup, ClassLoader.class, "defineClass", defineClassMethodType); -// try { -// return Cast.uncheckedCast(defineClassMethodHandle.bindTo(classLoader).invokeWithArguments(className, classBytes, 0, classBytes.length)); -// } catch (Throwable throwable) { -// throw new RuntimeException(throwable); -// return (Class) defineClassMethodHandle.bindTo(classLoader).invokeWithArguments(className, classBytes, 0, classBytes.length); -// } catch (Throwable e) { -// throw new RuntimeException(e); -// } -//} - - private void defineClass(ClassLoader loader, String name, byte[] bytes){ - defineClass(loader,name,bytes,null);//, ProtectionDomain protectionDomain) { + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + // Do not visit any methods or constructors, effectively removing them + return null; + } + } + + /** + * Throw-away child classloader with the sole purpose to define a single {@link Class} from the given bytecode + */ + private static class SingleClassLoader extends ClassLoader { + private final String mirrorClass; + private final byte[] mirrorClassBytes; + + private SingleClassLoader(String mirrorClass, byte[] mirrorClassBytes) { + super(SingleClassLoader.class.getClassLoader()); + this.mirrorClass = mirrorClass; + this.mirrorClassBytes = mirrorClassBytes; + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + return name.equals(mirrorClass) + ? super.defineClass(null, mirrorClassBytes, 0, mirrorClassBytes.length) + : super.loadClass(name); + } + } + + private void defineClass(ClassLoader loader, String name, byte[] bytes) { + defineClass(loader, name, bytes, null); + } + + private void defineClass(ClassLoader loader, String name, byte[] bytes, ProtectionDomain protectionDomain) { + if (trace.isTraceEnabled()) + trace.enter("defineClass", this, new Object[] { loader, name, bytes }); + debug("generating class '" + name + "'"); + Class definedClass = null; + try { + if (defineClassMethodHandle == null) + throw new RuntimeException("no valid method to define auxiliary classes -> weaver not working"); + definedClass = (Class) defineClassMethodHandle + .bindTo(unsafeInstance) + .invokeWithArguments(name, bytes, 0, bytes.length, loader, protectionDomain); + } + catch (Throwable t) { + t.printStackTrace(System.err); + warn("define generated class failed", t); + } + finally { + if (trace.isTraceEnabled()) + trace.exit("defineClass", definedClass); + } } -// if (trace.isTraceEnabled()) { -// trace.enter("defineClass", this, new Object[] { loader, name, bytes, protectionDomain }); -// } -// Object clazz = null; -// debug("generating class '" + name + "'"); -// try { -// getUnsafe().defineClass(name, bytes, 0, bytes.length, loader, protectionDomain); -// } catch (LinkageError le) { -// // likely thrown due to defining something that already exists? -// // Old comments from before moving to Unsafe.defineClass(): -// // is already defined (happens for X$ajcMightHaveAspect interfaces since aspects are reweaved) -// // TODO maw I don't think this is OK and -// } catch (Exception e) { -// warn("define generated class failed", e); -// } -// -// if (trace.isTraceEnabled()) { -// trace.exit("defineClass", clazz); -// } -// } } diff --git a/org.aspectj.ajdt.core/pom.xml b/org.aspectj.ajdt.core/pom.xml index 6ef954270c..6bb09b6eb5 100644 --- a/org.aspectj.ajdt.core/pom.xml +++ b/org.aspectj.ajdt.core/pom.xml @@ -67,6 +67,10 @@ org.ow2.asm asm
+ + org.ow2.asm + asm-commons + diff --git a/org.aspectj.ajdt.core/src/test/java/org/aspectj/tools/ajc/Ajc.java b/org.aspectj.ajdt.core/src/test/java/org/aspectj/tools/ajc/Ajc.java index 7f4ae01098..c6d8c99a89 100644 --- a/org.aspectj.ajdt.core/src/test/java/org/aspectj/tools/ajc/Ajc.java +++ b/org.aspectj.ajdt.core/src/test/java/org/aspectj/tools/ajc/Ajc.java @@ -38,8 +38,7 @@ import static java.io.File.pathSeparator; import static java.io.File.separator; -import static org.aspectj.tools.ajc.AjcTestCase.CLASSPATH_ASM; -import static org.aspectj.tools.ajc.AjcTestCase.CLASSPATH_JUNIT; +import static org.aspectj.tools.ajc.AjcTestCase.*; /** * The Ajc class is intended for use as part of a unit-test suite, it drives the AspectJ compiler and lets you check the compilation @@ -74,6 +73,7 @@ public static final String outputFolders(String... modules) { + outputFolder("bcel-builder") + pathSeparator + CLASSPATH_JUNIT + pathSeparator + CLASSPATH_ASM + + pathSeparator + CLASSPATH_ASM_COMMONS + outputFolder("bridge") + outputFolder("loadtime") + outputFolder("weaver") diff --git a/org.aspectj.ajdt.core/src/test/java/org/aspectj/tools/ajc/AjcTestCase.java b/org.aspectj.ajdt.core/src/test/java/org/aspectj/tools/ajc/AjcTestCase.java index 9aec7d947d..6fb2d26026 100644 --- a/org.aspectj.ajdt.core/src/test/java/org/aspectj/tools/ajc/AjcTestCase.java +++ b/org.aspectj.ajdt.core/src/test/java/org/aspectj/tools/ajc/AjcTestCase.java @@ -70,9 +70,15 @@ public abstract class AjcTestCase extends TestCase { public static final String CLASSPATH_ASM = Arrays.stream(System.getProperty("java.class.path") .split(pathSeparator)) - .filter(path -> path.replace('\\', '/').contains("org/ow2/asm/")) + .filter(path -> path.replace('\\', '/').contains("org/ow2/asm/asm/")) .findFirst() .orElseThrow(() -> new RuntimeException("ASM library not found on classpath")); + public static final String CLASSPATH_ASM_COMMONS = + Arrays.stream(System.getProperty("java.class.path") + .split(pathSeparator)) + .filter(path -> path.replace('\\', '/').contains("org/ow2/asm/asm-commons/")) + .findFirst() + .orElseThrow(() -> new RuntimeException("ASM Commons library not found on classpath")); public static final String CLASSPATH_JDT_CORE = Arrays.stream(System.getProperty("java.class.path") .split(pathSeparator)) @@ -102,6 +108,7 @@ public abstract class AjcTestCase extends TestCase { + pathSeparator + ".." + separator + "lib" + separator + "bcel" + separator + "bcel-verifier.jar" + pathSeparator + CLASSPATH_JDT_CORE + pathSeparator + CLASSPATH_ASM + + pathSeparator + CLASSPATH_ASM_COMMONS // hmmm, this next one should perhaps point to an aj-build jar... + pathSeparator + ".." + separator + "lib" + separator + "test" + separator + "aspectjrt.jar" ; diff --git a/pom.xml b/pom.xml index 823f65ccd8..5a62b005e7 100644 --- a/pom.xml +++ b/pom.xml @@ -555,6 +555,11 @@ asm ${asm.version} + + org.ow2.asm + asm-commons + ${asm.version} + org.aspectj diff --git a/run-all-junit-tests/pom.xml b/run-all-junit-tests/pom.xml index 537d2db413..f2370f3129 100644 --- a/run-all-junit-tests/pom.xml +++ b/run-all-junit-tests/pom.xml @@ -161,6 +161,11 @@ asm test + + org.ow2.asm + asm-commons + test + org.aspectj ajde diff --git a/taskdefs/pom.xml b/taskdefs/pom.xml index 9e6831a2d3..8bc3c35bb2 100644 --- a/taskdefs/pom.xml +++ b/taskdefs/pom.xml @@ -42,6 +42,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons + ant diff --git a/testing-drivers/pom.xml b/testing-drivers/pom.xml index a15c3a5349..d6975d22bc 100644 --- a/testing-drivers/pom.xml +++ b/testing-drivers/pom.xml @@ -38,6 +38,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons + diff --git a/testing/pom.xml b/testing/pom.xml index 38784790a7..c5e082255f 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -52,6 +52,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons + org.aspectj testing-client diff --git a/testing/src/test/java/org/aspectj/testing/AntSpec.java b/testing/src/test/java/org/aspectj/testing/AntSpec.java index 7a6bd3cd9e..33668d509b 100644 --- a/testing/src/test/java/org/aspectj/testing/AntSpec.java +++ b/testing/src/test/java/org/aspectj/testing/AntSpec.java @@ -98,9 +98,15 @@ public void execute(final AjcTestCase inTestCase) { // setup aj.dir "modules" folder p.setUserProperty("aj.root", new File("..").getAbsolutePath()); - // On Java 16+, LTW no longer works without this parameter. Add the argument here and not in AjcTestCase::run, - // because even if 'useLTW' and 'useFullLTW' are not set, we might in the future have tests for weaver attachment - // during runtime. See also docs/release/README-1.8.7.html. + // On Java 16+, LTW did not work on AspectJ 1.9.7 to 1.9.21 without this parameter. So, we added the argument here + // and not in AjcTestCase::run, because without 'useLTW' or 'useFullLTW', there might have been a need for weaver + // attachment during runtime. See also docs/release/README-1.8.7.adoc. + // + // Since AspectJ 1.9.21.1, '--add-opens' is no longer necessary, because we found a workaround for defining + // classes in arbitrary class loaders. But some tests, e.g. AtAjLTWTests.testLTWUnweavable, still use + // ClassLoader::defineClass to inject dynamically generated classes into the current class loader. Therefore, we + // still set the parameters, so they can be used on demand - not for LTW as such, but for class injection. See + // also tests/java5/ataspectj/ataspectj/UnweavableTest.java. // // Attention: Ant 1.6.3 under Linux neither likes "" (empty string) nor " " (space), on Windows it would not be // a problem. So we use "_dummy" Java system properties, even though they pollute the command line. diff --git a/testing/src/test/java/org/aspectj/testing/RunSpec.java b/testing/src/test/java/org/aspectj/testing/RunSpec.java index 593c5b9577..4d7526f44a 100644 --- a/testing/src/test/java/org/aspectj/testing/RunSpec.java +++ b/testing/src/test/java/org/aspectj/testing/RunSpec.java @@ -68,14 +68,21 @@ public void execute(AjcTestCase inTestCase) { if (vmargs == null) vmargs = ""; - // On Java 16+, LTW no longer works without this parameter. Add the argument here and not in AjcTestCase::run, - // because even if 'useLTW' and 'useFullLTW' are not set, we might in the future have tests for weaver attachment - // during runtime. See also docs/release/README-1.8.7.html. + // On Java 16+, LTW did not work on AspectJ 1.9.7 to 1.9.21 without this parameter. So, we added the argument here + // and not in AjcTestCase::run, because without 'useLTW' or 'useFullLTW', there might have been a need for weaver + // attachment during runtime. See also docs/release/README-1.8.7.adoc. + // + // Since AspectJ 1.9.21.1, '--add-opens' is no longer necessary, because we found a workaround for defining + // classes in arbitrary class loaders. But some tests, e.g. AtAjLTWTests.testLTWUnweavable, still use + // ClassLoader::defineClass to inject dynamically generated classes into the current class loader. Therefore, we + // still set the parameters, so they can be used on demand - not for LTW as such, but for class injection. See + // also tests/java5/ataspectj/ataspectj/UnweavableTest.java. // // The reason for setting this parameter for Java 9+ instead of 16+ is that it helps to avoid the JVM printing // unwanted illegal access warnings during weaving in 'useFullLTW' mode, either making existing tests fail or // having to assert on the warning messages. - vmargs += is16VMOrGreater() ? " --add-opens java.base/java.lang=ALL-UNNAMED" : ""; + // + // vmargs += is16VMOrGreater() ? " --add-opens java.base/java.lang=ALL-UNNAMED" : ""; AjcTestCase.RunResult rr = inTestCase.run(getClassToRun(), getModuleToRun(), args, vmargs, getClasspath(), getModulepath(), useLtw, "true".equalsIgnoreCase(usefullltw)); diff --git a/tests/bugs153/pr155033/ant.xml b/tests/bugs153/pr155033/ant.xml index 4f2dfb8855..6ef88c87ba 100644 --- a/tests/bugs153/pr155033/ant.xml +++ b/tests/bugs153/pr155033/ant.xml @@ -15,8 +15,8 @@ - - + + + diff --git a/tests/bugs153/pr158957/ant.xml b/tests/bugs153/pr158957/ant.xml index ca5dbc2543..74dac1409b 100644 --- a/tests/bugs153/pr158957/ant.xml +++ b/tests/bugs153/pr158957/ant.xml @@ -20,8 +20,8 @@ - - + + diff --git a/tests/java5/ataspectj/ajc-ant.xml b/tests/java5/ataspectj/ajc-ant.xml index 9fa6205725..285082612d 100644 --- a/tests/java5/ataspectj/ajc-ant.xml +++ b/tests/java5/ataspectj/ajc-ant.xml @@ -24,8 +24,8 @@ - - + + @@ -36,8 +36,8 @@ - - + + @@ -48,8 +48,8 @@ - - + + @@ -60,8 +60,8 @@ - - + + @@ -69,8 +69,8 @@ - - + + @@ -80,8 +80,8 @@ - - + + @@ -101,8 +101,8 @@ - - + + @@ -119,8 +119,8 @@ - - + + - - + + - - + + @@ -160,6 +160,7 @@ + @@ -175,8 +176,8 @@ - - + + - - + + @@ -211,8 +212,8 @@ - - + + @@ -230,8 +231,8 @@ - - + + - - + + @@ -273,8 +274,8 @@ - - + + @@ -291,8 +292,8 @@ - - + + diff --git a/tests/java5/ataspectj/ataspectj/UnweavableTest.java b/tests/java5/ataspectj/ataspectj/UnweavableTest.java index 1ef9706127..50c8779303 100644 --- a/tests/java5/ataspectj/ataspectj/UnweavableTest.java +++ b/tests/java5/ataspectj/ataspectj/UnweavableTest.java @@ -104,6 +104,8 @@ ISome getJit() { try { ClassLoader loader = this.getClass().getClassLoader(); + // Needs "--add-opens java.base/java.lang=ALL-UNNAMED" on the JVM command line, injected in Ant build via + // aj.addOpensKey and aj.addOpensValue variables. See also AntSpec::execute. Method def = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); def.setAccessible(true); Class gen = (Class) def.invoke(loader, "ataspectj.ISomeGen", cw.toByteArray(), 0, cw.toByteArray().length); @@ -127,6 +129,8 @@ Serializable getJitNoMatch() { try { ClassLoader loader = this.getClass().getClassLoader(); + // Needs "--add-opens java.base/java.lang=ALL-UNNAMED" on the JVM command line, injected in Ant build via + // aj.addOpensKey and aj.addOpensValue variables. See also AntSpec::execute. Method def = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); def.setAccessible(true); Class gen = (Class) def.invoke(loader, "ataspectj.unmatched.Gen", cw.toByteArray(), 0, cw.toByteArray().length); diff --git a/tests/ltw/ant-server.xml b/tests/ltw/ant-server.xml index c5f143fea5..d4958e3e3e 100644 --- a/tests/ltw/ant-server.xml +++ b/tests/ltw/ant-server.xml @@ -14,8 +14,8 @@ - - + + @@ -30,8 +30,8 @@ - - + + diff --git a/tests/ltw/ant.xml b/tests/ltw/ant.xml index 0cae97a367..abaf349d07 100644 --- a/tests/ltw/ant.xml +++ b/tests/ltw/ant.xml @@ -11,8 +11,8 @@ - - + + + - - + + @@ -80,8 +80,8 @@ to bootclasspath --> - - + + @@ -109,8 +109,8 @@ - - + + @@ -124,8 +124,8 @@ - - + + diff --git a/tests/pom.xml b/tests/pom.xml index 65d6ddc7a7..1489268b14 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -43,6 +43,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons + org.aspectj weaver diff --git a/tests/profiling/build.xml b/tests/profiling/build.xml index aa7db9d0e5..23a98c2ba1 100644 --- a/tests/profiling/build.xml +++ b/tests/profiling/build.xml @@ -290,8 +290,8 @@ - - + + @@ -323,8 +323,8 @@ - - + + diff --git a/tests/tracing/ant.xml b/tests/tracing/ant.xml index 6e0ddd78e9..687d41b10a 100644 --- a/tests/tracing/ant.xml +++ b/tests/tracing/ant.xml @@ -33,8 +33,8 @@ - - + + @@ -48,8 +48,8 @@ - - + + @@ -63,8 +63,8 @@ - - + + @@ -76,8 +76,8 @@ - - + + diff --git a/weaver/pom.xml b/weaver/pom.xml index 657813b8d0..f51e590e17 100644 --- a/weaver/pom.xml +++ b/weaver/pom.xml @@ -65,5 +65,9 @@ org.ow2.asm asm + + org.ow2.asm + asm-commons +