Bug 516279 - [JDK9] ajc$preClinit not allowed in static initializer
Summary: [JDK9] ajc$preClinit not allowed in static initializer
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: DEVELOPMENT   Edit
Hardware: PC Linux
: P3 blocker (vote)
Target Milestone: 1.9.0.RC1   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-05-06 15:35 EDT by Cleber Muramoto CLA
Modified: 2017-09-28 16:43 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Cleber Muramoto CLA 2017-05-06 15:35:09 EDT
Seems like the verifier in Java 9 became more strict.

AJC generates code that attempts to initialize static final fields in ajc$preClinit, which is caleed on <clinit>, e.g.,

//regular field
private static final String ADDRESS;
//inserted by ajc
private static final /* synthetic */ JoinPoint.StaticPart ajc$tjp_0;

static {
        //post-weaved code   
        ServiceImpl.ajc$preClinit();
        ADDRESS = "https://...";
}

private static synthetic void ajc$preClinit() {
        Factory factory = new Factory("ServiceImpl.java", ServiceImpl.class);
        ajc$tjp_0 = factory.makeSJP("method-execution", (Signature)factory.makeMethodSig("80", "remove", "le.package.ServiceImpl", "[Ljava.lang.String;", "names", "", "void"), 1344);
}

Seems like Java 9 doesn't like this and it throws an IllegalAccessError during classloading:

ServiceImpl.ajc$tjp_0 attempted from a different method (ajc$preClinit) than the initializer method <clinit> 

I believe the only definitive solution, apart from removing the final modifier from ajc generated fields, would be inlining ajc$preClinit.

Tested with aspectj 1.9.0.BETA-5 (from http://repo.spring.io/milestone) and JDK build 9-ea+164.
Comment 1 Cleber Muramoto CLA 2017-05-06 16:09:13 EDT
Anyone awaiting for this fix, can work-around by patching aspectjtools.jar with a trivial change in org.aspectj.weaver.bcel.LazyClassGen 

public Field getTjpField(BcelShadow shadow, final boolean isEnclosingJp) {
		Field tjpField = tjpFields.get(shadow);
		if (tjpField != null) {
			return tjpField;
		}

		int modifiers = Modifier.STATIC /*| Modifier.FINAL*/ ;
...
}
Comment 2 Cleber Muramoto CLA 2017-05-08 17:25:46 EDT
Another similar issue when ajc compiles aspects themselves. 

AJC produces ajc$perSingletonInstance as static final field and ajc$postClinit attempts to initialize it.

Quick Hack: Patch org.aspectj.weaver.AjcMemberMaker

public static ResolvedMember perSingletonField(UnresolvedType declaringType) {
		return new ResolvedMemberImpl(Member.FIELD, declaringType, PUBLIC_STATIC, NameMangler.PERSINGLETON_FIELD_NAME, declaringType.getSignature());
}
Comment 3 Andrew Clement CLA 2017-09-28 16:43:45 EDT
Fixed up (well mostly). Removed the final modifier.  Unfortunately that doesn't help the case of weaving default methods in an interface since you can't take the final off in that case (and the preclinit will need inlining).  But I think that is a much smaller issue than the general problem. So will capture it separately (address it when someone starts hitting it).