Skip to content

Commit

Permalink
Support running on JDK 17 (#1281)
Browse files Browse the repository at this point in the history
With this change, WALA's regression tests pass on JDK 17, and WALA can
also load and process some JDK 17 bytecodes. We have _not_ thoroughly
tested recent bytecode features and they may still not work, but
whatever is exercised by current regression tests seems to be working.
Getting things working on JDK 17 required various minor changes.
  • Loading branch information
msridhar authored Jun 27, 2023
1 parent 6f9e6ce commit c6f20aa
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 48 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
java: 11
- os: windows-latest
java: 11
- os: ubuntu-latest
java: 17
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ dependencies {
"javadocSource"(sourceSets.main.get().allJava)
}

the<JavaPluginExtension>().toolchain.languageVersion.set(JavaLanguageVersion.of(11))

tasks.withType<JavaCompile>().configureEach {
// Generate JDK 11 bytecodes; that is the minimum version supported by WALA
options.release.set(11)
options.errorprone {
// don't run warning-level checks by default as they add too much noise to build output
// NOTE: until https://github.com/google/error-prone/pull/3462 makes it to a release,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ public void testMiniaturSliceBug() throws IllegalArgumentException, CancelExcept
AstJavaSlicer.computeAssertionSlice(cg, pa, roots, false);
Collection<Statement> slice = y.fst;
dumpSlice(slice);
Assert.assertEquals(0, SlicerUtil.countAllocations(slice));
Assert.assertEquals(0, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(1, SlicerUtil.countPutfields(slice));

// test slice from main
Expand All @@ -731,7 +731,7 @@ public void testMiniaturSliceBug() throws IllegalArgumentException, CancelExcept
y = AstJavaSlicer.computeAssertionSlice(cg, pa, roots, false);
slice = y.fst;
// SlicerUtil.dumpSlice(slice);
Assert.assertEquals(2, SlicerUtil.countAllocations(slice));
Assert.assertEquals(2, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(2, SlicerUtil.countPutfields(slice));
}

Expand Down
6 changes: 6 additions & 0 deletions cast/java/test/data/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,9 @@ sourceSets.test.get().java.srcDir(downloadJLex.map { it.extra["downloadedSourceD
//

tasks.register("prepareMavenBuild") { dependsOn("eclipseClasspath", "eclipseProject") }

// On JDK 17, deprecation errors in ECJ cannot be disabled when compiling JLex code. So, we disable
// the ECJ task on JDK 17+.
if (JavaVersion.current() >= JavaVersion.VERSION_17) {
tasks.named("compileTestJavaUsingEcj") { enabled = false }
}
2 changes: 1 addition & 1 deletion core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ tasks.named<Copy>("processTestResources") {
}

tasks.named<Test>("test") {
maxHeapSize = "1500M"
maxHeapSize = "2000M"
systemProperty("com.ibm.wala.junit.profile", "short")
classpath += files(sourceSets.test.get().output.classesDirs)
testLogging {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.ibm.wala.analysis.arraybounds.ArrayOutOfBoundsAnalysis;
import com.ibm.wala.analysis.nullpointer.IntraproceduralNullPointerAnalysis;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.dataflow.graph.BitVectorFramework;
import com.ibm.wala.dataflow.graph.BitVectorSolver;
import com.ibm.wala.fixpoint.BitVectorVariable;
Expand Down Expand Up @@ -127,10 +128,18 @@ public boolean catchesException(
boolean isCaught = false;
while (caughtExceptions.hasNext() && !isCaught) {
TypeReference caughtException = caughtExceptions.next();
IClass caughtExceptionClass = cha.lookupClass(caughtException);
if (caughtExceptionClass == null) {
// for now, assume it is not caught
continue;
}
for (TypeReference thrownException : thrownExceptions) {
isCaught |=
cha.isAssignableFrom(
cha.lookupClass(caughtException), cha.lookupClass(thrownException));
IClass thrownExceptionClass = cha.lookupClass(thrownException);
if (thrownExceptionClass == null) {
// for now, assume it is not caught
continue;
}
isCaught |= cha.isAssignableFrom(caughtExceptionClass, thrownExceptionClass);
if (isCaught) break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import com.ibm.wala.util.collections.FilterIterator;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.MapIterator;
import com.ibm.wala.util.debug.UnimplementedError;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
import com.ibm.wala.util.intset.MutableIntSet;
Expand Down Expand Up @@ -301,7 +302,17 @@ public IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass rec
.getClassHierarchy()
.lookupClass(TypeReference.JavaLangInvokeMethodHandle),
false,
false);
false) {
@Override
public IR makeIR(Context context, SSAOptions options) throws UnimplementedError {
// MS: On JDK 17, sometimes makeIR() is getting called, and the default
// implementation fails with an error. I don't fully understand the invariants of
// this class, but overriding and returning null makes the tests pass.
// Eventually, we should document this class and figure out if this is the right
// fix.
return null;
}
};
impls.put(target, invokeExactTrampoline);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,8 @@ public SSAInstruction[] getStatements(@SuppressWarnings("unused") SSAOptions opt
* @param options options governing IR conversion
*/
public IR makeIR(Context context, SSAOptions options) throws UnimplementedError {
throw new UnimplementedError("haven't implemented IR yet for class " + getClass());
throw new UnimplementedError(
"haven't implemented IR yet for class " + getClass() + ", method " + method);
}

@Override
Expand Down
38 changes: 17 additions & 21 deletions core/src/main/java/com/ibm/wala/ipa/slicer/SlicerUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,28 +93,13 @@ public static void dumpSliceToFile(Collection<Statement> slice, String fileName)
}
}

public static int countAllocations(Collection<Statement> slice) {
public static int countAllocations(Collection<Statement> slice, boolean applicationOnly) {
int count = 0;
for (Statement s : slice) {
if (s.getKind().equals(Statement.Kind.NORMAL)) {
NormalStatement ns = (NormalStatement) s;
if (ns.getInstruction() instanceof SSANewInstruction) {
count++;
}
}
}
return count;
}

public static int countApplicationAllocations(Collection<Statement> slice) {
int count = 0;
for (Statement s : slice) {
if (s.getKind().equals(Statement.Kind.NORMAL)) {
NormalStatement ns = (NormalStatement) s;
if (ns.getInstruction() instanceof SSANewInstruction) {
AnalysisScope scope = s.getNode().getClassHierarchy().getScope();
if (scope.isApplicationLoader(
s.getNode().getMethod().getDeclaringClass().getClassLoader())) {
if (!applicationOnly || fromApplicationLoader(s)) {
count++;
}
}
Expand All @@ -123,13 +108,22 @@ public static int countApplicationAllocations(Collection<Statement> slice) {
return count;
}

public static int countThrows(Collection<Statement> slice) {
private static boolean fromApplicationLoader(Statement s) {
return s.getNode()
.getClassHierarchy()
.getScope()
.isApplicationLoader(s.getNode().getMethod().getDeclaringClass().getClassLoader());
}

public static int countThrows(Collection<Statement> slice, boolean applicationOnly) {
int count = 0;
for (Statement s : slice) {
if (s.getKind().equals(Statement.Kind.NORMAL)) {
NormalStatement ns = (NormalStatement) s;
if (ns.getInstruction() instanceof SSAAbstractThrowInstruction) {
count++;
if (!applicationOnly || fromApplicationLoader(s)) {
count++;
}
}
}
}
Expand Down Expand Up @@ -228,15 +222,17 @@ public static int countReturns(Collection<Statement> slice) {
return count;
}

public static int countGetfields(Collection<Statement> slice) {
public static int countGetfields(Collection<Statement> slice, boolean applicationOnly) {
int count = 0;
for (Statement s : slice) {
if (s.getKind().equals(Statement.Kind.NORMAL)) {
NormalStatement ns = (NormalStatement) s;
if (ns.getInstruction() instanceof SSAGetInstruction) {
SSAGetInstruction p = (SSAGetInstruction) ns.getInstruction();
if (!p.isStatic()) {
count++;
if (!applicationOnly || fromApplicationLoader(s)) {
count++;
}
}
}
}
Expand Down
29 changes: 14 additions & 15 deletions core/src/test/java/com/ibm/wala/core/tests/slicer/SlicerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public void testSlice3()
Slicer.computeBackwardSlice(
s, cg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countAllocations(slice, false));
}

@Test
Expand Down Expand Up @@ -598,7 +598,7 @@ public void testTestId()
Slicer.computeBackwardSlice(
s, cg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countAllocations(slice, false));
}

@Test
Expand Down Expand Up @@ -626,7 +626,7 @@ public void testTestArrays()
Slicer.computeBackwardSlice(
s, cg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countAloads(slice));
}

Expand Down Expand Up @@ -655,7 +655,7 @@ public void testTestFields()
Slicer.computeBackwardSlice(
s, cg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countPutfields(slice));
}

Expand Down Expand Up @@ -686,7 +686,7 @@ public void testThin1()
Slicer.computeBackwardSlice(
s, cg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(3, SlicerUtil.countAllocations(slice));
Assert.assertEquals(3, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(2, SlicerUtil.countPutfields(slice));

// compute thin slice .. ignore base pointers
Expand All @@ -699,7 +699,7 @@ public void testThin1()
ControlDependenceOptions.NONE);
slice = computeBackwardSlice;
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countPutfields(slice));
}

Expand Down Expand Up @@ -728,7 +728,7 @@ public void testTestGlobal()
Slicer.computeBackwardSlice(
s, cg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countPutstatics(slice));
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countGetstatics(slice));
}
Expand Down Expand Up @@ -758,7 +758,7 @@ public void testTestMultiTarget()
Slicer.computeBackwardSlice(
s, cg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countAllocations(slice, false));
}

@Test
Expand Down Expand Up @@ -787,7 +787,7 @@ public void testTestRecursion()
Slicer.computeBackwardSlice(
s, cg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 3, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 3, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(slice.toString(), 2, SlicerUtil.countPutfields(slice));
}

Expand Down Expand Up @@ -819,7 +819,7 @@ public void testPrimGetterSetter()
Slicer.computeBackwardSlice(
s, pcg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.FULL);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 0, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 0, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countPutfields(slice));
}

Expand Down Expand Up @@ -878,7 +878,7 @@ public void testPrimGetterSetter2()
Slicer.computeBackwardSlice(
s, pcg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countAllocations(slice));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countAllocations(slice, false));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countPutfields(slice));
}

Expand Down Expand Up @@ -906,10 +906,9 @@ public void testTestThrowCatch()
Collection<Statement> slice =
Slicer.computeBackwardSlice(
s, cg, pointerAnalysis, DataDependenceOptions.FULL, ControlDependenceOptions.NONE);
SlicerUtil.dumpSlice(slice);
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countApplicationAllocations(slice));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countThrows(slice));
Assert.assertEquals(slice.toString(), 1, SlicerUtil.countGetfields(slice));
Assert.assertEquals("wrong number of allocations", 1, SlicerUtil.countAllocations(slice, true));
Assert.assertEquals("wrong number of throws", 1, SlicerUtil.countThrows(slice, true));
Assert.assertEquals("wrong number of getfields", 1, SlicerUtil.countGetfields(slice, true));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ private void parse() throws InvalidClassFileException {
if (magic != MAGIC) {
throw new InvalidClassFileException(offset, "bad magic number: " + magic);
}
if (majorVersion < 45 || majorVersion > 60) {
// Support class files up through JDK 17 (version 61)
if (majorVersion < 45 || majorVersion > 61) {
throw new InvalidClassFileException(
offset, "unknown class file version: " + majorVersion + '.' + minorVersion);
}
Expand Down
2 changes: 1 addition & 1 deletion util/.settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=error
org.eclipse.jdt.core.compiler.problem.deadCode=warning
org.eclipse.jdt.core.compiler.problem.deprecation=error
org.eclipse.jdt.core.compiler.problem.deprecation=disabled
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=error
Expand Down

0 comments on commit c6f20aa

Please sign in to comment.