Skip to content

Commit

Permalink
[fixes #2681] [jdk16] support jdk16
Browse files Browse the repository at this point in the history
  • Loading branch information
rzwitserloot committed Mar 16, 2021
1 parent 476a43b commit 9806e5c
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 2 deletions.
91 changes: 89 additions & 2 deletions src/core/lombok/javac/apt/LombokProcessor.java
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2019 The Project Lombok Authors.
* Copyright (C) 2009-2020 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -63,6 +63,8 @@
import lombok.core.DiagnosticsReceiver;
import lombok.javac.JavacTransformer;
import lombok.permit.Permit;
import lombok.permit.dummy.Parent;
import sun.misc.Unsafe;

/**
* This Annotation Processor is the standard injection mechanism for lombok-enabling the javac compiler.
Expand Down Expand Up @@ -430,6 +432,7 @@ private JCCompilationUnit toUnit(Element element) {
* gradle incremental compilation, the delegate ProcessingEnvironment of the gradle wrapper is returned.
*/
public JavacProcessingEnvironment getJavacProcessingEnvironment(Object procEnv) {
addOpensForLombok();
if (procEnv instanceof JavacProcessingEnvironment) return (JavacProcessingEnvironment) procEnv;

// try to find a "delegate" field in the object, and use this to try to obtain a JavacProcessingEnvironment
Expand All @@ -446,7 +449,91 @@ public JavacProcessingEnvironment getJavacProcessingEnvironment(Object procEnv)
"Can't get the delegate of the gradle IncrementalProcessingEnvironment. Lombok won't work.");
return null;
}


private static Object getOwnModule() {
try {
Method m = Permit.getMethod(Class.class, "getModule");
return m.invoke(LombokProcessor.class);
} catch (Exception e) {
return null;
}
}

private static Object getJdkCompilerModule() {
/* call public api: ModuleLayer.boot().findModule("jdk.compiler").get();
but use reflection because we don't want this code to crash on jdk1.7 and below.
In that case, none of this stuff was needed in the first place, so we just exit via
the catch block and do nothing.
*/

try {
Class<?> cModuleLayer = Class.forName("java.lang.ModuleLayer");
Method mBoot = cModuleLayer.getDeclaredMethod("boot");
Object bootLayer = mBoot.invoke(null);
Class<?> cOptional = Class.forName("java.util.Optional");
Method mFindModule = cModuleLayer.getDeclaredMethod("findModule", String.class);
Object oCompilerO = mFindModule.invoke(bootLayer, "jdk.compiler");
return cOptional.getDeclaredMethod("get").invoke(oCompilerO);
} catch (Exception e) {
return null;
}
}

/** Useful from jdk9 and up; required from jdk16 and up. This code is supposed to gracefully do nothing on jdk8 and below, as this operation isn't needed there. */
private static void addOpensForLombok() {
Class<?> cModule;
try {
cModule = Class.forName("java.lang.Module");
} catch (ClassNotFoundException e) {
return; //jdk8-; this is not needed.
}

Unsafe unsafe = getUnsafe();
Object jdkCompilerModule = getJdkCompilerModule();
Object ownModule = getOwnModule();
String[] allPkgs = {
"com.sun.tools.javac.code",
"com.sun.tools.javac.comp",
"com.sun.tools.javac.file",
"com.sun.tools.javac.main",
"com.sun.tools.javac.model",
"com.sun.tools.javac.parser",
"com.sun.tools.javac.processing",
"com.sun.tools.javac.tree",
"com.sun.tools.javac.util",
"com.sun.tools.javac.jvm",
};

try {
Method m = cModule.getDeclaredMethod("implAddOpens", String.class, cModule);
long firstFieldOffset = getFirstFieldOffset(unsafe);
unsafe.putBooleanVolatile(m, firstFieldOffset, true);
for (String p : allPkgs) m.invoke(jdkCompilerModule, p, ownModule);
} catch (Exception ignore) {}
}

private static long getFirstFieldOffset(Unsafe unsafe) {
try {
return unsafe.objectFieldOffset(Parent.class.getDeclaredField("first"));
} catch (NoSuchFieldException e) {
// can't happen.
throw new RuntimeException(e);
} catch (SecurityException e) {
// can't happen
throw new RuntimeException(e);
}
}

private static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
return null;
}
}

/**
* This class returns the given filer as a JavacFiler. In case the filer is no
* JavacFiler (e.g. the Gradle IncrementalFiler), its "delegate" field is used to get the JavacFiler
Expand Down
9 changes: 9 additions & 0 deletions src/utils/lombok/permit/dummy/Child.java
@@ -0,0 +1,9 @@
package lombok.permit.dummy;

@SuppressWarnings("all")
public abstract class Child extends Parent {
private transient volatile boolean foo;
private transient volatile Object[] bar;
private transient volatile Object baz;

}
19 changes: 19 additions & 0 deletions src/utils/lombok/permit/dummy/GrandChild.java
@@ -0,0 +1,19 @@
package lombok.permit.dummy;

@SuppressWarnings("all")
public final class GrandChild extends Child {
private Class<?> a;
private int b;
private String c;
private Class<?> d;
private Class<?>[] e;
private Class<?>[] f;
private int g;
private transient String h;
private transient Object i;
private byte[] j;
private byte[] k;
private byte[] l;
private volatile Object m;
private Object n;
}
12 changes: 12 additions & 0 deletions src/utils/lombok/permit/dummy/Parent.java
@@ -0,0 +1,12 @@
package lombok.permit.dummy;

import java.io.OutputStream;

@SuppressWarnings("all")
public class Parent {
boolean first;
static final Object staticObj = OutputStream.class;
volatile Object second;
private static volatile boolean staticSecond;
private static volatile boolean staticThird;
}
8 changes: 8 additions & 0 deletions src/utils/lombok/permit/dummy/package-info.java
@@ -0,0 +1,8 @@
/**
* This package recreates the type hierarchy of {@code java.lang.reflect.AccessibleObject} and friends (such as {@code java.lang.reflect.Method});
* its purpose is to allow us to ask {@code sun.misc.internal.Unsafe} about the exact offset of the {@code override} field of {@code AccessibleObject};
* asking about that field directly doesn't work after jdk14, presumably because the fields of AO are expressly hidden somehow.

This comment has been minimized.

Copy link
@orionll

orionll Mar 17, 2021

AccessibleObject.override was hidden in JDK 12: https://bugs.openjdk.java.net/browse/JDK-8210522

*
* NB: It's usually 12, on the vast majority of OS, VM, and architecture combos.
*/
package lombok.permit.dummy;

0 comments on commit 9806e5c

Please sign in to comment.