Skip to content

Commit

Permalink
Weaver returns null instead of original bytes for unwoven classes
Browse files Browse the repository at this point in the history
This change makes sense independently of #277, but also enables using

  - cp "my.jar;aspectjweaver.jar"
  -XX:+AllowArchivingWithJavaAgent
  -javaagent:aspectjweaver.jar

while creating a CDS archive. Afterward, the application can be run in
its woven state from the CDS archive even without '-javaagent', because
the byte code was archived in its woven state ("poor man's AJC"). See
#277 (comment)
for details.

Fixes #277.

Signed-off-by: Alexander Kriegisch <Alexander@Kriegisch.name>
  • Loading branch information
kriegaex committed Feb 7, 2024
1 parent 0cba9d1 commit 1b878ef
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 21 deletions.
10 changes: 5 additions & 5 deletions loadtime/src/main/java/org/aspectj/weaver/loadtime/Aj.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,18 @@ public void initialize() {
private final static String deleLoader2 = "jdk.internal.reflect.DelegatingClassLoader"; // On JDK11+

@Override
public byte[] preProcess(String className, byte[] bytes, ClassLoader loader, ProtectionDomain protectionDomain) {
public byte[] preProcess(String className, final byte[] bytes, ClassLoader loader, ProtectionDomain protectionDomain) {
if (loader == null || className == null ||
loader.getClass().getName().equals(deleLoader) || loader.getClass().getName().equals(deleLoader2)) {
// skip boot loader, null classes (hibernate), or those from a reflection loader
return bytes;
return null;
}

if (loadersToSkip != null) {
// Check whether to reject it
if (loadersToSkip.contains(loader.getClass().getName())) {
// System.out.println("debug: no weaver created for loader '"+loader.getClass().getName()+"'");
return bytes;
return null;
}
}

Expand All @@ -109,7 +109,7 @@ public byte[] preProcess(String className, byte[] bytes, ClassLoader loader, Pro
if (weavingAdaptor == null) {
if (trace.isTraceEnabled())
trace.exit("preProcess");
return bytes;
return null;
}
try {
weavingAdaptor.setActiveProtectionDomain(protectionDomain);
Expand All @@ -134,7 +134,7 @@ public byte[] preProcess(String className, byte[] bytes, ClassLoader loader, Pro
// would make sense at least in test f.e. see TestHelper.handleMessage()
if (trace.isTraceEnabled())
trace.exit("preProcess", th);
return bytes;
return null;
} finally {
CompilationAndWeavingContext.resetForThread();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public interface ClassPreProcessor {
*/
void initialize();

byte[] preProcess(String className, byte[] bytes, ClassLoader classLoader, ProtectionDomain protectionDomain);
byte[] preProcess(String className, final byte[] bytes, ClassLoader classLoader, ProtectionDomain protectionDomain);

void prepareForRedefinition(ClassLoader loader, String className);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class ClassPreProcessorAgentAdapter implements ClassFileTransformer {
*/
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] bytes) throws IllegalClassFormatException {
final byte[] bytes) throws IllegalClassFormatException {
if (classBeingRedefined != null) {
System.err.println("INFO: (Enh120375): AspectJ attempting reweave of '" + className + "'");
classPreProcessor.prepareForRedefinition(loader, className);
Expand Down
33 changes: 19 additions & 14 deletions weaver/src/main/java/org/aspectj/weaver/tools/WeavingAdaptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -324,20 +324,21 @@ protected Boolean initialValue() {
* @return the woven bytes
* @exception IOException weave failed
*/
public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IOException {
public byte[] weaveClass(String name, final byte[] bytes, boolean mustWeave) throws IOException {
if (trace == null) {
// Pr231945: we are likely to be under tomcat and ENABLE_CLEAR_REFERENCES hasn't been set
System.err
.println("AspectJ Weaver cannot continue to weave, static state has been cleared. Are you under Tomcat? In order to weave '"
+ name
+ "' during shutdown, 'org.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false' must be set (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=231945).");
return bytes;
return null;
}
if (weaverRunning.get()) {
// System.out.println("AJC: avoiding re-entrant call to transform " + name);
return bytes;
return null;
}
try {
byte[] newBytes = null;
weaverRunning.set(true);
if (trace.isTraceEnabled()) {
trace.enter("weaveClass", this, new Object[] { name, bytes });
Expand All @@ -347,7 +348,7 @@ public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IO
if (trace.isTraceEnabled()) {
trace.exit("weaveClass", false);
}
return bytes;
return null;
}

boolean debugOn = !messageHandler.isIgnoring(Message.DEBUG);
Expand All @@ -360,15 +361,14 @@ public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IO

// Determine if we have the weaved class cached
CachedClassReference cacheKey = null;
final byte[] original_bytes = bytes;
if (cache != null && !mustWeave) {
cacheKey = cache.createCacheKey(name, original_bytes);
CachedClassEntry entry = cache.get(cacheKey, original_bytes);
cacheKey = cache.createCacheKey(name, bytes);
CachedClassEntry entry = cache.get(cacheKey, bytes);
if (entry != null) {
// If the entry has been explicitly ignored
// return the original bytes
if (entry.isIgnored()) {
return bytes;
return null;
}
return entry.getBytes();
}
Expand All @@ -382,7 +382,12 @@ public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IO
if (debugOn) {
debug("weaving '" + name + "'");
}
bytes = getWovenBytes(name, bytes);
newBytes = getWovenBytes(name, bytes);
// TODO: Is this OK performance-wise?
if (Arrays.equals(bytes, newBytes)) {
// null means unchanged in java.lang.instrument.ClassFileTransformer::transform
newBytes = null;

This comment has been minimized.

Copy link
@KimmingLau

KimmingLau Feb 7, 2024

Contributor

I think the performance-wise is ok, because if a class is enhanced, there is a high probability that the lengths of the arrays are different. Arrays.equals has this fast judgment.

This comment has been minimized.

Copy link
@kriegaex

kriegaex Feb 7, 2024

Author Contributor

I know that. What I mean is the time it takes to compare identical arrays, which is more common, because normally, most classes are unwoven. With identical sizes, we have to compare byte by byte.

}
// temporarily out - searching for @Aspect annotated types is a slow thing to do - we should
// expect the user to name them if they want them woven - just like code style
// } else if (shouldWeaveAnnotationStyleAspect(name, bytes)) {
Expand All @@ -405,10 +410,10 @@ public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IO
if (cacheKey != null) {
// If no transform has been applied, mark the class
// as ignored.
if (Arrays.equals(original_bytes, bytes)) {
cache.ignore(cacheKey, original_bytes);
if (newBytes == null) {
cache.ignore(cacheKey, bytes);
} else {
cache.put(cacheKey, original_bytes, bytes);
cache.put(cacheKey, bytes, newBytes);
}
}
} else if (debugOn) {
Expand All @@ -422,9 +427,9 @@ public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IO
}

if (trace.isTraceEnabled()) {
trace.exit("weaveClass", bytes);
trace.exit("weaveClass", newBytes);
}
return bytes;
return newBytes;
} finally {
weaverRunning.remove();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public byte[] getAndInitialize(String classname, byte[] bytes,
byte[] res = get(classname, bytes);

if (Arrays.equals(SAME_BYTES, res)) {
// TODO: Should we return null (means "not transformed") in this case?
return bytes;
} else {
if (res != null) {
Expand Down

0 comments on commit 1b878ef

Please sign in to comment.