Skip to content

Commit

Permalink
Shim Java 10 collections APIs (#328)
Browse files Browse the repository at this point in the history
This commit adds Maven `<modules>` to the parent POM and two small
sub-modules: java8-shim and java10-shim.

Java8-shim defines an interface with methods like `.listCopyOf`
corresponding to Java 10's `java.util.List.copyOf`.

On Java 8-9, those APIs delegate to a homegrown equivalent.
On Java 10 and later, those APIs just call out to the standard
library functions.

I did the following experiment to see how well this JIT inlines.
The trace far below is derived by adding the main method below to
Java8Shim and running the command line second from bottom

```java
    @OverRide public void main(String... argv) {
        List<List<Integer>> ls = new ArrayList<>();
        for (int i = 0; i < 10000000; ++i) {
            ls.add(get().listOf(i, i + 1, i + 2));
        }
    }
```

Getting JIT diagnostics:

```sh
javac --release 8 -d out src/main/java/org/owasp/shim/Java8Shim.java \
    src/main/java/org/owasp/shim/ForJava8.java
javac --release 10 -d out -cp out \
    src/main/java/org/owasp/shim/ForJava9AndLater.java
java -cp out \
    -XX:+UnlockDiagnosticVMOptions \
    -XX:CompileCommand=print,org/owasp/shim/ForJava9AndLater.listOf \
    org.owasp.shim.Java8Shim
```

<details><summary>Dump with -XX:CompileCommand=print</summary>

```
  0x00000001144e9380: ; ImmutableOopMap {rbp=Oop [0]=Oop [8]=Oop }
                      ;*anewarray {reexecute=0 rethrow=0 return_oop=1}
                      ; - java.util.List::of@1 (line 847)
                      ; - org.owasp.shim.ForJava9AndLater::listOf@3 (line 21)
  0x00000001144e9380: fc83 9bff | 488b d8e9 | 27ff ffff

  0x00000001144e938c: ;   {metadata('java/util/ImmutableCollections$ListN')}
  0x00000001144e938c: 48be 2807 | 1b44 0100 | 0000 488b

  0x00000001144e9398: ;   {runtime_call _new_instance_Java}
  0x00000001144e9398: eb66 90e8

  0x00000001144e939c: ; ImmutableOopMap {rbp=Oop [8]=Oop }
                      ;*new {reexecute=0 rethrow=0 return_oop=1}
                      ; - java.util.ImmutableCollections::listFromTrustedArray@115 (line 220)
                      ; - java.util.List::of@16 (line 847)
                      ; - org.owasp.shim.ForJava9AndLater::listOf@3 (line 21)
  0x00000001144e939c: 60ad 9bff | ebac bd01 | 0000 004c | 8bc9 eb05 | bd02 0000 | 004c 890c | 24eb 0633 | ed4c 8914
  0x00000001144e93bc: 24be 45ff

  0x00000001144e93c0: ;   {runtime_call UncommonTrapBlob}
  0x00000001144e93c0: ffff 90e8

  0x00000001144e93c4: ; ImmutableOopMap {[0]=Oop [8]=Oop }
                      ;*ifnonnull {reexecute=1 rethrow=0 return_oop=0}
                      ; - (reexecute) java.util.Objects::requireNonNull@1 (line 208)
                      ; - java.util.ImmutableCollections::listFromTrustedArray@42 (line 213)
                      ; - java.util.List::of@16 (line 847)
                      ; - org.owasp.shim.ForJava9AndLater::listOf@3 (line 21)
  0x00000001144e93c4: 3842 91ff | 488b f0eb | 0348 8bf0 | 4883 c430

  0x00000001144e93d4: ;   {runtime_call _rethrow_Java}
  0x00000001144e93d4: 5de9 26b0

  0x00000001144e93d8: ;   {internal_word}
  0x00000001144e93d8: 9bff 49ba | 6093 4e14 | 0100 0000 | 4d89 9760

  0x00000001144e93e8: ;   {runtime_call SafepointBlob}
  0x00000001144e93e8: 0300 00e9 | 1053 91ff | f4f4 f4f4 | f4f4 f4f4 | f4f4 f4f4 | f4f4 f4f4
[Exception Handler]
  0x00000001144e9400: ;   {no_reloc}
  0x00000001144e9400: e97b f59a | ffe8 0000 | 0000 4883

  0x00000001144e940c: ;   {runtime_call DeoptimizationBlob}
  0x00000001144e940c: 2c24 05e9 | 8c45 91ff | f4f4 f4f4
[/MachCode]
```

iiuc, when there is one implementation of an interface loaded, the interface methods can devirtualize and the below shows that ForJava9AndLater::listOf with 3 arguments inlines to a null check and delegates the rest to `listFromTrustedArray`.

```
  0x00000001144e93c4: ; ImmutableOopMap {[0]=Oop [8]=Oop }
                      ;*ifnonnull {reexecute=1 rethrow=0 return_oop=0}
                      ; - (reexecute) java.util.Objects::requireNonNull@1 (line 208)
                      ; - java.util.ImmutableCollections::listFromTrustedArray@42 (line 213)
                      ; - java.util.List::of@16 (line 847)
                      ; - org.owasp.shim.ForJava9AndLater::listOf@3 (line 21)
```

Signed-off-by: Mike Samuel <mikesamuel@gmail.com>
  • Loading branch information
mikesamuel committed Mar 25, 2024
1 parent 032d11b commit 630524d
Show file tree
Hide file tree
Showing 86 changed files with 1,458 additions and 890 deletions.
7 changes: 4 additions & 3 deletions aggregate/pom.xml
Expand Up @@ -5,15 +5,16 @@
<packaging>pom</packaging>
<version>20220608.2-SNAPSHOT</version>
<parent>
<relativePath>../parent</relativePath>
<relativePath>..</relativePath>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>parent</artifactId>
<version>20220608.2-SNAPSHOT</version>
</parent>

<modules>
<module>..</module>
<module>../html-types</module>
<module>../parent</module>
<module>../java8-shim</module>
<module>../java10-shim</module>
<module>../owasp-java-html-sanitizer</module>
</modules>
</project>
2 changes: 1 addition & 1 deletion empiricism/pom.xml
Expand Up @@ -5,7 +5,7 @@
<version>20220608.2-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<relativePath>../parent</relativePath>
<relativePath>..</relativePath>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>parent</artifactId>
<version>20220608.2-SNAPSHOT</version>
Expand Down
2 changes: 1 addition & 1 deletion html-types/pom.xml
Expand Up @@ -5,7 +5,7 @@
<version>20220608.2-SNAPSHOT</version>
<packaging>bundle</packaging>
<parent>
<relativePath>../parent</relativePath>
<relativePath>..</relativePath>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>parent</artifactId>
<version>20220608.2-SNAPSHOT</version>
Expand Down
41 changes: 41 additions & 0 deletions java10-shim/pom.xml
@@ -0,0 +1,41 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>java10-shim</artifactId>
<packaging>jar</packaging>
<parent>
<relativePath>..</relativePath>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>parent</artifactId>
<version>20220608.2-SNAPSHOT</version>
</parent>

<name>Java 10 Shim</name>
<description>
Provides an implementation of java8-shim that interoperates with
Java >= 10 idioms for immutable collections.
</description>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>10</release>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>java8-shim</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
67 changes: 67 additions & 0 deletions java10-shim/src/main/java/org/owasp/shim/ForJava9AndLater.java
@@ -0,0 +1,67 @@
package org.owasp.shim;

import java.util.*;

@SuppressWarnings("Since15") // We're compiling two versions to handle @since problems.
final class ForJava9AndLater extends Java8Shim {

@Override public <T> List<T> listOf() {
return List.of();
}

@Override public <T> List<T> listOf(T a) {
return List.of(a);
}

@Override public <T> List<T> listOf(T a, T b) {
return List.of(a, b);
}

@Override public <T> List<T> listOf(T a, T b, T c) {
return List.of(a, b, c);
}

@Override public <T> List<T> listOf(T... els) {
return List.of(els);
}

@Override public <T> List<T> listCopyOf(Collection<? extends T> c) {
return List.copyOf(c);
}

@Override public <K, V> Map<K, V> mapCopyOf(Map<? extends K, ? extends V> m) {
return Map.copyOf(m);
}

@Override public <K, V> Map.Entry<K, V> mapEntry(K key, V value) {
return Map.entry(key, value);
}

@Override public <K, V> Map<K, V> mapOfEntries(Map.Entry<K, V>... entries) {
return Map.ofEntries(entries);
}

@Override public <T> Set<T> setOf() {
return Set.of();
}

@Override public <T> Set<T> setOf(T a) {
return Set.of(a);
}

@Override public <T> Set<T> setOf(T a, T b) {
return Set.of(a, b);
}

@Override public <T> Set<T> setOf(T a, T b, T c) {
return Set.of(a, b, c);
}

@Override public <T> Set<T> setOf(T... els) {
return Set.of(els);
}

@Override public <T> Set<T> setCopyOf(Collection<? extends T> c) {
return Set.copyOf(c);
}
}
38 changes: 38 additions & 0 deletions java8-shim/pom.xml
@@ -0,0 +1,38 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>java8-shim</artifactId>
<packaging>jar</packaging>
<parent>
<relativePath>..</relativePath>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>parent</artifactId>
<version>20220608.2-SNAPSHOT</version>
</parent>

<name>Java 8 Shim</name>
<description>
Backports @since Java 9 collection factories like List.of onto
Java8 in a way that uses the real ones where available, falls back
to a conforming implementation on Java8 and JIT compiles well.
</description>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>8</release>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

0 comments on commit 630524d

Please sign in to comment.